/***************************************************************************
 *   Copyright (C) 2003-2005 by liuspider                                  *
 *   liuspider@users.sourceforge.net                                       *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/
#define USE_SCIM_KDE_SETTINGS
#include "src/skimpluginmanager.h"
#include "mainwindow.h"

#include <qlayout.h>
#include <qevent.h>
#include <qtoolbutton.h>
#include <qlabel.h>

#include <kpopupmenu.h>
#include <ktoolbar.h>
#include <kiconloader.h>
#include <kxmlguifactory.h>
#include <kapplication.h>
#include <kdebug.h>

#include "utils/scimtoolbar.h"
#include "utils/scimmovehandle.h"
#include "src/skimglobalactions.h"
#include "utils/scimxmlguibuilder.cpp"
#include "utils/scimactions.h"
#include "src/extra_utils.h"

#include <dcopref.h>
#include <dcopclient.h>

#include <kdeversion.h>
#define KDEGT340 (KDE::version() >= KDE_MAKE_VERSION(3,4,0))

#include <qxembed.h>

MainWindow::MainWindow( QWidget* parent, const char* name, WFlags fl )
    : ScimDragableFrame( parent, parent, name, fl ),
    ScimXMLGUIClient(SkimPluginManager::self()->getActionCollection()), DCOPObject("Skim_MainWindow"),
    AutoHideTimeoutTimer(0), ShowHandleTimer(0), ShowExtHandleTimer(0),Mode(PanelEmbedded), 
    embedInitialized(false), contentIsVisible( false ), PanelTurnedOn( false ),
    updatePropertiesNeeded(false), updateGUIProperties(false), updateFrontendProperties(false),
    applet_direction(Qt::Horizontal), shouldChangeDirection(false), logo(0) {

    QXEmbed::initialize ();

//     setWFlags(Qt::WStyle_Customize | Qt::WX11BypassWM | Qt::WStyle_StaysOnTop);
    setKeepVisible( true );
    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    allModules = SkimPluginManager::self();

    allModules->registerSpecialProperyObject(this);

    InputServer = allModules->getInputServer();
    ScimXMLGUIBuilder* guiBuilder = new ScimXMLGUIBuilder(this);
    guiFactory = new KXMLGUIFactory(guiBuilder, this);

    setCaption(i18n("Main Toolbar"));

    serverAction =
      dynamic_cast<ScimAction *>(allModules->getActionCollection()->action( "change_server" ));

    MainWindowLayout = new QBoxLayout( this, QBoxLayout::LeftToRight, -1, 0, "MainWindowLayout" );
    MainWindowLayout->setAlignment(Qt::AlignCenter);
    MainWindowLayout->setResizeMode(QLayout::FreeResize);
    moveHandle = new ScimMoveHandle( this, this );
    moveHandle->setKeepVisible( false );
    MainWindowLayout->addWidget( moveHandle );

    //FIXME:qpopupmenu will steal focus from current editing widget, however 
    //kpopupmenu won't. this should be a bug in Qt
    contextMenu = new KPopupMenu(this, "MainToolBar_RightClickMenu");

    createToolbar();

    defaultActionCollection = allModules->getActionCollection();

    toggleDockingAction =
            static_cast<KToggleAction*>(defaultActionCollection->action( "toggledocking_mainwindow" ));
    connect( moveHandle, SIGNAL( doubleClicked() ), toggleDockingAction, SLOT( activate() ) );

    clearWState( WState_Polished );

    if(Mode == StandAlone)
        move( ScimKdeSettings::mainWindow_Position());

    changeSetting();

    #if 0 && ENABLE_DEBUG
    KAction * reloadaction;
    //we should remove the old one first if exist
    if(reloadaction = defaultActionCollection->action( "reload_wm" ))
        delete reloadaction;

    reloadaction = new KAction( KGuiItem( i18n( "Reload" ), "reload" ),
                "", this, SLOT(requestReloadSelf()), defaultActionCollection, "reload_wm");

    reloadaction->plug(toolbar);
    #endif

    connect(defaultActionCollection, SIGNAL(propertiesRegistered(bool)), SLOT(updateProperties (bool)));
    connect(defaultActionCollection, SIGNAL(propertiesRemoved(bool)), SLOT(updateProperties (bool)));
    connect(defaultActionCollection, SIGNAL(propertyChanged(bool)), SLOT(updateProperties (bool)));
    connect(InputServer, SIGNAL( turnOnPanelReq() ), this, SLOT( slotTurnOn() ));
    connect(InputServer, SIGNAL( turnOffPanelReq() ), this, SLOT( slotTurnOff() ));

    #if ENABLE_DEBUG
    show();
    #endif

    connect(allModules->getActionCollection(), SIGNAL(standaloneHelperActionsChanged()),
        this, SLOT(initContextMenu()));

    connect( InputServer, SIGNAL( transaction_start() ), this, SLOT( disableUpdates() ) );
    connect( InputServer, SIGNAL( transaction_end() ), this, SLOT( enableUpdates() ) );

    initContextMenu();
}

MainWindow::~MainWindow() {
    if(Mode == StandAlone)
    {
        ScimKdeSettings::setMainWindow_Position(pos());
        ScimKdeSettings::setMainWindow_Direction( (int)MainWindowLayout->direction() );
    }

    ScimKdeSettings::writeConfig();
    contextMenu->clear();
}

void MainWindow::disableUpdates()
{
    setUpdatesEnabled( false );
    toolbar->setUpdatesEnabled( false );
}

void MainWindow::enableUpdates()
{
    setUpdatesEnabled( true );
    toolbar->setUpdatesEnabled( true );

    if(updateGUIProperties)
        updateProperties(false);

    if(updateFrontendProperties)
        updateProperties(true);

    //FIXME: see the FIXME in MainWindow::show()
    if(isVisible())
        QTimer::singleShot( 100, this, SLOT( adjustSize() ) );
}

void MainWindow::initContextMenu() {
    contextMenu->clear();
    //load helper actions (copied from kdetraystatus.cpp, with slight modification)
    //TODO: add a new function in defaultActionCollection to handle this?
    KActionCollection * helperActioncol = defaultActionCollection->helperActionCollection();
    if ( helperActioncol->count() ) {
        for(size_t i=0; i<helperActioncol->count();i++) {
            helperActioncol->action(i)->plug(contextMenu);
        }
        contextMenu->insertSeparator();
    }

    toggleDockingAction->plug(contextMenu);

    KAction* configureaction = defaultActionCollection->action( "configure" );
    if(configureaction)
        configureaction->plug(contextMenu);

    KAction* helpAction = defaultActionCollection->action( "help" );
    if(helpAction)
        helpAction->plug(contextMenu);
}

void MainWindow::createToolbar () {
      toolbar = new ScimToolBar( this, "MainToolBar" );
      toolbar->setIconSize(fontMetrics().height() + 2);
      toolbar->setEnableContextMenu(true);
      toolbar->setFrameStyle( QFrame::NoFrame );
      toolbar->setBackgroundOrigin(QWidget::AncestorOrigin);
      toolbar->setBackgroundMode(QWidget::X11ParentRelative);
      toolbar->boxLayout()->setAlignment(Qt::AlignCenter);
      MainWindowLayout->addWidget( toolbar );
}

void MainWindow::updateProperties (bool isFrontEndProperties) {
    if(isUpdatesEnabled())
    {
        if(isFrontEndProperties)
            updateFrontendProperties = false;
        else
            updateGUIProperties = false;

        KActionPtrList exta = isFrontEndProperties ?
                defaultActionCollection->frontendPropertyActions() : defaultActionCollection->guiPropertyActions();
        actionListName = isFrontEndProperties ? "Frontend Properties" : "GUI Properties";

        insertedActions.clear();
        for(uint i=0; i<exta.size(); i++) {
            bool visible = true;
            if(ScimAction * action = dynamic_cast<ScimAction *>(exta[i])){
                if(!action->visible() || !action->currentShown())
                    visible = false;
            }
            if(visible)
                insertedActions.append(exta[i]);
        }

        if(insertedActions.count())
            updatePropertiesNeeded = true;

        unplugActionList(actionListName.latin1());

        if(updatePropertiesNeeded && contentIsVisible)
            show();
    }
    else
    {
        if(isFrontEndProperties)
            updateFrontendProperties = true;
        else
            updateGUIProperties = true;
    }
}

void MainWindow::changeDirection(QBoxLayout::Direction d)
{
    shouldChangeDirection = false;

    MainWindowLayout->setDirection( d );
    moveHandle->setDirection( d );
    toolbar->boxLayout()->setDirection( d );
}

void MainWindow::requestReloadSelf () {
    setUpdatesEnabled( FALSE );
    guiFactory->removeClient(this);
    if(serverAction)
    serverAction->setOption(
        ScimKdeSettings::show_Factory_Text()?
        scim_kde::ToolBarIconUseText : scim_kde::ToolBarPreferIcon);
    setXMLFile("mainwindowui.rc");
    setXMLGUIBuildDocument( QDomDocument() );
    guiFactory->addClient(this);
    insertedActions.clear();
    updateProperties (true);
    updateProperties (false);
    setUpdatesEnabled( TRUE );
    adjustSize();
}

void MainWindow::adjustSize() {
    //only do the real adjustSize when we are in StandAlone mode
    if( Mode == StandAlone && isUpdatesEnabled())
    {
        if(!isMouseButtonPressed() && shouldChangeDirection)
            changeDirection(changeToDirection);
        ScimDragableFrame::adjustSize();
        if(autoSnap && !isMouseButtonPressed()) {
        //     std::cout << "Successfully exited.\n" << screen.x() << " " <<screen.height()  << " " << x() << "\n";
            if(screen.width() - x() - width() < x())
                move(screen.width() - width(), y());
            else
                move(0, y());
        }
    }
//     else
//         QFrame::adjustSize();
}

void MainWindow::contextMenuEvent ( QContextMenuEvent * e) {
    contextMenu->popup(e->globalPos());
}

void MainWindow::slotTurnOn()
{
    show();
    PanelTurnedOn = true;
}

void MainWindow::show() {
    if (updatePropertiesNeeded) {
        plugActionList(actionListName.latin1(), insertedActions);
        updatePropertiesNeeded=false;
        //FIXME: ugly hack: at this point, the toolbar has not been changed,
        // so if call adjustSize here will take no effect
        // This is a work around although may be not feasible in some old/slow
        // or heavily loaded machines. IMPROVEMENT for this work around: implement
        // a check in adjustSize, if 100 ms is not long enough, just start
        // another singleShot
        if(isUpdatesEnabled())
            QTimer::singleShot( 100, this, SLOT( adjustSize() ) );
    }

    if(isUpdatesEnabled())
    {
        if(Mode == StandAlone && AutoHideTimeoutTimer)
        {
            AutoHideTimeoutTimer->stop();
            toolbar->show();
            moveHandle->show();
            logo->hide();
        }

        QFrame::show();

        //adjustSize immediately is not useful here, so we schedule
        //an adjustSize after all the events in the queue are processed
        QTimer::singleShot( 0, this, SLOT( adjustSize() ) );
    }
    contentIsVisible = true;
}

void MainWindow::standaloneModeHide()
{
    if(Mode == StandAlone)
        if(!AlwaysShow)
        {
            hide();
            contentIsVisible = false;
        }
        else
            hideToolbar();
}

void MainWindow::slotTurnOff() {
    standaloneModeHide();
    PanelTurnedOn = false;
}

void MainWindow::hideToolbar()
{
    if( contentIsVisible )
        if( AutoHideTimeoutTimer && !AutoHideTimeoutTimer->isActive())
            AutoHideTimeoutTimer->start( AutoHideTimeout, true );

    if( AutoHideTimeoutTimer && !AutoHideTimeoutTimer->isActive())
    {
        toolbar->hide();
        moveHandle->hide();
        logo->show();
        adjustSize();
    }

    contentIsVisible = false;
}

void MainWindow::changeSetting()
{
    toggleDockingAction->setChecked(ScimKdeSettings::dockingToPanelApplet());
    toggleDocking(true); //retrieve the Mode first

    if(Mode == StandAlone)
    {
        //re-initialize embed if next time toggle to that docking mode
        embedInitialized = false;

        setName("mainWindow");
        reparent(0, Qt::WStyle_Customize | Qt::WX11BypassWM | Qt::WStyle_StaysOnTop,
                 ScimKdeSettings::mainWindow_Position(),false);

        moveHandle->show();
        setFrameStyle( QFrame::PopupPanel | QFrame::Raised );
        //if margin is 0, the frame can not be drawn correctly, frameWidth() is
        // sometimes too big (>1 and the main toolbar is not so decent), so
        // just fix it to 1
        MainWindowLayout->setMargin(1);
        setBackgroundOrigin(QWidget::WindowOrigin);
    }
    else
    {
        //change name so that it won't be listed in the composite management page
        setName("mainWindow_embedded");
        setWFlags(Qt::WStyle_Customize);

        moveHandle->hide();
        setFrameStyle( QFrame::NoFrame );
        MainWindowLayout->setMargin(0);
        setBackgroundOrigin(QWidget::AncestorOrigin);
        setBackgroundMode(QWidget::X11ParentRelative);
    }

    AutoHideTimeout = ScimKdeSettings::hide_Timeout() * 1000;
    AlwaysShow = ScimKdeSettings::always_Show();
    autoSnap = ScimKdeSettings::auto_Snap();
    requestReloadSelf();

    if( AlwaysShow && AutoHideTimeout > 0 && Mode == StandAlone) {
        if(!AutoHideTimeoutTimer)
        {
            AutoHideTimeoutTimer = new QTimer(this);
            connect( AutoHideTimeoutTimer, SIGNAL( timeout() ), this, SLOT( hideToolbar() ) );
        }
    } else {
        if(AutoHideTimeoutTimer)
            AutoHideTimeoutTimer->deleteLater();
        AutoHideTimeoutTimer = 0;
        toolbar->show();
        if(Mode == StandAlone)
            moveHandle->show();
    }

    alwaysShowHandle = ScimKdeSettings::alwaysShowHandle();

    alwaysShowExtensionHandle = ScimKdeSettings::alwaysShowExtensionHandle();

    if(Mode == PanelEmbedded)
    {
        //init alwaysShowHandle option support timer
        if(alwaysShowHandle)
        {
            if(ShowHandleTimer)
                ShowHandleTimer->deleteLater();
            ShowHandleTimer = 0;
        }
        else
        {
            if(!ShowHandleTimer)
            {
                ShowHandleTimer = new QTimer(this);
                connect(ShowHandleTimer, SIGNAL(timeout()), this, SLOT(showHandleRequest()));
            }
        }

        //init alwaysShowExtensionHandle option support timer
        if(alwaysShowExtensionHandle)
        {
            if(ShowExtHandleTimer)
                ShowExtHandleTimer->deleteLater();
            ShowExtHandleTimer = 0;
            if(embeddedAreaSize.isValid())  //only reset toolbar size if embeddedAreaSize is set before
                resetToolbarSize(embeddedAreaSize);
        }
        else
        {
            if(!ShowExtHandleTimer)
            {
                ShowExtHandleTimer = new QTimer(this);
                connect(ShowExtHandleTimer, SIGNAL(timeout()), this, SLOT(showExtHandleRequest()));
            }
        }

        initEmbedPanel();
    }

    if(Mode == StandAlone)
    {
        if(AlwaysShow)
        {
            if(AutoHideTimeoutTimer && !logo)
            {
                logo = new QLabel(this);
                logo->setPixmap(KGlobal::iconLoader()->loadIcon("skim", KIcon::Toolbar));
                MainWindowLayout->addWidget(logo);
                logo->hide();
            }
            QTimer::singleShot(0, this, SLOT(show()));//FIXME
        }

        if((!AlwaysShow || !AutoHideTimeoutTimer) && logo)
        {
            logo->deleteLater();
            logo = 0;
        }

        UPDATE_WINDOW_OPACITY(this);
    }

    if(Mode == StandAlone || (!ScimKdeSettings::force_LeftToRight_In_Kicker() && Mode == PanelEmbedded))
        changeDirection((QBoxLayout::Direction)(ScimKdeSettings::mainWindow_Direction()));
    else
        changeDirection(QBoxLayout::LeftToRight);

    if(Mode == StandAlone || (!alwaysShowExtensionHandle && Mode == PanelEmbedded))
    {
        resetToolbarSize();
    }
}

void MainWindow::reInit()
{
    changeSetting();
}

void MainWindow::initEmbedPanel()
{
    static int kicker_start_timeout_counter = 0, load_skimapplet_timeout_counter = 0;

    if(kapp->dcopClient()->isApplicationRegistered("kicker"))
    {
        kicker_start_timeout_counter = 0;
        if(kapp->dcopClient()->remoteObjects("kicker").contains("SkimApplet"))
        {
            load_skimapplet_timeout_counter = 0;
            DCOPRef m_kickerSkimApplet("kicker","SkimApplet");

            if(!embedInitialized)
            {
                embedInitialized = true;

                disconnectDCOPSignal("kicker", "SkimApplet",
                                     "preferedSizeChanged(QSize, int)", "changePreferedSize(QSize, int)");
                disconnectDCOPSignal("kicker", "SkimApplet",
                                     "appletDestroyed(bool)", "appletDestroyed(bool)");
                disconnectDCOPSignal("kicker", "SkimApplet",
                                     "doubleCliked()", "toggleDocking()");

                connectDCOPSignal("kicker", "SkimApplet",
                                  "preferedSizeChanged(QSize, int)", "changePreferedSize(QSize, int)", false);
                connectDCOPSignal("kicker", "SkimApplet",
                                  "appletDestroyed(bool)", "appletDestroyed(bool)", false);
                connectDCOPSignal("kicker", "SkimApplet",
                                  "doubleCliked()", "toggleDocking()", false);

                m_kickerSkimApplet.call("embedWindow(Q_UINT32)", (Q_UINT32)winId());
            }

            m_kickerSkimApplet.call("setAutoHideHandle(bool)", !alwaysShowHandle);
            show();
        }
        else
        {
            if(load_skimapplet_timeout_counter < 1)
            {
                DCOPRef m_kickerPanel("kicker","Panel");
                m_kickerPanel.call("addApplet(QString)", QString("skimapplet.desktop"));

                // if this is KDE 3.3.x, then we have to restart kicker after we add
                // the new applet, otherwise, the new added applet will be a separate
                // dcop object, rather than an object under kicker.
                if(!KDEGT340)
                    m_kickerPanel.call("restart()");
                load_skimapplet_timeout_counter++;
                QTimer::singleShot(500, this, SLOT(initEmbedPanel()));
            }
            else if(load_skimapplet_timeout_counter<20)
            {
                QTimer::singleShot(500, this, SLOT(initEmbedPanel()));
                load_skimapplet_timeout_counter++;
            }
            else
            {
                //TODO: tell user: timeout when waiting for kicker to load SkimApplet
                kdDebug() << k_lineinfo << " timeout when waiting for kicker to load SkimApplet\n";
                toggleDocking();
            }
        }
    }
    else    //waiting for kicker to start
    {
        if(kicker_start_timeout_counter < 1)
        {
            kapp->dcopClient()->setNotifications(true);
            connect(kapp->dcopClient(), SIGNAL(applicationRegistered (const QCString &)),
                    SLOT(slotApplicationRegistered (const QCString &)));

            //this timer will make sure if kicker is not started within 50s, the initEmbedPanel
            // will be called. ATTENTION here: if no timeout occur, this will init another call
            // to initEmbedPanel(). However as we have embedInitialized variable, there should
            // be no problems.
            QTimer::singleShot(50000, this, SLOT(initEmbedPanel()));
            kicker_start_timeout_counter++;
        }
        else
        {
            //TODO: tell user: timeout when waiting for kicker to start
            kdDebug() << k_lineinfo << " timeout when waiting for kicker to start\n";
            slotApplicationRegistered("kicker");    //ATTENTION: call this to disconnect the applicationRegistered signal
            toggleDocking();
        }
    }
}

void MainWindow::slotApplicationRegistered (const QCString & appid)
{
    if(appid == "kicker")
    {
        kapp->dcopClient()->setNotifications(false);
        disconnect(kapp->dcopClient(), SIGNAL(applicationRegistered (const QCString &)),
                   this, SLOT(slotApplicationRegistered (const QCString &)));
        if(kapp->dcopClient()->isApplicationRegistered("kicker"))
            QTimer::singleShot(1000, this, SLOT(initEmbedPanel())); //add one second to wait for kicker to load skimapplet
    }
}

void MainWindow::appletDestroyed(bool appClosing)
{
    if(Mode == PanelEmbedded)
    {
        embedInitialized = false;
        reparent(0, ScimKdeSettings::mainWindow_Position(), false);
        hide();
        if(appClosing)  
        {
            //TODO: kicker is shutting down, may be caused by logout of KDE, crash of kicker or killed by users
            toggleDocking();
            //FIXME: ugly hack: why the toolbar is so small after the previous call? Any why call adjustSize here
            //won't do any good either: so we have to use a timer. This may be a potential bug
            QTimer::singleShot(1000, this, SLOT(adjustSize()));
        }
        else
        {   //TODO:applet is closed by user, ask what he want to do
            QTimer::singleShot(1000, this, SLOT(initEmbedPanel())); //reload
        }
    }
//     kdDebug() << k_lineinfo << " with para appClosing = " << appClosing << "\n";
}

void MainWindow::changePreferedSize(QSize newsize, int d)
{
    Q_UNUSED( d );

    if( Mode == PanelEmbedded )
    {
        embeddedAreaSize = newsize;

        //only Horizontal toolbar can have the extension handle correctly
        //displayed, so currently just fix applet direction to Horizontal
        if(ScimKdeSettings::force_LeftToRight_In_Kicker())
        {
            applet_direction = Qt::Horizontal; //(Qt::Orientation)d;
        }

        settleToolbar();
    }
}

void MainWindow::settleToolbar()
{
    if(!isVisible())
    {
        QTimer::singleShot(200, this, SLOT(settleToolbar()));
        return;
    }

    QSize as = embeddedAreaSize;
    if(!alwaysShowExtensionHandle)
        if(applet_direction == Qt::Horizontal)
            as.setWidth(2000);

    resetToolbarSize(as);
}

#define HandleTimeout 200
#define ExtHandleTimeout 300

void MainWindow::startDockingTimer()
{
    if(!alwaysShowHandle && ShowHandleTimer)
    {
        //FIXME: do we need to make this time customizable
        ShowHandleTimer->start(HandleTimeout, true);
    }
    else if(!alwaysShowExtensionHandle && ShowExtHandleTimer)
        ShowExtHandleTimer->start(ExtHandleTimeout, true);
}

void MainWindow::enterEvent ( QEvent * e )
{
    if(!isMouseButtonPressed())
    {
        if(Mode == PanelEmbedded)
        {
            setMouseTracking(true); //so we can receive mouseMoveEvent
            startDockingTimer();
        }
        else  //Mode == StandAlone
        {
            if(AlwaysShow && logo)
                show();
        }
    }
    ScimDragableFrame::enterEvent ( e );
}

void MainWindow::mouseMoveEvent ( QMouseEvent * e )
{
    if(Mode == PanelEmbedded)
        if(!isMouseButtonPressed() && hasMouseTracking())
        {
            startDockingTimer();
        }

    ScimDragableFrame::mouseMoveEvent(e);

    if(Mode == StandAlone)
    {
        if(ScimKdeSettings::auto_Adjust_Direction())
        {
            QRect visiblerect = frameGeometry();
            if( !shouldChangeDirection && !screenContainsRect(visiblerect) )
            {
                //some part of this mainwindow is invisible: we check if less than half
                // of the mainwindow is visible, then try to change the direction
                QRect intersect = screen & frameGeometry();
                QRect frect = frameGeometry();
                double visible_radio = (double)(intersect.width() * intersect.height()) / (frect.width() * frect.height());
                if(!intersect.isEmpty() && visible_radio < 0.48)
                {
                    shouldChangeDirection = true;
                    switch(MainWindowLayout->direction())
                    {
                        case QBoxLayout::LeftToRight:
                            changeToDirection = QBoxLayout::TopToBottom;
                            break;
                        case QBoxLayout::TopToBottom:
                            changeToDirection = QBoxLayout::RightToLeft;
                            break;
                        case QBoxLayout::RightToLeft:
                            changeToDirection = QBoxLayout::BottomToTop;
                            break;
                        case QBoxLayout::BottomToTop:
                            changeToDirection = QBoxLayout::LeftToRight;
                            break;
                    }
                }
            }
        }
    }
}

void MainWindow::showHandleRequest()
{
    if( Mode == PanelEmbedded )
    {
        if(!alwaysShowHandle)
        {
            DCOPRef m_kickerSkimApplet("kicker","SkimApplet");
            m_kickerSkimApplet.call("slotEnterEvent()");

            setMouseTracking(false);
        }

        //only after the handle is shown, we can start the timer of ShowExtHandleTimer
        //otherwise, the ext handle can not be shown reliably. Here ExtHandleTimeout
        //must be long enough for the m_kickerSkimApplet.call to take effective
        if(!alwaysShowExtensionHandle && ShowExtHandleTimer)
            ShowExtHandleTimer->start(ExtHandleTimeout, true);
    }
}

void MainWindow::showExtHandleRequest()
{
    if(!alwaysShowExtensionHandle)
        resetToolbarSize(embeddedAreaSize);
}

void MainWindow::resetToolbarSize (QSize newsize)
{
    bool isHorizontal = false;
    if( (applet_direction == Qt::Horizontal && Mode == PanelEmbedded) ||
         Mode == StandAlone && (MainWindowLayout->direction() == QBoxLayout::LeftToRight ||
         MainWindowLayout->direction() == QBoxLayout::RightToLeft))
        isHorizontal = true;

    if(!newsize.isValid())
        if(isHorizontal)
            newsize = QSize(2000, 10);
        else
            newsize = QSize(10, 2000);

    if(isHorizontal)
    {
        toolbar->setMaximumWidth(newsize.width() - 2);
        toolbar->setMinimumHeight(newsize.height() - 2);
    }
    else
    {
        toolbar->setMinimumWidth(newsize.width() - 2);
        toolbar->setMaximumHeight(newsize.height() - 2);
    }
}

void MainWindow::leaveEvent ( QEvent * e )
{
    setMouseTracking(false);    //we must disable the mousetracking as soon as possible here
    if(!isMouseButtonPressed())
    {
        if(Mode == PanelEmbedded && (!alwaysShowHandle || !alwaysShowExtensionHandle))
        {
            //we have to use a timer, otherwise when the user move the mouse
            //to a popupmenu of mainwindow, if the leaveEvent is processed
            //immediately, the popupmenu will be hiden before the user have
            //a chance to go into it
            QTimer::singleShot(100, this, SLOT(slotLeaveEvent()));
        }
        else if(Mode == StandAlone && AlwaysShow && AutoHideTimeoutTimer && !PanelTurnedOn)
        {
            hideToolbar();
        }
    }

    ScimDragableFrame::enterEvent ( e );
}

#include <qobjectlist.h>
void MainWindow::slotLeaveEvent()
{
    //FIXME: ugly hack to make sure the user can move to a popup menu
    //of this widget, when in docking mode and auto hiding of the handle 
    //and ext handle
    QPopupMenu * mouseContainer = 0;
    QObjectList *l = queryList( "QPopupMenu" );
    QObjectListIt it( *l ); // iterate over the buttons
    QObject *obj;

    while ( (obj = it.current()) != 0 ) {
        ++it;
        if(((QPopupMenu*)obj)->hasMouse())
        {
            mouseContainer = (QPopupMenu*)obj;
            break;
        }
    }
    delete l;
    
    if(!mouseContainer)
    {
        hideHandleRequest();
    } else
    {
        mouseContainer->disconnect(this);
        connect(mouseContainer, SIGNAL(aboutToHide()), this, SLOT(hideHandleRequest()));
    }
}

void MainWindow::hideHandleRequest()
{
    if(ShowHandleTimer)
    {
        ShowHandleTimer->stop();
        if(!alwaysShowHandle)
        {
            DCOPRef m_kickerSkimApplet("kicker","SkimApplet");
            m_kickerSkimApplet.call("slotLeaveEvent()");
        }
    }
    if(ShowExtHandleTimer)
    {
        ShowExtHandleTimer->stop();
        if(!alwaysShowExtensionHandle)
        {
            resetToolbarSize();
        }
    }
}

void MainWindow::toggleDocking()
{
    toggleDockingAction->activate();
}

void MainWindow::toggleDocking(bool internal)
{
    ToolBarModeType oldMode = Mode;
    Mode = toggleDockingAction->isChecked() ? PanelEmbedded : StandAlone;

    toggleDockingAction->setIcon( toggleDockingAction->isChecked() ? "skim_restore": "skim_minimize" );

    if(!internal)
    {
        //as the detach/attach requires some time to finish
        //it is better to hide self first. changeSetting()
        //will re-show this if required
        if( Mode != oldMode )
            hide();

        //if original mode is StandAlone, then save current direction before change to embeded mode
        if( oldMode == StandAlone )
            ScimKdeSettings::setMainWindow_Direction((int)MainWindowLayout->direction());

        ScimKdeSettings::setDockingToPanelApplet(toggleDockingAction->isChecked());
        changeSetting();
        updateProperties (true);
        updateProperties (false);
    }
}

#include <kgenericfactory.h>
typedef KGenericFactory<MainWindowPlugin> MainWindowPluginFactory;

K_EXPORT_COMPONENT_FACTORY( skimplugin_mainwindow,
  MainWindowPluginFactory( "skimplugin_mainwindow" ) )

MainWindowPlugin::MainWindowPlugin( QObject *parent, const char *name, const QStringList & /*args*/ )
    : SkimPlugin(MainWindowPluginFactory::instance(), parent, name)
{
    Qt::WidgetFlags flags = Qt::WStyle_Customize;
    if(!ScimKdeSettings::dockingToPanelApplet())
        flags = (Qt::WidgetFlags)(Qt::WStyle_Customize | Qt::WX11BypassWM | Qt::WStyle_StaysOnTop);

    mainwindow = new MainWindow(0, "mainWindow", flags);
    connect( this, SIGNAL(settingsChanged()), mainwindow, SLOT(changeSetting()));
}

void MainWindowPlugin::toggleDocking()
{
    //do not call mainwindow->toggleDocking(void), because it will
    //toggle the action again. While this function is called
    //after the action has been toggled already
    mainwindow->toggleDocking(false);
}

MainWindowPlugin::~MainWindowPlugin()
{
    delete mainwindow;
}

#include "mainwindow.moc"
