/***************************************************************************
                          kstarsinit.cpp  -  K Desktop Planetarium
                             -------------------
    begin                : Mon Feb 25 2002
    copyright            : (C) 2002 by Jason Harris
    email                : jharris@30doradus.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <QFile>
#include <QDir>
#include <QTextStream>

#include <kactioncollection.h>
#include <kactionmenu.h>
#include <kiconloader.h>
#include <kmenu.h>
#include <kstatusbar.h>
#include <ktip.h>
#include <kmessagebox.h>
#include <kstandardaction.h>
#include <kstandarddirs.h>
#include <ktoggleaction.h>
#include <ktoolbar.h>
#include <kicon.h>
#include <knewstuff2/ui/knewstuffaction.h>

#include "Options.h"
#include "fov.h"
#include "kstars.h"
#include "kstarsdata.h"
#include "skymap.h"
#include "skyobjects/skyobject.h"
#include "skyobjects/ksplanetbase.h"
#include "simclock.h"
#include "widgets/timestepbox.h"
#include "comast/equipmentwriter.h"
#include "comast/observeradd.h"

#include <config-kstars.h>

#ifdef HAVE_INDI_H
#include "indi/indimenu.h"
#endif

//This file contains functions that kstars calls at startup (except constructors).
//These functions are declared in kstars.h

namespace {
    // A lot of KAction is defined there. In order to decrease amount
    // of boilerplate code a trick with << operator overloading is used.
    // This makes code more concise and readable.
    //
    // When data type could not used directly. Either because of
    // overloading rules or because one data type have different
    // semantics its wrapped into struct.
    //
    // Downside is unfamiliar syntax and really unhelpful error
    // messages due to general abuse of << overloading

    // Set KAction text
    KAction* operator << (KAction* ka, QString text) {
        ka->setText(text);
        return ka;
    }
    // Set icon for KAction
    KAction* operator << (KAction* ka, const KIcon& icon) {
        ka->setIcon(icon);
        return ka;
    }
    // Set keyboard shortcut
    KAction* operator << (KAction* ka, const KShortcut& sh) {
        ka->setShortcuts(sh);
        return ka;
    }

    // Add action to group. AddToGroup struct acts as newtype wrapper
    // in order to allow overloading.
    struct AddToGroup {
        QActionGroup* grp;
        AddToGroup(QActionGroup* g) : grp(g) {}
    };
    KAction* operator << (KAction* ka, AddToGroup g) {
        g.grp->addAction(ka);
        return ka;
    }

    // Set checked property. Checked is newtype wrapper.
    struct Checked {
        bool flag;
        Checked(bool f) : flag(f) {}
    };
    KAction* operator << (KAction* ka, Checked chk) {
        ka->setCheckable(true);
        ka->setChecked(chk.flag);
        return ka;
    }

    // Set tool tip. ToolTip is used as newtype wrapper.
    struct ToolTip {
        QString tip;
        ToolTip(QString msg) : tip(msg) {}
    };
    KAction* operator << (KAction* ka, const ToolTip& tool) {
        ka->setToolTip(tool.tip);
        return ka;
    }

    // Create new KToggleAction and connect slot to toggled(bool) signal
    KAction* newToggleAction(KActionCollection* col, QString name, QString text,
                             QObject* receiver, const char* member) {
        KAction* ka = col->add<KToggleAction>(name) << text;
        QObject::connect(ka, SIGNAL( toggled(bool) ), receiver, member);
        return ka;
    }
}

void KStars::initActions() {
    KIconLoader::global()->addAppDir( "kstars" );
    KAction *ka;

    // ==== File menu ================
    ka = KNS::standardAction(i18n("Download New Data..."), this, SLOT(slotDownload()), actionCollection(), "get_data")
        << KShortcut( Qt::CTRL+Qt::Key_D );
    ka->setWhatsThis(i18n("Downloads new data"));
    ka->setToolTip(ka->whatsThis());
    ka->setStatusTip(ka->whatsThis());

#ifdef HAVE_CFITSIO_H
    actionCollection()->addAction("open_file", this, SLOT(slotOpenFITS()) )
        << i18n("Open FITS...")
        << KIcon("document-open")
        << KShortcut( Qt::CTRL+Qt::Key_O );
#endif

    actionCollection()->addAction("export_image", this, SLOT( slotExportImage() ) )
        << i18n("&Save Sky Image...")
        << KIcon("document-export-image")
        << KShortcut( Qt::CTRL+Qt::Key_I );
    actionCollection()->addAction("run_script", this, SLOT( slotRunScript() ))
        << i18n("&Run Script...")
        << KIcon("system-run" )
        << KShortcut( Qt::CTRL+Qt::Key_R );
    actionCollection()->addAction( KStandardAction::Print, "print", this, SLOT( slotPrint() ) );
    actionCollection()->addAction( KStandardAction::Quit,  "quit",  this, SLOT( close() ) );

    // ==== Time Menu ================
    actionCollection()->addAction("time_to_now", this, SLOT( slotSetTimeToNow() ))
        << i18n("Set Time to &Now")
        << KShortcut( Qt::CTRL+Qt::Key_E );

    actionCollection()->addAction("time_dialog", this, SLOT( slotSetTime() ) )
        << i18nc("set Clock to New Time", "&Set Time..." )
        << KShortcut( Qt::CTRL+Qt::Key_S )
        << KIcon("view-history");

    ka = actionCollection()->add<KToggleAction>("clock_startstop")
        << i18n("Stop &Clock" )
        << KIcon("media-playback-pause" );
    QObject::connect( ka, SIGNAL( triggered() ), this, SLOT( slotToggleTimer() ) );
    QObject::connect(data()->clock(), SIGNAL(clockToggled(bool)), ka, SLOT(setChecked(bool)) );
    //UpdateTime() if clock is stopped (so hidden objects get drawn)
    QObject::connect(data()->clock(), SIGNAL(clockStopped()), this, SLOT(updateTime()) );

    // ==== Pointing Menu ================
    actionCollection()->addAction("zenith", this, SLOT( slotPointFocus() ) )
        << i18n("&Zenith")
        << KShortcut("Z");
    actionCollection()->addAction("north", this, SLOT( slotPointFocus() ) )
        << i18n("&North")
        << KShortcut("N");
    actionCollection()->addAction("east", this, SLOT( slotPointFocus() ) )
        << i18n("&East")
        << KShortcut("E");
    actionCollection()->addAction("south", this, SLOT( slotPointFocus() ) )
        << i18n("&South")
        << KShortcut("S");
    actionCollection()->addAction("west", this, SLOT( slotPointFocus() ) )
        << i18n("&West")
        << KShortcut("W");

    actionCollection()->addAction("find_object", this, SLOT( slotFind() ) )
        << i18n("&Find Object...")
        << KIcon("edit-find")
        << KShortcut( Qt::CTRL+Qt::Key_F );
    actionCollection()->addAction("track_object", this, SLOT( slotTrack() ) )
        << i18n("Engage &Tracking")
        << KIcon("object-locked" )
        << KShortcut( Qt::CTRL+Qt::Key_T  );
    actionCollection()->addAction("manual_focus", this, SLOT( slotManualFocus() ) )
        << i18n("Set Focus &Manually..." )
        << KShortcut( Qt::CTRL+Qt::Key_M );

    // ==== View Menu ================
    actionCollection()->addAction( KStandardAction::ZoomIn,  "zoom_in", this, SLOT( zoomIn() ) );
    actionCollection()->addAction( KStandardAction::ZoomOut, "zoom_out", this, SLOT( zoomOut() ) );
    actionCollection()->addAction("zoom_default", this, SLOT( defaultZoom() ) )
        << i18n("&Default Zoom")
        << KIcon("zoom-fit-best" )
        << KShortcut( Qt::CTRL+Qt::Key_Z );
    actionCollection()->addAction("zoom_set", this, SLOT( slotSetZoom() ) )
        << i18n("&Zoom to Angular Size..." )
        << KIcon("zoom-original" )
        << KShortcut( Qt::CTRL+Qt::SHIFT+Qt::Key_Z );

    actionCollection()->addAction( KStandardAction::FullScreen, this, SLOT( slotFullScreen() ) );

    actionCollection()->addAction("coordsys", this, SLOT( slotCoordSys() ) )
        << (Options::useAltAz() ? i18n("Horizontal &Coordinates") : i18n("Equatorial &Coordinates"))
        << KShortcut("Space" );

    actionCollection()->addAction("project_lambert", this, SLOT( slotMapProjection() ) )
        << i18n("&Lambert Azimuthal Equal-area" )
        << KShortcut("F5" )
        << AddToGroup(projectionGroup)
        << Checked(Options::projection() == SkyMap::Lambert);
    actionCollection()->addAction("project_azequidistant", this, SLOT( slotMapProjection() ) )
        << i18n("&Azimuthal Equidistant" )
        << KShortcut("F6" )
        << AddToGroup(projectionGroup)
        << Checked(Options::projection() == SkyMap::AzimuthalEquidistant);
    actionCollection()->addAction("project_orthographic", this, SLOT( slotMapProjection() ) )
        << i18n("&Orthographic" )
        << KShortcut("F7" )
        << AddToGroup(projectionGroup)
        << Checked(Options::projection() == SkyMap::Orthographic);
    actionCollection()->addAction("project_equirectangular", this, SLOT( slotMapProjection() ) )
        << i18n("&Equirectangular" )
        << KShortcut("F8" )
        << AddToGroup(projectionGroup)
        << Checked(Options::projection() == SkyMap::Equirectangular);
    actionCollection()->addAction("project_stereographic", this, SLOT( slotMapProjection() ) )
        << i18n("&Stereographic" )
        << KShortcut("F9" )
        << AddToGroup(projectionGroup)
        << Checked(Options::projection() == SkyMap::Stereographic);
    actionCollection()->addAction("project_gnomonic", this, SLOT( slotMapProjection() ) )
        << i18n("&Gnomonic" )
        << KShortcut("F10" )
        << AddToGroup(projectionGroup)
        << Checked(Options::projection() == SkyMap::Gnomonic);

    //Settings Menu:
    //Info Boxes option actions
    KAction* kaBoxes = actionCollection()->add<KToggleAction>("show_boxes" )
        << i18nc("Show the information boxes", "Show &Info Boxes")
        << Checked( Options::showInfoBoxes() );

    ka = actionCollection()->add<KToggleAction>("show_time_box")
        << i18nc("Show time-related info box", "Show &Time Box");
    connect(kaBoxes, SIGNAL( toggled(bool) ), ka, SLOT( setEnabled(bool) ) );

    ka = actionCollection()->add<KToggleAction>("show_focus_box")
        << i18nc("Show focus-related info box", "Show &Focus Box");
    connect(kaBoxes, SIGNAL( toggled(bool) ), ka, SLOT( setEnabled(bool) ) );

    ka = actionCollection()->add<KToggleAction>("show_location_box")
        << i18nc("Show location-related info box", "Show &Location Box");
    connect(kaBoxes, SIGNAL( toggled(bool) ), ka, SLOT( setEnabled(bool) ) );


    //Toolbar options
    newToggleAction( actionCollection(), "show_mainToolBar", i18n("Show Main Toolbar"),
                     this, SLOT(slotShowGUIItem(bool)));
    newToggleAction( actionCollection(), "show_viewToolBar", i18n("Show View Toolbar"),
                     this, SLOT(slotShowGUIItem(bool)));

    //Statusbar view options
    newToggleAction( actionCollection(), "show_statusBar", i18n("Show Statusbar"),
                     this, SLOT(slotShowGUIItem(bool)));
    newToggleAction( actionCollection(), "show_sbAzAlt",   i18n("Show Az/Alt Field"),
                     this, SLOT(slotShowGUIItem(bool)));
    newToggleAction( actionCollection(), "show_sbRADec",   i18n("Show RA/Dec Field"),
                     this, SLOT(slotShowGUIItem(bool)));

    //Color scheme actions.  These are added to the "colorschemes" KActionMenu.
    colorActionMenu = actionCollection()->add<KActionMenu>("colorschemes" );
    colorActionMenu->setText( i18n("C&olor Schemes" ) );
    addColorMenuItem( i18n("&Classic" ), "cs_classic" );
    addColorMenuItem( i18n("&Star Chart" ), "cs_chart" );
    addColorMenuItem( i18n("&Night Vision" ), "cs_night" );
    addColorMenuItem( i18n("&Moonless Night" ), "cs_moonless-night" );

    //Add any user-defined color schemes:
    QFile file( KStandardDirs::locate("appdata", "colors.dat" ) ); //determine filename in local user KDE directory tree.
    if ( file.exists() && file.open( QIODevice::ReadOnly ) ) {
        QTextStream stream( &file );
        while ( !stream.atEnd() ) {
            QString line = stream.readLine();
            QString schemeName = line.left( line.indexOf( ':' ) );
            QString actionname = "cs_" + line.mid( line.indexOf( ':' ) +1, line.indexOf( '.' ) - line.indexOf( ':' ) - 1 );
            addColorMenuItem( i18n( schemeName.toLocal8Bit() ), actionname.toLocal8Bit() );
        }
        file.close();
    }

    //Add FOV Symbol actions
    fovActionMenu = actionCollection()->add<KActionMenu>("fovsymbols" );
    fovActionMenu->setText( i18n("&FOV Symbols" ) );
    repopulateFOV();

    actionCollection()->addAction("geolocation", this, SLOT( slotGeoLocator() ) )
        << i18nc("Location on Earth", "&Geographic..." )
        << KIcon("applications-internet" )
        << KShortcut( Qt::CTRL+Qt::Key_G );
    actionCollection()->addAction( KStandardAction::Preferences, "configure", this, SLOT( slotViewOps() ) );
    actionCollection()->addAction("startwizard", this, SLOT( slotWizard() ) )
        << i18n("Startup Wizard..." )
        << KIcon("tools-wizard" );

    //Tools Menu:
    actionCollection()->addAction("astrocalculator", this, SLOT( slotCalculator() ) )
        << i18n("Calculator...")
        << KIcon("accessories-calculator" )
        << KShortcut( Qt::CTRL+Qt::Key_C );
    actionCollection()->addAction("obslist", this, SLOT( slotObsList() ) )
        << i18n("Observing List...")
        << KShortcut( Qt::CTRL+Qt::Key_L );

    // enable action only if file was loaded and processed successfully.
    actionCollection()->addAction("lightcurvegenerator", this, SLOT( slotLCGenerator() ) )
        << i18n("AAVSO Light Curves...")
        << KShortcut( Qt::CTRL+Qt::Key_V );

    actionCollection()->addAction("altitude_vs_time", this, SLOT( slotAVT() ) )
        << i18n("Altitude vs. Time...")
        << KShortcut( Qt::CTRL+Qt::Key_A );
    actionCollection()->addAction("whats_up_tonight", this, SLOT( slotWUT() ) )
        << i18n("What's up Tonight...")
        << KShortcut(Qt::CTRL+Qt::Key_U );
    actionCollection()->addAction("skycalendar", this, SLOT( slotCalendar() ) )
        << i18n("Sky Calendar...");

//FIXME: implement glossary
//     ka = actionCollection()->addAction("glossary");
//     ka->setText( i18n("Glossary...") );
//     ka->setShortcuts( KShortcut(Qt::CTRL+Qt::Key_K ) );
//     connect( ka, SIGNAL( triggered() ), this, SLOT( slotGlossary() ) );

    actionCollection()->addAction("scriptbuilder", this, SLOT( slotScriptBuilder() ) )
        << i18n("Script Builder...")
        << KShortcut(Qt::CTRL+Qt::Key_B );
    actionCollection()->addAction("solarsystem", this, SLOT( slotSolarSystem() ) )
        << i18n("Solar System...")
        << KShortcut(Qt::CTRL+Qt::Key_Y );
    actionCollection()->addAction("jmoontool", this, SLOT( slotJMoonTool() ) )
        << i18n("Jupiter's Moons...")
        << KShortcut(Qt::CTRL+Qt::Key_J );
    actionCollection()->addAction("flagmanager", this, SLOT( slotFlagManager() ) )
        << i18n("Flags...");

    actionCollection()->addAction("ewriter", this, SLOT( slotEquipmentWriter() ) )
        << i18n("Define Equipment...")
        << KShortcut( Qt::CTRL+Qt::Key_0 );
    actionCollection()->addAction("obsadd", this, SLOT( slotObserverAdd() ) )
        << i18n( "Add Observer..." )
        << KShortcut( Qt::CTRL+Qt::Key_1 );

    // ==== observation menu ================
    ka = actionCollection()->addAction("execute", this, SLOT( slotExecute() ) )
        << i18n( "Execute the session Plan..." )
        << KShortcut( Qt::CTRL+Qt::Key_2 );

    // ==== devices Menu ================
#ifdef HAVE_INDI_H
#ifndef Q_WS_WIN

    actionCollection()->addAction("telescope_wizard", this, SLOT( slotTelescopeWizard() ) )
        << i18n("Telescope Wizard...")
        << KIcon("tools-wizard" );
    actionCollection()->addAction("telescope_properties", this, SLOT( slotTelescopeProperties() ) )
        << i18n("Telescope Properties...");
    actionCollection()->addAction("device_manager", this, SLOT( slotINDIDriver() ) )
        << i18n("Device Manager...")
        << KIcon("network-server" );

    ka = actionCollection()->addAction("capture_sequence", this, SLOT( slotImageSequence() ) )
        << i18n("Capture Image Sequence...");
    ka->setEnabled(false);

    ka = actionCollection()->addAction("indi_cpl", this, SLOT( slotINDIPanel() ) )
        << i18n("INDI Control Panel...");
    ka->setEnabled(false);

#endif
#endif

    //Help Menu:
    //	KStandardAction::tipOfDay(this, SLOT( slotTipOfDay() ), actionCollection(), "help_tipofday" );

    //	KStandardAction::help(this, SLOT( appHelpActivated() ), actionCollection(), "help_contents" );

    //Add timestep widget for toolbar
    TimeStep = new TimeStepBox( toolBar("kstarsToolBar") );
    // Add a tool tip to TimeStep describing the weird nature of time steps
    QString TSBToolTip = i18nc( "Tooltip describing the nature of the time step control", "Use this to set the rate at which time in the simulation flows.\nFor time step \'X\' up to 10 minutes, time passes at the rate of \'X\' per second.\nFor time steps larger than 10 minutes, frames are displayed at an interval of \'X\'." );
    TimeStep->setToolTip( TSBToolTip );
    TimeStep->tsbox()->setToolTip( TSBToolTip );
    ka = actionCollection()->addAction("timestep_control")
        << i18n("Time step control");
    ka->setDefaultWidget( TimeStep );

    // ==== viewToolBar actions ================
    actionCollection()->add<KToggleAction>("show_stars", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle Stars in the display", "Stars" )
        << KIcon("kstars_stars" )
        << ToolTip( i18n("Toggle stars") );
    actionCollection()->add<KToggleAction>("show_deepsky", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle Deep Sky Objects in the display", "Deep Sky" )
        << KIcon("kstars_deepsky" )
        << ToolTip( i18n("Toggle deep sky objects") );
    actionCollection()->add<KToggleAction>("show_planets", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle Solar System objects in the display", "Solar System" )
        << KIcon("kstars_planets" )
        << ToolTip( i18n("Toggle Solar system objects") );
    actionCollection()->add<KToggleAction>("show_clines", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle Constellation Lines in the display", "Const. Lines" )
        << KIcon("kstars_clines" )
        << ToolTip( i18n("Toggle constellation lines") );
    actionCollection()->add<KToggleAction>("show_cnames", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle Constellation Names in the display", "Const. Names" )
        << KIcon("kstars_cnames" )
        << ToolTip( i18n("Toggle constellation names") );
    actionCollection()->add<KToggleAction>("show_cbounds", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle Constellation Boundaries in the display", "C. Boundaries" )
        << KIcon("kstars_cbound" )
        << ToolTip( i18n("Toggle constellation boundaries") );
    actionCollection()->add<KToggleAction>("show_mw", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle Milky Way in the display", "Milky Way" )
        << KIcon("kstars_mw" )
        << ToolTip( i18n("Toggle milky way") );
    actionCollection()->add<KToggleAction>("show_grid", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle Coordinate Grid in the display", "Coord. grid" )
        << KIcon("kstars_grid" )
        << ToolTip( i18n("Toggle coordinate grid") );
    actionCollection()->add<KToggleAction>("show_horizon", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle the opaque fill of the ground polygon in the display", "Ground" )
        << KIcon("kstars_horizon" )
        << ToolTip( i18n("Toggle opaque ground") );
    actionCollection()->add<KToggleAction>("show_flags", this, SLOT( slotViewToolBar() ) )
        << i18nc("Toggle flags in the display", "Flags" )
        << KIcon("kstars_flag" )
        << ToolTip( i18n("Toggle flags") );

    setXMLFile("kstarsui.rc" );

    if (Options::fitsDir().isEmpty())
        Options::setFitsDir(QDir:: homePath());
}

void KStars::repopulateFOV() {
    // Read list of all FOVs
    qDeleteAll( data()->availFOVs );
    data()->availFOVs = FOV::readFOVs();
    data()->syncFOV();

    // Iterate through FOVs
    fovActionMenu->menu()->clear();
    foreach(FOV* fov, data()->availFOVs) {
        KToggleAction *kta = actionCollection()->add<KToggleAction>( fov->name() );
        kta->setText( fov->name() );
        if( Options::fOVNames().contains( fov->name() ) ) {
            kta->setChecked(true);
        }
        fovActionMenu->addAction( kta );
        connect( kta, SIGNAL( toggled( bool ) ), this, SLOT( slotTargetSymbol(bool) ) );
    }
    // Add menu bottom
    KAction* ka = actionCollection()->addAction("edit_fov",  this, SLOT( slotFOVEdit() ) )
        << i18n("Edit FOV Symbols...");
    fovActionMenu->addSeparator();
    fovActionMenu->addAction( ka );
}

void KStars::initStatusBar() {
    statusBar()->insertPermanentItem( i18n( " Welcome to KStars " ), 0, 1 );
    statusBar()->setItemAlignment( 0, Qt::AlignLeft | Qt::AlignVCenter );

    QString s = "000d 00m 00s,   +00d 00\' 00\""; //only need this to set the width
    if ( Options::showAltAzField() ) {
        statusBar()->insertPermanentFixedItem( s, 1 );
        statusBar()->setItemAlignment( 1, Qt::AlignRight | Qt::AlignVCenter );
        statusBar()->changeItem( QString(), 1 );
    }

    if ( Options::showRADecField() ) {
        statusBar()->insertPermanentFixedItem( s, 2 );
        statusBar()->setItemAlignment( 2, Qt::AlignRight | Qt::AlignVCenter );
        statusBar()->changeItem( QString(), 2 );
    }

    if ( ! Options::showStatusBar() )
        statusBar()->hide();
}

void KStars::datainitFinished() {
    //Add GUI elements to main window
    buildGUI();

    //Time-related connections
    connect( data()->clock(), SIGNAL( timeAdvanced() ),
             this, SLOT( updateTime() ) );
    connect( data()->clock(), SIGNAL( timeChanged() ),
             this, SLOT( updateTime() ) );
    connect( data()->clock(), SIGNAL( scaleChanged( float ) ),
             map(), SLOT( slotClockSlewing() ) );

    connect( data(),   SIGNAL( update() ),            map(),  SLOT( forceUpdateNow() ) );
    connect( TimeStep, SIGNAL( scaleChanged(float) ), data(), SLOT( setTimeDirection( float ) ) );
    connect( TimeStep, SIGNAL( scaleChanged(float) ),
             data()->clock(), SLOT( setScale( float )) );
    connect( TimeStep, SIGNAL( scaleChanged(float) ), map(),  SLOT( setFocus() ) );


    #ifdef HAVE_INDI_H
    //Initialize INDIMenu
    indimenu = new INDIMenu(this);
    #endif

    //Initialize Observing List
    obsList = new ObservingList( this );
    eWriter = new EquipmentWriter();
    oAdd = new ObserverAdd;

    //Do not start the clock if "--paused" specified on the cmd line
    if ( StartClockRunning )
        data()->clock()->start();

    // Connect cache function for Find dialog
    connect( data(), SIGNAL( clearCache() ), this,
             SLOT( clearCachedFindDialog() ) );

    //Propagate config settings
    applyConfig( false );

    //show the window.  must be before kswizard and messageboxes
    show();

    //Initialize focus
    initFocus();

    data()->setFullTimeUpdate();
    updateTime();

    //If this is the first startup, show the wizard
    if ( Options::runStartupWizard() ) {
        slotWizard();
    }

    //Show TotD
    KTipDialog::showTip(this, "kstars/tips");

    //DEBUG
    kDebug() << "The current Date/Time is: " << KStarsDateTime::currentDateTime().toString();
}

void KStars::initFocus() {
    //Case 1: tracking on an object
    if ( Options::isTracking() && Options::focusObject() != i18n("nothing") ) {
        SkyObject *oFocus;
        if ( Options::focusObject() == i18n("star") ) {
            SkyPoint p( Options::focusRA(), Options::focusDec() );
            double maxrad = 1.0;

            oFocus = data()->skyComposite()->starNearest( &p, maxrad );
        } else {
            oFocus = data()->objectNamed( Options::focusObject() );
        }

        if ( oFocus ) {
            map()->setFocusObject( oFocus );
            map()->setClickedObject( oFocus );
            map()->setFocusPoint( oFocus );
        } else {
            kWarning() << "Cannot center on "
                       << Options::focusObject()
                       << ": no object found." << endl;
        }

    //Case 2: not tracking, and using Alt/Az coords.  Set focus point using
    //FocusRA as the Azimuth, and FocusDec as the Altitude
    } else if ( ! Options::isTracking() && Options::useAltAz() ) {
        SkyPoint pFocus;
        pFocus.setAz( Options::focusRA() );
        pFocus.setAlt( Options::focusDec() );
        pFocus.HorizontalToEquatorial( data()->lst(), data()->geo()->lat() );
        map()->setFocusPoint( &pFocus );

    //Default: set focus point using FocusRA as the RA and
    //FocusDec as the Dec
    } else {
        SkyPoint pFocus( Options::focusRA(), Options::focusDec() );
        pFocus.EquatorialToHorizontal( data()->lst(), data()->geo()->lat() );
        map()->setFocusPoint( &pFocus );
    }
    data()->setSnapNextFocus();
    map()->setDestination( map()->focusPoint() );
    map()->setFocus( map()->destination() );

    map()->showFocusCoords();

    //Check whether initial position is below the horizon.
    if ( Options::useAltAz() && Options::showHorizon() && Options::showGround() &&
            map()->focus()->alt()->Degrees() < -1.0 ) {
        QString caption = i18n( "Initial Position is Below Horizon" );
        QString message = i18n( "The initial position is below the horizon.\nWould you like to reset to the default position?" );
        if ( KMessageBox::warningYesNo( this, message, caption,
                                        KGuiItem(i18n("Reset Position")), KGuiItem(i18n("Do Not Reset")), "dag_start_below_horiz" ) == KMessageBox::Yes ) {
            map()->setClickedObject( NULL );
            map()->setFocusObject( NULL );
            Options::setIsTracking( false );

            data()->setSnapNextFocus(true);

            SkyPoint DefaultFocus;
            DefaultFocus.setAz( 180.0 );
            DefaultFocus.setAlt( 45.0 );
            DefaultFocus.HorizontalToEquatorial( data()->lst(), data()->geo()->lat() );
            map()->setDestination( &DefaultFocus );
        }
    }

    //If there is a focusObject() and it is a SS body, add a temporary Trail
    if ( map()->focusObject() && map()->focusObject()->isSolarSystem()
            && Options::useAutoTrail() ) {
        ((KSPlanetBase*)map()->focusObject())->addToTrail();
        data()->temporaryTrail = true;
    }
}

void KStars::buildGUI() {
    //Initialize menus, toolbars, and statusbars
    initStatusBar();
    initActions();

    //create the skymap
    skymap = SkyMap::Create();
    setCentralWidget( skymap );
    connect(skymap, SIGNAL(zoomChanged()), this, SLOT( slotZoomChanged() ));


    setupGUI(StandardWindowOptions (Default & ~Create));

#ifdef Q_WS_WIN
    createGUI("kstarsui-win.rc");
#else
    createGUI("kstarsui.rc");
#endif

    //get focus of keyboard and mouse actions (for example zoom in with +)
    map()->QWidget::setFocus();
    resize( Options::windowWidth(), Options::windowHeight() );

    // check zoom in/out buttons
    if ( Options::zoomFactor() >= MAXZOOM ) actionCollection()->action("zoom_in")->setEnabled( false );
    if ( Options::zoomFactor() <= MINZOOM ) actionCollection()->action("zoom_out")->setEnabled( false );
}
