• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kstars

kstarsdata.cpp

Go to the documentation of this file.
00001  /***************************************************************************
00002                           kstarsdata.cpp  -  K Desktop Planetarium
00003                              -------------------
00004     begin                : Sun Jul 29 2001
00005     copyright            : (C) 2001 by Heiko Evermann
00006     email                : heiko@evermann.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include <qregexp.h>
00019 #include <qdir.h>
00020 #include <qfile.h>
00021 
00022 #include <kapplication.h>
00023 #include <kmessagebox.h>
00024 #include <kdebug.h>
00025 #include <klocale.h>
00026 #include <kstandarddirs.h>
00027 
00028 #include "kstarsdata.h"
00029 
00030 #include "Options.h"
00031 #include "dms.h"
00032 #include "skymap.h"
00033 #include "ksutils.h"
00034 #include "ksnumbers.h"
00035 #include "skypoint.h"
00036 #include "skyobject.h"
00037 #include "starobject.h"
00038 #include "deepskyobject.h"
00039 #include "skyobjectname.h"
00040 #include "ksplanet.h"
00041 #include "ksasteroid.h"
00042 #include "kscomet.h"
00043 #include "ksmoon.h"
00044 #include "jupitermoons.h"
00045 
00046 #include "simclock.h"
00047 #include "timezonerule.h"
00048 #include "filesource.h"
00049 #include "stardatasink.h"
00050 #include "ksfilereader.h"
00051 #include "indidriver.h"
00052 #include "indi/lilxml.h"
00053 #include "indistd.h"
00054 #include "detaildialog.h"
00055 #include "csegment.h"
00056 #include "customcatalog.h"
00057 
00058 QPtrList<GeoLocation> KStarsData::geoList = QPtrList<GeoLocation>();
00059 QMap<QString, TimeZoneRule> KStarsData::Rulebook = QMap<QString, TimeZoneRule>();
00060 QStringList KStarsData::CustomColumns = QStringList::split( " ", "ID RA Dc Tp Nm Mg Mj Mn PA Ig" );
00061 int KStarsData::objects = 0;
00062 
00063 KStarsData::KStarsData() : stdDirs(0), locale(0), 
00064         LST(0), HourAngle(0),
00065         PCat(0), Moon(0), jmoons(0),
00066         starFileReader(0), initTimer(0),
00067         source(0), loader(0), pump(0)
00068 {
00069     startupComplete = false;
00070     objects++;
00071 
00072     //standard directories and locale objects
00073     stdDirs = new KStandardDirs();
00074     locale = new KLocale( "kstars" );
00075 
00076     //Check to see if config file already exists.  If not, set 
00077     //useDefaultOptions = true
00078     QString fname = locateLocal( "config", "kstarsrc" );
00079     useDefaultOptions = ! ( QFile(fname).exists() );
00080 
00081     //Instantiate LST and HourAngle
00082     LST = new dms();
00083     HourAngle = new dms();
00084     
00085     //Instantiate planet catalog
00086     PCat = new PlanetCatalog(this);
00087 
00088     //initialize FOV symbol
00089     fovSymbol = FOV();
00090 
00091     //set AutoDelete property for QPtrLists.  Most are set TRUE,
00092     //but some 'meta-lists' need to be FALSE.
00093     starList.setAutoDelete( TRUE );
00094     ADVtreeList.setAutoDelete( TRUE );
00095     geoList.setAutoDelete( TRUE );
00096     deepSkyList.setAutoDelete( TRUE );        // list of all deep space objects
00097 
00098     //separate lists for each deep-sky catalog.  The objects are duplicates of
00099     //deepSkyList, so do not delete them twice!
00100     deepSkyListMessier.setAutoDelete( FALSE );
00101     deepSkyListNGC.setAutoDelete( FALSE );
00102     deepSkyListIC.setAutoDelete( FALSE );
00103     deepSkyListOther.setAutoDelete( FALSE );
00104 
00105     //ObjLabelList does not construct new objects, so no autoDelete needed
00106     ObjLabelList.setAutoDelete( FALSE );
00107 
00108     cometList.setAutoDelete( TRUE );
00109     asteroidList.setAutoDelete( TRUE );
00110 
00111     //Constellation lines are now pointers to existing StarObjects;
00112     //these are already auto-deleted by starList.
00113     clineList.setAutoDelete( FALSE );
00114     clineModeList.setAutoDelete( TRUE );
00115     cnameList.setAutoDelete( TRUE );
00116     csegmentList.setAutoDelete( TRUE );
00117 
00118     Equator.setAutoDelete( TRUE );
00119     Ecliptic.setAutoDelete( TRUE );
00120     Horizon.setAutoDelete( TRUE );
00121     for ( unsigned int i=0; i<11; ++i ) MilkyWay[i].setAutoDelete( TRUE );
00122 
00123     VariableStarsList.setAutoDelete(TRUE);
00124     INDIHostsList.setAutoDelete(TRUE);
00125     INDITelescopeList.setAutoDelete(TRUE);
00126 
00127     //Initialize object type strings
00128     TypeName[0] = i18n( "star" );
00129     TypeName[1] = i18n( "multiple star" );
00130     TypeName[2] = i18n( "planet" );
00131     TypeName[3] = i18n( "open cluster" );
00132     TypeName[4] = i18n( "globular cluster" );
00133     TypeName[5] = i18n( "gaseous nebula" );
00134     TypeName[6] = i18n( "planetary nebula" );
00135     TypeName[7] = i18n( "supernova remnant" );
00136     TypeName[8] = i18n( "galaxy" );
00137     TypeName[9] = i18n( "comet" );
00138     TypeName[10] = i18n( "asteroid" );
00139     TypeName[11] = i18n( "constellation" );
00140 
00141     // at startup times run forward
00142     setTimeDirection( 0.0 );
00143 
00144     //The StoredDate is used when saving user settings in a script; initialize to invalid date
00145     StoredDate.setDJD( (long double)INVALID_DAY );
00146 
00147     temporaryTrail = false;
00148 }
00149 
00150 KStarsData::~KStarsData() {
00151     objects--;
00152     checkDataPumpAction();
00153 
00154     // the list items do not need to be removed by hand.
00155     // all lists are set to AutoDelete = true
00156 
00157     delete stdDirs;
00158     delete Moon;
00159     delete locale;
00160     delete PCat;
00161     delete jmoons;
00162     delete initTimer;
00163 }
00164 
00165 bool KStarsData::readMWData( void ) {
00166     QFile file;
00167 
00168     for ( unsigned int i=0; i<11; ++i ) {
00169         QString snum, fname, szero;
00170         snum = snum.setNum( i+1 );
00171         if ( i+1 < 10 ) szero = "0"; else szero = "";
00172         fname = "mw" + szero + snum + ".dat";
00173 
00174         if ( KSUtils::openDataFile( file, fname ) ) {
00175             KSFileReader fileReader( file ); // close file is included
00176             while ( fileReader.hasMoreLines() ) {
00177                 QString line;
00178                 double ra, dec;
00179 
00180                 line = fileReader.readLine();
00181 
00182                 ra = line.mid( 0, 8 ).toDouble();
00183                 dec = line.mid( 9, 8 ).toDouble();
00184 
00185                 SkyPoint *o = new SkyPoint( ra, dec );
00186                 MilkyWay[i].append( o );
00187             }
00188         } else {
00189             return false;
00190         }
00191     }
00192     return true;
00193 }
00194 
00195 bool KStarsData::readADVTreeData(void)
00196 {
00197 
00198   QFile file;
00199   QString Interface;
00200 
00201   if (!KSUtils::openDataFile(file, "advinterface.dat"))
00202    return false;
00203 
00204    QTextStream stream(&file);
00205    QString Line;
00206 
00207   while  (!stream.atEnd())
00208   {
00209     QString Name, Link, subName;
00210     int Type, interfaceIndex;
00211 
00212     Line = stream.readLine();
00213 
00214     if (Line.startsWith("[KSLABEL]"))
00215     {
00216        Name = Line.mid(9);
00217        Type = 0;
00218     }
00219     else if (Line.startsWith("[END]"))
00220        Type = 1;
00221     else if (Line.startsWith("[KSINTERFACE]"))
00222     {
00223       Interface = Line.mid(13);
00224       continue;
00225     }
00226 
00227     else
00228     {
00229       Name = Line.mid(0, Line.find(":"));
00230       Link = Line.mid(Line.find(":") + 1);
00231 
00232       // Link is empty, using Interface instead
00233       if (Link.isEmpty())
00234       {
00235          Link = Interface;
00236          subName = Name;
00237          interfaceIndex = Link.find("KSINTERFACE");
00238          Link.remove(interfaceIndex, 11);
00239          Link = Link.insert(interfaceIndex, subName.replace( QRegExp(" "), "+"));
00240 
00241        }
00242 
00243       Type = 2;
00244     }
00245 
00246     ADVTreeData *ADVData = new ADVTreeData;
00247 
00248     ADVData->Name = Name;
00249     ADVData->Link = Link;
00250     ADVData->Type = Type;
00251 
00252     ADVtreeList.append(ADVData);
00253    }
00254 
00255    return true;
00256 
00257 
00258 
00259 }
00260 
00261 bool KStarsData::readVARData(void)
00262 {
00263   QString varFile("valaav.txt");
00264   QFile localeFile;
00265   QFile file;
00266 
00267   file.setName( locateLocal( "appdata", varFile ) );
00268         if ( !file.open( IO_ReadOnly ) )
00269         {
00270             // Open default variable stars file
00271             if ( KSUtils::openDataFile( file, varFile ) )
00272             {
00273                 // we found urlfile, we need to copy it to locale
00274                 localeFile.setName( locateLocal( "appdata", varFile ) );
00275 
00276                 if (localeFile.open(IO_WriteOnly))
00277                 {
00278                     QTextStream readStream(&file);
00279                     QTextStream writeStream(&localeFile);
00280                     writeStream <<  readStream.read();
00281                     localeFile.close();
00282                     file.reset();
00283                 }
00284             }
00285             else
00286              return false;
00287         }
00288 
00289 
00290    QTextStream stream(&file);
00291 
00292   stream.readLine();
00293 
00294   while  (!stream.atEnd())
00295   {
00296     QString Name;
00297     QString Designation;
00298     QString Line;
00299 
00300     Line = stream.readLine();
00301 
00302     if (Line[0] == QChar('*'))
00303      break;
00304 
00305     Designation = Line.mid(0,8).stripWhiteSpace();
00306     Name          = Line.mid(10,20).simplifyWhiteSpace();
00307 
00308     VariableStarInfo *VInfo = new VariableStarInfo;
00309 
00310     VInfo->Designation = Designation;
00311     VInfo->Name          = Name;
00312     VariableStarsList.append(VInfo);
00313    }
00314 
00315    return true;
00316 
00317 }
00318 
00319 
00320 bool KStarsData::readINDIHosts(void)
00321 {
00322   QString indiFile("indihosts.xml");
00323   QFile localeFile;
00324   QFile file;
00325   char errmsg[1024];
00326   signed char c;
00327   LilXML *xmlParser = newLilXML();
00328   XMLEle *root = NULL;
00329   XMLAtt *ap;
00330 
00331   file.setName( locate( "appdata", indiFile ) );
00332     if ( file.name().isEmpty() || !file.open( IO_ReadOnly ) )
00333          return false;
00334 
00335  while ( (c = (signed char) file.getch()) != -1)
00336  {
00337     root = readXMLEle(xmlParser, c, errmsg);
00338 
00339     if (root)
00340     {
00341 
00342       // Get host name
00343       ap = findXMLAtt(root, "name");
00344       if (!ap) {
00345     delLilXML(xmlParser);
00346     return false;
00347       }
00348 
00349        INDIHostsInfo *VInfo = new INDIHostsInfo;
00350 
00351        VInfo->name = QString(valuXMLAtt(ap));
00352 
00353       // Get host name
00354       ap = findXMLAtt(root, "hostname");
00355 
00356       if (!ap) {
00357     delLilXML(xmlParser);
00358     return false;
00359       }
00360 
00361     VInfo->hostname = QString(valuXMLAtt(ap));
00362 
00363     ap = findXMLAtt(root, "port");
00364 
00365     if (!ap) {
00366       delLilXML(xmlParser);
00367       return false;
00368     }
00369 
00370     VInfo->portnumber = QString(valuXMLAtt(ap));
00371 
00372     VInfo->isConnected = false;
00373     VInfo->mgrID = -1;
00374 
00375     INDIHostsList.append(VInfo);
00376 
00377     delXMLEle(root);
00378     }
00379 
00380     else if (errmsg[0])
00381      kdDebug() << errmsg << endl;
00382 
00383   }
00384 
00385   delLilXML(xmlParser);
00386 
00387   return true;
00388 
00389 
00390 }
00391 
00392 bool KStarsData::readCLineData( void ) {
00393     //The constellation lines data file (clines.dat) contains lists
00394     //of abbreviated genetive star names in the same format as they 
00395     //appear in the star data files (hipNNN.dat).  
00396     //
00397     //Each constellation consists of a QPtrList of SkyPoints, 
00398     //corresponding to the stars at each "node" of the constellation.
00399     //These are pointers to the starobjects themselves, so the nodes 
00400     //will automatically be fixed to the stars even as the star 
00401     //positions change due to proper motions.  In addition, each node 
00402     //has a corresponding flag that determines whether a line should 
00403     //connect this node and the previous one.
00404     
00405     QFile file;
00406     if ( KSUtils::openDataFile( file, "clines.dat" ) ) {
00407       QTextStream stream( &file );
00408 
00409         while ( !stream.eof() ) {
00410             QString line, name;
00411             QChar *mode;
00412 
00413             line = stream.readLine();
00414 
00415             //ignore lines beginning with "#":
00416             if ( line.at( 0 ) != '#' ) {
00417                 name = line.mid( 2 ).stripWhiteSpace();
00418                 
00419                 //Find the star with the same abbreviated genitive name ( name2() )
00420                 //increase efficiency by searching the list of named objects, rather than the 
00421                 //full list of all stars.  
00422                 bool starFound( false );
00423                 for ( SkyObjectName *oname = ObjNames.first(); oname; oname = ObjNames.next() ) {
00424                     if ( oname->skyObject()->type() == SkyObject::STAR && 
00425                              oname->skyObject()->name2() == name ) {
00426                         starFound = true;
00427                         clineList.append( (SkyPoint *)( oname->skyObject() ) );
00428                         
00429                         mode = new QChar( line.at( 0 ) );
00430                         clineModeList.append( mode );
00431                         break;
00432                     }
00433                 }
00434                 
00435                 if ( ! starFound ) 
00436                     kdWarning() << i18n( "No star named %1 found." ).arg(name) << endl;
00437             }
00438         }
00439         file.close();
00440 
00441         return true;
00442     } else {
00443         return false;
00444     }
00445 }
00446 
00447 bool KStarsData::readCNameData( void ) {
00448     QFile file;
00449     cnameFile = "cnames.dat";
00450 
00451     if ( KSUtils::openDataFile( file, cnameFile ) ) {
00452         QTextStream stream( &file );
00453 
00454         while ( !stream.eof() ) {
00455             QString line, name, abbrev;
00456             int rah, ram, ras, dd, dm, ds;
00457             QChar sgn;
00458 
00459             line = stream.readLine();
00460 
00461             rah = line.mid( 0, 2 ).toInt();
00462             ram = line.mid( 2, 2 ).toInt();
00463             ras = line.mid( 4, 2 ).toInt();
00464 
00465             sgn = line.at( 6 );
00466             dd = line.mid( 7, 2 ).toInt();
00467             dm = line.mid( 9, 2 ).toInt();
00468             ds = line.mid( 11, 2 ).toInt();
00469 
00470             abbrev = line.mid( 13, 3 );
00471             name  = line.mid( 17 ).stripWhiteSpace();
00472 
00473             dms r; r.setH( rah, ram, ras );
00474             dms d( dd, dm,  ds );
00475 
00476             if ( sgn == "-" ) { d.setD( -1.0*d.Degrees() ); }
00477 
00478             SkyObject *o = new SkyObject( SkyObject::CONSTELLATION, r, d, 0.0, name, abbrev );
00479             cnameList.append( o );
00480             ObjNames.append( o );
00481         }
00482         file.close();
00483 
00484         return true;
00485     } else {
00486         return false;
00487     }
00488 }
00489 
00490 bool KStarsData::readCBoundData( void ) {
00491     QFile file;
00492 
00493     if ( KSUtils::openDataFile( file, "cbound.dat" ) ) {
00494         QTextStream stream( &file );
00495 
00496         unsigned int nn(0);
00497         double ra(0.0), dec(0.0);
00498         QString d1, d2;
00499         bool ok(false), comment(false);
00500         
00501         //read the stream one field at a time.  Individual segments can span
00502         //multiple lines, so our normal readLine() is less convenient here.
00503         //Read fields into strings and then attempt to recast them as ints 
00504         //or doubles..this lets us do error checking on the stream.
00505         while ( !stream.eof() ) {
00506             stream >> d1;
00507             if ( d1.at(0) == '#' ) { 
00508                 comment = true; 
00509                 ok = true; 
00510             } else {
00511                 comment = false;
00512                 nn = d1.toInt( &ok );
00513             }
00514             
00515             if ( !ok || comment ) {
00516                 d1 = stream.readLine();
00517                 
00518                 if ( !ok ) 
00519                     kdWarning() << i18n( "Unable to parse boundary segment." ) << endl;
00520                 
00521             } else { 
00522                 CSegment *seg = new CSegment();
00523                 
00524                 for ( unsigned int i=0; i<nn; ++i ) {
00525                     stream >> d1 >> d2;
00526                     ra = d1.toDouble( &ok );
00527                     if ( ok ) dec = d2.toDouble( &ok );
00528                     if ( !ok ) break;
00529                     
00530                     seg->addPoint( ra, dec );
00531                 }
00532                 
00533                 if ( !ok ) {
00534                     //uh oh, this entry was not parsed.  Skip to the next line.
00535                     kdWarning() << i18n( "Unable to parse boundary segment." ) << endl;
00536                     delete seg;
00537                     d1 = stream.readLine();
00538                     
00539                 } else {
00540                     stream >> d1; //this should always equal 2
00541                     
00542                     nn = d1.toInt( &ok );
00543                     //error check
00544                     if ( !ok || nn != 2 ) {
00545                         kdWarning() << i18n( "Bad Constellation Boundary data." ) << endl;
00546                         delete seg;
00547                         d1 = stream.readLine();
00548                     }
00549                 }
00550 
00551                 if ( ok ) {
00552                     stream >> d1 >> d2;
00553                     ok = seg->setNames( d1, d2 );
00554                     if ( ok ) csegmentList.append( seg );
00555                 }
00556             }
00557         }
00558         
00559         return true;
00560     } else {
00561         return false;
00562     }
00563 }
00564 
00565 bool KStarsData::openStarFile( int i ) {
00566     if (starFileReader != 0) delete starFileReader;
00567     QFile file;
00568     QString snum, fname;
00569     snum = QString().sprintf("%03d", i);
00570     fname = "hip" + snum + ".dat";
00571     if (KSUtils::openDataFile(file, fname)) {
00572         starFileReader = new KSFileReader(file); // close file is included
00573     } else {
00574         starFileReader = 0;
00575         return false;
00576     }
00577     return true;
00578 }
00579 
00580 bool KStarsData::readStarData( void ) {
00581     bool ready = false;
00582 
00583     float loadUntilMag = MINDRAWSTARMAG;
00584     if (Options::magLimitDrawStar() > loadUntilMag) loadUntilMag = Options::magLimitDrawStar();
00585     
00586     for (unsigned int i=1; i<NHIPFILES+1; ++i) {
00587         emit progressText( i18n( "Loading Star Data (%1%)" ).arg( int(100.*float(i)/float(NHIPFILES)) ) );
00588         
00589         if (openStarFile(i) == true) {
00590             while (starFileReader->hasMoreLines()) {
00591                 QString line;
00592                 float mag;
00593 
00594                 line = starFileReader->readLine();
00595                 if ( line.left(1) != "#" ) {  //ignore comments
00596                     // check star magnitude
00597                     mag = line.mid( 46,5 ).toFloat();
00598                     if ( mag > loadUntilMag ) {
00599                         ready = true;
00600                         break;
00601                     }
00602 
00603                     processStar(&line);
00604                 }
00605             }  // end of while
00606 
00607         } else { //one of the star files could not be read.
00608             if ( starList.count() ) return true;
00609             else return false;
00610         }
00611         // magnitude level is reached
00612         if (ready == true) break;
00613     }
00614 
00615 //Store the max set magnitude of current session. Will increase in KStarsData::appendNewData()
00616     maxSetMagnitude = Options::magLimitDrawStar();
00617     delete starFileReader;
00618     starFileReader = 0;
00619     return true;
00620 }
00621 
00622 void KStarsData::processStar( QString *line, bool reloadMode ) {
00623     QString name, gname, SpType;
00624     int rah, ram, ras, ras2, dd, dm, ds, ds2;
00625     bool mult, var;
00626     QChar sgn;
00627     double mag, bv, dmag, vper;
00628     double pmra, pmdec, plx;
00629 
00630     name = ""; gname = "";
00631 
00632     //parse coordinates
00633     rah = line->mid( 0, 2 ).toInt();
00634     ram = line->mid( 2, 2 ).toInt();
00635     ras = int(line->mid( 4, 5 ).toDouble());
00636     ras2 = int(60.0*(line->mid( 4, 5 ).toDouble()-ras) + 0.5); //add 0.5 to get nearest integer with int()
00637 
00638     sgn = line->at(10);
00639     dd = line->mid(11, 2).toInt();
00640     dm = line->mid(13, 2).toInt();
00641     ds = int(line->mid(15, 4).toDouble());
00642     ds2 = int(60.0*(line->mid( 15, 5 ).toDouble()-ds) + 0.5); //add 0.5 to get nearest integer with int()
00643 
00644     //parse proper motion and parallax
00645     pmra = line->mid( 20, 9 ).toDouble();
00646     pmdec = line->mid( 29, 9 ).toDouble();
00647     plx = line->mid( 38, 7 ).toDouble();
00648 
00649     //parse magnitude, B-V color, and spectral type
00650     mag = line->mid( 46, 5 ).toDouble();
00651     bv  = line->mid( 51, 5 ).toDouble();
00652     SpType = line->mid(56, 2);
00653 
00654     //parse multiplicity
00655     mult = line->mid( 59, 1 ).toInt();
00656 
00657     //parse variablility...currently not using dmag or var
00658     var = false; dmag = 0.0; vper = 0.0;
00659     if ( line->at( 62 ) == '.' ) {
00660         var = true;
00661         dmag = line->mid( 61, 4 ).toDouble();
00662         vper = line->mid( 66, 6 ).toDouble();
00663     }
00664 
00665     //parse name(s)
00666     name = line->mid( 72 ).stripWhiteSpace(); //the rest of the line
00667     if (name.contains( ':' )) { //genetive form exists
00668         gname = name.mid( name.find(':')+1 ).stripWhiteSpace();
00669         name = name.mid( 0, name.find(':') ).stripWhiteSpace();
00670     }
00671 
00672     // HEV: look up star name in internationalization filesource
00673     name = i18n("star name", name.local8Bit().data());
00674 
00675     bool starIsUnnamed( false );
00676     if (name.isEmpty() && gname.isEmpty()) { //both names are empty
00677         starIsUnnamed = true;
00678     }
00679     
00680     dms r;
00681     r.setH(rah, ram, ras, ras2);
00682     dms d(dd, dm, ds, ds2);
00683 
00684     if (sgn == "-") { d.setD( -1.0*d.Degrees() ); }
00685 
00686     StarObject *o = new StarObject(r, d, mag, name, gname, SpType, pmra, pmdec, plx, mult, var );
00687     starList.append(o);
00688     
00689     // get horizontal coordinates when object will loaded while running the application
00690     // first run doesn't need this because updateTime() will called after loading all data
00691     if (reloadMode) {
00692         o->EquatorialToHorizontal( LST, geo()->lat() );
00693     }
00694     
00695     //STAR_SIZE
00696 //  StarObject *p = new StarObject(r, d, mag, name, gname, SpType, pmra, pmdec, plx, mult, var );
00697 //  starList.append(p);
00698 
00699     // add named stars to list
00700     if (starIsUnnamed == false) {
00701         ObjNames.append(o);
00702     }
00703 }
00704 
00705 bool KStarsData::readAsteroidData( void ) {
00706     QFile file;
00707 
00708     if ( KSUtils::openDataFile( file, "asteroids.dat" ) ) {
00709         KSFileReader fileReader( file );
00710 
00711         while( fileReader.hasMoreLines() ) {
00712             QString line, name;
00713             int mJD;
00714             double a, e, dble_i, dble_w, dble_N, dble_M, H;
00715             long double JD;
00716             KSAsteroid *ast = 0;
00717 
00718             line = fileReader.readLine();
00719             name = line.mid( 6, 17 ).stripWhiteSpace();
00720             mJD  = line.mid( 24, 5 ).toInt();
00721             a    = line.mid( 30, 9 ).toDouble();
00722             e    = line.mid( 41, 10 ).toDouble();
00723             dble_i = line.mid( 52, 9 ).toDouble();
00724             dble_w = line.mid( 62, 9 ).toDouble();
00725             dble_N = line.mid( 72, 9 ).toDouble();
00726             dble_M = line.mid( 82, 11 ).toDouble();
00727             H = line.mid( 94, 5 ).toDouble();
00728 
00729             JD = double( mJD ) + 2400000.5;
00730 
00731             ast = new KSAsteroid( this, name, "", JD, a, e, dms(dble_i), dms(dble_w), dms(dble_N), dms(dble_M), H );
00732             ast->setAngularSize( 0.005 );
00733             asteroidList.append( ast );
00734             ObjNames.append( ast );
00735         }
00736 
00737         if ( asteroidList.count() ) return true;
00738     }
00739 
00740     return false;
00741 }
00742 
00743 bool KStarsData::readCometData( void ) {
00744     QFile file;
00745 
00746     if ( KSUtils::openDataFile( file, "comets.dat" ) ) {
00747         KSFileReader fileReader( file );
00748 
00749         while( fileReader.hasMoreLines() ) {
00750             QString line, name;
00751             int mJD;
00752             double q, e, dble_i, dble_w, dble_N, Tp;
00753             long double JD;
00754             KSComet *com = 0;
00755 
00756             line = fileReader.readLine();
00757             name = line.mid( 3, 35 ).stripWhiteSpace();
00758             mJD  = line.mid( 38, 5 ).toInt();
00759             q    = line.mid( 44, 10 ).toDouble();
00760             e    = line.mid( 55, 10 ).toDouble();
00761             dble_i = line.mid( 66, 9 ).toDouble();
00762             dble_w = line.mid( 76, 9 ).toDouble();
00763             dble_N = line.mid( 86, 9 ).toDouble();
00764             Tp = line.mid( 96, 14 ).toDouble();
00765 
00766             JD = double( mJD ) + 2400000.5;
00767 
00768             com = new KSComet( this, name, "", JD, q, e, dms(dble_i), dms(dble_w), dms(dble_N), Tp );
00769             com->setAngularSize( 0.005 );
00770 
00771             cometList.append( com );
00772             ObjNames.append( com );
00773         }
00774 
00775         if ( cometList.count() ) return true;
00776     }
00777 
00778     return false;
00779 }
00780 
00781 
00782 //02/2003: NEW: split data files, using Heiko's new KSFileReader.
00783 bool KStarsData::readDeepSkyData( void ) {
00784     QFile file;
00785 
00786     for ( unsigned int i=0; i<NNGCFILES; ++i ) {
00787         QString snum, fname;
00788         snum = QString().sprintf( "%02d", i+1 );
00789         fname = "ngcic" + snum + ".dat";
00790 
00791         emit progressText( i18n( "Loading NGC/IC Data (%1%)" ).arg( int(100.*float(i)/float(NNGCFILES)) ) );
00792 
00793         if ( KSUtils::openDataFile( file, fname ) ) {
00794             KSFileReader fileReader( file ); // close file is included
00795             while ( fileReader.hasMoreLines() ) {
00796                 QString line, con, ss, name, name2, longname;
00797                 QString cat, cat2;
00798                 float mag(1000.0), ras, a, b;
00799                 int type, ingc, imess(-1), rah, ram, dd, dm, ds, pa;
00800                 int pgc, ugc;
00801                 QChar sgn, iflag;
00802 
00803                 line = fileReader.readLine();
00804                 //Ignore comment lines
00805                 while ( line.at(0) == '#' && fileReader.hasMoreLines() ) line = fileReader.readLine();
00806                 //Ignore lines with no coordinate values
00807                 while ( line.mid(6,8).stripWhiteSpace().isEmpty() ) line = fileReader.readLine();
00808                 
00809                 iflag = line.at( 0 ); //check for NGC/IC catalog flag
00810                 if ( iflag == 'I' ) cat = "IC";
00811                 else if ( iflag == 'N' ) cat = "NGC";
00812 
00813                 ingc = line.mid( 1, 4 ).toInt();  // NGC/IC catalog number
00814                 if ( ingc==0 ) cat = ""; //object is not in NGC or IC catalogs
00815 
00816                 //coordinates
00817                 rah = line.mid( 6, 2 ).toInt();
00818                 ram = line.mid( 8, 2 ).toInt();
00819                 ras = line.mid( 10, 4 ).toFloat();
00820                 sgn = line.at( 15 );
00821                 dd = line.mid( 16, 2 ).toInt();
00822                 dm = line.mid( 18, 2 ).toInt();
00823                 ds = line.mid( 20, 2 ).toInt();
00824 
00825                 //B magnitude
00826                 ss = line.mid( 23, 4 );
00827               if (ss == "    " ) { mag = 99.9; } else { mag = ss.toFloat(); }
00828 
00829                 //object type
00830                 type = line.mid( 29, 1 ).toInt();
00831 
00832                 //major and minor axes
00833                 ss = line.mid( 31, 5 );
00834                 if (ss == "      " ) { a = 0.0; } else { a = ss.toFloat(); }
00835                 ss = line.mid( 37, 5 );
00836                 if (ss == "     " ) { b = 0.0; } else { b = ss.toFloat(); }
00837                 //position angle.  The catalog PA is zero when the Major axis 
00838                 //is horizontal.  But we want the angle measured from North, so 
00839                 //we set PA = 90 - pa.
00840                 ss = line.mid( 43, 3 );
00841                 if (ss == "   " ) { pa = 90; } else { pa = 90 - ss.toInt(); }
00842 
00843                 //PGC number
00844                 ss = line.mid( 47, 6 );
00845                 if (ss == "      " ) { pgc = 0; } else { pgc = ss.toInt(); }
00846 
00847                 //UGC number
00848                 if ( line.mid( 54, 3 ) == "UGC" ) {
00849                     ugc = line.mid( 58, 5 ).toInt();
00850                 } else {
00851                     ugc = 0;
00852                 }
00853 
00854                 //Messier number
00855                 if ( line.at( 70 ) == 'M' ) {
00856                     cat2 = cat;
00857                     if ( ingc==0 ) cat2 = "";
00858                     cat = "M";
00859                     imess = line.mid( 72, 3 ).toInt();
00860                 }
00861 
00862                 longname = line.mid( 76, line.length() ).stripWhiteSpace();
00863 
00864                 dms r;
00865                 r.setH( rah, ram, int(ras) );
00866                 dms d( dd, dm, ds );
00867 
00868                 if ( sgn == "-" ) { d.setD( -1.0*d.Degrees() ); }
00869 
00870 //              QString snum;
00871                 if ( cat=="IC" || cat=="NGC" ) {
00872                     snum.setNum( ingc );
00873                     name = cat + " " + snum;
00874                 } else if ( cat=="M" ) {
00875                     snum.setNum( imess );
00876                     name = cat + " " + snum;
00877                     if ( cat2=="NGC" ) {
00878                         snum.setNum( ingc );
00879                         name2 = cat2 + " " + snum;
00880                     } else if ( cat2=="IC" ) {
00881                         snum.setNum( ingc );
00882                         name2 = cat2 + " " + snum;
00883                     } else {
00884                         name2 = "";
00885                     }
00886                 } else {
00887                     if ( longname.isEmpty() ) name = i18n( "Unnamed Object" );
00888                     else name = longname;
00889                 }
00890 
00891                 // create new deepskyobject
00892                 DeepSkyObject *o = 0;
00893                 if ( type==0 ) type = 1; //Make sure we use CATALOG_STAR, not STAR
00894                 o = new DeepSkyObject( type, r, d, mag, name, name2, longname, cat, a, b, pa, pgc, ugc );
00895 
00896                 // keep object in deep sky objects' list
00897                 deepSkyList.append( o );
00898                 // plus: keep objects separated for performance reasons. Switching the colors during
00899                 // paint is too expensive.
00900                 if ( o->isCatalogM()) {
00901                     deepSkyListMessier.append( o );
00902                 } else if (o->isCatalogNGC() ) {
00903                     deepSkyListNGC.append( o );
00904                 } else if ( o->isCatalogIC() ) {
00905                     deepSkyListIC.append( o );
00906                 } else {
00907                     deepSkyListOther.append( o );
00908                 }
00909 
00910                 // list of object names
00911                 ObjNames.append( (SkyObject*)o );
00912 
00913                 //Add longname to objList, unless longname is the same as name
00914                 if ( !o->longname().isEmpty() && o->name() != o->longname() && o->hasName() ) {
00915                     ObjNames.append( o, true );  // append with longname
00916                 }
00917             } //end while-filereader
00918         } else { //one of the files could not be opened
00919             return false;
00920         }
00921     } //end for-loop through files
00922 
00923     return true;
00924 }
00925 
00926 bool KStarsData::openURLFile(QString urlfile, QFile & file) {
00927     //QFile file;
00928     QString localFile;
00929     bool fileFound = false;
00930     QFile localeFile;
00931 
00932     if ( locale->language() != "en_US" )
00933         localFile = locale->language() + "/" + urlfile;
00934 
00935     if ( ! localFile.isEmpty() && KSUtils::openDataFile( file, localFile ) ) {
00936         fileFound = true;
00937     } else {
00938    // Try to load locale file, if not successful, load regular urlfile and then copy it to locale.
00939         file.setName( locateLocal( "appdata", urlfile ) );
00940         if ( file.open( IO_ReadOnly ) ) {
00941             //local file found.  Now, if global file has newer timestamp, then merge the two files.
00942             //First load local file into QStringList
00943             bool newDataFound( false );
00944             QStringList urlData;
00945             QTextStream lStream( &file );
00946             while ( ! lStream.eof() ) urlData.append( lStream.readLine() );
00947 
00948             //Find global file(s) in findAllResources() list.
00949             QFileInfo fi_local( file.name() );
00950             QStringList flist = KGlobal::instance()->dirs()->findAllResources( "appdata", urlfile );
00951             for ( unsigned int i=0; i< flist.count(); i++ ) {
00952                 if ( flist[i] != file.name() ) {
00953                     QFileInfo fi_global( flist[i] );
00954 
00955                     //Is this global file newer than the local file?
00956                     if ( fi_global.lastModified() > fi_local.lastModified() ) {
00957                         //Global file has newer timestamp than local.  Add lines in global file that don't already exist in local file.
00958                         //be smart about this; in some cases the URL is updated but the image is probably the same if its
00959                         //label string is the same.  So only check strings up to last ":"
00960                         QFile globalFile( flist[i] );
00961                         if ( globalFile.open( IO_ReadOnly ) ) {
00962                             QTextStream gStream( &globalFile );
00963                             while ( ! gStream.eof() ) {
00964                                 QString line = gStream.readLine();
00965 
00966                                 //If global-file line begins with "XXX:" then this line should be removed from the local file.
00967                                 if ( line.left( 4 ) == "XXX:"  && urlData.contains( line.mid( 4 ) ) ) {
00968                                     urlData.remove( urlData.find( line.mid( 4 ) ) );
00969                                 } else {
00970                                     //does local file contain the current global file line, up to second ':' ?
00971 
00972                                     bool linefound( false );
00973                                     for ( unsigned int j=0; j< urlData.count(); ++j ) {
00974                                         if ( urlData[j].contains( line.left( line.find( ':', line.find( ':' ) + 1 ) ) ) ) {
00975                                             //replace line in urlData with its equivalent in the newer global file.
00976                                             urlData.remove( urlData.at(j) );
00977                                             urlData.insert( urlData.at(j), line );
00978                                             if ( !newDataFound ) newDataFound = true;
00979                                             linefound = true;
00980                                             break;
00981                                         }
00982                                     }
00983                                     if ( ! linefound ) {
00984                                         urlData.append( line );
00985                                         if ( !newDataFound ) newDataFound = true;
00986                                     }
00987                                 }
00988                             }
00989                         }
00990                     }
00991                 }
00992             }
00993 
00994             file.close();
00995 
00996             //(possibly) write appended local file
00997             if ( newDataFound ) {
00998                 if ( file.open( IO_WriteOnly ) ) {
00999                     QTextStream outStream( &file );
01000                     for ( unsigned int i=0; i<urlData.count(); i++ ) {
01001                         outStream << urlData[i] << endl;
01002                     }
01003                     file.close();
01004                 }
01005             }
01006 
01007             if ( file.open( IO_ReadOnly ) ) fileFound = true;
01008 
01009         } else {
01010             if ( KSUtils::openDataFile( file, urlfile ) ) {
01011                 if ( locale->language() != "en_US" ) kdDebug() << i18n( "No localized URL file; using default English file." ) << endl;
01012                 // we found urlfile, we need to copy it to locale
01013                 localeFile.setName( locateLocal( "appdata", urlfile ) );
01014                 if (localeFile.open(IO_WriteOnly)) {
01015                     QTextStream readStream(&file);
01016                     QTextStream writeStream(&localeFile);
01017                     while ( ! readStream.eof() ) {
01018                         QString line = readStream.readLine();
01019                         if ( line.left( 4 ) != "XXX:" ) //do not write "deleted" lines
01020                             writeStream << line << endl;
01021                     }
01022 
01023                     localeFile.close();
01024                     file.reset();
01025                 } else {
01026                     kdDebug() << i18n( "Failed to copy default URL file to locale folder, modifying default object links is not possible" ) << endl;
01027                 }
01028                 fileFound = true;
01029             }
01030         }
01031     }
01032     return fileFound;
01033 }
01034 
01035 bool KStarsData::readUserLog(void)
01036 {
01037     QFile file;
01038     QString buffer;
01039     QString sub, name, data;
01040 
01041     if (!KSUtils::openDataFile( file, "userlog.dat" )) return false;
01042 
01043     QTextStream stream(&file);
01044 
01045     if (!stream.eof()) buffer = stream.read();
01046 
01047     while (!buffer.isEmpty()) {
01048         int startIndex, endIndex;
01049 
01050         startIndex = buffer.find("[KSLABEL:");
01051         sub = buffer.mid(startIndex);
01052         endIndex = sub.find("[KSLogEnd]");
01053 
01054         // Read name after KSLABEL identifer
01055         uint uiFirstNewline = sub.find("\n", startIndex + 9);
01056         name = sub.mid(startIndex + 9, sub.findRev( "]", uiFirstNewline ) - (startIndex + 9) );
01057         // Read data and skip new line
01058         data   = sub.mid( uiFirstNewline + 1, endIndex - (uiFirstNewline + 1));
01059         buffer = buffer.mid(endIndex + 11);
01060 
01061         //Find the sky object named 'name'.
01062         //Note that ObjectNameList::find() looks for the ascii representation 
01063         //of star genetive names, so stars are identified that way in the user log.
01064         SkyObjectName *sonm = ObjNames.find(name);
01065         if (sonm == 0) {
01066             kdWarning() << k_funcinfo << name << " not found" << endl;
01067         } else {
01068             sonm->skyObject()->userLog = data;
01069         }
01070 
01071     } // end while
01072     file.close();
01073     return true;
01074 }
01075 
01076 bool KStarsData::readURLData( QString urlfile, int type, bool deepOnly ) {
01077     QFile file;
01078     if (!openURLFile(urlfile, file)) return false;
01079 
01080     QTextStream stream(&file);
01081 
01082     while ( !stream.eof() ) {
01083         QString line = stream.readLine();
01084 
01085         //ignore comment lines
01086         if ( line.left(1) != "#" ) {
01087             QString name = line.mid( 0, line.find(':') );
01088             QString sub = line.mid( line.find(':')+1 );
01089             QString title = sub.mid( 0, sub.find(':') );
01090             QString url = sub.mid( sub.find(':')+1 );
01091     
01092             SkyObjectName *sonm = ObjNames.find(name);
01093             
01094             if (sonm == 0) {
01095                 kdWarning() << k_funcinfo << name << " not found" << endl;
01096             } else {
01097                 if ( ! deepOnly || ( sonm->skyObject()->type() > 2 && sonm->skyObject()->type() < 9 ) ) {
01098                     if ( type==0 ) { //image URL
01099                         sonm->skyObject()->ImageList.append( url );
01100                         sonm->skyObject()->ImageTitle.append( title );
01101                     } else if ( type==1 ) { //info URL
01102                         sonm->skyObject()->InfoList.append( url );
01103                         sonm->skyObject()->InfoTitle.append( title );
01104                     }
01105                 }
01106             }
01107         }
01108     }
01109     file.close();
01110     return true;
01111 }
01112 
01113 bool KStarsData::readCustomCatalogs() {
01114     bool result = false;
01115 
01116     for ( uint i=0; i < Options::catalogFile().count(); i++ ) {
01117         bool thisresult = addCatalog( Options::catalogFile()[i] );
01118         //Make result = true if at least one catalog is added
01119         result = ( result || thisresult );
01120     }
01121     return result;
01122 }
01123 
01124 bool KStarsData::addCatalog( QString filename ) {
01125     CustomCatalog *newCat = createCustomCatalog( filename, false );
01126     if ( newCat ) {
01127         CustomCatalogs.append( newCat );
01128 
01129         // add object names to ObjNames list
01130         for ( uint i=0; i < newCat->objList().count(); i++ ) {
01131 //      for ( SkyObject *o=newCat->objList().first(); o; o = newCat->objList().next() ) {
01132             SkyObject *o = newCat->objList().at(i);
01133             ObjNames.append( o );
01134             if ( o->hasLongName() && o->longname() != o->name() ) 
01135                 ObjNames.append( o, true ); //Add long name
01136             // PdV
01137             //if (reloadMode) {
01138                 //        o->EquatorialToHorizontal( LST, geo()->lat() );
01139             //}
01140 
01141         }
01142 
01143         return true;
01144     } else
01145         kdWarning() << k_funcinfo << i18n("Error adding catalog: %1").arg( filename ) << endl;
01146 
01147     return false;
01148 }
01149 
01150 bool KStarsData::removeCatalog( int i ) {
01151     if ( ! CustomCatalogs.at(i) ) return false;
01152 
01153     QPtrList<SkyObject> cat = CustomCatalogs.at(i)->objList();
01154 
01155     for ( SkyObject *o=cat.first(); o; o=cat.next() ) {
01156         ObjNames.remove( o->name() );
01157         if ( o->hasLongName() && o->longname() != o->name() ) 
01158             ObjNames.remove( o->longname() );
01159     }
01160 
01161     CustomCatalogs.remove(i);
01162 
01163     return true;
01164 }
01165 
01166 CustomCatalog* KStarsData::createCustomCatalog( QString filename, bool showerrs ) {
01167     QDir::setCurrent( QDir::homeDirPath() );  //for files with relative path
01168     QPtrList<SkyObject> objList;
01169     QString CatalogName, CatalogPrefix, CatalogColor;
01170     float CatalogEpoch;
01171 
01172     //If the filename begins with "~", replace the "~" with the user's home directory
01173     //(otherwise, the file will not successfully open)
01174     if ( filename.at(0)=='~' )
01175         filename = QDir::homeDirPath() + filename.mid( 1, filename.length() );
01176     QFile ccFile( filename );
01177 
01178     if ( ccFile.open( IO_ReadOnly ) ) {
01179         int iStart(0); //the line number of the first non-header line
01180         QStringList errs; //list of error messages 
01181         QStringList Columns; //list of data column descriptors in the header
01182 
01183         QTextStream stream( &ccFile );
01184         QStringList lines = QStringList::split( "\n", stream.read() );
01185 
01186         if ( parseCustomDataHeader( lines, Columns, CatalogName, CatalogPrefix, 
01187                 CatalogColor, CatalogEpoch, iStart, showerrs, errs ) ) {
01188     
01189             QStringList::Iterator it = lines.begin();
01190             QStringList::Iterator itEnd  = lines.end();
01191             it += iStart; //jump ahead past header
01192         
01193             for ( uint i=iStart; i < lines.count(); i++ ) {
01194                 QStringList d = QStringList::split( " ", lines[i] );
01195     
01196                 //Now, if one of the columns is the "Name" field, the name may contain spaces.
01197                 //In this case, the name field will need to be surrounded by quotes.  
01198                 //Check for this, and adjust the d list accordingly
01199                 int iname = Columns.findIndex( "Nm" );
01200                 if ( iname >= 0 && d[iname].left(1) == "\"" ) { //multi-word name in quotes
01201                     d[iname] = d[iname].mid(1); //remove leading quote
01202                     //It's possible that the name is one word, but still in quotes
01203                     if ( d[iname].right(1) == "\"" ) {
01204                         d[iname] = d[iname].left( d[iname].length() - 1 );
01205                     } else {
01206                         int iend = iname + 1;
01207                         while ( d[iend].right(1) != "\"" ) {
01208                             d[iname] += " " + d[iend];
01209                             ++iend;
01210                         }
01211                         d[iname] += " " + d[iend].left( d[iend].length() - 1 );
01212     
01213                         //remove the entries from d list that were the multiple words in the name
01214                         for ( int j=iname+1; j<=iend; j++ ) {
01215                             d.remove( d.at(iname + 1) ); //index is *not* j, because next item becomes "iname+1" after remove
01216                         }
01217                     }
01218                 }
01219     
01220                 if ( d.count() == Columns.count() ) {
01221                     processCustomDataLine( i, d, Columns, CatalogPrefix, objList, showerrs, errs );
01222                 } else {
01223                     if ( showerrs ) errs.append( i18n( "Line %1 does not contain %2 fields.  Skipping it." ).arg( i ).arg( Columns.count() ) );
01224                 }
01225             }
01226         }
01227 
01228         if ( objList.count() ) {
01229             if ( errs.count() > 0 ) { //some data parsed, but there are errs to report
01230                 QString message( i18n( "Some lines in the custom catalog could not be parsed; see error messages below." ) + "\n" +
01231                                                 i18n( "To reject the file, press Cancel. " ) +
01232                                                 i18n( "To accept the file (ignoring unparsed lines), press Accept." ) );
01233                 if ( KMessageBox::warningContinueCancelList( 0, message, errs,
01234                         i18n( "Some Lines in File Were Invalid" ), i18n( "Accept" ) ) != KMessageBox::Continue ) {
01235                     return 0; //User pressed Cancel, return NULL pointer
01236                 }
01237             }
01238         } else { //objList.count() == 0
01239             if ( showerrs ) {
01240                 QString message( i18n( "No lines could be parsed from the specified file, see error messages below." ) );
01241                 KMessageBox::informationList( 0, message, errs,
01242                         i18n( "No Valid Data Found in File" ) );
01243             }
01244             return 0; //no valid catalog data parsed, return NULL pointer
01245         }
01246 
01247     } else { //Error opening catalog file
01248         if ( showerrs )
01249             KMessageBox::sorry( 0, i18n( "Could not open custom data file: %1" ).arg( filename ), 
01250                     i18n( "Error opening file" ) );
01251         else 
01252             kdDebug() << i18n( "Could not open custom data file: %1" ).arg( filename ) << endl;
01253     }
01254 
01255     //Return the catalog
01256     if ( objList.count() )
01257         return new CustomCatalog( CatalogName, CatalogPrefix, CatalogColor, CatalogEpoch, objList );
01258     else
01259         return 0;
01260 }
01261 
01262 
01263 bool KStarsData::processCustomDataLine( int lnum, QStringList d, QStringList Columns, 
01264         QString Prefix, QPtrList<SkyObject> &objList, bool showerrs, QStringList &errs ) {
01265 
01266     //object data
01267     unsigned char iType(0);
01268     dms RA, Dec;
01269     float mag(0.0), a(0.0), b(0.0), PA(0.0);
01270     QString name(""); QString lname("");
01271 
01272     for ( uint i=0; i<Columns.count(); i++ ) {
01273         if ( Columns[i] == "ID" ) 
01274             name = Prefix + " " + d[i];
01275 
01276         if ( Columns[i] == "Nm" )
01277             lname = d[i];
01278 
01279         if ( Columns[i] == "RA" ) {
01280             if ( ! RA.setFromString( d[i], false ) ) {
01281                 if ( showerrs ) 
01282                     errs.append( i18n( "Line %1, field %2: Unable to parse RA value: %3" )
01283                             .arg(lnum).arg(i).arg(d[i]) );
01284                 return false;
01285             }
01286         }
01287 
01288         if ( Columns[i] == "Dc" ) {
01289             if ( ! Dec.setFromString( d[i], true ) ) {
01290                 if ( showerrs )
01291                     errs.append( i18n( "Line %1, field %2: Unable to parse Dec value: %3" )
01292                             .arg(lnum).arg(i).arg(d[i]) );
01293                 return false;
01294             }
01295         }
01296 
01297         if ( Columns[i] == "Tp" ) {
01298             bool ok(false);
01299             iType = d[i].toUInt( &ok );
01300             if ( ok ) {
01301                 if ( iType == 2 || iType > 8 ) {
01302                     if ( showerrs )
01303                         errs.append( i18n( "Line %1, field %2: Invalid object type: %3" )
01304                                 .arg(lnum).arg(i).arg(d[i]) +
01305                                 i18n( "Must be one of 0, 1, 3, 4, 5, 6, 7, 8." ) );
01306                     return false;
01307                 }
01308             } else {
01309                 if ( showerrs )
01310                     errs.append( i18n( "Line %1, field %2: Unable to parse Object type: %3" )
01311                             .arg(lnum).arg(i).arg(d[i]) );
01312                 return false;
01313             }
01314         }
01315 
01316         if ( Columns[i] == "Mg" ) {
01317             bool ok(false);
01318             mag = d[i].toFloat( &ok );
01319             if ( ! ok ) {
01320                 if ( showerrs )
01321                     errs.append( i18n( "Line %1, field %2: Unable to parse Magnitude: %3" )
01322                             .arg(lnum).arg(i).arg(d[i]) );
01323                 return false;
01324             }
01325         }
01326 
01327         if ( Columns[i] == "Mj" ) {
01328             bool ok(false);
01329             a = d[i].toFloat( &ok );
01330             if ( ! ok ) {
01331                 if ( showerrs )
01332                     errs.append( i18n( "Line %1, field %2: Unable to parse Major Axis: %3" )
01333                             .arg(lnum).arg(i).arg(d[i]) );
01334                 return false;
01335             }
01336         }
01337 
01338         if ( Columns[i] == "Mn" ) {
01339             bool ok(false);
01340             b = d[i].toFloat( &ok );
01341             if ( ! ok ) {
01342                 if ( showerrs )
01343                     errs.append( i18n( "Line %1, field %2: Unable to parse Minor Axis: %3" )
01344                             .arg(lnum).arg(i).arg(d[i]) );
01345                 return false;
01346             }
01347         }
01348 
01349         if ( Columns[i] == "PA" ) {
01350             bool ok(false);
01351             PA = d[i].toFloat( &ok );
01352             if ( ! ok ) {
01353                 if ( showerrs )
01354                     errs.append( i18n( "Line %1, field %2: Unable to parse Position Angle: %3" )
01355                             .arg(lnum).arg(i).arg(d[i]) );
01356                 return false;
01357             }
01358         }
01359     }
01360 
01361     if ( iType == 0 ) { //Add a star
01362         StarObject *o = new StarObject( RA, Dec, mag, lname );
01363         objList.append( o );
01364     } else { //Add a deep-sky object
01365         DeepSkyObject *o = new DeepSkyObject( iType, RA, Dec, mag, 
01366                     name, "", lname, Prefix, a, b, PA );
01367         objList.append( o );
01368     }
01369 
01370     return true;
01371 }
01372 
01373 bool KStarsData::parseCustomDataHeader( QStringList lines, QStringList &Columns, 
01374             QString &CatalogName, QString &CatalogPrefix, QString &CatalogColor, float &CatalogEpoch,
01375             int &iStart, bool showerrs, QStringList &errs ) {
01376 
01377     bool foundDataColumns( false ); //set to true if description of data columns found
01378     int ncol( 0 );
01379 
01380     QStringList::Iterator it = lines.begin();
01381     QStringList::Iterator itEnd  = lines.end();
01382 
01383     CatalogName = "";
01384     CatalogPrefix = "";
01385     CatalogColor = "";
01386     CatalogEpoch = 0.;
01387     for ( ; it != itEnd; it++ ) {
01388         QString d( *it ); //current data line
01389         if ( d.left(1) != "#" ) break;  //no longer in header!
01390 
01391         int iname   = d.find( "# Name: " );
01392         int iprefix = d.find( "# Prefix: " );
01393         int icolor  = d.find( "# Color: " );
01394         int iepoch  = d.find( "# Epoch: " );
01395 
01396         if ( iname == 0 ) { //line contains catalog name
01397             iname = d.find(":")+2;
01398             if ( CatalogName.isEmpty() ) { 
01399                 CatalogName = d.mid( iname );
01400             } else { //duplicate name in header
01401                 if ( showerrs )
01402                     errs.append( i18n( "Parsing header: " ) + 
01403                             i18n( "Extra Name field in header: %1.  Will be ignored" ).arg( d.mid(iname) ) );
01404             }
01405         } else if ( iprefix == 0 ) { //line contains catalog prefix
01406             iprefix = d.find(":")+2;
01407             if ( CatalogPrefix.isEmpty() ) { 
01408                 CatalogPrefix = d.mid( iprefix );
01409             } else { //duplicate prefix in header
01410                 if ( showerrs )
01411                     errs.append( i18n( "Parsing header: " ) + 
01412                             i18n( "Extra Prefix field in header: %1.  Will be ignored" ).arg( d.mid(iprefix) ) );
01413             }
01414         } else if ( icolor == 0 ) { //line contains catalog prefix
01415             icolor = d.find(":")+2;
01416             if ( CatalogColor.isEmpty() ) { 
01417                 CatalogColor = d.mid( icolor );
01418             } else { //duplicate prefix in header
01419                 if ( showerrs )
01420                     errs.append( i18n( "Parsing header: " ) + 
01421                             i18n( "Extra Color field in header: %1.  Will be ignored" ).arg( d.mid(icolor) ) );
01422             }
01423         } else if ( iepoch == 0 ) { //line contains catalog epoch
01424             iepoch = d.find(":")+2;
01425             if ( CatalogEpoch == 0. ) {
01426                 bool ok( false );
01427                 CatalogEpoch = d.mid( iepoch ).toFloat( &ok );
01428                 if ( !ok ) {
01429                     if ( showerrs )
01430                         errs.append( i18n( "Parsing header: " ) + 
01431                                 i18n( "Could not convert Epoch to float: %1.  Using 2000. instead" ).arg( d.mid(iepoch) ) );
01432                     CatalogEpoch = 2000.; //adopt default value
01433                 }
01434             } else { //duplicate epoch in header
01435                 if ( showerrs )
01436                     errs.append( i18n( "Parsing header: " ) + 
01437                             i18n( "Extra Epoch field in header: %1.  Will be ignored" ).arg( d.mid(iepoch) ) );
01438             }
01439         } else if ( ! foundDataColumns ) { //don't try to parse data column descriptors if we already found them
01440             //Chomp off leading "#" character
01441             d = d.replace( QRegExp( "#" ), "" );
01442 
01443             QStringList fields = QStringList::split( " ", d ); //split on whitespace
01444 
01445             //we need a copy of the master list of data fields, so we can 
01446             //remove fields from it as they are encountered in the "fields" list.
01447             //this allows us to detect duplicate entries
01448             QStringList master( KStarsData::CustomColumns ); 
01449 
01450             QStringList::Iterator itf    = fields.begin();
01451             QStringList::Iterator itfEnd = fields.end();
01452 
01453             for ( ; itf != itfEnd; itf++ ) {
01454                 QString s( *itf );
01455                 if ( master.contains( s ) ) {
01456                     //add the data field
01457                     Columns.append( s );
01458 
01459                     // remove the field from the master list and inc the 
01460                     // count of "good" columns (unless field is "Ignore")
01461                     if ( s != "Ig" ) {
01462                         master.remove( master.find( s ) );
01463                         ncol++;
01464                     }
01465                 } else if ( fields.contains( s ) ) { //duplicate field
01466                     fields.append( "Ig" ); //skip this column
01467                     if ( showerrs )
01468                         errs.append( i18n( "Parsing header: " ) + 
01469                                 i18n( "Duplicate data field descriptor \"%1\" will be ignored" ).arg( s ) );
01470                 } else { //Invalid field
01471                     fields.append( "Ig" ); //skip this column
01472                     if ( showerrs )
01473                         errs.append( i18n( "Parsing header: " ) + 
01474                                 i18n( "Invalid data field descriptor \"%1\" will be ignored" ).arg( s ) );
01475                 }
01476             }
01477 
01478             if ( ncol ) foundDataColumns = true;
01479         }
01480     }
01481 
01482     if ( ! foundDataColumns ) {
01483         if ( showerrs )
01484             errs.append( i18n( "Parsing header: " ) + 
01485                     i18n( "No valid column descriptors found.  Exiting" ) );
01486         return false;
01487     }
01488 
01489     if ( it == itEnd ) {
01490         if ( showerrs ) errs.append( i18n( "Parsing header: " ) +
01491                 i18n( "No data lines found after header.  Exiting." ) );
01492         return false; //fatal error
01493     } else {
01494         //Make sure Name, Prefix, Color and Epoch were set
01495         if ( CatalogName.isEmpty() ) { 
01496             if ( showerrs ) errs.append( i18n( "Parsing header: " ) +
01497                 i18n( "No Catalog Name specified; setting to \"Custom\"" ) );
01498             CatalogName = i18n("Custom");
01499         }
01500         if ( CatalogPrefix.isEmpty() ) { 
01501             if ( showerrs ) errs.append( i18n( "Parsing header: " ) +
01502                 i18n( "No Catalog Prefix specified; setting to \"CC\"" ) );
01503             CatalogPrefix = "CC";
01504         }
01505         if ( CatalogColor.isEmpty() ) { 
01506             if ( showerrs ) errs.append( i18n( "Parsing header: " ) +
01507                 i18n( "No Catalog Color specified; setting to Red" ) );
01508             CatalogColor = "#CC0000";
01509         }
01510         if ( CatalogEpoch == 0. ) { 
01511             if ( showerrs ) errs.append( i18n( "Parsing header: " ) +
01512                 i18n( "No Catalog Epoch specified; assuming 2000." ) );
01513             CatalogEpoch = 2000.;
01514         }
01515 
01516         //the it iterator now points to the first line past the header
01517         iStart = lines.findIndex( QString( *it ) );
01518         return true;
01519     }
01520 }
01521 
01522 bool KStarsData::processCity( QString& line ) {
01523     QString totalLine;
01524     QString name, province, country;
01525     QStringList fields;
01526     TimeZoneRule *TZrule;
01527     bool intCheck = true;
01528     char latsgn, lngsgn;
01529     int lngD, lngM, lngS;
01530     int latD, latM, latS;
01531     double TZ;
01532     float lng, lat;
01533 
01534     totalLine = line;
01535 
01536     // separate fields
01537     fields = QStringList::split( ":", line );
01538 
01539     for ( unsigned int i=0; i< fields.count(); ++i )
01540         fields[i] = fields[i].stripWhiteSpace();
01541 
01542     if ( fields.count() < 11 ) {
01543         kdDebug()<< i18n( "Cities.dat: Ran out of fields.  Line was:" ) <<endl;
01544         kdDebug()<< totalLine.local8Bit() <<endl;
01545         return false;
01546     } else if ( fields.count() < 12 ) {
01547         // allow old format (without TZ) for mycities.dat
01548         fields.append("");
01549         fields.append("--");
01550     } else if ( fields.count() < 13 ) {
01551         // Set TZrule to "--"
01552         fields.append("--");
01553     }
01554 
01555     name = fields[0];
01556     province = fields[1];
01557     country = fields[2];
01558 
01559     latD = fields[3].toInt( &intCheck );
01560     if ( !intCheck ) {
01561         kdDebug() << fields[3] << i18n( "\nCities.dat: Bad integer.  Line was:\n" ) << totalLine << endl;
01562         return false;
01563     }
01564 
01565     latM = fields[4].toInt( &intCheck );
01566     if ( !intCheck ) {
01567         kdDebug() << fields[4] << i18n( "\nCities.dat: Bad integer.  Line was:\n" ) << totalLine << endl;
01568         return false;
01569     }
01570 
01571     latS = fields[5].toInt( &intCheck );
01572     if ( !intCheck ) {
01573         kdDebug() << fields[5] << i18n( "\nCities.dat: Bad integer.  Line was:\n" ) << totalLine << endl;
01574         return false;
01575     }
01576 
01577     QChar ctemp = fields[6].at(0);
01578     latsgn = ctemp;
01579     if (latsgn != 'N' && latsgn != 'S') {
01580         kdDebug() << latsgn << i18n( "\nCities.dat: Invalid latitude sign.  Line was:\n" ) << totalLine << endl;
01581         return false;
01582     }
01583 
01584     lngD = fields[7].toInt( &intCheck );
01585     if ( !intCheck ) {
01586         kdDebug() << fields[7] << i18n( "\nCities.dat: Bad integer.  Line was:\n" ) << totalLine << endl;
01587         return false;
01588     }
01589 
01590     lngM = fields[8].toInt( &intCheck );
01591     if ( !intCheck ) {
01592         kdDebug() << fields[8] << i18n( "\nCities.dat: Bad integer.  Line was:\n" ) << totalLine << endl;
01593         return false;
01594     }
01595 
01596     lngS = fields[9].toInt( &intCheck );
01597     if ( !intCheck ) {
01598         kdDebug() << fields[9] << i18n( "\nCities.dat: Bad integer.  Line was:\n" ) << totalLine << endl;
01599         return false;
01600     }
01601 
01602     ctemp = fields[10].at(0);
01603     lngsgn = ctemp;
01604     if (lngsgn != 'E' && lngsgn != 'W') {
01605         kdDebug() << latsgn << i18n( "\nCities.dat: Invalid longitude sign.  Line was:\n" ) << totalLine << endl;
01606         return false;
01607     }
01608 
01609     lat = (float)latD + ((float)latM + (float)latS/60.0)/60.0;
01610     lng = (float)lngD + ((float)lngM + (float)lngS/60.0)/60.0;
01611 
01612     if ( latsgn == 'S' ) lat *= -1.0;
01613     if ( lngsgn == 'W' ) lng *= -1.0;
01614 
01615     // find time zone. Use value from Cities.dat if available.
01616     // otherwise use the old approximation: int(lng/15.0);
01617     if ( fields[11].isEmpty() || ('x' == fields[11].at(0)) ) {
01618         TZ = int(lng/15.0);
01619     } else {
01620         bool doubleCheck = true;
01621         TZ = fields[11].toDouble( &doubleCheck);
01622         if ( !doubleCheck ) {
01623             kdDebug() << fields[11] << i18n( "\nCities.dat: Bad time zone.  Line was:\n" ) << totalLine << endl;
01624             return false;
01625         }
01626     }
01627 
01628     //last field is the TimeZone Rule ID.
01629     TZrule = &( Rulebook[ fields[12] ] );
01630 
01631 //  if ( fields[12]=="--" )
01632 //      kdDebug() << "Empty rule start month: " << TZrule->StartMonth << endl;
01633     geoList.append ( new GeoLocation( lng, lat, name, province, country, TZ, TZrule ));  // appends city names to list
01634     return true;
01635 }
01636 
01637 bool KStarsData::readTimeZoneRulebook( void ) {
01638     QFile file;
01639     QString id;
01640 
01641     if ( KSUtils::openDataFile( file, "TZrules.dat" ) ) {
01642         QTextStream stream( &file );
01643 
01644         while ( !stream.eof() ) {
01645             QString line = stream.readLine().stripWhiteSpace();
01646             if ( line.left(1) != "#" && line.length() ) { //ignore commented and blank lines
01647                 QStringList fields = QStringList::split( " ", line );
01648                 id = fields[0];
01649                 QTime stime = QTime( fields[3].left( fields[3].find(':')).toInt() ,
01650                                 fields[3].mid( fields[3].find(':')+1, fields[3].length()).toInt() );
01651                 QTime rtime = QTime( fields[6].left( fields[6].find(':')).toInt(),
01652                                 fields[6].mid( fields[6].find(':')+1, fields[6].length()).toInt() );
01653 
01654                 Rulebook[ id ] = TimeZoneRule( fields[1], fields[2], stime, fields[4], fields[5], rtime );
01655             }
01656         }
01657         return true;
01658     } else {
01659         return false;
01660     }
01661 }
01662 
01663 bool KStarsData::readCityData( void ) {
01664     QFile file;
01665     bool citiesFound = false;
01666 
01667 // begin new code
01668     if ( KSUtils::openDataFile( file, "Cities.dat" ) ) {
01669     KSFileReader fileReader( file ); // close file is included
01670     while ( fileReader.hasMoreLines() ) {
01671             citiesFound |= processCity( fileReader.readLine() );
01672     }
01673   }
01674 // end new code
01675 
01676     //check for local cities database, but don't require it.
01677     file.setName( locate( "appdata", "mycities.dat" ) ); //determine filename in local user KDE directory tree.
01678     if ( file.exists() && file.open( IO_ReadOnly ) ) {
01679         QTextStream stream( &file );
01680 
01681     while ( !stream.eof() ) {
01682             QString line = stream.readLine();
01683             citiesFound |= processCity( line );
01684         }   // while ( !stream.eof() )
01685         file.close();
01686     }   // if ( fileopen() )
01687 
01688     return citiesFound;
01689 }
01690 
01691 void KStarsData::setMagnitude( float newMagnitude, bool forceReload ) {
01692 // only reload data if not loaded yet
01693 // if checkDataPumpAction() detects that new magnitude is higher than the
01694 // loaded, it can force a reload
01695     if ( newMagnitude > maxSetMagnitude || forceReload ) {
01696         maxSetMagnitude = newMagnitude;  // store new highest magnitude level
01697 
01698         if (reloadingData() == false) {  // if not already reloading data
01699             source = new FileSource(this, newMagnitude);
01700             loader = new StarDataSink(this);
01701             connect(loader, SIGNAL(done()), this, SLOT(checkDataPumpAction()));
01702             connect(loader, SIGNAL(updateSkymap()), this, SLOT(updateSkymap()));
01703             connect(loader, SIGNAL(clearCache()), this, SLOT(sendClearCache()));
01704             // start reloading
01705             pump = new QDataPump (source, (QDataSink*) loader);
01706         }
01707     } /*else if ( newMagnitude < maxSetMagnitude ) {
01708         StarObject *lastStar = starList.last();
01709         while ( lastStar->mag() > newMagnitude  && starList.count() ) {
01710             //check if star is named.  If so, remove it from ObjNames
01711             if ( ! lastStar->name().isEmpty() ) {
01712                 ObjNames.remove( lastStar->name() );
01713             }
01714             starList.removeLast();
01715             lastStar = starList.last();
01716 
01717             //Need to recompute names of objects
01718             sendClearCache();
01719         }
01720     }*/
01721 
01722     // change current magnitude level in KStarsOptions
01723     Options::setMagLimitDrawStar( newMagnitude );
01724 }
01725 
01726 void KStarsData::checkDataPumpAction() {
01727     // it will set to true if new data should be reloaded
01728     bool reloadMoreData = false;
01729     if (source != 0) {
01730         // check if a new reload must be started
01731         if (source->magnitude() < maxSetMagnitude) reloadMoreData = true;
01732         delete source;
01733         source = 0;
01734     }
01735     if (pump != 0) {  // if pump exists
01736         delete pump;
01737         pump = 0;
01738     }
01739     if (loader != 0) {  // if loader exists
01740         delete loader;
01741         loader = 0;
01742     }
01743     // If magnitude was changed while reloading data start a new reload of data.
01744     if (reloadMoreData == true) {
01745         setMagnitude(maxSetMagnitude, true);
01746     }
01747 }
01748 
01749 bool KStarsData::reloadingData() {
01750     return ( pump || loader || source );  // true if variables != 0
01751 }
01752 
01753 void KStarsData::updateSkymap() {
01754     emit update();
01755 }
01756 
01757 void KStarsData::sendClearCache() {
01758     emit clearCache();
01759 }
01760 
01761 void KStarsData::initialize() {
01762     if (startupComplete) return;
01763 
01764     initTimer = new QTimer;
01765     QObject::connect(initTimer, SIGNAL(timeout()), this, SLOT( slotInitialize() ) );
01766     initCounter = 0;
01767     initTimer->start(1);
01768 }
01769 
01770 void KStarsData::initError(QString s, bool required = false) {
01771     QString message, caption;
01772     initTimer->stop();
01773     if (required) {
01774         message = i18n( "The file %1 could not be found. "
01775                 "KStars cannot run properly without this file. "
01776                 "To continue loading, place the file in one of the "
01777                 "following locations, then press Retry:\n\n" ).arg( s )
01778                 + QString( "\t$(KDEDIR)/share/apps/kstars/%1\n" ).arg( s )
01779                 + QString( "\t~/.kde/share/apps/kstars/%1\n\n" ).arg( s ) 
01780                 + i18n( "Otherwise, press Cancel to shutdown." );
01781         caption = i18n( "Critical File Not Found: %1" ).arg( s );
01782     } else {
01783         message = i18n( "The file %1 could not be found. "
01784                 "KStars can still run without this file. "
01785                 "However, to avoid seeing this message in the future, you can "
01786                 "place the file in one of the following locations, then press Retry:\n\n" ).arg( s )
01787                 + QString( "\t$(KDEDIR)/share/apps/kstars/%1\n" ).arg( s )
01788                 + QString( "\t~/.kde/share/apps/kstars/%1\n\n" ).arg( s )
01789                 + i18n( "Otherwise, press Cancel to continue loading without this file." ).arg( s );
01790         caption = i18n( "Non-Critical File Not Found: %1" ).arg( s );
01791     }
01792 
01793     if ( KMessageBox::warningContinueCancel( 0, message, caption, i18n( "Retry" ) ) == KMessageBox::Continue ) {
01794         initCounter--;
01795         initTimer->start(1);
01796     } else {
01797         if (required) {
01798             delete initTimer;
01799             initTimer = 0L;
01800             emit initFinished(false);
01801         } else {
01802             initTimer->start(1);
01803         }
01804     }
01805 }
01806 
01807 void KStarsData::slotInitialize() {
01808     QFile imFile;
01809     QString ImageName;
01810 
01811     kapp->flush(); // flush all paint events before loading data
01812 
01813     switch ( initCounter )
01814     {
01815         case 0: //Load Time Zone Rules//
01816             emit progressText( i18n("Reading Time Zone Rules") );
01817 
01818             if (objects==1) {
01819                 // timezone rules
01820                 if ( !readTimeZoneRulebook( ) )
01821                     initError( "TZrules.dat", true );
01822             }
01823 
01824             // read INDI hosts file, not required
01825             readINDIHosts();
01826             break;
01827 
01828         case 1: //Load Cities//
01829         {
01830             if (objects>1) break;
01831 
01832             emit progressText( i18n("Loading City Data") );
01833 
01834             if ( !readCityData( ) )
01835                 initError( "Cities.dat", true );
01836             
01837             break;
01838         }
01839 
01840         case 2: //Load stellar database//
01841 
01842             emit progressText(i18n("Loading Star Data (%1%)" ).arg(0) );
01843             if ( !readStarData( ) )
01844                 initError( "hipNNN.dat", true );
01845             if (!readVARData())
01846                 initError( "valaav.dat", false);
01847             if (!readADVTreeData())
01848                 initError( "advinterface.dat", false);
01849             break;
01850 
01851         case 3: //Load NGC/IC database and custom catalogs//
01852 
01853             emit progressText( i18n("Loading NGC/IC Data (%1%)" ).arg(0) );
01854             if ( !readDeepSkyData( ) )
01855                 initError( "ngcicN.dat", true );
01856 
01857             emit progressText( i18n("Loading Custom catalogs" ) );
01858             readCustomCatalogs( );
01859 //          if ( !readCustomCatalogs( ) )
01860 //              initError( "<custom catalog>", true );
01861             break;
01862 
01863         case 4: //Load Constellation lines//
01864 
01865             emit progressText( i18n("Loading Constellations" ) );
01866             if ( !readCLineData( ) )
01867                 initError( "clines.dat", true );
01868             break;
01869 
01870         case 5: //Load Constellation names//
01871 
01872             emit progressText( i18n("Loading Constellation Names" ) );
01873             if ( !readCNameData( ) )
01874                 initError( cnameFile, true );
01875             break;
01876 
01877         case 6: //Load Constellation boundaries//
01878 
01879             emit progressText( i18n("Loading Constellation Boundaries" ) );
01880             if ( !readCBoundData( ) )
01881                 initError( "cbound.dat", true );
01882             break;
01883 
01884         case 7: //Load Milky Way//
01885 
01886             emit progressText( i18n("Loading Milky Way" ) );
01887             if ( !readMWData( ) )
01888                 initError( "mw*.dat", true );
01889             break;
01890 
01891         case 8: //Initialize the Planets//
01892 
01893             emit progressText( i18n("Creating Planets" ) );
01894             if (PCat->initialize())
01895                 PCat->addObject( ObjNames );
01896 
01897             jmoons = new JupiterMoons();
01898             break;
01899 
01900         case 9: //Initialize Asteroids & Comets//
01901 
01902             emit progressText( i18n( "Creating Asteroids and Comets" ) );
01903             if ( !readAsteroidData() )
01904                 initError( "asteroids.dat", false );
01905             if ( !readCometData() )
01906                 initError( "comets.dat", false );
01907 
01908             break;
01909 
01910         case 10: //Initialize the Moon//
01911 
01912             emit progressText( i18n("Creating Moon" ) );
01913             Moon = new KSMoon(this);
01914             ObjNames.append( Moon );
01915             Moon->loadData();
01916             break;
01917 
01918         case 11: //Load Image URLs//
01919 
01920             emit progressText( i18n("Loading Image URLs" ) );
01921             if ( !readURLData( "image_url.dat", 0 ) ) {
01922                 initError( "image_url.dat", false );
01923             }
01924             //if ( !readURLData( "myimage_url.dat", 0 ) ) {
01925             //Don't do anything if the local file is not found.
01926             //}
01927           // doesn't belong here, only temp
01928              readUserLog();
01929 
01930             break;
01931 
01932         case 12: //Load Information URLs//
01933 
01934             emit progressText( i18n("Loading Information URLs" ) );
01935             if ( !readURLData( "info_url.dat", 1 ) ) {
01936                 initError( "info_url.dat", false );
01937             }
01938             //if ( !readURLData( "myinfo_url.dat", 1 ) ) {
01939             //Don't do anything if the local file is not found.
01940             //}
01941             break;
01942 
01943         default:
01944             initTimer->stop();
01945             delete initTimer;
01946             initTimer = 0L;
01947             startupComplete = true;
01948             emit initFinished(true);
01949             break;
01950     } // switch ( initCounter )
01951 
01952     initCounter++;
01953 }
01954 
01955 void KStarsData::initGuides(KSNumbers *num)
01956 {
01957     // Define the Celestial Equator
01958     for ( unsigned int i=0; i<NCIRCLE; ++i ) {
01959         SkyPoint *o = new SkyPoint( i*24./NCIRCLE, 0.0 );
01960         o->EquatorialToHorizontal( LST, geo()->lat() );
01961         Equator.append( o );
01962     }
01963 
01964   // Define the horizon.
01965   // Use the celestial Equator as a convenient starting point, but instead of RA and Dec,
01966   // interpret the coordinates as azimuth and altitude, and then convert to RA, dec.
01967   // The horizon will be redefined whenever the positions of sky objects are updated.
01968     dms temp( 0.0 );
01969     for (SkyPoint *point = Equator.first(); point; point = Equator.next()) {
01970         double sinlat, coslat, sindec, cosdec, sinAz, cosAz;
01971         double HARad;
01972         dms dec, HA, RA, Az;
01973         Az = dms(*(point->ra()));
01974 
01975         Az.SinCos( sinAz, cosAz );
01976         geo()->lat()->SinCos( sinlat, coslat );
01977 
01978         dec.setRadians( asin( coslat*cosAz ) );
01979         dec.SinCos( sindec, cosdec );
01980 
01981         HARad = acos( -1.0*(sinlat*sindec)/(coslat*cosdec) );
01982         if ( sinAz > 0.0 ) { HARad = 2.0*dms::PI - HARad; }
01983         HA.setRadians( HARad );
01984         RA = LST->Degrees() - HA.Degrees();
01985 
01986         SkyPoint *o = new SkyPoint( RA, dec );
01987         o->setAlt( 0.0 );
01988         o->setAz( Az );
01989 
01990         Horizon.append( o );
01991 
01992         //Define the Ecliptic (use the same ListIteration; interpret coordinates as Ecliptic long/lat)
01993         o = new SkyPoint( 0.0, 0.0 );
01994         o->setFromEcliptic( num->obliquity(), point->ra(), &temp );
01995         o->EquatorialToHorizontal( LST, geo()->lat() );
01996         Ecliptic.append( o );
01997     }
01998 }
01999 
02000 void KStarsData::resetToNewDST(const GeoLocation *geo, const bool automaticDSTchange) {
02001     // reset tzrules data with local time, timezone offset and time direction (forward or backward)
02002     // force a DST change with option true for 3. parameter
02003     geo->tzrule()->reset_with_ltime( LTime, geo->TZ0(), TimeRunsForward, automaticDSTchange );
02004     // reset next DST change time
02005     setNextDSTChange( geo->tzrule()->nextDSTChange() );
02006     //reset LTime, because TZoffset has changed
02007     LTime = geo->UTtoLT( ut() );
02008 }
02009 
02010 void KStarsData::updateTime( GeoLocation *geo, SkyMap *skymap, const bool automaticDSTchange ) {
02011     // sync LTime with the simulation clock
02012     LTime = geo->UTtoLT( ut() );
02013     syncLST();
02014     
02015     //Only check DST if (1) TZrule is not the empty rule, and (2) if we have crossed
02016     //the DST change date/time.
02017     if ( !geo->tzrule()->isEmptyRule() ) {
02018         if ( TimeRunsForward ) {
02019             // timedirection is forward
02020             // DST change happens if current date is bigger than next calculated dst change
02021             if ( ut() > NextDSTChange ) resetToNewDST(geo, automaticDSTchange);
02022         } else {
02023             // timedirection is backward
02024             // DST change happens if current date is smaller than next calculated dst change
02025             if ( ut() < NextDSTChange ) resetToNewDST(geo, automaticDSTchange);
02026         }
02027     }
02028 
02029     KSNumbers num( ut().djd() );
02030 
02031     bool needNewCoords = false;
02032     if ( fabs( ut().djd() - LastNumUpdate.djd() ) > 1.0 ) {
02033         //update time-dependent variables once per day
02034         needNewCoords = true;
02035         LastNumUpdate = ut().djd();
02036     }
02037 
02038     // Update positions of objects, if necessary
02039     if ( fabs( ut().djd() - LastPlanetUpdate.djd() ) > 0.01 ) {
02040         LastPlanetUpdate = ut().djd();
02041 
02042         if ( Options::showPlanets() ) PCat->findPosition( &num, geo->lat(), LST );
02043 
02044         //Asteroids
02045         if ( Options::showPlanets() && Options::showAsteroids() )
02046             for ( KSAsteroid *ast = asteroidList.first(); ast; ast = asteroidList.next() )
02047                 ast->findPosition( &num, geo->lat(), LST, earth() );
02048 
02049         //Comets
02050         if ( Options::showPlanets() && Options::showComets() )
02051             for ( KSComet *com = cometList.first(); com; com = cometList.next() )
02052                 com->findPosition( &num, geo->lat(), LST, earth() );
02053 
02054         //Recompute the Ecliptic
02055         if ( Options::showEcliptic() ) {
02056             Ecliptic.clear();
02057 
02058             dms temp(0.0);
02059             for ( unsigned int i=0; i<Equator.count(); ++i ) {
02060                 SkyPoint *o = new SkyPoint( 0.0, 0.0 );
02061                 o->setFromEcliptic( num.obliquity(), Equator.at(i)->ra(), &temp );
02062                 Ecliptic.append( o );
02063             }
02064         }
02065     }
02066 
02067     // Moon moves ~30 arcmin/hr, so update its position every minute.
02068     if ( fabs( ut().djd() - LastMoonUpdate.djd() ) > 0.00069444 ) {
02069         LastMoonUpdate = ut();
02070         if ( Options::showMoon() ) {
02071             Moon->findPosition( &num, geo->lat(), LST );
02072             Moon->findPhase( PCat->planetSun() );
02073         }
02074 
02075         //for now, update positions of Jupiter's moons here also
02076         if ( Options::showPlanets() && Options::showJupiter() )
02077             jmoons->findPosition( &num, (const KSPlanet*)PCat->findByName("Jupiter"), PCat->planetSun() );
02078     }
02079 
02080     //Update Alt/Az coordinates.  Timescale varies with zoom level
02081     //If Clock is in Manual Mode, always update. (?)
02082     if ( fabs( ut().djd() - LastSkyUpdate.djd() ) > 0.25/Options::zoomFactor() || clock()->isManualMode() ) {
02083         LastSkyUpdate = ut();
02084 
02085         //Recompute Alt, Az coords for all objects
02086         //Planets
02087         //This updates trails as well
02088         PCat->EquatorialToHorizontal( LST, geo->lat() );
02089 
02090         jmoons->EquatorialToHorizontal( LST, geo->lat() );
02091         if ( Options::showMoon() ) {
02092             Moon->EquatorialToHorizontal( LST, geo->lat() );
02093             if ( Moon->hasTrail() ) Moon->updateTrail( LST, geo->lat() );
02094         }
02095 
02096 //      //Planet Trails
02097 //      for( SkyPoint *p = PlanetTrail.first(); p; p = PlanetTrail.next() )
02098 //          p->EquatorialToHorizontal( LST, geo->lat() );
02099 
02100         //Asteroids
02101         if ( Options::showAsteroids() ) {
02102             for ( KSAsteroid *ast = asteroidList.first(); ast; ast = asteroidList.next() ) {
02103                 ast->EquatorialToHorizontal( LST, geo->lat() );
02104                 if ( ast->hasTrail() ) ast->updateTrail( LST, geo->lat() );
02105             }
02106         }
02107 
02108         //Comets
02109         if ( Options::showComets() ) {
02110             for ( KSComet *com = cometList.first(); com; com = cometList.next() ) {
02111                 com->EquatorialToHorizontal( LST, geo->lat() );
02112                 if ( com->hasTrail() ) com->updateTrail( LST, geo->lat() );
02113             }
02114         }
02115 
02116         //Stars (need to update if constell. lines or stars are shown)
02117         if ( Options::showStars() || Options::showCLines() ) {
02118             // use MINDRAWSTARMAG for calculating constellation lines right
02119             float mag = Options::magLimitDrawStar();
02120             if (mag < MINDRAWSTARMAG) mag = MINDRAWSTARMAG;
02121             for ( StarObject *star = starList.first(); star; star = starList.next() ) {
02122                 if ( star->mag() > mag ) break;
02123                 if (needNewCoords) star->updateCoords( &num );
02124                 star->EquatorialToHorizontal( LST, geo->lat() );
02125             }
02126         }
02127 
02128         //Deep-sky objects. Keep lists separated for performance reasons
02129         if ( Options::showMessier() || Options::showMessierImages() ) {
02130             for ( SkyObject *o = deepSkyListMessier.first(); o; o = deepSkyListMessier.next() ) {
02131                 if (needNewCoords) o->updateCoords( &num );
02132                 o->EquatorialToHorizontal( LST, geo->lat() );
02133             }
02134         }
02135         if ( Options::showNGC() ) {
02136             for ( SkyObject *o = deepSkyListNGC.first(); o; o = deepSkyListNGC.next() ) {
02137                 if (needNewCoords) o->updateCoords( &num );
02138                 o->EquatorialToHorizontal( LST, geo->lat() );
02139             }
02140         }
02141         if ( Options::showIC() ) {
02142             for ( SkyObject *o = deepSkyListIC.first(); o; o = deepSkyListIC.next() ) {
02143                 if (needNewCoords) o->updateCoords( &num );
02144                 o->EquatorialToHorizontal( LST, geo->lat() );
02145             }
02146         }
02147         if ( Options::showOther() ) {
02148             for ( SkyObject *o = deepSkyListOther.first(); o; o = deepSkyListOther.next() ) {
02149                 if (needNewCoords) o->updateCoords( &num );
02150                 o->EquatorialToHorizontal( LST, geo->lat() );
02151             }
02152         }
02153 
02154 
02155         //Custom Catalogs
02156         for ( unsigned int j=0; j< CustomCatalogs.count(); ++j ) {
02157             QPtrList<SkyObject> cat = CustomCatalogs.at(j)->objList();
02158             if ( Options::showCatalog()[j] ) {
02159                                  for ( SkyObject *o = cat.first(); o; o = cat.next() ) {
02160                     if (needNewCoords) o->updateCoords( &num );
02161                     o->EquatorialToHorizontal( LST, geo->lat() );
02162                 }
02163             }
02164         }
02165 
02166         //Milky Way
02167         if ( Options::showMilkyWay() ) {
02168             for ( unsigned int j=0; j<11; ++j ) {
02169                 for ( SkyPoint *p = MilkyWay[j].first(); p; p = MilkyWay[j].next() ) {
02170                     if (needNewCoords) p->updateCoords( &num );
02171                     p->EquatorialToHorizontal( LST, geo->lat() );
02172                 }
02173             }
02174         }
02175 
02176         //CNames
02177         if ( Options::showCNames() ) {
02178             for ( SkyPoint *p = cnameList.first(); p; p = cnameList.next() ) {
02179                 if (needNewCoords) p->updateCoords( &num );
02180                 p->EquatorialToHorizontal( LST, geo->lat() );
02181             }
02182         }
02183 
02184         //Constellation Boundaries
02185         if ( Options::showCBounds() ) {  
02186             for ( CSegment *seg = csegmentList.first(); seg; seg = csegmentList.next() ) {
02187                 for ( SkyPoint *p = seg->firstNode(); p; p = seg->nextNode() ) {
02188                     if ( needNewCoords ) p->updateCoords( &num );
02189                     p->EquatorialToHorizontal( LST, geo->lat() );
02190                 }
02191             }
02192         }
02193         
02194         //Celestial Equator
02195         if ( Options::showEquator() ) {
02196             for ( SkyPoint *p = Equator.first(); p; p = Equator.next() ) {
02197                 p->EquatorialToHorizontal( LST, geo->lat() );
02198             }
02199         }
02200 
02201         //Ecliptic
02202         if ( Options::showEcliptic() ) {
02203             for ( SkyPoint *p = Ecliptic.first(); p; p = Ecliptic.next() ) {
02204                 p->EquatorialToHorizontal( LST, geo->lat() );
02205             }
02206         }
02207 
02208         //Horizon: different than the others; Alt & Az remain constant, RA, Dec must keep up
02209         if ( Options::showHorizon() || Options::showGround() ) {
02210             for ( SkyPoint *p = Horizon.first(); p; p = Horizon.next() ) {
02211                 p->HorizontalToEquatorial( LST, geo->lat() );
02212             }
02213         }
02214 
02215         for (SkyObject *o = INDITelescopeList.first(); o; o = INDITelescopeList.next())
02216             o->EquatorialToHorizontal(LST, geo->lat());
02217 
02218         //Update focus
02219         skymap->updateFocus();
02220 
02221         if ( clock()->isManualMode() )
02222             QTimer::singleShot( 0, skymap, SLOT( forceUpdateNow() ) );
02223         else skymap->forceUpdate();
02224     }
02225 }
02226 
02227 void KStarsData::setTimeDirection( float scale ) {
02228     TimeRunsForward = ( scale < 0 ? false : true );
02229 }
02230 
02231 void KStarsData::setFullTimeUpdate() {
02232     LastSkyUpdate.setDJD(    (long double)INVALID_DAY );
02233     LastPlanetUpdate.setDJD( (long double)INVALID_DAY );
02234     LastMoonUpdate.setDJD(   (long double)INVALID_DAY );
02235     LastNumUpdate.setDJD(    (long double)INVALID_DAY );
02236 }
02237 
02238 void KStarsData::setLocationFromOptions() {
02239     QMap<QString, TimeZoneRule>::Iterator it = Rulebook.find( Options::dST() );
02240     setLocation( GeoLocation ( Options::longitude(), Options::latitude(), 
02241             Options::cityName(), Options::provinceName(), Options::countryName(), 
02242             Options::timeZone(), &(it.data()), 4, Options::elevation() ) );
02243 }
02244 
02245 void KStarsData::setLocation( const GeoLocation &l ) {
02246     GeoLocation g( l );
02247     if ( g.lat()->Degrees() >= 90.0 ) g.setLat( 89.99 );
02248     if ( g.lat()->Degrees() <= -90.0 ) g.setLat( -89.99 );
02249 
02250     Geo = g;
02251 
02252     //store data in the Options objects
02253     Options::setCityName( g.name() );
02254     Options::setProvinceName( g.province() );
02255     Options::setCountryName( g.country() );
02256     Options::setTimeZone( g.TZ0() );
02257     Options::setElevation( g.height() );
02258     Options::setLongitude( g.lng()->Degrees() );
02259     Options::setLatitude( g.lat()->Degrees() );
02260 }
02261 
02262 void KStarsData::syncLST() {
02263     LST->set( geo()->GSTtoLST( ut().gst() ) );
02264 }
02265 
02266 void KStarsData::changeDateTime( const KStarsDateTime &newDate ) {
02267     //Turn off animated slews for the next time step.
02268     setSnapNextFocus();
02269     
02270     clock()->setUTC( newDate );
02271     LTime = geo()->UTtoLT( ut() );
02272     //set local sideral time
02273     syncLST();
02274     
02275     //Make sure Numbers, Moon, planets, and sky objects are updated immediately
02276     setFullTimeUpdate();
02277 
02278     // reset tzrules data with new local time and time direction (forward or backward)
02279     geo()->tzrule()->reset_with_ltime(LTime, geo()->TZ0(), isTimeRunningForward() );
02280 
02281     // reset next dst change time
02282     setNextDSTChange( geo()->tzrule()->nextDSTChange() );
02283 }
02284 
02285 SkyObject* KStarsData::objectNamed( const QString &name ) {
02286     if ( (name== "star") || (name== "nothing") || name.isEmpty() ) return NULL;
02287     if ( name== Moon->name() ) return Moon;
02288 
02289     SkyObject *so = PCat->findByName(name);
02290 
02291     if (so != 0)
02292         return so;
02293 
02294     //Stars
02295     for ( unsigned int i=0; i<starList.count(); ++i ) {
02296         if ( name==starList.at(i)->name() ) return starList.at(i);
02297     }
02298 
02299     //Deep sky objects
02300     for ( unsigned int i=0; i<deepSkyListMessier.count(); ++i ) {
02301         if ( name==deepSkyListMessier.at(i)->name() ) return deepSkyListMessier.at(i);
02302     }
02303     for ( unsigned int i=0; i<deepSkyListNGC.count(); ++i ) {
02304         if ( name==deepSkyListNGC.at(i)->name() ) return deepSkyListNGC.at(i);
02305     }
02306     for ( unsigned int i=0; i<deepSkyListIC.count(); ++i ) {
02307         if ( name==deepSkyListIC.at(i)->name() ) return deepSkyListIC.at(i);
02308     }
02309     for ( unsigned int i=0; i<deepSkyListOther.count(); ++i ) {
02310         if ( name==deepSkyListOther.at(i)->name() ) return deepSkyListOther.at(i);
02311     }
02312 
02313     //Constellations
02314     for ( unsigned int i=0; i<cnameList.count(); ++i ) {
02315         if ( name==cnameList.at(i)->name() ) return cnameList.at(i);
02316     }
02317 
02318     //Still no match.  Try interpreting the string as a genetive star name 
02319     //(with ascii characters instead of a Greek letter)
02320     for ( unsigned int i=0; i<starList.count(); ++i ) {
02321         if ( name==starList.at(i)->gname( false ) ) return starList.at(i);
02322     }
02323 
02324        //Custom catalogs. 
02325         for ( unsigned int i=0; i<CustomCatalogs.count(); ++i ) {
02326                 QPtrList<SkyObject> custCatObjs = CustomCatalogs.at(i)->objList();
02327                 for ( unsigned int j = 0; j < custCatObjs.count(); ++j ) {
02328                         if ( name==custCatObjs.at(j)->name() ) return custCatObjs.at(j);
02329                 }
02330         }
02331 
02332     //reach here only if argument is not matched
02333     return NULL;
02334 }
02335 
02336 //"pseudo-execute" a shell script, ignoring all interactive aspects.  Just use
02337 //the portions of the script that change the state of the program.  This is only
02338 //used for image-dump mode, where the GUI is not running.  So, some things (such as
02339 //waitForKey()) don't make sense and should be ignored.
02340 //also, even functions that do make sense in this context have aspects that should
02341 //be modified or ignored.  For example, we don't need to call slotCenter() on recentering
02342 //commands, just setDestination().  (sltoCenter() does additional things that we dont need).
02343 bool KStarsData::executeScript( const QString &scriptname, SkyMap *map ) {
02344     int cmdCount(0);
02345 
02346     QFile f( scriptname );
02347     if ( !f.open( IO_ReadOnly) ) {
02348         kdDebug() << i18n( "Could not open file %1" ).arg( f.name() ) << endl;
02349         return false;
02350     }
02351 
02352     QTextStream istream(&f);
02353     while ( ! istream.eof() ) {
02354         QString line = istream.readLine();
02355 
02356         //found a dcop line
02357         if ( line.left(4) == "dcop" ) {
02358             line = line.mid( 20 );  //strip away leading characters
02359             QStringList fn = QStringList::split( " ", line );
02360 
02361             if ( fn[0] == "lookTowards" && fn.count() >= 2 ) {
02362                 double az(-1.0);
02363                 QString arg = fn[1].lower();
02364                 if ( arg == "n"  || arg == "north" )     az =   0.0;
02365                 if ( arg == "ne" || arg == "northeast" ) az =  45.0;
02366                 if ( arg == "e"  || arg == "east" )      az =  90.0;
02367                 if ( arg == "se" || arg == "southeast" ) az = 135.0;
02368                 if ( arg == "s"  || arg == "south" )     az = 180.0;
02369                 if ( arg == "sw" || arg == "southwest" ) az = 225.0;
02370                 if ( arg == "w"  || arg == "west" )      az = 270.0;
02371                 if ( arg == "nw" || arg == "northwest" ) az = 335.0;
02372                 if ( az >= 0.0 ) { 
02373                     map->setFocusAltAz( 15.0, az ); 
02374                     cmdCount++; 
02375                     map->setDestination( map->focus() );
02376                 }
02377 
02378                 if ( arg == "z" || arg == "zenith" ) {
02379                     map->setFocusAltAz( 90.0, map->focus()->az()->Degrees() );
02380                     cmdCount++;
02381                     map->setDestination( map->focus() );
02382                 }
02383 
02384                 //try a named object.  name is everything after the first word (which is 'lookTowards')
02385                 fn.remove( fn.first() );
02386                 SkyObject *target = objectNamed( fn.join( " " ) );
02387                 if ( target ) { map->setFocus( target ); cmdCount++; }
02388 
02389             } else if ( fn[0] == "setRaDec" && fn.count() == 3 ) {
02390                 bool ok( false );
02391                 dms r(0.0), d(0.0);
02392 
02393                 ok = r.setFromString( fn[1], false ); //assume angle in hours
02394                 if ( ok ) ok = d.setFromString( fn[2], true );  //assume angle in degrees
02395                 if ( ok ) {
02396                     map->setFocus( r, d );
02397                     cmdCount++;
02398                 }
02399 
02400             } else if ( fn[0] == "setAltAz" && fn.count() == 3 ) {
02401                 bool ok( false );
02402                 dms az(0.0), alt(0.0);
02403 
02404                 ok = alt.setFromString( fn[1] );
02405                 if ( ok ) ok = az.setFromString( fn[2] );
02406                 if ( ok ) {
02407                     map->setFocusAltAz( alt, az );
02408                     cmdCount++;
02409                 }
02410 
02411             } else if ( fn[0] == "zoom" && fn.count() == 2 ) {
02412                 bool ok(false);
02413                 double z = fn[1].toDouble(&ok);
02414                 if ( ok ) {
02415                     if ( z > MAXZOOM ) z = MAXZOOM;
02416                     if ( z < MINZOOM ) z = MINZOOM;
02417                     Options::setZoomFactor( z );
02418                     cmdCount++;
02419                 }
02420 
02421             } else if ( fn[0] == "zoomIn" ) {
02422                 if ( Options::zoomFactor() < MAXZOOM ) {
02423                     Options::setZoomFactor( Options::zoomFactor() * DZOOM );
02424                     cmdCount++;
02425                 }
02426             } else if ( fn[0] == "zoomOut" ) {
02427                 if ( Options::zoomFactor() > MINZOOM ) {
02428                     Options::setZoomFactor( Options::zoomFactor() / DZOOM );
02429                     cmdCount++;
02430                 }
02431             } else if ( fn[0] == "defaultZoom" ) {
02432                 Options::setZoomFactor( DEFAULTZOOM );
02433                 cmdCount++;
02434             } else if ( fn[0] == "setLocalTime" && fn.count() == 7 ) {
02435                 bool ok(false);
02436                 int yr(0), mth(0), day(0) ,hr(0), min(0), sec(0);
02437                 yr = fn[1].toInt(&ok);
02438                 if ( ok ) mth = fn[2].toInt(&ok);
02439                 if ( ok ) day = fn[3].toInt(&ok);
02440                 if ( ok ) hr  = fn[4].toInt(&ok);
02441                 if ( ok ) min = fn[5].toInt(&ok);
02442                 if ( ok ) sec = fn[6].toInt(&ok);
02443                 if ( ok ) {
02444                     changeDateTime( geo()->LTtoUT( KStarsDateTime( ExtDate(yr, mth, day), QTime(hr,min,sec) ) ) );
02445                     cmdCount++;
02446                 } else {
02447                     kdWarning() << i18n( "Could not set time: %1 / %2 / %3 ; %4:%5:%6" )
02448                         .arg(day).arg(mth).arg(yr).arg(hr).arg(min).arg(sec) << endl;
02449                 }
02450             } else if ( fn[0] == "changeViewOption" && fn.count() == 3 ) {
02451                 bool bOk(false), nOk(false), dOk(false);
02452 
02453                 //parse bool value
02454                 bool bVal(false);
02455                 if ( fn[2].lower() == "true" ) { bOk = true; bVal = true; }
02456                 if ( fn[2].lower() == "false" ) { bOk = true; bVal = false; }
02457                 if ( fn[2] == "1" ) { bOk = true; bVal = true; }
02458                 if ( fn[2] == "0" ) { bOk = true; bVal = false; }
02459 
02460                 //parse int value
02461                 int nVal = fn[2].toInt( &nOk );
02462 
02463                 //parse double value
02464                 double dVal = fn[2].toDouble( &dOk );
02465 
02466                 if ( fn[1] == "FOVName"                ) { Options::setFOVName(       fn[2] ); cmdCount++; }
02467                 if ( fn[1] == "FOVSize"         && dOk ) { Options::setFOVSize( (float)dVal ); cmdCount++; }
02468                 if ( fn[1] == "FOVShape"        && nOk ) { Options::setFOVShape(       nVal ); cmdCount++; }
02469                 if ( fn[1] == "FOVColor"               ) { Options::setFOVColor(      fn[2] ); cmdCount++; }
02470                 if ( fn[1] == "ShowStars"         && bOk ) { Options::setShowStars(    bVal ); cmdCount++; }
02471                 if ( fn[1] == "ShowMessier"        && bOk ) { Options::setShowMessier( bVal ); cmdCount++; }
02472                 if ( fn[1] == "ShowMessierImages"  && bOk ) { Options::setShowMessierImages( bVal ); cmdCount++; }
02473                 if ( fn[1] == "ShowCLines"      && bOk ) { Options::setShowCLines(   bVal ); cmdCount++; }
02474                 if ( fn[1] == "ShowCNames"      && bOk ) { Options::setShowCNames(   bVal ); cmdCount++; }
02475                 if ( fn[1] == "ShowNGC"         && bOk ) { Options::setShowNGC(      bVal ); cmdCount++; }
02476                 if ( fn[1] == "ShowIC"          && bOk ) { Options::setShowIC(       bVal ); cmdCount++; }
02477                 if ( fn[1] == "ShowMilkyWay"    && bOk ) { Options::setShowMilkyWay( bVal ); cmdCount++; }
02478                 if ( fn[1] == "ShowGrid"        && bOk ) { Options::setShowGrid(     bVal ); cmdCount++; }
02479                 if ( fn[1] == "ShowEquator"     && bOk ) { Options::setShowEquator(  bVal ); cmdCount++; }
02480                 if ( fn[1] == "ShowEcliptic"    && bOk ) { Options::setShowEcliptic( bVal ); cmdCount++; }
02481                 if ( fn[1] == "ShowHorizon"     && bOk ) { Options::setShowHorizon(  bVal ); cmdCount++; }
02482                 if ( fn[1] == "ShowGround"      && bOk ) { Options::setShowGround(   bVal ); cmdCount++; }
02483                 if ( fn[1] == "ShowSun"         && bOk ) { Options::setShowSun(      bVal ); cmdCount++; }
02484                 if ( fn[1] == "ShowMoon"        && bOk ) { Options::setShowMoon(     bVal ); cmdCount++; }
02485                 if ( fn[1] == "ShowMercury"     && bOk ) { Options::setShowMercury(  bVal ); cmdCount++; }
02486                 if ( fn[1] == "ShowVenus"       && bOk ) { Options::setShowVenus(    bVal ); cmdCount++; }
02487                 if ( fn[1] == "ShowMars"        && bOk ) { Options::setShowMars(     bVal ); cmdCount++; }
02488                 if ( fn[1] == "ShowJupiter"     && bOk ) { Options::setShowJupiter(  bVal ); cmdCount++; }
02489                 if ( fn[1] == "ShowSaturn"      && bOk ) { Options::setShowSaturn(   bVal ); cmdCount++; }
02490                 if ( fn[1] == "ShowUranus"      && bOk ) { Options::setShowUranus(   bVal ); cmdCount++; }
02491                 if ( fn[1] == "ShowNeptune"     && bOk ) { Options::setShowNeptune(  bVal ); cmdCount++; }
02492                 if ( fn[1] == "ShowPluto"       && bOk ) { Options::setShowPluto(    bVal ); cmdCount++; }
02493                 if ( fn[1] == "ShowAsteroids"   && bOk ) { Options::setShowAsteroids( bVal ); cmdCount++; }
02494                 if ( fn[1] == "ShowComets"      && bOk ) { Options::setShowComets(   bVal ); cmdCount++; }
02495                 if ( fn[1] == "ShowPlanets"     && bOk ) { Options::setShowPlanets(  bVal ); cmdCount++; }
02496                 if ( fn[1] == "ShowDeepSky"     && bOk ) { Options::setShowDeepSky(  bVal ); cmdCount++; }
02497                 if ( fn[1] == "ShowStarNames"      && bOk ) { Options::setShowStarNames(      bVal ); cmdCount++; }
02498                 if ( fn[1] == "ShowStarMagnitudes" && bOk ) { Options::setShowStarMagnitudes( bVal ); cmdCount++; }
02499                 if ( fn[1] == "ShowAsteroidNames"  && bOk ) { Options::setShowAsteroidNames(  bVal ); cmdCount++; }
02500                 if ( fn[1] == "ShowCometNames"     && bOk ) { Options::setShowCometNames(     bVal ); cmdCount++; }
02501                 if ( fn[1] == "ShowPlanetNames"    && bOk ) { Options::setShowPlanetNames(    bVal ); cmdCount++; }
02502                 if ( fn[1] == "ShowPlanetImages"   && bOk ) { Options::setShowPlanetImages(   bVal ); cmdCount++; }
02503 
02504                 if ( fn[1] == "UseAltAz"         && bOk ) { Options::setUseAltAz(      bVal ); cmdCount++; }
02505                 if ( fn[1] == "UseRefraction"    && bOk ) { Options::setUseRefraction( bVal ); cmdCount++; }
02506                 if ( fn[1] == "UseAutoLabel"     && bOk ) { Options::setUseAutoLabel(  bVal ); cmdCount++; }
02507                 if ( fn[1] == "UseAutoTrail"     && bOk ) { Options::setUseAutoTrail(  bVal ); cmdCount++; }
02508                 if ( fn[1] == "UseAnimatedSlewing"   && bOk ) { Options::setUseAnimatedSlewing( bVal ); cmdCount++; }
02509                 if ( fn[1] == "FadePlanetTrails" && bOk ) { Options::setFadePlanetTrails( bVal ); cmdCount++; }
02510                 if ( fn[1] == "SlewTimeScale"    && dOk ) { Options::setSlewTimeScale(    dVal ); cmdCount++; }
02511                 if ( fn[1] == "ZoomFactor"       && dOk ) { Options::setZoomFactor(       dVal ); cmdCount++; }
02512                 if ( fn[1] == "MagLimitDrawStar"     && dOk ) { Options::setMagLimitDrawStar( dVal ); cmdCount++; }
02513                 if ( fn[1] == "MagLimitDrawStarZoomOut" && dOk ) { Options::setMagLimitDrawStarZoomOut( dVal ); cmdCount++; }
02514                 if ( fn[1] == "MagLimitDrawDeepSky"     && dOk ) { Options::setMagLimitDrawDeepSky( dVal ); cmdCount++; }
02515                 if ( fn[1] == "MagLimitDrawDeepSkyZoomOut" && dOk ) { Options::setMagLimitDrawDeepSkyZoomOut( dVal ); cmdCount++; }
02516                 if ( fn[1] == "MagLimitDrawStarInfo" && dOk ) { Options::setMagLimitDrawStarInfo( dVal ); cmdCount++; }
02517                 if ( fn[1] == "MagLimitHideStar"     && dOk ) { Options::setMagLimitHideStar(     dVal ); cmdCount++; }
02518                 if ( fn[1] == "MagLimitAsteroid"     && dOk ) { Options::setMagLimitAsteroid(     dVal ); cmdCount++; }
02519                 if ( fn[1] == "MagLimitAsteroidName" && dOk ) { Options::setMagLimitAsteroidName( dVal ); cmdCount++; }
02520                 if ( fn[1] == "MaxRadCometName"      && dOk ) { Options::setMaxRadCometName(      dVal ); cmdCount++; }
02521 
02522                 //these three are a "radio group"
02523                 if ( fn[1] == "UseLatinConstellationNames" && bOk ) {
02524                     Options::setUseLatinConstellNames( true );
02525                     Options::setUseLocalConstellNames( false );
02526                     Options::setUseAbbrevConstellNames( false );
02527                     cmdCount++;
02528                 }
02529                 if ( fn[1] == "UseLocalConstellationNames" && bOk ) {
02530                     Options::setUseLatinConstellNames( false );
02531                     Options::setUseLocalConstellNames( true );
02532                     Options::setUseAbbrevConstellNames( false );
02533                     cmdCount++;
02534                 }
02535                 if ( fn[1] == "UseAbbrevConstellationNames" && bOk ) {
02536                     Options::setUseLatinConstellNames( false );
02537                     Options::setUseLocalConstellNames( false );
02538                     Options::setUseAbbrevConstellNames( true );
02539                     cmdCount++;
02540                 }
02541             } else if ( fn[0] == "setGeoLocation" && ( fn.count() == 3 || fn.count() == 4 ) ) {
02542                 QString city( fn[1] ), province( "" ), country( fn[2] );
02543                 if ( fn.count() == 4 ) {
02544                     province = fn[2];
02545                     country = fn[3];
02546                 }
02547 
02548                 bool cityFound( false );
02549                 for (GeoLocation *loc = geoList.first(); loc; loc = geoList.next()) {
02550                     if ( loc->translatedName() == city &&
02551                                 ( province.isEmpty() || loc->translatedProvince() == province ) &&
02552                                 loc->translatedCountry() == country ) {
02553 
02554                         cityFound = true;
02555                         setLocation( *loc );
02556                         cmdCount++;
02557                         break;
02558                     }
02559                 }
02560 
02561                 if ( !cityFound )
02562                     kdWarning() << i18n( "Could not set location named %1, %2, %3" ).arg(city).arg(province).arg(country) << endl;
02563             }
02564         }
02565     }  //end while
02566 
02567     if ( cmdCount ) return true;
02568     return false;
02569 }
02570 
02571 void KStarsData::appendTelescopeObject(SkyObject * object)
02572 {
02573   INDITelescopeList.append(object);
02574 }
02575 
02576 void KStarsData::saveTimeBoxShaded( bool b ) { Options::setShadeTimeBox( b ); }
02577 void KStarsData::saveGeoBoxShaded( bool b ) { Options::setShadeGeoBox( b ); }
02578 void KStarsData::saveFocusBoxShaded( bool b ) { Options::setShadeFocusBox( b ); }
02579 void KStarsData::saveTimeBoxPos( QPoint p ) { Options::setPositionTimeBox( p ); }
02580 void KStarsData::saveGeoBoxPos( QPoint p ) { Options::setPositionGeoBox( p ); }
02581 void KStarsData::saveFocusBoxPos( QPoint p ) { Options::setPositionFocusBox( p ); }
02582 
02583 #include "kstarsdata.moc"

kstars

Skip menu "kstars"
  • Main Page
  • Modules
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • keduca
  • kstars
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal