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