diff options
Diffstat (limited to 'kstars/kstars/detaildialog.cpp')
-rw-r--r-- | kstars/kstars/detaildialog.cpp | 1080 |
1 files changed, 1080 insertions, 0 deletions
diff --git a/kstars/kstars/detaildialog.cpp b/kstars/kstars/detaildialog.cpp new file mode 100644 index 00000000..24949c50 --- /dev/null +++ b/kstars/kstars/detaildialog.cpp @@ -0,0 +1,1080 @@ +/*************************************************************************** + detaildialog.cpp - description + ------------------- + begin : Sun May 5 2002 + copyright : (C) 2002 by Jason Harris and Jasem Mutlaq + email : kstars@30doradus.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qstring.h> +#include <qlayout.h> //still needed for secondary dialogs +#include <qlineedit.h> +#include <qimage.h> +#include <qregexp.h> + +#include <kapplication.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kactivelabel.h> +#include <kpushbutton.h> +#include <klistview.h> +#include <klineedit.h> + +#include "detaildialog.h" +//UI headers +#include "details_data.h" +#include "details_position.h" +#include "details_links.h" +#include "details_database.h" +#include "details_log.h" + +#include "kstars.h" +#include "kstarsdata.h" +#include "kstarsdatetime.h" +#include "geolocation.h" +#include "ksutils.h" +#include "skymap.h" +#include "skyobject.h" +#include "starobject.h" +#include "deepskyobject.h" +#include "ksplanetbase.h" +#include "ksmoon.h" +#include "thumbnailpicker.h" + +#include "indielement.h" +#include "indiproperty.h" +#include "indidevice.h" +#include "indimenu.h" +#include "devicemanager.h" +#include "indistd.h" + +LogEdit::LogEdit( QWidget *parent, const char *name ) : KTextEdit( parent, name ) +{ + setFrameStyle( QFrame::StyledPanel ); + setFrameShadow( QFrame::Plain ); + setLineWidth( 4 ); +} + +void LogEdit::focusOutEvent( QFocusEvent *e ) { + emit focusOut(); + QWidget::focusOutEvent(e); +} + +ClickLabel::ClickLabel( QWidget *parent, const char *name ) : QLabel( parent, name ) +{} + +DetailDialog::DetailDialog(SkyObject *o, const KStarsDateTime &ut, GeoLocation *geo, + QWidget *parent, const char *name ) : + KDialogBase( KDialogBase::Tabbed, i18n( "Object Details" ), Close, Close, parent, name ) , + selectedObject(o), ksw((KStars*)parent), Data(0), Pos(0), Links(0), Adv(0), Log(0) +{ + //Modify color palette + setPaletteBackgroundColor( palette().color( QPalette::Active, QColorGroup::Base ) ); + setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::Text ) ); + + //Create thumbnail image + Thumbnail = new QPixmap( 200, 200 ); + + createGeneralTab(); + createPositionTab( ut, geo ); + createLinksTab(); + createAdvancedTab(); + createLogTab(); + + //Connections + connect( Data->ObsListButton, SIGNAL( clicked() ), this, SLOT( addToObservingList() ) ); + connect( Data->CenterButton, SIGNAL( clicked() ), this, SLOT( centerMap() ) ); + connect( Data->ScopeButton, SIGNAL( clicked() ), this, SLOT( centerTelescope() ) ); + connect( Data->Image, SIGNAL( clicked() ), this, SLOT( updateThumbnail() ) ); +} + +void DetailDialog::createGeneralTab() +{ + QFrame *DataTab = addPage(i18n("General")); + Data = new DetailsDataUI( DataTab, "general_data_tab" ); + + //Modify colors + Data->Names->setPaletteBackgroundColor( palette().color( QPalette::Active, QColorGroup::Highlight ) ); + Data->Names->setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::HighlightedText ) ); + Data->DataFrame->setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::Highlight ) ); + Data->Type->setPalette( palette() ); + Data->Constellation->setPalette( palette() ); + Data->Mag->setPalette( palette() ); + Data->Distance->setPalette( palette() ); + Data->AngSize->setPalette( palette() ); + Data->InLabel->setPalette( palette() ); + Data->MagLabel->setPalette( palette() ); + Data->DistanceLabel->setPalette( palette() ); + Data->AngSizeLabel->setPalette( palette() ); + + //Show object thumbnail image + showThumbnail(); + + QVBoxLayout *vlay = new QVBoxLayout( DataTab, 0, 0 ); + vlay->addWidget( Data ); + + //Fill in the data fields + //Contents depend on type of object + StarObject *s = 0L; + DeepSkyObject *dso = 0L; + KSPlanetBase *ps = 0L; + QString pname(""), oname(""); + + switch ( selectedObject->type() ) { + case 0: //stars + s = (StarObject *)selectedObject; + + Data->Names->setText( s->longname() ); + Data->Type->setText( s->sptype() + " " + i18n("star") ); + Data->Mag->setText( i18n( "number in magnitudes", "%1 mag" ).arg( + KGlobal::locale()->formatNumber( s->mag(), 1 ) ) ); //show to tenths place + + //distance + if ( s->distance() > 2000. || s->distance() < 0. ) // parallax < 0.5 mas + Data->Distance->setText( QString(i18n("larger than 2000 parsecs", "> 2000 pc") ) ); + else if ( s->distance() > 50.0 ) //show to nearest integer + Data->Distance->setText( i18n( "number in parsecs", "%1 pc" ).arg( + QString::number( int( s->distance() + 0.5 ) ) ) ); + else if ( s->distance() > 10.0 ) //show to tenths place + Data->Distance->setText( i18n( "number in parsecs", "%1 pc" ).arg( + KGlobal::locale()->formatNumber( s->distance(), 1 ) ) ); + else //show to hundredths place + Data->Distance->setText( i18n( "number in parsecs", "%1 pc" ).arg( + KGlobal::locale()->formatNumber( s->distance(), 2 ) ) ); + + //Note multiplicity/variablility in angular size label + Data->AngSizeLabel->setText( "" ); + Data->AngSize->setText( "" ); + Data->AngSizeLabel->setFont( Data->AngSize->font() ); + if ( s->isMultiple() && s->isVariable() ) { + Data->AngSizeLabel->setText( i18n( "the star is a multiple star", "multiple" ) + "," ); + Data->AngSize->setText( i18n( "the star is a variable star", "variable" ) ); + } else if ( s->isMultiple() ) + Data->AngSizeLabel->setText( i18n( "the star is a multiple star", "multiple" ) ); + else if ( s->isVariable() ) + Data->AngSizeLabel->setText( i18n( "the star is a variable star", "variable" ) ); + + break; //end of stars case + + case 9: //asteroids [fall through to planets] + case 10: //comets [fall through to planets] + case 2: //planets (including comets and asteroids) + ps = (KSPlanetBase *)selectedObject; + + Data->Names->setText( ps->longname() ); + //Type is "G5 star" for Sun + if ( ps->name() == "Sun" ) + Data->Type->setText( i18n("G5 star") ); + else + Data->Type->setText( ps->typeName() ); + + Data->Constellation->setText( ps->constellation( ksw->data()->csegmentList, + ksw->data()->cnameList ) ); + + //Magnitude: The moon displays illumination fraction instead + if ( selectedObject->name() == "Moon" ) { + Data->MagLabel->setText( i18n("Illumination:") ); + Data->Mag->setText( QString("%1 %").arg( int( ((KSMoon *)selectedObject)->illum()*100. ) ) ); + } else { + Data->Mag->setText( i18n( "number in magnitudes", "%1 mag" ).arg( + KGlobal::locale()->formatNumber( ps->mag(), 1 ) ) ); //show to tenths place + } + + //Distance from Earth. The moon requires a unit conversion + if ( ps->name() == "Moon" ) { + Data->Distance->setText( i18n("distance in kilometers", "%1 km").arg( + KGlobal::locale()->formatNumber( ps->rearth()*AU_KM ) ) ); + } else { + Data->Distance->setText( i18n("distance in Astronomical Units", "%1 AU").arg( + KGlobal::locale()->formatNumber( ps->rearth() ) ) ); + } + + //Angular size; moon and sun in arcmin, others in arcsec + if ( ps->angSize() ) { + if ( ps->name() == "Sun" || ps->name() == "Moon" ) + Data->AngSize->setText( i18n("angular size in arcminutes", "%1 arcmin").arg( + KGlobal::locale()->formatNumber( ps->angSize() ) ) ); + else + Data->AngSize->setText( i18n("angular size in arcseconds", "%1 arcsec").arg( + KGlobal::locale()->formatNumber( ps->angSize()*60.0 ) ) ); + } else { + Data->AngSize->setText( "--" ); + } + + break; //end of planets/comets/asteroids case + + default: //deep-sky objects + dso = (DeepSkyObject *)selectedObject; + + //Show all names recorded for the object + if ( ! dso->longname().isEmpty() && dso->longname() != dso->name() ) { + pname = dso->translatedLongName(); + oname = dso->translatedName(); + } else { + pname = dso->translatedName(); + } + + if ( ! dso->translatedName2().isEmpty() ) { + if ( oname.isEmpty() ) oname = dso->translatedName2(); + else oname += ", " + dso->translatedName2(); + } + + if ( dso->ugc() != 0 ) { + if ( ! oname.isEmpty() ) oname += ", "; + oname += "UGC " + QString("%1").arg( dso->ugc() ); + } + if ( dso->pgc() != 0 ) { + if ( ! oname.isEmpty() ) oname += ", "; + oname += "PGC " + QString("%1").arg( dso->pgc() ); + } + + if ( ! oname.isEmpty() ) pname += ", " + oname; + Data->Names->setText( pname ); + + Data->Type->setText( dso->typeName() ); + + if ( dso->mag() > 90.0 ) + Data->Mag->setText( "--" ); + else + Data->Mag->setText( i18n( "number in magnitudes", "%1 mag" ).arg( + KGlobal::locale()->formatNumber( dso->mag(), 1 ) ) ); //show to tenths place + + //No distances at this point... + Data->Distance->setText( "--" ); + + //Only show decimal place for small angular sizes + if ( dso->a() > 10.0 ) + Data->AngSize->setText( i18n("angular size in arcminutes", "%1 arcmin").arg( + int( dso->a() ) ) ); + else if ( dso->a() ) + Data->AngSize->setText( i18n("angular size in arcminutes", "%1 arcmin").arg( + KGlobal::locale()->formatNumber( dso->a(), 1 ) ) ); + else + Data->AngSize->setText( "--" ); + + break; + } + + //Common to all types: + Data->Constellation->setText( selectedObject->constellation( ksw->data()->csegmentList, + ksw->data()->cnameList ) ); +} + +void DetailDialog::createPositionTab( const KStarsDateTime &ut, GeoLocation *geo ) { + QFrame *PosTab = addPage( i18n("Position") ); + Pos = new DetailsPositionUI( PosTab, "position_tab" ); + + //Modify colors + Pos->CoordTitle->setPaletteBackgroundColor( palette().color( QPalette::Active, QColorGroup::Highlight ) ); + Pos->CoordTitle->setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::HighlightedText ) ); + Pos->CoordFrame->setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::Highlight ) ); + Pos->RSTTitle->setPaletteBackgroundColor( palette().color( QPalette::Active, QColorGroup::Highlight ) ); + Pos->RSTTitle->setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::HighlightedText ) ); + Pos->RSTFrame->setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::Highlight ) ); + Pos->RA->setPalette( palette() ); + Pos->Dec->setPalette( palette() ); + Pos->Az->setPalette( palette() ); + Pos->Alt->setPalette( palette() ); + Pos->HA->setPalette( palette() ); + Pos->Airmass->setPalette( palette() ); + Pos->TimeRise->setPalette( palette() ); + Pos->TimeTransit->setPalette( palette() ); + Pos->TimeSet->setPalette( palette() ); + Pos->AzRise->setPalette( palette() ); + Pos->AltTransit->setPalette( palette() ); + Pos->AzSet->setPalette( palette() ); + Pos->RALabel->setPalette( palette() ); + Pos->DecLabel->setPalette( palette() ); + Pos->AzLabel->setPalette( palette() ); + Pos->AltLabel->setPalette( palette() ); + Pos->HALabel->setPalette( palette() ); + Pos->AirmassLabel->setPalette( palette() ); + Pos->TimeRiseLabel->setPalette( palette() ); + Pos->TimeTransitLabel->setPalette( palette() ); + Pos->TimeSetLabel->setPalette( palette() ); + Pos->AzRiseLabel->setPalette( palette() ); + Pos->AltTransitLabel->setPalette( palette() ); + Pos->AzSetLabel->setPalette( palette() ); + + QVBoxLayout *vlay = new QVBoxLayout( PosTab, 0, 0 ); + vlay->addWidget( Pos ); + + //Coordinates Section: + //Don't use KLocale::formatNumber() for the epoch string, + //because we don't want a thousands-place separator! + QString sEpoch = QString::number( ut.epoch(), 'f', 1 ); + //Replace the decimal point with localized decimal symbol + sEpoch.replace( ".", KGlobal::locale()->decimalSymbol() ); + + Pos->RALabel->setText( i18n( "RA (%1):" ).arg( sEpoch ) ); + Pos->DecLabel->setText( i18n( "Dec (%1):" ).arg( sEpoch ) ); + Pos->RA->setText( selectedObject->ra()->toHMSString() ); + Pos->Dec->setText( selectedObject->dec()->toDMSString() ); + Pos->Az->setText( selectedObject->az()->toDMSString() ); + Pos->Alt->setText( selectedObject->alt()->toDMSString() ); + + //Hour Angle can be negative, but dms HMS expressions cannot. + //Here's a kludgy workaround: + dms lst = geo->GSTtoLST( ut.gst() ); + dms ha( lst.Degrees() - selectedObject->ra()->Degrees() ); + QChar sgn('+'); + if ( ha.Hours() > 12.0 ) { + ha.setH( 24.0 - ha.Hours() ); + sgn = '-'; + } + Pos->HA->setText( QString("%1%2").arg(sgn).arg( ha.toHMSString() ) ); + + //Airmass is approximated as the secant of the zenith distance, + //equivalent to 1./sin(Alt). Beware of Inf at Alt=0! + if ( selectedObject->alt()->Degrees() > 0.0 ) + Pos->Airmass->setText( KGlobal::locale()->formatNumber( + 1./sin( selectedObject->alt()->radians() ), 2 ) ); + else + Pos->Airmass->setText( "--" ); + + //Rise/Set/Transit Section: + + //Prepare time/position variables + QTime rt = selectedObject->riseSetTime( ut, geo, true ); //true = use rise time + dms raz = selectedObject->riseSetTimeAz( ut, geo, true ); //true = use rise time + + //If transit time is before rise time, use transit time for tomorrow + QTime tt = selectedObject->transitTime( ut, geo ); + dms talt = selectedObject->transitAltitude( ut, geo ); + if ( tt < rt ) { + tt = selectedObject->transitTime( ut.addDays( 1 ), geo ); + talt = selectedObject->transitAltitude( ut.addDays( 1 ), geo ); + } + + //If set time is before rise time, use set time for tomorrow + QTime st = selectedObject->riseSetTime( ut, geo, false ); //false = use set time + dms saz = selectedObject->riseSetTimeAz( ut, geo, false ); //false = use set time + if ( st < rt ) { + st = selectedObject->riseSetTime( ut.addDays( 1 ), geo, false ); //false = use set time + saz = selectedObject->riseSetTimeAz( ut.addDays( 1 ), geo, false ); //false = use set time + } + + if ( rt.isValid() ) { + Pos->TimeRise->setText( QString().sprintf( "%02d:%02d", rt.hour(), rt.minute() ) ); + Pos->TimeSet->setText( QString().sprintf( "%02d:%02d", st.hour(), st.minute() ) ); + Pos->AzRise->setText( raz.toDMSString() ); + Pos->AzSet->setText( saz.toDMSString() ); + } else { + if ( selectedObject->alt()->Degrees() > 0.0 ) { + Pos->TimeRise->setText( i18n( "Circumpolar" ) ); + Pos->TimeSet->setText( i18n( "Circumpolar" ) ); + } else { + Pos->TimeRise->setText( i18n( "Never rises" ) ); + Pos->TimeSet->setText( i18n( "Never rises" ) ); + } + + Pos->AzRise->setText( i18n( "Not Applicable", "N/A" ) ); + Pos->AzSet->setText( i18n( "Not Applicable", "N/A" ) ); + } + + Pos->TimeTransit->setText( QString().sprintf( "%02d:%02d", tt.hour(), tt.minute() ) ); + Pos->AltTransit->setText( talt.toDMSString() ); +} + +void DetailDialog::createLinksTab() +{ + // don't create a link tab for an unnamed star + if (selectedObject->name() == QString("star")) + return; + + QFrame *LinksTab = addPage( i18n( "Links" ) ); + Links = new DetailsLinksUI( LinksTab, "links_tab" ); + + //Modify colors + Links->InfoTitle->setPaletteBackgroundColor( palette().color( QPalette::Active, QColorGroup::Text ) ); + Links->InfoTitle->setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::Base ) ); + Links->ImagesTitle->setPaletteBackgroundColor( palette().color( QPalette::Active, QColorGroup::Text ) ); + Links->ImagesTitle->setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::Base ) ); + + QPalette p = palette(); + p.setColor( QPalette::Active, QColorGroup::Dark, palette().color( QPalette::Active, QColorGroup::Highlight ) ); + Links->InfoList->setPalette( p ); + Links->ImagesList->setPalette( p ); + + QVBoxLayout *vlay = new QVBoxLayout( LinksTab, 0, 0 ); + vlay->addWidget( Links ); + + QStringList::Iterator itList = selectedObject->InfoList.begin(); + QStringList::Iterator itTitle = selectedObject->InfoTitle.begin(); + QStringList::Iterator itListEnd = selectedObject->InfoList.end(); + + for ( ; itList != itListEnd; ++itList ) { + Links->InfoList->insertItem(QString(*itTitle)); + itTitle++; + } + + Links->InfoList->setSelected(0, true); + + itList = selectedObject->ImageList.begin(); + itTitle = selectedObject->ImageTitle.begin(); + itListEnd = selectedObject->ImageList.end(); + + for ( ; itList != itListEnd; ++itList ) { + Links->ImagesList->insertItem(QString(*itTitle)); + itTitle++; + } + + if (! Links->InfoList->count() && ! Links->ImagesList->count()) { + Links->EditLinkButton->setDisabled(true); + Links->RemoveLinkButton->setDisabled(true); + } + + // Signals/Slots + connect( Links->ViewButton, SIGNAL(clicked()), this, SLOT( viewLink() ) ); + connect( Links->AddLinkButton, SIGNAL(clicked()), ksw->map(), SLOT( addLink() ) ); + connect( Links->EditLinkButton, SIGNAL(clicked()), this, SLOT( editLinkDialog() ) ); + connect( Links->RemoveLinkButton, SIGNAL(clicked()), this, SLOT( removeLinkDialog() ) ); + connect( Links->InfoList, SIGNAL(highlighted(int)), this, SLOT( unselectImagesList() ) ); + connect( Links->ImagesList, SIGNAL(highlighted(int)), this, SLOT( unselectInfoList() ) ); + connect( ksw->map(), SIGNAL(linkAdded()), this, SLOT( updateLists() ) ); +} + +void DetailDialog::createAdvancedTab() +{ + // Don't create an adv tab for an unnamed star or if advinterface file failed loading + // We also don't need adv dialog for solar system objects. + if (selectedObject->name() == QString("star") || + ksw->data()->ADVtreeList.isEmpty() || + selectedObject->type() == SkyObject::PLANET || + selectedObject->type() == SkyObject::COMET || + selectedObject->type() == SkyObject::ASTEROID ) + return; + + QFrame *AdvancedTab = addPage(i18n("Advanced")); + Adv = new DetailsDatabaseUI( AdvancedTab, "database_tab" ); +// Adv->setPaletteBackgroundColor( QColor( "white" ) ); + QVBoxLayout *vlay = new QVBoxLayout( AdvancedTab, 0, 0 ); + vlay->addWidget( Adv ); + + treeIt = new QPtrListIterator<ADVTreeData> (ksw->data()->ADVtreeList); + connect( Adv->ADVTree, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(viewADVData())); + + populateADVTree(NULL); +} + +void DetailDialog::createLogTab() +{ + //Don't create a a log tab for an unnamed star + if (selectedObject->name() == QString("star")) + return; + + // Log Tab + QFrame *LogTab = addPage(i18n("Log")); + Log = new DetailsLogUI( LogTab, "log_tab" ); + + //Modify colors + Log->LogTitle->setPaletteBackgroundColor( palette().color( QPalette::Active, QColorGroup::Text ) ); + Log->LogTitle->setPaletteForegroundColor( palette().color( QPalette::Active, QColorGroup::Base ) ); + + QVBoxLayout *vlay = new QVBoxLayout( LogTab, 0, 0 ); + vlay->addWidget( Log ); + + if ( selectedObject->userLog.isEmpty() ) + Log->UserLog->setText(i18n("Record here observation logs and/or data on %1.").arg(selectedObject->translatedName())); + else + Log->UserLog->setText(selectedObject->userLog); + + //Automatically save the log contents when the widget loses focus + connect( Log->UserLog, SIGNAL( focusOut() ), this, SLOT( saveLogData() ) ); +} + + +void DetailDialog::unselectInfoList() +{ + Links->InfoList->setSelected( Links->InfoList->currentItem(), false ); +} + +void DetailDialog::unselectImagesList() +{ + Links->ImagesList->setSelected( Links->ImagesList->currentItem(), false ); +} + +void DetailDialog::viewLink() +{ + QString URL; + + if ( Links->InfoList->currentItem() != -1 && + Links->InfoList->isSelected( Links->InfoList->currentItem() ) ) + URL = QString( *selectedObject->InfoList.at( Links->InfoList->currentItem() ) ); + else if ( Links->ImagesList->currentItem() != -1 ) + URL = QString( *selectedObject->ImageList.at( Links->ImagesList->currentItem() ) ); + + if (!URL.isEmpty()) + kapp->invokeBrowser(URL); +} + +void DetailDialog::updateLists() +{ + Links->InfoList->clear(); + Links->ImagesList->clear(); + + QStringList::Iterator itList = selectedObject->InfoList.begin(); + QStringList::Iterator itTitle = selectedObject->InfoTitle.begin(); + QStringList::Iterator itListEnd = selectedObject->InfoList.end(); + + for ( ; itList != itListEnd; ++itList ) { + Links->InfoList->insertItem(QString(*itTitle)); + itTitle++; + } + + Links->InfoList->setSelected(0, true); + itList = selectedObject->ImageList.begin(); + itTitle = selectedObject->ImageTitle.begin(); + itListEnd = selectedObject->ImageList.end(); + + for ( ; itList != itListEnd; ++itList ) { + Links->ImagesList->insertItem(QString(*itTitle)); + itTitle++; + } +} + +void DetailDialog::editLinkDialog() +{ + int type; + uint i; + QString defaultURL , entry; + QFile newFile; + + KDialogBase editDialog(KDialogBase::Plain, i18n("Edit Link"), Ok|Cancel, Ok , this, "editlink", false); + QFrame *editFrame = editDialog.plainPage(); + + editLinkURL = new QLabel(i18n("URL:"), editFrame); + editLinkField = new QLineEdit(editFrame, "lineedit"); + editLinkField->setMinimumWidth(300); + editLinkField->home(false); + editLinkLayout = new QHBoxLayout(editFrame, 6, 6, "editlinklayout"); + editLinkLayout->addWidget(editLinkURL); + editLinkLayout->addWidget(editLinkField); + + currentItemIndex = Links->InfoList->currentItem(); + + if (currentItemIndex != -1 && Links->InfoList->isSelected(currentItemIndex)) + { + defaultURL = *selectedObject->InfoList.at(currentItemIndex); + editLinkField->setText(defaultURL); + type = 1; + currentItemTitle = Links->InfoList->currentText(); + } + else if ( (currentItemIndex = Links->ImagesList->currentItem()) != -1) + { + defaultURL = *selectedObject->ImageList.at(currentItemIndex); + editLinkField->setText(defaultURL); + type = 0; + currentItemTitle = Links->ImagesList->currentText(); + } + else return; + + // If user presses cancel then return + if (!editDialog.exec() == QDialog::Accepted) + return; + // if it wasn't edit, don't do anything + if (!editLinkField->edited()) + return; + + // Save the URL of the current item + currentItemURL = editLinkField->text(); + entry = selectedObject->name() + ":" + currentItemTitle + ":" + currentItemURL; + + //FIXME: usage of verifyUserData() is pretty unclear + //verifyUserData() returns false if currentItemTitle/currentItemURL + //are not found in the user's list already. If they are, then that + //item is removed. + switch (type) + { + case 0: + if (!verifyUserData(type)) + return; + break; + case 1: + if (!verifyUserData(type)) + return; + break; + } + + // Open a new file with the same name and copy all data along with changes + newFile.setName(file.name()); + newFile.open(IO_WriteOnly); + + QTextStream newStream(&newFile); + + for (i=0; i<dataList.count(); i++) + { + newStream << dataList[i] << endl; + continue; + } + + if (type==0) + { + *selectedObject->ImageTitle.at(currentItemIndex) = currentItemTitle; + *selectedObject->ImageList.at(currentItemIndex) = currentItemURL; + } + else + { + *selectedObject->InfoTitle.at(currentItemIndex) = currentItemTitle; + *selectedObject->InfoList.at(currentItemIndex) = currentItemURL; + } + + newStream << entry << endl; + + newFile.close(); + file.close(); + updateLists(); +} + +void DetailDialog::removeLinkDialog() +{ + int type; + uint i; + QString defaultURL, entry; + QFile newFile; + + currentItemIndex = Links->InfoList->currentItem(); + + if (currentItemIndex != -1 && Links->InfoList->isSelected(currentItemIndex)) + { + defaultURL = *selectedObject->InfoList.at(currentItemIndex); + type = 1; + currentItemTitle = Links->InfoList->currentText(); + } + else + { + currentItemIndex = Links->ImagesList->currentItem(); + defaultURL = *selectedObject->ImageList.at(currentItemIndex); + type = 0; + currentItemTitle = Links->ImagesList->currentText(); + } + + if (KMessageBox::warningContinueCancel( 0, i18n("Are you sure you want to remove the %1 link?").arg(currentItemTitle), i18n("Delete Confirmation"),KStdGuiItem::del())!=KMessageBox::Continue) + return; + + switch (type) + { + case 0: + if (!verifyUserData(type)) + return; + selectedObject->ImageTitle.remove( selectedObject->ImageTitle.at(currentItemIndex)); + selectedObject->ImageList.remove( selectedObject->ImageList.at(currentItemIndex)); + break; + + case 1: + if (!verifyUserData(type)) + return; + selectedObject->InfoTitle.remove(selectedObject->InfoTitle.at(currentItemIndex)); + selectedObject->InfoList.remove(selectedObject->InfoList.at(currentItemIndex)); + break; + } + + // Open a new file with the same name and copy all data along with changes + newFile.setName(file.name()); + newFile.open(IO_WriteOnly); + + QTextStream newStream(&newFile); + + for (i=0; i<dataList.count(); i++) + newStream << dataList[i] << endl; + + newFile.close(); + file.close(); + updateLists(); +} + +bool DetailDialog::verifyUserData(int type) +{ + QString line, name, sub, title; + bool ObjectFound = false; + uint i; + + switch (type) + { + case 0: + if (!readUserFile(type)) + return false; + for (i=0; i<dataList.count(); i++) + { + line = dataList[i]; + name = line.mid( 0, line.find(':') ); + sub = line.mid( line.find(':')+1 ); + title = sub.mid( 0, sub.find(':') ); + if (name == selectedObject->name() && title == currentItemTitle) + { + ObjectFound = true; + dataList.remove(dataList.at(i)); + break; + } + } + break; + case 1: + if (!readUserFile(type)) + return false; + for (i=0; i<dataList.count(); i++) + { + line = dataList[i]; + name = line.mid( 0, line.find(':') ); + sub = line.mid( line.find(':')+1 ); + title = sub.mid( 0, sub.find(':') ); + if (name == selectedObject->name() && title == currentItemTitle) + { + ObjectFound = true; + dataList.remove(dataList.at(i)); + break; + } + } + break; + } + return ObjectFound; +} + +bool DetailDialog::readUserFile(int type)//, int sourceFileType) +{ + switch (type) + { + case 0: + file.setName( locateLocal( "appdata", "image_url.dat" ) ); //determine filename + if ( !file.open( IO_ReadOnly) ) + { + ksw->data()->initError("image_url.dat", false); + return false; + } + break; + + case 1: + file.setName( locateLocal( "appdata", "info_url.dat" ) ); //determine filename + if ( !file.open( IO_ReadOnly) ) + { + ksw->data()->initError("info_url.dat", false); + return false; + } + break; + } + + // Must reset file + file.reset(); + QTextStream stream(&file); + + dataList.clear(); + + // read all data into memory + while (!stream.eof()) + dataList.append(stream.readLine()); + + return true; +} + +void DetailDialog::populateADVTree(QListViewItem *parent) +{ + // list done + if (!treeIt->current()) + return; + + // if relative top level [KSLABEL] + if (treeIt->current()->Type == 0) + forkTree(parent); + + while (treeIt->current()) + { + if (treeIt->current()->Type == 0) + { + forkTree(parent); + continue; + } + else if (treeIt->current()->Type == 1) + break; + + if (parent) + new QListViewItem( parent, treeIt->current()->Name); + else + new QListViewItem( Adv->ADVTree, treeIt->current()->Name); + + ++(*treeIt); + } +} + +void DetailDialog::forkTree(QListViewItem *parent) +{ + QListViewItem *current = 0; + if (parent) + current = new QListViewItem(parent, treeIt->current()->Name); + else + current = new QListViewItem(Adv->ADVTree, treeIt->current()->Name); + + // we need to increment the iterator before and after populating the tree + ++(*treeIt); + populateADVTree(current); + ++(*treeIt); +} + +void DetailDialog::viewADVData() +{ + QString link; + QListViewItem * current = Adv->ADVTree->currentItem(); + + if (!current) return; + + treeIt->toFirst(); + while (treeIt->current()) + { + if (treeIt->current()->Name == current->text(0)) + { + if (treeIt->current()->Type == 2) break; + else return; + } + ++(*treeIt); + } + + link = treeIt->current()->Link; + link = parseADVData(link); + kapp->invokeBrowser(link); +} + +QString DetailDialog::parseADVData(QString link) +{ + QString subLink; + int index; + + if ( (index = link.find("KSOBJ")) != -1) + { + link.remove(index, 5); + link = link.insert(index, selectedObject->name()); + } + + if ( (index = link.find("KSRA")) != -1) + { + link.remove(index, 4); + subLink = QString().sprintf("%02d%02d%02d", selectedObject->ra0()->hour(), selectedObject->ra0()->minute(), selectedObject->ra0()->second()); + subLink = subLink.insert(2, "%20"); + subLink = subLink.insert(7, "%20"); + + link = link.insert(index, subLink); + } + if ( (index = link.find("KSDEC")) != -1) + { + link.remove(index, 5); + if (selectedObject->dec()->degree() < 0) + { + subLink = QString().sprintf("%03d%02d%02d", selectedObject->dec0()->degree(), selectedObject->dec0()->arcmin(), selectedObject->dec0()->arcsec()); + subLink = subLink.insert(3, "%20"); + subLink = subLink.insert(8, "%20"); + } + else + { + subLink = QString().sprintf("%02d%02d%02d", selectedObject->dec0()->degree(), selectedObject->dec0()->arcmin(), selectedObject->dec0()->arcsec()); + subLink = subLink.insert(0, "%2B"); + subLink = subLink.insert(5, "%20"); + subLink = subLink.insert(10, "%20"); + } + link = link.insert(index, subLink); + } + + return link; +} + +void DetailDialog::saveLogData() { + selectedObject->saveUserLog( Log->UserLog->text() ); +} + +void DetailDialog::addToObservingList() { + ksw->observingList()->slotAddObject( selectedObject ); +} + +void DetailDialog::centerMap() { + ksw->map()->setClickedObject( selectedObject ); + ksw->map()->slotCenter(); +} + +void DetailDialog::centerTelescope() +{ + + INDI_D *indidev(NULL); + INDI_P *prop(NULL), *onset(NULL); + INDI_E *RAEle(NULL), *DecEle(NULL), *AzEle(NULL), *AltEle(NULL), *ConnectEle(NULL), *nameEle(NULL); + bool useJ2000( false); + int selectedCoord(0); + SkyPoint sp; + + // Find the first device with EQUATORIAL_EOD_COORD or EQUATORIAL_COORD and with SLEW element + // i.e. the first telescope we find! + + INDIMenu *imenu = ksw->getINDIMenu(); + + + for (unsigned int i=0; i < imenu->mgr.count() ; i++) + { + for (unsigned int j=0; j < imenu->mgr.at(i)->indi_dev.count(); j++) + { + indidev = imenu->mgr.at(i)->indi_dev.at(j); + indidev->stdDev->currentObject = NULL; + prop = indidev->findProp("EQUATORIAL_EOD_COORD"); + if (prop == NULL) + { + prop = indidev->findProp("EQUATORIAL_COORD"); + if (prop == NULL) + { + prop = indidev->findProp("HORIZONTAL_COORD"); + if (prop == NULL) + continue; + else + selectedCoord = 1; /* Select horizontal */ + } + else + useJ2000 = true; + } + + ConnectEle = indidev->findElem("CONNECT"); + if (!ConnectEle) continue; + + if (ConnectEle->state == PS_OFF) + { + KMessageBox::error(0, i18n("Telescope %1 is offline. Please connect and retry again.").arg(indidev->label)); + return; + } + + switch (selectedCoord) + { + // Equatorial + case 0: + if (prop->perm == PP_RO) continue; + RAEle = prop->findElement("RA"); + if (!RAEle) continue; + DecEle = prop->findElement("DEC"); + if (!DecEle) continue; + break; + + // Horizontal + case 1: + if (prop->perm == PP_RO) continue; + AzEle = prop->findElement("AZ"); + if (!AzEle) continue; + AltEle = prop->findElement("ALT"); + if (!AltEle) continue; + break; + } + + onset = indidev->findProp("ON_COORD_SET"); + if (!onset) continue; + + onset->activateSwitch("SLEW"); + + indidev->stdDev->currentObject = selectedObject; + + /* Send object name if available */ + if (indidev->stdDev->currentObject) + { + nameEle = indidev->findElem("OBJECT_NAME"); + if (nameEle && nameEle->pp->perm != PP_RO) + { + nameEle->write_w->setText(indidev->stdDev->currentObject->name()); + nameEle->pp->newText(); + } + } + + switch (selectedCoord) + { + case 0: + if (indidev->stdDev->currentObject) + sp.set (indidev->stdDev->currentObject->ra(), indidev->stdDev->currentObject->dec()); + else + sp.set (ksw->map()->clickedPoint()->ra(), ksw->map()->clickedPoint()->dec()); + + if (useJ2000) + sp.apparentCoord(ksw->data()->ut().djd(), (long double) J2000); + + RAEle->write_w->setText(QString("%1:%2:%3").arg(sp.ra()->hour()).arg(sp.ra()->minute()).arg(sp.ra()->second())); + DecEle->write_w->setText(QString("%1:%2:%3").arg(sp.dec()->degree()).arg(sp.dec()->arcmin()).arg(sp.dec()->arcsec())); + + break; + + case 1: + if (indidev->stdDev->currentObject) + { + sp.setAz(*indidev->stdDev->currentObject->az()); + sp.setAlt(*indidev->stdDev->currentObject->alt()); + } + else + { + sp.setAz(*ksw->map()->clickedPoint()->az()); + sp.setAlt(*ksw->map()->clickedPoint()->alt()); + } + + AzEle->write_w->setText(QString("%1:%2:%3").arg(sp.az()->degree()).arg(sp.az()->arcmin()).arg(sp.az()->arcsec())); + AltEle->write_w->setText(QString("%1:%2:%3").arg(sp.alt()->degree()).arg(sp.alt()->arcmin()).arg(sp.alt()->arcsec())); + + break; + } + + prop->newText(); + + return; + } + } + + // We didn't find any telescopes + KMessageBox::sorry(0, i18n("KStars did not find any active telescopes.")); + +} + +void DetailDialog::showThumbnail() { + //No image if object is a star + if ( selectedObject->type() == SkyObject::STAR || + selectedObject->type() == SkyObject::CATALOG_STAR ) { + Thumbnail->resize( Data->Image->width(), Data->Image->height() ); + Thumbnail->fill( Data->paletteBackgroundColor() ); + Data->Image->setPixmap( *Thumbnail ); + return; + } + + //Try to load the object's image from disk + //If no image found, load "no image" image + //If that isn't found, make it blank. + QFile file; + QString fname = "thumb-" + selectedObject->name().lower().replace( QRegExp(" "), "" ) + ".png"; + if ( KSUtils::openDataFile( file, fname ) ) { + file.close(); + Thumbnail->load( file.name(), "PNG" ); + } else if ( KSUtils::openDataFile( file, "noimage.png" ) ) { + file.close(); + Thumbnail->load( file.name(), "PNG" ); + } else { + Thumbnail->resize( Data->Image->width(), Data->Image->height() ); + Thumbnail->fill( Data->paletteBackgroundColor() ); + } + + Data->Image->setPixmap( *Thumbnail ); +} + +void DetailDialog::updateThumbnail() { + ThumbnailPicker tp( selectedObject, *Thumbnail, this, "thumbnaileditor" ); + + if ( tp.exec() == QDialog::Accepted ) { + QString fname = locateLocal( "appdata", "thumb-" + + selectedObject->name().lower().replace( QRegExp(" "), "" ) + ".png" ); + + Data->Image->setPixmap( *(tp.image()) ); + + //If a real image was set, save it. + //If the image was unset, delete the old image on disk. + if ( tp.imageFound() ) { + Data->Image->pixmap()->save( fname, "PNG" ); + *Thumbnail = *(Data->Image->pixmap()); + } else { + QFile f; + f.setName( fname ); + f.remove(); + } + } +} + +#include "detaildialog.moc" |