/*
 *
 * Copyright (C) 2002-2003 Rich Moore <rich@kde.org>
 * Copyright (C) 2002-2003 George Staikos <staikos@kde.org>
 * Copyright (C) 2003-2004 Dirk Ziegelmeier <dziegel@gmx.de>
 *
 *   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 <qdir.h>
#include <qpushbutton.h>
#include <qtimer.h>
#include <qtextedit.h>
#include <qevent.h>

#include <kaction.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kkeydialog.h>
#include <klocale.h>
#include <kmenubar.h>
#include <kpopupmenu.h>
#include <krun.h>
#include <kstandarddirs.h>
#include <kstatusbar.h>
#include <ktoolbar.h>
#include <kapplication.h>
#include <kedittoolbar.h>
#include <kwin.h>
#include <ktip.h>
#include <dcopclient.h>

#include "actions.h" // QSlider.h included by actions.h clashes with netwm #includes

#include <netwm.h>

#include "kdetvwidget.h"
#include "viewmanager.h"
#include "kdetvview.h"
#include "kdetv.h"
#include "libkdetvactions.h"
#include "sourcemanager.h"
#include "sidebar.h"
#include "systray.h"
#include "savercontrol.h"
#include "dpmscontrol.h"
#include "osdmanager.h"
#include "cfgdata.h"
#include "statusmanager.h"
#include "audiomanager.h"

#include "kdetvsettingswidgetimpl.h"


#define STATUSBAR_MAIN		0
#define STATUSBAR_PROGRAM	1

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#ifdef HAVE_LIRC_KDETV
#include "lirc.h"
#endif

#include "mainwindow.h"
#include "mainwindow.moc"

MainWindow::MainWindow( QWidget *parent, const char *name, WFlags f )
    : DCOPObject( "KdetvViewIface" ),
      KDockMainWindow( parent, name ? name : "main_window", f ),
      _systray(0), _lirc(0), _viewMode(ViewNormal), _sleepdelay(0), _savedGuiStateValid(false)
{
    _toolbarVisibilityList.setAutoDelete(true);

    _haveKWin = KApplication::dcopClient()->isApplicationRegistered("kwin");

    // Views
    KDockWidget* mainDock = createDockWidget("TVScreen", QPixmap(), 0L, i18n("TV Screen"));
    _screen = new KdetvWidget(mainDock);
    mainDock->setWidget(_screen);
    mainDock->setDockSite(KDockWidget::DockCorner);
    mainDock->setEnableDocking(KDockWidget::DockNone);
    setView(mainDock);
    setMainDockWidget(mainDock);

    _sideDock = createDockWidget("Sidebar", QPixmap(), 0L, i18n("Channel Sidebar"));
    Sidebar* side = new Sidebar(_screen, _sideDock);
    side->createViews();
    _sideDock->setWidget(side);
    _sideDock->setEnableDocking(KDockWidget::DockCorner); // unhiding when it is a top-level widget is broken
    _sideDock->manualDock(mainDock, KDockWidget::DockLeft, 20); // nice default position

    // Cfg handle
    _cfg = kapp->config();

    // Create the actions
    actionCollection()->setHighlightingEnabled( true );
    createActions();

    // Setup status messages
    connect( actionCollection(), SIGNAL( actionStatusText(const QString &) ),
             this, SLOT( statusMessage(const QString & ) ) );
    connect( actionCollection(), SIGNAL( clearStatusText() ),
             this, SLOT( clearStatusBar() ) );
    connect( _screen->driver(), SIGNAL( channelChanged(const QString &) ),
             this, SLOT( setCaption(const QString & ) ) );
    connect( _screen->view(), SIGNAL( doubleClicked() ),
             this, SLOT( nextViewMode() ) );
    connect( this, SIGNAL( numberKeyPressed(int) ),
             _screen->driver(), SLOT( processNumberKeyEvent(int) ) );

    // Add kdetv config widget to settings dialog
    _screen->driver()->views()->registerPageFactory(static_cast<SettingsDialogPageFactory*>(this));

    // Enable/disable actions
    _actions->deviceChanged( 0 );

    _sleeptimer = new QTimer(parent);
    connect(_sleeptimer, SIGNAL(timeout()),
            this, SLOT(slotSleepTimerTimeout()));

    connect(this, SIGNAL(sleepTimerDelay(const QString &)),
            _screen->driver()->osdManager(), SLOT(displayCC(const QString &)));

    setupInfraRed();

    // Create the main window shell
    setXMLFile( "kdetvui.rc" );
    setStandardToolBarMenuEnabled(true);
    createGUI( QString::null, false );
    resize(700, 400); // nice default size
    restoreWindowSettings();

    if (_staysOnTop) {
        KWin::setState(winId(), NET::StaysOnTop);
    }
    KWin::setOnAllDesktops(winId(), _sticky);

    KMenuBar *mb = menuBar();
    mb->changeItem( mb->idAt(0), i18n("&Channels") );

    // Store the current status of the screensaver
    _screenSaverWasEnabled = SaverControl::getSaverStatus();
    // and the dpms
    _dpmsWasEnabled = DpmsControl::getDpmsStatus();

    // save current background color
    _bgcol = paletteBackgroundColor();

    // Update screensaver when necessary
    connect( this, SIGNAL( visibilityChanged(bool) ),
             this, SLOT( checkScreenSaver() ) );
    connect( this, SIGNAL( viewModeChanged(int) ),
             this, SLOT( checkScreenSaver() ) );

    // Create the status bar
    statusBar()->insertItem(QString::null, STATUSBAR_MAIN, 1);
    statusBar()->setItemAlignment(STATUSBAR_MAIN, AlignLeft | AlignVCenter);
    statusBar()->insertItem(QString::null, STATUSBAR_PROGRAM, 0, true);

    connect(_screen->driver()->statusManager(),
            SIGNAL(messageSent(const QString&)),
            this, SLOT(shortMessage(const QString&)));

    connect(_screen->driver()->statusManager(),
            SIGNAL(programChanged(const QString&)),
            this, SLOT(sbProgramName(const QString&)));

    // allow installation of plugin gui elements
    _screen->driver()->setGuiFactory(guiFactory(), actionCollection());

    // enable/disable audio controls
    connect(_screen->driver()->audioManager(), SIGNAL( mixerAvailable(bool) ),
            _actions, SLOT( enableAudioActions(bool) ));
    _actions->enableAudioActions(_screen->driver()->audioManager()->plugin());

    // keeps devices actionlist up to date
    connect(_screen->driver()->sourceManager(), SIGNAL( devicesChanged() ),
            this, SLOT( devicePluginsChanged() ));

    // keeps audiomodes actionlist up to date
    connect(_screen->driver()->sourceManager(), SIGNAL( deviceChanged(const QString&) ),
            this, SLOT( audioModesChanged() ));
    connect(_screen->driver()->sourceManager(), SIGNAL( sourceChanged(const QString&) ),
            this, SLOT( audioModesChanged() ));

    KTipDialog::showTip(this);

    QTimer::singleShot( 0, this, SLOT(restoreViewMode()) );
    QTimer::singleShot( 0, _screen->driver(), SLOT(start()) );
}

MainWindow::~MainWindow()
{
    // tell the driver to remove it's GUI elements
    _screen->driver()->setGuiFactory(0L, 0L);

    // Save the current window settings & size
    saveWindowSettings();

    // If the screensaver was previously enabled, re-enable it.
    // May cause confusion if the screensaver's configuration
    // has been changed while this application was running...
    disableScreenSaver( false );

    delete _sleeptimer;

    // So we don't crash on exit
    delete _actions;
}

void MainWindow::createActions()
{
    KActionCollection* acts = actionCollection();

    // Standard actions
    (void) KStdAction::quit( qApp, SLOT( quit() ), acts );
    _actShowMenubar   = KStdAction::showMenubar( this, SLOT( toggleMenubar() ), acts );

    createStandardStatusBarAction();

    // Kdetv actions
    _actions = new LibKdetvActions( _screen->driver() );
    _actions->createActions( acts );

    connect( _screen->driver(), SIGNAL( channelText(const QString &) ),
             _actions->channel(), SLOT( display(const QString &) ) );

    connect( _actions, SIGNAL(launchBindings()), this, SLOT(keyBindings()) );

    // View Modes
    _actShowNorm = new KRadioAction( i18n("&Normal"),        "kdetv",             Key_Home,     acts, "show_normal" );
    _actShowTV   = new KRadioAction( i18n("T&V Mode"),       "inline_image",      Key_PageDown, acts, "show_top_level" );
    _actShowFull = new KRadioAction( i18n("&Full Screen"),   "window_fullscreen", Key_PageUp,   acts, "full_screen" );
    //    _actShowDesk = new KRadioAction( i18n("Video &Desktop"), "frame_image",       0,            acts, "show_video_desktop" );
    _actShowNorm->setExclusiveGroup( "view_modes" );
    _actShowTV->setExclusiveGroup(   "view_modes" );
    _actShowFull->setExclusiveGroup( "view_modes" );
    //    _actShowDesk->setExclusiveGroup( "view_modes" );
    connect( _actShowNorm, SIGNAL(toggled(bool)), this, SLOT(actSetViewModeNormal(bool)) );
    connect( _actShowTV,   SIGNAL(toggled(bool)), this, SLOT(actSetViewModeTV(bool)) );
    connect( _actShowFull, SIGNAL(toggled(bool)), this, SLOT(actSetViewModeFullScreen(bool)) );
    //    connect( _actShowDesk, SIGNAL(toggled(bool)), this, SLOT(actSetViewModeVideoDesktop(bool)) );

    _actNextView = new KAction( i18n("Next View"), "next", 0, this, SLOT( nextViewMode() ), acts,
                                "next_view_mode" );
    _actToggleFull = new KToggleAction( i18n("Toggle FullScreen"), "window_fullscreen", Key_F,
                                        this, SLOT( toggleFullScreen() ),
                                        acts, "toggle_fullscreen" );

    // GUI elements
    _actShowSidebar = new KToggleAction( i18n("Show Sidebar"), "view_sidetree", Key_F9,
                                         acts, "show_sidebar" );
    _actShowSidebar->setStatusText( i18n( "Shows and hides the sidebar." ) );
    connect(_actShowSidebar, SIGNAL( toggled(bool) ),
            this,            SLOT( setSidebarVisibility(bool) ));

    // sidebar visibility tracking (ugly...)
    connect(_sideDock, SIGNAL( iMBeingClosed() ),
            this,      SLOT( sideBarVisibilityChanged() ));
    connect(_sideDock, SIGNAL( headerCloseButtonClicked() ),
            this,      SLOT( sideBarVisibilityChanged() ));
    connect(_sideDock, SIGNAL( hasUndocked() ),
            this,      SLOT( sideBarVisibilityChanged() ));

    _actConfigToolbar = new KAction( i18n("Configure Toolbars..."), "configure", 0, this,
                                     SLOT( configureToolbars() ), acts, "config_toolbars");

    // Help actions
    _actWebSite = new KAction( i18n("kdetv Web Site"), "html", 0,
                               this, SLOT( showWebSite() ),
                               acts, "help_view_website" );
    _actFAQ = new KAction( i18n("kdetv FAQ"), "help", 0,
                           this, SLOT( showFAQ() ),
                           acts, "help_view_faq" );

    _sleepTime = new KToggleAction( i18n("Sleep Timer"), "kalarm", Key_T,
                                    this, SLOT( sleepTimer() ), acts,
                                    "sleep_timer" );
    _actShowTips = new KAction( i18n("Tip of the Day"), "ktip", 0,
                                this, SLOT( showTipOfTheDay() ),
                                acts, "help_tip_of_the_day" );

    // setup import/export actions for channel files
    const QStringList& fread = _screen->driver()->fileFormatsRead();
    for (QStringList::const_iterator it = fread.constBegin();
         it != fread.constEnd();
         ++it) {
        ImpExChannelsAction* a = new ImpExChannelsAction(*it + i18n(" File..."), 0, *it,
                                                         _screen->driver(), 1,
                                                         actionCollection(), (*it).local8Bit());
        a->setIcon("1leftarrow");
        _importActionList.append(a);
    }

    const QStringList& fwrite = _screen->driver()->fileFormatsWrite();
    for (QStringList::const_iterator it = fwrite.constBegin();
         it != fwrite.constEnd();
         ++it) {
        ImpExChannelsAction* a = new ImpExChannelsAction(*it + i18n(" File..."), 0, *it,
                                                         _screen->driver(), 0,
                                                         actionCollection(), (*it).local8Bit());
        a->setIcon("1rightarrow");
        _exportActionList.append(a);
    }
}

void MainWindow::devicePluginsChanged()
{
    unplugActionList( "devices_actionlist" );
    plugActionList( "devices_actionlist", _actions->devicesActionList( actionCollection() ) );
}

void MainWindow::audioModesChanged()
{
    unplugActionList( "audiomode_actionlist" );
    plugActionList( "audiomode_actionlist", _actions->audioModesActionList( actionCollection() ) );
}

void MainWindow::addDynamicActions()
{
    unplugActionList( "channels_import_actionlist" );
    plugActionList( "channels_import_actionlist", _importActionList );

    unplugActionList( "channels_export_actionlist" );
    plugActionList( "channels_export_actionlist", _exportActionList );

    // Create context menu
    insertContextMenu( "screen_context_popup" );

    devicePluginsChanged();
    audioModesChanged();
}

void MainWindow::setupInfraRed()
{
#ifdef HAVE_LIRC_KDETV

    // Remove the instance in case this function gets invoked
    // twice.  This should not happen.  However, since we can
    // not be certain about that it is always better to be safe
    // than sorry...
    delete _lirc;

    // Attach it to this window, not its parent.  Actually
    // parent () in this case will return 0L since this is
    // the top-level window...
    _lirc = new Lirc (this, "kdetv");

    QMap<QString, QString> lircKeyMap;
    lircKeyMap["CH+"] = "channel_up";
    lircKeyMap["CH-"] = "channel_down";
    lircKeyMap["VOL+"] = "volume_up";
    lircKeyMap["VOL-"] = "volume_down";
    lircKeyMap["CH_UP"] = "channel_up";
    lircKeyMap["CH_DOWN"] = "channel_down";
    lircKeyMap["VOL_UP"] = "volume_up";
    lircKeyMap["VOL_DOWN"] = "volume_down";
    lircKeyMap["MUTE"] = "volume_mute";
    lircKeyMap["QUIT"] = "file_quit";
    lircKeyMap["POWER"] = "file_quit";
    //lircKeyMap["FULL_SCREEN"] = "next_view_mode";
    //lircKeyMap["FULLSCREEN"] = "next_view_mode";
    lircKeyMap["FULL_SCREEN"] = "toggle_fullscreen";
    lircKeyMap["FULLSCREEN"] = "toggle_fullscreen";
    lircKeyMap["TTX"] = "toggle_teletext";
    lircKeyMap["CC"] = "toggle_teletext";

    _lirc->setDefaultKeyMap(lircKeyMap);
    connect(_lirc, SIGNAL(command(const QString&, unsigned)),
            SLOT(lircCommand(const QString&, unsigned)));
    connect(_lirc, SIGNAL(event(const QString&, unsigned)),
            SLOT(lircCommand(const QString&, unsigned)));
#else
    kdWarning() << "MainWindow::setupInfraRed(): Lirc not available" << endl;
#endif
}

QPtrList<SettingsDialogPage>* MainWindow::getPages()
{
    QPtrList<SettingsDialogPage>* p = new QPtrList<SettingsDialogPage>;

    p->append(static_cast<SettingsDialogPage*>(new KdetvSettingsWidgetImpl(0L, this)));

    return p;
}

KPopupMenu *MainWindow::createMenu( const QString &name )
{
    KPopupMenu *pop = static_cast<KPopupMenu *>( factory()->container(name, this) );
    if ( !pop )
        return 0;

    pop->insertTitle( i18n("kdetv"), -1, 0 );
    return pop;
}

KPopupMenu *MainWindow::insertContextMenu( const QString &name )
{
    KPopupMenu *pop = createMenu( name );
    _screen->addContextMenu( pop );

    return pop;
}

void MainWindow::toggleStatus()
{
    if ( statusBar()->isVisible())
        statusBar()->hide();
    else
        statusBar()->show();
}

void MainWindow::toggleMenubar()
{
    if ( menuBar()->isVisible() )
        menuBar()->hide();
    else
        menuBar()->show();
}

void MainWindow::setShowTrayIcon( bool show )
{
    if ( show ) {
        if ( !_systray ) {
            kdDebug() << "Creating systray icon" << endl;
            _systray = new SysTray(this, "kdetv_systray",
                                   createMenu("system_tray_popup"), _actions);
            connect(_systray, SIGNAL(doubleClicked()), this, SLOT(setViewModeNormal()));
            connect(_systray, SIGNAL(leftClicked()), this, SLOT(bringToFront()));
        }
        kdDebug() << "Showing systray icon" << endl;
        _systray->show();
    } else {
        if ( _systray ) {
            _systray->hide();
        }
    }
}

void MainWindow::disableScreenSaver( bool disable )
{
    if ( disable ) {
        SaverControl::disableSaver();
        DpmsControl::disableDpms();
    }
    else {
        if ( _screenSaverWasEnabled )
            SaverControl::enableSaver();

        if ( _dpmsWasEnabled )
            DpmsControl::enableDpms();
    }
}

void MainWindow::checkScreenSaver()
{
    if ( !_disableSaver ) {
        // restore old mode
        disableScreenSaver( false );
        return;
    }

    switch( _screenSaverMode ) {
    case SaverRunning:
        disableScreenSaver( true );
        break;
    case SaverVisible:
        disableScreenSaver( !isHidden() );
        break;
    case SaverFullScreen:
        if ( _viewMode == ViewFullScreen ) {
            disableScreenSaver( true );
        } else {
            disableScreenSaver( false );
        }
        break;
    default:
        kdWarning() << "MainWindow: checkScreenSaver(): We should never get here!" << endl;
        break;
    }
}

void MainWindow::configureToolbars()
{
    saveWindowSettings();
    KEditToolbar dlg( guiFactory() );
    connect(&dlg, SIGNAL( newToolbarConfig() ),
    	    this, SLOT( restoreWindowSettings() ));
    dlg.exec();
}

void MainWindow::saveWindowSettings()
{
	kdDebug() << k_funcinfo << "Called" << endl;
    _cfg->setGroup( "Window Geometry" );

    _cfg->writeEntry( "View Mode", _viewMode );

	/* Make sure sidebar visibility is stored correctly
	 * even while saving settings in tv mode
	 */
	if (_viewMode == ViewTV)
		setSidebarVisibility(_sidebarVisible);

	_cfg->writeEntry("Window Position X", _pos.x());
	_cfg->writeEntry("Window Position Y", _pos.y());
    _cfg->writeEntry("TopLevel Pos", _topLevelPos);
    _cfg->writeEntry("TopLevel Size", _topLevelSize);
    _cfg->writeEntry("Disable Screensaver", _disableSaver);
    _cfg->writeEntry("Screensaver Mode", _screenSaverMode);
    _cfg->writeEntry("Stay on Top", _staysOnTop);
    _cfg->writeEntry("Sticky", _sticky);
    _cfg->writeEntry("No Sticky when fullscreen", _noStickyFull);
    _cfg->writeEntry("Cycle Normal View", _viewNormalEnabled);
    _cfg->writeEntry("Cycle FullScreen View", _viewFullEnabled);
    _cfg->writeEntry("Cycle TV View", _viewTVEnabled);
    _cfg->writeEntry("Cycle Desktop View", _viewDesktopEnabled);
    _cfg->writeEntry("Hide Taskbar Button Normal View", _hideTBNormal);
    _cfg->writeEntry("Hide Taskbar Button Fullscreen View", _hideTBFull);
    _cfg->writeEntry("Hide Taskbar Button TV View", _hideTBTV);

    writeDockConfig(_cfg, "MainWindow Docks");
	// only save toolbar menubar etc settings if we are in normal mode
	if (_viewMode == ViewNormal)
    saveMainWindowSettings(_cfg, "MainWindow");
}

void MainWindow::restoreWindowSettings()
{
	kdDebug() << k_funcinfo << "Called" << endl;
    applyMainWindowSettings(_cfg, "MainWindow");
    readDockConfig(_cfg, "MainWindow Docks");

    // these are just toggleActions (they do not track widget state)
    _actShowMenubar->setChecked(!menuBar()->isHidden());
    _actShowSidebar->setChecked(!_sideDock->isHidden());

    _cfg->setGroup( "Window Geometry" );
    int x = _cfg->readNumEntry( "Window Position X", 0 );
    int y = _cfg->readNumEntry( "Window Position Y", 0 );
    topLevelWidget()->move( x, y );

    QSize defS(400, 300);
    _topLevelPos  = _cfg->readPointEntry("TopLevel Pos");
    _topLevelSize = _cfg->readSizeEntry("TopLevel Size", &defS);

    _hideTBNormal       = _cfg->readBoolEntry( "Hide Taskbar Button Normal View", false );
    _hideTBFull         = _cfg->readBoolEntry( "Hide Taskbar Button Fullscreen View", false );
    _hideTBTV           = _cfg->readBoolEntry( "Hide Taskbar Button TV View", false );
    _staysOnTop         = _cfg->readBoolEntry("Stay on Top", false);
    _sticky             = _cfg->readBoolEntry("Sticky", false);
    _noStickyFull       = _cfg->readBoolEntry("No Sticky when fullscreen", true);
    _viewNormalEnabled  = _cfg->readBoolEntry("Cycle Normal View", true);
    _viewFullEnabled    = _cfg->readBoolEntry("Cycle FullScreen View", true);
    _viewTVEnabled      = _cfg->readBoolEntry("Cycle TV View", true);
    //    _viewDesktopEnabled = _cfg->readBoolEntry("Cycle Desktop View", false);
    _viewDesktopEnabled = false;
    _disableSaver       = _cfg->readBoolEntry("Disable Screensaver", true);
    _screenSaverMode    = _cfg->readNumEntry("Screensaver Mode", SaverVisible);

    addDynamicActions();
}

void MainWindow::restoreViewMode()
{
    // Save main window settings & size
    _size = size();
    _pos  = topLevelWidget()->pos();

    _cfg->setGroup( "Window Geometry" );
    setViewMode( _cfg->readNumEntry("View Mode", ViewNormal) );
}

void MainWindow::showTipOfTheDay()
{
    KTipDialog::showTip(this, QString::null, true);
}

void MainWindow::showWebSite()
{
    KURL url( i18n("http://www.kdetv.org/") );
    KRun::runURL( url, QString("text/html") );
}

void MainWindow::showFAQ()
{
    KURL url( i18n("http://docs.kde.org/development/en/extragear-multimedia/kdetv/faq.html") );
    KRun::runURL( url, QString("text/html") );
}

void MainWindow::lircCommand(const QString &cmd, unsigned /*repeat*/)
{
    if (cmd.length() == 1 && cmd[0] >= '0' && cmd[0] <= '9') {
        // handle numpad keys
        int key = cmd.toInt();
        emit numberKeyPressed(key);
    }

    KAction* act = action( cmd.latin1() );
    if (act)
        act->activate();
    else
        kdWarning() << "lirc: command '" << cmd << "' not recognized" << endl;
}

void MainWindow::keyBindings()
{
    KKeyDialog dlg;

    QPtrList<KXMLGUIClient> c = guiFactory()->clients();

    for(QPtrList<KXMLGUIClient>::const_iterator it = c.constBegin();
        it != c.constEnd();
        ++it) {
        dlg.insert((*it)->actionCollection());
    }

    dlg.configure();
}

void MainWindow::setSidebarVisibility(bool v)
{
    if (v) {
        makeDockVisible(_sideDock);
    } else {
        makeDockInvisible(_sideDock);
    }

    sideBarVisibilityChanged();
}

void MainWindow::sideBarVisibilityChanged()
{
    _actShowSidebar->setChecked(!_sideDock->isHidden());
}

void MainWindow::sbProgramName(const QString& name)
{
    statusBar()->changeItem(name, STATUSBAR_PROGRAM);
}

void MainWindow::statusMessage(const QString& name)
{
    statusBar()->changeItem(name, STATUSBAR_MAIN);
}

void MainWindow::shortMessage(const QString& name)
{
    statusBar()->changeItem(name, STATUSBAR_MAIN);
    QTimer::singleShot(2000, this, SLOT(clearStatusBar()));
}

void MainWindow::clearStatusBar()
{
    statusBar()->changeItem("", STATUSBAR_MAIN);
}

void MainWindow::slotSleepTimerTimeout()
{
    kdWarning() << "Kdetv: sleepTimer timeout reached - quitting client." << endl;
    QApplication::exit();
}

void MainWindow::sleepTimer()
{
    if (_sleeptimer->isActive())
        _sleeptimer->stop();

    kdDebug() << "sleepTimer() called.." << endl;

    if (_sleepdelay == 0) {
        // Change to 15 minutes.
        _sleepdelay = 900000;

    } else if (_sleepdelay == 900000) {
        // Change to 30 minutes.
        _sleepdelay = 1800000;

    } else if (_sleepdelay == 1800000) {
        // Change to 60 minutes.
        _sleepdelay = 3600000;

    } else if (_sleepdelay == 3600000) {
        // Change to 120 minutes.
        _sleepdelay = 7200000;

    } else {
        // Remove sleep-delay
        _sleepdelay = 0;
    }

    if (_sleepdelay)
        _sleeptimer->start(_sleepdelay, true);  // start the count-down timer

    // Display to the screen, how many minutes there are to the TV turns
    // off.
    emit sleepTimerDelay(QString::number(_sleepdelay / 1000 / 60));
}

void MainWindow::updateTaskbarButton()
{
    if( (_hideTBNormal && (_viewMode == ViewNormal))     ||
        (_hideTBTV     && (_viewMode == ViewTV))         ||
        (_hideTBFull   && (_viewMode == ViewFullScreen))    ) {
        setShowTrayIcon( true );
        KWin::setState(winId(), NET::SkipTaskbar);
    } else {
        setShowTrayIcon( false );
        KWin::clearState(winId(), NET::SkipTaskbar);
    }
}

void MainWindow::updateWindowAttr()
{
    if (KDE::versionMajor() == 3 && KDE::versionMinor() <= 1) {
        // reapply staysOnTop flag because it gets lost during the view change
        // we only do this for kde version < 3.2 because this seems to be fixed there
        if(_staysOnTop) {
            KWin::setState(winId(), NET::StaysOnTop);
            setWFlags(WStyle_StaysOnTop);
        }

        KWin::setOnAllDesktops(winId(), _sticky &&
                               !(_noStickyFull && (_viewMode == ViewFullScreen)));
    }
}

void MainWindow::nextViewMode()
{
    kdDebug() << "MainWindow::nextViewMode() Current is " << _viewMode << endl;

    // Ensure at least one is enabled
    if (!_viewNormalEnabled &&
        !_viewFullEnabled &&
        !_viewTVEnabled &&
        !_viewDesktopEnabled) {
        _viewNormalEnabled = true;
    }

    int viewMode = _viewMode;
    bool found = false;

    // Note: We don't want to switch to the ViewNone mode
    do {
        viewMode = (viewMode+1) % (ViewMaxIterable+1);

        switch (viewMode) {
        case ViewNormal:
            if (_viewNormalEnabled) found = true;
            break;
        case ViewFullScreen:
            if (_viewFullEnabled) found = true;
            break;
        case ViewTV:
            if (_viewTVEnabled) found = true;
            break;
        case ViewVideoDesktop:
            if (_viewDesktopEnabled) found = true;
            break;
        default:
            viewMode = ViewNormal;
            found = true;
            break;
        }
    } while (!found);

    setViewMode( viewMode );
}

void MainWindow::toggleFullScreen()
{
    if ( _viewMode == ViewFullScreen ) {
        setViewMode( (_oldViewMode <= ViewMaxIterable) ? _oldViewMode : ViewNormal );
    } else {
        _oldViewMode = _viewMode;
        setViewMode( ViewFullScreen );
    }
}

void MainWindow::setViewMode( int mode )
{
    saveWindowSettings();
    _changingViewMode = true;
    doSetViewMode( _viewMode, false ); // clean up last view mode
    doSetViewMode( mode,      true  ); // init new view mode
    _changingViewMode = false;
    emit viewModeChanged( _viewMode );

    // give the TV widget focus
    _screen->view()->setFocus();

    updateTaskbarButton();
}

void MainWindow::doSetViewMode( int mode, bool enable )
{
    switch( mode ) {
    case ViewNone:
        setShowNone( enable );
        break;
    case ViewNormal:
        setShowNormal( enable );
        break;
    case ViewTV:
        setShowTV( enable );
        break;
    case ViewFullScreen:
        setShowFullScreen( enable );
        break;
    case ViewVideoDesktop:
        setShowVideoDesktop( enable );
        break;
    default:
        kdWarning() << "MainWindow::setViewMode(): Unknown mode " << mode
                    << ", defaulting to ViewNormal" << endl;
        setShowNormal( enable );
        break;
    }
}

void MainWindow::setShowNone( bool enable )
{
    kdDebug() << "MainWindow::setShowNone(): " << enable << endl;
    if (enable) {
        _screen->driver()->stop();
        hide();
        _viewMode = ViewNone;
    } else {
        show();
        _screen->driver()->start();
    }
}

void MainWindow::setShowNormal( bool enable )
{
    kdDebug() << "MainWindow::setShowNormal(): " << enable << endl;
    _viewMode = ViewNormal;
    _actShowNorm->setChecked( true );
}

void MainWindow::setShowTV( bool enable )
{
    kdDebug() << "MainWindow::setShowTV(): " << enable << endl;
    if (enable) {
        hideGUIElements();
        topLevelWidget()->move( _topLevelPos );
        resize( _topLevelSize );
        QTimer::singleShot(0, this, SLOT(bringToFront()));
        _viewMode = ViewTV;
        _actShowTV->setChecked( true );
    } else {
        restoreGUIElements();
        topLevelWidget()->move( _pos );
        resize( _size );
    }
}

void MainWindow::setShowFullScreen( bool enable )
{
    kdDebug() << "MainWindow::setShowFullScreen(): " << enable << endl;
    if (enable) {
        // icons are lost at showFullScreen()
        _miniIcon = KWin::icon( winId(), 16, 16, true );
        _icon     = KWin::icon( winId(), 34, 34, false );
        if ( _icon.isNull() ) {
            _icon = KWin::icon( winId(), 32, 32, true );
        }
        _screen->driver()->sourceManager()->viewModeHint(SourceManager::Fullscreen);
        hideGUIElements();
        if(_haveKWin) {
            KWin::setState(winId(), NET::FullScreen);
        } else {
            showFullScreen();
        }
        _bgcol = paletteBackgroundColor();
        setPaletteBackgroundColor( QColor( 0, 0, 0 ) );
        QTimer::singleShot(1, this, SLOT(bringToFront()));
        _wasSticky = KWin::windowInfo(winId()).onAllDesktops();
        if(_noStickyFull) {
            KWin::setOnAllDesktops(winId(), false);
        }
        _viewMode = ViewFullScreen;
        _actShowFull->setChecked( true );
    } else {
        setPaletteBackgroundColor( _bgcol );
        _screen->driver()->sourceManager()->viewModeHint(SourceManager::Windowed);
        restoreGUIElements();
        if(_haveKWin) {
            KWin::clearState(winId(), NET::FullScreen);
        } else {
            showNormal();
        }
        KWin::setOnAllDesktops(winId(), _wasSticky);
        KWin::setIcons( winId(), _icon, _miniIcon );
    }
}

void MainWindow::setShowVideoDesktop( bool enable )
{
    kdDebug() << "MainWindow::setShowVideoDesktop(): " << enable << endl;
    if (enable) {
        _screen->driver()->sourceManager()->setVideoDesktop( true );
        setShowTrayIcon( true );
        hide();
        _viewMode = ViewVideoDesktop;
        //        _actShowDesk->setChecked( true );
    } else {
        show();
        setShowTrayIcon( false );
        _screen->driver()->sourceManager()->setVideoDesktop(false);
    }
}

void MainWindow::bringToFront()
{
    KWin::activateWindow(winId());
}

void MainWindow::hideGUIElements()
{
    _menubarVisible = !menuBar()->isHidden();
    menuBar()->hide();
    _actShowMenubar->setEnabled(false);

    _statusbarVisible = !statusBar()->isHidden();
    statusBar()->hide();

    _sidebarVisible = !_sideDock->isHidden();
    setSidebarVisibility(false);
    _actShowSidebar->setEnabled(false);

    _toolbarVisibilityList.clear();
    KToolBar *toolbar = 0;
    QPtrListIterator<KToolBar> it( toolBarIterator() );
    while ( ( toolbar = it.current() ) != 0 ) {
        ++it;
        _toolbarVisibilityList.append(new toolBarVisibilityPair(toolbar, !toolbar->isHidden()));
        toolbar->hide();
    }

    _savedGuiStateValid = true;
}

void MainWindow::restoreGUIElements()
{
    if (!_savedGuiStateValid) return;

    if (_menubarVisible) {
        menuBar()->show();
        _actShowMenubar->setChecked(true);
    }
    _actShowMenubar->setEnabled(true);

    if (_statusbarVisible) {
        statusBar()->show();
    }

    setSidebarVisibility(_sidebarVisible);
    _actShowSidebar->setEnabled(true);

    for(toolBarVisibilityPair *it = _toolbarVisibilityList.first();
        it;
        it = _toolbarVisibilityList.next()) {
        if (it->second) {
            it->first->show();
        }
    }
}

void MainWindow::moveEvent(QMoveEvent*)
{
    if (_changingViewMode) return;

    if (_viewMode == ViewTV) {
        _topLevelPos = topLevelWidget()->pos();
    } else if (_viewMode == ViewNormal) {
        _pos = topLevelWidget()->pos();
    }
}

void MainWindow::resizeEvent( QResizeEvent* e )
{
    if (_changingViewMode) return;

    if (_viewMode == ViewTV) {
        _topLevelSize = e->size();
    } else if (_viewMode == ViewNormal) {
        _size = e->size();
    }
}

void MainWindow::hideEvent( QEvent* )
{
    emit visibilityChanged(false);
}

void MainWindow::showEvent( QEvent* )
{
    emit visibilityChanged(true);
}
