moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kstars / kstars / kstarsdata.cpp
blobba2f889fc1da6f3a729854537776d3cfdfd0360c
1 /***************************************************************************
2 kstarsdata.cpp - K Desktop Planetarium
3 -------------------
4 begin : Sun Jul 29 2001
5 copyright : (C) 2001 by Heiko Evermann
6 email : heiko@evermann.de
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include <qregexp.h>
19 #include <qdir.h>
20 #include <qfile.h>
22 #include <kapplication.h>
23 #include <kmessagebox.h>
24 #include <kdebug.h>
25 #include <klocale.h>
26 #include <kstandarddirs.h>
28 #include "kstarsdata.h"
30 #include "Options.h"
31 #include "dms.h"
32 #include "skymap.h"
33 #include "ksutils.h"
34 #include "ksnumbers.h"
35 #include "skypoint.h"
36 #include "skyobject.h"
37 #include "starobject.h"
38 #include "deepskyobject.h"
39 #include "skyobjectname.h"
40 #include "ksplanet.h"
41 #include "ksasteroid.h"
42 #include "kscomet.h"
43 #include "ksmoon.h"
44 #include "jupitermoons.h"
46 #include "simclock.h"
47 #include "timezonerule.h"
48 #include "filesource.h"
49 #include "stardatasink.h"
50 #include "ksfilereader.h"
51 #include "indidriver.h"
52 #include "indi/lilxml.h"
53 #include "indistd.h"
54 #include "detaildialog.h"
55 #include "csegment.h"
57 QPtrList<GeoLocation> KStarsData::geoList = QPtrList<GeoLocation>();
58 QMap<QString, TimeZoneRule> KStarsData::Rulebook = QMap<QString, TimeZoneRule>();
59 int KStarsData::objects = 0;
61 KStarsData::KStarsData() : stdDirs(0), locale(0),
62 LST(0), HourAngle(0),
63 PCat(0), Moon(0), jmoons(0),
64 starFileReader(0), initTimer(0),
65 source(0), loader(0), pump(0)
67 startupComplete = false;
68 objects++;
70 //standard directories and locale objects
71 stdDirs = new KStandardDirs();
72 locale = new KLocale( "kstars" );
74 //Check to see if config file already exists. If not, set
75 //useDefaultOptions = true
76 QString fname = locate( "config", "kstarsrc" );
77 useDefaultOptions = fname.isEmpty();
79 //Instantiate LST and HourAngle
80 LST = new dms();
81 HourAngle = new dms();
83 //Instantiate planet catalog
84 PCat = new PlanetCatalog(this);
86 //initialize FOV symbol
87 fovSymbol = FOV();
89 //set AutoDelete property for QPtrLists. Most are set TRUE,
90 //but some 'meta-lists' need to be FALSE.
91 starList.setAutoDelete( TRUE );
92 ADVtreeList.setAutoDelete( TRUE );
93 geoList.setAutoDelete( TRUE );
94 deepSkyList.setAutoDelete( TRUE ); // list of all deep space objects
96 //separate lists for each deep-sky catalog. The objects are duplicates of
97 //deepSkyList, so do not delete them twice!
98 deepSkyListMessier.setAutoDelete( FALSE );
99 deepSkyListNGC.setAutoDelete( FALSE );
100 deepSkyListIC.setAutoDelete( FALSE );
101 deepSkyListOther.setAutoDelete( FALSE );
103 //ObjLabelList does not construct new objects, so no autoDelete needed
104 ObjLabelList.setAutoDelete( FALSE );
106 cometList.setAutoDelete( TRUE );
107 asteroidList.setAutoDelete( TRUE );
109 //Constellation lines are now pointers to existing StarObjects;
110 //these are already auto-deleted by starList.
111 clineList.setAutoDelete( FALSE );
112 clineModeList.setAutoDelete( TRUE );
113 cnameList.setAutoDelete( TRUE );
114 csegmentList.setAutoDelete( TRUE );
116 Equator.setAutoDelete( TRUE );
117 Ecliptic.setAutoDelete( TRUE );
118 Horizon.setAutoDelete( TRUE );
119 for ( unsigned int i=0; i<11; ++i ) MilkyWay[i].setAutoDelete( TRUE );
121 VariableStarsList.setAutoDelete(TRUE);
122 INDIHostsList.setAutoDelete(TRUE);
124 //Initialize object type strings
125 //(type==-1 is a constellation)
126 TypeName[0] = i18n( "star" );
127 TypeName[1] = i18n( "multiple star" );
128 TypeName[2] = i18n( "planet" );
129 TypeName[3] = i18n( "open cluster" );
130 TypeName[4] = i18n( "globular cluster" );
131 TypeName[5] = i18n( "gaseous nebula" );
132 TypeName[6] = i18n( "planetary nebula" );
133 TypeName[7] = i18n( "supernova remnant" );
134 TypeName[8] = i18n( "galaxy" );
135 TypeName[9] = i18n( "comet" );
136 TypeName[10] = i18n( "asteroid" );
137 TypeName[11] = i18n( "constellation" );
139 // at startup times run forward
140 setTimeDirection( 0.0 );
142 temporaryTrail = false;
145 KStarsData::~KStarsData() {
146 objects--;
147 checkDataPumpAction();
149 // the list items do not need to be removed by hand.
150 // all lists are set to AutoDelete = true
152 delete stdDirs;
153 delete Moon;
154 delete locale;
155 delete PCat;
156 delete jmoons;
157 delete initTimer;
160 bool KStarsData::readMWData( void ) {
161 QFile file;
163 for ( unsigned int i=0; i<11; ++i ) {
164 QString snum, fname, szero;
165 snum = snum.setNum( i+1 );
166 if ( i+1 < 10 ) szero = "0"; else szero = "";
167 fname = "mw" + szero + snum + ".dat";
169 if ( KSUtils::openDataFile( file, fname ) ) {
170 KSFileReader fileReader( file ); // close file is included
171 while ( fileReader.hasMoreLines() ) {
172 QString line;
173 double ra, dec;
175 line = fileReader.readLine();
177 ra = line.mid( 0, 8 ).toDouble();
178 dec = line.mid( 9, 8 ).toDouble();
180 SkyPoint *o = new SkyPoint( ra, dec );
181 MilkyWay[i].append( o );
183 } else {
184 return false;
187 return true;
190 bool KStarsData::readADVTreeData(void)
193 QFile file;
194 QString Interface;
196 if (!KSUtils::openDataFile(file, "advinterface.dat"))
197 return false;
199 QTextStream stream(&file);
200 QString Line;
202 while (!stream.atEnd())
204 QString Name, Link, subName;
205 int Type, interfaceIndex;
207 Line = stream.readLine();
209 if (Line.startsWith("[KSLABEL]"))
211 Name = Line.mid(9);
212 Type = 0;
214 else if (Line.startsWith("[END]"))
215 Type = 1;
216 else if (Line.startsWith("[KSINTERFACE]"))
218 Interface = Line.mid(13);
219 continue;
222 else
224 Name = Line.mid(0, Line.find(":"));
225 Link = Line.mid(Line.find(":") + 1);
227 // Link is empty, using Interface instead
228 if (Link.isEmpty())
230 Link = Interface;
231 subName = Name;
232 interfaceIndex = Link.find("KSINTERFACE");
233 Link.remove(interfaceIndex, 11);
234 Link = Link.insert(interfaceIndex, subName.replace( QRegExp(" "), "+"));
238 Type = 2;
241 ADVTreeData *ADVData = new ADVTreeData;
243 ADVData->Name = Name;
244 ADVData->Link = Link;
245 ADVData->Type = Type;
247 ADVtreeList.append(ADVData);
250 return true;
256 bool KStarsData::readVARData(void)
258 QString varFile("valaav.txt");
259 QFile localeFile;
260 QFile file;
262 file.setName( locateLocal( "appdata", varFile ) );
263 if ( !file.open( IO_ReadOnly ) )
265 // Open default variable stars file
266 if ( KSUtils::openDataFile( file, varFile ) )
268 // we found urlfile, we need to copy it to locale
269 localeFile.setName( locateLocal( "appdata", varFile ) );
271 if (localeFile.open(IO_WriteOnly))
273 QTextStream readStream(&file);
274 QTextStream writeStream(&localeFile);
275 writeStream << readStream.read();
276 localeFile.close();
277 file.reset();
280 else
281 return false;
285 QTextStream stream(&file);
287 stream.readLine();
289 while (!stream.atEnd())
291 QString Name;
292 QString Designation;
293 QString Line;
295 Line = stream.readLine();
297 if (Line[0] == QChar('*'))
298 break;
300 Designation = Line.mid(0,8).stripWhiteSpace();
301 Name = Line.mid(10,20).simplifyWhiteSpace();
303 VariableStarInfo *VInfo = new VariableStarInfo;
305 VInfo->Designation = Designation;
306 VInfo->Name = Name;
307 VariableStarsList.append(VInfo);
310 return true;
315 bool KStarsData::readINDIHosts(void)
317 QString indiFile("indihosts.xml");
318 QFile localeFile;
319 QFile file;
320 char errmsg[1024];
321 signed char c;
322 LilXML *xmlParser = newLilXML();
323 XMLEle *root = NULL;
324 XMLAtt *ap;
326 file.setName( locate( "appdata", indiFile ) );
327 if ( file.name().isEmpty() || !file.open( IO_ReadOnly ) )
328 return false;
330 while ( (c = (signed char) file.getch()) != -1)
332 root = readXMLEle(xmlParser, c, errmsg);
334 if (root)
337 // Get host name
338 ap = findXMLAtt(root, "name");
339 if (!ap) {
340 delLilXML(xmlParser);
341 return false;
344 INDIHostsInfo *VInfo = new INDIHostsInfo;
346 VInfo->name = QString(valuXMLAtt(ap));
348 // Get host name
349 ap = findXMLAtt(root, "hostname");
351 if (!ap) {
352 delLilXML(xmlParser);
353 return false;
356 VInfo->hostname = QString(valuXMLAtt(ap));
358 ap = findXMLAtt(root, "port");
360 if (!ap) {
361 delLilXML(xmlParser);
362 return false;
365 VInfo->portnumber = QString(valuXMLAtt(ap));
367 VInfo->isConnected = false;
368 VInfo->mgrID = -1;
370 INDIHostsList.append(VInfo);
372 delXMLEle(root);
375 else if (errmsg[0])
376 kdDebug() << errmsg << endl;
380 delLilXML(xmlParser);
382 return true;
387 bool KStarsData::readCLineData( void ) {
388 //The constellation lines data file (clines.dat) contains lists
389 //of abbreviated genetive star names in the same format as they
390 //appear in the star data files (hipNNN.dat).
392 //Each constellation consists of a QPtrList of SkyPoints,
393 //corresponding to the stars at each "node" of the constellation.
394 //These are pointers to the starobjects themselves, so the nodes
395 //will automatically be fixed to the stars even as the star
396 //positions change due to proper motions. In addition, each node
397 //has a corresponding flag that determines whether a line should
398 //connect this node and the previous one.
400 QFile file;
401 if ( KSUtils::openDataFile( file, "clines.dat" ) ) {
402 QTextStream stream( &file );
404 while ( !stream.eof() ) {
405 QString line, name;
406 QChar *mode;
408 line = stream.readLine();
410 //ignore lines beginning with "#":
411 if ( line.at( 0 ) != '#' ) {
412 name = line.mid( 2 ).stripWhiteSpace();
414 //Find the star with the same abbreviated genitive name ( name2() )
415 //increase efficiency by searching the list of named objects, rather than the
416 //full list of all stars.
417 bool starFound( false );
418 for ( SkyObjectName *oname = ObjNames.first(); oname; oname = ObjNames.next() ) {
419 if ( oname->skyObject()->type() == SkyObject::STAR &&
420 oname->skyObject()->name2() == name ) {
421 starFound = true;
422 clineList.append( (SkyPoint *)( oname->skyObject() ) );
424 mode = new QChar( line.at( 0 ) );
425 clineModeList.append( mode );
426 break;
430 if ( ! starFound )
431 kdWarning() << i18n( "No star named %1 found." ).arg(name) << endl;
434 file.close();
436 return true;
437 } else {
438 return false;
442 bool KStarsData::readCNameData( void ) {
443 QFile file;
444 cnameFile = "cnames.dat";
446 if ( KSUtils::openDataFile( file, cnameFile ) ) {
447 QTextStream stream( &file );
449 while ( !stream.eof() ) {
450 QString line, name, abbrev;
451 int rah, ram, ras, dd, dm, ds;
452 QChar sgn;
454 line = stream.readLine();
456 rah = line.mid( 0, 2 ).toInt();
457 ram = line.mid( 2, 2 ).toInt();
458 ras = line.mid( 4, 2 ).toInt();
460 sgn = line.at( 6 );
461 dd = line.mid( 7, 2 ).toInt();
462 dm = line.mid( 9, 2 ).toInt();
463 ds = line.mid( 11, 2 ).toInt();
465 abbrev = line.mid( 13, 3 );
466 name = line.mid( 17 ).stripWhiteSpace();
468 dms r; r.setH( rah, ram, ras );
469 dms d( dd, dm, ds );
471 if ( sgn == "-" ) { d.setD( -1.0*d.Degrees() ); }
473 SkyObject *o = new SkyObject( SkyObject::CONSTELLATION, r, d, 0.0, name, abbrev );
474 cnameList.append( o );
475 ObjNames.append( o );
477 file.close();
479 return true;
480 } else {
481 return false;
485 bool KStarsData::readCBoundData( void ) {
486 QFile file;
488 if ( KSUtils::openDataFile( file, "cbound.dat" ) ) {
489 QTextStream stream( &file );
491 unsigned int nn(0);
492 double ra(0.0), dec(0.0);
493 QString d1, d2;
494 bool ok(false), comment(false);
496 //read the stream one field at a time. Individual segments can span
497 //multiple lines, so our normal readLine() is less convenient here.
498 //Read fields into strings and then attempt to recast them as ints
499 //or doubles..this lets us do error checking on the stream.
500 while ( !stream.eof() ) {
501 stream >> d1;
502 if ( d1.at(0) == '#' ) {
503 comment = true;
504 ok = true;
505 } else {
506 comment = false;
507 nn = d1.toInt( &ok );
510 if ( !ok || comment ) {
511 d1 = stream.readLine();
513 if ( !ok )
514 kdWarning() << i18n( "Unable to parse boundary segment." ) << endl;
516 } else {
517 CSegment *seg = new CSegment();
519 for ( unsigned int i=0; i<nn; ++i ) {
520 stream >> d1 >> d2;
521 ra = d1.toDouble( &ok );
522 if ( ok ) dec = d2.toDouble( &ok );
523 if ( !ok ) break;
525 seg->addPoint( ra, dec );
528 if ( !ok ) {
529 //uh oh, this entry was not parsed. Skip to the next line.
530 kdWarning() << i18n( "Unable to parse boundary segment." ) << endl;
531 delete seg;
532 d1 = stream.readLine();
534 } else {
535 stream >> d1; //this should always equal 2
537 nn = d1.toInt( &ok );
538 //error check
539 if ( !ok || nn != 2 ) {
540 kdWarning() << i18n( "Bad Constellation Boundary data." ) << endl;
541 delete seg;
542 d1 = stream.readLine();
546 if ( ok ) {
547 stream >> d1 >> d2;
548 ok = seg->setNames( d1, d2 );
549 if ( ok ) csegmentList.append( seg );
554 return true;
555 } else {
556 return false;
560 bool KStarsData::openStarFile( int i ) {
561 if (starFileReader != 0) delete starFileReader;
562 QFile file;
563 QString snum, fname;
564 snum = QString().sprintf("%03d", i);
565 fname = "hip" + snum + ".dat";
566 if (KSUtils::openDataFile(file, fname)) {
567 starFileReader = new KSFileReader(file); // close file is included
568 } else {
569 starFileReader = 0;
570 return false;
572 return true;
575 bool KStarsData::readStarData( void ) {
576 bool ready = false;
578 float loadUntilMag = MINDRAWSTARMAG;
579 if (Options::magLimitDrawStar() > loadUntilMag) loadUntilMag = Options::magLimitDrawStar();
581 for (unsigned int i=1; i<NHIPFILES+1; ++i) {
582 emit progressText( i18n( "Loading Star Data (%1%)" ).arg( int(100.*float(i)/float(NHIPFILES)) ) );
584 if (openStarFile(i) == true) {
585 while (starFileReader->hasMoreLines()) {
586 QString line;
587 float mag;
589 line = starFileReader->readLine();
590 if ( line.left(1) != "#" ) { //ignore comments
591 // check star magnitude
592 mag = line.mid( 46,5 ).toFloat();
593 if ( mag > loadUntilMag ) {
594 ready = true;
595 break;
598 processStar(&line);
600 } // end of while
602 } else { //one of the star files could not be read.
603 if ( starList.count() ) return true;
604 else return false;
606 // magnitude level is reached
607 if (ready == true) break;
610 //Store the max set magnitude of current session. Will increase in KStarsData::appendNewData()
611 maxSetMagnitude = Options::magLimitDrawStar();
612 delete starFileReader;
613 starFileReader = 0;
614 return true;
617 void KStarsData::processStar( QString *line, bool reloadMode ) {
618 QString name, gname, SpType;
619 int rah, ram, ras, ras2, dd, dm, ds, ds2;
620 bool mult, var;
621 QChar sgn;
622 double mag, bv, dmag, vper;
623 double pmra, pmdec, plx;
625 name = ""; gname = "";
627 //parse coordinates
628 rah = line->mid( 0, 2 ).toInt();
629 ram = line->mid( 2, 2 ).toInt();
630 ras = int(line->mid( 4, 5 ).toDouble());
631 ras2 = int(60.0*(line->mid( 4, 5 ).toDouble()-ras) + 0.5); //add 0.5 to get nearest integer with int()
633 sgn = line->at(10);
634 dd = line->mid(11, 2).toInt();
635 dm = line->mid(13, 2).toInt();
636 ds = int(line->mid(15, 4).toDouble());
637 ds2 = int(60.0*(line->mid( 15, 5 ).toDouble()-ds) + 0.5); //add 0.5 to get nearest integer with int()
639 //parse proper motion and parallax
640 pmra = line->mid( 20, 9 ).toDouble();
641 pmdec = line->mid( 29, 9 ).toDouble();
642 plx = line->mid( 38, 7 ).toDouble();
644 //parse magnitude, B-V color, and spectral type
645 mag = line->mid( 46, 5 ).toDouble();
646 bv = line->mid( 51, 5 ).toDouble();
647 SpType = line->mid(56, 2);
649 //parse multiplicity
650 mult = line->mid( 59, 1 ).toInt();
652 //parse variablility...currently not using dmag or var
653 var = false; dmag = 0.0; vper = 0.0;
654 if ( line->at( 62 ) == '.' ) {
655 var = true;
656 dmag = line->mid( 61, 4 ).toDouble();
657 vper = line->mid( 66, 6 ).toDouble();
660 //parse name(s)
661 name = line->mid( 72 ).stripWhiteSpace(); //the rest of the line
662 if (name.contains( ':' )) { //genetive form exists
663 gname = name.mid( name.find(':')+1 ).stripWhiteSpace();
664 name = name.mid( 0, name.find(':') ).stripWhiteSpace();
667 // HEV: look up star name in internationalization filesource
668 name = i18n("star name", name.local8Bit().data());
670 bool starIsUnnamed( false );
671 if (name.isEmpty() && gname.isEmpty()) { //both names are empty
672 starIsUnnamed = true;
675 dms r;
676 r.setH(rah, ram, ras, ras2);
677 dms d(dd, dm, ds, ds2);
679 if (sgn == "-") { d.setD( -1.0*d.Degrees() ); }
681 StarObject *o = new StarObject(r, d, mag, name, gname, SpType, pmra, pmdec, plx, mult, var );
682 starList.append(o);
684 // get horizontal coordinates when object will loaded while running the application
685 // first run doesn't need this because updateTime() will called after loading all data
686 if (reloadMode) {
687 o->EquatorialToHorizontal( LST, geo()->lat() );
690 //STAR_SIZE
691 // StarObject *p = new StarObject(r, d, mag, name, gname, SpType, pmra, pmdec, plx, mult, var );
692 // starList.append(p);
694 // add named stars to list
695 if (starIsUnnamed == false) {
696 ObjNames.append(o);
700 bool KStarsData::readAsteroidData( void ) {
701 QFile file;
703 if ( KSUtils::openDataFile( file, "asteroids.dat" ) ) {
704 KSFileReader fileReader( file );
706 while( fileReader.hasMoreLines() ) {
707 QString line, name;
708 int mJD;
709 double a, e, dble_i, dble_w, dble_N, dble_M, H;
710 long double JD;
711 KSAsteroid *ast = 0;
713 line = fileReader.readLine();
714 name = line.mid( 6, 17 ).stripWhiteSpace();
715 mJD = line.mid( 24, 5 ).toInt();
716 a = line.mid( 30, 9 ).toDouble();
717 e = line.mid( 41, 10 ).toDouble();
718 dble_i = line.mid( 52, 9 ).toDouble();
719 dble_w = line.mid( 62, 9 ).toDouble();
720 dble_N = line.mid( 72, 9 ).toDouble();
721 dble_M = line.mid( 82, 11 ).toDouble();
722 H = line.mid( 94, 5 ).toDouble();
724 JD = double( mJD ) + 2400000.5;
726 ast = new KSAsteroid( this, name, "", JD, a, e, dms(dble_i), dms(dble_w), dms(dble_N), dms(dble_M), H );
727 ast->setAngularSize( 0.005 );
728 asteroidList.append( ast );
729 ObjNames.append( ast );
732 if ( asteroidList.count() ) return true;
735 return false;
738 bool KStarsData::readCometData( void ) {
739 QFile file;
741 if ( KSUtils::openDataFile( file, "comets.dat" ) ) {
742 KSFileReader fileReader( file );
744 while( fileReader.hasMoreLines() ) {
745 QString line, name;
746 int mJD;
747 double q, e, dble_i, dble_w, dble_N, Tp;
748 long double JD;
749 KSComet *com = 0;
751 line = fileReader.readLine();
752 name = line.mid( 3, 35 ).stripWhiteSpace();
753 mJD = line.mid( 38, 5 ).toInt();
754 q = line.mid( 44, 10 ).toDouble();
755 e = line.mid( 55, 10 ).toDouble();
756 dble_i = line.mid( 66, 9 ).toDouble();
757 dble_w = line.mid( 76, 9 ).toDouble();
758 dble_N = line.mid( 86, 9 ).toDouble();
759 Tp = line.mid( 96, 14 ).toDouble();
761 JD = double( mJD ) + 2400000.5;
763 com = new KSComet( this, name, "", JD, q, e, dms(dble_i), dms(dble_w), dms(dble_N), Tp );
764 com->setAngularSize( 0.005 );
766 cometList.append( com );
767 ObjNames.append( com );
770 if ( cometList.count() ) return true;
773 return false;
777 //02/2003: NEW: split data files, using Heiko's new KSFileReader.
778 bool KStarsData::readDeepSkyData( void ) {
779 QFile file;
781 for ( unsigned int i=0; i<NNGCFILES; ++i ) {
782 QString snum, fname;
783 snum = QString().sprintf( "%02d", i+1 );
784 fname = "ngcic" + snum + ".dat";
786 emit progressText( i18n( "Loading NGC/IC Data (%1%)" ).arg( int(100.*float(i)/float(NNGCFILES)) ) );
788 if ( KSUtils::openDataFile( file, fname ) ) {
789 KSFileReader fileReader( file ); // close file is included
790 while ( fileReader.hasMoreLines() ) {
791 QString line, con, ss, name, name2, longname;
792 QString cat, cat2;
793 float mag(1000.0), ras, a, b;
794 int type, ingc, imess(-1), rah, ram, dd, dm, ds, pa;
795 int pgc, ugc;
796 QChar sgn, iflag;
798 line = fileReader.readLine();
799 //Ignore comment lines
800 while ( line.at(0) == '#' && fileReader.hasMoreLines() ) line = fileReader.readLine();
801 //Ignore lines with no coordinate values
802 while ( line.mid(6,8).stripWhiteSpace().isEmpty() ) line = fileReader.readLine();
804 iflag = line.at( 0 ); //check for NGC/IC catalog flag
805 if ( iflag == 'I' ) cat = "IC";
806 else if ( iflag == 'N' ) cat = "NGC";
808 ingc = line.mid( 1, 4 ).toInt(); // NGC/IC catalog number
809 if ( ingc==0 ) cat = ""; //object is not in NGC or IC catalogs
811 //coordinates
812 rah = line.mid( 6, 2 ).toInt();
813 ram = line.mid( 8, 2 ).toInt();
814 ras = line.mid( 10, 4 ).toFloat();
815 sgn = line.at( 15 );
816 dd = line.mid( 16, 2 ).toInt();
817 dm = line.mid( 18, 2 ).toInt();
818 ds = line.mid( 20, 2 ).toInt();
820 //B magnitude
821 ss = line.mid( 23, 4 );
822 if (ss == " " ) { mag = 99.9; } else { mag = ss.toFloat(); }
824 //object type
825 type = line.mid( 29, 1 ).toInt();
827 //major and minor axes and position angle
828 ss = line.mid( 31, 5 );
829 if (ss == " " ) { a = 0.0; } else { a = ss.toFloat(); }
830 ss = line.mid( 37, 5 );
831 if (ss == " " ) { b = 0.0; } else { b = ss.toFloat(); }
832 ss = line.mid( 43, 3 );
833 if (ss == " " ) { pa = 0; } else { pa = ss.toInt(); }
835 //PGC number
836 ss = line.mid( 47, 6 );
837 if (ss == " " ) { pgc = 0; } else { pgc = ss.toInt(); }
839 //UGC number
840 if ( line.mid( 54, 3 ) == "UGC" ) {
841 ugc = line.mid( 58, 5 ).toInt();
842 } else {
843 ugc = 0;
846 //Messier number
847 if ( line.at( 70 ) == 'M' ) {
848 cat2 = cat;
849 if ( ingc==0 ) cat2 = "";
850 cat = "M";
851 imess = line.mid( 72, 3 ).toInt();
854 longname = line.mid( 76, line.length() ).stripWhiteSpace();
856 dms r;
857 r.setH( rah, ram, int(ras) );
858 dms d( dd, dm, ds );
860 if ( sgn == "-" ) { d.setD( -1.0*d.Degrees() ); }
862 // QString snum;
863 if ( cat=="IC" || cat=="NGC" ) {
864 snum.setNum( ingc );
865 name = cat + " " + snum;
866 } else if ( cat=="M" ) {
867 snum.setNum( imess );
868 name = cat + " " + snum;
869 if ( cat2=="NGC" ) {
870 snum.setNum( ingc );
871 name2 = cat2 + " " + snum;
872 } else if ( cat2=="IC" ) {
873 snum.setNum( ingc );
874 name2 = cat2 + " " + snum;
875 } else {
876 name2 = "";
878 } else {
879 if ( longname.isEmpty() ) name = i18n( "Unnamed Object" );
880 else name = longname;
883 // create new deepskyobject
884 DeepSkyObject *o = 0;
885 if ( type==0 ) type = 1; //Make sure we use CATALOG_STAR, not STAR
886 o = new DeepSkyObject( type, r, d, mag, name, name2, longname, cat, a, b, pa, pgc, ugc );
888 // keep object in deep sky objects' list
889 deepSkyList.append( o );
890 // plus: keep objects separated for performance reasons. Switching the colors during
891 // paint is too expensive.
892 if ( o->isCatalogM()) {
893 deepSkyListMessier.append( o );
894 } else if (o->isCatalogNGC() ) {
895 deepSkyListNGC.append( o );
896 } else if ( o->isCatalogIC() ) {
897 deepSkyListIC.append( o );
898 } else {
899 deepSkyListOther.append( o );
902 // list of object names
903 ObjNames.append( (SkyObject*)o );
905 //Add longname to objList, unless longname is the same as name
906 if ( !o->longname().isEmpty() && o->name() != o->longname() && o->hasName() ) {
907 ObjNames.append( o, true ); // append with longname
909 } //end while-filereader
910 } else { //one of the files could not be opened
911 return false;
913 } //end for-loop through files
915 return true;
918 bool KStarsData::openURLFile(QString urlfile, QFile & file) {
919 //QFile file;
920 QString localFile;
921 bool fileFound = false;
922 QFile localeFile;
924 if ( locale->language() != "en_US" )
925 localFile = locale->language() + "/" + urlfile;
927 if ( ! localFile.isEmpty() && KSUtils::openDataFile( file, localFile ) ) {
928 fileFound = true;
929 } else {
930 // Try to load locale file, if not successful, load regular urlfile and then copy it to locale.
931 file.setName( locateLocal( "appdata", urlfile ) );
932 if ( file.open( IO_ReadOnly ) ) {
933 //local file found. Now, if global file has newer timestamp, then merge the two files.
934 //First load local file into QStringList
935 bool newDataFound( false );
936 QStringList urlData;
937 QTextStream lStream( &file );
938 while ( ! lStream.eof() ) urlData.append( lStream.readLine() );
940 //Find global file(s) in findAllResources() list.
941 QFileInfo fi_local( file.name() );
942 QStringList flist = KGlobal::instance()->dirs()->findAllResources( "appdata", urlfile );
943 for ( unsigned int i=0; i< flist.count(); i++ ) {
944 if ( flist[i] != file.name() ) {
945 QFileInfo fi_global( flist[i] );
947 //Is this global file newer than the local file?
948 if ( fi_global.lastModified() > fi_local.lastModified() ) {
949 //Global file has newer timestamp than local. Add lines in global file that don't already exist in local file.
950 //be smart about this; in some cases the URL is updated but the image is probably the same if its
951 //label string is the same. So only check strings up to last ":"
952 QFile globalFile( flist[i] );
953 if ( globalFile.open( IO_ReadOnly ) ) {
954 QTextStream gStream( &globalFile );
955 while ( ! gStream.eof() ) {
956 QString line = gStream.readLine();
958 //If global-file line begins with "XXX:" then this line should be removed from the local file.
959 if ( line.left( 4 ) == "XXX:" && urlData.contains( line.mid( 4 ) ) ) {
960 urlData.remove( urlData.find( line.mid( 4 ) ) );
961 } else {
962 //does local file contain the current global file line, up to second ':' ?
964 bool linefound( false );
965 for ( unsigned int j=0; j< urlData.count(); ++j ) {
966 if ( urlData[j].contains( line.left( line.find( ':', line.find( ':' ) + 1 ) ) ) ) {
967 //replace line in urlData with its equivalent in the newer global file.
968 urlData.remove( urlData.at(j) );
969 urlData.insert( urlData.at(j), line );
970 if ( !newDataFound ) newDataFound = true;
971 linefound = true;
972 break;
975 if ( ! linefound ) {
976 urlData.append( line );
977 if ( !newDataFound ) newDataFound = true;
986 file.close();
988 //(possibly) write appended local file
989 if ( newDataFound ) {
990 if ( file.open( IO_WriteOnly ) ) {
991 QTextStream outStream( &file );
992 for ( unsigned int i=0; i<urlData.count(); i++ ) {
993 outStream << urlData[i] << endl;
995 file.close();
999 if ( file.open( IO_ReadOnly ) ) fileFound = true;
1001 } else {
1002 if ( KSUtils::openDataFile( file, urlfile ) ) {
1003 if ( locale->language() != "en_US" ) kdDebug() << i18n( "No localized URL file; using default English file." ) << endl;
1004 // we found urlfile, we need to copy it to locale
1005 localeFile.setName( locateLocal( "appdata", urlfile ) );
1006 if (localeFile.open(IO_WriteOnly)) {
1007 QTextStream readStream(&file);
1008 QTextStream writeStream(&localeFile);
1009 while ( ! readStream.eof() ) {
1010 QString line = readStream.readLine();
1011 if ( line.left( 4 ) != "XXX:" ) //do not write "deleted" lines
1012 writeStream << line << endl;
1015 localeFile.close();
1016 file.reset();
1017 } else {
1018 kdDebug() << i18n( "Failed to copy default URL file to locale folder, modifying default object links is not possible" ) << endl;
1020 fileFound = true;
1024 return fileFound;
1027 bool KStarsData::readUserLog(void)
1029 QFile file;
1030 QString buffer;
1031 QString sub, name, data;
1033 if (!KSUtils::openDataFile( file, "userlog.dat" )) return false;
1035 QTextStream stream(&file);
1037 if (!stream.eof()) buffer = stream.read();
1039 while (!buffer.isEmpty()) {
1040 int startIndex, endIndex;
1042 startIndex = buffer.find("[KSLABEL:");
1043 sub = buffer.mid(startIndex);
1044 endIndex = sub.find("[KSLogEnd]");
1046 // Read name after KSLABEL identifer
1047 name = sub.mid(startIndex + 9, sub.find("]") - (startIndex + 9));
1048 // Read data and skip new line
1049 data = sub.mid(sub.find("]") + 2, endIndex - (sub.find("]") + 2));
1050 buffer = buffer.mid(endIndex + 11);
1052 //Find the sky object named 'name'.
1053 //Note that ObjectNameList::find() looks for the ascii representation
1054 //of star genetive names, so stars are identified that way in the user log.
1055 SkyObjectName *sonm = ObjNames.find(name);
1056 if (sonm == 0) {
1057 kdWarning() << k_funcinfo << name << " not found" << endl;
1058 } else {
1059 sonm->skyObject()->userLog = data;
1062 } // end while
1063 file.close();
1064 return true;
1067 bool KStarsData::readURLData( QString urlfile, int type, bool deepOnly ) {
1068 QFile file;
1069 if (!openURLFile(urlfile, file)) return false;
1071 QTextStream stream(&file);
1073 while ( !stream.eof() ) {
1074 QString line = stream.readLine();
1076 //ignore comment lines
1077 if ( line.left(1) != "#" ) {
1078 QString name = line.mid( 0, line.find(':') );
1079 QString sub = line.mid( line.find(':')+1 );
1080 QString title = sub.mid( 0, sub.find(':') );
1081 QString url = sub.mid( sub.find(':')+1 );
1083 SkyObjectName *sonm = ObjNames.find(name);
1085 if (sonm == 0) {
1086 kdWarning() << k_funcinfo << name << " not found" << endl;
1087 } else {
1088 if ( ! deepOnly || ( sonm->skyObject()->type() > 2 && sonm->skyObject()->type() < 9 ) ) {
1089 if ( type==0 ) { //image URL
1090 sonm->skyObject()->ImageList.append( url );
1091 sonm->skyObject()->ImageTitle.append( title );
1092 } else if ( type==1 ) { //info URL
1093 sonm->skyObject()->InfoList.append( url );
1094 sonm->skyObject()->InfoTitle.append( title );
1100 file.close();
1101 return true;
1104 bool KStarsData::readCustomData( QString filename, QPtrList<DeepSkyObject> &objList, bool showerrs ) {
1105 bool checkValue;
1106 bool badLine(false);
1107 int countValidLines(0);
1108 int countLine(0);
1110 unsigned char iType(0);
1111 double RA(0.0), Dec(0.0), mag(0.0);
1112 QString name(""); QString lname(""); QString spType("");
1114 //If the filename begins with "~", replace the "~" with the user's home directory
1115 //(otherwise, the file will not successfully open)
1116 if ( filename.at(0)=='~' ) filename = QDir::homeDirPath() + filename.mid( 1, filename.length() );
1118 QFile test( filename );
1119 QStringList errs;
1121 if ( test.open( IO_ReadOnly ) ) {
1122 QTextStream stream( &test );
1123 while ( !stream.eof() ) {
1124 QString sub, msg;
1125 QString line = stream.readLine();
1126 ++countLine;
1127 iType = SkyObject::TYPE_UNKNOWN; //initialize to invalid values
1128 RA = 0.0; Dec = 0.0; mag = 0.0;
1129 name = ""; lname = ""; spType = "";
1131 if ( line.left(1) != "#" ) { //ignore commented lines
1132 QStringList fields = QStringList::split( " ", line ); //parse the line
1133 if ( fields.count() < 5 ) { //every valid line has at least 5 fields
1134 badLine = true;
1135 if (showerrs) errs.append( i18n( "Line " ) + QString( "%1" ).arg( countLine ) +
1136 i18n( " does not have enough fields." ) );
1137 } else {
1138 iType = (*fields.at(0)).toInt( &checkValue );
1139 if ( !checkValue ) {
1140 badLine = true;
1141 iType = SkyObject::TYPE_UNKNOWN;
1142 if (showerrs) errs.append( i18n( "Line " ) + QString( "%1" ).arg( countLine ) +
1143 i18n( ": field 1 is not an integer." ) );
1145 RA = (*fields.at(1)).toDouble( &checkValue );
1146 if ( !checkValue ) {
1147 badLine = true;
1148 if (showerrs) errs.append( i18n( "Line " ) + QString( "%1" ).arg( countLine ) +
1149 i18n( ": field 2 is not a float (right ascension)." ) );
1151 Dec = (*fields.at(2)).toDouble( &checkValue );
1152 if ( !checkValue ) {
1153 badLine = true;
1154 if (showerrs) errs.append( i18n( "Line " ) + QString( "%1" ).arg( countLine ) +
1155 i18n( ": field 3 is not a float (declination)." ) );
1157 mag = (*fields.at(3)).toDouble( &checkValue );
1158 if ( !checkValue ) {
1159 badLine = true;
1160 if (showerrs) errs.append( i18n( "Line " ) + QString( "%1" ).arg( countLine ) +
1161 i18n( ": field 4 is not a float (magnitude)." ) );
1164 if ( iType==0 || iType==1 ) { //Star
1165 spType = (*fields.at(4));
1166 if ( !( spType.left(1)=="O" || spType.left(1)=="B" ||
1167 spType.left(1)=="A" || spType.left(1)=="F" ||
1168 spType.left(1)=="G" || spType.left(1)=="K" ||
1169 spType.left(1)=="M" ) ) { //invalid spType
1170 badLine = true;
1171 if (showerrs) errs.append( i18n( "Line " ) + QString( "%1" ).arg( countLine ) +
1172 i18n( ", field 5: invalid spectral type (must start with O,B,A,F,G,K or M)" ) );
1174 } else if ( iType < 3 || iType > 8 ) { //invalid object type
1175 badLine = true;
1176 if (showerrs) errs.append( i18n( "Line " ) + QString( "%1" ).arg( countLine ) +
1177 i18n( ", field 1: invalid object type (must be 0,1,3,4,5,6,7 or 8)" ) );
1181 if ( !badLine ) { //valid data found! add to objList
1182 ++countValidLines;
1183 unsigned int Mark(4); //field marker; 5 for stars, 4 for deep-sky
1185 //Stars:
1186 if ( iType==0 || iType==1 ) Mark = 5;
1188 //First, check for name:
1189 if ( fields.count() > Mark && (*fields.at(Mark)).left(1)=="\"" ) {
1190 //The name is (probably) more than one word...
1191 name = (*fields.at(Mark)).mid(1); //remove leading quote mark
1192 if (name.right(1)=="\"") { //name was one word in quotes...
1193 name = name.left( name.length() -1 ); //remove trailing quote mark
1194 } else {
1195 for ( unsigned int i=Mark+1; i<fields.count(); ++i ) {
1196 name = name + " " + (*fields.at(i));
1197 if (name.right(1)=="\"") {
1198 name = name.left( name.length() -1 ); //remove trailing quote mark
1199 break;
1203 } else if ( fields.count() > Mark ) { //one-word name
1204 name = (*fields.at(Mark));
1207 //Not handling custom star catalogs yet...
1208 // if ( Mark==5 ) { //Stars...
1210 // StarObject *o = new StarObject( RA, Dec, mag, name, "", spType );
1211 // objList.append( o );
1212 // } else if ( iType > 2 && iType <= 8 ) { //Deep-sky objects...
1213 if ( name.isEmpty()) name = i18n( "unnamed object" );
1215 DeepSkyObject *o = new DeepSkyObject( iType, RA, Dec, mag, name, "", "" );
1216 objList.append( o );
1217 // }
1221 } else {
1222 if (showerrs) errs.append( i18n( "Could not open custom data file: " ) + filename );
1223 kdWarning() << i18n( "Could not open custom data file: " ) << filename;
1226 if ( countValidLines==countLine && countValidLines ) { //all lines were valid!
1227 return true;
1228 } else if ( countValidLines ) { //found some valid lines, some invalid lines.
1229 if ( showerrs ) {
1230 QString message( i18n( "Some lines could not be parsed in the specified file, see error messages below." ) + "\n" +
1231 i18n( "To reject the file, press Cancel. " ) +
1232 i18n( "To accept the file (ignoring unparsed lines), press Accept." ) );
1233 if ( KMessageBox::warningContinueCancelList( 0, message, errs,
1234 i18n( "Some Lines in File Were Invalid" ), i18n( "Accept" ) )==KMessageBox::Continue ) {
1235 return true;
1236 } else {
1237 return false;
1239 return true; //not showing errs; return true for parsed lines
1241 } else {
1242 if ( showerrs ) {
1243 QString message( i18n( "No lines could be parsed from the specified file, see error messages below." ) );
1244 KMessageBox::informationList( 0, message, errs,
1245 i18n( "No Valid Data Found in File" ) );
1247 return false;
1249 // all test passed
1250 return false;
1254 bool KStarsData::processCity( QString& line ) {
1255 QString totalLine;
1256 QString name, province, country;
1257 QStringList fields;
1258 TimeZoneRule *TZrule;
1259 bool intCheck = true;
1260 char latsgn, lngsgn;
1261 int lngD, lngM, lngS;
1262 int latD, latM, latS;
1263 double TZ;
1264 float lng, lat;
1266 totalLine = line;
1268 // separate fields
1269 fields = QStringList::split( ":", line );
1271 for ( unsigned int i=0; i< fields.count(); ++i )
1272 fields[i] = fields[i].stripWhiteSpace();
1274 if ( fields.count() < 11 ) {
1275 kdDebug()<< i18n( "Cities.dat: Ran out of fields. Line was:" ) <<endl;
1276 kdDebug()<< totalLine.local8Bit() <<endl;
1277 return false;
1278 } else if ( fields.count() < 12 ) {
1279 // allow old format (without TZ) for mycities.dat
1280 fields.append("");
1281 fields.append("--");
1282 } else if ( fields.count() < 13 ) {
1283 // Set TZrule to "--"
1284 fields.append("--");
1287 name = fields[0];
1288 province = fields[1];
1289 country = fields[2];
1291 latD = fields[3].toInt( &intCheck );
1292 if ( !intCheck ) {
1293 kdDebug() << fields[3] << i18n( "\nCities.dat: Bad integer. Line was:\n" ) << totalLine << endl;
1294 return false;
1297 latM = fields[4].toInt( &intCheck );
1298 if ( !intCheck ) {
1299 kdDebug() << fields[4] << i18n( "\nCities.dat: Bad integer. Line was:\n" ) << totalLine << endl;
1300 return false;
1303 latS = fields[5].toInt( &intCheck );
1304 if ( !intCheck ) {
1305 kdDebug() << fields[5] << i18n( "\nCities.dat: Bad integer. Line was:\n" ) << totalLine << endl;
1306 return false;
1309 QChar ctemp = fields[6].at(0);
1310 latsgn = ctemp;
1311 if (latsgn != 'N' && latsgn != 'S') {
1312 kdDebug() << latsgn << i18n( "\nCities.dat: Invalid latitude sign. Line was:\n" ) << totalLine << endl;
1313 return false;
1316 lngD = fields[7].toInt( &intCheck );
1317 if ( !intCheck ) {
1318 kdDebug() << fields[7] << i18n( "\nCities.dat: Bad integer. Line was:\n" ) << totalLine << endl;
1319 return false;
1322 lngM = fields[8].toInt( &intCheck );
1323 if ( !intCheck ) {
1324 kdDebug() << fields[8] << i18n( "\nCities.dat: Bad integer. Line was:\n" ) << totalLine << endl;
1325 return false;
1328 lngS = fields[9].toInt( &intCheck );
1329 if ( !intCheck ) {
1330 kdDebug() << fields[9] << i18n( "\nCities.dat: Bad integer. Line was:\n" ) << totalLine << endl;
1331 return false;
1334 ctemp = fields[10].at(0);
1335 lngsgn = ctemp;
1336 if (lngsgn != 'E' && lngsgn != 'W') {
1337 kdDebug() << latsgn << i18n( "\nCities.dat: Invalid longitude sign. Line was:\n" ) << totalLine << endl;
1338 return false;
1341 lat = (float)latD + ((float)latM + (float)latS/60.0)/60.0;
1342 lng = (float)lngD + ((float)lngM + (float)lngS/60.0)/60.0;
1344 if ( latsgn == 'S' ) lat *= -1.0;
1345 if ( lngsgn == 'W' ) lng *= -1.0;
1347 // find time zone. Use value from Cities.dat if available.
1348 // otherwise use the old approximation: int(lng/15.0);
1349 if ( fields[11].isEmpty() || ('x' == fields[11].at(0)) ) {
1350 TZ = int(lng/15.0);
1351 } else {
1352 bool doubleCheck = true;
1353 TZ = fields[11].toDouble( &doubleCheck);
1354 if ( !doubleCheck ) {
1355 kdDebug() << fields[11] << i18n( "\nCities.dat: Bad time zone. Line was:\n" ) << totalLine << endl;
1356 return false;
1360 //last field is the TimeZone Rule ID.
1361 TZrule = &( Rulebook[ fields[12] ] );
1363 // if ( fields[12]=="--" )
1364 // kdDebug() << "Empty rule start month: " << TZrule->StartMonth << endl;
1365 geoList.append ( new GeoLocation( lng, lat, name, province, country, TZ, TZrule )); // appends city names to list
1366 return true;
1369 bool KStarsData::readTimeZoneRulebook( void ) {
1370 QFile file;
1371 QString id;
1373 if ( KSUtils::openDataFile( file, "TZrules.dat" ) ) {
1374 QTextStream stream( &file );
1376 while ( !stream.eof() ) {
1377 QString line = stream.readLine().stripWhiteSpace();
1378 if ( line.left(1) != "#" && line.length() ) { //ignore commented and blank lines
1379 QStringList fields = QStringList::split( " ", line );
1380 id = fields[0];
1381 QTime stime = QTime( fields[3].left( fields[3].find(':')).toInt() ,
1382 fields[3].mid( fields[3].find(':')+1, fields[3].length()).toInt() );
1383 QTime rtime = QTime( fields[6].left( fields[6].find(':')).toInt(),
1384 fields[6].mid( fields[6].find(':')+1, fields[6].length()).toInt() );
1386 Rulebook[ id ] = TimeZoneRule( fields[1], fields[2], stime, fields[4], fields[5], rtime );
1389 return true;
1390 } else {
1391 return false;
1395 bool KStarsData::readCityData( void ) {
1396 QFile file;
1397 bool citiesFound = false;
1399 // begin new code
1400 if ( KSUtils::openDataFile( file, "Cities.dat" ) ) {
1401 KSFileReader fileReader( file ); // close file is included
1402 while ( fileReader.hasMoreLines() ) {
1403 citiesFound |= processCity( fileReader.readLine() );
1406 // end new code
1408 //check for local cities database, but don't require it.
1409 file.setName( locate( "appdata", "mycities.dat" ) ); //determine filename in local user KDE directory tree.
1410 if ( file.exists() && file.open( IO_ReadOnly ) ) {
1411 QTextStream stream( &file );
1413 while ( !stream.eof() ) {
1414 QString line = stream.readLine();
1415 citiesFound |= processCity( line );
1416 } // while ( !stream.eof() )
1417 file.close();
1418 } // if ( fileopen() )
1420 return citiesFound;
1423 void KStarsData::setMagnitude( float newMagnitude, bool forceReload ) {
1424 // only reload data if not loaded yet
1425 // if checkDataPumpAction() detects that new magnitude is higher than the
1426 // loaded, it can force a reload
1427 if ( newMagnitude > maxSetMagnitude || forceReload ) {
1428 maxSetMagnitude = newMagnitude; // store new highest magnitude level
1430 if (reloadingData() == false) { // if not already reloading data
1431 source = new FileSource(this, newMagnitude);
1432 loader = new StarDataSink(this);
1433 connect(loader, SIGNAL(done()), this, SLOT(checkDataPumpAction()));
1434 connect(loader, SIGNAL(updateSkymap()), this, SLOT(updateSkymap()));
1435 connect(loader, SIGNAL(clearCache()), this, SLOT(sendClearCache()));
1436 // start reloading
1437 pump = new QDataPump (source, (QDataSink*) loader);
1439 } /*else if ( newMagnitude < maxSetMagnitude ) {
1440 StarObject *lastStar = starList.last();
1441 while ( lastStar->mag() > newMagnitude && starList.count() ) {
1442 //check if star is named. If so, remove it from ObjNames
1443 if ( ! lastStar->name().isEmpty() ) {
1444 ObjNames.remove( lastStar->name() );
1446 starList.removeLast();
1447 lastStar = starList.last();
1449 //Need to recompute names of objects
1450 sendClearCache();
1454 // change current magnitude level in KStarsOptions
1455 Options::setMagLimitDrawStar( newMagnitude );
1458 void KStarsData::checkDataPumpAction() {
1459 // it will set to true if new data should be reloaded
1460 bool reloadMoreData = false;
1461 if (source != 0) {
1462 // check if a new reload must be started
1463 if (source->magnitude() < maxSetMagnitude) reloadMoreData = true;
1464 delete source;
1465 source = 0;
1467 if (pump != 0) { // if pump exists
1468 delete pump;
1469 pump = 0;
1471 if (loader != 0) { // if loader exists
1472 delete loader;
1473 loader = 0;
1475 // If magnitude was changed while reloading data start a new reload of data.
1476 if (reloadMoreData == true) {
1477 setMagnitude(maxSetMagnitude, true);
1481 bool KStarsData::reloadingData() {
1482 return ( pump || loader || source ); // true if variables != 0
1485 void KStarsData::updateSkymap() {
1486 emit update();
1489 void KStarsData::sendClearCache() {
1490 emit clearCache();
1493 void KStarsData::addCatalog( QString name, QPtrList<DeepSkyObject> oList ) {
1494 CustomCatalogs[ name ] = oList;
1495 CustomCatalogs[ name ].setAutoDelete( TRUE );
1498 void KStarsData::initialize() {
1499 if (startupComplete) return;
1501 initTimer = new QTimer;
1502 QObject::connect(initTimer, SIGNAL(timeout()), this, SLOT( slotInitialize() ) );
1503 initCounter = 0;
1504 initTimer->start(1);
1507 void KStarsData::initError(QString s, bool required = false) {
1508 QString message, caption;
1509 initTimer->stop();
1510 if (required) {
1511 message = i18n( "The file %1 could not be found. "
1512 "KStars cannot run properly without this file. "
1513 "To continue loading, place the file in one of the "
1514 "following locations, then press Retry:\n\n" ).arg( s )
1515 + QString( "\t$(KDEDIR)/share/apps/kstars/%1\n" ).arg( s )
1516 + QString( "\t~/.kde/share/apps/kstars/%1\n\n" ).arg( s )
1517 + i18n( "Otherwise, press Cancel to shutdown." );
1518 caption = i18n( "Critical File Not Found: %1" ).arg( s );
1519 } else {
1520 message = i18n( "The file %1 could not be found. "
1521 "KStars can still run without this file. "
1522 "However, to avoid seeing this message in the future, you can "
1523 "place the file in one of the following locations, then press Retry:\n\n" ).arg( s )
1524 + QString( "\t$(KDEDIR)/share/apps/kstars/%1\n" ).arg( s )
1525 + QString( "\t~/.kde/share/apps/kstars/%1\n\n" ).arg( s )
1526 + i18n( "Otherwise, press Cancel to continue loading without this file." ).arg( s );
1527 caption = i18n( "Non-Critical File Not Found: %1" ).arg( s );
1530 if ( KMessageBox::warningContinueCancel( 0, message, caption, i18n( "Retry" ) ) == KMessageBox::Continue ) {
1531 initCounter--;
1532 initTimer->start(1);
1533 } else {
1534 if (required) {
1535 delete initTimer;
1536 initTimer = 0L;
1537 emit initFinished(false);
1538 } else {
1539 initTimer->start(1);
1544 void KStarsData::slotInitialize() {
1545 QFile imFile;
1546 QString ImageName;
1548 kapp->flush(); // flush all paint events before loading data
1550 switch ( initCounter )
1552 case 0: //Load Time Zone Rules//
1553 emit progressText( i18n("Reading Time Zone Rules") );
1555 if (objects==1) {
1556 // timezone rules
1557 if ( !readTimeZoneRulebook( ) )
1558 initError( "TZrules.dat", true );
1561 // read INDI hosts file, not required
1562 readINDIHosts();
1563 break;
1565 case 1: //Load Cities//
1567 if (objects>1) break;
1569 emit progressText( i18n("Loading City Data") );
1571 if ( !readCityData( ) )
1572 initError( "Cities.dat", true );
1574 break;
1577 case 2: //Load stellar database//
1579 emit progressText(i18n("Loading Star Data (%1%)" ).arg(0) );
1580 if ( !readStarData( ) )
1581 initError( "hipNNN.dat", true );
1582 if (!readVARData())
1583 initError( "valaav.dat", false);
1584 if (!readADVTreeData())
1585 initError( "advinterface.dat", false);
1586 break;
1588 case 3: //Load NGC/IC database//
1590 emit progressText( i18n("Loading NGC/IC Data (%1%)" ).arg(0) );
1591 if ( !readDeepSkyData( ) )
1592 initError( "ngcicN.dat", true );
1593 break;
1595 case 4: //Load Constellation lines//
1597 emit progressText( i18n("Loading Constellations" ) );
1598 if ( !readCLineData( ) )
1599 initError( "clines.dat", true );
1600 break;
1602 case 5: //Load Constellation names//
1604 emit progressText( i18n("Loading Constellation Names" ) );
1605 if ( !readCNameData( ) )
1606 initError( cnameFile, true );
1607 break;
1609 case 6: //Load Constellation boundaries//
1611 emit progressText( i18n("Loading Constellation Boundaries" ) );
1612 if ( !readCBoundData( ) )
1613 initError( "cbound.dat", true );
1614 break;
1616 case 7: //Load Milky Way//
1618 emit progressText( i18n("Loading Milky Way" ) );
1619 if ( !readMWData( ) )
1620 initError( "mw*.dat", true );
1621 break;
1623 case 8: //Initialize the Planets//
1625 emit progressText( i18n("Creating Planets" ) );
1626 if (PCat->initialize())
1627 PCat->addObject( ObjNames );
1629 jmoons = new JupiterMoons();
1630 break;
1632 case 9: //Initialize Asteroids & Comets//
1634 emit progressText( i18n( "Creating Asteroids and Comets" ) );
1635 if ( !readAsteroidData() )
1636 initError( "asteroids.dat", false );
1637 if ( !readCometData() )
1638 initError( "comets.dat", false );
1640 break;
1642 case 10: //Initialize the Moon//
1644 emit progressText( i18n("Creating Moon" ) );
1645 Moon = new KSMoon(this);
1646 ObjNames.append( Moon );
1647 Moon->loadData();
1648 break;
1650 case 11: //Load Image URLs//
1652 emit progressText( i18n("Loading Image URLs" ) );
1653 if ( !readURLData( "image_url.dat", 0 ) ) {
1654 initError( "image_url.dat", false );
1656 //if ( !readURLData( "myimage_url.dat", 0 ) ) {
1657 //Don't do anything if the local file is not found.
1659 // doesn't belong here, only temp
1660 readUserLog();
1662 break;
1664 case 12: //Load Information URLs//
1666 emit progressText( i18n("Loading Information URLs" ) );
1667 if ( !readURLData( "info_url.dat", 1 ) ) {
1668 initError( "info_url.dat", false );
1670 //if ( !readURLData( "myinfo_url.dat", 1 ) ) {
1671 //Don't do anything if the local file is not found.
1673 break;
1675 default:
1676 initTimer->stop();
1677 delete initTimer;
1678 initTimer = 0L;
1679 startupComplete = true;
1680 emit initFinished(true);
1681 break;
1682 } // switch ( initCounter )
1684 initCounter++;
1687 void KStarsData::initGuides(KSNumbers *num)
1689 // Define the Celestial Equator
1690 for ( unsigned int i=0; i<NCIRCLE; ++i ) {
1691 SkyPoint *o = new SkyPoint( i*24./NCIRCLE, 0.0 );
1692 o->EquatorialToHorizontal( LST, geo()->lat() );
1693 Equator.append( o );
1696 // Define the horizon.
1697 // Use the celestial Equator as a convenient starting point, but instead of RA and Dec,
1698 // interpret the coordinates as azimuth and altitude, and then convert to RA, dec.
1699 // The horizon will be redefined whenever the positions of sky objects are updated.
1700 dms temp( 0.0 );
1701 for (SkyPoint *point = Equator.first(); point; point = Equator.next()) {
1702 double sinlat, coslat, sindec, cosdec, sinAz, cosAz;
1703 double HARad;
1704 dms dec, HA, RA, Az;
1705 Az = dms(*(point->ra()));
1707 Az.SinCos( sinAz, cosAz );
1708 geo()->lat()->SinCos( sinlat, coslat );
1710 dec.setRadians( asin( coslat*cosAz ) );
1711 dec.SinCos( sindec, cosdec );
1713 HARad = acos( -1.0*(sinlat*sindec)/(coslat*cosdec) );
1714 if ( sinAz > 0.0 ) { HARad = 2.0*dms::PI - HARad; }
1715 HA.setRadians( HARad );
1716 RA = LST->Degrees() - HA.Degrees();
1718 SkyPoint *o = new SkyPoint( RA, dec );
1719 o->setAlt( 0.0 );
1720 o->setAz( Az );
1722 Horizon.append( o );
1724 //Define the Ecliptic (use the same ListIteration; interpret coordinates as Ecliptic long/lat)
1725 o = new SkyPoint( 0.0, 0.0 );
1726 o->setFromEcliptic( num->obliquity(), point->ra(), &temp );
1727 o->EquatorialToHorizontal( LST, geo()->lat() );
1728 Ecliptic.append( o );
1732 void KStarsData::resetToNewDST(const GeoLocation *geo, const bool automaticDSTchange) {
1733 // reset tzrules data with local time, timezone offset and time direction (forward or backward)
1734 // force a DST change with option true for 3. parameter
1735 geo->tzrule()->reset_with_ltime( LTime, geo->TZ0(), TimeRunsForward, automaticDSTchange );
1736 // reset next DST change time
1737 setNextDSTChange( geo->tzrule()->nextDSTChange() );
1738 //reset LTime, because TZoffset has changed
1739 LTime = geo->UTtoLT( ut() );
1742 void KStarsData::updateTime( GeoLocation *geo, SkyMap *skymap, const bool automaticDSTchange ) {
1743 // sync LTime with the simulation clock
1744 LTime = geo->UTtoLT( ut() );
1745 syncLST();
1747 //Only check DST if (1) TZrule is not the empty rule, and (2) if we have crossed
1748 //the DST change date/time.
1749 if ( !geo->tzrule()->isEmptyRule() ) {
1750 if ( TimeRunsForward ) {
1751 // timedirection is forward
1752 // DST change happens if current date is bigger than next calculated dst change
1753 if ( ut() > NextDSTChange ) resetToNewDST(geo, automaticDSTchange);
1754 } else {
1755 // timedirection is backward
1756 // DST change happens if current date is smaller than next calculated dst change
1757 if ( ut() < NextDSTChange ) resetToNewDST(geo, automaticDSTchange);
1761 KSNumbers num( ut().djd() );
1763 bool needNewCoords = false;
1764 if ( fabs( ut().djd() - LastNumUpdate.djd() ) > 1.0 ) {
1765 //update time-dependent variables once per day
1766 needNewCoords = true;
1767 LastNumUpdate = ut().djd();
1770 // Update positions of objects, if necessary
1771 if ( fabs( ut().djd() - LastPlanetUpdate.djd() ) > 0.01 ) {
1772 LastPlanetUpdate = ut().djd();
1774 if ( Options::showPlanets() ) PCat->findPosition( &num, geo->lat(), LST );
1776 //Asteroids
1777 if ( Options::showPlanets() && Options::showAsteroids() )
1778 for ( KSAsteroid *ast = asteroidList.first(); ast; ast = asteroidList.next() )
1779 ast->findPosition( &num, geo->lat(), LST, earth() );
1781 //Comets
1782 if ( Options::showPlanets() && Options::showComets() )
1783 for ( KSComet *com = cometList.first(); com; com = cometList.next() )
1784 com->findPosition( &num, geo->lat(), LST, earth() );
1786 //Recompute the Ecliptic
1787 if ( Options::showEcliptic() ) {
1788 Ecliptic.clear();
1790 dms temp(0.0);
1791 for ( unsigned int i=0; i<Equator.count(); ++i ) {
1792 SkyPoint *o = new SkyPoint( 0.0, 0.0 );
1793 o->setFromEcliptic( num.obliquity(), Equator.at(i)->ra(), &temp );
1794 Ecliptic.append( o );
1799 // Moon moves ~30 arcmin/hr, so update its position every minute.
1800 if ( fabs( ut().djd() - LastMoonUpdate.djd() ) > 0.00069444 ) {
1801 LastMoonUpdate = ut();
1802 if ( Options::showMoon() ) {
1803 Moon->findPosition( &num, geo->lat(), LST );
1804 Moon->findPhase( PCat->planetSun() );
1807 //for now, update positions of Jupiter's moons here also
1808 if ( Options::showPlanets() && Options::showJupiter() )
1809 jmoons->findPosition( &num, (const KSPlanet*)PCat->findByName("Jupiter"), PCat->planetSun() );
1812 //Update Alt/Az coordinates. Timescale varies with zoom level
1813 //If Clock is in Manual Mode, always update. (?)
1814 if ( fabs( ut().djd() - LastSkyUpdate.djd() ) > 0.25/Options::zoomFactor() || clock()->isManualMode() ) {
1815 LastSkyUpdate = ut();
1817 //Recompute Alt, Az coords for all objects
1818 //Planets
1819 //This updates trails as well
1820 PCat->EquatorialToHorizontal( LST, geo->lat() );
1822 jmoons->EquatorialToHorizontal( LST, geo->lat() );
1823 if ( Options::showMoon() ) {
1824 Moon->EquatorialToHorizontal( LST, geo->lat() );
1825 if ( Moon->hasTrail() ) Moon->updateTrail( LST, geo->lat() );
1828 // //Planet Trails
1829 // for( SkyPoint *p = PlanetTrail.first(); p; p = PlanetTrail.next() )
1830 // p->EquatorialToHorizontal( LST, geo->lat() );
1832 //Asteroids
1833 if ( Options::showAsteroids() ) {
1834 for ( KSAsteroid *ast = asteroidList.first(); ast; ast = asteroidList.next() ) {
1835 ast->EquatorialToHorizontal( LST, geo->lat() );
1836 if ( ast->hasTrail() ) ast->updateTrail( LST, geo->lat() );
1840 //Comets
1841 if ( Options::showComets() ) {
1842 for ( KSComet *com = cometList.first(); com; com = cometList.next() ) {
1843 com->EquatorialToHorizontal( LST, geo->lat() );
1844 if ( com->hasTrail() ) com->updateTrail( LST, geo->lat() );
1848 //Stars
1849 if ( Options::showStars() ) {
1850 // use MINDRAWSTARMAG for calculating constellation lines right
1851 float mag = Options::magLimitDrawStar();
1852 if (mag < MINDRAWSTARMAG) mag = MINDRAWSTARMAG;
1853 for ( StarObject *star = starList.first(); star; star = starList.next() ) {
1854 if ( star->mag() > mag ) break;
1855 if (needNewCoords) star->updateCoords( &num );
1856 star->EquatorialToHorizontal( LST, geo->lat() );
1860 //Deep-sky objects. Keep lists separated for performance reasons
1861 if ( Options::showMessier() || Options::showMessierImages() ) {
1862 for ( SkyObject *o = deepSkyListMessier.first(); o; o = deepSkyListMessier.next() ) {
1863 if (needNewCoords) o->updateCoords( &num );
1864 o->EquatorialToHorizontal( LST, geo->lat() );
1867 if ( Options::showNGC() ) {
1868 for ( SkyObject *o = deepSkyListNGC.first(); o; o = deepSkyListNGC.next() ) {
1869 if (needNewCoords) o->updateCoords( &num );
1870 o->EquatorialToHorizontal( LST, geo->lat() );
1873 if ( Options::showIC() ) {
1874 for ( SkyObject *o = deepSkyListIC.first(); o; o = deepSkyListIC.next() ) {
1875 if (needNewCoords) o->updateCoords( &num );
1876 o->EquatorialToHorizontal( LST, geo->lat() );
1879 if ( Options::showOther() ) {
1880 for ( SkyObject *o = deepSkyListOther.first(); o; o = deepSkyListOther.next() ) {
1881 if (needNewCoords) o->updateCoords( &num );
1882 o->EquatorialToHorizontal( LST, geo->lat() );
1886 //Custom Catalogs
1887 for ( unsigned int j=0; j<Options::catalogCount(); ++j ) {
1888 QPtrList<DeepSkyObject> cat = CustomCatalogs[ Options::catalogName()[j] ];
1889 if ( Options::showCatalog()[j] ) {
1890 for ( SkyObject *o = cat.first(); o; o = cat.next() ) {
1891 if (needNewCoords) o->updateCoords( &num );
1892 o->EquatorialToHorizontal( LST, geo->lat() );
1897 //Milky Way
1898 if ( Options::showMilkyWay() ) {
1899 for ( unsigned int j=0; j<11; ++j ) {
1900 for ( SkyPoint *p = MilkyWay[j].first(); p; p = MilkyWay[j].next() ) {
1901 if (needNewCoords) p->updateCoords( &num );
1902 p->EquatorialToHorizontal( LST, geo->lat() );
1907 //CNames
1908 if ( Options::showCNames() ) {
1909 for ( SkyPoint *p = cnameList.first(); p; p = cnameList.next() ) {
1910 if (needNewCoords) p->updateCoords( &num );
1911 p->EquatorialToHorizontal( LST, geo->lat() );
1915 //Constellation Boundaries
1916 if ( Options::showCBounds() ) {
1917 for ( CSegment *seg = csegmentList.first(); seg; seg = csegmentList.next() ) {
1918 for ( SkyPoint *p = seg->firstNode(); p; p = seg->nextNode() ) {
1919 if ( needNewCoords ) p->updateCoords( &num );
1920 p->EquatorialToHorizontal( LST, geo->lat() );
1925 //Celestial Equator
1926 if ( Options::showEquator() ) {
1927 for ( SkyPoint *p = Equator.first(); p; p = Equator.next() ) {
1928 p->EquatorialToHorizontal( LST, geo->lat() );
1932 //Ecliptic
1933 if ( Options::showEcliptic() ) {
1934 for ( SkyPoint *p = Ecliptic.first(); p; p = Ecliptic.next() ) {
1935 p->EquatorialToHorizontal( LST, geo->lat() );
1939 //Horizon: different than the others; Alt & Az remain constant, RA, Dec must keep up
1940 if ( Options::showHorizon() || Options::showGround() ) {
1941 for ( SkyPoint *p = Horizon.first(); p; p = Horizon.next() ) {
1942 p->HorizontalToEquatorial( LST, geo->lat() );
1946 //Update focus
1947 skymap->updateFocus();
1949 if ( clock()->isManualMode() )
1950 QTimer::singleShot( 0, skymap, SLOT( forceUpdateNow() ) );
1951 else skymap->forceUpdate();
1955 void KStarsData::setTimeDirection( float scale ) {
1956 TimeRunsForward = ( scale < 0 ? false : true );
1959 void KStarsData::setFullTimeUpdate() {
1960 LastSkyUpdate.setDJD( (long double)INVALID_DAY );
1961 LastPlanetUpdate.setDJD( (long double)INVALID_DAY );
1962 LastMoonUpdate.setDJD( (long double)INVALID_DAY );
1963 LastNumUpdate.setDJD( (long double)INVALID_DAY );
1966 void KStarsData::setLocationFromOptions() {
1967 QMap<QString, TimeZoneRule>::Iterator it = Rulebook.find( Options::dST() );
1968 setLocation( GeoLocation ( Options::longitude(), Options::latitude(),
1969 Options::cityName(), Options::provinceName(), Options::countryName(),
1970 Options::timeZone(), &(it.data()), 4, Options::elevation() ) );
1973 void KStarsData::setLocation( const GeoLocation &l ) {
1974 GeoLocation g( l );
1975 if ( g.lat()->Degrees() >= 90.0 ) g.setLat( 89.99 );
1976 if ( g.lat()->Degrees() <= -90.0 ) g.setLat( -89.99 );
1978 Geo = g;
1980 //store data in the Options objects
1981 Options::setCityName( g.name() );
1982 Options::setProvinceName( g.province() );
1983 Options::setCountryName( g.country() );
1984 Options::setTimeZone( g.TZ0() );
1985 Options::setElevation( g.height() );
1986 Options::setLongitude( g.lng()->Degrees() );
1987 Options::setLatitude( g.lat()->Degrees() );
1990 void KStarsData::syncLST() {
1991 LST->set( geo()->GSTtoLST( ut().gst() ) );
1994 void KStarsData::changeDateTime( const KStarsDateTime &newDate ) {
1995 //Turn off animated slews for the next time step.
1996 setSnapNextFocus();
1998 clock()->setUTC( newDate );
1999 LTime = geo()->UTtoLT( ut() );
2000 //set local sideral time
2001 syncLST();
2003 //Make sure Numbers, Moon, planets, and sky objects are updated immediately
2004 setFullTimeUpdate();
2006 // reset tzrules data with new local time and time direction (forward or backward)
2007 geo()->tzrule()->reset_with_ltime(LTime, geo()->TZ0(), isTimeRunningForward() );
2009 // reset next dst change time
2010 setNextDSTChange( geo()->tzrule()->nextDSTChange() );
2013 SkyObject* KStarsData::objectNamed( const QString &name ) {
2014 if ( (name== "star") || (name== "nothing") || name.isEmpty() ) return NULL;
2015 if ( name== Moon->name() ) return Moon;
2017 SkyObject *so = PCat->findByName(name);
2019 if (so != 0)
2020 return so;
2022 //Stars
2023 for ( unsigned int i=0; i<starList.count(); ++i ) {
2024 if ( name==starList.at(i)->name() ) return starList.at(i);
2027 //Deep sky objects
2028 for ( unsigned int i=0; i<deepSkyListMessier.count(); ++i ) {
2029 if ( name==deepSkyListMessier.at(i)->name() ) return deepSkyListMessier.at(i);
2031 for ( unsigned int i=0; i<deepSkyListNGC.count(); ++i ) {
2032 if ( name==deepSkyListNGC.at(i)->name() ) return deepSkyListNGC.at(i);
2034 for ( unsigned int i=0; i<deepSkyListIC.count(); ++i ) {
2035 if ( name==deepSkyListIC.at(i)->name() ) return deepSkyListIC.at(i);
2037 for ( unsigned int i=0; i<deepSkyListOther.count(); ++i ) {
2038 if ( name==deepSkyListOther.at(i)->name() ) return deepSkyListOther.at(i);
2041 //Constellations
2042 for ( unsigned int i=0; i<cnameList.count(); ++i ) {
2043 if ( name==cnameList.at(i)->name() ) return cnameList.at(i);
2046 //reach here only if argument is not matched
2047 return NULL;
2050 //"pseudo-execute" a shell script, ignoring all interactive aspects. Just use
2051 //the portions of the script that change the state of the program. This is only
2052 //used for image-dump mode, where the GUI is not running. So, some things (such as
2053 //waitForKey()) don't make sense and should be ignored.
2054 //also, even functions that do make sense in this context have aspects that should
2055 //be modified or ignored. For example, we don't need to call slotCenter() on recentering
2056 //commands, just setDestination(). (sltoCenter() does additional things that we dont need).
2057 bool KStarsData::executeScript( const QString &scriptname, SkyMap *map ) {
2058 int cmdCount(0);
2060 QFile f( scriptname );
2061 if ( !f.open( IO_ReadOnly) ) {
2062 kdDebug() << i18n( "Could not open file %1" ).arg( f.name() ) << endl;
2063 return false;
2066 QTextStream istream(&f);
2067 while ( ! istream.eof() ) {
2068 QString line = istream.readLine();
2070 //found a dcop line
2071 if ( line.left(4) == "dcop" ) {
2072 line = line.mid( 20 ); //strip away leading characters
2073 QStringList fn = QStringList::split( " ", line );
2075 if ( fn[0] == "lookTowards" && fn.count() >= 2 ) {
2076 double az(-1.0);
2077 QString arg = fn[1].lower();
2078 if ( arg == "n" || arg == "north" ) az = 0.0;
2079 if ( arg == "ne" || arg == "northeast" ) az = 45.0;
2080 if ( arg == "e" || arg == "east" ) az = 90.0;
2081 if ( arg == "se" || arg == "southeast" ) az = 135.0;
2082 if ( arg == "s" || arg == "south" ) az = 180.0;
2083 if ( arg == "sw" || arg == "southwest" ) az = 225.0;
2084 if ( arg == "w" || arg == "west" ) az = 270.0;
2085 if ( arg == "nw" || arg == "northwest" ) az = 335.0;
2086 if ( az >= 0.0 ) { map->setFocusAltAz( 15.0, az ); cmdCount++; }
2088 if ( arg == "z" || arg == "zenith" ) {
2089 map->setFocusAltAz( 90.0, map->focus()->az()->Degrees() );
2090 cmdCount++;
2093 //try a named object. name is everything after the first word (which is 'lookTowards')
2094 fn.remove( fn.first() );
2095 SkyObject *target = objectNamed( fn.join( " " ) );
2096 if ( target ) { map->setFocus( target ); cmdCount++; }
2098 } else if ( fn[0] == "setRaDec" && fn.count() == 3 ) {
2099 bool ok( false );
2100 dms r(0.0), d(0.0);
2102 ok = r.setFromString( fn[1], false ); //assume angle in hours
2103 if ( ok ) ok = d.setFromString( fn[2], true ); //assume angle in degrees
2104 if ( ok ) {
2105 map->setFocus( r, d );
2106 cmdCount++;
2109 } else if ( fn[0] == "setAltAz" && fn.count() == 3 ) {
2110 bool ok( false );
2111 dms az(0.0), alt(0.0);
2113 ok = alt.setFromString( fn[1] );
2114 if ( ok ) ok = az.setFromString( fn[2] );
2115 if ( ok ) {
2116 map->setFocusAltAz( alt, az );
2117 cmdCount++;
2120 } else if ( fn[0] == "zoom" && fn.count() == 2 ) {
2121 bool ok(false);
2122 double z = fn[1].toDouble(&ok);
2123 if ( ok ) {
2124 if ( z > MAXZOOM ) z = MAXZOOM;
2125 if ( z < MINZOOM ) z = MINZOOM;
2126 Options::setZoomFactor( z );
2127 cmdCount++;
2130 } else if ( fn[0] == "zoomIn" ) {
2131 if ( Options::zoomFactor() < MAXZOOM ) {
2132 Options::setZoomFactor( Options::zoomFactor() * DZOOM );
2133 cmdCount++;
2135 } else if ( fn[0] == "zoomOut" ) {
2136 if ( Options::zoomFactor() > MINZOOM ) {
2137 Options::setZoomFactor( Options::zoomFactor() / DZOOM );
2138 cmdCount++;
2140 } else if ( fn[0] == "defaultZoom" ) {
2141 Options::setZoomFactor( DEFAULTZOOM );
2142 cmdCount++;
2143 } else if ( fn[0] == "setLocalTime" && fn.count() == 7 ) {
2144 bool ok(false);
2145 int yr(0), mth(0), day(0) ,hr(0), min(0), sec(0);
2146 yr = fn[1].toInt(&ok);
2147 if ( ok ) mth = fn[2].toInt(&ok);
2148 if ( ok ) day = fn[3].toInt(&ok);
2149 if ( ok ) hr = fn[4].toInt(&ok);
2150 if ( ok ) min = fn[5].toInt(&ok);
2151 if ( ok ) sec = fn[6].toInt(&ok);
2152 if ( ok ) {
2153 changeDateTime( KStarsDateTime( ExtDate(yr, mth, day), QTime(hr,min,sec) ) );
2154 cmdCount++;
2155 } else {
2156 kdWarning() << i18n( "Could not set time: %1 / %2 / %3 ; %4:%5:%6" )
2157 .arg(day).arg(mth).arg(yr).arg(hr).arg(min).arg(sec) << endl;
2159 } else if ( fn[0] == "changeViewOption" && fn.count() == 3 ) {
2160 bool bOk(false), nOk(false), dOk(false);
2162 //parse bool value
2163 bool bVal(false);
2164 if ( fn[2].lower() == "true" ) { bOk = true; bVal = true; }
2165 if ( fn[2].lower() == "false" ) { bOk = true; bVal = false; }
2166 if ( fn[2] == "1" ) { bOk = true; bVal = true; }
2167 if ( fn[2] == "0" ) { bOk = true; bVal = false; }
2169 //parse int value
2170 int nVal = fn[2].toInt( &nOk );
2172 //parse double value
2173 double dVal = fn[2].toDouble( &dOk );
2175 if ( fn[1] == "FOVName" ) { Options::setFOVName( fn[2] ); cmdCount++; }
2176 if ( fn[1] == "FOVSize" && dOk ) { Options::setFOVSize( (float)dVal ); cmdCount++; }
2177 if ( fn[1] == "FOVShape" && nOk ) { Options::setFOVShape( nVal ); cmdCount++; }
2178 if ( fn[1] == "FOVColor" ) { Options::setFOVColor( fn[2] ); cmdCount++; }
2179 if ( fn[1] == "ShowStars" && bOk ) { Options::setShowStars( bVal ); cmdCount++; }
2180 if ( fn[1] == "ShowMessier" && bOk ) { Options::setShowMessier( bVal ); cmdCount++; }
2181 if ( fn[1] == "ShowMessierImages" && bOk ) { Options::setShowMessierImages( bVal ); cmdCount++; }
2182 if ( fn[1] == "ShowCLines" && bOk ) { Options::setShowCLines( bVal ); cmdCount++; }
2183 if ( fn[1] == "ShowCNames" && bOk ) { Options::setShowCNames( bVal ); cmdCount++; }
2184 if ( fn[1] == "ShowNGC" && bOk ) { Options::setShowNGC( bVal ); cmdCount++; }
2185 if ( fn[1] == "ShowIC" && bOk ) { Options::setShowIC( bVal ); cmdCount++; }
2186 if ( fn[1] == "ShowMilkyWay" && bOk ) { Options::setShowMilkyWay( bVal ); cmdCount++; }
2187 if ( fn[1] == "ShowGrid" && bOk ) { Options::setShowGrid( bVal ); cmdCount++; }
2188 if ( fn[1] == "ShowEquator" && bOk ) { Options::setShowEquator( bVal ); cmdCount++; }
2189 if ( fn[1] == "ShowEcliptic" && bOk ) { Options::setShowEcliptic( bVal ); cmdCount++; }
2190 if ( fn[1] == "ShowHorizon" && bOk ) { Options::setShowHorizon( bVal ); cmdCount++; }
2191 if ( fn[1] == "ShowGround" && bOk ) { Options::setShowGround( bVal ); cmdCount++; }
2192 if ( fn[1] == "ShowSun" && bOk ) { Options::setShowSun( bVal ); cmdCount++; }
2193 if ( fn[1] == "ShowMoon" && bOk ) { Options::setShowMoon( bVal ); cmdCount++; }
2194 if ( fn[1] == "ShowMercury" && bOk ) { Options::setShowMercury( bVal ); cmdCount++; }
2195 if ( fn[1] == "ShowVenus" && bOk ) { Options::setShowVenus( bVal ); cmdCount++; }
2196 if ( fn[1] == "ShowMars" && bOk ) { Options::setShowMars( bVal ); cmdCount++; }
2197 if ( fn[1] == "ShowJupiter" && bOk ) { Options::setShowJupiter( bVal ); cmdCount++; }
2198 if ( fn[1] == "ShowSaturn" && bOk ) { Options::setShowSaturn( bVal ); cmdCount++; }
2199 if ( fn[1] == "ShowUranus" && bOk ) { Options::setShowUranus( bVal ); cmdCount++; }
2200 if ( fn[1] == "ShowNeptune" && bOk ) { Options::setShowNeptune( bVal ); cmdCount++; }
2201 if ( fn[1] == "ShowPluto" && bOk ) { Options::setShowPluto( bVal ); cmdCount++; }
2202 if ( fn[1] == "ShowAsteroids" && bOk ) { Options::setShowAsteroids( bVal ); cmdCount++; }
2203 if ( fn[1] == "ShowComets" && bOk ) { Options::setShowComets( bVal ); cmdCount++; }
2204 if ( fn[1] == "ShowPlanets" && bOk ) { Options::setShowPlanets( bVal ); cmdCount++; }
2205 if ( fn[1] == "ShowDeepSky" && bOk ) { Options::setShowDeepSky( bVal ); cmdCount++; }
2206 if ( fn[1] == "ShowStarNames" && bOk ) { Options::setShowStarNames( bVal ); cmdCount++; }
2207 if ( fn[1] == "ShowStarMagnitudes" && bOk ) { Options::setShowStarMagnitudes( bVal ); cmdCount++; }
2208 if ( fn[1] == "ShowAsteroidNames" && bOk ) { Options::setShowAsteroidNames( bVal ); cmdCount++; }
2209 if ( fn[1] == "ShowCometNames" && bOk ) { Options::setShowCometNames( bVal ); cmdCount++; }
2210 if ( fn[1] == "ShowPlanetNames" && bOk ) { Options::setShowPlanetNames( bVal ); cmdCount++; }
2211 if ( fn[1] == "ShowPlanetImages" && bOk ) { Options::setShowPlanetImages( bVal ); cmdCount++; }
2213 if ( fn[1] == "UseAltAz" && bOk ) { Options::setUseAltAz( bVal ); cmdCount++; }
2214 if ( fn[1] == "UseRefraction" && bOk ) { Options::setUseRefraction( bVal ); cmdCount++; }
2215 if ( fn[1] == "UseAutoLabel" && bOk ) { Options::setUseAutoLabel( bVal ); cmdCount++; }
2216 if ( fn[1] == "UseAutoTrail" && bOk ) { Options::setUseAutoTrail( bVal ); cmdCount++; }
2217 if ( fn[1] == "UseAnimatedSlewing" && bOk ) { Options::setUseAnimatedSlewing( bVal ); cmdCount++; }
2218 if ( fn[1] == "FadePlanetTrails" && bOk ) { Options::setFadePlanetTrails( bVal ); cmdCount++; }
2219 if ( fn[1] == "SlewTimeScale" && dOk ) { Options::setSlewTimeScale( dVal ); cmdCount++; }
2220 if ( fn[1] == "ZoomFactor" && dOk ) { Options::setZoomFactor( dVal ); cmdCount++; }
2221 if ( fn[1] == "MagLimitDrawStar" && dOk ) { Options::setMagLimitDrawStar( dVal ); cmdCount++; }
2222 if ( fn[1] == "MagLimitDrawStarZoomOut" && dOk ) { Options::setMagLimitDrawStarZoomOut( dVal ); cmdCount++; }
2223 if ( fn[1] == "MagLimitDrawDeepSky" && dOk ) { Options::setMagLimitDrawDeepSky( dVal ); cmdCount++; }
2224 if ( fn[1] == "MagLimitDrawDeepSkyZoomOut" && dOk ) { Options::setMagLimitDrawDeepSkyZoomOut( dVal ); cmdCount++; }
2225 if ( fn[1] == "MagLimitDrawStarInfo" && dOk ) { Options::setMagLimitDrawStarInfo( dVal ); cmdCount++; }
2226 if ( fn[1] == "MagLimitHideStar" && dOk ) { Options::setMagLimitHideStar( dVal ); cmdCount++; }
2227 if ( fn[1] == "MagLimitAsteroid" && dOk ) { Options::setMagLimitAsteroid( dVal ); cmdCount++; }
2228 if ( fn[1] == "MagLimitAsteroidName" && dOk ) { Options::setMagLimitAsteroidName( dVal ); cmdCount++; }
2229 if ( fn[1] == "MaxRadCometName" && dOk ) { Options::setMaxRadCometName( dVal ); cmdCount++; }
2231 //these three are a "radio group"
2232 if ( fn[1] == "UseLatinConstellationNames" && bOk ) {
2233 Options::setUseLatinConstellNames( true );
2234 Options::setUseLocalConstellNames( false );
2235 Options::setUseAbbrevConstellNames( false );
2236 cmdCount++;
2238 if ( fn[1] == "UseLocalConstellationNames" && bOk ) {
2239 Options::setUseLatinConstellNames( false );
2240 Options::setUseLocalConstellNames( true );
2241 Options::setUseAbbrevConstellNames( false );
2242 cmdCount++;
2244 if ( fn[1] == "UseAbbrevConstellationNames" && bOk ) {
2245 Options::setUseLatinConstellNames( false );
2246 Options::setUseLocalConstellNames( false );
2247 Options::setUseAbbrevConstellNames( true );
2248 cmdCount++;
2250 } else if ( fn[0] == "setGeoLocation" && ( fn.count() == 3 || fn.count() == 4 ) ) {
2251 QString city( fn[1] ), province( "" ), country( fn[2] );
2252 if ( fn.count() == 4 ) {
2253 province = fn[2];
2254 country = fn[3];
2257 bool cityFound( false );
2258 for (GeoLocation *loc = geoList.first(); loc; loc = geoList.next()) {
2259 if ( loc->translatedName() == city &&
2260 ( province.isEmpty() || loc->translatedProvince() == province ) &&
2261 loc->translatedCountry() == country ) {
2263 cityFound = true;
2264 setLocation( *loc );
2265 cmdCount++;
2266 break;
2270 if ( !cityFound )
2271 kdWarning() << i18n( "Could not set location named %1, %2, %3" ).arg(city).arg(province).arg(country) << endl;
2274 } //end while
2276 if ( cmdCount ) return true;
2277 return false;
2280 void KStarsData::saveTimeBoxShaded( bool b ) { Options::setShadeTimeBox( b ); }
2281 void KStarsData::saveGeoBoxShaded( bool b ) { Options::setShadeGeoBox( b ); }
2282 void KStarsData::saveFocusBoxShaded( bool b ) { Options::setShadeFocusBox( b ); }
2283 void KStarsData::saveTimeBoxPos( QPoint p ) { Options::setPositionTimeBox( p ); }
2284 void KStarsData::saveGeoBoxPos( QPoint p ) { Options::setPositionGeoBox( p ); }
2285 void KStarsData::saveFocusBoxPos( QPoint p ) { Options::setPositionFocusBox( p ); }
2287 #include "kstarsdata.moc"