File indexing completed on 2024-05-19 12:54:51

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
0003    Copyright (C) 2003-2018 Jarosław Staniek <staniek@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "KexiMainWindow.h"
0022 #include "KexiMainWindow_p.h"
0023 #include "kexiactionproxy.h"
0024 #include "kexipartmanager.h"
0025 #include "kexipart.h"
0026 #include "kexipartinfo.h"
0027 #include "kexipartguiclient.h"
0028 #include "kexiproject.h"
0029 #include "kexiprojectdata.h"
0030 #include "kexi.h"
0031 #include "kexiinternalpart.h"
0032 #include "kexiactioncategories.h"
0033 #include "kexifinddialog.h"
0034 #include "kexisearchandreplaceiface.h"
0035 #include "KexiBugReportDialog.h"
0036 #define KEXI_SKIP_REGISTERICONSRESOURCE
0037 #define KEXI_SKIP_SETUPPRIVATEICONSRESOURCE
0038 #include "KexiRegisterResource_p.h"
0039 #include "KexiObjectViewWidget.h"
0040 #include "KexiObjectViewTabWidget.h"
0041 #include <kexiutils/utils.h>
0042 #include <kexiutils_global.h>
0043 #include <KexiStyle.h>
0044 #include <kexiutils/KexiCloseButton.h>
0045 #include <kexiutils/KexiTester.h>
0046 #include <KexiVersion.h>
0047 #include <core/KexiWindow.h>
0048 #include <core/KexiRecentProjects.h>
0049 #include <core/kexiaboutdata.h>
0050 #include <core/KexiCommandLineOptions.h>
0051 #include <KexiIcon.h>
0052 #include <kexi_global.h>
0053 #include <KexiPropertyPaneWidget.h>
0054 #include <widget/utils/kexirecordnavigator.h>
0055 #include <widget/utils/KexiDockableWidget.h>
0056 #include <widget/navigator/KexiProjectNavigator.h>
0057 #include <widget/navigator/KexiProjectModel.h>
0058 #include <widget/KexiNameDialog.h>
0059 #include <widget/KexiNameWidget.h>
0060 #include <widget/KexiDBPasswordDialog.h>
0061 #include "startup/KexiStartup.h"
0062 #include "startup/KexiNewProjectAssistant.h"
0063 #include "startup/KexiOpenProjectAssistant.h"
0064 #include "startup/KexiWelcomeAssistant.h"
0065 #include "startup/KexiImportExportAssistant.h"
0066 #include <KexiAssistantPage.h>
0067 
0068 #include <KDbConnection>
0069 #include <KDbConnectionOptions>
0070 #include <KDbCursor>
0071 #include <KDbAdmin>
0072 #include <KDbDriverManager>
0073 #include <KDbObjectNameValidator>
0074 
0075 #include <KPropertyEditorView>
0076 #include <KPropertySet>
0077 
0078 #include <KActionCollection>
0079 #include <KActionMenu>
0080 #include <KToggleAction>
0081 #include <KStandardShortcut>
0082 #include <KStandardGuiItem>
0083 #include <KConfig>
0084 #include <KShortcutsDialog>
0085 #include <KEditToolBar>
0086 #include <KToggleFullScreenAction>
0087 #include <KIconLoader>
0088 #include <KHelpMenu>
0089 #include <KMultiTabBar>
0090 #include <KLocalizedString>
0091 #include <KMessageBox>
0092 #include <KConfigGroup>
0093 #include <KAcceleratorManager>
0094 
0095 #include <QApplication>
0096 #include <QFile>
0097 #include <QProcess>
0098 #include <QToolButton>
0099 #include <QDebug>
0100 #include <QHash>
0101 #include <QStylePainter>
0102 #include <QStyleFactory>
0103 #include <QDesktopWidget>
0104 #include <QResource>
0105 #include <QMenuBar>
0106 
0107 #if !defined(KexiVDebug)
0108 # define KexiVDebug if (0) qDebug()
0109 #endif
0110 
0111 #ifdef HAVE_KCRASH
0112 #include <kcrash.h>
0113 //! @todo else, add Breakpad? https://phabricator.kde.org/T1642
0114 #endif
0115 
0116 KexiDockWidgetStyle::KexiDockWidgetStyle(const QString &baseStyleName)
0117  : QProxyStyle(baseStyleName)
0118 {
0119 }
0120 
0121 KexiDockWidgetStyle::~KexiDockWidgetStyle()
0122 {
0123 }
0124 
0125 void KexiDockWidgetStyle::polish(QWidget* widget)
0126 {
0127     baseStyle()->polish(widget);
0128     widget->setContentsMargins(0, 0, 0, 0);
0129 }
0130 
0131 class Q_DECL_HIDDEN KexiDockWidget::Private
0132 {
0133 public:
0134     Private() {}
0135     QSize hint;
0136 };
0137 
0138 KexiDockWidget::KexiDockWidget(const QString &_tabText, QWidget *parent)
0139         : QDockWidget(parent), tabText(_tabText), d(new Private)
0140 {
0141     // No floatable dockers, Dolphin had problems, we don't want the same...
0142     // https://bugs.kde.org/show_bug.cgi?id=288629
0143     // https://bugs.kde.org/show_bug.cgi?id=322299
0144     setFeatures(QDockWidget::NoDockWidgetFeatures);//DockWidgetClosable);
0145     setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea);
0146     setFocusPolicy(Qt::NoFocus);
0147     if (style()->objectName().compare("windowsvista", Qt::CaseInsensitive) == 0) {
0148         // windowsvista style has broken accelerator visualization support
0149         KAcceleratorManager::setNoAccel(this);
0150     }
0151     KexiDockWidgetStyle *customStyle = new KexiDockWidgetStyle(style()->objectName());
0152     customStyle->setParent(this);
0153     setStyle(customStyle);
0154     setTitleBarWidget(new QWidget(this)); // hide the title
0155     layout()->setContentsMargins(0, 0, 0, 0);
0156     layout()->setSpacing(0);
0157 }
0158 
0159 KexiDockWidget::~KexiDockWidget()
0160 {
0161     delete d;
0162 }
0163 
0164 void KexiDockWidget::paintEvent(QPaintEvent *pe)
0165 {
0166     Q_UNUSED(pe);
0167     QStylePainter p(this);
0168     if (isFloating()) {
0169         QStyleOptionFrame framOpt;
0170         framOpt.initFrom(this);
0171         p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
0172     }
0173 
0174     // Title must be painted after the frame, since the areas overlap, and
0175     // the title may wish to extend out to all sides (eg. XP style)
0176     QStyleOptionDockWidget titleOpt;
0177     initStyleOption(&titleOpt);
0178     p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
0179 }
0180 
0181 void KexiDockWidget::setSizeHint(const QSize& hint)
0182 {
0183     d->hint = hint;
0184 }
0185 
0186 QSize KexiDockWidget::sizeHint() const
0187 {
0188     return d->hint.isValid() ? d->hint : QDockWidget::sizeHint();
0189 }
0190 
0191 //-------------------------------------------------
0192 
0193 static bool setupIconTheme(KLocalizedString *errorMessage, KLocalizedString *detailsErrorMessage)
0194 {
0195     // Register kexi resource first to have priority over the standard breeze theme.
0196     // For example "table" icon exists in both resources.
0197     if (!registerResource("icons/kexi_breeze.rcc", QStandardPaths::AppDataLocation,
0198                           QString(), QString(), errorMessage, detailsErrorMessage)
0199         || !registerGlobalBreezeIconsResource(errorMessage, detailsErrorMessage))
0200     {
0201         return false;
0202     }
0203     setupBreezeIconTheme();
0204 
0205     // tell KIconLoader an co. about the theme
0206     KConfigGroup cg(KSharedConfig::openConfig(), "Icons");
0207     cg.writeEntry("Theme", "breeze");
0208     cg.sync();
0209     return true;
0210 }
0211 
0212 //! @todo 3.1 replace with KexiStyle
0213 bool setupApplication()
0214 {
0215 #if defined Q_OS_WIN || defined Q_OS_MACOS
0216     // Only this style matches current KEXI theme and can be supported/tested
0217     const char *name = "breeze";
0218     QScopedPointer<QStyle> style(QStyleFactory::create(name));
0219     if (!style || style->objectName() != name) {
0220         qWarning() <<
0221              qPrintable(QString("Could not find application style %1. "
0222                                 "KEXI will not start. Please check if KEXI is properly installed. ")
0223                                 .arg(name));
0224          return false;
0225      }
0226      qApp->setStyle(style.take());
0227 #endif
0228      return true;
0229 }
0230 
0231 //static
0232 int KexiMainWindow::create(const QStringList &arguments, const QString &componentName,
0233                            const QList<QCommandLineOption> &extraOptions)
0234 {
0235     qApp->setQuitOnLastWindowClosed(false);
0236 
0237     KLocalizedString::setApplicationDomain("kexi");
0238     //! @todo KEXI3 app->setAttribute(Qt::AA_UseHighDpiPixmaps, true);
0239 
0240     KexiAboutData aboutData;
0241     if (!componentName.isEmpty()) {
0242         aboutData.setComponentName(componentName);
0243     }
0244     KAboutData::setApplicationData(aboutData);
0245 
0246     if (!setupApplication()) {
0247         return 1;
0248     }
0249 
0250 #ifdef HAVE_KCRASH
0251     KCrash::initialize();
0252 #endif
0253 
0254     KLocalizedString errorMessage;
0255     KLocalizedString detailsErrorMessage;
0256     if (!setupIconTheme(&errorMessage, &detailsErrorMessage)
0257         || !KexiStyle::setupApplication(&errorMessage))
0258     {
0259         if (detailsErrorMessage.isEmpty()) {
0260             KMessageBox::error(nullptr, errorMessage.toString());
0261         } else {
0262             KMessageBox::detailedError(nullptr, errorMessage.toString(), detailsErrorMessage.toString());
0263         }
0264         qWarning() << qPrintable(errorMessage.toString(Kuit::PlainText));
0265         return 1;
0266     }
0267     QApplication::setWindowIcon(koIcon("kexi"));
0268 
0269     const tristate res = KexiStartupHandler::global()->init(arguments, extraOptions);
0270     if (!res || ~res) {
0271         return (~res) ? 0 : 1;
0272     }
0273     //qDebug() << "startupActions OK";
0274 
0275     /* Exit requested, e.g. after database removing. */
0276     if (KexiStartupHandler::global()->action() == KexiStartupData::Exit) {
0277         return 0;
0278     }
0279 
0280     KexiMainWindow *win = new KexiMainWindow();
0281 #ifdef KEXI_DEBUG_GUI
0282     KConfigGroup generalGroup = KSharedConfig::openConfig()->group("General");
0283     if (generalGroup.readEntry("ShowInternalDebugger", false)) {
0284         QWidget* debugWindow = KexiUtils::createDebugWindow(win);
0285         debugWindow->show();
0286     }
0287 #endif
0288 
0289     if (true != win->startup()) {
0290         delete win;
0291         return 1;
0292     }
0293 
0294     win->restoreSettings();
0295     win->show();
0296 #ifdef KEXI_DEBUG_GUI
0297     win->raise();
0298     static_cast<QWidget*>(win)->activateWindow();
0299 #endif
0300     /*foreach (QWidget *widget, QApplication::topLevelWidgets()) {
0301         qDebug() << widget;
0302     }*/
0303     return 0;
0304 }
0305 
0306 //-------------------------------------------------
0307 
0308 KexiMainMenuActionShortcut::KexiMainMenuActionShortcut(const QKeySequence& key,
0309                                                        QAction *action, QWidget *parent)
0310     : QShortcut(key, parent)
0311     , m_action(action)
0312 {
0313     connect(this, SIGNAL(activated()), this, SLOT(slotActivated()));
0314 }
0315 
0316 KexiMainMenuActionShortcut::~KexiMainMenuActionShortcut()
0317 {
0318 }
0319 
0320 void KexiMainMenuActionShortcut::slotActivated()
0321 {
0322     if (!m_action->isEnabled()) {
0323         return;
0324     }
0325     m_action->trigger();
0326 }
0327 
0328 //-------------------------------------------------
0329 
0330 KexiMainWindow::KexiMainWindow(QWidget *parent)
0331         : QMainWindow(parent)
0332         , KexiMainWindowIface()
0333         , KexiGUIMessageHandler(this)
0334         , d(new KexiMainWindow::Private(this))
0335 {
0336     setObjectName("KexiMainWindow");
0337     setAttribute(Qt::WA_DeleteOnClose);
0338     kexiTester() << KexiTestObject(this);
0339 
0340     if (d->userMode) {
0341         //qDebug() << "starting up in the User Mode";
0342     }
0343     setAsDefaultHost(); //this is default host now.
0344 
0345     //get informed
0346     connect(&Kexi::partManager(), SIGNAL(partLoaded(KexiPart::Part*)),
0347             this, SLOT(slotPartLoaded(KexiPart::Part*)));
0348     connect(&Kexi::partManager(), SIGNAL(newObjectRequested(KexiPart::Info*)),
0349             this, SLOT(newObject(KexiPart::Info*)));
0350 
0351     setAcceptDrops(true);
0352     setupActions();
0353     setupMainWidget();
0354     setupMainMenu();
0355     updateAppCaption();
0356 
0357     if (!d->userMode) {
0358         setupContextHelp();
0359         //setupPropertyEditor();
0360     }
0361 
0362     invalidateActions();
0363     d->timer.singleShot(0, this, SLOT(slotLastActions()));
0364     if (KexiStartupHandler::global()->forcedFullScreen()) {
0365         toggleFullScreen(true);
0366     }
0367 
0368     // --- global config
0369     //! @todo move to specialized KexiConfig class
0370     KConfigGroup tablesGroup(d->config->group("Tables"));
0371     const int defaultMaxLengthForTextFields = tablesGroup.readEntry("DefaultMaxLengthForTextFields", int(-1));
0372     if (defaultMaxLengthForTextFields >= 0) {
0373         KDbField::setDefaultMaxLength(defaultMaxLengthForTextFields);
0374     }
0375     // --- /global config
0376 }
0377 
0378 KexiMainWindow::~KexiMainWindow()
0379 {
0380     d->forceWindowClosing = true;
0381     closeProject();
0382     delete d;
0383     Kexi::deleteGlobalObjects();
0384 }
0385 
0386 KexiProject *KexiMainWindow::project()
0387 {
0388     return d->prj;
0389 }
0390 
0391 QList<QAction*> KexiMainWindow::allActions() const
0392 {
0393     return actionCollection()->actions();
0394 }
0395 
0396 KActionCollection *KexiMainWindow::actionCollection() const
0397 {
0398     return d->actionCollection;
0399 }
0400 
0401 KexiWindow* KexiMainWindow::currentWindow() const
0402 {
0403     if (!d->objectViewWidget || !d->objectViewWidget->tabWidget()) {
0404         return 0;
0405     }
0406     return windowForTab(d->objectViewWidget->tabWidget()->currentIndex());
0407 }
0408 
0409 KexiWindow* KexiMainWindow::windowForTab(int tabIndex) const
0410 {
0411     if (!d->objectViewWidget || !d->objectViewWidget->tabWidget())
0412         return 0;
0413     return d->objectViewWidget->tabWidget()->window(tabIndex);
0414 }
0415 
0416 void KexiMainWindow::setupMainMenuActionShortcut(QAction * action)
0417 {
0418     if (!action->shortcut().isEmpty()) {
0419         //foreach(const QKeySequence &shortcut, action->shortcuts()) {
0420             //(void)new KexiMainMenuActionShortcut(shortcut, action, this);
0421         //}
0422     }
0423 }
0424 
0425 static void addThreeDotsToActionText(QAction* action)
0426 {
0427     action->setText(xi18nc("Action name with three dots...", "%1...", action->text()));
0428 }
0429 
0430 QAction * KexiMainWindow::addAction(const char *name, const QIcon &icon, const QString& text,
0431                                    const char *shortcut)
0432 {
0433     QAction *action = icon.isNull() ? new QAction(text, this) : new QAction(icon, text, this);
0434     actionCollection()->addAction(name, action);
0435     if (shortcut) {
0436         action->setShortcut(QKeySequence(shortcut));
0437         action->setShortcutContext(Qt::ApplicationShortcut);
0438         //QShortcut *s = new QShortcut(action->shortcut(), this);
0439         //connect(s, SIGNAL(activated()), action, SLOT(trigger()));
0440     }
0441     return action;
0442 }
0443 
0444 QAction * KexiMainWindow::addAction(const char *name, const QString& text, const char *shortcut)
0445 {
0446     return addAction(name, QIcon(), text, shortcut);
0447 }
0448 
0449 void KexiMainWindow::setupActions()
0450 {
0451     KActionCollection *ac = actionCollection();
0452 
0453     // PROJECT MENU
0454     QAction *action;
0455 
0456     ac->addAction("project_new",
0457         action = new KexiMenuWidgetAction(KStandardAction::New, this));
0458     action->setText(xi18n("&New Project..."));
0459     action->setShortcuts(KStandardShortcut::openNew());
0460     action->setToolTip(xi18n("Create a new project"));
0461     action->setWhatsThis(
0462         xi18n("Creates a new project. Currently opened project is not affected."));
0463     connect(action, SIGNAL(triggered()), this, SLOT(slotProjectNew()));
0464     setupMainMenuActionShortcut(action);
0465 
0466     ac->addAction("project_open",
0467             action = new KexiMenuWidgetAction(KStandardAction::Open, this));
0468     action->setText(xi18n("&Open Project..."));
0469     action->setIcon(koIcon("project-open"));
0470     action->setToolTip(xi18n("Open an existing project"));
0471     action->setWhatsThis(
0472         xi18n("Opens an existing project. Currently opened project is not affected."));
0473     connect(action, SIGNAL(triggered()), this, SLOT(slotProjectOpen()));
0474     setupMainMenuActionShortcut(action);
0475 
0476     ac->addAction("project_open_recent",
0477                   action = KStandardAction::openRecent(this, SLOT(slotProjectOpen()), this));
0478     action->setToolTip(xi18n("Open a project that was recently opened."));
0479     action->setWhatsThis(xi18n("Opens a project that was recently opened."));
0480 
0481     {
0482         ac->addAction("project_welcome",
0483             action = d->action_project_welcome = new KexiMenuWidgetAction(
0484                 QIcon(), xi18n("Welcome"), this));
0485             addThreeDotsToActionText(action);
0486         connect(action, SIGNAL(triggered()), this, SLOT(slotProjectWelcome()));
0487         setupMainMenuActionShortcut(action);
0488         action->setToolTip(xi18n("Show Welcome page"));
0489         action->setWhatsThis(
0490             xi18n("Shows Welcome page with list of recently opened projects and other information. "));
0491     }
0492 
0493     ac->addAction("project_save",
0494                   d->action_save = KStandardAction::save(this, SLOT(slotProjectSave()), this));
0495     d->action_save->setToolTip(xi18n("Save object changes"));
0496     d->action_save->setWhatsThis(xi18n("Saves object changes from currently selected window."));
0497     setupMainMenuActionShortcut(d->action_save);
0498 
0499     d->action_save_as = addAction("project_saveas", koIcon("document-save-as"),
0500                                   xi18n("Save &As..."));
0501     d->action_save_as->setToolTip(xi18n("Save object as"));
0502     d->action_save_as->setWhatsThis(
0503         xi18n("Saves object from currently selected window under a new name (within the same project)."));
0504     connect(d->action_save_as, SIGNAL(triggered()), this, SLOT(slotProjectSaveAs()));
0505 
0506 #ifdef KEXI_SHOW_UNIMPLEMENTED
0507     ac->addAction("project_properties",
0508         action = d->action_project_properties = new KexiMenuWidgetAction(
0509             koIcon("document-properties"), futureI18n("Project Properties"), this));
0510     connect(action, SIGNAL(triggered()), this, SLOT(slotProjectProperties()));
0511     setupMainMenuActionShortcut(action);
0512 #else
0513     d->action_project_properties = d->dummy_action;
0514 #endif
0515 
0516     //! @todo replace document-import icon with something other
0517     ac->addAction("project_import_export_send",
0518         action = d->action_project_import_export_send = new KexiMenuWidgetAction(
0519             koIcon("document-import"), xi18n("&Import, Export or Send..."), this));
0520     action->setToolTip(xi18n("Import, export or send project"));
0521     action->setWhatsThis(
0522         xi18n("Imports, exports or sends project."));
0523     connect(action, SIGNAL(triggered()), this, SLOT(slotProjectImportExportOrSend()));
0524     setupMainMenuActionShortcut(action);
0525 
0526     ac->addAction("project_close",
0527         action = d->action_close = new KexiMenuWidgetAction(
0528             koIcon("project-development-close"), xi18n("&Close Project"), this));
0529     action->setToolTip(xi18n("Close the current project"));
0530     action->setWhatsThis(xi18n("Closes the current project."));
0531     connect(action, SIGNAL(triggered()), this, SLOT(slotProjectClose()));
0532     setupMainMenuActionShortcut(action);
0533 
0534     ac->addAction("quit",
0535                   action = new KexiMenuWidgetAction(KStandardAction::Quit, this));
0536     connect(action, SIGNAL(triggered()), this, SLOT(slotProjectQuit()));
0537     action->setWhatsThis(xi18nc("@info:whatsthis", "Quits <application>%1</application> application.",
0538                                QApplication::applicationDisplayName()));
0539     setupMainMenuActionShortcut(action);
0540 
0541 #ifdef KEXI_SHOW_UNIMPLEMENTED
0542     d->action_project_relations = addAction("project_relations", KexiIcon("database-relations"),
0543                                             futureI18n("&Relationships..."));
0544     d->action_project_relations->setToolTip(futureI18n("Project relationships"));
0545     d->action_project_relations->setWhatsThis(futureI18n("Shows project relationships."));
0546     connect(d->action_project_relations, SIGNAL(triggered()),
0547             this, SLOT(slotProjectRelations()));
0548 
0549 #else
0550     d->action_project_relations = d->dummy_action;
0551 #endif
0552     d->action_tools_import_project = addAction("tools_import_project", KexiIcon("database-import"),
0553                                                xi18n("&Import Database..."));
0554     d->action_tools_import_project->setToolTip(xi18n("Import entire database as a KEXI project"));
0555     d->action_tools_import_project->setWhatsThis(
0556         xi18n("Imports entire database as a KEXI project."));
0557     connect(d->action_tools_import_project, SIGNAL(triggered()),
0558             this, SLOT(slotToolsImportProject()));
0559 
0560     d->action_tools_data_import = addAction("tools_import_tables", koIcon("document-import"),
0561                                             xi18n("Import Tables..."));
0562     d->action_tools_data_import->setToolTip(xi18n("Import data from an external source into this project"));
0563     d->action_tools_data_import->setWhatsThis(xi18n("Imports data from an external source into this project."));
0564     connect(d->action_tools_data_import, SIGNAL(triggered()), this, SLOT(slotToolsImportTables()));
0565 
0566     d->action_tools_compact_database = addAction("tools_compact_database",
0567 //! @todo icon
0568                                                  koIcon("application-x-compress"),
0569                                                  xi18n("&Compact Database..."));
0570     d->action_tools_compact_database->setToolTip(xi18n("Compact the current database project"));
0571     d->action_tools_compact_database->setWhatsThis(
0572         xi18n("Compacts the current database project, so it will take less space and work faster."));
0573     connect(d->action_tools_compact_database, SIGNAL(triggered()),
0574             this, SLOT(slotToolsCompactDatabase()));
0575 
0576     if (d->userMode)
0577         d->action_project_import_data_table = 0;
0578     else {
0579         d->action_project_import_data_table = addAction("project_import_data_table",
0580             KexiIcon("document-empty"),
0581             /*! @todo: change to "file_import" with a table or so */
0582             xi18nc("Import->Table Data From File...", "Import Data From &File..."));
0583         d->action_project_import_data_table->setToolTip(xi18n("Import table data from a file"));
0584         d->action_project_import_data_table->setWhatsThis(xi18n("Imports table data from a file."));
0585         connect(d->action_project_import_data_table, SIGNAL(triggered()),
0586                 this, SLOT(slotProjectImportDataTable()));
0587     }
0588 
0589     d->action_project_export_data_table = addAction("project_export_data_table",
0590         KexiIcon("table"),
0591         /*! @todo: change to "file_export" with a table or so */
0592         xi18nc("Export->Table or Query Data to File...", "Export Data to &File..."));
0593     d->action_project_export_data_table->setToolTip(
0594         xi18n("Export data from the active table or query to a file"));
0595     d->action_project_export_data_table->setWhatsThis(
0596         xi18n("Exports data from the active table or query to a file."));
0597     connect(d->action_project_export_data_table, SIGNAL(triggered()),
0598             this, SLOT(slotProjectExportDataTable()));
0599 
0600 //! @todo new QAction(xi18n("From File..."), "document-open", 0,
0601 //!          this, SLOT(slotImportFile()), actionCollection(), "project_import_file");
0602 //! @todo new QAction(xi18n("From Server..."), "network-server-database", 0,
0603 //!          this, SLOT(slotImportServer()), actionCollection(), "project_import_server");
0604 
0605 #ifdef KEXI_SHOW_UNIMPLEMENTED
0606     ac->addAction("project_print",
0607                   d->action_project_print = KStandardAction::print(this, SLOT(slotProjectPrint()), this));
0608     d->action_project_print->setToolTip(futureI18n("Print data from the active table or query"));
0609     d->action_project_print->setWhatsThis(futureI18n("Prints data from the active table or query."));
0610 
0611     ac->addAction("project_print_preview",
0612                   d->action_project_print_preview = KStandardAction::printPreview(
0613                                                         this, SLOT(slotProjectPrintPreview()), this));
0614     d->action_project_print_preview->setToolTip(
0615         futureI18n("Show print preview for the active table or query"));
0616     d->action_project_print_preview->setWhatsThis(
0617         futureI18n("Shows print preview for the active table or query."));
0618 
0619     d->action_project_print_setup = addAction("project_print_setup",
0620         koIcon("configure"), futureI18n("Print Set&up...")); //!< @todo document-page-setup could be a better icon
0621     d->action_project_print_setup->setToolTip(
0622         futureI18n("Show print setup for the active table or query"));
0623     d->action_project_print_setup->setWhatsThis(
0624         futureI18n("Shows print setup for the active table or query."));
0625     connect(d->action_project_print_setup, SIGNAL(triggered()),
0626             this, SLOT(slotProjectPageSetup()));
0627 #else
0628     d->action_project_print = d->dummy_action;
0629     d->action_project_print_preview = d->dummy_action;
0630     d->action_project_print_setup = d->dummy_action;
0631 #endif
0632 
0633     //EDIT MENU
0634     d->action_edit_cut = createSharedAction(KStandardAction::Cut);
0635     d->action_edit_copy = createSharedAction(KStandardAction::Copy);
0636     d->action_edit_paste = createSharedAction(KStandardAction::Paste);
0637 
0638     if (d->userMode)
0639         d->action_edit_paste_special_data_table = 0;
0640     else {
0641         d->action_edit_paste_special_data_table = addAction(
0642             "edit_paste_special_data_table",
0643             d->action_edit_paste->icon(), xi18nc("Paste Special->As Data &Table...", "Paste Special..."));
0644         d->action_edit_paste_special_data_table->setToolTip(
0645             xi18n("Paste clipboard data as a table"));
0646         d->action_edit_paste_special_data_table->setWhatsThis(
0647             xi18n("Pastes clipboard data as a table."));
0648         connect(d->action_edit_paste_special_data_table, SIGNAL(triggered()),
0649                 this, SLOT(slotEditPasteSpecialDataTable()));
0650     }
0651 
0652     d->action_edit_copy_special_data_table = addAction(
0653         "edit_copy_special_data_table",
0654         KexiIcon("table"), xi18nc("Copy Special->Table or Query Data...", "Copy Special..."));
0655     d->action_edit_copy_special_data_table->setToolTip(
0656         xi18n("Copy selected table or query data to clipboard"));
0657     d->action_edit_copy_special_data_table->setWhatsThis(
0658         xi18n("Copies selected table or query data to clipboard."));
0659     connect(d->action_edit_copy_special_data_table, SIGNAL(triggered()),
0660             this, SLOT(slotEditCopySpecialDataTable()));
0661 
0662     d->action_edit_undo = createSharedAction(KStandardAction::Undo);
0663     d->action_edit_undo->setWhatsThis(xi18n("Reverts the most recent editing action."));
0664     d->action_edit_redo = createSharedAction(KStandardAction::Redo);
0665     d->action_edit_redo->setWhatsThis(xi18n("Reverts the most recent undo action."));
0666 
0667     ac->addAction("edit_find",
0668                   d->action_edit_find = KStandardAction::find(
0669                                             this, SLOT(slotEditFind()), this));
0670     d->action_edit_find->setToolTip(xi18n("Find text"));
0671     d->action_edit_find->setWhatsThis(xi18n("Looks up the first occurrence of a piece of text."));
0672     ac->addAction("edit_findnext",
0673                   d->action_edit_findnext = KStandardAction::findNext(
0674                                                 this, SLOT(slotEditFindNext()), this));
0675     ac->addAction("edit_findprevious",
0676                   d->action_edit_findprev = KStandardAction::findPrev(
0677                                                 this, SLOT(slotEditFindPrevious()), this));
0678     ac->addAction("edit_replace",
0679                   d->action_edit_replace = KStandardAction::replace(
0680                                                 this, SLOT(slotEditReplace()), this));
0681     d->action_edit_replace_all = addAction("edit_replace_all", xi18n("Replace All"));
0682 
0683     d->action_edit_select_all =  createSharedAction(KStandardAction::SelectAll);
0684 
0685     d->action_edit_delete = createSharedAction(xi18n("&Delete"), koIconName("edit-delete"),
0686                             QKeySequence(), "edit_delete");
0687     d->action_edit_delete->setToolTip(xi18n("Delete selected object"));
0688     d->action_edit_delete->setWhatsThis(xi18n("Deletes currently selected object."));
0689 
0690     d->action_edit_delete_row = createSharedAction(xi18n("Delete Record"), KexiIconName("edit-table-delete-row"),
0691                                 QKeySequence(Qt::CTRL + Qt::Key_Delete), "edit_delete_row");
0692     d->action_edit_delete_row->setToolTip(xi18n("Delete the current record"));
0693     d->action_edit_delete_row->setWhatsThis(xi18n("Deletes the current record."));
0694 
0695     d->action_edit_clear_table = createSharedAction(xi18n("Clear Table Contents..."),
0696                                  KexiIconName("edit-table-clear"), QKeySequence(), "edit_clear_table");
0697     d->action_edit_clear_table->setToolTip(xi18n("Clear table contents"));
0698     d->action_edit_clear_table->setWhatsThis(xi18n("Clears table contents."));
0699     setActionVolatile(d->action_edit_clear_table, true);
0700 
0701     d->action_edit_edititem = createSharedAction(xi18n("Edit Item"), QString(),
0702                               QKeySequence(), /* CONFLICT in TV: Qt::Key_F2,  */
0703                               "edit_edititem");
0704     d->action_edit_edititem->setToolTip(xi18n("Edit currently selected item"));
0705     d->action_edit_edititem->setWhatsThis(xi18n("Edits currently selected item."));
0706 
0707     d->action_edit_insert_empty_row = createSharedAction(xi18n("&Insert Empty Row"),
0708                                       KexiIconName("edit-table-insert-row"), QKeySequence(Qt::SHIFT | Qt::CTRL | Qt::Key_Insert),
0709                                       "edit_insert_empty_row");
0710     setActionVolatile(d->action_edit_insert_empty_row, true);
0711     d->action_edit_insert_empty_row->setToolTip(xi18n("Insert one empty row above"));
0712     d->action_edit_insert_empty_row->setWhatsThis(
0713         xi18n("Inserts one empty row above currently selected table row."));
0714 
0715     //VIEW MENU
0716     /* UNUSED, see KexiToggleViewModeAction
0717       if (!d->userMode) {
0718         d->action_view_mode = new QActionGroup(this);
0719         ac->addAction( "view_data_mode",
0720           d->action_view_data_mode = new KToggleAction(
0721             KexiIcon("data-view"), xi18n("&Data View"), d->action_view_mode) );
0722     //  d->action_view_data_mode->setObjectName("view_data_mode");
0723         d->action_view_data_mode->setShortcut(QKeySequence("F6"));
0724         //d->action_view_data_mode->setExclusiveGroup("view_mode");
0725         d->action_view_data_mode->setToolTip(xi18n("Switch to data view"));
0726         d->action_view_data_mode->setWhatsThis(xi18n("Switches to data view."));
0727         d->actions_for_view_modes.insert( Kexi::DataViewMode, d->action_view_data_mode );
0728         connect(d->action_view_data_mode, SIGNAL(triggered()),
0729           this, SLOT(slotViewDataMode()));
0730       }
0731       else {
0732         d->action_view_mode = 0;
0733         d->action_view_data_mode = 0;
0734       }
0735 
0736       if (!d->userMode) {
0737         ac->addAction( "view_design_mode",
0738           d->action_view_design_mode = new KToggleAction(
0739             KexiIcon("design-view"), xi18n("D&esign View"), d->action_view_mode) );
0740     //  d->action_view_design_mode->setObjectName("view_design_mode");
0741         d->action_view_design_mode->setShortcut(QKeySequence("F7"));
0742         //d->action_view_design_mode->setExclusiveGroup("view_mode");
0743         d->action_view_design_mode->setToolTip(xi18n("Switch to design view"));
0744         d->action_view_design_mode->setWhatsThis(xi18n("Switches to design view."));
0745         d->actions_for_view_modes.insert( Kexi::DesignViewMode, d->action_view_design_mode );
0746         connect(d->action_view_design_mode, SIGNAL(triggered()),
0747           this, SLOT(slotViewDesignMode()));
0748       }
0749       else
0750         d->action_view_design_mode = 0;
0751 
0752       if (!d->userMode) {
0753         ac->addAction( "view_text_mode",
0754           d->action_view_text_mode = new KToggleAction(
0755             KexiIcon("sql-view"), xi18n("&Text View"), d->action_view_mode) );
0756         d->action_view_text_mode->setObjectName("view_text_mode");
0757         d->action_view_text_mode->setShortcut(QKeySequence("F8"));
0758         //d->action_view_text_mode->setExclusiveGroup("view_mode");
0759         d->action_view_text_mode->setToolTip(xi18n("Switch to text view"));
0760         d->action_view_text_mode->setWhatsThis(xi18n("Switches to text view."));
0761         d->actions_for_view_modes.insert( Kexi::TextViewMode, d->action_view_text_mode );
0762         connect(d->action_view_text_mode, SIGNAL(triggered()),
0763           this, SLOT(slotViewTextMode()));
0764       }
0765       else
0766         d->action_view_text_mode = 0;
0767     */
0768     if (d->isProjectNavigatorVisible) {
0769         ac->addAction("view_navigator",
0770             d->action_show_nav = new KToggleAction(xi18n("Show Project Navigator"), this));
0771         d->action_show_nav->setChecked(true);
0772         d->action_show_nav->setShortcut(QKeySequence("Alt+0"));
0773         d->action_show_nav->setToolTip(xi18n("Show the Project Navigator pane"));
0774         d->action_show_nav->setWhatsThis(xi18n("Shows the Project Navigator pane."));
0775         connect(d->action_show_nav, SIGNAL(triggered()),
0776                 this, SLOT(slotToggleProjectNavigator()));
0777     } else {
0778         d->action_show_nav = 0;
0779     }
0780 
0781     if (d->isProjectNavigatorVisible) {
0782         // Shortcut taken from "Activate Projects pane" https://doc.qt.io/qtcreator/creator-keyboard-shortcuts.html
0783         d->action_activate_nav = addAction("activate_navigator",
0784                                        xi18n("Activate Project Navigator"),
0785                                        "Alt+X");
0786         d->action_activate_nav->setToolTip(xi18n("Activate the Project Navigator pane"));
0787         d->action_activate_nav->setWhatsThis(xi18n("Activates the Project Navigator pane. If it is hidden, shows it first."));
0788         connect(d->action_activate_nav, SIGNAL(triggered()),
0789                 this, SLOT(slotActivateNavigator()));
0790     } else {
0791         d->action_activate_nav = 0;
0792     }
0793 
0794     d->action_activate_mainarea = addAction("activate_mainarea",
0795                                         xi18n("Activate main area")
0796 // , "Alt+2"?
0797 //! @todo activate_mainarea: pressing Esc in project nav or propeditor should move back to the main area
0798                                         );
0799     d->action_activate_mainarea->setToolTip(xi18n("Activate the main area"));
0800     d->action_activate_mainarea->setWhatsThis(xi18n("Activates the main area."));
0801     connect(d->action_activate_mainarea, SIGNAL(triggered()),
0802             this, SLOT(slotActivateMainArea()));
0803 
0804     //! @todo windows with "_3" prefix have conflicting auto shortcut set to Alt+3 -> remove that!
0805     if (!d->userMode) {
0806         ac->addAction("view_propeditor",
0807             d->action_show_propeditor = new KToggleAction(xi18n("Show Property Pane"), this));
0808         d->action_show_propeditor->setShortcut(QKeySequence("Alt+3"));
0809         d->action_show_propeditor->setToolTip(xi18n("Show the Property pane"));
0810         d->action_show_propeditor->setWhatsThis(xi18n("Shows the Property pane."));
0811         connect(d->action_show_propeditor, SIGNAL(triggered()),
0812                 this, SLOT(slotTogglePropertyEditor()));
0813     } else {
0814         d->action_show_propeditor = 0;
0815     }
0816 
0817     if (!d->userMode) {
0818         d->action_activate_propeditor = addAction("activate_propeditor",
0819                                               xi18n("Activate Property Pane"), "Alt+-");
0820         d->action_activate_propeditor->setToolTip(xi18n("Activate the Property pane"));
0821         d->action_activate_propeditor->setWhatsThis(xi18n("Activates the Property pane. If it is hidden, shows it first."));
0822         connect(d->action_activate_propeditor, SIGNAL(triggered()),
0823                 this, SLOT(slotActivatePropertyPane()));
0824     } else {
0825         d->action_activate_propeditor = 0;
0826     }
0827 
0828     d->action_tools_locate = addAction("tools_locate",
0829                                              xi18n("Locate..."), "Ctrl+K");
0830     d->action_tools_locate->setToolTip(xi18n("Switch to Global Locate box"));
0831     d->action_tools_locate->setWhatsThis(xi18n("Switches to Global Locate box."));
0832     // (connection is added elsewhere)
0833 
0834     //DATA MENU
0835     d->action_data_save_row = createSharedAction(xi18n("&Accept"), koIconName("dialog-ok"),
0836                               QKeySequence(Qt::SHIFT + Qt::Key_Return), "data_save_row");
0837     d->action_data_save_row->setToolTip(xi18n("Accept changes made to the current record"));
0838     d->action_data_save_row->setWhatsThis(xi18n("Accepts changes made to the current record."));
0839 //temp. disable because of problems with volatile actions setActionVolatile( d->action_data_save_row, true );
0840 
0841     d->action_data_cancel_row_changes = createSharedAction(xi18n("&Cancel"),
0842                                         koIconName("dialog-cancel"), QKeySequence(Qt::Key_Escape), "data_cancel_row_changes");
0843     d->action_data_cancel_row_changes->setToolTip(
0844         xi18n("Cancel changes made to the current record"));
0845     d->action_data_cancel_row_changes->setWhatsThis(
0846         xi18n("Cancels changes made to the current record."));
0847 //temp. disable because of problems with volatile actions setActionVolatile( d->action_data_cancel_row_changes, true );
0848 
0849     d->action_data_execute = createSharedAction(
0850                                  xi18n("&Execute"), koIconName("media-playback-start"), QKeySequence(), "data_execute");
0851     //! @todo d->action_data_execute->setToolTip(xi18n(""));
0852     //! @todo d->action_data_execute->setWhatsThis(xi18n(""));
0853 
0854 #ifdef KEXI_SHOW_UNIMPLEMENTED
0855     action = createSharedAction(futureI18n("&Filter"), koIconName("view-filter"), QKeySequence(), "data_filter");
0856     setActionVolatile(action, true);
0857 #endif
0858 //! @todo action->setToolTip(xi18n(""));
0859 //! @todo action->setWhatsThis(xi18n(""));
0860 
0861     // - record-navigation related actions
0862     createSharedAction(KexiRecordNavigator::Actions::moveToFirstRecord(), QKeySequence(), "data_go_to_first_record");
0863     createSharedAction(KexiRecordNavigator::Actions::moveToPreviousRecord(), QKeySequence(), "data_go_to_previous_record");
0864     createSharedAction(KexiRecordNavigator::Actions::moveToNextRecord(), QKeySequence(), "data_go_to_next_record");
0865     createSharedAction(KexiRecordNavigator::Actions::moveToLastRecord(), QKeySequence(), "data_go_to_last_record");
0866     createSharedAction(KexiRecordNavigator::Actions::moveToNewRecord(), QKeySequence(), "data_go_to_new_record");
0867 
0868     //FORMAT MENU
0869 #ifdef KEXI_SHOW_UNIMPLEMENTED
0870     d->action_format_font = createSharedAction(xi18n("&Font..."), koIconName("fonts-package"),
0871                             QKeySequence(), "format_font");
0872     d->action_format_font->setToolTip(xi18n("Change font for selected object"));
0873     d->action_format_font->setWhatsThis(xi18n("Changes font for selected object."));
0874 #else
0875     d->action_format_font = d->dummy_action;
0876 #endif
0877 
0878     //TOOLS MENU
0879 
0880     //WINDOW MENU
0881     // additional 'Window' menu items
0882     d->action_window_next = addAction("window_next", xi18n("&Next Window"), "Alt+Right");
0883     d->action_window_next->setToolTip(xi18n("Next window"));
0884     d->action_window_next->setWhatsThis(xi18n("Switches to the next window."));
0885     connect(d->action_window_next, SIGNAL(triggered()), this, SLOT(activateNextWindow()));
0886 
0887     d->action_window_previous = addAction("window_previous", xi18n("&Previous Window"), "Alt+Left");
0888     d->action_window_previous->setToolTip(xi18n("Previous window"));
0889     d->action_window_previous->setWhatsThis(xi18n("Switches to the previous window."));
0890     connect(d->action_window_previous, SIGNAL(triggered()), this, SLOT(activatePreviousWindow()));
0891 
0892     d->action_close_tab = addAction("close_tab", koIcon("tab-close"), xi18n("&Close Tab"), "Ctrl+W");
0893     d->action_close_tab->setToolTip(xi18n("Close the current tab"));
0894     d->action_close_tab->setWhatsThis(xi18n("Closes the current tab."));
0895     connect(d->action_close_tab, SIGNAL(triggered()), this, SLOT(closeCurrentWindow()));
0896 
0897     d->action_close_all_tabs = addAction("close_all_tabs", QIcon(), xi18n("Cl&ose All Tabs"));
0898     d->action_close_all_tabs->setToolTip(xi18n("Close all tabs"));
0899     d->action_close_all_tabs->setWhatsThis(xi18n("Closes all tabs."));
0900     connect(d->action_close_all_tabs, SIGNAL(triggered()), this, SLOT(closeAllWindows()));
0901 
0902     d->action_tab_next = addAction("tab_next", koIcon("go-next"),
0903                                    KStandardShortcut::label(KStandardShortcut::TabNext));
0904     d->action_tab_next->setWhatsThis(KStandardShortcut::whatsThis(KStandardShortcut::TabNext));
0905     d->action_tab_next->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::TabNext));
0906     connect(d->action_tab_next, &QAction::triggered, this, &KexiMainWindow::activateNextTab);
0907 
0908     d->action_tab_previous = addAction("tab_previous", koIcon("go-previous"),
0909                                        KStandardShortcut::label(KStandardShortcut::TabPrev));
0910     d->action_tab_previous->setWhatsThis(KStandardShortcut::whatsThis(KStandardShortcut::TabPrev));
0911     d->action_tab_previous->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::TabPrev));
0912     connect(d->action_tab_previous, &QAction::triggered, this, &KexiMainWindow::activatePreviousTab);
0913 
0914     d->action_window_fullscreen = KStandardAction::fullScreen(this, SLOT(toggleFullScreen(bool)), this, ac);
0915     ac->addAction("full_screen", d->action_window_fullscreen);
0916 
0917     //SETTINGS MENU
0918 //! @todo put 'configure keys' into settings view
0919 
0920 #ifdef KEXI_SHOW_UNIMPLEMENTED
0921     //! @todo toolbars configuration will be handled in a special way
0922 #endif
0923 
0924 #ifdef KEXI_MACROS_SUPPORT
0925     Kexi::tempShowMacros() = true;
0926 #else
0927     Kexi::tempShowMacros() = false;
0928 #endif
0929 
0930 #ifdef KEXI_SCRIPTS_SUPPORT
0931     Kexi::tempShowScripts() = true;
0932 #else
0933     Kexi::tempShowScripts() = false;
0934 #endif
0935 
0936 #ifdef KEXI_SHOW_UNIMPLEMENTED
0937 //! @todo implement settings window in a specific way
0938     ac->addAction("settings",
0939                   action = d->action_settings = new KexiMenuWidgetAction(
0940                     KStandardAction::Preferences, this));
0941     action->setObjectName("settings");
0942     //action->setText(futureI18n("Settings..."));
0943     action->setToolTip(futureI18n("Show KEXI settings"));
0944     action->setWhatsThis(futureI18n("Shows KEXI settings."));
0945     connect(action, SIGNAL(triggered()), this, SLOT(slotSettings()));
0946     setupMainMenuActionShortcut(action);
0947 #else
0948     d->action_settings = d->dummy_action;
0949 #endif
0950 
0951 //! @todo reenable 'tip of the day' later
0952 #if 0
0953     KStandardAction::tipOfDay(this, SLOT(slotTipOfTheDayAction()), actionCollection())
0954     ->setWhatsThis(xi18n("This shows useful tips on the use of this application."));
0955 #endif
0956 
0957     // ----- declare action categories, so form's "assign action to button"
0958     //       (and macros in the future) will be able to recognize category
0959     //       of actions and filter them -----------------------------------
0960 //! @todo shouldn't we move this to core?
0961     Kexi::ActionCategories *acat = Kexi::actionCategories();
0962     acat->addAction("data_execute", Kexi::PartItemActionCategory);
0963 
0964     //! @todo unused for now
0965     acat->addWindowAction("data_filter",
0966                           KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
0967 
0968     acat->addWindowAction("data_save_row",
0969                           KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
0970 
0971     acat->addWindowAction("data_cancel_row_changes",
0972                           KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
0973 
0974     acat->addWindowAction("delete_table_row",
0975                           KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
0976 
0977     //! @todo support this in KexiPart::FormObjectType as well
0978     acat->addWindowAction("data_sort_az",
0979                           KexiPart::TableObjectType, KexiPart::QueryObjectType);
0980 
0981     //! @todo support this in KexiPart::FormObjectType as well
0982     acat->addWindowAction("data_sort_za",
0983                           KexiPart::TableObjectType, KexiPart::QueryObjectType);
0984 
0985     //! @todo support this in KexiPart::FormObjectType as well
0986     acat->addWindowAction("edit_clear_table",
0987                           KexiPart::TableObjectType, KexiPart::QueryObjectType);
0988 
0989     //! @todo support this in KexiPart::FormObjectType as well
0990     acat->addWindowAction("edit_copy_special_data_table",
0991                           KexiPart::TableObjectType, KexiPart::QueryObjectType);
0992 
0993     //! @todo support this in FormObjectType as well
0994     acat->addWindowAction("project_export_data_table",
0995                           KexiPart::TableObjectType, KexiPart::QueryObjectType);
0996 
0997     // GlobalActions, etc.
0998     acat->addAction("edit_copy", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory);
0999 
1000     acat->addAction("edit_cut", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory);
1001 
1002     acat->addAction("edit_paste", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory);
1003 
1004     acat->addAction("edit_delete", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory | Kexi::WindowActionCategory,
1005                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1006 
1007     acat->addAction("edit_delete_row", Kexi::GlobalActionCategory | Kexi::WindowActionCategory,
1008                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1009 
1010     acat->addAction("edit_edititem", Kexi::PartItemActionCategory | Kexi::WindowActionCategory,
1011                     KexiPart::TableObjectType, KexiPart::QueryObjectType);
1012 
1013     acat->addAction("edit_find", Kexi::GlobalActionCategory | Kexi::WindowActionCategory,
1014                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1015 
1016     acat->addAction("edit_findnext", Kexi::GlobalActionCategory | Kexi::WindowActionCategory,
1017                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1018 
1019     acat->addAction("edit_findprevious", Kexi::GlobalActionCategory | Kexi::WindowActionCategory,
1020                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1021 
1022     acat->addAction("edit_replace", Kexi::GlobalActionCategory | Kexi::WindowActionCategory,
1023                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1024 
1025     acat->addAction("edit_paste_special_data_table", Kexi::GlobalActionCategory);
1026 
1027     acat->addAction("help_about_app", Kexi::GlobalActionCategory);
1028 
1029     acat->addAction("help_about_kde", Kexi::GlobalActionCategory);
1030 
1031     acat->addAction("help_contents", Kexi::GlobalActionCategory);
1032 
1033     acat->addAction("help_report_bug", Kexi::GlobalActionCategory);
1034 
1035     acat->addAction("help_whats_this", Kexi::GlobalActionCategory);
1036 
1037     acat->addAction("help_donate", Kexi::GlobalActionCategory); // disabled for now
1038 
1039     acat->addAction("switch_application_language", Kexi::GlobalActionCategory);
1040 
1041     acat->addAction("options_configure_keybinding", Kexi::GlobalActionCategory);
1042 
1043     acat->addAction("project_close", Kexi::GlobalActionCategory);
1044 
1045     acat->addAction("project_import_data_table", Kexi::GlobalActionCategory);
1046 
1047     acat->addAction("project_new", Kexi::GlobalActionCategory);
1048 
1049     acat->addAction("project_open", Kexi::GlobalActionCategory);
1050 
1051 #ifdef KEXI_QUICK_PRINTING_SUPPORT
1052     //! @todo support this in FormObjectType, ReportObjectType as well as others
1053     acat->addAction("project_print", Kexi::WindowActionCategory,
1054                     KexiPart::TableObjectType, KexiPart::QueryObjectType);
1055 
1056     //! @todo support this in FormObjectType, ReportObjectType as well as others
1057     acat->addAction("project_print_preview", Kexi::WindowActionCategory,
1058                     KexiPart::TableObjectType, KexiPart::QueryObjectType);
1059 
1060     //! @todo support this in FormObjectType, ReportObjectType as well as others
1061     acat->addAction("project_print_setup", Kexi::WindowActionCategory,
1062                     KexiPart::TableObjectType, KexiPart::QueryObjectType);
1063 #endif
1064 
1065     acat->addAction("quit", Kexi::GlobalActionCategory);
1066 
1067     acat->addAction("tools_compact_database", Kexi::GlobalActionCategory);
1068 
1069     acat->addAction("tools_import_project", Kexi::GlobalActionCategory);
1070 
1071     acat->addAction("tools_import_tables", Kexi::GlobalActionCategory);
1072 
1073     acat->addAction("view_data_mode", Kexi::GlobalActionCategory);
1074 
1075     acat->addAction("view_design_mode", Kexi::GlobalActionCategory);
1076 
1077     acat->addAction("view_text_mode", Kexi::GlobalActionCategory);
1078 
1079     acat->addAction("view_mainarea", Kexi::GlobalActionCategory);
1080 
1081     acat->addAction("view_navigator", Kexi::GlobalActionCategory);
1082 
1083     acat->addAction("activate_navigator", Kexi::GlobalActionCategory);
1084 
1085     acat->addAction("view_propeditor", Kexi::GlobalActionCategory);
1086 
1087     acat->addAction("activate_mainarea", Kexi::GlobalActionCategory);
1088 
1089     acat->addAction("activate_propeditor", Kexi::GlobalActionCategory);
1090 
1091     acat->addAction("close_tab", Kexi::GlobalActionCategory | Kexi::WindowActionCategory);
1092     acat->setAllObjectTypesSupported("close_tab", true);
1093 
1094     acat->addAction("close_all_tabs", Kexi::GlobalActionCategory | Kexi::WindowActionCategory);
1095     acat->setAllObjectTypesSupported("close_all_tabs", true);
1096 
1097     acat->addAction("tab_next", Kexi::GlobalActionCategory);
1098 
1099     acat->addAction("tab_previous", Kexi::GlobalActionCategory);
1100 
1101     acat->addAction("full_screen", Kexi::GlobalActionCategory);
1102 
1103     //skipped - design view only
1104     acat->addAction("format_font", Kexi::NoActionCategory);
1105     acat->addAction("project_save", Kexi::NoActionCategory);
1106     acat->addAction("edit_insert_empty_row", Kexi::NoActionCategory);
1107     //! @todo support this in KexiPart::TableObjectType, KexiPart::QueryObjectType later
1108     acat->addAction("edit_select_all", Kexi::NoActionCategory);
1109     //! @todo support this in KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType later
1110     acat->addAction("edit_redo", Kexi::NoActionCategory);
1111     //! @todo support this in KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType later
1112     acat->addAction("edit_undo", Kexi::NoActionCategory);
1113 
1114     //record-navigation related actions
1115     acat->addAction("data_go_to_first_record", Kexi::WindowActionCategory,
1116                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1117     acat->addAction("data_go_to_previous_record", Kexi::WindowActionCategory,
1118                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1119     acat->addAction("data_go_to_next_record", Kexi::WindowActionCategory,
1120                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1121     acat->addAction("data_go_to_last_record", Kexi::WindowActionCategory,
1122                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1123     acat->addAction("data_go_to_new_record", Kexi::WindowActionCategory,
1124                     KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType);
1125 
1126     //skipped - internal:
1127     acat->addAction("tablepart_create", Kexi::NoActionCategory);
1128     acat->addAction("querypart_create", Kexi::NoActionCategory);
1129     acat->addAction("formpart_create", Kexi::NoActionCategory);
1130     acat->addAction("reportpart_create", Kexi::NoActionCategory);
1131     acat->addAction("macropart_create", Kexi::NoActionCategory);
1132     acat->addAction("scriptpart_create", Kexi::NoActionCategory);
1133 }
1134 
1135 void KexiMainWindow::setupMainMenu()
1136 {
1137     KActionCollection *ac = actionCollection();
1138     QMenuBar *menu = menuBar();
1139     {
1140         QMenu *fileMenu = menu->addMenu(xi18n("&File"));
1141         if (!d->userMode) {
1142             d->addAction(fileMenu, "project_new");
1143             fileMenu->addSeparator();
1144             d->addAction(fileMenu, "project_open");
1145             d->addAction(fileMenu, "project_open_recent");
1146             fileMenu->addSeparator();
1147         }
1148         fileMenu->addAction(d->action_save);
1149         if (!d->userMode) {
1150             fileMenu->addAction(d->action_save_as);
1151         }
1152         fileMenu->addSeparator();
1153         if (!d->userMode) {
1154             fileMenu->addAction(d->action_tools_import_project);
1155             fileMenu->addSeparator();
1156         }
1157 #ifdef KEXI_SHOW_UNIMPLEMENTED
1158         fileMenu->addAction(d->action_project_print);
1159         fileMenu->addAction(d->action_project_print_preview);
1160         fileMenu->addAction(d->action_project_print_setup);
1161         fileMenu->addSeparator();
1162 #endif
1163 #ifdef KEXI_SHOW_UNIMPLEMENTED
1164         fileMenu->addAction(d->action_project_properties);
1165         fileMenu->addSeparator();
1166 #endif
1167         fileMenu->addAction(d->action_close_tab);
1168         fileMenu->addAction(d->action_close_all_tabs);
1169         if (!d->userMode) {
1170             fileMenu->addAction(d->action_close);
1171         }
1172         fileMenu->addSeparator();
1173         d->addAction(fileMenu, "quit");
1174     }
1175     {
1176         QMenu *editMenu = menu->addMenu(xi18n("&Edit"));
1177         editMenu->addAction(d->action_edit_undo);
1178         editMenu->addAction(d->action_edit_redo);
1179         editMenu->addSeparator();
1180         editMenu->addAction(d->action_edit_cut);
1181         editMenu->addAction(d->action_edit_copy);
1182         editMenu->addAction(d->action_edit_copy_special_data_table);
1183         editMenu->addAction(d->action_edit_paste);
1184         if (!d->userMode) {
1185             editMenu->addAction(d->action_edit_paste_special_data_table);
1186         }
1187         editMenu->addSeparator();
1188         editMenu->addAction(d->action_edit_select_all);
1189         editMenu->addSeparator();
1190         {
1191             QMenu *findReplaceMenu = editMenu->addMenu(xi18n("&Find/Replace"));
1192             findReplaceMenu->addAction(d->action_edit_find);
1193             findReplaceMenu->addAction(d->action_edit_findnext);
1194             findReplaceMenu->addAction(d->action_edit_findprev);
1195 #ifdef KEXI_SHOW_UNIMPLEMENTED
1196             findReplaceMenu->addSeparator();
1197             findReplaceMenu->addAction(d->action_edit_replace);
1198             findReplaceMenu->addAction(d->action_edit_replace_all);
1199 #endif
1200         }
1201         editMenu->addSeparator();
1202         editMenu->addAction(d->action_edit_delete);
1203         // in local toolbar already: editMenu->addAction(d->action_data_save_row);
1204         // in local toolbar already: editMenu->addAction(d->action_data_cancel_row_changes);
1205         //TODO move to local menu: editMenu->addAction(d->action_edit_edititem);
1206         //TODO move to local menu: editMenu->addAction(d->action_edit_insert_empty_row);
1207         //TODO move to local menu: editMenu->addAction(d->action_data_execute);
1208         //editMenu->addSeparator();
1209         //TODO move to local menu: editMenu->addAction(d->action_edit_delete);
1210         //TODO move to local menu: editMenu->addAction(d->action_edit_delete_row);
1211         //in local menu already editMenu->addAction(d->action_edit_clear_table);
1212     }
1213 #ifdef KEXI_SHOW_UNIMPLEMENTED
1214     {
1215         QMenu *formatMenu = menu->addMenu(xi18n("F&ormat"));
1216         formatMenu->addAction(d->action_format_font);
1217     }
1218 #endif
1219     {
1220         QMenu *dataMenu = menu->addMenu(xi18n("&Data"));
1221         if (!d->userMode) {
1222             dataMenu->addAction(d->action_project_import_data_table);
1223             dataMenu->addAction(d->action_tools_data_import);
1224             dataMenu->addSeparator();
1225         }
1226         dataMenu->addAction(d->action_project_export_data_table);
1227     }
1228     {
1229         QMenu *toolsMenu = menu->addMenu(xi18n("&Tools"));
1230         toolsMenu->addAction(d->action_tools_locate);
1231         toolsMenu->addSeparator();
1232 #ifdef KEXI_SHOW_UNIMPLEMENTED
1233         toolsMenu->addAction(d->action_project_relations);
1234 #endif
1235         toolsMenu->addAction(d->action_tools_compact_database);
1236     }
1237     {
1238         QMenu *settingsMenu = menu->addMenu(xi18n("&Settings"));
1239         settingsMenu->addAction(d->action_window_fullscreen);
1240         settingsMenu->addSeparator();
1241 #ifdef KEXI_SHOW_UNIMPLEMENTED
1242         settingsMenu->addAction(d->action_settings);
1243 #endif
1244     }
1245     {
1246         QMenu *windowMenu = menu->addMenu(xi18n("&Window"));
1247         windowMenu->addAction(d->action_tab_next);
1248         windowMenu->addAction(d->action_tab_previous);
1249         windowMenu->addSeparator();
1250         windowMenu->addAction(d->action_show_nav);
1251         windowMenu->addAction(d->action_show_propeditor);
1252     }
1253     {
1254         // add help menu actions... (KexiTabbedToolBar depends on them)
1255         KHelpMenu *helpMenu = new KHelpMenu(this, KAboutData::applicationData(),
1256                                     true/*showWhatsThis*/);
1257         QAction* help_report_bug_action = helpMenu->action(KHelpMenu::menuReportBug);
1258         ac->addAction(help_report_bug_action->objectName(), help_report_bug_action);
1259         QObject::disconnect(help_report_bug_action, 0, 0, 0);
1260         QObject::connect(help_report_bug_action, &QAction::triggered, this, &KexiMainWindow::slotReportBug);
1261         help_report_bug_action->setText(xi18nc("Report a bug or wish for KEXI application", "Report a &Bug or Wish..."));
1262         help_report_bug_action->setIcon(koIcon("tools-report-bug")); // good icon for toolbar
1263         help_report_bug_action->setWhatsThis(xi18n("Files a bug or wish for KEXI application."));
1264         QAction* help_whats_this_action =  helpMenu->action(KHelpMenu::menuWhatsThis);
1265         ac->addAction(help_whats_this_action->objectName(), help_whats_this_action);
1266         help_whats_this_action->setWhatsThis(xi18n("Activates a \"What's This?\" tool."));
1267         QAction* help_contents_action = helpMenu->action(KHelpMenu::menuHelpContents);
1268         ac->addAction(help_contents_action->objectName(), help_contents_action);
1269         help_contents_action->setText(xi18n("Help"));
1270         help_contents_action->setWhatsThis(xi18n("Shows KEXI Handbook."));
1271         QAction* help_about_app_action = helpMenu->action(KHelpMenu::menuAboutApp);
1272         ac->addAction(help_about_app_action->objectName(), help_about_app_action);
1273         help_about_app_action->setWhatsThis(xi18n("Shows information about KEXI application."));
1274         QAction* help_about_kde_action = helpMenu->action(KHelpMenu::menuAboutKDE);
1275         ac->addAction(help_about_kde_action->objectName(), help_about_kde_action);
1276         help_about_kde_action->setWhatsThis(xi18n("Shows information about KDE."));
1277         menu->addMenu(helpMenu->menu());
1278     }
1279 }
1280 
1281 void KexiMainWindow::invalidateActions()
1282 {
1283     invalidateProjectWideActions();
1284     invalidateSharedActions();
1285 }
1286 
1287 void KexiMainWindow::invalidateSharedActions(QObject *o)
1288 {
1289     //! @todo enabling is more complex...
1290     /* d->action_edit_cut->setEnabled(true);
1291       d->action_edit_copy->setEnabled(true);
1292       d->action_edit_paste->setEnabled(true);*/
1293 
1294     if (!o)
1295         o = focusWindow();
1296     KexiSharedActionHost::invalidateSharedActions(o);
1297 }
1298 
1299 void KexiMainWindow::invalidateSharedActions()
1300 {
1301     invalidateSharedActions(0);
1302 }
1303 
1304 // unused, I think
1305 void KexiMainWindow::invalidateSharedActionsLater()
1306 {
1307     QTimer::singleShot(1, this, SLOT(invalidateSharedActions()));
1308 }
1309 
1310 void KexiMainWindow::invalidateProjectWideActions()
1311 {
1312     const bool has_window = currentWindow();
1313     const bool window_dirty = currentWindow() && currentWindow()->isDirty();
1314     const bool readOnly = d->prj && d->prj->dbConnection() && d->prj->dbConnection()->options()->isReadOnly();
1315 
1316     //PROJECT MENU
1317     d->action_save->setEnabled(has_window && window_dirty && !readOnly);
1318     d->action_save_as->setEnabled(has_window && !readOnly);
1319     d->action_project_properties->setEnabled(d->prj);
1320     d->action_close->setEnabled(d->prj);
1321     d->action_project_relations->setEnabled(d->prj);
1322     if (d->objectViewWidget) {
1323         d->action_close_tab->setEnabled(has_window);
1324         d->action_close_all_tabs->setEnabled(has_window);
1325     }
1326 
1327     //DATA MENU
1328     if (d->action_project_import_data_table)
1329         d->action_project_import_data_table->setEnabled(d->prj && !readOnly);
1330     if (d->action_tools_data_import)
1331         d->action_tools_data_import->setEnabled(d->prj && !readOnly);
1332     d->action_project_export_data_table->setEnabled(
1333         currentWindow() && currentWindow()->part()->info()->isDataExportSupported());
1334     if (d->action_edit_paste_special_data_table)
1335         d->action_edit_paste_special_data_table->setEnabled(d->prj && !readOnly);
1336 
1337 #ifdef KEXI_SHOW_UNIMPLEMENTED
1338     const bool printingActionsEnabled =
1339         currentWindow() && currentWindow()->part()->info()->isPrintingSupported()
1340         && !currentWindow()->neverSaved();
1341     d->action_project_print->setEnabled(printingActionsEnabled);
1342     d->action_project_print_preview->setEnabled(printingActionsEnabled);
1343     d->action_project_print_setup->setEnabled(printingActionsEnabled);
1344 #endif
1345 
1346     //EDIT MENU
1347 //! @todo "copy special" is currently enabled only for data view mode;
1348 //!  what about allowing it to enable in design view for "kexi/table" ?
1349     if (currentWindow() && currentWindow()->currentViewMode() == Kexi::DataViewMode) {
1350         KexiPart::Info *activePartInfo = currentWindow()->part()->info();
1351         d->action_edit_copy_special_data_table->setEnabled(
1352             activePartInfo ? activePartInfo->isDataExportSupported() : false);
1353     } else {
1354         d->action_edit_copy_special_data_table->setEnabled(false);
1355     }
1356     d->action_edit_find->setEnabled(d->prj);
1357 
1358     //VIEW MENU
1359     if (d->action_show_nav)
1360         d->action_show_nav->setEnabled(d->prj);
1361     d->action_activate_mainarea->setEnabled(d->prj);
1362 
1363     //CREATE MENU
1364     if (d->tabbedToolBar && d->tabbedToolBar->createWidgetToolBar())
1365         d->tabbedToolBar->createWidgetToolBar()->setEnabled(d->prj);
1366 
1367     // DATA MENU
1368 
1369     // WINDOW MENU
1370     if (d->objectViewWidget) {
1371         d->action_tab_next->setEnabled(d->objectViewWidget->tabWidget()->count() > 1);
1372         d->action_tab_previous->setEnabled(d->objectViewWidget->tabWidget()->count() > 1);
1373     }
1374 
1375     //TOOLS MENU
1376     // "compact db" supported if there's no db or the current db supports compacting and is opened r/w:
1377     d->action_tools_compact_database->setEnabled(
1378         //! @todo Support compacting of non-opened projects
1379         /*!d->prj
1380         ||*/ (!readOnly && d->prj && d->prj->dbConnection()
1381             && (d->prj->dbConnection()->driver()->features() & KDbDriver::CompactingDatabaseSupported))
1382     );
1383 
1384     //DOCKS
1385     if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) {
1386         d->objectViewWidget->projectNavigator()->setEnabled(d->prj);
1387     }
1388     if (d->objectViewWidget && d->objectViewWidget->propertyPane()) {
1389         d->objectViewWidget->propertyPane()->setEnabled(d->prj);
1390     }
1391 }
1392 
1393 tristate KexiMainWindow::startup()
1394 {
1395     tristate result = true;
1396     switch (KexiStartupHandler::global()->action()) {
1397     case KexiStartupHandler::CreateBlankProject:
1398         d->updatePropEditorVisibility(Kexi::NoViewMode);
1399         break;
1400 #ifdef KEXI_PROJECT_TEMPLATES
1401     case KexiStartupHandler::CreateFromTemplate:
1402         result = createProjectFromTemplate(*KexiStartupHandler::global()->projectData());
1403         break;
1404 #endif
1405     case KexiStartupHandler::OpenProject:
1406         result = openProject(*KexiStartupHandler::global()->projectData());
1407         break;
1408     case KexiStartupHandler::ImportProject:
1409         result = showProjectMigrationWizard(
1410                    KexiStartupHandler::global()->importActionData().mimeType,
1411                    KexiStartupHandler::global()->importActionData().fileName
1412                );
1413         break;
1414     case KexiStartupHandler::ShowWelcomeScreen:
1415         //! @todo show welcome screen as soon as is available
1416         QTimer::singleShot(100, this, SLOT(slotProjectWelcome()));
1417         break;
1418     default:
1419         d->updatePropEditorVisibility(Kexi::NoViewMode);
1420     }
1421     return result;
1422 }
1423 
1424 static QString internalReason(const KDbResult &result)
1425 {
1426     const QString msg = result.message();
1427     if (msg.isEmpty()) {
1428         return QString();
1429     }
1430     return xi18n("<br/>(reason: <i>%1</i>)", msg);
1431 }
1432 
1433 tristate KexiMainWindow::openProject(const KexiProjectData& projectData)
1434 {
1435     //qDebug() << projectData;
1436     QScopedPointer<KexiProject> prj(createKexiProjectObject(projectData));
1437     if (~KexiDBPasswordDialog::getPasswordIfNeeded(prj->data()->connectionData(), this)) {
1438         return cancelled;
1439     }
1440     bool incompatibleWithKexi;
1441     tristate res = prj->open(&incompatibleWithKexi);
1442 
1443     if (prj->data()->connectionData()->isPasswordNeeded()) {
1444         // password was supplied in this session, and shouldn't be stored or reused afterwards,
1445         // so let's remove it
1446         prj->data()->connectionData()->setPassword(QString());
1447     }
1448 
1449     if (~res) {
1450         return cancelled;
1451     }
1452     else if (!res) {
1453         if (incompatibleWithKexi) {
1454             if (KMessageBox::Yes == KMessageBox::questionYesNo(this,
1455                     xi18nc("@info (don't add tags around %1, it's done already)",
1456                            "Database project %1 does not appear to have been created using "
1457                            "<application>%2</application>.<nl/>"
1458                            "Do you want to import it as a new KEXI project?",
1459                            projectData.infoString(), QApplication::applicationDisplayName()),
1460                     QString(), KGuiItem(xi18nc("@action:button Import Database", "&Import..."), KexiIconName("database-import")),
1461                     KStandardGuiItem::cancel()))
1462             {
1463                 const bool anotherProjectAlreadyOpened = prj;
1464                 tristate res = showProjectMigrationWizard("application/x-kexi-connectiondata",
1465                                    projectData.databaseName(), *projectData.connectionData());
1466 
1467                 if (!anotherProjectAlreadyOpened) //the project could have been opened within this instance
1468                     return res;
1469 
1470                 //always return cancelled because even if migration succeeded, new Kexi instance
1471                 //will be started if user wanted to open the imported db
1472                 return cancelled;
1473             }
1474             return cancelled;
1475         }
1476         return false;
1477     }
1478 
1479     // success
1480     d->prj = prj.take();
1481     d->modeSelector->setCurrentMode(Kexi::EditGlobalMode);
1482     d->prj->data()->setLastOpened(QDateTime::currentDateTime());
1483     Kexi::recentProjects()->addProjectData(*d->prj->data());
1484     updateReadOnlyState();
1485     invalidateActions();
1486     setMessagesEnabled(false);
1487 
1488     QTimer::singleShot(1, this, SLOT(slotAutoOpenObjectsLater()));
1489     if (d->tabbedToolBar) {
1490         d->tabbedToolBar->showTab("create");// not needed since create toolbar already shows toolbar! move when kexi starts
1491         d->tabbedToolBar->hideTab("form");//temporalily until createToolbar is split
1492         d->tabbedToolBar->hideTab("report");//temporalily until createToolbar is split
1493 
1494         // make sure any tab is activated
1495         d->tabbedToolBar->setCurrentTab(0);
1496     }
1497     return true;
1498 }
1499 
1500 tristate KexiMainWindow::openProject(const KexiProjectData& data, const QString& shortcutPath,
1501                                      bool *opened)
1502 {
1503     if (!shortcutPath.isEmpty() && d->prj) {
1504         const tristate result = openProjectInExternalKexiInstance(
1505             shortcutPath, QString(), QString());
1506         if (result == true) {
1507             *opened = true;
1508         }
1509         return result;
1510     }
1511     return openProject(data);
1512 }
1513 
1514 tristate KexiMainWindow::createProjectFromTemplate(const KexiProjectData& projectData)
1515 {
1516     Q_UNUSED(projectData);
1517 #ifdef KEXI_PROJECT_TEMPLATES
1518     QStringList mimetypes;
1519     mimetypes.append(KDb::defaultFileBasedDriverMimeType());
1520     QString fname;
1521     //! @todo KEXI3 add equivalent of kfiledialog:///
1522     const QString startDir("kfiledialog:///OpenExistingOrCreateNewProject"/*as in KexiNewProjectWizard*/);
1523     const QString caption(xi18nc("@window:title", "Select New Project's Location"));
1524 
1525     while (true) {
1526         if (fname.isEmpty() &&
1527                 !projectData.connectionData()->databaseName().isEmpty()) {
1528             //propose filename from db template name
1529             fname = projectData.connectionData()->databaseName();
1530         }
1531         const bool specialDir = fname.isEmpty();
1532         qDebug() << fname << ".............";
1533         QFileDialog dlg(specialDir ? QUrl(startDir) : QUrl(),
1534                         QString(), this);
1535         dlg.setModal(true);
1536         dlg.setMimeFilter(mimetypes);
1537         if (!specialDir)
1538             dlg.selectUrl(QUrl::fromLocalFile(fname);   // may also be a filename
1539         dlg.setFileMode(QFileDialog::ExistingFile);
1540         dlg.setFileMode(QFileDialog::AcceptOpen);
1541         dlg.setWindowTitle(caption);
1542         if (QDialog::Accepted != dlg.exec()) {
1543             return cancelled;
1544         }
1545         if (dlg.selectedFiles().isEmpty()) {
1546             return cancelled;
1547         }
1548         fname = dlg.selectedFiles().first();
1549         if (fname.isEmpty()) {
1550             return cancelled;
1551         }
1552         if (KexiUtils::askForFileOverwriting(fname, this)) {
1553             break;
1554         }
1555     }
1556 
1557     QFile sourceFile(projectData.connectionData()->fileName());
1558     if (!sourceFile.copy(fname)) {
1559 //! @todo show error from with QFile::FileError
1560         return false;
1561     }
1562 
1563     return openProject(fname, 0, QString(), projectData.autoopenObjects/*copy*/);
1564 #else
1565     return false;
1566 #endif
1567 }
1568 
1569 void KexiMainWindow::updateReadOnlyState()
1570 {
1571     const bool readOnly = d->prj && d->prj->dbConnection() && d->prj->dbConnection()->options()->isReadOnly();
1572     //! @todo KEXI3 show read-only flag in the GUI because we have no statusbar
1573     if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) {
1574         d->objectViewWidget->projectNavigator()->setReadOnly(readOnly);
1575     }
1576 
1577     // update "insert ....." actions for every part
1578     KexiPart::PartInfoList *plist = Kexi::partManager().infoList();
1579     if (plist) {
1580         foreach(KexiPart::Info *info, *plist) {
1581             QAction *a = info->newObjectAction();
1582             if (a)
1583                 a->setEnabled(!readOnly);
1584         }
1585     }
1586 }
1587 
1588 void KexiMainWindow::slotAutoOpenObjectsLater()
1589 {
1590     QString not_found_msg;
1591     bool openingCancelled;
1592     //ok, now open "autoopen: objects
1593     if (d->prj) {
1594         for (const KexiProjectData::ObjectInfo &info : d->prj->data()->autoopenObjects) {
1595             KexiPart::Info *i = Kexi::partManager().infoForPluginId(info.value("type"));
1596             if (!i) {
1597                 not_found_msg += "<li>";
1598                 if (!info.value("name").isEmpty()) {
1599                     not_found_msg += (QString("\"") + info.value("name") + "\" - ");
1600                 }
1601                 if (info.value("action") == "new") {
1602                     not_found_msg += xi18n("cannot create object - unknown object type \"%1\"",
1603                                            info.value("type"));
1604                 } else {
1605                     not_found_msg += xi18n("unknown object type \"%1\"", info.value("type"));
1606                 }
1607                 not_found_msg += internalReason(Kexi::partManager().result()) + "<br></li>";
1608                 continue;
1609             }
1610             // * NEW
1611             if (info.value("action") == "new") {
1612                 if (!newObject(i, &openingCancelled) && !openingCancelled) {
1613                     not_found_msg += "<li>";
1614                     not_found_msg
1615                         += (xi18n("cannot create object of type \"%1\"", info.value("type"))
1616                             + internalReason(d->prj->result()) + "<br></li>");
1617                 } else {
1618                     d->wasAutoOpen = true;
1619                 }
1620                 continue;
1621             }
1622 
1623             KexiPart::Item *item = d->prj->item(i, info.value("name"));
1624             if (!item) {
1625                 QString taskName;
1626                 if (info.value("action") == "execute") {
1627                     taskName = xi18nc("\"executing object\" action", "executing");
1628 #ifdef KEXI_QUICK_PRINTING_SUPPORT
1629                 } else if (info->value("action") == "print-preview") {
1630                     taskName = futureI18n("making print preview for");
1631                 } else if (info->value("action") == "print") {
1632                     taskName = futureI18n("printing");
1633 #endif
1634                 } else {
1635                     taskName = xi18n("opening");
1636                 }
1637 
1638                 not_found_msg += (QString("<li>") + taskName + " \"" + info.value("name") + "\" - ");
1639                 if ("table" == info.value("type").toLower()) {
1640                     not_found_msg += xi18n("table not found");
1641                 } else if ("query" == info.value("type").toLower()) {
1642                     not_found_msg += xi18n("query not found");
1643                 } else if ("macro" == info.value("type").toLower()) {
1644                     not_found_msg += xi18n("macro not found");
1645                 } else if ("script" == info.value("type").toLower()) {
1646                     not_found_msg += xi18n("script not found");
1647                 } else {
1648                     not_found_msg += xi18n("object not found");
1649                 }
1650                 not_found_msg += (internalReason(d->prj->result()) + "<br></li>");
1651                 continue;
1652             }
1653             // * EXECUTE, PRINT, PRINT PREVIEW
1654             if (info.value("action") == "execute") {
1655                 tristate res = executeItem(item);
1656                 if (false == res) {
1657                     not_found_msg += (QString("<li>\"") + info.value("name") + "\" - "
1658                                       + xi18n("cannot execute object")
1659                                       + internalReason(d->prj->result()) + "<br></li>");
1660                 }
1661                 continue;
1662             }
1663 #ifdef KEXI_QUICK_PRINTING_SUPPORT
1664             else if (info.value("action") == "print") {
1665                 tristate res = printItem(item);
1666                 if (false == res) {
1667                     not_found_msg += (QString("<li>\"") + info.value("name") + "\" - " + futureI18n("cannot print object") +
1668                                       internalReason(d->prj->result()) + "<br></li>");
1669                 }
1670                 continue;
1671             }
1672             else if (info.value("action") == "print-preview") {
1673                 tristate res = printPreviewForItem(item);
1674                 if (false == res) {
1675                     not_found_msg += (QString("<li>\"") + info.value("name") + "\" - " + futureI18n("cannot make print preview of object") +
1676                                       internalReason(d->prj->result()) + "<br></li>");
1677                 }
1678                 continue;
1679             }
1680 #endif
1681 
1682             Kexi::ViewMode viewMode;
1683             if (info.value("action") == "open") {
1684                 viewMode = Kexi::DataViewMode;
1685             } else if (info.value("action") == "design") {
1686                 viewMode = Kexi::DesignViewMode;
1687             } else if (info.value("action") == "edittext") {
1688                 viewMode = Kexi::TextViewMode;
1689             } else {
1690                 continue; //sanity
1691             }
1692 
1693             QString openObjectMessage;
1694             if (!openObject(item, viewMode, &openingCancelled, 0, &openObjectMessage)
1695                     && (!openingCancelled || !openObjectMessage.isEmpty()))
1696             {
1697                 not_found_msg += (QString("<li>\"") + info.value("name") + "\" - ");
1698                 if (openObjectMessage.isEmpty()) {
1699                     not_found_msg += xi18n("cannot open object");
1700                 } else {
1701                     not_found_msg += openObjectMessage;
1702                 }
1703                 not_found_msg += internalReason(d->prj->result()) + "<br></li>";
1704                 continue;
1705             } else {
1706                 d->wasAutoOpen = true;
1707             }
1708         }
1709     }
1710     setMessagesEnabled(true);
1711 
1712     if (!not_found_msg.isEmpty()) {
1713         showErrorMessage(xi18n("You have requested selected objects to be automatically opened "
1714                               "or processed on startup. Several objects cannot be opened or processed."),
1715                          QString("<ul>%1</ul>").arg(not_found_msg));
1716     }
1717     d->updatePropEditorVisibility(currentWindow() ? currentWindow()->currentViewMode() : Kexi::NoViewMode);
1718 #if defined(KDOCKWIDGET_P)
1719     if (d->propEditor) {
1720         KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget();
1721         KDockSplitter *ds = (KDockSplitter *)dw->parentWidget();
1722         if (ds)
1723             ds->setSeparatorPosInPercent(d->config->readEntry("RightDockPosition", 80/* % */));
1724     }
1725 #endif
1726 
1727     updateAppCaption();
1728     if (d->tabbedToolBar) {
1729         d->tabbedToolBar->hideMainMenu();
1730     }
1731 
1732     qApp->processEvents();
1733     emit projectOpened();
1734 }
1735 
1736 tristate KexiMainWindow::closeProject()
1737 {
1738     if (d->tabbedToolBar)
1739         d->tabbedToolBar->hideMainMenu();
1740 
1741 #ifndef KEXI_NO_PENDING_DIALOGS
1742     if (d->pendingWindowsExist()) {
1743         qDebug() << "pendingWindowsExist...";
1744         d->actionToExecuteWhenPendingJobsAreFinished = Private::CloseProjectAction;
1745         return cancelled;
1746     }
1747 #endif
1748 
1749     //only save nav. visibility setting if there is project opened
1750     d->saveSettingsForShowProjectNavigator = d->prj && d->isProjectNavigatorVisible;
1751 
1752     if (!d->prj)
1753         return true;
1754 
1755     {
1756         // make sure the project can be closed
1757         bool cancel = false;
1758         emit acceptProjectClosingRequested(&cancel);
1759         if (cancel)
1760             return cancelled;
1761     }
1762 
1763     d->windowExistedBeforeCloseProject = currentWindow();
1764 
1765 #if defined(KDOCKWIDGET_P)
1766     //remember docks position - will be used on storeSettings()
1767     if (d->propEditor) {
1768         KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget();
1769         KDockSplitter *ds = (KDockSplitter *)dw->parentWidget();
1770         if (ds)
1771             d->propEditorDockSeparatorPos = ds->separatorPosInPercent();
1772     }
1773     if (d->nav) {
1774         if (d->propEditor) {
1775 //! @todo KEXI3 if (d->openedWindowsCount() == 0)
1776 //! @todo KEXI3 makeWidgetDockVisible(d->propEditorTabWidget);
1777             KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget();
1778             KDockSplitter *ds = (KDockSplitter *)dw->parentWidget();
1779             if (ds)
1780                 ds->setSeparatorPosInPercent(80);
1781         }
1782 
1783         KDockWidget *dw = (KDockWidget *)d->nav->parentWidget();
1784         KDockSplitter *ds = (KDockSplitter *)dw->parentWidget();
1785         int dwWidth = dw->width();
1786         if (ds) {
1787             if (d->openedWindowsCount() != 0 && d->propEditorTabWidget && d->propEditorTabWidget->isVisible()) {
1788                 d->navDockSeparatorPos = ds->separatorPosInPercent();
1789             }
1790             else {
1791                 d->navDockSeparatorPos = (100 * dwWidth) / width();
1792             }
1793         }
1794     }
1795 #endif
1796 
1797     //close each window, optionally asking if user wants to close (if data changed)
1798     while (currentWindow()) {
1799         tristate res = closeWindow(currentWindow());
1800         if (!res || ~res)
1801             return res;
1802     }
1803 
1804     // now we will close for sure
1805     emit beforeProjectClosing();
1806 
1807     if (!d->prj->closeConnection())
1808         return false;
1809 
1810     if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) {
1811         d->navWasVisibleBeforeProjectClosing = d->objectViewWidget->projectNavigator()->isVisible();
1812         d->setProjectNavigatorVisible(false);
1813         d->objectViewWidget->projectNavigator()->setProject(0);
1814         //slotProjectNavigatorVisibilityChanged(true); // hide side tab
1815     }
1816 
1817     if (d->objectViewWidget && d->objectViewWidget->propertyPane()) {
1818         d->objectViewWidget->propertyPane()->hide();
1819         d->action_show_propeditor->setChecked(false);
1820     }
1821     d->clearWindows(); //sanity!
1822     delete d->prj;
1823     d->prj = 0;
1824 
1825     updateReadOnlyState();
1826     invalidateActions();
1827     updateAppCaption();
1828     if (d->userMode) {
1829         d->modeSelector->setCurrentMode(Kexi::WelcomeGlobalMode);
1830     }
1831 
1832     emit projectClosed();
1833     return true;
1834 }
1835 
1836 void KexiMainWindow::setupContextHelp()
1837 {
1838 #ifdef KEXI_SHOW_CONTEXT_HELP
1839     d->ctxHelp = new KexiContextHelp(d->mainWidget, this);
1840     //! @todo
1841     /*
1842       d->ctxHelp->setContextHelp(xi18n("Welcome"),xi18n("The <B>KEXI team</B> wishes you a lot of productive work, "
1843         "with this product. <BR><HR><BR>If you have found a <B>bug</B> or have a <B>feature</B> request, please don't "
1844         "hesitate to report it at our <A href=\"http://www.kexi-project.org/cgi-bin/bug.pl\"> issue "
1845         "tracking system </A>.<BR><HR><BR>If you would like to <B>join</B> our effort, the <B>development</B> documentation "
1846         "at <A href=\"http://www.kexi-project.org\">www.kexi-project.org</A> is a good starting point."),0);
1847     */
1848     addToolWindow(d->ctxHelp, KDockWidget::DockBottom | KDockWidget::DockLeft, getMainDockWidget(), 20);
1849 #endif
1850 }
1851 
1852 void KexiMainWindow::setupMainWidget()
1853 {
1854     QWidget *centralWidget = new QWidget;
1855     setCentralWidget(centralWidget);
1856 
1857     QVBoxLayout *vlyr = new QVBoxLayout(centralWidget);
1858     vlyr->setContentsMargins(0, 0, 0, 0);
1859     vlyr->setSpacing(0);
1860 
1861     if (d->isMainMenuVisible) {
1862         QWidget *tabbedToolBarContainer = new QWidget(this);
1863         vlyr->addWidget(tabbedToolBarContainer);
1864         QVBoxLayout *tabbedToolBarContainerLyr = new QVBoxLayout(tabbedToolBarContainer);
1865         tabbedToolBarContainerLyr->setSpacing(0);
1866         tabbedToolBarContainerLyr->setContentsMargins(
1867             KexiUtils::marginHint() / 2, KexiUtils::marginHint() / 2,
1868             KexiUtils::marginHint() / 2, KexiUtils::marginHint() / 2);
1869 
1870         d->tabbedToolBar = new KexiTabbedToolBar(tabbedToolBarContainer);
1871         Q_ASSERT(d->action_tools_locate);
1872         connect(d->action_tools_locate, SIGNAL(triggered()),
1873                 d->tabbedToolBar, SLOT(activateSearchLineEdit()));
1874         tabbedToolBarContainerLyr->addWidget(d->tabbedToolBar);
1875         d->tabbedToolBar->hideTab("form"); //temporarily until createToolbar is split
1876         d->tabbedToolBar->hideTab("report"); //temporarily until createToolbar is split
1877     }
1878     else {
1879         d->tabbedToolBar = 0;
1880     }
1881 
1882     QWidget *mainWidgetContainer = new QWidget();
1883     vlyr->addWidget(mainWidgetContainer, 1);
1884     QHBoxLayout *mainWidgetContainerLyr = new QHBoxLayout(mainWidgetContainer);
1885     mainWidgetContainerLyr->setContentsMargins(0, 0, 0, 0);
1886     mainWidgetContainerLyr->setSpacing(0);
1887 
1888     d->modeSelector = new KexiGlobalViewModeSelector;
1889     connect(d->modeSelector, &KexiGlobalViewModeSelector::currentModeChanged,
1890             this, &KexiMainWindow::slotCurrentModeChanged);
1891     mainWidgetContainerLyr->addWidget(d->modeSelector);
1892     if (d->userMode) {
1893         d->modeSelector->hide();
1894     }
1895 
1896     d->globalViewStack = new QStackedWidget;
1897     mainWidgetContainerLyr->addWidget(d->globalViewStack, 1);
1898 }
1899 
1900 //void KexiMainWindow::slotSetProjectNavigatorVisible(bool set)
1901 //{
1902 //    if (d->navDockWidget)
1903 //        d->navDockWidget->setVisible(set);
1904 //}
1905 
1906 //void KexiMainWindow::slotSetPropertyEditorVisible(bool set)
1907 //{
1908 //    if (d->propEditorDockWidget)
1909 //        d->propEditorDockWidget->setVisible(set);
1910 //}
1911 
1912 //void KexiMainWindow::slotProjectNavigatorVisibilityChanged(bool visible)
1913 //{
1914 //    d->setTabBarVisible(KMultiTabBar::Left, PROJECT_NAVIGATOR_TABBAR_ID,
1915 //                        d->navDockWidget, !visible);
1916 //}
1917 
1918 //void KexiMainWindow::slotPropertyEditorVisibilityChanged(bool visible)
1919 //{
1920 //    if (!d->enable_slotPropertyEditorVisibilityChanged)
1921 //        return;
1922 //    d->setPropertyEditorTabBarVisible(!visible);
1923 //    if (!visible)
1924 //        d->propertyEditorCollapsed = true;
1925 //}
1926 
1927 /*
1928 void KexiMainWindow::slotMultiTabBarTabClicked(int id)
1929 {
1930     if (id == PROJECT_NAVIGATOR_TABBAR_ID) {
1931         slotProjectNavigatorVisibilityChanged(true);
1932         d->navDockWidget->show();
1933     }
1934     else if (id == PROPERTY_EDITOR_TABBAR_ID) {
1935         slotPropertyEditorVisibilityChanged(true);
1936         d->propEditorDockWidget->show();
1937         d->propertyEditorCollapsed = false;
1938     }
1939 }
1940 
1941 static Qt::DockWidgetArea applyRightToLeftToDockArea(Qt::DockWidgetArea area)
1942 {
1943     if (QApplication::layoutDirection() == Qt::RightToLeft) {
1944         if (area == Qt::LeftDockWidgetArea) {
1945             return Qt::RightDockWidgetArea;
1946         }
1947         else if (area == Qt::RightDockWidgetArea) {
1948             return Qt::LeftDockWidgetArea;
1949         }
1950     }
1951     return area;
1952 }*/
1953 
1954 void KexiMainWindow::setupObjectView()
1955 {
1956     if (d->objectViewWidget) {
1957         return;
1958     }
1959     KexiObjectViewWidget::Flags flags;
1960     if (d->isProjectNavigatorVisible) {
1961         flags |= KexiObjectViewWidget::ProjectNavigatorEnabled;
1962     }
1963     if (!d->userMode) {
1964         flags |= KexiObjectViewWidget::PropertyPaneEnabled;
1965     }
1966     d->objectViewWidget = new KexiObjectViewWidget(flags);
1967     connect(d->objectViewWidget, &KexiObjectViewWidget::activeWindowChanged,
1968             this, &KexiMainWindow::activeWindowChanged);
1969     connect(d->objectViewWidget, &KexiObjectViewWidget::closeWindowRequested,
1970             this, &KexiMainWindow::closeWindowForTab);
1971     connect(d->objectViewWidget, &KexiObjectViewWidget::closeAllWindowsRequested,
1972             this, &KexiMainWindow::closeAllWindows);
1973     connect(d->objectViewWidget, &KexiObjectViewWidget::projectNavigatorAnimationFinished,
1974             this, &KexiMainWindow::slotProjectNavigatorVisibilityChanged);
1975     slotProjectNavigatorVisibilityChanged(d->objectViewWidget->projectNavigator());
1976 
1977     // Restore settings
1978     //! @todo FIX LAYOUT PROBLEMS
1979     KConfigGroup propertyEditorGroup(d->config->group("PropertyEditor"));
1980     QFont f(KexiStyle::propertyPane().font());
1981     const qreal pointSizeF = propertyEditorGroup.readEntry("FontPointSize", -1.0f); // points are more accurate
1982     if (pointSizeF > 0.0) {
1983         f.setPointSizeF(pointSizeF);
1984     } else {
1985         const int pixelSize = propertyEditorGroup.readEntry("FontSize", -1); // compatibility with Kexi 2.x
1986         if (pixelSize > 0) {
1987             f.setPixelSize(pixelSize);
1988         }
1989     }
1990     if (d->objectViewWidget->propertyPane()) {
1991         d->objectViewWidget->propertyPane()->setFont(f);
1992 
1993         KConfigGroup mainWindowGroup(d->config->group("MainWindow"));
1994         const QSize projectNavigatorSize = mainWindowGroup.readEntry<QSize>("ProjectNavigatorSize", QSize());
1995         const QSize propertyEditorSize = mainWindowGroup.readEntry<QSize>("PropertyEditorSize", QSize());
1996         d->objectViewWidget->setSidebarWidths(projectNavigatorSize.isValid() ? projectNavigatorSize.width() : -1,
1997                                               propertyEditorSize.isValid() ? propertyEditorSize.width() : -1);
1998     }
1999 
2000     d->globalViewStack->addWidget(d->objectViewWidget);
2001     KexiProjectNavigator* navigator = d->objectViewWidget->projectNavigator();
2002     if (navigator) {
2003         //connect(d->navDockWidget, SIGNAL(visibilityChanged(bool)),
2004         //    this, SLOT(slotProjectNavigatorVisibilityChanged(bool)));
2005 
2006         //Nav2 Signals
2007         connect(navigator, SIGNAL(openItem(KexiPart::Item*,Kexi::ViewMode)),
2008                 this, SLOT(openObject(KexiPart::Item*,Kexi::ViewMode)));
2009         connect(navigator, SIGNAL(openOrActivateItem(KexiPart::Item*,Kexi::ViewMode)),
2010                 this, SLOT(openObjectFromNavigator(KexiPart::Item*,Kexi::ViewMode)));
2011         connect(navigator, SIGNAL(newItem(KexiPart::Info*)),
2012                 this, SLOT(newObject(KexiPart::Info*)));
2013         connect(navigator, SIGNAL(removeItem(KexiPart::Item*)),
2014                 this, SLOT(removeObject(KexiPart::Item*)));
2015         connect(navigator->model(), SIGNAL(renameItem(KexiPart::Item*,QString,bool*)),
2016                 this, SLOT(renameObject(KexiPart::Item*,QString,bool*)));
2017         connect(navigator->model(), SIGNAL(changeItemCaption(KexiPart::Item*,QString,bool*)),
2018                 this, SLOT(setObjectCaption(KexiPart::Item*,QString,bool*)));
2019         connect(navigator, SIGNAL(executeItem(KexiPart::Item*)),
2020                 this, SLOT(executeItem(KexiPart::Item*)));
2021         connect(navigator, SIGNAL(exportItemToClipboardAsDataTable(KexiPart::Item*)),
2022                 this, SLOT(copyItemToClipboardAsDataTable(KexiPart::Item*)));
2023         connect(navigator, SIGNAL(exportItemToFileAsDataTable(KexiPart::Item*)),
2024                 this, SLOT(exportItemAsDataTable(KexiPart::Item*)));
2025 #ifdef KEXI_QUICK_PRINTING_SUPPORT
2026         connect(navigator, SIGNAL(printItem(KexiPart::Item*)),
2027                 this, SLOT(printItem(KexiPart::Item*)));
2028         connect(navigator, SIGNAL(pageSetupForItem(KexiPart::Item*)),
2029                 this, SLOT(showPageSetupForItem(KexiPart::Item*)));
2030 #endif
2031         connect(navigator, SIGNAL(selectionChanged(KexiPart::Item*)),
2032                 this, SLOT(slotPartItemSelectedInNavigator(KexiPart::Item*)));
2033     }
2034 
2035     if (navigator) {
2036         if (d->prj) {
2037             connect(d->prj, SIGNAL(newItemStored(KexiPart::Item*)),
2038                     navigator->model(), SLOT(slotAddItem(KexiPart::Item*)));
2039             connect(d->prj, SIGNAL(itemRemoved(KexiPart::Item)),
2040                     navigator->model(), SLOT(slotRemoveItem(KexiPart::Item)));
2041             navigator->setFocus();
2042         }
2043 
2044         /*if (d->forceShowProjectNavigatorOnCreation) {
2045             slotShowNavigator();
2046             d->forceShowProjectNavigatorOnCreation = false;
2047         } else if (d->forceHideProjectNavigatorOnCreation) {
2048             d->forceHideProjectNavigatorOnCreation = false;
2049         }*/
2050     }
2051 
2052     invalidateActions();
2053 }
2054 
2055 void KexiMainWindow::updateObjectView()
2056 {
2057     setupObjectView();
2058 
2059     if (d->prj && d->prj->isConnected()) {
2060         KexiProjectNavigator* navigator = d->objectViewWidget->projectNavigator();
2061         if (navigator && !navigator->model()->project()) {
2062             QString partManagerErrorMessages;
2063             navigator->setProject(d->prj, QString()/*all classes*/, &partManagerErrorMessages);
2064             if (partManagerErrorMessages.isEmpty()) {
2065                 d->setProjectNavigatorVisible(true);
2066             } else {
2067                 showWarningContinueMessage(partManagerErrorMessages, QString(),
2068                                            "ShowWarningsRelatedToPluginsLoading");
2069             }
2070         }
2071     }
2072 }
2073 
2074 void KexiMainWindow::slotLastActions()
2075 {
2076 }
2077 
2078 void KexiMainWindow::slotPartLoaded(KexiPart::Part* p)
2079 {
2080     if (!p)
2081         return;
2082     p->createGUIClients();
2083 }
2084 
2085 void KexiMainWindow::updateAppCaption()
2086 {
2087 //! @todo allow to set custom "static" app caption
2088 
2089     d->appCaptionPrefix.clear();
2090     if (d->prj && d->prj->data()) {//add project name
2091         d->appCaptionPrefix = d->prj->data()->caption();
2092         if (d->appCaptionPrefix.isEmpty()) {
2093             d->appCaptionPrefix = d->prj->data()->databaseName();
2094         }
2095         if (d->prj->dbConnection()->options()->isReadOnly()) {
2096             d->appCaptionPrefix = xi18nc("<project-name> (read only)", "%1 (read only)", d->appCaptionPrefix);
2097         }
2098     }
2099 
2100     setWindowTitle(d->appCaptionPrefix);
2101 }
2102 
2103 bool KexiMainWindow::queryClose()
2104 {
2105 #ifndef KEXI_NO_PENDING_DIALOGS
2106     if (d->pendingWindowsExist()) {
2107         qDebug() << "pendingWindowsExist...";
2108         d->actionToExecuteWhenPendingJobsAreFinished = Private::QuitAction;
2109         return false;
2110     }
2111 #endif
2112     const tristate res = closeProject();
2113     if (~res)
2114         return false;
2115 
2116     if (res == true)
2117         storeSettings();
2118 
2119     if (! ~res) {
2120         Kexi::deleteGlobalObjects();
2121         qApp->quit();
2122     }
2123     return ! ~res;
2124 }
2125 
2126 void KexiMainWindow::closeEvent(QCloseEvent *ev)
2127 {
2128     if (queryClose()) {
2129         ev->accept();
2130     } else {
2131         ev->ignore();
2132     }
2133 }
2134 
2135 void KexiMainWindow::resizeEvent(QResizeEvent *e)
2136 {
2137     QMainWindow::resizeEvent(e);
2138     //qDebug() << "===" << e->size() << size() << isVisible();
2139 }
2140 
2141 static const QSize KEXI_MIN_WINDOW_SIZE(1024, 768);
2142 
2143 void
2144 KexiMainWindow::restoreSettings()
2145 {
2146     KConfigGroup mainWindowGroup(d->config->group("MainWindow"));
2147     const bool maximize = mainWindowGroup.readEntry("Maximized", false);
2148     const QRect geometry(mainWindowGroup.readEntry("Geometry", QRect()));
2149     if (geometry.isValid())
2150         setGeometry(geometry);
2151     else if (maximize)
2152         setWindowState(windowState() | Qt::WindowMaximized);
2153     else {
2154         QRect desk = QApplication::desktop()->screenGeometry(
2155             QApplication::desktop()->screenNumber(this));
2156         if (desk.width() <= KEXI_MIN_WINDOW_SIZE.width()
2157                 || desk.height() <= KEXI_MIN_WINDOW_SIZE.height())
2158         {
2159             setWindowState(windowState() | Qt::WindowMaximized);
2160         } else {
2161             resize(KEXI_MIN_WINDOW_SIZE);
2162         }
2163     }
2164 }
2165 
2166 void
2167 KexiMainWindow::storeSettings()
2168 {
2169     //qDebug();
2170     KConfigGroup mainWindowGroup(d->config->group("MainWindow"));
2171 
2172     if (isMaximized()) {
2173         mainWindowGroup.writeEntry("Maximized", true);
2174         mainWindowGroup.deleteEntry("Geometry");
2175     } else {
2176         mainWindowGroup.deleteEntry("Maximized");
2177         mainWindowGroup.writeEntry("Geometry", geometry());
2178     }
2179 
2180     if (d->objectViewWidget) {
2181         int projectNavigatorWidth;
2182         int propertyEditorWidth;
2183         d->objectViewWidget->getSidebarWidths(&projectNavigatorWidth, &propertyEditorWidth);
2184         if (projectNavigatorWidth > 0) {
2185             mainWindowGroup.writeEntry("ProjectNavigatorSize", QSize(projectNavigatorWidth, 1));
2186         }
2187         if (propertyEditorWidth > 0) {
2188             mainWindowGroup.writeEntry("PropertyEditorSize", QSize(propertyEditorWidth, 1));
2189         }
2190     }
2191     d->config->sync();
2192 }
2193 
2194 void
2195 KexiMainWindow::registerChild(KexiWindow *window)
2196 {
2197     //qDebug();
2198     connect(window, SIGNAL(dirtyChanged(KexiWindow*)), this, SLOT(slotDirtyFlagChanged(KexiWindow*)));
2199 
2200     if (window->id() != -1) {
2201         d->insertWindow(window);
2202     }
2203     //qDebug() << "ID=" << window->id();
2204 }
2205 
2206 void KexiMainWindow::updateCustomPropertyPanelTabs(KexiWindow *prevWindow,
2207         Kexi::ViewMode prevViewMode)
2208 {
2209     updateCustomPropertyPanelTabs(
2210         prevWindow ? prevWindow->part() : 0,
2211         prevWindow ? prevWindow->currentViewMode() : prevViewMode,
2212         currentWindow() ? currentWindow()->part() : 0,
2213         currentWindow() ? currentWindow()->currentViewMode() : Kexi::NoViewMode
2214     );
2215 }
2216 
2217 void KexiMainWindow::updateCustomPropertyPanelTabs(
2218     KexiPart::Part *prevWindowPart, Kexi::ViewMode prevViewMode,
2219     KexiPart::Part *curWindowPart, Kexi::ViewMode curViewMode)
2220 {
2221     if (!d->objectViewWidget || !d->objectViewWidget->propertyPane())
2222         return;
2223 
2224     if (   !curWindowPart
2225         || (/*prevWindowPart &&*/ curWindowPart
2226              && (prevWindowPart != curWindowPart || prevViewMode != curViewMode)
2227            )
2228        )
2229     {
2230 #ifdef __GNUC__
2231 #warning TODO KexiMainWindow::updateCustomPropertyPanelTabs()
2232 #else
2233 #pragma WARNING(TODO KexiMainWindow::updateCustomPropertyPanelTabs())
2234 #endif
2235 #if 0
2236         if (d->partForPreviouslySetupPropertyPanelTabs) {
2237             //remember current page number for this part
2238             if ((   prevViewMode == Kexi::DesignViewMode
2239                  && static_cast<KexiPart::Part*>(d->partForPreviouslySetupPropertyPanelTabs) != curWindowPart) //part changed
2240                 || curViewMode != Kexi::DesignViewMode)
2241             { //..or switching to other view mode
2242                 d->recentlySelectedPropertyPanelPages.insert(
2243                         d->partForPreviouslySetupPropertyPanelTabs,
2244                         d->objectViewWidget->propertyPane()->currentIndex());
2245             }
2246         }
2247 
2248         //delete old custom tabs (other than 'property' tab)
2249         const int count = d->objectViewWidget->propertyEditorTabWidget()->count();
2250         for (int i = 1; i < count; i++)
2251             d->objectViewWidget->propertyEditorTabWidget()->removeTab(1);
2252 #endif
2253     }
2254 
2255     //don't change anything if part is not switched nor view mode changed
2256     if ((!prevWindowPart && !curWindowPart)
2257             || (prevWindowPart == curWindowPart && prevViewMode == curViewMode)
2258             || (curWindowPart && curViewMode != Kexi::DesignViewMode))
2259     {
2260         //new part for 'previously setup tabs'
2261         d->partForPreviouslySetupPropertyPanelTabs = curWindowPart;
2262         return;
2263     }
2264 
2265     if (curWindowPart) {
2266         //recreate custom tabs
2267         d->objectViewWidget->propertyPane()->removeAllSections();
2268         curWindowPart->setupPropertyPane(d->objectViewWidget->propertyPane());
2269 
2270 #ifdef __GNUC__
2271 #warning TODO KexiMainWindow::updateCustomPropertyPanelTabs()
2272 #else
2273 #pragma WARNING(TODO KexiMainWindow::updateCustomPropertyPanelTabs())
2274 #endif
2275 #if 0
2276         //restore current page number for this part
2277         if (d->recentlySelectedPropertyPanelPages.contains(curWindowPart)) {
2278             d->objectViewWidget->propertyEditorTabWidget()->setCurrentIndex(
2279                 d->recentlySelectedPropertyPanelPages[ curWindowPart ]
2280             );
2281         }
2282 #endif
2283     }
2284 //#endif
2285     //new part for 'previously setup tabs'
2286     d->partForPreviouslySetupPropertyPanelTabs = curWindowPart;
2287 }
2288 
2289 void KexiMainWindow::activeWindowChanged(KexiWindow *window, KexiWindow *prevWindow)
2290 {
2291     //qDebug() << "to=" << (window ? window->windowTitle() : "<none>");
2292     bool windowChanged = prevWindow != window;
2293 
2294     if (windowChanged) {
2295         if (prevWindow) {
2296             //inform previously activated dialog about deactivation
2297             prevWindow->deactivate();
2298         }
2299     }
2300 
2301     updateCustomPropertyPanelTabs(prevWindow, prevWindow ? prevWindow->currentViewMode() : Kexi::NoViewMode);
2302 
2303     // inform the current view of the new dialog about property switching
2304     // (this will also call KexiMainWindow::propertySetSwitched() to update the current property editor's set
2305     if (windowChanged && currentWindow())
2306         currentWindow()->selectedView()->propertySetSwitched();
2307 
2308     if (windowChanged) {
2309         if (currentWindow() && currentWindow()->currentViewMode() != 0 && window) {
2310             setCurrentMode(viewModeToGlobal(currentWindow()->currentViewMode()));
2311 
2312             //on opening new dialog it can be 0; we don't want this
2313             d->updatePropEditorVisibility(currentWindow()->currentViewMode());
2314 
2315             restoreDesignTabIfNeeded(window->partItem()->pluginId(), window->currentViewMode(),
2316                                      prevWindow ? prevWindow->partItem()->identifier() : 0);
2317             activateDesignTabIfNeeded(window->partItem()->pluginId(),
2318                                       window->currentViewMode());
2319         }
2320     }
2321 
2322     invalidateActions();
2323     d->updateFindDialogContents();
2324     if (window)
2325         window->setFocus();
2326 }
2327 
2328 bool
2329 KexiMainWindow::activateWindow(int id)
2330 {
2331 #ifndef KEXI_NO_PENDING_DIALOGS
2332     Private::PendingJobType pendingType;
2333     return activateWindow(*d->openedWindowFor(id, pendingType));
2334 #else
2335     return activateWindow(*d->openedWindowFor(id));
2336 #endif
2337 }
2338 
2339 bool
2340 KexiMainWindow::activateWindow(KexiWindow& window)
2341 {
2342     //qDebug();
2343 
2344     d->focus_before_popup = &window;
2345     d->objectViewWidget->tabWidget()->setCurrentWidget(window.parentWidget()/*container*/);
2346     window.activate();
2347     return true;
2348 }
2349 
2350 void KexiMainWindow::activateNextWindow()
2351 {
2352     // Case 1: go to next assistant page
2353     KexiAssistantPage *page = d->visibleMainMenuWidgetPage();
2354     if (page) {
2355         page->next();
2356         return;
2357     }
2358     // Case 2: go to next tab
2359     activateNextTab();
2360 }
2361 
2362 void KexiMainWindow::activatePreviousWindow()
2363 {
2364     // Case 1: go to previous assistant page
2365     KexiAssistantPage *page = d->visibleMainMenuWidgetPage();
2366     if (page) {
2367         page->tryBack();
2368         return;
2369     }
2370     // Case 2: go to previous tab
2371     activatePreviousTab();
2372 }
2373 
2374 void KexiMainWindow::activateNextTab()
2375 {
2376     int index = d->objectViewWidget->tabWidget()->currentIndex() + 1;
2377     if (index >= d->objectViewWidget->tabWidget()->count()) {
2378         index = 0;
2379     }
2380     d->objectViewWidget->tabWidget()->setCurrentIndex(index);
2381 }
2382 
2383 void KexiMainWindow::activatePreviousTab()
2384 {
2385     int index = d->objectViewWidget->tabWidget()->currentIndex() - 1;
2386     if (index < 0) {
2387         index = d->objectViewWidget->tabWidget()->count() - 1;
2388     }
2389     d->objectViewWidget->tabWidget()->setCurrentIndex(index);
2390 }
2391 
2392 void
2393 KexiMainWindow::slotSettings()
2394 {
2395     if (d->tabbedToolBar) {
2396         d->tabbedToolBar->showMainMenu("settings");
2397         // dummy
2398         QLabel *dummy = KEXI_UNFINISHED_LABEL(actionCollection()->action("settings")->text());
2399         d->tabbedToolBar->setMainMenuContent(dummy);
2400     }
2401 }
2402 
2403 void
2404 KexiMainWindow::slotConfigureKeys()
2405 {
2406     KShortcutsDialog::configure(actionCollection(),
2407                                 KShortcutsEditor::LetterShortcutsDisallowed, this);
2408 }
2409 
2410 void
2411 KexiMainWindow::slotConfigureToolbars()
2412 {
2413     KEditToolBar edit(actionCollection());
2414     (void) edit.exec();
2415 }
2416 
2417 void KexiMainWindow::slotProjectNew()
2418 {
2419     createNewProject();
2420 }
2421 
2422 KexiProject* KexiMainWindow::createKexiProjectObject(const KexiProjectData &data)
2423 {
2424     KexiProject *prj = new KexiProject(data, this);
2425     connect(prj, SIGNAL(itemRenamed(KexiPart::Item,QString)), this, SLOT(slotObjectRenamed(KexiPart::Item,QString)));
2426 
2427     if (d->objectViewWidget && d->objectViewWidget->projectNavigator()){
2428         connect(prj, SIGNAL(itemRemoved(KexiPart::Item)),
2429                 d->objectViewWidget->projectNavigator()->model(),
2430                 SLOT(slotRemoveItem(KexiPart::Item)));
2431     }
2432     return prj;
2433 }
2434 
2435 void KexiMainWindow::createNewProject()
2436 {
2437     if (!d->tabbedToolBar)
2438         return;
2439     d->tabbedToolBar->showMainMenu("project_new");
2440     KexiNewProjectAssistant* assistant = new KexiNewProjectAssistant;
2441     connect(assistant, SIGNAL(createProject(KexiProjectData)),
2442             this, SLOT(createNewProject(KexiProjectData)));
2443 
2444     d->tabbedToolBar->setMainMenuContent(assistant);
2445 }
2446 
2447 tristate KexiMainWindow::createNewProject(const KexiProjectData &projectData)
2448 {
2449     QScopedPointer<KexiProject> prj(createKexiProjectObject(projectData));
2450     tristate res = prj->create(true /*overwrite*/);
2451     if (res != true) {
2452         return res;
2453     }
2454     //qDebug() << "new project created ---";
2455     if (d->prj) {
2456         res = openProjectInExternalKexiInstance(
2457                 prj->data()->connectionData()->databaseName(),
2458                 prj->data()->connectionData(),
2459                 prj->data()->databaseName());
2460         Kexi::recentProjects()->addProjectData(*prj->data());
2461         if (d->tabbedToolBar) {
2462             d->tabbedToolBar->hideMainMenu();
2463         }
2464         return res;
2465     }
2466     if (d->tabbedToolBar) {
2467         d->tabbedToolBar->hideMainMenu();
2468     }
2469     d->prj = prj.take();
2470     d->prj->data()->setLastOpened(QDateTime::currentDateTime());
2471     Kexi::recentProjects()->addProjectData(*d->prj->data());
2472     d->modeSelector->setCurrentMode(Kexi::EditGlobalMode);
2473 
2474     invalidateActions();
2475     updateAppCaption();
2476     return true;
2477 }
2478 
2479 void KexiMainWindow::slotProjectOpen()
2480 {
2481     if (!d->tabbedToolBar)
2482         return;
2483     d->tabbedToolBar->showMainMenu("project_open");
2484     KexiOpenProjectAssistant* assistant = new KexiOpenProjectAssistant;
2485     connect(assistant, SIGNAL(openProject(KexiProjectData)),
2486             this, SLOT(openProject(KexiProjectData)));
2487     connect(assistant, SIGNAL(openProject(QString)),
2488             this, SLOT(openProject(QString)));
2489     d->tabbedToolBar->setMainMenuContent(assistant);
2490 }
2491 
2492 tristate KexiMainWindow::openProject(const QString& aFileName)
2493 {
2494     return openProject(aFileName, QString(), QString());
2495 }
2496 
2497 tristate KexiMainWindow::openProject(const QString& aFileName,
2498                                      const QString& fileNameForConnectionData, const QString& dbName)
2499 {
2500     if (d->prj)
2501         return openProjectInExternalKexiInstance(aFileName, fileNameForConnectionData, dbName);
2502 
2503     KDbConnectionData *cdata = 0;
2504     if (!fileNameForConnectionData.isEmpty()) {
2505         cdata = Kexi::connset().connectionDataForFileName(fileNameForConnectionData);
2506         if (!cdata) {
2507             qWarning() << "cdata?";
2508             return false;
2509         }
2510     }
2511     return openProject(aFileName, cdata, dbName);
2512 }
2513 
2514 tristate KexiMainWindow::openProject(const QString& aFileName,
2515                                      KDbConnectionData *cdata, const QString& dbName,
2516                                      const KexiProjectData::AutoOpenObjects& autoopenObjects)
2517 {
2518     if (d->prj) {
2519         return openProjectInExternalKexiInstance(aFileName, cdata, dbName);
2520     }
2521 
2522     KexiProjectData* projectData = 0;
2523     const KexiStartupHandler *h = KexiStartupHandler::global();
2524     bool readOnly = h->isSet(h->options().readOnly);
2525     bool deleteAfterOpen = false;
2526     if (cdata) {
2527         //server-based project
2528         if (dbName.isEmpty()) {//no database name given, ask user
2529             bool cancel;
2530             projectData = KexiStartupHandler::global()->selectProject(cdata, &cancel, this);
2531             if (cancel)
2532                 return cancelled;
2533         } else {
2534 //! @todo caption arg?
2535             projectData = new KexiProjectData(*cdata, dbName);
2536             deleteAfterOpen = true;
2537         }
2538     } else {
2539         if (aFileName.isEmpty()) {
2540             qWarning() << "aFileName.isEmpty()";
2541             return false;
2542         }
2543         //file-based project
2544         //qDebug() << "Project File:" << aFileName;
2545         KDbConnectionData fileConnData;
2546         fileConnData.setDatabaseName(aFileName);
2547         QString detectedDriverId;
2548         int detectOptions = 0;
2549         if (readOnly) {
2550             detectOptions |= KexiStartupHandler::OpenReadOnly;
2551         }
2552         KexiStartupData::Import importActionData;
2553         bool forceReadOnly;
2554         const tristate res = KexiStartupHandler::detectActionForFile(
2555                                  &importActionData, &detectedDriverId, fileConnData.driverId(),
2556                                  aFileName, this, detectOptions, &forceReadOnly);
2557         if (forceReadOnly) {
2558             readOnly = true;
2559         }
2560         if (true != res)
2561             return res;
2562 
2563         if (importActionData) { //importing requested
2564             return showProjectMigrationWizard(importActionData.mimeType, importActionData.fileName);
2565         }
2566         fileConnData.setDriverId(detectedDriverId);
2567 
2568         if (fileConnData.driverId().isEmpty())
2569             return false;
2570 
2571         //opening requested
2572         projectData = new KexiProjectData(fileConnData);
2573         deleteAfterOpen = true;
2574     }
2575     if (!projectData)
2576         return false;
2577     projectData->setReadOnly(readOnly);
2578     projectData->autoopenObjects = autoopenObjects;
2579     const tristate res = openProject(*projectData);
2580     if (deleteAfterOpen) //projectData object has been copied
2581         delete projectData;
2582     return res;
2583 }
2584 
2585 tristate KexiMainWindow::openProjectInExternalKexiInstance(const QString& aFileName,
2586         KDbConnectionData *cdata, const QString& dbName)
2587 {
2588     QString fileNameForConnectionData;
2589     if (aFileName.isEmpty()) { //try .kexic file
2590         if (cdata)
2591             fileNameForConnectionData = Kexi::connset().fileNameForConnectionData(*cdata);
2592     }
2593     return openProjectInExternalKexiInstance(aFileName, fileNameForConnectionData, dbName);
2594 }
2595 
2596 tristate KexiMainWindow::openProjectInExternalKexiInstance(const QString& aFileName,
2597         const QString& fileNameForConnectionData, const QString& dbName)
2598 {
2599     QString fileName(aFileName);
2600     QStringList args;
2601 
2602     // open a file-based project or a server connection provided as a .kexic file
2603     // (we have no other simple way to provide the startup data to a new process)
2604     if (fileName.isEmpty()) { //try .kexic file
2605         if (!fileNameForConnectionData.isEmpty())
2606             args << "--skip-conn-dialog"; //user does not expect conn. dialog to be shown here
2607 
2608         if (dbName.isEmpty()) { //use 'kexi --skip-conn-dialog file.kexic'
2609             fileName = fileNameForConnectionData;
2610         } else { //use 'kexi --skip-conn-dialog --connection file.kexic dbName'
2611             if (fileNameForConnectionData.isEmpty()) {
2612                 qWarning() << "fileNameForConnectionData?";
2613                 return false;
2614             }
2615             args << "--connection" << fileNameForConnectionData;
2616             fileName = dbName;
2617         }
2618     }
2619     if (fileName.isEmpty()) {
2620         qWarning() << "fileName?";
2621         return false;
2622     }
2623 //! @todo use KRun
2624 //! @todo untested
2625 //Can arguments be supplied to KRun like is used here? AP
2626     args << fileName;
2627     const bool ok = QProcess::startDetached(
2628         qApp->applicationFilePath(), args,
2629         QFileInfo(fileName).absoluteDir().absolutePath());
2630     if (!ok) {
2631         d->showStartProcessMsg(args);
2632     }
2633     if (d->tabbedToolBar) {
2634         d->tabbedToolBar->hideMainMenu();
2635     }
2636     return ok;
2637 }
2638 
2639 void KexiMainWindow::slotProjectWelcome()
2640 {
2641     if (!d->tabbedToolBar)
2642         return;
2643     d->tabbedToolBar->showMainMenu("project_welcome");
2644     KexiWelcomeAssistant* assistant = new KexiWelcomeAssistant(
2645         Kexi::recentProjects(), this);
2646     connect(assistant, SIGNAL(openProject(KexiProjectData,QString,bool*)),
2647             this, SLOT(openProject(KexiProjectData,QString,bool*)));
2648     d->tabbedToolBar->setMainMenuContent(assistant);
2649 }
2650 
2651 void
2652 KexiMainWindow::slotProjectSave()
2653 {
2654     if (!currentWindow() || currentWindow()->currentViewMode() == Kexi::DataViewMode) {
2655         return;
2656     }
2657     saveObject(currentWindow());
2658     updateAppCaption();
2659     invalidateActions();
2660 }
2661 
2662 void
2663 KexiMainWindow::slotProjectSaveAs()
2664 {
2665     if (!currentWindow() || currentWindow()->currentViewMode() == Kexi::DataViewMode) {
2666         return;
2667     }
2668     saveObject(currentWindow(), QString(), SaveObjectAs);
2669     updateAppCaption();
2670     invalidateActions();
2671 }
2672 
2673 void
2674 KexiMainWindow::slotProjectPrint()
2675 {
2676 #ifdef KEXI_QUICK_PRINTING_SUPPORT
2677     if (currentWindow() && currentWindow()->partItem())
2678         printItem(currentWindow()->partItem());
2679 #endif
2680 }
2681 
2682 void
2683 KexiMainWindow::slotProjectPrintPreview()
2684 {
2685 #ifdef KEXI_QUICK_PRINTING_SUPPORT
2686     if (currentWindow() && currentWindow()->partItem())
2687         printPreviewForItem(currentWindow()->partItem());
2688 #endif
2689 }
2690 
2691 void
2692 KexiMainWindow::slotProjectPageSetup()
2693 {
2694 #ifdef KEXI_QUICK_PRINTING_SUPPORT
2695     if (currentWindow() && currentWindow()->partItem())
2696         showPageSetupForItem(currentWindow()->partItem());
2697 #endif
2698 }
2699 
2700 void KexiMainWindow::slotProjectExportDataTable()
2701 {
2702     if (currentWindow() && currentWindow()->partItem())
2703         exportItemAsDataTable(currentWindow()->partItem());
2704 }
2705 
2706 void KexiMainWindow::slotProjectProperties()
2707 {
2708     if (!d->tabbedToolBar)
2709         return;
2710     d->tabbedToolBar->showMainMenu("project_properties");
2711     // dummy
2712     QLabel *dummy = KEXI_UNFINISHED_LABEL(actionCollection()->action("project_properties")->text());
2713     d->tabbedToolBar->setMainMenuContent(dummy);
2714     //! @todo load the implementation not the ui :)
2715 // ProjectSettingsUI u(this);
2716 // u.exec();
2717 }
2718 
2719 void KexiMainWindow::slotProjectImportExportOrSend()
2720 {
2721     if (!d->tabbedToolBar)
2722         return;
2723     d->tabbedToolBar->showMainMenu("project_import_export_send");
2724     KexiImportExportAssistant* assistant = new KexiImportExportAssistant(
2725         d->action_project_import_export_send,
2726         d->action_tools_import_project);
2727     connect(assistant, SIGNAL(importProject()), this, SLOT(slotToolsImportProject()));
2728     d->tabbedToolBar->setMainMenuContent(assistant);
2729 }
2730 
2731 void
2732 KexiMainWindow::slotProjectClose()
2733 {
2734     closeProject();
2735 }
2736 
2737 void KexiMainWindow::slotProjectRelations()
2738 {
2739     if (!d->prj)
2740         return;
2741     KexiWindow *w = KexiInternalPart::createKexiWindowInstance("org.kexi-project.relations", this);
2742     if (w) {
2743         activateWindow(*w);
2744     }
2745 }
2746 
2747 void KexiMainWindow::slotImportFile()
2748 {
2749     KEXI_UNFINISHED("Import: " + xi18n("From File..."));
2750 }
2751 
2752 void KexiMainWindow::slotImportServer()
2753 {
2754     KEXI_UNFINISHED("Import: " + xi18n("From Server..."));
2755 }
2756 
2757 void
2758 KexiMainWindow::slotProjectQuit()
2759 {
2760     if (~ closeProject())
2761         return;
2762     close();
2763 }
2764 
2765 void KexiMainWindow::slotActivateNavigator()
2766 {
2767     if (!d->objectViewWidget || !d->objectViewWidget->projectNavigator()) {
2768         return;
2769     }
2770     d->objectViewWidget->projectNavigator()->setFocus();
2771 }
2772 
2773 void KexiMainWindow::slotActivateMainArea()
2774 {
2775     if (currentWindow())
2776         currentWindow()->setFocus();
2777 }
2778 
2779 void KexiMainWindow::slotActivatePropertyPane()
2780 {
2781     if (!d->objectViewWidget || !d->objectViewWidget->propertyPane()) {
2782         return;
2783     }
2784 
2785     d->objectViewWidget->propertyPane()->setFocus();
2786 //    if (d->objectViewWidget->propertyPane()->currentWidget()) {
2787 //        d->objectViewWidget->propertyPane()->currentWidget()->setFocus();
2788 //    }
2789 }
2790 
2791 void KexiMainWindow::slotToggleProjectNavigator()
2792 {
2793     if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) {
2794         d->setProjectNavigatorVisible(!d->objectViewWidget->projectNavigator()->isVisible(), Private::ShowAnimated);
2795     }
2796 }
2797 
2798 void KexiMainWindow::slotTogglePropertyEditor()
2799 {
2800     if (d->objectViewWidget && d->objectViewWidget->propertyPane()) {
2801         d->objectViewWidget->setPropertyPaneVisible(!d->objectViewWidget->propertyPane()->isVisible());
2802     }
2803 }
2804 
2805 tristate KexiMainWindow::switchToViewMode(KexiWindow& window, Kexi::ViewMode viewMode)
2806 {
2807     const Kexi::ViewMode prevViewMode = currentWindow()->currentViewMode();
2808     if (prevViewMode == viewMode)
2809         return true;
2810     if (!activateWindow(window))
2811         return false;
2812     if (!currentWindow()) {
2813         return false;
2814     }
2815     if (&window != currentWindow())
2816         return false;
2817     if (!currentWindow()->supportsViewMode(viewMode)) {
2818         showErrorMessage(xi18nc("@info",
2819                                 "Selected view is not supported for <resource>%1</resource> object.",
2820                                 currentWindow()->partItem()->name()),
2821                          xi18nc("@info",
2822                                 "Selected view (%1) is not supported by this object type (%2).",
2823                                 Kexi::nameForViewMode(viewMode),
2824                                 currentWindow()->part()->info()->name()));
2825         return false;
2826     }
2827     setCurrentMode(viewModeToGlobal(viewMode));
2828 
2829     updateCustomPropertyPanelTabs(currentWindow()->part(), prevViewMode,
2830                                   currentWindow()->part(), viewMode);
2831     tristate res = currentWindow()->switchToViewMode(viewMode);
2832     if (!res) {
2833         updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert
2834         showErrorMessage(xi18n("Switching to other view failed (%1).",
2835                               Kexi::nameForViewMode(viewMode)), currentWindow());
2836         return false;
2837     }
2838     if (~res) {
2839         updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert
2840         return cancelled;
2841     }
2842 
2843     activateWindow(window);
2844 
2845     invalidateSharedActions();
2846     invalidateProjectWideActions();
2847     d->updateFindDialogContents();
2848     d->updatePropEditorVisibility(viewMode);
2849     QString origTabToActivate;
2850     if (viewMode == Kexi::DesignViewMode) {
2851         // Save the orig tab: we want to back to design tab
2852         // when user moved to data view and then immediately to design view.
2853         origTabToActivate = d->tabsToActivateOnShow.value(currentWindow()->partItem()->identifier());
2854     }
2855     restoreDesignTabIfNeeded(currentWindow()->partItem()->pluginId(), viewMode,
2856                              currentWindow()->partItem()->identifier());
2857     if (viewMode == Kexi::DesignViewMode) {
2858         activateDesignTab(currentWindow()->partItem()->pluginId());
2859         // Restore the saved tab to the orig one. restoreDesignTabIfNeeded() saved tools tab probably.
2860         d->tabsToActivateOnShow.insert(currentWindow()->partItem()->identifier(), origTabToActivate);
2861     }
2862 
2863     return true;
2864 }
2865 
2866 void KexiMainWindow::slotViewDataMode()
2867 {
2868     if (currentWindow())
2869         switchToViewMode(*currentWindow(), Kexi::DataViewMode);
2870 }
2871 
2872 void KexiMainWindow::slotViewDesignMode()
2873 {
2874     if (currentWindow())
2875         switchToViewMode(*currentWindow(), Kexi::DesignViewMode);
2876 }
2877 
2878 void KexiMainWindow::slotViewTextMode()
2879 {
2880     if (currentWindow())
2881         switchToViewMode(*currentWindow(), Kexi::TextViewMode);
2882 }
2883 
2884 //! Used to control if we're not Saving-As object under the original name
2885 class SaveAsObjectNameValidator : public KexiNameDialogValidator
2886 {
2887 public:
2888     explicit SaveAsObjectNameValidator(const QString &originalObjectName)
2889      : m_originalObjectName(originalObjectName)
2890     {
2891     }
2892     virtual bool validate(KexiNameDialog *dialog) const override {
2893         if (dialog->widget()->nameText() == m_originalObjectName) {
2894             KMessageBox::information(dialog,
2895                                      xi18nc("Could not save object under the original name.",
2896                                            "Could not save under the original name."));
2897             return false;
2898         }
2899         return true;
2900     }
2901 private:
2902     QString m_originalObjectName;
2903 };
2904 
2905 tristate KexiMainWindow::getNewObjectInfo(
2906     KexiPart::Item *partItem, const QString &originalName, KexiPart::Part *part,
2907     bool allowOverwriting, bool *overwriteNeeded, const QString& messageWhenAskingForName)
2908 {
2909     //data was never saved in the past -we need to create a new object at the backend
2910     KexiPart::Info *info = part->info();
2911     if (!d->nameDialog) {
2912         d->nameDialog = new KexiNameDialog(
2913             messageWhenAskingForName, this);
2914         //check if that name is allowed
2915         d->nameDialog->widget()->addNameSubvalidator(
2916             new KDbObjectNameValidator(project()->dbConnection()->driver()));
2917         d->nameDialog->buttonBox()->button(QDialogButtonBox::Ok)->setText(xi18nc("@action:button Save object", "Save"));
2918     } else {
2919         d->nameDialog->widget()->setMessageText(messageWhenAskingForName);
2920     }
2921     d->nameDialog->widget()->setCaptionText(partItem->caption());
2922     d->nameDialog->widget()->setNameText(partItem->name());
2923     d->nameDialog->setWindowTitle(xi18nc("@title:window", "Save Object As"));
2924     d->nameDialog->setDialogIcon(info->iconName());
2925     d->nameDialog->setAllowOverwriting(allowOverwriting);
2926     if (!originalName.isEmpty()) {
2927         d->nameDialog->setValidator(new SaveAsObjectNameValidator(originalName));
2928     }
2929     if (d->nameDialog->execAndCheckIfObjectExists(*project(), *part, overwriteNeeded)
2930         != QDialog::Accepted)
2931     {
2932         return cancelled;
2933     }
2934 
2935     // close window of object that will be overwritten
2936     if (*overwriteNeeded) {
2937         KexiPart::Item* overwrittenItem = project()->item(info, d->nameDialog->widget()->nameText());
2938         if (overwrittenItem) {
2939             KexiWindow * openedWindow = d->openedWindowFor(overwrittenItem->identifier());
2940             if (openedWindow) {
2941                 const tristate res = closeWindow(openedWindow);
2942                 if (res != true) {
2943                     return res;
2944                 }
2945             }
2946         }
2947     }
2948 
2949     //update name and caption
2950     partItem->setName(d->nameDialog->widget()->nameText());
2951     partItem->setCaption(d->nameDialog->widget()->captionText());
2952     return true;
2953 }
2954 
2955 //! Used to delete part item on exit from block
2956 class PartItemDeleter : public QScopedPointer<KexiPart::Item>
2957 {
2958     public:
2959         explicit PartItemDeleter(KexiProject *prj) : m_prj(prj) {}
2960         ~PartItemDeleter() {
2961             if (!isNull()) {
2962                 m_prj->deleteUnstoredItem(take());
2963             }
2964         }
2965     private:
2966         KexiProject *m_prj;
2967 };
2968 
2969 static void showSavingObjectFailedErrorMessage(KexiMainWindow *wnd, KexiPart::Item *item)
2970 {
2971     wnd->showErrorMessage(
2972         xi18nc("@info Saving object failed",
2973               "Saving <resource>%1</resource> object failed.", item->name()),
2974               wnd->currentWindow());
2975 }
2976 
2977 tristate KexiMainWindow::saveObject(KexiWindow *window, const QString& messageWhenAskingForName,
2978                                     SaveObjectOptions options)
2979 {
2980     tristate res;
2981     bool saveAs = options & SaveObjectAs;
2982     if (!saveAs && !window->neverSaved()) {
2983         //data was saved in the past -just save again
2984         res = window->storeData(options & DoNotAsk);
2985         if (!res) {
2986             showSavingObjectFailedErrorMessage(this, window->partItem());
2987         }
2988         return res;
2989     }
2990     if (saveAs && window->neverSaved()) {
2991         //if never saved, saveAs == save
2992         saveAs = false;
2993     }
2994 
2995     const int oldItemID = window->partItem()->identifier();
2996 
2997     KexiPart::Item *partItem;
2998     KexiView::StoreNewDataOptions storeNewDataOptions;
2999     PartItemDeleter itemDeleter(d->prj);
3000     if (saveAs) {
3001         partItem = d->prj->createPartItem(window->part());
3002         if (!partItem) {
3003             //! @todo error
3004             return false;
3005         }
3006         itemDeleter.reset(partItem);
3007     }
3008     else {
3009         partItem = window->partItem();
3010     }
3011 
3012     bool overwriteNeeded;
3013     res = getNewObjectInfo(partItem, saveAs ? window->partItem()->name() : QString(),
3014                            window->part(), true /*allowOverwriting*/,
3015                            &overwriteNeeded, messageWhenAskingForName);
3016     if (res != true)
3017         return res;
3018     if (overwriteNeeded) {
3019         storeNewDataOptions |= KexiView::OverwriteExistingData;
3020     }
3021 
3022     if (saveAs) {
3023         res = window->storeDataAs(partItem, storeNewDataOptions);
3024     }
3025     else {
3026         res = window->storeNewData(storeNewDataOptions);
3027     }
3028 
3029     if (~res)
3030         return cancelled;
3031     if (!res) {
3032         showSavingObjectFailedErrorMessage(this, partItem);
3033         return false;
3034     }
3035 
3036     d->updateWindowId(window, oldItemID);
3037     invalidateProjectWideActions();
3038     itemDeleter.take();
3039     return true;
3040 }
3041 
3042 tristate KexiMainWindow::closeWindow(KexiWindow *window)
3043 {
3044     return closeWindow(window ? window : currentWindow(), true);
3045 }
3046 
3047 tristate KexiMainWindow::closeCurrentWindow()
3048 {
3049     return closeWindow(0);
3050 }
3051 
3052 tristate KexiMainWindow::closeWindowForTab(int tabIndex)
3053 {
3054     KexiWindow* window = windowForTab(tabIndex);
3055     if (!window)
3056         return false;
3057     return closeWindow(window);
3058 }
3059 
3060 tristate KexiMainWindow::closeAllWindows()
3061 {
3062     if (!d->objectViewWidget || !d->objectViewWidget->tabWidget())
3063         return true;
3064     QList<KexiWindow*> windowList;
3065     for (int i = 0; i < d->objectViewWidget->tabWidget()->count(); ++i) {
3066         KexiWindow *window = windowForTab(i);
3067         if (window) {
3068             windowList.append(window);
3069         }
3070     }
3071     tristate alternateResult = true;
3072     for (KexiWindow *window : windowList) {
3073         const tristate result = closeWindow(window);
3074         if (~result) {
3075             return result;
3076         }
3077         if (result == false) {
3078             alternateResult = false;
3079         }
3080     }
3081     return alternateResult;
3082 }
3083 
3084 tristate KexiMainWindow::closeWindow(KexiWindow *window, bool layoutTaskBar, bool doNotSaveChanges)
3085 {
3086 //! @todo KEXI3 KexiMainWindow::closeWindow()
3087     ///@note Q_UNUSED layoutTaskBar
3088     Q_UNUSED(layoutTaskBar);
3089 
3090     if (!window)
3091         return true;
3092     if (d->insideCloseWindow)
3093         return true;
3094 
3095     const int previousItemId = window->partItem()->identifier();
3096 
3097 #ifndef KEXI_NO_PENDING_DIALOGS
3098     d->addItemToPendingWindows(window->partItem(), Private::WindowClosingJob);
3099 #endif
3100 
3101     d->insideCloseWindow = true;
3102 
3103     if (window == currentWindow() && !window->isAttached()) {
3104         if (d->propertyEditor()) {
3105             // ah, closing detached window - better switch off property buffer right now...
3106             d->propertySet = 0;
3107             d->propertyEditor()->changeSet(0);
3108         }
3109     }
3110 
3111     bool remove_on_closing = window->partItem() ? window->partItem()->neverSaved() : false;
3112     if (window->isDirty() && !d->forceWindowClosing && !doNotSaveChanges) {
3113         //more accurate tool tips and what's this
3114         KGuiItem saveChanges(KStandardGuiItem::save());
3115         saveChanges.setToolTip(xi18n("Save changes"));
3116         saveChanges.setWhatsThis(
3117             xi18nc("@info", "Saves all recent changes made in <resource>%1</resource> object.",
3118                    window->partItem()->name()));
3119         KGuiItem discardChanges(KStandardGuiItem::discard());
3120         discardChanges.setWhatsThis(
3121             xi18nc("@info", "Discards all recent changes made in <resource>%1</resource> object.",
3122                    window->partItem()->name()));
3123 
3124         //dialog's data is dirty:
3125         //--adidional message, e.g. table designer will return
3126         //  "Note: This table is already filled with data which will be removed."
3127         //  if the window is in design view mode.
3128         const KLocalizedString additionalMessage(
3129             window->part()->i18nMessage(":additional message before saving design", window));
3130         QString additionalMessageString;
3131         if (!additionalMessage.isEmpty())
3132             additionalMessageString = additionalMessage.toString();
3133 
3134         if (additionalMessageString.startsWith(':'))
3135             additionalMessageString.clear();
3136         if (!additionalMessageString.isEmpty())
3137             additionalMessageString = "<p>" + additionalMessageString + "</p>";
3138 
3139         const KMessageBox::ButtonCode questionRes = KMessageBox::warningYesNoCancel(this,
3140                                 "<p>"
3141                                 + window->part()->i18nMessage("Design of object <resource>%1</resource> has been modified.", window)
3142                                 .subs(window->partItem()->name()).toString()
3143                                 + "</p><p>" + xi18n("Do you want to save changes?") + "</p>"
3144                                 + additionalMessageString /*may be empty*/,
3145                                 QString(),
3146                                 saveChanges,
3147                                 discardChanges);
3148         if (questionRes == KMessageBox::Cancel) {
3149 #ifndef KEXI_NO_PENDING_DIALOGS
3150             d->removePendingWindow(window->id());
3151 #endif
3152             d->insideCloseWindow = false;
3153             d->windowsToClose.clear(); //give up with 'close all'
3154             return cancelled;
3155         }
3156         if (questionRes == KMessageBox::Yes) {
3157             //save it
3158             tristate res = saveObject(window, QString(), DoNotAsk);
3159             if (!res || ~res) {
3160 //! @todo show error info; (retry/ignore/cancel)
3161 #ifndef KEXI_NO_PENDING_DIALOGS
3162                 d->removePendingWindow(window->id());
3163 #endif
3164                 d->insideCloseWindow = false;
3165                 d->windowsToClose.clear(); //give up with 'close all'
3166                 return res;
3167             }
3168             remove_on_closing = false;
3169         }
3170     }
3171 
3172     const int window_id = window->id(); //remember now, because removeObject() can destruct partitem object
3173     if (remove_on_closing) {
3174         //we won't save this object, and it was never saved -remove it
3175         if (!removeObject(window->partItem(), true)) {
3176 #ifndef KEXI_NO_PENDING_DIALOGS
3177             d->removePendingWindow(window->id());
3178 #endif
3179             //msg?
3180             //! @todo ask if we'd continue and return true/false
3181             d->insideCloseWindow = false;
3182             d->windowsToClose.clear(); //give up with 'close all'
3183             return false;
3184         }
3185     } else {
3186         //not dirty now
3187         if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) {
3188             d->objectViewWidget->projectNavigator()->updateItemName(*window->partItem(), false);
3189         }
3190     }
3191 
3192     hideDesignTab(previousItemId, QString());
3193 
3194     d->removeWindow(window_id);
3195     d->setWindowContainerExistsFor(window->partItem()->identifier(), false);
3196     QWidget *windowContainer = window->parentWidget();
3197     d->objectViewWidget->tabWidget()->removeTab(
3198         d->objectViewWidget->tabWidget()->indexOf(windowContainer));
3199 
3200 #ifdef KEXI_QUICK_PRINTING_SUPPORT
3201     //also remove from 'print setup dialogs' cache, if needed
3202     int printedObjectID = 0;
3203     if (d->pageSetupWindowItemID2dataItemID_map.contains(window_id))
3204         printedObjectID = d->pageSetupWindowItemID2dataItemID_map[ window_id ];
3205     d->pageSetupWindows.remove(printedObjectID);
3206 #endif
3207 
3208     delete windowContainer;
3209 
3210     //focus navigator if nothing else available
3211     if (d->openedWindowsCount() == 0) {
3212         if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) {
3213             d->objectViewWidget->projectNavigator()->setFocus();
3214         }
3215         d->updatePropEditorVisibility(Kexi::NoViewMode);
3216     }
3217 
3218     invalidateActions();
3219     d->insideCloseWindow = false;
3220     if (!d->windowsToClose.isEmpty()) {//continue 'close all'
3221         KexiWindow* w = d->windowsToClose.takeAt(0);
3222         closeWindow(w, true);
3223     }
3224 
3225 #ifndef KEXI_NO_PENDING_DIALOGS
3226     d->removePendingWindow(window_id);
3227 
3228     //perform pending global action that was suspended:
3229     if (!d->pendingWindowsExist()) {
3230         d->executeActionWhenPendingJobsAreFinished();
3231     }
3232 #endif
3233     //d->objectViewWidget->slotCurrentTabIndexChanged(d->objectViewWidget->tabWidget()->currentIndex());
3234     showDesignTabIfNeeded(0);
3235 
3236     if (currentWindow()) {
3237         restoreDesignTabIfNeeded(currentWindow()->partItem()->pluginId(),
3238                                  currentWindow()->currentViewMode(),
3239                                  0);
3240     }
3241     d->tabsToActivateOnShow.remove(previousItemId);
3242     return true;
3243 }
3244 
3245 QWidget* KexiMainWindow::findWindow(QWidget *w)
3246 {
3247     while (w && !acceptsSharedActions(w)) {
3248         if (w == d->objectViewWidget->propertyPane()) {
3249             return currentWindow();
3250         }
3251         w = w->parentWidget();
3252     }
3253     return w;
3254 }
3255 
3256 KexiWindow* KexiMainWindow::openedWindowFor(int identifier)
3257 {
3258     return d->openedWindowFor(identifier);
3259 }
3260 
3261 KexiWindow* KexiMainWindow::openedWindowFor(const KexiPart::Item* item)
3262 {
3263     return item ? openedWindowFor(item->identifier()) : 0;
3264 }
3265 
3266 KDbQuerySchema* KexiMainWindow::unsavedQuery(int queryId)
3267 {
3268     KexiWindow * queryWindow = openedWindowFor(queryId);
3269     if (!queryWindow || !queryWindow->isDirty()) {
3270         return 0;
3271     }
3272 
3273     return queryWindow->part()->currentQuery(queryWindow->viewForMode(Kexi::DataViewMode));
3274 }
3275 
3276 QList<QVariant> KexiMainWindow::currentParametersForQuery(int queryId) const
3277 {
3278     KexiWindow *queryWindow = d->openedWindowFor(queryId);
3279     if (!queryWindow) {
3280         return QList<QVariant>();
3281     }
3282 
3283     KexiView *view = queryWindow->viewForMode(Kexi::DataViewMode);
3284     if (!view) {
3285         return QList<QVariant>();
3286     }
3287 
3288     return view->currentParameters();
3289 }
3290 
3291 bool KexiMainWindow::acceptsSharedActions(QObject *w)
3292 {
3293     return w->inherits("KexiWindow") || w->inherits("KexiView");
3294 }
3295 
3296 bool KexiMainWindow::openingAllowed(KexiPart::Item* item, Kexi::ViewMode viewMode, QString* errorMessage)
3297 {
3298     //qDebug() << viewMode;
3299     //! @todo this can be more complex once we deliver ACLs...
3300     if (!d->userMode)
3301         return true;
3302     KexiPart::Part * part = Kexi::partManager().partForPluginId(item->pluginId());
3303     if (!part) {
3304         if (errorMessage) {
3305             *errorMessage = Kexi::partManager().result().message();
3306         }
3307     }
3308     //qDebug() << part << item->pluginId();
3309     //if (part)
3310     //    qDebug() << item->pluginId() << part->info()->supportedUserViewModes();
3311     return part && (part->info()->supportedUserViewModes() & viewMode);
3312 }
3313 
3314 KexiWindow *
3315 KexiMainWindow::openObject(const QString& pluginId, const QString& name,
3316                            Kexi::ViewMode viewMode, bool *openingCancelled, QMap<QString, QVariant>* staticObjectArgs)
3317 {
3318     KexiPart::Item *item = d->prj->itemForPluginId(pluginId, name);
3319     if (!item)
3320         return 0;
3321     return openObject(item, viewMode, openingCancelled, staticObjectArgs);
3322 }
3323 
3324 KexiWindow *
3325 KexiMainWindow::openObject(KexiPart::Item* item, Kexi::ViewMode viewMode, bool *openingCancelled,
3326                            QMap<QString, QVariant>* staticObjectArgs, QString* errorMessage)
3327 {
3328     Q_ASSERT(openingCancelled);
3329     if (!d->prj || !item) {
3330         return 0;
3331     }
3332 
3333     if (!openingAllowed(item, viewMode, errorMessage)) {
3334         if (errorMessage)
3335             *errorMessage = xi18nc(
3336                                 "opening is not allowed in \"data view/design view/text view\" mode",
3337                                 "opening is not allowed in \"%1\" mode", Kexi::nameForViewMode(viewMode));
3338         *openingCancelled = true;
3339         return 0;
3340     }
3341     //qDebug() << d->prj << item;
3342 
3343     KexiWindow *prevWindow = currentWindow();
3344 
3345     KexiUtils::WaitCursor wait;
3346 #ifndef KEXI_NO_PENDING_DIALOGS
3347     Private::PendingJobType pendingType;
3348     KexiWindow *window = d->openedWindowFor(item, pendingType);
3349     if (pendingType != Private::NoJob) {
3350         *openingCancelled = true;
3351         return 0;
3352     }
3353 #else
3354     KexiWindow *window = openedWindowFor(item);
3355 #endif
3356     int previousItemId = currentWindow() ? currentWindow()->partItem()->identifier() : 0;
3357     *openingCancelled = false;
3358 
3359     bool alreadyOpened = false;
3360     QWidget *windowContainer = 0;
3361 
3362     if (window) {
3363         if (viewMode != window->currentViewMode()) {
3364             if (true != switchToViewMode(*window, viewMode))
3365                 return 0;
3366         } else
3367             activateWindow(*window);
3368         alreadyOpened = true;
3369     } else {
3370         if (d->windowContainerExistsFor(item->identifier())) {
3371             // window not yet present but window container exists: return 0 and wait
3372             return 0;
3373         }
3374         KexiPart::Part *part = Kexi::partManager().partForPluginId(item->pluginId());
3375         d->updatePropEditorVisibility(viewMode, part ? part->info() : 0);
3376         //update tabs before opening
3377         updateCustomPropertyPanelTabs(currentWindow() ? currentWindow()->part() : 0,
3378                                       currentWindow() ? currentWindow()->currentViewMode() : Kexi::NoViewMode,
3379                                       part, viewMode);
3380 
3381         const int tabIndex = d->objectViewWidget->tabWidget()->addEmptyContainerTab(
3382                     part ? part->info()->icon() : koIcon("object"),
3383                     KexiWindow::windowTitleForItem(*item));
3384         // open new tab earlier
3385         d->setWindowContainerExistsFor(item->identifier(), true);
3386         d->objectViewWidget->tabWidget()->setTabToolTip(tabIndex, KexiPart::fullCaptionForItem(item, part));
3387         QString whatsThisText;
3388         if (part) {
3389             whatsThisText = xi18nc("@info",
3390                                    "Tab for <resource>%1</resource> (%2).",
3391                                    item->captionOrName(), part->info()->name());
3392         }
3393         else {
3394             whatsThisText = xi18nc("@info",
3395                                    "Tab for <resource>%1</resource>.", item->captionOrName());
3396         }
3397         d->objectViewWidget->tabWidget()->setTabWhatsThis(tabIndex, whatsThisText);
3398         d->objectViewWidget->tabWidget()->setCurrentIndex(tabIndex);
3399 
3400 #ifndef KEXI_NO_PENDING_DIALOGS
3401         d->addItemToPendingWindows(item, Private::WindowOpeningJob);
3402 #endif
3403         windowContainer = d->objectViewWidget->tabWidget()->widget(tabIndex);
3404         window = d->prj->openObject(windowContainer, item, viewMode, staticObjectArgs);
3405         if (window) {
3406             d->objectViewWidget->tabWidget()->setWindowForTab(tabIndex, window);
3407             // update text and icon
3408             d->objectViewWidget->tabWidget()->setTabText(tabIndex, window->windowTitle());
3409             d->objectViewWidget->tabWidget()->setTabIcon(tabIndex, window->windowIcon());
3410         }
3411     }
3412 
3413     if (!window || !activateWindow(*window)) {
3414 #ifndef KEXI_NO_PENDING_DIALOGS
3415         d->removePendingWindow(item->identifier());
3416 #endif
3417         d->setWindowContainerExistsFor(item->identifier(), false);
3418         d->objectViewWidget->tabWidget()->removeTab(
3419             d->objectViewWidget->tabWidget()->indexOf(windowContainer));
3420         delete windowContainer;
3421         updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert
3422         //! @todo add error msg...
3423         return 0;
3424     }
3425 
3426     if (viewMode != window->currentViewMode())
3427         invalidateSharedActions();
3428 
3429 #ifndef KEXI_NO_PENDING_DIALOGS
3430     d->removePendingWindow(window->id());
3431 
3432     //perform pending global action that was suspended:
3433     if (!d->pendingWindowsExist()) {
3434         d->executeActionWhenPendingJobsAreFinished();
3435     }
3436 #endif
3437     if (window && !alreadyOpened) {
3438         // Call switchToViewMode() and propertySetSwitched() again here because
3439         // this is the time when then new window is the current one - previous call did nothing.
3440         switchToViewMode(*window, window->currentViewMode());
3441         currentWindow()->selectedView()->propertySetSwitched();
3442     }
3443     invalidateProjectWideActions();
3444     restoreDesignTabIfNeeded(item->pluginId(), viewMode, previousItemId);
3445     activateDesignTabIfNeeded(item->pluginId(), viewMode);
3446     QString origTabToActivate;
3447     if (prevWindow) {
3448         // Save the orig tab for prevWindow that was stored in the restoreDesignTabIfNeeded() call above
3449         origTabToActivate = d->tabsToActivateOnShow.value(prevWindow->partItem()->identifier());
3450     }
3451     activeWindowChanged(window, prevWindow);
3452     if (prevWindow) {
3453         // Restore the orig tab
3454         d->tabsToActivateOnShow.insert(prevWindow->partItem()->identifier(), origTabToActivate);
3455     }
3456     return window;
3457 }
3458 
3459 KexiWindow *
3460 KexiMainWindow::openObjectFromNavigator(KexiPart::Item* item, Kexi::ViewMode viewMode)
3461 {
3462     bool openingCancelled;
3463     return openObjectFromNavigator(item, viewMode, &openingCancelled);
3464 }
3465 
3466 KexiWindow *
3467 KexiMainWindow::openObjectFromNavigator(KexiPart::Item* item, Kexi::ViewMode viewMode,
3468                                         bool *openingCancelled)
3469 {
3470     Q_ASSERT(openingCancelled);
3471     if (!openingAllowed(item, viewMode)) {
3472         *openingCancelled = true;
3473         return 0;
3474     }
3475     if (!d->prj || !item)
3476         return 0;
3477 #ifndef KEXI_NO_PENDING_DIALOGS
3478     Private::PendingJobType pendingType;
3479     KexiWindow *window = d->openedWindowFor(item, pendingType);
3480     if (pendingType != Private::NoJob) {
3481         *openingCancelled = true;
3482         return 0;
3483     }
3484 #else
3485     KexiWindow *window = openedWindowFor(item);
3486 #endif
3487     *openingCancelled = false;
3488     if (window) {
3489         if (activateWindow(*window)) {
3490             return window;
3491         }
3492     }
3493     //if DataViewMode is not supported, try Design, then Text mode (currently useful for script part)
3494     KexiPart::Part *part = Kexi::partManager().partForPluginId(item->pluginId());
3495     if (!part)
3496         return 0;
3497     if (viewMode == Kexi::DataViewMode && !(part->info()->supportedViewModes() & Kexi::DataViewMode)) {
3498         if (part->info()->supportedViewModes() & Kexi::DesignViewMode)
3499             return openObjectFromNavigator(item, Kexi::DesignViewMode, openingCancelled);
3500         else if (part->info()->supportedViewModes() & Kexi::TextViewMode)
3501             return openObjectFromNavigator(item, Kexi::TextViewMode, openingCancelled);
3502     }
3503     //do the same as in openObject()
3504     return openObject(item, viewMode, openingCancelled);
3505 }
3506 
3507 tristate KexiMainWindow::closeObject(KexiPart::Item* item)
3508 {
3509 #ifndef KEXI_NO_PENDING_DIALOGS
3510     Private::PendingJobType pendingType;
3511     KexiWindow *window = d->openedWindowFor(item, pendingType);
3512     if (pendingType == Private::WindowClosingJob)
3513         return true;
3514     else if (pendingType == Private::WindowOpeningJob)
3515         return cancelled;
3516 #else
3517     KexiWindow *window = openedWindowFor(item);
3518 #endif
3519     if (!window)
3520         return cancelled;
3521     return closeWindow(window);
3522 }
3523 
3524 bool KexiMainWindow::newObject(KexiPart::Info *info, bool* openingCancelled)
3525 {
3526     Q_ASSERT(openingCancelled);
3527     if (d->userMode) {
3528         *openingCancelled = true;
3529         return false;
3530     }
3531     *openingCancelled = false;
3532     if (!d->prj || !info)
3533         return false;
3534     KexiPart::Part *part = Kexi::partManager().part(info);
3535     if (!part)
3536         return false;
3537 
3538     KexiPart::Item *it = d->prj->createPartItem(info);
3539     if (!it) {
3540         //! @todo error
3541         return false;
3542     }
3543 
3544     if (!it->neverSaved()) { //only add stored objects to the browser
3545         d->objectViewWidget->projectNavigator()->model()->slotAddItem(it);
3546     }
3547     Kexi::ViewMode viewMode = (info->supportedViewModes() & Kexi::DesignViewMode)
3548             ? Kexi::DesignViewMode
3549             : Kexi::TextViewMode;
3550     return openObject(it, viewMode, openingCancelled);
3551 }
3552 
3553 tristate KexiMainWindow::removeObject(KexiPart::Item *item, bool dontAsk)
3554 {
3555     if (d->userMode)
3556         return cancelled;
3557     if (!d->prj || !item)
3558         return false;
3559 
3560     KexiPart::Part *part = Kexi::partManager().partForPluginId(item->pluginId());
3561     if (!part)
3562         return false;
3563 
3564     if (!dontAsk) {
3565         if (KMessageBox::No == KMessageBox::questionYesNo(this,
3566                 xi18nc("@info Delete <objecttype> <objectname>?",
3567                       "<para>Do you want to permanently delete the following object?<nl/>"
3568                       "<nl/>%1 <resource>%2</resource></para>"
3569                       "<para><note>If you click <interface>Delete</interface>, "
3570                       "you will not be able to undo the deletion.</note></para>",
3571                       part->info()->name(), item->name()),
3572                 xi18nc("@title:window Delete Object %1.",
3573                       "Delete <resource>%1</resource>?", item->name()),
3574                 KStandardGuiItem::del(),
3575                 KStandardGuiItem::no(), QString(), KMessageBox::Notify | KMessageBox::Dangerous))
3576         {
3577             return cancelled;
3578         }
3579     }
3580 
3581     tristate res = true;
3582 #ifdef KEXI_QUICK_PRINTING_SUPPORT
3583     //also close 'print setup' dialog for this item, if any
3584     KexiWindow * pageSetupWindow = d->pageSetupWindows[ item->identifier()];
3585     const bool oldInsideCloseWindow = d->insideCloseWindow;
3586     {
3587         d->insideCloseWindow = false;
3588         if (pageSetupWindow)
3589             res = closeWindow(pageSetupWindow);
3590     }
3591     d->insideCloseWindow = oldInsideCloseWindow;
3592     if (!res || ~res) {
3593         return res;
3594     }
3595 #endif
3596 
3597 #ifndef KEXI_NO_PENDING_DIALOGS
3598     Private::PendingJobType pendingType;
3599     KexiWindow *window = d->openedWindowFor(item, pendingType);
3600     if (pendingType != Private::NoJob) {
3601         return cancelled;
3602     }
3603 #else
3604     KexiWindow *window = openedWindowFor(item);
3605 #endif
3606 
3607     if (window) {//close existing window
3608         const bool tmp = d->forceWindowClosing;
3609         d->forceWindowClosing = true;
3610         res = closeWindow(window);
3611         d->forceWindowClosing = tmp; //restore
3612         if (!res || ~res) {
3613             return res;
3614         }
3615     }
3616 
3617 #ifdef KEXI_QUICK_PRINTING_SUPPORT
3618     //in case the dialog is a 'print setup' dialog, also update d->pageSetupWindows
3619     int dataItemID = d->pageSetupWindowItemID2dataItemID_map[item->identifier()];
3620     d->pageSetupWindowItemID2dataItemID_map.remove(item->identifier());
3621     d->pageSetupWindows.remove(dataItemID);
3622 #endif
3623 
3624     if (!d->prj->removeObject(item)) {
3625         //! @todo better msg
3626         showSorryMessage(xi18n("Could not delete object."));
3627         return false;
3628     }
3629     return true;
3630 }
3631 
3632 void KexiMainWindow::renameObject(KexiPart::Item *item, const QString& _newName, bool *success)
3633 {
3634     Q_ASSERT(success);
3635     if (d->userMode) {
3636         *success = false;
3637         return;
3638     }
3639     QString newName = _newName.trimmed();
3640     if (newName.isEmpty()) {
3641         showSorryMessage(xi18n("Could not set empty name for this object."));
3642         *success = false;
3643         return;
3644     }
3645 
3646     KexiWindow *window = openedWindowFor(item);
3647     if (window) {
3648         QString msg = xi18nc("@info",
3649                             "<para>Before renaming object <resource>%1</resource> it should be closed.</para>"
3650                             "<para>Do you want to close it?</para>",
3651                             item->name());
3652         KGuiItem closeAndRenameItem(KStandardGuiItem::closeWindow());
3653         closeAndRenameItem.setText(xi18n("Close Window and Rename"));
3654         const int r = KMessageBox::questionYesNo(this, msg, QString(), closeAndRenameItem,
3655                                            KStandardGuiItem::cancel());
3656         if (r != KMessageBox::Yes) {
3657             *success = false;
3658             return;
3659         }
3660         const tristate closeResult = closeWindow(window);
3661         if (closeResult != true) {
3662             *success = false;
3663             return;
3664         }
3665     }
3666     setMessagesEnabled(false); //to avoid double messages
3667     const bool res = d->prj->renameObject(item, newName);
3668     setMessagesEnabled(true);
3669     if (!res) {
3670         showErrorMessage(xi18nc("@info", "Renaming object <resource>%1</resource> failed.",
3671                                 newName), d->prj);
3672         *success = false;
3673         return;
3674     }
3675     *success = true;
3676 }
3677 
3678 void KexiMainWindow::setObjectCaption(KexiPart::Item *item, const QString& _newCaption, bool *success)
3679 {
3680     Q_ASSERT(success);
3681     if (d->userMode) {
3682         *success = false;
3683         return;
3684     }
3685     QString newCaption = _newCaption.trimmed();
3686     setMessagesEnabled(false); //to avoid double messages
3687     const bool res = d->prj->setObjectCaption(item, newCaption);
3688     setMessagesEnabled(true);
3689     if (!res) {
3690         showErrorMessage(xi18nc("@info",
3691                                 "Setting caption for object <resource>%1</resource> failed.",
3692                                 newCaption), d->prj);
3693         *success = false;
3694         return;
3695     }
3696     *success = true;
3697 }
3698 
3699 void KexiMainWindow::slotObjectRenamed(const KexiPart::Item &item, const QString& oldName)
3700 {
3701     Q_UNUSED(oldName);
3702 #ifndef KEXI_NO_PENDING_DIALOGS
3703     Private::PendingJobType pendingType;
3704     KexiWindow *window = d->openedWindowFor(&item, pendingType);
3705     if (pendingType != Private::NoJob)
3706         return;
3707 #else
3708     KexiWindow *window = openedWindowFor(&item);
3709 #endif
3710     if (!window)
3711         return;
3712 
3713     //change item
3714     window->updateCaption();
3715     if (static_cast<KexiWindow*>(currentWindow()) == window)//optionally, update app. caption
3716         updateAppCaption();
3717 }
3718 
3719 void KexiMainWindow::acceptPropertySetEditing()
3720 {
3721     if (d->propertyEditor()) {
3722         d->propertyEditor()->acceptInput();
3723     }
3724 }
3725 
3726 void KexiMainWindow::propertySetSwitched(KexiWindow *window, bool force,
3727         bool preservePrevSelection, bool sortedProperties, const QByteArray& propertyToSelect)
3728 {
3729     KexiWindow* _currentWindow = currentWindow();
3730     //qDebug() << "currentWindow(): "
3731     //    << (_currentWindow ? _currentWindow->windowTitle() : QString("NULL"))
3732     //    << "window:" << (window ? window->windowTitle() : QString("NULL"));
3733     if (_currentWindow && _currentWindow != window) {
3734         d->propertySet = 0; //we'll need to move to another prop. set
3735         return;
3736     }
3737     if (d->propertyEditor()) {
3738         KPropertySet *newSet = _currentWindow ? _currentWindow->propertySet() : 0;
3739         if (!newSet || (force || static_cast<KPropertySet*>(d->propertySet) != newSet)) {
3740             d->propertySet = newSet;
3741             if (preservePrevSelection || force) {
3742                 KPropertyEditorView::SetOptions options;
3743                 if (preservePrevSelection) {
3744                     options |= KPropertyEditorView::SetOption::PreservePreviousSelection;
3745                 }
3746                 if (sortedProperties) {
3747                     options |= KPropertyEditorView::SetOption::AlphabeticalOrder;
3748                 }
3749 
3750                 d->objectViewWidget->propertyPane()->changePropertySet(
3751                             d->propertySet, propertyToSelect, options,
3752                             (_currentWindow && _currentWindow->selectedView())
3753                                 ? _currentWindow->selectedView()->textToDisplayForNullSet()
3754                                 : QString());
3755             }
3756         }
3757     }
3758 }
3759 
3760 void KexiMainWindow::slotDirtyFlagChanged(KexiWindow* window)
3761 {
3762     KexiPart::Item *item = window->partItem();
3763     //update text in navigator and app. caption
3764     if (!d->userMode) {
3765         d->objectViewWidget->projectNavigator()->updateItemName(*item, window->isDirty());
3766     }
3767 
3768     invalidateActions();
3769     updateAppCaption();
3770     d->objectViewWidget->tabWidget()->setTabText(
3771         d->objectViewWidget->tabWidget()->indexOf(window->parentWidget()),
3772         window->windowTitle());
3773 }
3774 
3775 void KexiMainWindow::slotTipOfTheDay()
3776 {
3777     //! @todo
3778 }
3779 
3780 void KexiMainWindow::slotReportBug()
3781 {
3782     KexiBugReportDialog bugReport(this);
3783     bugReport.exec();
3784 }
3785 
3786 bool KexiMainWindow::userMode() const
3787 {
3788     return d->userMode;
3789 }
3790 
3791 void
3792 KexiMainWindow::setupUserActions()
3793 {
3794 }
3795 
3796 void KexiMainWindow::slotToolsImportProject()
3797 {
3798     if (d->tabbedToolBar)
3799         d->tabbedToolBar->hideMainMenu();
3800     showProjectMigrationWizard(QString(), QString());
3801 }
3802 
3803 void KexiMainWindow::slotToolsImportTables()
3804 {
3805     if (project()) {
3806         QMap<QString, QString> args;
3807         QDialog *dlg = KexiInternalPart::createModalDialogInstance("org.kexi-project.migration", "importtable", this, 0, &args);
3808         if (!dlg)
3809             return; //error msg has been shown by KexiInternalPart
3810 
3811         const int result = dlg->exec();
3812         delete dlg;
3813         if (result != QDialog::Accepted)
3814             return;
3815 
3816         QString destinationTableName(args["destinationTableName"]);
3817         if (!destinationTableName.isEmpty()) {
3818             QString pluginId = "org.kexi-project.table";
3819             bool openingCancelled;
3820             KexiMainWindow::openObject(pluginId, destinationTableName, Kexi::DataViewMode, &openingCancelled);
3821         }
3822     }
3823 }
3824 
3825 void KexiMainWindow::slotToolsCompactDatabase()
3826 {
3827     KexiProjectData *data = 0;
3828     KDbDriver *drv = 0;
3829     const bool projectWasOpened = d->prj;
3830 
3831     if (!d->prj) {
3832         //! @todo Support compacting of non-opened projects
3833         return;
3834 #if 0
3835         KexiStartupDialog dlg(
3836             KexiStartupDialog::OpenExisting, 0, Kexi::connset(), this);
3837 
3838         if (dlg.exec() != QDialog::Accepted)
3839             return;
3840 
3841         if (dlg.selectedFile().isEmpty()) {
3842 //! @todo add support for server based if needed?
3843             return;
3844         }
3845         KDbConnectionData cdata;
3846         cdata.setDatabaseName(dlg.selectedFile());
3847 
3848         //detect driver name for the selected file
3849         KexiStartupData::Import detectedImportAction;
3850         QString detectedDriverId;
3851         tristate res = KexiStartupHandler::detectActionForFile(
3852                            &detectedImportAction, &detectedDriverId,
3853                            QString() /*suggestedDriverId*/, cdata.databaseName(), 0,
3854                            KexiStartupHandler::SkipMessages | KexiStartupHandler::ThisIsAProjectFile
3855                            | KexiStartupHandler::DontConvert);
3856 
3857         if (true == res && !detectedImportAction) {
3858             cdata.setDriverId(detectedDriverId);
3859             drv = Kexi::driverManager().driver(cdata.driverId());
3860         }
3861         if (!drv || !(drv->features() & KDbDriver::CompactingDatabaseSupported)) {
3862             KMessageBox::information(this,
3863                                      xi18n("Compacting database file <filename>%1</filename> is not supported.",
3864                                            QDir::toNativeSeparators(cdata.databaseName())));
3865             return;
3866         }
3867         data = new KexiProjectData(cdata);
3868 #endif
3869     } else {
3870         //sanity
3871         if (!(d->prj && d->prj->dbConnection()
3872                 && (d->prj->dbConnection()->driver()->features() & KDbDriver::CompactingDatabaseSupported)))
3873             return;
3874 
3875         KGuiItem yesItem(KStandardGuiItem::cont());
3876         yesItem.setText(xi18nc("@action:button Compact database", "Compact"));
3877         if (KMessageBox::Yes != KMessageBox::questionYesNo(this,
3878                 xi18n("The current project has to be closed before compacting the database. "
3879                      "It will be open again after compacting.\n\nDo you want to continue?"),
3880                 QString(), yesItem, KStandardGuiItem::cancel()))
3881         {
3882             return;
3883         }
3884         data = new KexiProjectData(*d->prj->data()); // a copy
3885         drv = d->prj->dbConnection()->driver();
3886         const tristate res = closeProject();
3887         if (~res || !res) {
3888             delete data;
3889             return;
3890         }
3891     }
3892 
3893     if (!drv->adminTools().vacuum(*data->connectionData(), data->databaseName())) {
3894       showErrorMessage(QString(), &drv->adminTools());
3895     }
3896 
3897     if (projectWasOpened)
3898       openProject(*data);
3899 
3900     delete data;
3901 }
3902 
3903 tristate KexiMainWindow::showProjectMigrationWizard(const QString& mimeType, const QString& databaseName)
3904 {
3905     return d->showProjectMigrationWizard(mimeType, databaseName, 0);
3906 }
3907 
3908 tristate KexiMainWindow::showProjectMigrationWizard(
3909     const QString& mimeType, const QString& databaseName, const KDbConnectionData &cdata)
3910 {
3911     return d->showProjectMigrationWizard(mimeType, databaseName, &cdata);
3912 }
3913 
3914 tristate KexiMainWindow::executeItem(KexiPart::Item* item)
3915 {
3916     KexiPart::Info *info = item ? Kexi::partManager().infoForPluginId(item->pluginId()) : 0;
3917     if ((! info) || (! info->isExecuteSupported()))
3918         return false;
3919     KexiPart::Part *part = Kexi::partManager().part(info);
3920     if (!part)
3921         return false;
3922     return part->execute(item);
3923 }
3924 
3925 void KexiMainWindow::slotProjectImportDataTable()
3926 {
3927 //! @todo allow data appending (it is not possible now)
3928     if (d->userMode)
3929         return;
3930     QMap<QString, QString> args;
3931     args.insert("sourceType", "file");
3932     QDialog *dlg = KexiInternalPart::createModalDialogInstance(
3933                        "org.kexi-project.importexport.csv", "KexiCSVImportDialog", this, 0, &args);
3934     if (!dlg)
3935         return; //error msg has been shown by KexiInternalPart
3936     dlg->exec();
3937     delete dlg;
3938 }
3939 
3940 tristate KexiMainWindow::executeCustomActionForObject(KexiPart::Item* item,
3941         const QString& actionName)
3942 {
3943     if (actionName == "exportToCSV")
3944         return exportItemAsDataTable(item);
3945     else if (actionName == "copyToClipboardAsCSV")
3946         return copyItemToClipboardAsDataTable(item);
3947 
3948     qWarning() << "no such action:" << actionName;
3949     return false;
3950 }
3951 
3952 tristate KexiMainWindow::exportItemAsDataTable(KexiPart::Item* item)
3953 {
3954     if (!item)
3955         return false;
3956 
3957     QMap<QString, QString> args;
3958 
3959     if (!checkForDirtyFlagOnExport(item, &args)) {
3960             return false;
3961     }
3962 
3963     //! @todo: accept record changes...
3964     args.insert("destinationType", "file");
3965     args.insert("itemId", QString::number(item->identifier()));
3966     QDialog *dlg = KexiInternalPart::createModalDialogInstance(
3967                        "org.kexi-project.importexport.csv", "KexiCSVExportWizard", this, 0, &args);
3968     if (!dlg)
3969         return false; //error msg has been shown by KexiInternalPart
3970     int result = dlg->exec();
3971     delete dlg;
3972     return result == QDialog::Rejected ? tristate(cancelled) : tristate(true);
3973 }
3974 
3975 bool KexiMainWindow::checkForDirtyFlagOnExport(KexiPart::Item *item, QMap<QString, QString> *args)
3976 {
3977     //! @todo: handle tables
3978     if (item->pluginId() != "org.kexi-project.query") {
3979         return true;
3980     }
3981 
3982     KexiWindow * itemWindow = openedWindowFor(item);
3983     if (itemWindow && itemWindow->isDirty()) {
3984         tristate result;
3985         if (item->neverSaved()) {
3986             result = true;
3987         } else {
3988             int prevWindowId = 0;
3989             if (!itemWindow->isVisible()) {
3990                 prevWindowId = currentWindow()->id();
3991                 activateWindow(itemWindow->id());
3992             }
3993             result = askOnExportingChangedQuery(item);
3994 
3995             if (prevWindowId != 0) {
3996                 activateWindow(prevWindowId);
3997             }
3998         }
3999 
4000         if (~result) {
4001             return false;
4002         } else if (true == result) {
4003             args->insert("useTempQuery","1");
4004         }
4005     }
4006 
4007     return true;
4008 }
4009 
4010 tristate KexiMainWindow::askOnExportingChangedQuery(KexiPart::Item *item) const
4011 {
4012     const KMessageBox::ButtonCode result = KMessageBox::warningYesNoCancel(const_cast<KexiMainWindow*>(this),
4013         xi18nc("@info", "Design of query <resource>%1</resource> that you want to export data"
4014                                          " from is changed and has not yet been saved. Do you want to use data"
4015                                          " from the changed query for exporting or from its original (saved)"
4016                                          " version?", item->captionOrName()),
4017         QString(),
4018         KGuiItem(xi18nc("@action:button Export query data", "Use the Changed Query")),
4019         KGuiItem(xi18nc("@action:button Export query data", "Use the Original Query")),
4020         KStandardGuiItem::cancel(),
4021         QString(),
4022         KMessageBox::Notify | KMessageBox::Dangerous);
4023     if (result == KMessageBox::Yes) {
4024         return true;
4025     } else if (result == KMessageBox::No) {
4026         return false;
4027     }
4028 
4029     return cancelled;
4030 }
4031 
4032 bool KexiMainWindow::printItem(KexiPart::Item* item, const QString& titleText)
4033 {
4034     //! @todo printItem(item, KexiSimplePrintingSettings::load(), titleText);
4035     Q_UNUSED(item)
4036     Q_UNUSED(titleText)
4037     return false;
4038 }
4039 
4040 tristate KexiMainWindow::printItem(KexiPart::Item* item)
4041 {
4042     return printItem(item, QString());
4043 }
4044 
4045 bool KexiMainWindow::printPreviewForItem(KexiPart::Item* item, const QString& titleText, bool reload)
4046 {
4047 //! @todo printPreviewForItem(item, KexiSimplePrintingSettings::load(), titleText, reload);
4048     Q_UNUSED(item)
4049     Q_UNUSED(titleText)
4050     Q_UNUSED(reload)
4051     return false;
4052 }
4053 
4054 tristate KexiMainWindow::printPreviewForItem(KexiPart::Item* item)
4055 {
4056     return printPreviewForItem(item, QString(),
4057 //! @todo store cached record data?
4058                                true/*reload*/);
4059 }
4060 
4061 tristate KexiMainWindow::showPageSetupForItem(KexiPart::Item* item)
4062 {
4063     Q_UNUSED(item)
4064 //! @todo check if changes to this object's design are saved, if not: ask for saving
4065 //! @todo accept record changes...
4066 //! @todo printActionForItem(item, PageSetupForItem);
4067     return false;
4068 }
4069 
4070 //! @todo reenable printItem() when ported
4071 #if 0
4072 bool KexiMainWindow::printItem(KexiPart::Item* item, const KexiSimplePrintingSettings& settings,
4073                                const QString& titleText)
4074 {
4075 //! @todo: check if changes to this object's design are saved, if not: ask for saving
4076 //! @todo: accept record changes...
4077     KexiSimplePrintingCommand cmd(this, item->identifier());
4078     //modal
4079     return cmd.print(settings, titleText);
4080 }
4081 
4082 bool KexiMainWindow::printPreviewForItem(KexiPart::Item* item,
4083         const KexiSimplePrintingSettings& settings, const QString& titleText, bool reload)
4084 {
4085 //! @todo: check if changes to this object's design are saved, if not: ask for saving
4086 //! @todo: accept record changes...
4087     KexiSimplePrintingCommand* cmd = d->openedCustomObjectsForItem<KexiSimplePrintingCommand>(
4088                                          item, "KexiSimplePrintingCommand");
4089     if (!cmd) {
4090         d->addOpenedCustomObjectForItem(
4091             item,
4092             cmd = new KexiSimplePrintingCommand(this, item->identifier()),
4093             "KexiSimplePrintingCommand"
4094         );
4095     }
4096     return cmd->showPrintPreview(settings, titleText, reload);
4097 }
4098 
4099 tristate KexiMainWindow::printActionForItem(KexiPart::Item* item, PrintActionType action)
4100 {
4101     if (!item)
4102         return false;
4103     KexiPart::Info *info = Kexi::partManager().infoForPluginId(item->pluginId());
4104     if (!info->isPrintingSupported())
4105         return false;
4106 
4107     KexiWindow *printingWindow = d->pageSetupWindows[ item->identifier()];
4108     if (printingWindow) {
4109         if (!activateWindow(*printingWindow))
4110             return false;
4111         if (action == PreviewItem || action == PrintItem) {
4112             QTimer::singleShot(0, printingWindow->selectedView(),
4113                                (action == PreviewItem) ? SLOT(printPreview()) : SLOT(print()));
4114         }
4115         return true;
4116     }
4117 
4118 #ifndef KEXI_NO_PENDING_DIALOGS
4119     Private::PendingJobType pendingType;
4120     KexiWindow *window = d->openedWindowFor(item, pendingType);
4121     if (pendingType != Private::NoJob)
4122         return cancelled;
4123 #else
4124     KexiWindow *window = openedWindowFor(item);
4125 #endif
4126 
4127     if (window) {
4128         // accept record changes
4129         QWidget *prevFocusWidget = focusWidget();
4130         window->setFocus();
4131         d->action_data_save_row->activate(QAction::Trigger);
4132         if (prevFocusWidget)
4133             prevFocusWidget->setFocus();
4134 
4135         // opened: check if changes made to this dialog are saved, if not: ask for saving
4136         if (window->neverSaved()) //sanity check
4137             return false;
4138         if (window->isDirty()) {
4139             KGuiItem saveChanges(KStandardGuiItem::save());
4140             saveChanges.setToolTip(futureI18n("Save changes"));
4141             saveChanges.setWhatsThis(
4142                 futureI18n("Pressing this button will save all recent changes made in \"%1\" object.",
4143                      item->name()));
4144             KGuiItem doNotSave(KStandardGuiItem::no());
4145             doNotSave.setWhatsThis(
4146                 futureI18n("Pressing this button will ignore all unsaved changes made in \"%1\" object.",
4147                      window->partItem()->name()));
4148 
4149             QString question;
4150             if (action == PrintItem)
4151                 question = futureI18n("Do you want to save changes before printing?");
4152             else if (action == PreviewItem)
4153                 question = futureI18n("Do you want to save changes before making print preview?");
4154             else if (action == PageSetupForItem)
4155                 question = futureI18n("Do you want to save changes before showing page setup?");
4156             else
4157                 return false;
4158 
4159             const KMessageBox::ButtonCode questionRes = KMessageBox::warningYesNoCancel(this,
4160                                     "<p>"
4161                                     + window->part()->i18nMessage("Design of object <resource>%1</resource> has been modified.", window)
4162                                     .subs(item->name())
4163                                     + "</p><p>" + question + "</p>",
4164                                     QString(),
4165                                     saveChanges,
4166                                     doNotSave);
4167             if (KMessageBox::Cancel == questionRes)
4168                 return cancelled;
4169             if (KMessageBox::Yes == questionRes) {
4170                 tristate savingRes = saveObject(window, QString(), DoNotAsk);
4171                 if (true != savingRes)
4172                     return savingRes;
4173             }
4174         }
4175     }
4176     KexiPart::Part * printingPart = Kexi::partManager().partForClass("org.kexi-project.simpleprinting");
4177     if (!printingPart)
4178         printingPart = new KexiSimplePrintingPart(); //hardcoded as there're no .desktop file
4179     KexiPart::Item* printingPartItem = d->prj->createPartItem(
4180                                            printingPart, item->name() //<-- this will look like "table1 : printing" on the window list
4181                                        );
4182     QMap<QString, QVariant> staticObjectArgs;
4183     staticObjectArgs["identifier"] = QString::number(item->identifier());
4184     if (action == PrintItem)
4185         staticObjectArgs["action"] = "print";
4186     else if (action == PreviewItem)
4187         staticObjectArgs["action"] = "printPreview";
4188     else if (action == PageSetupForItem)
4189         staticObjectArgs["action"] = "pageSetup";
4190     else
4191         return false;
4192     bool openingCancelled;
4193     printingWindow = openObject(printingPartItem, Kexi::DesignViewMode,
4194                                 &openingCancelled, &staticObjectArgs);
4195     if (openingCancelled)
4196         return cancelled;
4197     if (!printingWindow) //sanity
4198         return false;
4199     d->pageSetupWindows.insert(item->identifier(), printingWindow);
4200     d->pageSetupWindowItemID2dataItemID_map.insert(
4201         printingWindow->partItem()->identifier(), item->identifier());
4202 
4203     return true;
4204 }
4205 #endif
4206 
4207 void KexiMainWindow::slotEditCopySpecialDataTable()
4208 {
4209     KexiPart::Item* item = d->objectViewWidget->projectNavigator()->selectedPartItem();
4210     if (item)
4211         copyItemToClipboardAsDataTable(item);
4212 }
4213 
4214 tristate KexiMainWindow::copyItemToClipboardAsDataTable(KexiPart::Item* item)
4215 {
4216     if (!item)
4217         return false;
4218 
4219     QMap<QString, QString> args;
4220 
4221     if (!checkForDirtyFlagOnExport(item, &args)) {
4222             return false;
4223     }
4224 
4225     args.insert("destinationType", "clipboard");
4226     args.insert("itemId", QString::number(item->identifier()));
4227     QDialog *dlg = KexiInternalPart::createModalDialogInstance(
4228                        "org.kexi-project.importexport.csv", "KexiCSVExportWizard", this, 0, &args);
4229     if (!dlg)
4230         return false; //error msg has been shown by KexiInternalPart
4231     const int result = dlg->exec();
4232     delete dlg;
4233     return result == QDialog::Rejected ? tristate(cancelled) : tristate(true);
4234 }
4235 
4236 void KexiMainWindow::slotEditPasteSpecialDataTable()
4237 {
4238 //! @todo allow data appending (it is not possible now)
4239     if (d->userMode)
4240         return;
4241     QMap<QString, QString> args;
4242     args.insert("sourceType", "clipboard");
4243     QDialog *dlg = KexiInternalPart::createModalDialogInstance(
4244                        "org.kexi-project.importexport.csv", "KexiCSVImportDialog", this, 0, &args);
4245     if (!dlg)
4246         return; //error msg has been shown by KexiInternalPart
4247     dlg->exec();
4248     delete dlg;
4249 }
4250 
4251 void KexiMainWindow::slotEditFind()
4252 {
4253     KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface();
4254     if (!iface)
4255         return;
4256     d->updateFindDialogContents(true/*create if does not exist*/);
4257     d->findDialog()->setReplaceMode(false);
4258 
4259     d->findDialog()->show();
4260     d->findDialog()->activateWindow();
4261     d->findDialog()->raise();
4262 }
4263 
4264 void KexiMainWindow::slotEditFind(bool next)
4265 {
4266     KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface();
4267     if (!iface)
4268         return;
4269     tristate res = iface->find(
4270                        d->findDialog()->valueToFind(), d->findDialog()->options(), next);
4271     if (~res)
4272         return;
4273     d->findDialog()->updateMessage(true == res);
4274 //! @todo result
4275 }
4276 
4277 void KexiMainWindow::slotEditFindNext()
4278 {
4279     slotEditFind(true);
4280 }
4281 
4282 void KexiMainWindow::slotEditFindPrevious()
4283 {
4284     slotEditFind(false);
4285 }
4286 
4287 void KexiMainWindow::slotEditReplace()
4288 {
4289     KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface();
4290     if (!iface)
4291         return;
4292     d->updateFindDialogContents(true/*create if does not exist*/);
4293     d->findDialog()->setReplaceMode(true);
4294 //! @todo slotEditReplace()
4295     d->findDialog()->show();
4296     d->findDialog()->activateWindow();
4297 }
4298 
4299 void KexiMainWindow::slotEditReplaceNext()
4300 {
4301     slotEditReplace(false);
4302 }
4303 
4304 void KexiMainWindow::slotEditReplace(bool all)
4305 {
4306     KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface();
4307     if (!iface)
4308         return;
4309 //! @todo add question: "Do you want to replace every occurrence of \"%1\" with \"%2\"?
4310 //!       You won't be able to undo this." + "Do not ask again".
4311     tristate res = iface->findNextAndReplace(
4312                        d->findDialog()->valueToFind(), d->findDialog()->valueToReplaceWith(),
4313                        d->findDialog()->options(), all);
4314     d->findDialog()->updateMessage(true == res);
4315 //! @todo result
4316 }
4317 
4318 void KexiMainWindow::slotEditReplaceAll()
4319 {
4320     slotEditReplace(true);
4321 }
4322 
4323 void KexiMainWindow::highlightObject(const QString& pluginId, const QString& name)
4324 {
4325     if (!d->prj)
4326         return;
4327     KexiPart::Item *item = d->prj->itemForPluginId(pluginId, name);
4328     if (!item)
4329         return;
4330     if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) {
4331         d->setProjectNavigatorVisible(true, Private::ShowAnimated);
4332         d->objectViewWidget->projectNavigator()->selectItem(*item);
4333     }
4334 }
4335 
4336 void KexiMainWindow::slotPartItemSelectedInNavigator(KexiPart::Item* item)
4337 {
4338     Q_UNUSED(item);
4339 }
4340 
4341 KToolBar *KexiMainWindow::toolBar(const QString& name) const
4342 {
4343     return d->tabbedToolBar ? d->tabbedToolBar->toolBar(name) : 0;
4344 }
4345 
4346 void KexiMainWindow::appendWidgetToToolbar(const QString& name, QWidget* widget)
4347 {
4348     if (d->tabbedToolBar)
4349         d->tabbedToolBar->appendWidgetToToolbar(name, widget);
4350 }
4351 
4352 void KexiMainWindow::setWidgetVisibleInToolbar(QWidget* widget, bool visible)
4353 {
4354     if (d->tabbedToolBar)
4355         d->tabbedToolBar->setWidgetVisibleInToolbar(widget, visible);
4356 }
4357 
4358 void KexiMainWindow::addToolBarAction(const QString& toolBarName, QAction *action)
4359 {
4360     if (d->tabbedToolBar)
4361         d->tabbedToolBar->addAction(toolBarName, action);
4362 }
4363 
4364 void KexiMainWindow::updatePropertyEditorInfoLabel()
4365 {
4366     if (d->objectViewWidget && d->objectViewWidget->propertyPane()) {
4367         d->objectViewWidget->propertyPane()->updateInfoLabelForPropertySet(
4368             (currentWindow() && currentWindow()->selectedView())
4369                     ? currentWindow()->selectedView()->textToDisplayForNullSet()
4370                     : QString());
4371     }
4372 }
4373 
4374 void KexiMainWindow::beginPropertyPaneUpdate()
4375 {
4376     if (d->propertyPaneAnimation) {
4377         d->propertyPaneAnimation->hide();
4378         d->propertyPaneAnimation->deleteLater();
4379     }
4380     d->propertyPaneAnimation = new KexiFadeWidgetEffect(d->objectViewWidget->propertyPane());
4381 }
4382 
4383 void KexiMainWindow::endPropertyPaneUpdate()
4384 {
4385     if (d->propertyPaneAnimation) {
4386         d->objectViewWidget->propertyPane()->repaint();
4387         d->propertyPaneAnimation->start(150);
4388     }
4389 }
4390 
4391 void KexiMainWindow::addSearchableModel(KexiSearchableModel *model)
4392 {
4393     if (d->tabbedToolBar) {
4394         d->tabbedToolBar->addSearchableModel(model);
4395     }
4396 }
4397 
4398 void KexiMainWindow::removeSearchableModel(KexiSearchableModel *model)
4399 {
4400     if (d->tabbedToolBar) {
4401         d->tabbedToolBar->removeSearchableModel(model);
4402     }
4403 }
4404 
4405 void KexiMainWindow::setReasonableDialogSize(QDialog *dialog)
4406 {
4407     dialog->setMinimumSize(600, 400);
4408     dialog->resize(size() * 0.8);
4409 }
4410 
4411 void KexiMainWindow::restoreDesignTabAndActivateIfNeeded(const QString &tabName)
4412 {
4413     if (!d->tabbedToolBar) {
4414         return;
4415     }
4416     d->tabbedToolBar->showTab(tabName);
4417     if (currentWindow() && currentWindow()->partItem()
4418         && currentWindow()->partItem()->identifier() != 0) // for unstored items id can be < 0
4419     {
4420         const QString tabToActivate = d->tabsToActivateOnShow.value(
4421                                           currentWindow()->partItem()->identifier());
4422         //qDebug() << "tabToActivate:" << tabToActivate << "tabName:" << tabName;
4423         if (tabToActivate == tabName) {
4424             d->tabbedToolBar->setCurrentTab(tabToActivate);
4425         }
4426     }
4427 }
4428 
4429 void KexiMainWindow::restoreDesignTabIfNeeded(const QString &pluginId, Kexi::ViewMode viewMode,
4430                                               int previousItemId)
4431 {
4432     //qDebug() << pluginId << viewMode << previousItemId;
4433     if (viewMode == Kexi::DesignViewMode) {
4434         switch (d->prj->typeIdForPluginId(pluginId)) {
4435         case KexiPart::FormObjectType: {
4436             hideDesignTab(previousItemId, "org.kexi-project.report");
4437             restoreDesignTabAndActivateIfNeeded("form");
4438             break;
4439         }
4440         case KexiPart::ReportObjectType: {
4441             hideDesignTab(previousItemId, "org.kexi-project.form");
4442             restoreDesignTabAndActivateIfNeeded("report");
4443             break;
4444         }
4445         default:
4446             hideDesignTab(previousItemId);
4447         }
4448     }
4449     else {
4450         hideDesignTab(previousItemId);
4451     }
4452 }
4453 
4454 void KexiMainWindow::activateDesignTab(const QString &pluginId)
4455 {
4456     if (!d->tabbedToolBar) {
4457         return;
4458     }
4459     switch (d->prj->typeIdForPluginId(pluginId)) {
4460     case KexiPart::FormObjectType:
4461         d->tabbedToolBar->setCurrentTab("form");
4462         break;
4463     case KexiPart::ReportObjectType:
4464         d->tabbedToolBar->setCurrentTab("report");
4465         break;
4466     default:;
4467     }
4468 }
4469 
4470 void KexiMainWindow::activateDesignTabIfNeeded(const QString &pluginId, Kexi::ViewMode viewMode)
4471 {
4472     if (!d->tabbedToolBar) {
4473         return;
4474     }
4475     const QString tabToActivate = d->tabsToActivateOnShow.value(currentWindow()->partItem()->identifier());
4476     //qDebug() << pluginId << viewMode << tabToActivate;
4477 
4478     if (viewMode == Kexi::DesignViewMode && tabToActivate.isEmpty()) {
4479         activateDesignTab(pluginId);
4480     }
4481     else {
4482         d->tabbedToolBar->setCurrentTab(tabToActivate);
4483     }
4484 }
4485 
4486 void KexiMainWindow::hideDesignTab(int itemId, const QString &pluginId)
4487 {
4488     if (!d->tabbedToolBar) {
4489         return;
4490     }
4491     //qDebug() << itemId << pluginId;
4492     if (   itemId > 0
4493         && d->tabbedToolBar->currentWidget())
4494     {
4495         const QString currentTab = d->tabbedToolBar->currentWidget()->objectName();
4496         //qDebug() << "d->tabsToActivateOnShow.insert" << itemId << currentTab;
4497         d->tabsToActivateOnShow.insert(itemId, currentTab);
4498     }
4499     switch (d->prj->typeIdForPluginId(pluginId)) {
4500     case KexiPart::FormObjectType:
4501         d->tabbedToolBar->hideTab("form");
4502         break;
4503     case KexiPart::ReportObjectType:
4504         d->tabbedToolBar->hideTab("report");
4505         break;
4506     default:
4507         d->tabbedToolBar->hideTab("form");
4508         d->tabbedToolBar->hideTab("report");
4509     }
4510 }
4511 
4512 void KexiMainWindow::showDesignTabIfNeeded(int previousItemId)
4513 {
4514     if (d->insideCloseWindow && d->tabbedToolBar)
4515         return;
4516     if (currentWindow()) {
4517         restoreDesignTabIfNeeded(currentWindow()->partItem()->pluginId(),
4518                                  currentWindow()->currentViewMode(), previousItemId);
4519     } else {
4520         hideDesignTab(previousItemId);
4521     }
4522 }
4523 
4524 KexiUserFeedbackAgent* KexiMainWindow::userFeedbackAgent() const
4525 {
4526     return &d->userFeedback;
4527 }
4528 
4529 KexiMigrateManagerInterface* KexiMainWindow::migrateManager()
4530 {
4531     if (!d->migrateManager) {
4532         d->migrateManager = dynamic_cast<KexiMigrateManagerInterface*>(
4533                     KexiInternalPart::createObjectInstance(
4534                         "org.kexi-project.migration", "manager", this, this, nullptr));
4535     }
4536     return d->migrateManager;
4537 }
4538 
4539 void KexiMainWindow::toggleFullScreen(bool isFullScreen)
4540 {
4541     if (d->tabbedToolBar) {
4542         static bool isTabbarRolledDown;
4543         if (isFullScreen) {
4544             isTabbarRolledDown = !d->tabbedToolBar->isRolledUp();
4545             if (isTabbarRolledDown) {
4546                 d->tabbedToolBar->toggleRollDown();
4547             }
4548         } else {
4549             if (isTabbarRolledDown && d->tabbedToolBar->isRolledUp()) {
4550                 d->tabbedToolBar->toggleRollDown();
4551             }
4552         }
4553     }
4554     const Qt::WindowStates s = windowState() & Qt::WindowMaximized;
4555     if (isFullScreen) {
4556         setWindowState(windowState() | Qt::WindowFullScreen | s);
4557     } else {
4558         setWindowState((windowState() & ~Qt::WindowFullScreen));
4559         showMaximized();
4560     }
4561 }
4562 
4563 Kexi::GlobalViewMode KexiMainWindow::currentMode() const
4564 {
4565     return d->modeSelector->currentMode();
4566 }
4567 
4568 void KexiMainWindow::setCurrentMode(Kexi::GlobalViewMode mode)
4569 {
4570     d->modeSelector->setCurrentMode(mode);
4571 }
4572 
4573 void KexiMainWindow::slotCurrentModeChanged(Kexi::GlobalViewMode previousMode)
4574 {
4575     const Kexi::ViewMode viewMode = currentWindow()
4576             ? currentWindow()->currentViewMode() : Kexi::NoViewMode;
4577     switch (d->modeSelector->currentMode()) {
4578     case Kexi::WelcomeGlobalMode:
4579         break;
4580     case Kexi::ProjectGlobalMode:
4581         break;
4582     case Kexi::EditGlobalMode:
4583         updateObjectView();
4584         d->globalViewStack->setCurrentWidget(d->objectViewWidget);
4585         if (viewMode == Kexi::DesignViewMode || viewMode == Kexi::TextViewMode) {
4586             if (true != switchToViewMode(*currentWindow(), Kexi::DataViewMode)) {
4587                 setCurrentMode(previousMode);
4588             }
4589         }
4590         break;
4591     case Kexi::DesignGlobalMode:
4592         updateObjectView();
4593         d->globalViewStack->setCurrentWidget(d->objectViewWidget);
4594         if (viewMode == Kexi::DataViewMode) {
4595             Kexi::ViewMode newViewMode;
4596             if (currentWindow()->supportsViewMode(Kexi::TextViewMode)
4597                 && d->modeSelector->keyboardModifiers() == Qt::CTRL)
4598             {
4599                 newViewMode = Kexi::TextViewMode;
4600             } else {
4601                 newViewMode = Kexi::DesignViewMode;
4602             }
4603             if (true != switchToViewMode(*currentWindow(), newViewMode)) {
4604                 setCurrentMode(previousMode);
4605             }
4606         }
4607         break;
4608     case Kexi::HelpGlobalMode:
4609         break;
4610     case Kexi::NoGlobalMode:
4611         break;
4612     }
4613 }
4614 
4615 void KexiMainWindow::slotProjectNavigatorVisibilityChanged(bool visible)
4616 {
4617     if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) {
4618         d->modeSelector->setArrowColor(visible
4619             ? d->objectViewWidget->projectNavigator()->palette().color(QPalette::Window)
4620             : d->objectViewWidget->tabWidget()->palette().color(QPalette::Window));
4621     }
4622 }