/***************************************************************************
*   Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr  *
*                                                                         *
*   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.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program.  If not, see <http://www.gnu.org/licenses/>  *
***************************************************************************/
/** @file
* This file defines classes skgmainpanel.
*
* @author Stephane MANKOWSKI / Guillaume DE BURE
*/
#include "skgmainpanel.h"
#include "skgtraces.h"
#include "skgservices.h"
#include "skginterfaceplugin.h"
#include "skgtransactionmng.h"
#include "skgzoomselector.h"
#include "skgtreeview.h"
#include "skgwebview.h"

#include <KTemporaryFile>
#include <ktip.h>
#include <ksplashscreen.h>
#include <kconfigdialog.h>
#include <kstatusbar.h>
#include <ktoolbar.h>
#include <kmenubar.h>
#include <kpushbutton.h>
#include <KDE/KLocale>
#include <kglobal.h>
#include <kparts/componentfactory.h>
#include <kaction.h>
#include <kactionmenu.h>
#include <kactioncollection.h>
#include <kmessagebox.h>
#include <ktabwidget.h>
#include <kservice.h>
#include <kxmlguifactory.h>
#include <knotification.h>
#include <kfiledialog.h>
#include <kmenu.h>
#include <kcombobox.h>
#include <kselectaction.h>
#include <kstandarddirs.h>
#include <kstringhandler.h>
#include <ktoolbarpopupaction.h>
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <ktoggleaction.h>

#include <QtGui/QProgressBar>
#include <QtGui/QHeaderView>
#include <QApplication>
#include <QDir>
#include <QResizeEvent>
#include <klineedit.h>
#include <qtextcodec.h>
#include <kencodingfiledialog.h>
#include <ktabbar.h>

bool SKGMainPanel::m_currentActionCanceled = false;
SKGMainPanel* SKGMainPanel::m_mainPanel = NULL;
SKGMainPanel::SKGMainPanel(KSplashScreen* iSplashScreen, SKGDocument* iDocument, const QStringList& iArguments)
    : KParts::MainWindow(),
      m_tabWidget(new SKGTabWidget(this)),
      m_splashScreen(iSplashScreen),
      m_currentDocument(iDocument),
      m_tipOfDayAction(NULL), m_closePageAction(NULL), m_closeAllPagesAction(NULL), m_closeAllOtherPagesAction(NULL),
      m_fullScreenAction(NULL), m_actLock(NULL), m_actUnLock(NULL), m_kSystemTrayIcon(NULL),
      m_kNormalMessage(NULL), m_zoomSelector(NULL),  m_previousAction(NULL), m_nextAction(NULL), m_buttonMenuAction(NULL),
      m_middleClick(false), m_saveOnClose(false)
{
    SKGTRACEIN(1, "SKGMainPanel::SKGMainPanel");

    //Set main panel
    m_mainPanel = this;

    //Initialize settings
    KSharedConfigPtr config = KSharedConfig::openConfig();
    KConfigGroup prefskg = config->group("Main Panel");
    if (prefskg.readEntry("update_modified_contexts", 100) == 100) {
        //First call, we set default values
        prefskg.writeEntry("update_modified_contexts", 2);
        prefskg.writeEntry("update_modified_bookmarks", 2);

        KMessageBox::saveDontShowAgainYesNo("updateContextOnClose", KMessageBox::No);
        KMessageBox::saveDontShowAgainYesNo("updateBookmarkOnClose", KMessageBox::No);
    }

    //Search plugins
    KService::List offers = KServiceTypeTrader::self()->query(QLatin1String("SKG GUI/Plugin"));

    //Create temporary file for tips
    m_tipsFile.setSuffix(".tips");

    bool tipsFileOpened = m_tipsFile.open();
    bool tipsFound = false;

    QTextStream stream(&m_tipsFile);

    //Load plugins
    KAboutData* about = const_cast<KAboutData*>(KGlobal::mainComponent().aboutData());
    int nb = offers.count();
    SKGTRACEL(1) << nb << " plugins found" << endl;
    if (m_splashScreen) m_splashScreen->showMessage(i18nc("Splash screen message", "Loading plugins..."), Qt::AlignLeft, QColor(221, 130, 8));          // krazy:exclude=qmethods
    SKGError err;
    QStringList listAuthors;
    QStringList listTasks;
    QStringList listEmails;
    QStringList listOscs;
    for (int i = 0; i < nb; ++i) {
        KService::Ptr service = offers.at(i);
        QString name = service->name();
        QString version = service->property("X-KDE-PluginInfo-Version", QVariant::String).toString();
        QString email = service->property("X-KDE-PluginInfo-Email", QVariant::String).toString();
        QString id = service->property("X-Krunner-ID", QVariant::String).toString();
        QString msg = i18nc("Splash screen message", "Loading plugin %1/%2: %3...", i + 1, nb, name);
        SKGTRACEL(1) << msg << endl;
        if (m_splashScreen) m_splashScreen->showMessage(msg, Qt::AlignLeft, QColor(221, 130, 8));         // krazy:exclude=qmethods
        KPluginLoader loader(service->library());
        if (version.isEmpty() || SKGServices::stringToDouble(version) < 1) {
            SKGTRACE << "WARNING: plugin [" << name << "] not loaded because of version too old (<1)" << endl;
        } else {
            KPluginFactory* factory = loader.factory();
            if (factory) {
                SKGInterfacePlugin* pluginInterface = factory->create<SKGInterfacePlugin> (this);
                if (pluginInterface && pluginInterface->isEnabled() && pluginInterface->setupActions(getDocument(), iArguments)) {
                    //Add plugin in about
                    if (about) {
                        QString author = service->property("X-KDE-PluginInfo-Author", QVariant::String).toString();
                        if (!author.isEmpty()) {
                            QString authorId;
                            QStringList authors = SKGServices::splitCSVLine(author, ',');
                            if (authors.count() == 2) {
                                author = authors.at(0);
                                authorId = authors.at(1);
                            }
                            int pos = listAuthors.indexOf(author);
                            if (pos == -1) {
                                listAuthors.push_back(author);
                                listTasks.push_back(i18n("Developer of plugin '%1'", name));
                                listEmails.push_back(email);
                                listOscs.push_back(authorId);
                            } else {
                                listTasks[pos] += i18n(", '%1'", name);
                            }
                        }
                    }

                    //Store plugin
                    int nbplugin = m_pluginsList.count();
                    int pos = nbplugin;
                    for (int j = nbplugin - 1; j >= 0; --j) {
                        if (pluginInterface->getOrder() < m_pluginsList.at(j)->getOrder()) {
                            pos = j;
                        }
                    }

                    m_pluginsList.insert(pos, pluginInterface);
                    pluginInterface->setObjectName(id);

                    //Build temporary tips file
                    if (tipsFileOpened) {
                        QStringList tipsList = pluginInterface->tips();
                        int nbtips = tipsList.count();
                        for (int t = 0; t < nbtips; ++t) {
                            tipsFound = true;
                            stream << "<tip category=\""
                                   << id
                                   << "\"><html>" << SKGServices::stringToHtml(tipsList.at(t))
                                   << "</html></tip>"
                                   << endl;
                        }
                    }
                }
            } else {
                getDocument()->sendMessage(i18nc("An information message",  "Loading plugin %1 failed because the factory could not be found in %2", id, service->library()));
            }
        }
    }

    //Add credits
    nb = listAuthors.count();
    for (int i = 0; i < nb; ++i) {
        about->addCredit(ki18n("%1").subs(listAuthors.at(i).toAscii().data()),
                         ki18n("%1").subs(listTasks.at(i).toAscii().data()),
                         listEmails.at(i).toAscii(),
                         ""
#ifdef SKGKDE46ENABLED
                         , listOscs.at(i).toAscii()
#endif
                        );
    }

    // accept dnd
    setAcceptDrops(true);
    ui.setupUi(this);

    // tell the KXmlGuiWindow that this is indeed the main widget
    setCentralWidget(m_tabWidget);

    refreshTabPosition();
    m_tabWidget->setMovable(true);
    m_tabWidget->setTabsClosable(true);
    m_tabWidget->setAutomaticResizeTabs(true);
    m_tabWidget->setTabBarHidden(false);
    m_tabWidget->setUsesScrollButtons(true);
#ifdef SKGKDE46ENABLED
    m_tabWidget->tabBar()->setSelectionBehaviorOnRemove(KTabBar::SelectPreviousTab);
#endif
    m_tabWidget->setDocumentMode(true);

    m_tabWidget->show();

    //System tray
    if (KSystemTrayIcon::isSystemTrayAvailable()) {
        m_kSystemTrayIcon = new KSystemTrayIcon(qApp->windowIcon());
        KMenu* systemTrayMenu = new KMenu(this);
        QAction* quit = systemTrayMenu->addAction(KIcon("application-exit"),  i18nc("Verb", "Quit"));
        connect(quit, SIGNAL(triggered(bool)), this, SLOT(onQuitAction()));

        m_kSystemTrayIcon->setContextMenu(systemTrayMenu);
        connect(m_kSystemTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(onTrayActivated(QSystemTrayIcon::ActivationReason)));
        if (iconInSystemtray()) m_kSystemTrayIcon->show();
    }

    // then, setup our actions
    setupActions();

    displayErrorMessage(err);

    if (tipsFileOpened) {
        m_tipsFile.close();
    }

    //Add a status bar
    statusBar()->show();

    //Add action to control hide / display of Pages
    /*KAction* toggle = actionCollection()->addAction("view_context");
    toggle->setShortcut(QKeySequence(Qt::SHIFT+Qt::Key_F9));
    toggle->setText(i18nc ("Noun", "Pages" ) );
    toggle->setCheckable(true);
    toggle->setChecked(true);
    connect(toggle, SIGNAL(toggled(bool)), ui.kDockContext->toggleViewAction(), SLOT(toggle()));
    connect(ui.kDockContext, SIGNAL(visibilityChanged(bool)), toggle, SLOT(setChecked(bool)));*/

    QPalette palette = QApplication::palette();
    palette.setColor(QPalette::Base, Qt::transparent);
    ui.kContextList->setPalette(palette);

    QAction* toggle = ui.kDockContext->toggleViewAction();
    if (toggle) {
        toggle->setText(i18nc("Noun", "Pages"));
        toggle->setShortcut(Qt::SHIFT + Qt::Key_F9);
        actionCollection()->addAction("view_context", toggle);
    }
    KSelectAction* contextMenu = new KSelectAction(KIcon("tab-new"), i18nc("Noun", "Pages"), this);
    actionCollection()->addAction("view_contextmenu" , contextMenu);

    //Add plugin in client in right order
    QList<QListWidgetItem*> pageNotVisible;
    KConfigGroup prefContextVisibility = config->group("Context Visibility");
    int shortCutIndex = 0;
    QString shortCutPrefix = "Ctrl+";
    int nbplugin = m_pluginsList.count();
    QList<QAction*> contextActionList;
    for (int j = 0; j < nbplugin; ++j) {
        SKGInterfacePlugin* pluginInterface = m_pluginsList.at(j);
        if (pluginInterface) {
            //Creation of the item
            QString title = pluginInterface->title();
            SKGTRACEL(1) << "Add plugin (" << pluginInterface->getOrder() << ") : " << title << endl;
            if (!title.isEmpty()) {
                //Add menu item with shortcuts
                if (pluginInterface->isInPagesChooser()) {
                    bool visible = prefContextVisibility.readEntry(pluginInterface->objectName(), true);
                    KIcon icon(pluginInterface->icon());

                    QListWidgetItem* contextItem = new QListWidgetItem(icon, title);
                    contextItem->setStatusTip(pluginInterface->statusTip());
                    contextItem->setToolTip(pluginInterface->toolTip());
                    contextItem->setData(12, j);     //context item ==> plugin
                    int page = ui.kContextList->count();
                    pluginInterface->setProperty("contextItem", page); //plugin ==> context item

                    ui.kContextList->addItem(contextItem);

                    KAction* action = contextMenu->addAction(icon, title);
                    if (action) {
                        action->setCheckable(false);
                        action->setData(page);
                        contextItem->setData(15, (qlonglong) action);     //context item ==> action
                        if (!shortCutPrefix.isEmpty()) {
                            ++shortCutIndex;
                            if (shortCutIndex == 10) {
                                shortCutIndex = 0;
                                if (shortCutPrefix == "Ctrl+") shortCutPrefix += "Alt+";
                                else shortCutPrefix = "";
                            }
                            if (!shortCutPrefix.isEmpty()) action->setShortcut(QString(shortCutPrefix % SKGServices::intToString(shortCutIndex)));
                        }
                        connect(action, SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), this, SLOT(onOpenContext(Qt::MouseButtons,Qt::KeyboardModifiers)));

                        contextActionList.append(action);

                        if (!visible) pageNotVisible.push_back(contextItem);
                    }
                }

                //Create dock if needed
                QDockWidget* dockWidget = pluginInterface->getDockWidget();
                if (dockWidget) {
                    addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
                    tabifyDockWidget(ui.kDockContext, dockWidget);
                    tabifyDockWidget(dockWidget, ui.kDockContext);
                }
            }
        }
    }

    //Lock docs if needed
    KConfigGroup pref = getMainConfigGroup();
    if (pref.readEntry("docks_locked", false)) {
        actionLockDocks();
    }

    //267773 this->setWindowState(windowState() | Qt::WindowMaximized);

    // a call to KXmlGuiWindow::setupGUI() populates the GUI
    // with actions, using KXMLGUI.
    // It also applies the saved mainwindow settings, if any, and ask the
    // mainwindow to automatically save settings if changed: window size,
    // toolbar position, icon size, etc.
    setupGUI(Default, "../skg/skgmainpanel.rc");
    plugActionList("context_actionlist", contextActionList);

    for (int j = 0; j < nbplugin; ++j) {
        SKGInterfacePlugin* pluginInterface = m_pluginsList.at(j);
        if (pluginInterface) {
            QString title = pluginInterface->title();
            SKGTRACEL(1) << "Add plugin client (" << pluginInterface->getOrder() << ") : " << title << endl;
            guiFactory()->addClient(pluginInterface);
        }
    }

    //Hide items in context
    nb = pageNotVisible.count();
    for (int i = 0; i < nb; ++i) {
        setContextVisibility(pageNotVisible.at(i), false);
    }

    //Set status bar
    m_kNormalMessage = new QLabel(this);

    QProgressBar* kProgressBar = new QProgressBar(this);
    kProgressBar->setObjectName(QString::fromUtf8("kProgressBar"));
    kProgressBar->setValue(0);
    kProgressBar->setMinimumSize(100, 20);
    QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
    kProgressBar->setSizePolicy(sizePolicy);
    kProgressBar->setToolTip(i18nc("Widget description", "Progress of the current action"));
    QFont f = kProgressBar->font();
    f.setPointSize(6.0);
    kProgressBar->setFont(f);
    kProgressBar->setVisible(false);
    kProgressBar->setAlignment(Qt::AlignTop | Qt::AlignHCenter);

    m_zoomSelector = new SKGZoomSelector(this);
    m_zoomSelector->setSizePolicy(sizePolicy);
    connect(m_zoomSelector, SIGNAL(changed(int)), this, SLOT(onZoomChanged()));

    statusBar()->addWidget(m_kNormalMessage);
    statusBar()->addPermanentWidget(kProgressBar);

    //Set Cancel button
    KPushButton* kCancelButton = new KPushButton();
    kCancelButton->setObjectName(QString::fromUtf8("kCancelButton"));
    kCancelButton->setIcon(KIcon("media-playback-stop"));
    kCancelButton->setToolTip(i18nc("Widget description", "Cancel the current action"));
    kCancelButton->setStatusTip(i18nc("Widget description", "Cancel the current action"));
    kCancelButton->setVisible(false);
    connect(kCancelButton, SIGNAL(clicked()), this, SLOT(onCancelCurrentAction()));

    //Add special button in toolbar
    KToolBar* tb = toolBar();
    if (tb) {
        QLabel* label = new QLabel(this);
        QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
        sizePolicy.setHorizontalStretch(0);
        sizePolicy.setVerticalStretch(0);
        sizePolicy.setHeightForWidth(label->sizePolicy().hasHeightForWidth());
        label->setSizePolicy(sizePolicy);
        tb->addWidget(label);
        tb->addAction(m_buttonMenuAction);
    }

    statusBar()->addPermanentWidget(kCancelButton);
    statusBar()->addPermanentWidget(m_zoomSelector);

    //Set progress bar call back
    if (getDocument()) {
        m_progressObjects.p1 = (void*) kProgressBar;
        m_progressObjects.p2 = (void*) kCancelButton;
        getDocument()->setProgressCallback(&SKGMainPanel::progressBarCallBack, (void*) &m_progressObjects);
    }

    //Connection
    if (getDocument()) {
        connect((const QObject*) getDocument(), SIGNAL(transactionSuccessfullyEnded(int)), this, SLOT(refresh()), Qt::QueuedConnection);
        connect((const QObject*) getDocument(), SIGNAL(transactionSuccessfullyEnded(int)), this, SLOT(notify(int)), Qt::QueuedConnection);
    }
    connect(ui.kContextList, SIGNAL(itemPressed(QListWidgetItem*)), this, SLOT(onBeforeOpenContext()));
    connect(ui.kContextList, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(onOpenContext()));
    connect(m_tabWidget, SIGNAL(closeRequest(QWidget*)), this, SLOT(closePage(QWidget*)));
    connect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget*)), this, SLOT(closePage(QWidget*)));
    connect(m_tabWidget, SIGNAL(mouseDoubleClick()), this, SLOT(addTab()));
    connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SIGNAL(currentPageChanged()));
    connect(this, SIGNAL(currentPageChanged()), this, SLOT(refresh()));

    //Refresh
    refresh();

    //Tip of day
    if (tipsFound) {
        //Tip of day is available
        KSharedConfigPtr config = KSharedConfig::openConfig();
        KConfigGroup pref = config->group("TipOfDay");
        if (pref.readEntry("RunOnStart", true)) onTipOfDay();
    } else {
        //Remove useless menu
        delete m_tipOfDayAction;
        m_tipOfDayAction = NULL;
    }

    ui.kContextList->installEventFilter(this);

    //Build contextual menu
    ui.kContextList->setContextMenuPolicy(Qt::CustomContextMenu);

    m_contextMenu = new KMenu(ui.kContextList);
    m_actHideContextItem = m_contextMenu->addAction(KIcon("layer-visible-off"), i18nc("Verb", "Hide"));
    connect(m_actHideContextItem, SIGNAL(triggered(bool)), this, SLOT(actionHideContextItem()));

    m_actShowAllContextItems = m_contextMenu->addAction(KIcon("layer-visible-on"), i18nc("Verb", "Show all"));
    connect(m_actShowAllContextItems, SIGNAL(triggered(bool)), this, SLOT(actionShowAllContextItems()));

    m_contextMenu->addSeparator();
    m_contextMenu->addAction(getGlobalAction("tab_savedefaultstate"));
    m_contextMenu->addAction(getGlobalAction("tab_resetdefaultstate"));

    connect(ui.kContextList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));

    //Show menu bar and status bar
    menuBar()->show();
    statusBar()->show();

    notify(); //Due to sendMessage not in a transaction
    m_splashScreen = NULL;
}

SKGMainPanel::~SKGMainPanel()
{
    SKGTRACEIN(1, "SKGMainPanel::~SKGMainPanel");
    disconnect((const QObject*) getDocument(), 0, this, 0);

    //close plugins
    int nb = m_pluginsList.count();
    for (int i = 0; i < nb; ++i) {
        getPluginByIndex(i)->close();
    }

    if (getDocument()) {
        getDocument()->close();
    }
    m_kNormalMessage = NULL;
}

void SKGMainPanel::showMenu(const QPoint& pos)
{
    if (m_contextMenu) m_contextMenu->popup(ui.kContextList->mapToGlobal(pos));
}

void SKGMainPanel::setContextVisibility(QListWidgetItem* iItem, bool iVisibility)
{
    if (iItem) {
        //Hide item in context
        iItem->setHidden(!iVisibility);

        //Hide corresponding action
        KAction* act = (KAction*) iItem->data(15).toLongLong();
        if (act) act->setVisible(iVisibility);

        //Save state in settings
        SKGInterfacePlugin* plugin = getPluginByIndex(iItem->data(12).toInt());
        if (plugin) {
            KSharedConfigPtr config = KSharedConfig::openConfig();
            KConfigGroup pref = config->group("Context Visibility");
            pref.writeEntry(plugin->objectName(), iVisibility);
        }
    }
}

void SKGMainPanel::setContextVisibility(int iPage, bool iVisibility)
{
    setContextVisibility(ui.kContextList->item(iPage), iVisibility);
}

void SKGMainPanel::actionHideContextItem()
{
    setContextVisibility(ui.kContextList->currentRow(), false);
}

void SKGMainPanel::actionShowAllContextItems()
{
    int nb = ui.kContextList->count();
    for (int i = 0; i < nb; ++i) {
        setContextVisibility(i, true);
    }
}

SKGDocument* SKGMainPanel::getDocument() const
{
    return m_currentDocument;
}

void SKGMainPanel::processArguments(const QStringList& iArgument)
{
    foreach(SKGInterfacePlugin * plugin, m_pluginsList) {
        if (plugin) plugin->processArguments(iArgument);
    }
}

void SKGMainPanel::registedGlobalAction(const QString& iIdentifier, KAction* iAction)
{
    m_registeredGlogalAction[iIdentifier] = iAction;
}

KAction* SKGMainPanel::getGlobalAction(const QString& iIdentifier)
{
    return m_registeredGlogalAction[iIdentifier];
}

SKGInterfacePlugin* SKGMainPanel::getPluginByIndex(int iIndex)
{
    SKGInterfacePlugin* output = NULL;
    if (iIndex >= 0 && iIndex < m_pluginsList.count()) {
        output = m_pluginsList[iIndex];
    }

    return output;
}

SKGInterfacePlugin* SKGMainPanel::getPluginByName(const QString& iName)
{
    SKGInterfacePlugin* output = NULL;
    int nbplugin = m_pluginsList.count();
    for (int j = 0; !output && j < nbplugin; ++j) {
        if (m_pluginsList[j]->objectName() == iName) {
            output = m_pluginsList[j];
        }
    }

    return output;
}

void SKGMainPanel::setupActions()
{
    SKGTRACEIN(1, "SKGMainPanel::setupActions");

    //Std File
    KStandardAction::quit(this, SLOT(onQuitAction()), actionCollection());

    //Preferences
    KStandardAction::preferences(this, SLOT(optionsPreferences()), actionCollection());

    // New Tab
    m_addTabAction = new KAction(KIcon("tab-new-background"), i18nc("Noun, user action", "New Tab"), this);
    actionCollection()->addAction(QLatin1String("new_tab"), m_addTabAction);
    m_addTabAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_W);
    connect(m_addTabAction, SIGNAL(triggered()), this, SLOT(addTab()));

    registedGlobalAction("tab-new-background", m_addTabAction);

    m_actLock = new KAction(KIcon("document-encrypt"), i18nc("Verb", "Lock panels"), this);
    actionCollection()->addAction(QLatin1String("view_lock"), m_actLock);
    connect(m_actLock, SIGNAL(triggered(bool)), this, SLOT(actionLockDocks()));

    m_actUnLock = new KAction(KIcon("document-decrypt"), i18nc("Verb", "Unlock panels"), this);
    actionCollection()->addAction(QLatin1String("view_unlock"), m_actUnLock);
    connect(m_actUnLock, SIGNAL(triggered(bool)), this, SLOT(actionUnlockDocks()));

    //
    m_closePageAction = actionCollection()->addAction(KStandardAction::Close, "tab_close", this, SLOT(closePage()));

    registedGlobalAction("tab_close", m_closePageAction);

    //
    m_closeAllPagesAction = new KAction(KIcon("window-close"), i18nc("Noun, user action", "Close All"), this);
    actionCollection()->addAction(QLatin1String("tab_closeall"), m_closeAllPagesAction);
    m_closeAllPagesAction->setShortcut(Qt::ALT + Qt::Key_W);
    connect(m_closeAllPagesAction, SIGNAL(triggered()), this, SLOT(closeAllPages()));

    registedGlobalAction("tab_closeall", m_closeAllPagesAction);

    //
    m_closeAllOtherPagesAction = new KAction(KIcon("window-close"), i18nc("Noun, user action", "Close All Other"), this);
    actionCollection()->addAction(QLatin1String("tab_closeallother"), m_closeAllOtherPagesAction);
    m_closeAllOtherPagesAction->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_W);
    connect(m_closeAllOtherPagesAction, SIGNAL(triggered()), this, SLOT(closeAllOtherPages()));

    registedGlobalAction("tab_closeallother", m_closeAllOtherPagesAction);

    //
    m_saveDefaultStateAction = new KAction(KIcon("document-save"), i18nc("Noun, user action", "Save page state"), this);
    actionCollection()->addAction(QLatin1String("tab_savedefaultstate"), m_saveDefaultStateAction);
    m_saveDefaultStateAction->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_S);
    connect(m_saveDefaultStateAction, SIGNAL(triggered()), this, SLOT(saveDefaultState()));

    registedGlobalAction("tab_savedefaultstate", m_saveDefaultStateAction);

    //
    m_resetDefaultStateAction = new KAction(KIcon("edit-clear"), i18nc("Noun, user action", "Reset page state"), this);
    actionCollection()->addAction(QLatin1String("tab_resetdefaultstate"), m_resetDefaultStateAction);
    m_resetDefaultStateAction->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_R);
    connect(m_resetDefaultStateAction, SIGNAL(triggered()), this, SLOT(resetDefaultState()));

    registedGlobalAction("tab_resetdefaultstate", m_resetDefaultStateAction);

    //
    QStringList overlay;
    overlay.push_back("rating");
    m_overwriteBookmarkStateAction = new KAction(KIcon("document-save", NULL, overlay), i18nc("Noun, user action", "Overwrite bookmark state"), this);
    actionCollection()->addAction(QLatin1String("tab_overwritebookmark"), m_overwriteBookmarkStateAction);
    connect(m_overwriteBookmarkStateAction, SIGNAL(triggered()), this, SLOT(overwriteBookmarkState()));
    m_overwriteBookmarkStateAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_S);

    registedGlobalAction("tab_overwritebookmark", m_overwriteBookmarkStateAction);

    //
    m_configureAction = new KAction(KIcon("configure"), i18nc("Noun, user action", "Configure..."), this);
    actionCollection()->addAction(QLatin1String("tab_configure"), m_configureAction);
    connect(m_configureAction, SIGNAL(triggered()), this, SLOT(optionsPreferences()));

    registedGlobalAction("tab_configure", m_configureAction);

    m_tipOfDayAction = KStandardAction::tipOfDay(this, SLOT(onTipOfDay()), actionCollection());

    //Menu
    m_buttonMenuAction = new KToolBarPopupAction(KIcon("configure"), "", this);
    m_buttonMenuAction->setToolTip(i18nc("Noun, user action", "Menu"));
    actionCollection()->addAction(QLatin1String("view_menu"), m_buttonMenuAction);

    m_buttonMenu = static_cast<KMenu*>(m_buttonMenuAction->menu());
    connect(m_buttonMenu , SIGNAL(aboutToShow()), this, SLOT(onShowButtonMenu()));
    m_buttonMenuAction->setDelayed(false);

    registedGlobalAction("view_menu", m_buttonMenuAction);

    m_showMenuBarAction = KStandardAction::showMenubar(this, SLOT(onShowMenuBar()), actionCollection());

    KConfigGroup pref = getMainConfigGroup();
    m_showMenuBarAction->setChecked(pref.readEntry("menubar_shown", true));

    QTimer::singleShot(200, this, SLOT(onShowMenuBar()));

    //
    m_previousAction = new KToolBarPopupAction(KIcon("go-previous"), i18nc("Noun, user action", "Previous"), this);
    connect(m_previousAction, SIGNAL(triggered(bool)), this, SLOT(actionPrevious()));
    actionCollection()->addAction(QLatin1String("go_previous"), m_previousAction);
    m_previousAction->setShortcut(Qt::ALT + Qt::Key_Left);

    //m_tabWidget->setCornerWidget(toolBar(), Qt::TopLeftCorner);

    m_previousMenu = static_cast<KMenu*>(m_previousAction->menu());
    connect(m_previousMenu , SIGNAL(aboutToShow()), this, SLOT(onShowPreviousMenu()));

    m_previousAction->setStickyMenu(false);
    m_previousAction->setData(0);

    registedGlobalAction("go_previous", m_previousAction);

    //
    m_nextAction = new KToolBarPopupAction(KIcon("go-next"), i18nc("Noun, user action", "Next"), this);
    connect(m_nextAction, SIGNAL(triggered(bool)), this, SLOT(actionNext()));
    actionCollection()->addAction(QLatin1String("go_next"), m_nextAction);
    m_nextAction->setShortcut(Qt::ALT + Qt::Key_Right);

    m_nextMenu = static_cast<KMenu*>(m_nextAction->menu());
    connect(m_nextMenu , SIGNAL(aboutToShow()), this, SLOT(onShowNextMenu()));

    m_nextAction->setStickyMenu(false);
    m_nextAction->setData(0);

    registedGlobalAction("go_next", m_nextAction);

    //
    m_fullScreenAction = actionCollection()->addAction(KStandardAction::FullScreen, "fullscreen", this, SLOT(actionFullScreen()));

    registedGlobalAction("fullscreen", m_fullScreenAction);


    //
    m_enableEditorAction = new KAction(KIcon("appointment-new"), i18nc("Noun, user action", "Enable editor"), this);
    actionCollection()->addAction(QLatin1String("enable_editor"), m_enableEditorAction);
    m_enableEditorAction->setShortcut(Qt::CTRL + Qt::Key_Insert);
    connect(m_enableEditorAction, SIGNAL(triggered()), this, SLOT(enableEditor()));

    //Contextual menu
    m_tabWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
    m_tabWidget->insertAction(0, getGlobalAction("tab-new-background"));
    m_tabWidget->insertAction(0, getGlobalAction("tab_close"));
    m_tabWidget->insertAction(0, getGlobalAction("tab_closeall"));
    m_tabWidget->insertAction(0, getGlobalAction("tab_closeallother"));
    {
        QAction* sep = new QAction(this);
        sep->setSeparator(true);
        m_tabWidget->insertAction(0, sep);
    }
    m_tabWidget->insertAction(0, getGlobalAction("tab_resetdefaultstate"));
    m_tabWidget->insertAction(0, getGlobalAction("tab_savedefaultstate"));
    m_tabWidget->insertAction(0, getGlobalAction("tab_overwritebookmark"));
    m_tabWidget->insertAction(0, getGlobalAction("tab_configure"));
    {
        QAction* sep = new QAction(this);
        sep->setSeparator(true);
        m_tabWidget->insertAction(0, sep);
    }
    m_tabWidget->insertAction(0, getGlobalAction("fullscreen"));
}

void SKGMainPanel::enableEditor()
{
    SKGTabPage* cPage = currentPage();
    if (cPage) cPage->activateEditor();
}

void SKGMainPanel::actionPrevious()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGMainPanel::actionPrevious", err);

    SKGTabPage* cPage = currentPage();
    if (cPage) {
        //Get index in history of page to refresh
        int pos = ((QAction*) sender())->data().toInt();

        //Get lists
        QList<SKGTabPage::SKGPageHistoryItem> listPrevious = cPage->getPreviousPages();
        QList<SKGTabPage::SKGPageHistoryItem> listNext = cPage->getNextPages();
        SKGTabPage::SKGPageHistoryItem current = currentPageHistoryItem();

        //Get item to refresh
        SKGTabPage::SKGPageHistoryItem item = listPrevious.at(pos);

        //Open page
        cPage = openPage(getPluginByName(item.plugin), currentPageIndex(), item.state, item.name, item.bookmarkID);
        if (cPage) {
            cPage->setBookmarkID(item.bookmarkID);

            //Update lists
            listNext.insert(0, current);
            listPrevious.removeAt(pos);
            for (int i = 0; i < pos; ++i) {
                SKGTabPage::SKGPageHistoryItem item = listPrevious.at(0);  //Because the list is modified
                listNext.insert(0, item);
                listPrevious.removeAt(0);
            }

            //Set lists
            cPage->setPreviousPages(listPrevious);
            cPage->setNextPages(listNext);
        }

        refresh();
    }
}

void SKGMainPanel::onShowPreviousMenu()
{
    if (m_previousMenu) {
        m_previousMenu->clear();

        SKGTabPage* cPage = currentPage();
        if (cPage) {
            QList<SKGTabPage::SKGPageHistoryItem> list = cPage->getPreviousPages();
            int nb = list.count();
            for (int i = 0; i < nb; ++i) {
                QAction* act = m_previousMenu->addAction(KIcon(list.at(i).icon), list.at(i).name);
                if (act) {
                    act->setData(i);
                    connect(act, SIGNAL(triggered()), this, SLOT(actionPrevious()));
                }
            }
        }
    }
}

void SKGMainPanel::onShowMenuBar()
{
    bool test = m_showMenuBarAction->isChecked();
    menuBar()->setVisible(test);
    m_buttonMenuAction->setVisible(!test);

    KConfigGroup pref = getMainConfigGroup();
    pref.writeEntry("menubar_shown", test);
}

void SKGMainPanel::actionFullScreen()
{
    if (!m_fullScreenAction->isChecked()) {
        //No Full screen
        setWindowState(windowState() & ~Qt::WindowFullScreen);   // reset

        //Show widget
        int nb = m_hiddenWidgets.count();
        for (int i = nb - 1; i >= 0; --i) { //Must be done in this order
            m_hiddenWidgets.at(i)->show();
        }
        m_hiddenWidgets.clear();
    } else {
        //Full screen
        //Create list of widget to hide
        m_hiddenWidgets.push_back(menuBar());
        m_hiddenWidgets.push_back(statusBar());
        QList<KToolBar*> toolbars = toolBars();
        foreach(KToolBar * toolbar, toolbars) {
            m_hiddenWidgets.push_back(toolbar);
        }

        QObjectList cs = children();
        foreach(QObject * c, cs) {
            QDockWidget* doc = qobject_cast<QDockWidget*>(c);
            if (doc) m_hiddenWidgets.push_back(doc);
        }

        //Hide widget, keep in list hidden widget
        int nb = m_hiddenWidgets.count();
        for (int i = nb - 1; i >= 0; --i) {
            QWidget* w = m_hiddenWidgets.at(i);
            if (w && w->isVisible()) w->hide();
            else m_hiddenWidgets.removeAt(i);
        }

        setWindowState(windowState() | Qt::WindowFullScreen);   // set
    }
}

void SKGMainPanel::actionNext()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGMainPanel::actionNext", err);

    SKGTabPage* cPage = currentPage();
    if (cPage) {
        //Get index in history of page to refresh
        int pos = ((QAction*) sender())->data().toInt();

        //Get lists
        QList<SKGTabPage::SKGPageHistoryItem> listPrevious = cPage->getPreviousPages();
        QList<SKGTabPage::SKGPageHistoryItem> listNext = cPage->getNextPages();
        SKGTabPage::SKGPageHistoryItem current = currentPageHistoryItem();

        //Get item to refresh
        SKGTabPage::SKGPageHistoryItem item = listNext.at(pos);

        //Open page
        cPage = openPage(getPluginByName(item.plugin), currentPageIndex(), item.state, item.name, item.bookmarkID);
        if (cPage) {
            cPage->setBookmarkID(item.bookmarkID);

            //Update lists
            listPrevious.insert(0, current);
            listNext.removeAt(pos);
            for (int i = 0; i < pos; ++i) {
                SKGTabPage::SKGPageHistoryItem item = listNext.at(0);  //Because the list is modified
                listPrevious.insert(0, item);
                listNext.removeAt(0);
            }

            //Set lists
            cPage->setPreviousPages(listPrevious);
            cPage->setNextPages(listNext);
        }

        refresh();
    }
}

void SKGMainPanel::actionLockDocks()
{
    QObjectList cs = children();
    foreach(QObject * c, cs) {
        QDockWidget* doc = qobject_cast<QDockWidget*>(c);
        if (doc) {
            doc->setFeatures(QDockWidget::NoDockWidgetFeatures);
        }
    }

    KConfigGroup pref = getMainConfigGroup();
    pref.writeEntry("docks_locked", true);

    refresh();
}

void SKGMainPanel::actionUnlockDocks()
{
    QObjectList cs = children();
    foreach(QObject * c, cs) {
        QDockWidget* doc = qobject_cast<QDockWidget*>(c);
        if (doc) doc->setFeatures(QDockWidget::AllDockWidgetFeatures);
    }

    KConfigGroup pref = getMainConfigGroup();
    pref.writeEntry("docks_locked", false);

    refresh();
}

void SKGMainPanel::onShowNextMenu()
{
    if (m_nextMenu) {
        m_nextMenu->clear();

        SKGTabPage* cPage = currentPage();
        if (cPage) {
            QList<SKGTabPage::SKGPageHistoryItem> list = cPage->getNextPages();
            int nb = list.count();
            for (int i = 0; i < nb; ++i) {
                QAction* act = m_nextMenu->addAction(KIcon(list.at(i).icon), list.at(i).name);
                if (act) {
                    act->setData(i);
                    connect(act, SIGNAL(triggered()), this, SLOT(actionNext()));
                }
            }
        }
    }
}

void SKGMainPanel::onShowButtonMenu()
{
    if (m_buttonMenu) {
        m_buttonMenu->clear();

        KMenuBar* mb = menuBar();
        if (mb) m_buttonMenu->addActions(mb->actions());
    }
}

bool SKGMainPanel::queryClose()
{
    SKGTRACEIN(1, "SKGMainPanel::queryClose");
    //Bug 2777697: To be sure that all page modifications are closed
    closeAllPages();
    //Bug 2777697:

    bool output = queryFileClose();

    if (output && m_kSystemTrayIcon) {
        m_kSystemTrayIcon->hide();
        delete m_kSystemTrayIcon;
        m_kSystemTrayIcon = NULL;
    }

    //To be sure that the application is not closed in fullscreen mode
    if (output) {
        if (m_fullScreenAction->isChecked()) m_fullScreenAction->trigger();
    }

    return output;
}

void SKGMainPanel::setSaveOnClose(bool iSaveOnClose)
{
    m_saveOnClose = iSaveOnClose;
}

bool SKGMainPanel::queryFileClose()
{
    SKGTRACEIN(1, "SKGMainPanel::queryFileClose");
    bool output = true;
    if (getDocument()->getCurrentTransaction()) {
        QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
        KMessageBox::information(this, i18nc("Question", "The application cannot be closed when an operation is running."));
        QApplication::restoreOverrideCursor();
        output = false;
    } else if (getDocument()->isFileModified()) {
        QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
        int code = KMessageBox::Yes;
        QString fileName = getDocument()->getCurrentFileName();
        KAction* save = getGlobalAction(fileName.isEmpty() ? "file_save_as" : "file_save");
        if (save) {
            if (!m_saveOnClose) code = KMessageBox::questionYesNoCancel(this, i18nc("Question", "The document has been modified.\nDo you want to save it before closing?"),
                                           QString(),
                                           KGuiItem(fileName.isEmpty() ?  i18nc("Question", "Save as") : i18nc("Question", "Save"),
                                                    KIcon(fileName.isEmpty() ?  "document-save-as" : "document-save")),
                                           KGuiItem(i18nc("Question", "Do not save"))
                                                                           );
            if (code == KMessageBox::Yes) save->trigger();
            output = (code == KMessageBox::No || code == KMessageBox::Yes);
        } else {
            code = KMessageBox::questionYesNo(this, i18nc("Question", "Current modifications will not be saved.\nDo you want to continue?"));
            output = (code == KMessageBox::Yes);
        }
        QApplication::restoreOverrideCursor();
    }

    return output;
}

SKGObjectBase::SKGListSKGObjectBase SKGMainPanel::getSelectedObjects()
{
    SKGObjectBase::SKGListSKGObjectBase selection;

    SKGTabPage* cPage = currentPage();
    if (cPage) {
        selection = cPage->getSelectedObjects();
    }
    return selection;
}

int SKGMainPanel::getNbSelectedObjects()
{
    int nb = 0;

    SKGTabPage* cPage = currentPage();
    if (cPage) {
        nb = cPage->getNbSelectedObjects();
    }
    return nb;
}

SKGAdviceList SKGMainPanel::getAdvices() const
{
    //Get list of ignored advices
    QString currentMonth = QDate::currentDate().toString("yyyy-MM");
    QStringList ignoredAdvices = getDocument()->getParameters("advices", "t_value='I' OR t_value='I_" % currentMonth % '\'');

    //Build the list of all advices by requesting all plugins
    SKGAdviceList globalAdvicesList;
    int index = 0;
    while (index >= 0) {
        SKGInterfacePlugin* plugin = SKGMainPanel::getMainPanel()->getPluginByIndex(index);
        if (plugin) {
            foreach(const SKGAdvice & ad, plugin->advices()) {
                if (!ignoredAdvices.contains(ad.getUUID()) && !ignoredAdvices.contains(SKGServices::splitCSVLine(ad.getUUID(), '|').at(0))) globalAdvicesList.push_back(ad);
            }
        } else index = -2;
        ++index;
    }
    qSort(globalAdvicesList.begin(), globalAdvicesList.end(), adviceLessThan);

    return globalAdvicesList;
}

KConfigGroup SKGMainPanel::getMainConfigGroup()
{
    KSharedConfigPtr config = KSharedConfig::openConfig();
    return config->group("Main Panel");
}

void SKGMainPanel::optionsPreferences(const QString& iPluginName)
{
    SKGTRACEIN(1, "SKGMainPanel::optionsPreferences");
    //Compute page
    QString pluginName = iPluginName;
    if (pluginName.isEmpty() && this->currentPage()) pluginName = this->currentPage()->objectName();

    //Synchronize setting with confirmation panel
    {
        KMessageBox::ButtonCode confirm;
        int ask = KMessageBox::shouldBeShownYesNo("updateBookmarkOnClose", confirm);

        KConfigGroup pref = getMainConfigGroup();
        if (ask) {
            pref.writeEntry("update_modified_bookmarks", 0);
        } else if (confirm == KMessageBox::Yes) {
            pref.writeEntry("update_modified_bookmarks", 1);
        } else {
            pref.writeEntry("update_modified_bookmarks", 2);
        }
    }
    {
        KMessageBox::ButtonCode confirm;
        int ask = KMessageBox::shouldBeShownYesNo("updateContextOnClose", confirm);

        KConfigGroup pref = getMainConfigGroup();
        if (ask) {
            pref.writeEntry("update_modified_contexts", 0);
        } else if (confirm == KMessageBox::Yes) {
            pref.writeEntry("update_modified_contexts", 1);
        } else {
            pref.writeEntry("update_modified_contexts", 2);
        }
    }
    skgbasegui_settings::self()->readConfig();


    if (KConfigDialog::showDialog("settings")) return;

    KConfigDialog* dialog = new KConfigDialog(this, "settings", skgbasegui_settings::self());

    //Add main
    QWidget* widget = new QWidget();
    uipref.setupUi(widget);

    uipref.kcfg_date_format->addItem(i18nc("Date format", "Short date (%1, %2)",
                                           KGlobal::locale()->formatDate(QDate::currentDate(), KLocale::ShortDate),
                                           KGlobal::locale()->formatDate(QDate::currentDate().addDays(-10), KLocale::ShortDate)));
    uipref.kcfg_date_format->addItem(i18nc("Date format", "Long date (%1, %2)",
                                           KGlobal::locale()->formatDate(QDate::currentDate(), KLocale::LongDate),
                                           KGlobal::locale()->formatDate(QDate::currentDate().addDays(-10), KLocale::LongDate)));
    uipref.kcfg_date_format->addItem(i18nc("Date format", "Fancy short date (%1, %2)",
                                           KGlobal::locale()->formatDate(QDate::currentDate(), KLocale::FancyShortDate),
                                           KGlobal::locale()->formatDate(QDate::currentDate().addDays(-10), KLocale::FancyShortDate)));
    uipref.kcfg_date_format->addItem(i18nc("Date format", "Fancy long date (%1, %2)",
                                           KGlobal::locale()->formatDate(QDate::currentDate(), KLocale::FancyLongDate),
                                           KGlobal::locale()->formatDate(QDate::currentDate().addDays(-10), KLocale::FancyLongDate)));
    uipref.kcfg_date_format->addItem(i18nc("Date format", "ISO date (%1, %2)",
                                           KGlobal::locale()->formatDate(QDate::currentDate(), KLocale::IsoDate),
                                           KGlobal::locale()->formatDate(QDate::currentDate().addDays(-10), KLocale::IsoDate)));
    uipref.kcfg_date_format->addItem(i18nc("Date format", "ISO week date (%1, %2)",
                                           KGlobal::locale()->formatDate(QDate::currentDate(), KLocale::IsoWeekDate),
                                           KGlobal::locale()->formatDate(QDate::currentDate().addDays(-10), KLocale::IsoWeekDate)));
    uipref.kcfg_date_format->addItem(i18nc("Date format", "ISO ordinal date (%1, %2)",
                                           KGlobal::locale()->formatDate(QDate::currentDate(), KLocale::IsoOrdinalDate),
                                           KGlobal::locale()->formatDate(QDate::currentDate().addDays(-10), KLocale::IsoOrdinalDate)));

    dialog->addPage(widget, skgbasegui_settings::self(), i18nc("Noun", "General"), "preferences-other");

    //Add plugin in client in right order
    int nbplugin = m_pluginsList.count();
    for (int j = 0; j < nbplugin; ++j) {
        SKGInterfacePlugin* pluginInterface = getPluginByIndex(j);
        if (pluginInterface) {
            QWidget* w = pluginInterface->getPreferenceWidget();
            if (w) {
                KPageWidgetItem* p = dialog->addPage(w, pluginInterface->getPreferenceSkeleton(), pluginInterface->title(), pluginInterface->icon());
                if (p && pluginName == pluginInterface->objectName()) dialog->setCurrentPage(p);
            }
        }
    }

    connect(dialog, SIGNAL(settingsChanged(QString)), this, SLOT(onSettingsChanged()));

    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->show();

    //Refresh
    refresh();
}

void SKGMainPanel::refreshTabPosition()
{
    m_tabWidget->setTabPosition((KTabWidget::TabPosition) skgbasegui_settings::main_tabs_position());
}

void SKGMainPanel::onSettingsChanged()
{
    SKGError err;
    SKGTRACEINRC(1, "SKGMainPanel::onSettingsChanged", err);
    {
        int nb = m_pluginsList.count();
        SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Save settings"), err, nb);

        //Refresh plugins
        for (int i = 0; !err && i < nb; ++i) {
            err = getPluginByIndex(i)->savePreferences();
            if (!err) err = getDocument()->stepForward(i + 1);
        }

        //Setting for icon
        if (m_kSystemTrayIcon) {
            if (iconInSystemtray()) m_kSystemTrayIcon->show();
            else m_kSystemTrayIcon->hide();
        }

        //Setting for tab position
        refreshTabPosition();

        //Setting for bookmarks modification
        {
            int option = skgbasegui_settings::update_modified_bookmarks();
            if (option == 0) {
                //ASK: remove following setting
                KMessageBox::enableMessage("updateBookmarkOnClose");
            } else if (option == 1) {
                //ALWAYS: set following setting
                KMessageBox::saveDontShowAgainYesNo("updateBookmarkOnClose", KMessageBox::Yes);
            } else {
                //NEVER: set following setting
                KMessageBox::saveDontShowAgainYesNo("updateBookmarkOnClose", KMessageBox::No);
            }
        }
        {
            int option = skgbasegui_settings::update_modified_contexts();
            if (option == 0) {
                //ASK: remove following setting
                KMessageBox::enableMessage("updateContextOnClose");
            } else if (option == 1) {
                //ALWAYS: set following setting
                KMessageBox::saveDontShowAgainYesNo("updateContextOnClose", KMessageBox::Yes);
            } else {
                //NEVER: set following setting
                KMessageBox::saveDontShowAgainYesNo("updateContextOnClose", KMessageBox::No);
            }
        }
        skgbasegui_settings::self()->readConfig();
    }

    emit settingsChanged();

    //Display error
    displayErrorMessage(err);
}

void SKGMainPanel::refresh()
{
    SKGTRACEIN(1, "SKGMainPanel::refresh");

    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

    //Refresh plugins
    int nb = m_pluginsList.count();
    for (int i = 0; i < nb; ++i) {
        getPluginByIndex(i)->refresh();
    }

    //Enable addTabeAction
    bool atLeastOnePageOpened = (m_tabWidget->count() > 0);
    m_addTabAction->setEnabled(atLeastOnePageOpened);
    m_closePageAction->setEnabled(atLeastOnePageOpened);
    m_closeAllPagesAction->setEnabled(atLeastOnePageOpened);
    m_closeAllOtherPagesAction->setEnabled(m_tabWidget->count() > 1);

    SKGTabPage* toSave = currentPage();
    if (toSave)
        if (m_saveDefaultStateAction) m_saveDefaultStateAction->setEnabled(toSave && !toSave->getDefaultStateAttribute().isEmpty());
    if (m_resetDefaultStateAction) m_resetDefaultStateAction->setEnabled(toSave && !toSave->getDefaultStateAttribute().isEmpty());
    if (m_overwriteBookmarkStateAction) m_overwriteBookmarkStateAction->setEnabled(toSave && !toSave->getBookmarkID().isEmpty());
    if (m_enableEditorAction) m_enableEditorAction->setEnabled(toSave && toSave->isEditor());
    if (m_zoomSelector) {
        m_zoomSelector->setVisible(toSave && toSave->isZoomable());
        if (toSave) {
            m_zoomSelector->setValue(toSave->zoomPosition());
            QWidget* widget = toSave->zoomableWidget();
            SKGTreeView* treeView = qobject_cast<SKGTreeView*>(widget);
            if (treeView) {
                disconnect(treeView, SIGNAL(zoomChanged(int)), m_zoomSelector, SLOT(setValue(int)));
                connect(treeView, SIGNAL(zoomChanged(int)), m_zoomSelector, SLOT(setValue(int)));
            } else {
                SKGWebView* webView = qobject_cast<SKGWebView*>(widget);
                if (webView) {
                    disconnect(webView, SIGNAL(zoomChanged(int)), m_zoomSelector, SLOT(setValue(int)));
                    connect(webView, SIGNAL(zoomChanged(int)), m_zoomSelector, SLOT(setValue(int)));
                }
            }
        }
    }

    if (m_actLock) m_actLock->setVisible(ui.kDockContext->features() == QDockWidget::AllDockWidgetFeatures);
    if (m_actUnLock) m_actUnLock->setVisible(ui.kDockContext->features() == QDockWidget::NoDockWidgetFeatures);

    if (m_previousAction) {
        QList<SKGTabPage::SKGPageHistoryItem> list;
        if (toSave) list = toSave->getPreviousPages();
        m_previousAction->setEnabled(list.count());
    }
    if (m_nextAction) {
        QList<SKGTabPage::SKGPageHistoryItem> list;
        if (toSave) list = toSave->getNextPages();
        m_nextAction->setEnabled(list.count());
    }

    //Set current selection of context
    ui.kContextList->clearSelection();
    if (toSave) {
        //Get plugin of current page
        SKGInterfacePlugin* plugin = getPluginByName(toSave->objectName());
        int index = (plugin ? plugin->property("contextItem").toInt() : -1);
        if (index != -1) ui.kContextList->setCurrentItem(ui.kContextList->item(index));
    }

    //Set window title
    QString modified;
    if (getDocument()->isFileModified()) modified += i18nc("Noun, indicate that current document is modified", " [modified]");
    if (getDocument()->isReadOnly()) modified += i18nc("Noun, indicate that current document is loaded in read only", " [read only]");
    QString fileName = getDocument()->getCurrentFileName();
    if (fileName.isEmpty()) fileName = i18nc("Noun, default name for a new document", "Untitled");
    setWindowTitle(i18nc("Title of the main window", "%1%2 - %3", fileName, modified, KGlobal::activeComponent().componentName()));

    QApplication::restoreOverrideCursor();
}

SKGTabPage::SKGPageHistoryItem SKGMainPanel::currentPageHistoryItem() const
{
    SKGTabPage::SKGPageHistoryItem page;
    int currentIndex = currentPageIndex();
    SKGTabPage* cPage = currentPage();
    if (currentIndex >= 0 && cPage) {
        page.plugin = cPage->objectName();
        SKGInterfacePlugin* plugin = SKGMainPanel::getMainPanel()->getPluginByName(page.plugin);
        if (plugin) {
            page.name = m_tabWidget->tabText(currentIndex);
            page.icon = plugin->icon();
        }
        page.state = cPage->getState();
        page.bookmarkID = cPage->getBookmarkID();
    }

    return page;
}

SKGTabPage* SKGMainPanel::openPage(SKGInterfacePlugin* plugin, int index, const QString& parameters, const QString& title, const QString& iID, bool iSetCurrent)
{
    SKGTRACEIN(1, "SKGMainPanel::openPage");
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    bool previous = m_tabWidget->blockSignals(true);
    SKGTabPage* w = NULL;

    QList<SKGTabPage::SKGPageHistoryItem> previousPages;

    if (index != -1) {
        int currentIndex = currentPageIndex();
        SKGTabPage* cPage = currentPage();
        if (currentIndex >= 0 && cPage) {
            previousPages = cPage->getPreviousPages();
            previousPages.insert(0, currentPageHistoryItem());

            m_tabWidget->removeTab(currentIndex);
            closePage(cPage);
        }
    }

    if (plugin) {
        w = plugin->getWidget();
        if (w) {
            //Title
            QString title2 = (title.isEmpty() ? plugin->title() : title);
            w->setObjectName(plugin->objectName());
            if (!iID.isEmpty()) w->setBookmarkID(iID);

            QString param = parameters;
            if (param.isEmpty()) {
                QString def = w->getDefaultStateAttribute();
                if (!def.isEmpty()) {
                    param = getDocument()->getParameter(def);
                }
            }
            SKGTRACEL(10) << "state=[" << param << "]" << endl;
            w->setState(param);
            connect(w, SIGNAL(selectionChanged()), SLOT(refresh()));

            if (index == -1) {
                SKGTRACEIN(20, "SKGMainPanel::openPage-addTab");
                m_tabWidget->addTab(w, KIcon(plugin->icon()), title2);
                if (iSetCurrent) m_tabWidget->setCurrentWidget(w);
            } else {
                SKGTRACEIN(20, "SKGMainPanel::openPage-insertTab");
                m_tabWidget->insertTab(index, w, KIcon(plugin->icon()), title2);
                if (iSetCurrent) m_tabWidget->setCurrentWidget(w);

                w->setPreviousPages(previousPages);
                QList<SKGTabPage::SKGPageHistoryItem> empty;
                w->setNextPages(empty);
            }
            SKGTRACEL(1) << "opening plugin [" << plugin->objectName() << ']' << endl;
        }
    } else {
        getDocument()->sendMessage(i18nc("An information message",  "Impossible to open the page because the plugin was not found"));
        notify(); //Due to sendMessage not in a transaction
    }
    m_tabWidget->blockSignals(previous);
    if (iSetCurrent) Q_EMIT currentPageChanged();
    QApplication::restoreOverrideCursor();
    return w;
}

int SKGMainPanel::currentPageIndex() const
{
    return m_tabWidget->currentIndex();
}

SKGTabPage* SKGMainPanel::currentPage() const
{
    return (SKGTabPage*) m_tabWidget->currentWidget();
}

KSplashScreen* SKGMainPanel::splashScreen() const
{
    return m_splashScreen;
}

int SKGMainPanel::countPages() const
{
    return m_tabWidget->count();
}

SKGTabPage* SKGMainPanel::page(int iIndex) const
{
    return (SKGTabPage*) m_tabWidget->widget(iIndex);
}

void SKGMainPanel::setCurrentPage(int iIndex)
{
    m_tabWidget->setCurrentIndex(iIndex);
}

void SKGMainPanel::onBeforeOpenContext()
{
    m_middleClick = QApplication::mouseButtons() & Qt::MidButton;
}

void SKGMainPanel::openPage(int iPage, bool iNewPage)
{
    SKGTRACEIN(1, "SKGMainPanel::openPage");
    SKGTRACEL(1) << "iPage=" << iPage << endl;
    int index = ui.kContextList->item(iPage)->data(12).toInt();
    openPage(getPluginByIndex(index), iNewPage ? -1 : currentPageIndex());
}

void SKGMainPanel::onOpenContext(Qt::MouseButtons iMouse, Qt::KeyboardModifiers iKeyboard)
{
    SKGTRACEIN(1, "SKGMainPanel::onOpenContext");
    int page = -1;
    QAction* sender = qobject_cast<QAction*>(this->sender());
    if (sender) page = sender->data().toInt();
    else page = ui.kContextList->currentRow();
    if (page != -1) openPage(page, QApplication::keyboardModifiers() &Qt::ControlModifier || m_middleClick || iMouse & Qt::MidButton || iKeyboard & Qt::ControlModifier);
    m_middleClick = false;
}

void SKGMainPanel::closePage(QWidget* iWidget)
{
    SKGTRACEIN(1, "SKGMainPanel::closePage");
    if (getDocument()->getCurrentTransaction()) {
        QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
        KMessageBox::information(this, i18nc("Question", "A page cannot be closed when an operation is running."));
        QApplication::restoreOverrideCursor();
    } else {
        QWidget* toRemove = iWidget;
        if (toRemove == NULL)  toRemove = m_tabWidget->currentWidget();
        if (toRemove) {
            ((SKGTabPage*) toRemove)->close();
            delete toRemove;
        }
    }
}

void SKGMainPanel::closeAllPages()
{
    SKGTRACEIN(1, "SKGMainPanel::closeAllPages");
    bool previous = m_tabWidget->blockSignals(true);
    int nb = m_tabWidget->count();
    for (int i = nb - 1; i >= 0; --i) {
        closePage(m_tabWidget->widget(i));
    }
    m_tabWidget->blockSignals(previous);
    Q_EMIT currentPageChanged();
}

void SKGMainPanel::closeAllOtherPages(QWidget* iWidget)
{
    SKGTRACEIN(1, "SKGMainPanel::closeAllOtherPages");
    bool previous = m_tabWidget->blockSignals(true);
    QWidget* toKeep = iWidget;
    if (toKeep == NULL)  toKeep = m_tabWidget->currentWidget();

    int nb = m_tabWidget->count();
    for (int i = nb - 1; i >= 0; --i) {
        QWidget* w = m_tabWidget->widget(i);
        if (w != toKeep) closePage(w);
    }
    m_tabWidget->blockSignals(previous);
    Q_EMIT currentPageChanged();
}

void SKGMainPanel::saveDefaultState()
{
    SKGTRACEIN(1, "SKGMainPanel::saveDefaultState");
    SKGError err;
    SKGTabPage* toSave = (SKGTabPage*) m_tabWidget->currentWidget();
    if (toSave) {
        //Get bookmarks uuid
        QString uuid = toSave->getBookmarkID();

        //Reset bookmarks uuid to overwrite page state
        toSave->setBookmarkID("");

        //Overwrite
        toSave->overwrite(false);

        //Set original bookmarks uuid
        toSave->setBookmarkID(uuid);
    }
}

void SKGMainPanel::overwriteBookmarkState()
{
    SKGTRACEIN(1, "SKGMainPanel::overwriteBookmarkState");
    SKGError err;
    SKGTabPage* toSave = (SKGTabPage*) m_tabWidget->currentWidget();
    if (toSave) {
        //Get bookmarks uuid
        QString uuid = toSave->getBookmarkID();
        if (!uuid.isEmpty()) {
            //Overwrite
            toSave->overwrite(false);
        }
    }
}

void SKGMainPanel::resetDefaultState()
{
    SKGTRACEIN(1, "SKGMainPanel::resetDefaultState");
    SKGError err;
    SKGTabPage* toSave = (SKGTabPage*) m_tabWidget->currentWidget();
    if (toSave) {
        QString name = toSave->getDefaultStateAttribute();
        if (!name.isEmpty()) {
            SKGBEGINLIGHTTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Reset default state"), err);
            err = getDocument()->setParameter(name, "<!DOCTYPE SKGML>");

            //Refresh panel
            if (!err) toSave->setState("");
        }
    }

    //status bar
    if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Default state has been reset"));
    displayErrorMessage(err);
}

void SKGMainPanel::addTab()
{
    SKGTRACEIN(1, "SKGMainPanel::addTab");
    SKGTabPage* cPage = currentPage();
    if (cPage) openPage(getPluginByName(cPage->objectName()));
}

bool SKGMainPanel::eventFilter(QObject* object, QEvent* event)
{
    if (event && object) {
        QResizeEvent* resizeEvent = dynamic_cast<QResizeEvent*>(event);
        if (resizeEvent) {
            QSize newSize = resizeEvent->size();

            //Compute icon size
            int s = qMax(qMin(newSize.width() / 5, 64), 16);
            ui.kContextList->setIconSize(QSize(s, s));
        }
    }
    return false;
}

QString SKGMainPanel::getTipOfDayFileName()
{
    return m_tipsFile.fileName();
}

void SKGMainPanel::onTipOfDay()
{
    SKGTRACEIN(1, "SKGMainPanel::onTipOfDay");
    KTipDatabase* tipDatabase = new KTipDatabase(getTipOfDayFileName()); //This pointer is deleted by destructor of KTipDialog
    KTipDialog* tipsDialog = new KTipDialog(tipDatabase, this);
    tipsDialog->setAttribute(Qt::WA_DeleteOnClose);
    tipsDialog->show();
}

void SKGMainPanel::onTrayActivated(QSystemTrayIcon::ActivationReason reason)
{
    SKGTRACEIN(1, "SKGMainPanel::onTrayActivated");
    if (reason == KSystemTrayIcon::Trigger) {
        setVisible(!isVisible());
    }
}

void SKGMainPanel::notify(int iTransaction)
{
    SKGTRACEIN(1, "SKGMainPanel::notify");
    SKGTRACEL(1) << "iTransaction=" << iTransaction << endl;

    //Notify
    SKGObjectBase transaction(getDocument(), "doctransaction", iTransaction);
    if (iTransaction == 0 || transaction.getAttribute("t_mode") != "R") {
        QStringList msg;
        getDocument()->getMessages(iTransaction, msg, false);
        int nbMessages = msg.count();
        if (nbMessages) {
            //Build message
            QString message;
            for (int i = 0; i < nbMessages; ++i) {
                if (i != 0) message += "<br>";
                message += msg.at(i);
            }

            if (nbMessages < 20) {
                //Display a simple notification
                KNotification* notify = new KNotification(KCmdLineArgs::appName() % "_info_event" , this);
                notify->setText(message);
                notify->sendEvent();
            } else {
                //Too many message, display a warning panel
                KMessageBox::information(SKGMainPanel::getMainPanel(), message, i18nc("Noun",  "Notification"));
            }
        }
    }
}

void SKGMainPanel::changeEvent(QEvent* e)
{
    KParts::MainWindow::changeEvent(e);
}

bool SKGMainPanel::iconInSystemtray()
{
    return skgbasegui_settings::icon_in_system_tray();
}

QLabel* SKGMainPanel::statusNormalMessage() const
{
    return m_kNormalMessage;
}

void SKGMainPanel::displayErrorMessage(const SKGError& iError)
{
    SKGTRACEIN(1, "SKGMainPanel::displayErrorMessage");
    SKGMainPanel* parent = SKGMainPanel::getMainPanel();
    if (parent) {
        if (iError) {
            QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
            int rc = KMessageBox::Cancel;
            if (iError.getHistoricalSize()) rc = KMessageBox::warningContinueCancel(parent, iError.getFullMessage(),
                                                     i18nc("Question",  "Error"),
                                                     KStandardGuiItem::cont(),
                                                     KGuiItem(i18nc("Noun", "History"), KIcon("dialog-information")));
            if (rc == KMessageBox::Cancel) {
                KMessageBox::error(parent, iError.getFullMessageWithHistorical(), i18nc("Noun", "Error"));
            }
            QApplication::restoreOverrideCursor();
        } else {
            //Status bar
            QLabel* label = parent->statusNormalMessage();
            QString message = iError.getMessage();
            if (label && !message.isEmpty()) label->setText(message);
        }
    }
}

void SKGMainPanel::onCancelCurrentAction()
{
    SKGMainPanel::m_currentActionCanceled = true;
}

void SKGMainPanel::onQuitAction()
{
    //Bug 2777697: To be sure that all page modifications are closed
    closeAllPages();
    //Bug 2777697:

    qApp->closeAllWindows();
}

int SKGMainPanel::progressBarCallBack(int iPos, qint64 iTime, const QString& iName, void* iProgressBar)
{
    Q_UNUSED(iTime);
    QProgressBar* progressBar = NULL;
    QPushButton* button = NULL;
    doublePointer* pointers = (doublePointer*) iProgressBar;
    if (pointers) {
        progressBar = static_cast<QProgressBar*>(pointers->p1);
        button = static_cast<QPushButton*>(pointers->p2);
    }

    bool visible = (iPos > 0 && iPos <= 100);
    if (progressBar) {
        QString commonFormat = "%p%";
        /*if (iPos > 0) {
            qint64 estimatedTime = 100 * iTime / iPos;
            qint64 remainingTime = estimatedTime - iTime;
            commonFormat = commonFormat % " - " % i18nc("To print a remaining time (in seconde) / estimated time (in second)", "%1s / %2s",
                           SKGServices::intToString(remainingTime / 1000),
                           SKGServices::intToString(estimatedTime / 1000));
        }*/
        progressBar->setFormat(iName.isEmpty() ? commonFormat : commonFormat % '\n' % iName);
        progressBar->setValue(iPos);
        progressBar->setVisible(visible);
        if (iPos == 100) QTimer::singleShot(300, progressBar, SLOT(hide()));
        progressBar->setToolTip(iName);
    }
    if (button) {
        button->setVisible(visible);
        if (iPos == 100) QTimer::singleShot(300, button, SLOT(hide()));
    }


    SKGMainPanel::m_currentActionCanceled = false;
    if (iPos != 0 && iPos != 100) qApp->processEvents(QEventLoop::AllEvents, 500);
    return (SKGMainPanel::m_currentActionCanceled ? 1 : 0);
}

QString SKGMainPanel::getSaveFileName(const QString& startDir, const QString& filter, QWidget* parent, const QString& caption, QString* iCodec)
{
    QString fileName;
    if (iCodec) {
        QString lastCodecUsed = QTextCodec::codecForLocale()->name();
        KEncodingFileDialog::Result result = KEncodingFileDialog::getSaveFileNameAndEncoding(lastCodecUsed, startDir, filter , parent, caption);
        if (result.fileNames.count()) fileName = result.fileNames.at(0);
        *iCodec = result.encoding;
    } else {
        fileName = KFileDialog::getSaveFileName(KUrl(startDir), filter , parent, caption);
    }
    if (fileName.isEmpty()) return "";
    QFile f(fileName);
    if (f.exists() && KMessageBox::warningContinueCancel(parent,
            i18nc("Question", "File <b>%1</b> already exists. Do you really want to overwrite it?", fileName),
            i18nc("Question", "Warning"),
            KGuiItem(i18nc("Verb",  "Save"), KIcon("document-save"))) != KMessageBox::Continue) return "";

    return fileName;
}

void SKGMainPanel::fillWithDistinctValue(
    QWidget* iWidget,
    SKGDocument* iDoc,
    const QString& iTable,
    const QString& iAttribut,
    const QString& iWhereClause,
    bool iAddoperators)
{
    SKGTRACEIN(10, "SKGMainPanel::fillWithDistinctValue");

    if (iWidget && iDoc) {
        //Get list
        QStringList list;
        iDoc->getDistinctValues(iTable, iAttribut, iWhereClause, list);
        if (list.count() && !list.at(0).isEmpty()) list.insert(0, "");

        //Sorting list
        //Correction bug 202341 vvv
        qSort(list.begin(), list.end(), naturalLessThan);
        //Correction bug 202341 ^^^

        //Fill completion
        KCompletion* comp = NULL;
        KComboBox* kcmb = qobject_cast<KComboBox*> (iWidget);
        if (kcmb) {
            //Fill combo
            kcmb->clear();
            kcmb->addItems(list);

            comp = kcmb->completionObject();
        } else {
            KLineEdit* kline = qobject_cast<KLineEdit*> (iWidget);
            if (kline) comp = kline->completionObject();
        }

        //Add operator
        if (iAddoperators) {
            list.push_back('=' % i18nc("Key word to modify a string into a field", "capitalize"));
            list.push_back('=' % i18nc("Key word to modify a string into a field", "capwords"));
            list.push_back('=' % i18nc("Key word to modify a string into a field", "lower"));
            list.push_back('=' % i18nc("Key word to modify a string into a field", "trim"));
            list.push_back('=' % i18nc("Key word to modify a string into a field", "upper"));
        }

        if (comp) {
            comp->setIgnoreCase(true);
            comp->setSoundsEnabled(true);
            comp->clear();
            comp->insertItems(list);
        }
    }
}

bool SKGMainPanel::naturalLessThan(const QString& s1, const QString& s2)
{
    return (KStringHandler::naturalCompare(s1, s2, Qt::CaseInsensitive) < 0);
}

bool SKGMainPanel::adviceLessThan(const SKGAdvice& s1, const SKGAdvice& s2)
{
    return (s1.getPriority() > s2.getPriority());
}

SKGMainPanel* SKGMainPanel::getMainPanel()
{
    return m_mainPanel;
}

void SKGMainPanel::onZoomChanged()
{
    SKGTabPage* toSave = currentPage();
    if (toSave) {
        toSave->setZoomPosition(m_zoomSelector->value());
        m_zoomSelector->setValue(toSave->zoomPosition()); //In case of a limit is reached
    }
}

#include "skgmainpanel.moc"
