diff --git a/src/doc/dev/settings.txt b/src/doc/dev/settings.txt index 48604050d..1d3158a65 100644 --- a/src/doc/dev/settings.txt +++ b/src/doc/dev/settings.txt @@ -1,164 +1,169 @@ ----------------------------------------------------------- Settings stored in 'kexirc' config file This is official list. All other settings are unofficial and are subject to change. Started: 2004-08-20, js ----------------------------------------------------------- Group: MainWindow # percentage width of the Project Navigator pane -LeftDockPosition [integer: 0..100] # True if the Project Navigator pane is visible after startup. -ShowProjectNavigator [boolean] (default: true) # True if single click should open item in the Project Navigator. # Otherwise double click should be used to open item. # Meaningful when "single click to open files" option is set # in the Control Center. - SingleClickOpensItem [boolean] (default: true on Windows, system settings elsewhere) +# Controls display of the global search box. +# This option allows to disable the box if it crashes for reason unrelated to KEXI +# (as in bug #390794). +- GlobalSearchBoxEnabled [boolean] (default: true) + Group: PropertyEditor # Font size in pixels. Obsolete since Kexi 3. See FontPointSize instead. -FontSize [integer] (default: system settings) # Font size in points. -FontPointSize [double] (default: system settings) Group: Notification Messages -AskBeforeDeleteRow [boolean] (default: true) TODO: -askBeforeOpeningFileReadOnly [boolean] (default: true) # If true, warning messages related to plugins, e.g. # "Errors encountered during loading plugins" # will be displayed on the application's startup. -ShowWarningsRelatedToPluginsLoading [boolean] (default: true) Group: General # especially useful for SQL-related messages TODO: -alwaysShowDetailsInMsgBoxes [boolean] (default: true for advanced Kexi mode) # True if internal debugger window should be displayed with Kexi. # The window shows database operations and enables extra actions like 'Show Form UI Code' # in the Form Designer. # Only available when KEXI_DEBUG_GUI build option is enabled. -ShowInternalDebugger [boolean] (default: false) Group: File Dialogs # If the KEXI_USE_KFILEWIDGET build option is on and UseKFileWidget is true, # KF5's KFileWidget-based widget is used in places where embedded file widget is needed. # If the KEXI_USE_KFILEWIDGET build option is on and UseKFileWidget is false, # simple file requester widget is used in places where embedded file widget is needed. # To delete the override, delete the UseKFileWidget option in the aplication's config file. -UseKFileWidget [boolean] (default: not present) Group: Recent Dirs # A list of recently displayed directories in file dialogs related to images (e.g. images within forms). # See KexiImageBox::slotInsertFromFile() and slotSaveAs(); TODO: -LastVisitedImagePath [URL list] (default: empty) Group: TableView TODO: -add default values for KexiTableView::Appearance Group: TableDesigner TODO: -autogeneratePrimaryKeysOnTableDesignSaving [boolean] TODO: -defaultFieldType [the list of types], default=Text TODO: -autoPrimaryKeyForFieldNames [stringlist] TODO: -defaultIntegerFieldSubtype [the list of types (byte, short, etc.)] default=long # Settings related to handling of database tables Group: Tables # value of DefaultTextFieldMaxLength should be also used on other places where we create tables with Text fields, e.g. on table importing # Default maximum length for fields of type Text TODO: -DefaultMaxLengthForTextFields [int] (0: unlimited or up to engine's limit, default=0) Group: QueryDesigner TODO: -autoJoinOnTableInserting [boolean] Group: KeyboardNavigation TODO: -cursorPlacementAfterLastOrFirstFormField [stringlist: nextOrPrevRecord|firstOrLastField(default)] Group: Forms TODO:-overrideStyleName [string] (empty if do not override) TODO:-doNotFocusAutonumberFields [boolean] (true by default; when this and autoTabStop for a form is true, autonumber text fields are skipped) implement this in KexiFormView::afterSwitchFrom() TODO:-appendColonToAutoLabels [boolean] (true by default; when true, colon character is appended to autolabel text) TODO:-makeFirstCharacterUpperCaseInAutoLabels [boolean] (true by default; when true, first character in autolabel text is converted to upper case. Usable when no field's title is provided) TODO:-labelPositionInAutoLabels [enum: Left, Top] (Left by default) TODO:-gridSize [int] (default: 10) Group: NewFormDefaults TODO: -styleName [string] TODO: -autoTabStop [boolean] Group: ImportExport # Default character encoding for MS Access MDB/MDE files (older than 2000). # Currently used by in Advanced Options of Importing Wizard. # Useful if you are performing many imports of MS Access databases. # Valid values can be "cp 1250", "cp 1251", etc. Case insensitive. # If not provided, system default will be is assumed. -DefaultEncodingForMSAccessFiles [string] (default: system specific) # Default character encoding for importing CSV (Comma-Separated Value) files. # If not provided, system default will be is assumed. -DefaultEncodingForImportingCSVFiles [string] (default: system locale) # True if options should be visible in the "CSV Export dialog". -ShowOptionsInCSVExportDialog [boolean] (default: false) # If provided, appropriate options for CSV Export Dialog will be loaded -StoreOptionsForCSVExportDialog [boolean] (default: false) # Default delimiter used for exporting CSV (Comma-Separated Value) files. -DefaultDelimiterForExportingCSVFiles [string] (default: ",") # Default text quote character used for exporting CSV (Comma-Separated Value) files. -DefaultTextQuoteForExportingCSVFiles [string] (default: ") # Import missing text values in CSV files as empty text ('' not NULL). -ImportNULLsAsEmptyText [boolean] (default: true) # Default character encoding for exporting CSV (Comma-Separated Value) files. # If not provided, system default will be is assumed. # Only used when StoreOptionsForCSVExportDialog option is true. -DefaultEncodingForExportingCSVFiles [string] (default: UTF-8) # Default setting used to specify whether column names should be added as the first row # for exporting CSV (Comma-Separated Value) files. # Only used when StoreOptionsForCSVExportDialog option is true. -AddColumnNamesForExportingCSVFiles [string] (default: true) # Maximum number of rows that can be displayed in the CSV import dialog. # Used to decrease memory consumption. -MaximumRowsForPreviewInImportDialog [int] (default: 100) # Maximum number of bytes that can be loaded to preview the data in the CSV # import dialog. Used to decrease memory consumption and speed up the GUI. -MaximumBytesForPreviewInImportDialog [int] (default: 10240) Group: Recent Dirs # A list of recently displayed directories in file dialogs related to CSV import/export. -CSVImportExport [URL list] (default: empty) # A list of recently displayed directories in "Source database" file dialog of Project Migration -ProjectMigrationSourceDir [URL list] (default: empty) # A list of recently displayed directories in "Destination database" file dialog of Project Migration -ProjectMigrationDestinationDir [URL list] (default: empty) # A list of recently displayed directories in "Open existing project" and "Create new project" file dialog of Startup Dialog -OpenExistingOrCreateNewProject [URL list] (default: empty) # A list of recent displayed directories in a file dialogs used for dowloading example databases (Get Hot New Stuff) TODO: -DownloadExampleDatabases [URL list] (default: empty) diff --git a/src/main/KexiMainWindow_p.cpp b/src/main/KexiMainWindow_p.cpp index 1f4510e98..4aacde5e7 100644 --- a/src/main/KexiMainWindow_p.cpp +++ b/src/main/KexiMainWindow_p.cpp @@ -1,1596 +1,1621 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2003-2015 Jarosław Staniek + Copyright (C) 2003-2018 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KexiMainWindow_p.h" #include #include +#include + #include #include #include #include #include #include KexiWindowContainer::KexiWindowContainer(QWidget* parent) : QWidget(parent) , window(0) , lyr(new QVBoxLayout(this)) { lyr->setContentsMargins(0, 0, 0, 0); } KexiWindowContainer::~KexiWindowContainer() { //! @todo warning if saveSettings() failed? if (window) { window->saveSettings(); delete (KexiWindow*)window; } } void KexiWindowContainer::setWindow(KexiWindow* w) { window = w; if (w) lyr->addWidget(w); } // --- EmptyMenuContentWidget::EmptyMenuContentWidget(QWidget* parent) : QWidget(parent) { setAutoFillBackground(true); alterBackground(); } void EmptyMenuContentWidget::alterBackground() { QPalette pal(palette()); QColor bg(pal.color(QPalette::Window)); bg.setAlpha(200); pal.setColor(QPalette::Window, bg); setPalette(pal); } void EmptyMenuContentWidget::changeEvent(QEvent *e) { if (e->type() == QEvent::PaletteChange) { alterBackground(); } QWidget::changeEvent(e); } //! @todo KEXI3 is KexiMenuWidgetStyle needed? #if 0 KexiMenuWidgetStyle::KexiMenuWidgetStyle(QStyle *style, QObject *parent) : KexiUtils::StyleProxy(style, parent) { } KexiMenuWidgetStyle::~KexiMenuWidgetStyle() { } void KexiMenuWidgetStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const { if (element == QStyle::CE_MenuItem && (option->state & QStyle::State_Selected) && (option->state & QStyle::State_Enabled) && parentStyle()->objectName() == QLatin1String("oxygen")) { // Ugly fix for visual glitch of oxygen; no chance for improvement since // we've forked QMenu and oxygen checks for qobject_cast directly. QColor c(option->palette.color(QPalette::Window)); int h, s, v, a; c.getHsv(&h, &s, &v, &a); // Why 0.91208791? I knew you're curious. There are some algorithms in Oxygen // to make color a bit lighter. They are not in the public API nor they are simple. // So the number was computed by me to find the proper value for the color // (the accuracy is quite OK). // It's also related to the fact that Oxygen's menus have gradient background. // A lot of computation happens under the mask... c.setHsv(h, s, v * 0.91208791, a); painter->fillRect(option->rect.x() + 6, option->rect.y() + 6, option->rect.width() - 12, option->rect.height() - 12, c); } KexiUtils::StyleProxy::drawControl(element, option, painter, widget); } #endif KexiMainMenu::KexiMainMenu(KexiTabbedToolBar *toolBar, QWidget* parent) : QWidget(parent), m_toolBar(toolBar), m_initialized(false) { m_content = 0; m_selectFirstItem = false; } KexiMainMenu::~KexiMainMenu() { delete (QWidget*)m_contentWidget; } bool KexiMainMenu::eventFilter(QObject * watched, QEvent* event) { if (event->type() == QEvent::MouseButtonPress && watched == m_content && !m_contentWidget) { emit contentAreaPressed(); } else if (event->type() == QEvent::KeyPress) { QKeyEvent* ke = static_cast(event); if ((ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) { emit hideContentsRequested(); return true; } } return QWidget::eventFilter(watched, event); } void KexiMainMenu::setContent(QWidget *contentWidget) { if (m_menuWidget && m_persistentlySelectedAction) { m_menuWidget->setPersistentlySelectedAction( m_persistentlySelectedAction, m_persistentlySelectedAction->persistentlySelected()); } /*if (m_menuWidget->persistentlySelectedAction()) qDebug() << "****" << m_menuWidget->persistentlySelectedAction()->objectName();*/ KexiFadeWidgetEffect *fadeEffect = 0; if (m_contentWidget && contentWidget) { fadeEffect = new KexiFadeWidgetEffect(m_content); } if (m_contentWidget) m_contentWidget->deleteLater(); m_contentWidget = contentWidget; if (m_contentWidget) { QPalette contentWidgetPalette(m_contentWidget->palette()); contentWidgetPalette.setBrush(QPalette::Active, QPalette::Window, contentWidgetPalette.brush(QPalette::Active, QPalette::Base)); contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::Window, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Base)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Window, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base)); contentWidgetPalette.setBrush(QPalette::Active, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Active, QPalette::Text)); contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Text)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Text)); const QColor highlightDisabled(KexiUtils::blendedColors( contentWidgetPalette.color(QPalette::Active, QPalette::Highlight), contentWidgetPalette.color(QPalette::Disabled, QPalette::Window), 1, 2)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlightDisabled); const QColor highlightedTextDisabled(KexiUtils::blendedColors( contentWidgetPalette.color(QPalette::Active, QPalette::HighlightedText), contentWidgetPalette.color(QPalette::Disabled, QPalette::WindowText), 1, 2)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::HighlightedText, highlightedTextDisabled); m_contentWidget->setPalette(contentWidgetPalette); for(QAbstractScrollArea *area : m_contentWidget->findChildren()) { QPalette pal(area->viewport()->palette()); pal.setBrush(QPalette::Disabled, QPalette::Base, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base)); area->viewport()->setPalette(pal); } m_contentWidget->setAutoFillBackground(true); m_contentWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); m_contentWidget->setContentsMargins(0, 0, 0, 0); m_contentLayout->addWidget(m_contentWidget); m_contentLayout->setCurrentWidget(m_contentWidget); m_contentWidget->setFocus(); m_contentWidget->installEventFilter(this); //connect(m_contentWidget, SIGNAL(destroyed()), this, SLOT(contentWidgetDestroyed())); } if (fadeEffect) { if (m_contentWidget) m_contentLayout->update(); QTimer::singleShot(10, fadeEffect, SLOT(start())); } } const QWidget *KexiMainMenu::contentWidget() const { return m_contentWidget; } void KexiMainMenu::setPersistentlySelectedAction(KexiMenuWidgetAction* action, bool set) { m_persistentlySelectedAction = action; m_persistentlySelectedAction->setPersistentlySelected(set); } /* void KexiMainMenu::setActiveAction(QAction* action = 0) { if (!action && !m_menuWidget->actions().isEmpty()) { action = actions().first(); } if (action) { m_menuWidget->setActiveAction(action); } } */ void KexiMainMenu::selectFirstItem() { m_selectFirstItem = true; } void KexiMainMenu::showEvent(QShowEvent * event) { if (!m_initialized) { m_initialized = true; KActionCollection *ac = KexiMainWindowIface::global()->actionCollection(); QHBoxLayout *hlyr = new QHBoxLayout(this); hlyr->setSpacing(0); hlyr->setMargin(0); m_menuWidget = new KexiMenuWidget; //! @todo KEXI3 is KexiMenuWidgetStyle needed? #if 0 QString styleName(m_menuWidget->style()->objectName()); if (KDE::version() < KDE_MAKE_VERSION(4, 8, 0) // a fix is apparently needed for glitch in KDE < 4.8 && styleName == "oxygen") { KexiMenuWidgetStyle *customStyle = new KexiMenuWidgetStyle(m_menuWidget->style()->objectName(), this); m_menuWidget->setStyle(customStyle); } #endif m_menuWidget->installEventFilter(this); m_menuWidget->setFocusPolicy(Qt::StrongFocus); setFocusProxy(m_menuWidget); m_menuWidget->setFrame(false); m_menuWidget->setAutoFillBackground(true); m_menuWidget->addAction(ac->action("project_welcome")); m_menuWidget->addAction(ac->action("project_open")); m_menuWidget->addAction(ac->action("project_close")); m_menuWidget->addSeparator(); m_menuWidget->addAction(ac->action("project_new")); m_menuWidget->addAction(ac->action("project_import_export_send")); #ifdef KEXI_SHOW_UNIMPLEMENTED m_menuWidget->addAction(ac->action("project_properties")); //! @todo project information m_menuWidget->addAction(ac->action("settings")); #endif m_menuWidget->addSeparator(); m_menuWidget->addAction(ac->action("quit")); hlyr->addWidget(m_menuWidget); m_content = new EmptyMenuContentWidget; m_content->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); m_content->installEventFilter(this); m_mainContentLayout = new QVBoxLayout; hlyr->addLayout(m_mainContentLayout); m_contentLayout = new QStackedLayout(m_content); m_contentLayout->setStackingMode(QStackedLayout::StackAll); m_contentLayout->setContentsMargins(0, 0, 0, 0); m_mainContentLayout->addWidget(m_content); hlyr->setStretchFactor(m_mainContentLayout, 1); } QWidget::showEvent(event); if (m_selectFirstItem && !m_menuWidget->actions().isEmpty()) { QAction* action = m_menuWidget->actions().first(); m_menuWidget->setActiveAction(action); m_selectFirstItem = false; } } // --- KexiTabbedToolBar::Private::Private(KexiTabbedToolBar *t) : q(t), createWidgetToolBar(0) #ifdef KEXI_AUTORISE_TABBED_TOOLBAR , tabToRaise(-1) #endif , rolledUp(false) { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR tabRaiseTimer.setSingleShot(true); tabRaiseTimer.setInterval(300); #endif tabBarAnimation.setPropertyName("opacity"); tabBarAnimation.setDuration(500); connect(&tabBarAnimation, SIGNAL(finished()), q, SLOT(tabBarAnimationFinished())); tabIndex = 0; lowestIndex = 2; } //! @return true if @a style name is specific regarding tab styling static bool isSpecificTabStyle(const QString &styleName) { return styleName == "oxygen" || styleName == "qtcurve" || styleName == "gtk+" || styleName == "gtk2"; } KexiTabbedToolBarStyle::KexiTabbedToolBarStyle(const QString &baseStyleName) : QProxyStyle(baseStyleName) { } KexiTabbedToolBarStyle::~KexiTabbedToolBarStyle() { } void KexiTabbedToolBarStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { const QString styleName(baseStyle()->objectName()); qreal origOpacity = -1.0; if (element == CE_TabBarTab) { const QStyleOptionTab* opt = qstyleoption_cast(option); const QTabBar* tabBar = qobject_cast(widget); KexiTabbedToolBar* tbar = tabBar ? qobject_cast(tabBar->parentWidget()) : 0; if (opt && tbar) { const int index = tabBar->tabAt(opt->rect.center()); if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) return; bool mouseOver = opt->state & QStyle::State_MouseOver; bool unselectedOrMenuVisible = !(opt->state & State_Selected) || tbar->mainMenuVisible(); if (unselectedOrMenuVisible) { if (styleName == "bespin") { unselectedOrMenuVisible = false; } } QStyleOptionTab newOpt(*opt); const bool specificStyle = isSpecificTabStyle(styleName); newOpt.text = (specificStyle ? " " : "") + tabBar->tabText(index) + (specificStyle ? " " : ""); if (!mouseOver && unselectedOrMenuVisible && index > 0) { if (tbar->mainMenuVisible()) newOpt.state &= ~QStyle::State_HasFocus; QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget); return; } else if (index == 0) { QBrush bg; newOpt.state |= State_Selected; if (tbar->mainMenuVisible()) { bg = newOpt.palette.brush(QPalette::Active, QPalette::Highlight); if (!specificStyle) { newOpt.palette.setBrush(QPalette::WindowText, newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText)); newOpt.palette.setBrush(QPalette::ButtonText, newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText)); } } else { if (styleName == "fusion") { bg = newOpt.palette.brush(QPalette::Active, QPalette::Button); } else { bg = Qt::transparent; } } QFont origFont(painter->font()); QFont f(origFont); f.setBold(true); painter->setFont(f); newOpt.palette.setBrush(QPalette::Window, bg); newOpt.palette.setBrush(QPalette::Button, // needed e.g. for Plastique style bg); QProxyStyle::drawControl(element, &newOpt, painter, widget); painter->setFont(origFont); if (!mouseOver || tbar->mainMenuVisible() || styleName == "gtk+") { return; } } if (index > 0 || mouseOver) { const QPalette::ColorGroup hbGroup = (styleName == "oxygen") ? QPalette::Active : QPalette::Inactive; const QBrush hb(newOpt.palette.brush(hbGroup, QPalette::Highlight)); newOpt.palette.setBrush(QPalette::Window, hb); newOpt.palette.setBrush(QPalette::Button, hb); // needed e.g. for Plastique style if (mouseOver && (index != tbar->currentIndex() || tbar->mainMenuVisible())) { // use lower opacity for diplaying hovered tabs origOpacity = painter->opacity(); painter->setOpacity(styleName == "qtcurve" ? 0.2 : 0.3); newOpt.state |= State_Selected; } else { if (!specificStyle) { newOpt.palette.setBrush(QPalette::WindowText, newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText)); newOpt.palette.setBrush(QPalette::ButtonText, newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText)); } } if (index == tbar->currentIndex() && styleName == "qtcurve") { origOpacity = painter->opacity(); painter->setOpacity(0.5); } (newOpt.state |= State_Active) ^= State_Active; QProxyStyle::drawControl(element, &newOpt, painter, widget); if (origOpacity != -1.0) { // restore opacity and draw labels using full this opacity painter->setOpacity(origOpacity); if (index > 0) { QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget); } } return; } } } else if (element == CE_ToolBar) { return; } QProxyStyle::drawControl(element, option, painter, widget); } void KexiTabbedToolBarStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { const QString styleName(baseStyle()->objectName()); if (element == PE_FrameTabWidget) { return; } if (element == PE_FrameTabBarBase) { const QTabBar* tabBar = qobject_cast(widget); KexiTabbedToolBar* tbar = tabBar ? qobject_cast(tabBar->parentWidget()) : 0; if (tbar && tbar->mainMenuVisible() && styleName != "bespin") { return; } } if (element == QStyle::PE_PanelToolBar || element == QStyle::PE_FrameMenu) { return; } QProxyStyle::drawPrimitive(element, option, painter, widget); } int KexiTabbedToolBarStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const { if (metric == QStyle::PM_SmallIconSize) return KIconLoader::SizeMedium; return QProxyStyle::pixelMetric(metric, option, widget); } // --- KexiTabbedToolBarTabBar::KexiTabbedToolBarTabBar(QWidget *parent) : QTabBar(parent) { setObjectName("tabbar"); customStyle = new KexiTabbedToolBarStyle(style()->objectName()); customStyle->setParent(this); setStyle(customStyle); installEventFilter(parent); QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); mainWindow->installEventFilter(parent); setAttribute(Qt::WA_Hover, true); } QSize KexiTabbedToolBarTabBar::originalTabSizeHint(int index) const { return QTabBar::tabSizeHint(index); } QSize KexiTabbedToolBarTabBar::tabSizeHint(int index) const { QSize s = QTabBar::tabSizeHint(index); QStyleOptionTab ot; ot.initFrom(this); QFont f(font()); f.setBold(true); ot.text = (isSpecificTabStyle(customStyle->baseStyle()->objectName()) ? " " : "") + tabText(index); ot.fontMetrics = QFontMetrics(f); int w = customStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, &ot, this); if (w <= 0) { // needed e.g. for oxygen w = fontMetrics().width(" "); } if (index == 0) { s.setWidth(QFontMetrics(f).width(ot.text) + w * 2); return s; } else if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) { // fix width of the spacer tab s.setWidth(w); } return s; } void KexiTabbedToolBar::Private::toggleMainMenu() { if (q->mainMenuVisible()) hideMainMenu(); else showMainMenu(); } void KexiTabbedToolBar::Private::showMainMenu(const char* actionName) { QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); if (!mainMenu) { mainMenu = new KexiMainMenu(q, mainWindow); connect(mainMenu, SIGNAL(contentAreaPressed()), this, SLOT(hideMainMenu())); connect(mainMenu, SIGNAL(hideContentsRequested()), this, SLOT(hideContentsOrMainMenu())); } updateMainMenuGeometry(); if (actionName) { q->selectMainMenuItem(actionName); } else { mainMenu->selectFirstItem(); } mainMenu->show(); mainMenu->setFocus(); q->update(); // tab bar could have a line that should be repainted } void KexiTabbedToolBar::Private::updateMainMenuGeometry() { if (!mainMenu) return; QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); KexiTabbedToolBarTabBar *tabBar = static_cast(q->tabBar()); QPoint pos = q->mapToGlobal(QPoint(0, tabBar->originalTabSizeHint(0).height() - 1)); // qDebug() << "1." << pos; pos = mainWindow->mapFromGlobal(pos); // qDebug() << "2." << pos; // qDebug() << "3." << q->pos(); QStyleOptionTab ot; ot.initFrom(tabBar); int overlap = tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &ot, tabBar) - tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseHeight, &ot, tabBar); // qDebug() << "4. overlap=" << overlap; mainMenu->setGeometry(0, pos.y() - overlap /*- q->y()*/, mainWindow->width(), mainWindow->height() - pos.y() + overlap /*+ q->y()*/); } +void KexiTabbedToolBar::Private::initSearchLineEdit() +{ + //! @todo use KexiConfig + KConfigGroup mainWindowGroup(KSharedConfig::openConfig()->group("MainWindow")); + const bool enabled = mainWindowGroup.readEntry("GlobalSearchBoxEnabled", true); + if (enabled && !searchLineEdit) { + searchLineEdit = new KexiSearchLineEdit; + kexiTester() << KexiTestObject(searchLineEdit, "globalSearch.lineEdit"); + searchLineEdit->installEventFilter(q); + helpLayer->addWidget(searchLineEdit); + } else if (!enabled && searchLineEdit) { + helpLayer->removeWidget(searchLineEdit); + delete searchLineEdit; + searchLineEdit = nullptr; + } +} + void KexiTabbedToolBar::activateSearchLineEdit() { + if (!d->searchLineEdit) { + return; + } d->searchLineEdit->selectAll(); d->searchLineEdit->setFocus(); } void KexiTabbedToolBar::Private::hideMainMenu() { if (!mainMenu || !mainMenu->isVisible()) return; mainMenu->hide(); mainMenu->setContent(0); q->update(); // tab bar could have a line that should be repainted } void KexiTabbedToolBar::Private::hideContentsOrMainMenu() { if (!mainMenu || !mainMenu->isVisible()) return; if (mainMenu->contentWidget()) { mainMenu->setContent(0); } else { hideMainMenu(); } } KToolBar *KexiTabbedToolBar::Private::createToolBar(const char *name, const QString& caption) { KToolBar *tbar = new KToolBar(q, true /*main toolbar*/, false /*read config*/); tbar->setIconDimensions(22); //!< @todo make configurable or system-dependent? // needed e.g. for Windows style to remove the toolbar's frame tbar->setStyle(customTabBar->customStyle); toolbarsForName.insert(name, tbar); tbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); tbar->setObjectName(name); toolbarsCaptionForName.insert(name, caption); tabIndex = q->addTab(tbar, caption); toolbarsVisibleForIndex.append(true); toolbarsIndexForName.insert(name, tabIndex); return tbar; } KexiTabbedToolBar::KexiTabbedToolBar(QWidget *parent) : QTabWidget(parent) , d(new Private(this)) { d->customTabBar = new KexiTabbedToolBarTabBar(this); setTabBar(d->customTabBar); setStyle(d->customTabBar->customStyle); // from ktabwidget.cpp //! @todo QTabWidget::setTabBar() should be added with this code //! @todo KEXI3 Are these tabBar() connections useful to port? #if 0 connect(tabBar(), SIGNAL(contextMenu(int,QPoint)), SLOT(contextMenu(int,QPoint&))); connect(tabBar(), SIGNAL(tabDoubleClicked(int)), SLOT(mouseDoubleClick(int))); connect(tabBar(), SIGNAL(newTabRequest()), this, SIGNAL(mouseDoubleClick())); // #185487 connect(tabBar(), SIGNAL(mouseMiddleClick(int)), SLOT(mouseMiddleClick(int))); connect(tabBar(), SIGNAL(initiateDrag( int )), SLOT(initiateDrag( int ))); connect(tabBar(), SIGNAL(testCanDecode(QDragMoveEvent*,bool*)), SIGNAL(testCanDecode(QDragMoveEvent*,bool*))); connect(tabBar(), SIGNAL(receivedDropEvent(int,QDropEvent*)), SLOT(receivedDropEvent(int,QDropEvent*))); connect(tabBar(), SIGNAL(moveTab(int,int)), SLOT(moveTab(int,int))); connect(tabBar(), SIGNAL(tabCloseRequested(int)), SLOT(closeRequest(int))); #endif setMouseTracking(true); // for mouseMoveEvent() setWhatsThis(xi18n("Task-oriented toolbar. Groups commands using tabs.")); #ifdef KEXI_AUTORISE_TABBED_TOOLBAR connect(&d->tabRaiseTimer, SIGNAL(timeout()), this, SLOT(slotDelayedTabRaise())); #endif connect(tabBar(), SIGNAL(tabBarDoubleClicked(int)), this, SLOT(slotTabDoubleClicked(int))); d->ac = KexiMainWindowIface::global()->actionCollection(); QWidget *mainWin = KexiMainWindowIface::global()->thisWidget(); const bool userMode = KexiMainWindowIface::global()->userMode(); KToolBar *tbar; slotSettingsChanged(0);//KGlobalSettings::FontChanged //! @todo KEXI3 port from KGlobalSettings::Private::_k_slotNotifyChange: //! connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(slotSettingsChanged(int))); // help area QWidget *helpWidget = new QWidget(this); helpWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - QHBoxLayout *helpLyr = new QHBoxLayout(helpWidget); - helpLyr->setContentsMargins(0, 0, 0, 0); + d->helpLayer = new QHBoxLayout(helpWidget); + d->helpLayer->setContentsMargins(0, 0, 0, 0); // * HELP MENU // add help menu actions... (KexiTabbedToolBar depends on them) d->helpMenu = new KHelpMenu(this, KAboutData::applicationData(), true/*showWhatsThis*/); QAction* help_report_bug_action = d->helpMenu->action(KHelpMenu::menuReportBug); d->ac->addAction(help_report_bug_action->objectName(), help_report_bug_action); QObject::disconnect(help_report_bug_action, 0, 0, 0); QObject::connect(help_report_bug_action, SIGNAL(triggered()), mainWin, SLOT(slotReportBug())); help_report_bug_action->setText(xi18nc("Report a bug or wish for Kexi application", "Report a &Bug or Wish...")); help_report_bug_action->setIcon(koIcon("tools-report-bug")); // good icon for toolbar help_report_bug_action->setWhatsThis(xi18n("Files a bug or wish for Kexi application.")); QAction* help_whats_this_action = d->helpMenu->action(KHelpMenu::menuWhatsThis); d->ac->addAction(help_whats_this_action->objectName(), help_whats_this_action); help_whats_this_action->setWhatsThis(xi18n("Activates a \"What's This?\" tool.")); QAction* help_contents_action = d->helpMenu->action(KHelpMenu::menuHelpContents); d->ac->addAction(help_contents_action->objectName(), help_contents_action); help_contents_action->setText(xi18n("Help")); help_contents_action->setWhatsThis(xi18n("Shows Kexi Handbook.")); QAction* help_about_app_action = d->helpMenu->action(KHelpMenu::menuAboutApp); d->ac->addAction(help_about_app_action->objectName(), help_about_app_action); help_about_app_action->setWhatsThis(xi18n("Shows information about Kexi application.")); QAction* help_about_kde_action = d->helpMenu->action(KHelpMenu::menuAboutKDE); d->ac->addAction(help_about_kde_action->objectName(), help_about_kde_action); help_about_kde_action->setWhatsThis(xi18n("Shows information about KDE.")); QAction* help_switch_language_action = d->helpMenu->action(KHelpMenu::menuSwitchLanguage); if (help_switch_language_action) { d->ac->addAction(help_switch_language_action->objectName(), help_switch_language_action); } // extra action such as help_donate may be confusing for the user or conflicting with existing so hide it QAction *extraAction = d->helpMenu->action(static_cast(KHelpMenu::menuSwitchLanguage + 1)); if (extraAction) { extraAction->setVisible(false); } QAction *action_show_help_menu = d->ac->action("help_show_menu"); KexiSmallToolButton *btn = new KexiSmallToolButton(koIcon("help-about"), QString(), helpWidget); btn->setToolButtonStyle(Qt::ToolButtonIconOnly); btn->setPopupMode(QToolButton::InstantPopup); btn->setToolTip(action_show_help_menu->toolTip()); btn->setWhatsThis(action_show_help_menu->whatsThis()); btn->setFocusPolicy(Qt::NoFocus); QStyleOptionToolButton opt; opt.initFrom(btn); int w = btn->sizeHint().width(); int wAdd = btn->style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, btn); if (w <= (2 * (wAdd + 1))) { w += wAdd + 2; } btn->setMinimumWidth(w); connect(action_show_help_menu, SIGNAL(triggered()), btn, SLOT(showMenu())); - helpLyr->addWidget(btn); + d->helpLayer->addWidget(btn); btn->setMenu(d->helpMenu->menu()); setCornerWidget(helpWidget, Qt::TopRightCorner); - d->searchLineEdit = new KexiSearchLineEdit; - kexiTester() << KexiTestObject(d->searchLineEdit, "globalSearch.lineEdit"); - d->searchLineEdit->installEventFilter(this); - helpLyr->addWidget(d->searchLineEdit); + d->initSearchLineEdit(); // needed e.g. for Windows style to remove the toolbar's frame QWidget *dummyWidgetForMainMenu = new QWidget(this); dummyWidgetForMainMenu->setObjectName("kexi"); addTab(dummyWidgetForMainMenu, KAboutData::applicationData().displayName()); d->toolbarsVisibleForIndex.append(true); addTab(new QWidget(this), QString()); // dummy for spacer d->toolbarsVisibleForIndex.append(true); if (!userMode) { d->createWidgetToolBar = d->createToolBar("create", xi18n("Create")); } tbar = d->createToolBar("data", xi18n("Data")); addAction(tbar, "edit_cut"); addAction(tbar, "edit_copy"); addAction(tbar, "edit_paste"); if (!userMode) addAction(tbar, "edit_paste_special_data_table"); //! @todo move undo/redo to quickbar: tbar = d->createToolBar("external", xi18n("External Data")); if (!userMode) { addAction(tbar, "project_import_data_table"); addAction(tbar, "tools_import_tables"); } tbar = d->createToolBar("tools", xi18n("Tools")); addAction(tbar, "tools_compact_database"); //! @todo move to form plugin tbar = d->createToolBar("form", xi18n("Form Design")); //! @todo move to report plugin tbar = d->createToolBar("report", xi18n("Report Design")); connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int))); setCurrentWidget(widget(KEXITABBEDTOOLBAR_SPACER_TAB_INDEX + 1)); // the default setFocusPolicy(Qt::NoFocus); } void KexiTabbedToolBar::Private::setCurrentTab(const QString& name) { q->setCurrentWidget(q->toolBar(name)); } void KexiTabbedToolBar::Private::hideTab(const QString& name) { q->removeTab(q->indexOf(toolbarsForName.value(name))); toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = false; } bool KexiTabbedToolBar::Private::isTabVisible(const QString& name) const { return q->indexOf(toolbarsForName.value(name)) != -1 && toolbarsVisibleForIndex[toolbarsIndexForName.value(name)]; } #ifndef NDEBUG void KexiTabbedToolBar::Private::debugToolbars() const { qDebug() << "QHash toolbarsForName:"; for (QHash::ConstIterator it(toolbarsForName.constBegin()); it!=toolbarsForName.constEnd(); ++it) { qDebug() << it.key() << "->" << it.value(); } qDebug() << "QHash toolbarsIndexForName:"; for (QHash::ConstIterator it(toolbarsIndexForName.constBegin()); it!=toolbarsIndexForName.constEnd(); ++it) { qDebug() << it.key() << "->" << it.value(); } qDebug() << "QHash toolbarsCaptionForName:"; for (QHash::ConstIterator it(toolbarsCaptionForName.constBegin()); it!=toolbarsCaptionForName.constEnd(); ++it) { qDebug() << it.key() << "->" << it.value(); } qDebug() << "QVector toolbarsVisibleForIndex:"; for (int i = 0; i < toolbarsVisibleForIndex.size(); i++) { qDebug() << i << "->" << toolbarsVisibleForIndex[i]; } } #endif void KexiTabbedToolBar::Private::showTab(const QString& name) { // qDebug() << "name:" << name; // qDebug() << "toolbarsForName.value(name):" << toolbarsForName.value(name); // qDebug() << "toolbarsIndexForName.value(name):" << toolbarsIndexForName.value(name); // qDebug() << "q->indexOf(toolbarsForName.value(name))" << q->indexOf(toolbarsForName.value(name)); #ifndef NDEBUG //debugToolbars(); #endif if (q->indexOf(toolbarsForName.value(name)) == -1) { int h = 0; // count h = invisible tabs before this for (int i = lowestIndex; i < toolbarsIndexForName.value(name); i++) { if (!toolbarsVisibleForIndex.at(i)) h++; } q->insertTab(toolbarsIndexForName.value(name) - h, toolbarsForName.value(name), toolbarsCaptionForName.value(name)); toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = true; } } // --- KexiTabbedToolBar::~KexiTabbedToolBar() { delete d; } bool KexiTabbedToolBar::mainMenuVisible() const { return d->mainMenu && d->mainMenu->isVisible(); } QRect KexiTabbedToolBar::tabRect(int index) const { return tabBar()->tabRect(index); } KHelpMenu* KexiTabbedToolBar::helpMenu() const { return d->helpMenu; } void KexiTabbedToolBar::slotSettingsChanged(int category) { Q_UNUSED(category); //! @todo if (category == KGlobalSettings::FontChanged) { //! @todo KEXI3 KGlobalSettings::menuFont() not available (using QFontDatabase::systemFont(QFontDatabase::GeneralFont) for now) //! https://community.kde.org/Frameworks/Porting_Notes#Global_Settings setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); // the toolbar acts like a menu //} } KToolBar* KexiTabbedToolBar::createWidgetToolBar() const { return d->createWidgetToolBar; } void KexiTabbedToolBar::mouseMoveEvent(QMouseEvent* event) { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR QPoint p = event->pos(); int tab = tabBar()->tabAt(p); if (d->tabToRaise != -1 && (tab == -1 || tab == currentIndex())) { d->tabRaiseTimer.stop(); d->tabToRaise = -1; } else if (d->tabToRaise != tab) { d->tabRaiseTimer.start(); d->tabToRaise = tab; } #endif QTabWidget::mouseMoveEvent(event); } void KexiTabbedToolBar::leaveEvent(QEvent* event) { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR d->tabRaiseTimer.stop(); d->tabToRaise = -1; #endif QTabWidget::leaveEvent(event); } bool KexiTabbedToolBar::eventFilter(QObject* watched, QEvent* event) { switch (event->type()) { case QEvent::MouseButtonPress: { QWidget *mainWin = KexiMainWindowIface::global()->thisWidget(); // qDebug() << "MouseButtonPress: watched:" << watched << "window()->focusWidget():" << window()->focusWidget(); - if (watched == d->searchLineEdit) { + if (d->searchLineEdit && watched == d->searchLineEdit) { activateSearchLineEdit(); // custom setFocus() for search box, so it's possible to focus // back on Escape key press return false; } else if (watched == tabBar()) { QMouseEvent* me = static_cast(event); QPoint p = me->pos(); KexiTabbedToolBarTabBar *tb = static_cast(tabBar()); int index = tb->tabAt(p); if (index == 0) { d->toggleMainMenu(); return true; } d->hideMainMenu(); if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) { return true; } } else if (watched == mainWin && d->mainMenu) { QMouseEvent* me = static_cast(event); if (!QRect(d->mainMenu->mapToGlobal(QPoint(0,0)), d->mainMenu->size()) .contains(mainWin->mapToGlobal(me->pos()))) { // hide if clicked outside of the menu d->hideMainMenu(); } } } break; case QEvent::KeyPress: { QKeyEvent* ke = static_cast(event); // qDebug() << "**********" << QString::number(ke->key(), 16) // << QKeySequence::mnemonic(tabText(0))[0]; if (QKeySequence::mnemonic(tabText(0)) == QKeySequence(ke->key())) { // qDebug() << "eat the &File accel"; if (!d->mainMenu || !d->mainMenu->isVisible()) { d->showMainMenu(); } /*this could be unexpected: else if (d->mainMenu && d->mainMenu->isVisible()) { d->hideMainMenu(); }*/ return true; } if (d->mainMenu && d->mainMenu->isVisible() && (ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) { d->hideContentsOrMainMenu(); return true; } break; } case QEvent::Resize: if (watched == KexiMainWindowIface::global()->thisWidget()) { d->updateMainMenuGeometry(); } break; case QEvent::Shortcut: { QShortcutEvent *se = static_cast(event); if (watched == tabBar() && QKeySequence::mnemonic(tabText(0)) == se->key()) { // qDebug() << "eat the &File accel"; if (!d->mainMenu || !d->mainMenu->isVisible()) { d->showMainMenu(); return true; } } break; } default:; } return QTabWidget::eventFilter(watched, event); } void KexiTabbedToolBar::slotCurrentChanged(int index) { if (index == indexOf(d->createWidgetToolBar) && index != -1) { if (d->createWidgetToolBar->actions().isEmpty()) { QTimer::singleShot(10, this, SLOT(setupCreateWidgetToolbar())); } } if (d->rolledUp) { // switching the tab rolls down slotTabDoubleClicked(index); } if (index == 0) { // main menu d->showMainMenu(); } else { d->hideMainMenu(); } } void KexiTabbedToolBar::slotTabDoubleClicked(int index) { if (index <= 0) { return; // main item does not count here } d->rolledUp = !d->rolledUp; d->tabBarAnimation.stop(); QWidget *w = widget(index); if (!w) { return; } w->setGraphicsEffect(&d->tabBarOpacityEffect); if (d->rolledUp) { d->tabBarOpacityEffect.setOpacity(1.0); d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect); d->tabBarAnimation.setStartValue(1.0); d->tabBarAnimation.setEndValue(0.0); d->tabBarAnimation.start(); } else { // roll down d->tabBarOpacityEffect.setOpacity(0.0); setMaximumHeight(QWIDGETSIZE_MAX); widget(d->rolledUpIndex)->show(); widget(d->rolledUpIndex)->setMaximumHeight(QWIDGETSIZE_MAX); w->setMaximumHeight(QWIDGETSIZE_MAX); w->show(); d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect); d->tabBarAnimation.setStartValue(0.0); d->tabBarAnimation.setEndValue(1.0); d->tabBarAnimation.start(); } } void KexiTabbedToolBar::tabBarAnimationFinished() { if (d->rolledUp) { // hide and collapse the area widget(currentIndex())->hide(); KexiTabbedToolBarTabBar *tb = static_cast(tabBar()); setFixedHeight(tb->tabSizeHint(currentIndex()).height()); widget(currentIndex())->setFixedHeight(0); d->rolledUpIndex = currentIndex(); } } void KexiTabbedToolBar::setupCreateWidgetToolbar() { if (!d->createWidgetToolBar->actions().isEmpty()) return; //! @todo separate core object types from custom.... KexiPart::PartInfoList *plist = Kexi::partManager().infoList(); //this list is properly sorted if (plist) { foreach(KexiPart::Info *info, *plist) { QAction* a = info->newObjectAction(); if (a) { d->createWidgetToolBar->addAction(a); } else { //! @todo err } } } } void KexiTabbedToolBar::slotDelayedTabRaise() { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR QPoint p = mapFromGlobal(QCursor::pos()); // make sure cursor is still over the tab int tab = tabBar()->tabAt(p); if (tab != d->tabToRaise) { d->tabToRaise = -1; } else if (d->tabToRaise != -1) { setCurrentIndex(d->tabToRaise); d->tabToRaise = -1; } #endif } KToolBar *KexiTabbedToolBar::toolBar(const QString& name) const { return d->toolbarsForName[name]; } void KexiTabbedToolBar::addAction(KToolBar *tbar, const char* actionName) { QAction *a = d->ac->action(actionName); if (a) tbar->addAction(a); } void KexiTabbedToolBar::addAction(const QString& toolBarName, QAction *action) { if (!action) return; KToolBar *tbar = d->toolbarsForName[toolBarName]; if (!tbar) return; tbar->addAction(action); } void KexiTabbedToolBar::addSeparatorAndAction(KToolBar *tbar, const char* actionName) { QAction *a = d->ac->action(actionName); if (a) { tbar->addSeparator(); tbar->addAction(a); } } void KexiTabbedToolBar::appendWidgetToToolbar(const QString& name, QWidget* widget) { KToolBar *tbar = d->toolbarsForName[name]; if (!tbar) { return; } QAction *action = tbar->addWidget(widget); d->extraActions.insert(widget, action); } void KexiTabbedToolBar::setWidgetVisibleInToolbar(QWidget* widget, bool visible) { QAction *action = d->extraActions[widget]; if (!action) { return; } action->setVisible(visible); } void KexiTabbedToolBar::showMainMenu(const char* actionName) { d->showMainMenu(actionName); } void KexiTabbedToolBar::hideMainMenu() { d->hideMainMenu(); } void KexiTabbedToolBar::toggleMainMenu() { d->toggleMainMenu(); } void KexiTabbedToolBar::setMainMenuContent(QWidget *w) { d->mainMenu->setContent(w); } void KexiTabbedToolBar::selectMainMenuItem(const char *actionName) { if (actionName) { KActionCollection *ac = KexiMainWindowIface::global()->actionCollection(); KexiMenuWidgetAction *a = qobject_cast(ac->action(actionName)); if (a) { d->mainMenu->setPersistentlySelectedAction(a, true); } } } void KexiTabbedToolBar::addSearchableModel(KexiSearchableModel *model) { + if (!d->searchLineEdit) { + return; + } d->searchLineEdit->addSearchableModel(model); } void KexiTabbedToolBar::removeSearchableModel(KexiSearchableModel *model) { + if (!d->searchLineEdit) { + return; + } d->searchLineEdit->removeSearchableModel(model); } KToolBar* KexiTabbedToolBar::createToolBar(const char* name, const QString& caption) { return d->createToolBar(name, caption); } void KexiTabbedToolBar::setCurrentTab(const QString& name) { //qDebug() << name; d->setCurrentTab(name); } void KexiTabbedToolBar::setCurrentTab(int index) { setCurrentIndex(d->lowestIndex + index); } void KexiTabbedToolBar::hideTab(const QString& name) { //qDebug() << name; d->hideTab(name); } void KexiTabbedToolBar::showTab(const QString& name) { //qDebug() << name; d->showTab(name); } bool KexiTabbedToolBar::isTabVisible(const QString& name) const { return d->isTabVisible(name); } bool KexiTabbedToolBar::isRolledUp() { return d->rolledUp; } void KexiTabbedToolBar::toggleRollDown() { slotTabDoubleClicked(-1);//use -1 just to rolldown/up the tabbar } // --- KexiMainWidget::KexiMainWidget() : KMainWindow(0, Qt::Widget) , m_mainWindow(0) { setupCentralWidget(); } KexiMainWidget::~KexiMainWidget() { } void KexiMainWidget::setParent(KexiMainWindow* mainWindow) { KMainWindow::setParent(mainWindow); m_mainWindow = mainWindow; } KexiMainWindowTabWidget* KexiMainWidget::tabWidget() const { return m_tabWidget; } void KexiMainWidget::setupCentralWidget() { QWidget *centralWidget = new QWidget(this); QVBoxLayout *centralWidgetLyr = new QVBoxLayout(centralWidget); m_tabWidget = new KexiMainWindowTabWidget(centralWidget, this); connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentTabIndexChanged(int))); centralWidgetLyr->setContentsMargins(0, 0, 0, 0); centralWidgetLyr->setSpacing(0); centralWidgetLyr->addWidget(m_tabWidget); setCentralWidget(centralWidget); layout()->setContentsMargins(0, 0, 0, 0); layout()->setSpacing(0); } bool KexiMainWidget::queryClose() { return m_mainWindow ? m_mainWindow->queryClose() : true; } void KexiMainWidget::slotCurrentTabIndexChanged(int index) { KexiWindowContainer* cont = dynamic_cast(m_tabWidget->widget(index)); if (! cont || (KexiWindow*)m_previouslyActiveWindow == cont->window) return; if (m_mainWindow) m_mainWindow->activeWindowChanged(cont->window, (KexiWindow*)m_previouslyActiveWindow); m_previouslyActiveWindow = cont->window; emit currentTabIndexChanged(index); } //------------------------------------------ KexiMainWindow::Private::Private(KexiMainWindow* w) : wnd(w) { actionCollection = new KActionCollection(w); propEditor = 0; propEditorDockWidget = 0; navDockWidget = 0; propEditorTabWidget = 0; KexiProjectData *pdata = KexiStartupHandler::global()->projectData(); userMode = KexiStartupHandler::global()->forcedUserMode() /* <-- simply forced the user mode */ /* project has 'user mode' set as default and not 'design mode' override is found: */ || (pdata && pdata->userMode() && !KexiStartupHandler::global()->forcedDesignMode()); isProjectNavigatorVisible = KexiStartupHandler::global()->isProjectNavigatorVisible(); isMainMenuVisible = KexiStartupHandler::global()->isMainMenuVisible(); navigator = 0; prj = 0; config = KSharedConfig::openConfig(); nameDialog = 0; m_findDialog = 0; focus_before_popup = 0; action_show_nav = 0; action_show_propeditor = 0; action_activate_nav = 0; action_activate_propeditor = 0; action_welcome_projects_title_id = -1; action_welcome_connections_title_id = -1; forceWindowClosing = false; insideCloseWindow = false; #ifndef KEXI_NO_PENDING_DIALOGS actionToExecuteWhenPendingJobsAreFinished = NoAction; #endif propEditorDockSeparatorPos = -1; navDockSeparatorPos = -1; wasAutoOpen = false; windowExistedBeforeCloseProject = false; #ifndef KEXI_SHOW_UNIMPLEMENTED dummy_action = new KActionMenu(QString(), wnd); #endif forceShowProjectNavigatorOnCreation = false; forceHideProjectNavigatorOnCreation = false; navWasVisibleBeforeProjectClosing = false; saveSettingsForShowProjectNavigator = true; propertyEditorCollapsed = false; enable_slotPropertyEditorVisibilityChanged = true; migrateManager = 0; } KexiMainWindow::Private::~Private() { qDeleteAll(m_openedCustomObjectsForItem); } void KexiMainWindow::Private::insertWindow(KexiWindow *window) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.insert(window->id(), window); #ifndef KEXI_NO_PENDING_DIALOGS pendingWindows.remove(window->id()); #endif } bool KexiMainWindow::Private::windowContainerExistsFor(int identifier) const { return windowContainers.contains(identifier); } void KexiMainWindow::Private::setWindowContainerExistsFor(int identifier, bool set) { if (set) { windowContainers.insert(identifier); } else { windowContainers.remove(identifier); } } void KexiMainWindow::Private::updateWindowId(KexiWindow *window, int oldItemID) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.remove(oldItemID); #ifndef KEXI_NO_PENDING_DIALOGS pendingWindows.remove(oldItemID); #endif windows.insert(window->id(), window); } void KexiMainWindow::Private::removeWindow(int identifier) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.remove(identifier); } int KexiMainWindow::Private::openedWindowsCount() { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return windows.count(); } //! Used in KexiMainWindowe::closeProject() void KexiMainWindow::Private::clearWindows() { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.clear(); #ifndef KEXI_NO_PENDING_DIALOGS pendingWindows.clear(); #endif } void KexiMainWindow::Private::showStartProcessMsg(const QStringList& args) { wnd->showErrorMessage(xi18nc("@info", "Could not start %1 application.", QString::fromLatin1(KEXI_APP_NAME)), xi18nc("@info", "Command %1 failed.", args.join(" "))); } void KexiMainWindow::Private::updatePropEditorVisibility(Kexi::ViewMode viewMode, KexiPart::Info *info) { if (!propEditorDockWidget) return; KexiWindow *currentWindow = wnd->currentWindow(); if (!info && currentWindow) { info = currentWindow->part()->info(); } const bool visible = (viewMode == Kexi::DesignViewMode) && ((currentWindow && currentWindow->propertySet()) || (info && info->isPropertyEditorAlwaysVisibleInDesignMode())); //qDebug() << "visible == " << visible; enable_slotPropertyEditorVisibilityChanged = false; if (visible && propertyEditorCollapsed) { // used when we're switching back to a window with propeditor available but collapsed propEditorDockWidget->setVisible(!visible); setPropertyEditorTabBarVisible(true); } else { propEditorDockWidget->setVisible(visible); setPropertyEditorTabBarVisible(false); } enable_slotPropertyEditorVisibilityChanged = true; } void KexiMainWindow::Private::setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position, int id, KexiDockWidget *dockWidget, bool visible) { KMultiTabBar *mtbar = multiTabBars.value(position); if (!mtbar) { return; } if (!visible) { mtbar->removeTab(id); } else if (!mtbar->tab(id)) { mtbar->appendTab(koIcon("document-properties"), id, dockWidget->tabText); KMultiTabBarTab *tab = mtbar->tab(id); QObject::connect(tab, SIGNAL(clicked(int)), wnd, SLOT(slotMultiTabBarTabClicked(int)), Qt::UniqueConnection); } } void KexiMainWindow::Private::setPropertyEditorTabBarVisible(bool visible) { setTabBarVisible(KMultiTabBar::Right, PROPERTY_EDITOR_TABBAR_ID, propEditorDockWidget, visible); } QObject *KexiMainWindow::Private::openedCustomObjectsForItem(KexiPart::Item* item, const char* name) { if (!item || !name) { qWarning() << "!item || !name"; return 0; } QByteArray key(QByteArray::number(item->identifier()) + name); return m_openedCustomObjectsForItem.value(key); } void KexiMainWindow::Private::addOpenedCustomObjectForItem(KexiPart::Item* item, QObject* object, const char* name) { QByteArray key(QByteArray::number(item->identifier()) + name); m_openedCustomObjectsForItem.insert(key, object); } KexiFindDialog *KexiMainWindow::Private::findDialog() { if (!m_findDialog) { m_findDialog = new KexiFindDialog(wnd); m_findDialog->setActions(action_edit_findnext, action_edit_findprev, action_edit_replace, action_edit_replace_all); } return m_findDialog; } void KexiMainWindow::Private::updateFindDialogContents(bool createIfDoesNotExist) { if (!wnd->currentWindow()) return; if (!createIfDoesNotExist && (!m_findDialog || !m_findDialog->isVisible())) return; KexiSearchAndReplaceViewInterface* iface = currentViewSupportingSearchAndReplaceInterface(); if (!iface) { if (m_findDialog) { m_findDialog->setButtonsEnabled(false); m_findDialog->setLookInColumnList(QStringList(), QStringList()); } return; } //! @todo use ->caption() here, depending on global settings related to displaying captions findDialog()->setObjectNameForCaption(wnd->currentWindow()->partItem()->name()); QStringList columnNames; QStringList columnCaptions; QString currentColumnName; // for 'look in' if (!iface->setupFindAndReplace(columnNames, columnCaptions, currentColumnName)) { m_findDialog->setButtonsEnabled(false); m_findDialog->setLookInColumnList(QStringList(), QStringList()); return; } m_findDialog->setButtonsEnabled(true); const QString prevColumnName(m_findDialog->currentLookInColumnName()); m_findDialog->setLookInColumnList(columnNames, columnCaptions); m_findDialog->setCurrentLookInColumnName(prevColumnName); } KexiView *KexiMainWindow::Private::currentViewSupportingAction(const char* actionName) const { if (!wnd->currentWindow()) return 0; KexiView *view = wnd->currentWindow()->selectedView(); if (!view) return 0; QAction *action = view->sharedAction(actionName); if (!action || !action->isEnabled()) return 0; return view; } KexiSearchAndReplaceViewInterface* KexiMainWindow::Private::currentViewSupportingSearchAndReplaceInterface() const { if (!wnd->currentWindow()) return 0; KexiView *view = wnd->currentWindow()->selectedView(); if (!view) return 0; return dynamic_cast(view); } tristate KexiMainWindow::Private::showProjectMigrationWizard( const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata) { //pass arguments QMap args; args.insert("mimeType", mimeType); args.insert("databaseName", databaseName); if (cdata) { //pass KDbConnectionData serialized as a string... QString str; KDbUtils::serializeMap(cdata->toMap(), &str); args.insert("connectionData", str); } QDialog *dlg = KexiInternalPart::createModalDialogInstance("org.kexi-project.migration", "migration", wnd, 0, &args); if (!dlg) return false; //error msg has been shown by KexiInternalPart const int result = dlg->exec(); delete dlg; if (result != QDialog::Accepted) return cancelled; //open imported project in a new Kexi instance QString destinationDatabaseName(args["destinationDatabaseName"]); QString fileName, destinationConnectionShortcut; if (!destinationDatabaseName.isEmpty()) { if (args.contains("destinationConnectionShortcut")) { // server-based destinationConnectionShortcut = args["destinationConnectionShortcut"]; } else { // file-based fileName = destinationDatabaseName; destinationDatabaseName.clear(); } tristate res = wnd->openProject(fileName, destinationConnectionShortcut, destinationDatabaseName); wnd->raise(); return res; } return true; } #ifndef KEXI_NO_PENDING_DIALOGS void KexiMainWindow::Private::executeActionWhenPendingJobsAreFinished() { ActionToExecuteWhenPendingJobsAreFinished a = actionToExecuteWhenPendingJobsAreFinished; actionToExecuteWhenPendingJobsAreFinished = NoAction; switch (a) { case QuitAction: qApp->quit(); break; case CloseProjectAction: wnd->closeProject(); break; default:; } } KexiWindow *KexiMainWindow::Private::openedWindowFor(const KexiPart::Item* item, PendingJobType &pendingType) { return openedWindowFor(item->identifier(), pendingType); } KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier, PendingJobType &pendingType) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); QHash::ConstIterator it = pendingWindows.find(identifier); if (it == pendingWindows.end()) pendingType = NoJob; else pendingType = it.value(); if (pendingType == WindowOpeningJob) { return 0; } return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0; } void KexiMainWindow::Private::addItemToPendingWindows(const KexiPart::Item* item, PendingJobType jobType) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); pendingWindows.insert(item->identifier(), jobType); } bool KexiMainWindow::Private::pendingWindowsExist() { if (pendingWindows.begin() != pendingWindows.end()) qDebug() << pendingWindows.constBegin().key() << " " << (int)pendingWindows.constBegin().value(); //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return !pendingWindows.isEmpty(); } void KexiMainWindow::Private::removePendingWindow(int identifier) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); pendingWindows.remove(identifier); } #else // KEXI_NO_PENDING_DIALOGS KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0; } #endif diff --git a/src/main/KexiMainWindow_p.h b/src/main/KexiMainWindow_p.h index f4006abd6..169b90c76 100644 --- a/src/main/KexiMainWindow_p.h +++ b/src/main/KexiMainWindow_p.h @@ -1,700 +1,704 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2003-2016 Jarosław Staniek + Copyright (C) 2003-2018 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KEXIMAINWINDOW_P_H #define KEXIMAINWINDOW_P_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KexiMainWindow.h" #include "KexiSearchLineEdit.h" #include "KexiUserFeedbackAgent.h" #include "KexiMenuWidget.h" #include "kexifinddialog.h" #include "KexiStartup.h" #include #include #include #include #include #include #include #define KEXI_NO_PROCESS_EVENTS #ifdef KEXI_NO_PROCESS_EVENTS # define KEXI_NO_PENDING_DIALOGS #endif #define PROJECT_NAVIGATOR_TABBAR_ID 0 #define PROPERTY_EDITOR_TABBAR_ID 1 #define KEXITABBEDTOOLBAR_SPACER_TAB_INDEX 1 class QPainter; class KexiProjectNavigator; //! @short Main application's tabbed toolbar class KexiTabbedToolBar : public QTabWidget { Q_OBJECT public: explicit KexiTabbedToolBar(QWidget *parent); virtual ~KexiTabbedToolBar(); KToolBar *createWidgetToolBar() const; KToolBar *toolBar(const QString& name) const; void appendWidgetToToolbar(const QString& name, QWidget* widget); void setWidgetVisibleInToolbar(QWidget* widget, bool visible); //! @todo replace with the final Actions API void addAction(const QString& toolBarName, QAction *action); bool mainMenuVisible() const; QRect tabRect(int index) const; KHelpMenu *helpMenu() const; void addSearchableModel(KexiSearchableModel *model); void removeSearchableModel(KexiSearchableModel *model); KToolBar *createToolBar(const char *name, const QString& caption); void setCurrentTab(const QString& name); //! Sets current tab to @a index, counting from first visible (non-Kexi) tab. //! In non-user mode, the first visible tab is "create" tab. void setCurrentTab(int index); void hideTab(const QString& name); void showTab(const QString& name); bool isTabVisible(const QString& name) const; bool isRolledUp(); public Q_SLOTS: void setMainMenuContent(QWidget *w); void selectMainMenuItem(const char *actionName); void showMainMenu(const char* actionName = 0); void hideMainMenu(); void toggleMainMenu(); void activateSearchLineEdit(); void toggleRollDown(); protected: virtual void mouseMoveEvent(QMouseEvent* event); virtual void leaveEvent(QEvent* event); virtual bool eventFilter(QObject* watched, QEvent* event); protected Q_SLOTS: void slotCurrentChanged(int index); void slotDelayedTabRaise(); void slotSettingsChanged(int category); //! Used for delayed loading of the "create" toolbar. Called only once. void setupCreateWidgetToolbar(); void slotTabDoubleClicked(int index); void tabBarAnimationFinished(); private: void addAction(KToolBar *tbar, const char* actionName); void addSeparatorAndAction(KToolBar *tbar, const char* actionName); class Private; Private * const d; }; //! @internal window container created to speedup opening new tabs class KexiWindowContainer : public QWidget { Q_OBJECT public: explicit KexiWindowContainer(QWidget* parent); virtual ~KexiWindowContainer(); void setWindow(KexiWindow* w); QPointer window; private: QVBoxLayout *lyr; }; class EmptyMenuContentWidget : public QWidget { Q_OBJECT public: explicit EmptyMenuContentWidget(QWidget* parent = 0); void alterBackground(); virtual void changeEvent(QEvent *e); }; //! @todo KEXI3 is KexiMenuWidgetStyle needed? #if 0 //! A style proxy for KexiMenuWidget class KexiMenuWidgetStyle : public KexiUtils::StyleProxy { public: explicit KexiMenuWidgetStyle(QStyle *style, QObject *parent = 0); virtual ~KexiMenuWidgetStyle(); virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; }; #endif //! Main menu class KexiMainMenu : public QWidget { Q_OBJECT public: explicit KexiMainMenu(KexiTabbedToolBar *toolBar, QWidget* parent = 0); ~KexiMainMenu(); virtual bool eventFilter(QObject * watched, QEvent* event); void setContent(QWidget *contentWidget); const QWidget *contentWidget() const; void setPersistentlySelectedAction(KexiMenuWidgetAction* action, bool set); /* void setActiveAction(QAction* action = 0);*/ void selectFirstItem(); tristate showProjectMigrationWizard( const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata); Q_SIGNALS: void contentAreaPressed(); void hideContentsRequested(); protected Q_SLOTS: //void contentWidgetDestroyed(); protected: virtual void showEvent(QShowEvent * event); private: QPointer m_menuWidget; KexiTabbedToolBar* m_toolBar; bool m_initialized; EmptyMenuContentWidget *m_content; QStackedLayout *m_contentLayout = nullptr; QPointer m_contentWidget; QVBoxLayout* m_mainContentLayout = nullptr; QPointer m_persistentlySelectedAction; bool m_selectFirstItem; }; class KexiTabbedToolBarTabBar; //! @internal class Q_DECL_HIDDEN KexiTabbedToolBar::Private : public QObject { Q_OBJECT public: explicit Private(KexiTabbedToolBar *t); KToolBar *createToolBar(const char *name, const QString& caption); int tabIndex; public Q_SLOTS: void showMainMenu(const char* actionName = 0); void hideMainMenu(); void hideContentsOrMainMenu(); void toggleMainMenu(); void updateMainMenuGeometry(); + //! Initializes global search line edit. If it is enabled, it's created, if disabled, it's deleted. + void initSearchLineEdit(); + public: KexiTabbedToolBarTabBar *customTabBar; QPointer mainMenu; KexiTabbedToolBar *q; KActionCollection *ac; int createId; KToolBar *createWidgetToolBar; + QHBoxLayout *helpLayer; #ifdef KEXI_AUTORISE_TABBED_TOOLBAR //! Used for delayed tab raising int tabToRaise; //! Used for delayed tab raising QTimer tabRaiseTimer; #endif //! Toolbars for name QHash toolbarsForName; QHash toolbarsIndexForName; QHash toolbarsCaptionForName; QVector toolbarsVisibleForIndex; QHash extraActions; bool rolledUp; QPropertyAnimation tabBarAnimation; QGraphicsOpacityEffect tabBarOpacityEffect; int rolledUpIndex; KHelpMenu *helpMenu; - KexiSearchLineEdit *searchLineEdit; + KexiSearchLineEdit *searchLineEdit = nullptr; void setCurrentTab(const QString& name); void hideTab(const QString& name); void showTab(const QString& name); bool isTabVisible(const QString& name) const; #ifndef NDEBUG void debugToolbars() const; #endif int lowestIndex; }; class KexiTabbedToolBarStyle; //! Tab bar reimplementation for KexiTabbedToolBar. /*! The main its purpose is to alter the width of "Kexi" tab. */ class KexiTabbedToolBarTabBar : public QTabBar { Q_OBJECT public: explicit KexiTabbedToolBarTabBar(QWidget *parent = 0); virtual QSize originalTabSizeHint(int index) const; virtual QSize tabSizeHint(int index) const; KexiTabbedToolBarStyle* customStyle; }; //! Style proxy for KexiTabbedToolBar, to get the "Kexi" tab style right. class KexiTabbedToolBarStyle : public QProxyStyle { Q_OBJECT public: explicit KexiTabbedToolBarStyle(const QString &baseStyleName); virtual ~KexiTabbedToolBarStyle(); virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; virtual void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; virtual int pixelMetric(PixelMetric metric, const QStyleOption* option = 0, const QWidget* widget = 0) const; }; //! Style proxy for KexiTabbedToolBar, to fix the hardcoded margins (e.g. for Breeze). class KexiDockWidgetStyle : public QProxyStyle { Q_OBJECT public: explicit KexiDockWidgetStyle(const QString &baseStyleName); virtual ~KexiDockWidgetStyle(); using QProxyStyle::polish; void polish(QWidget* widget) Q_DECL_OVERRIDE; }; class KexiMainWidget; //! @internal tab widget acting as central widget for KexiMainWindow class KexiMainWindowTabWidget : public QTabWidget { Q_OBJECT public: KexiMainWindowTabWidget(QWidget *parent, KexiMainWidget *mainWidget); virtual ~KexiMainWindowTabWidget(); public Q_SLOTS: void closeTab(); tristate closeAllTabs(); protected: //! Shows context menu for tab at @a index at point @a point. //! If @a index is -1, context menu for empty area is requested. void showContextMenuForTab(int index, const QPoint& point); //! Reimplemented to hide frame when no tabs are displayed virtual void paintEvent(QPaintEvent * event); virtual void mousePressEvent(QMouseEvent *event); KexiMainWidget *m_mainWidget; QAction *m_closeAction; QAction *m_closeAllTabsAction; private: int m_tabIndex; void setTabIndexFromContextMenu(int clickedIndex); }; //! @short A widget being main part of KexiMainWindow class KexiMainWidget : public KMainWindow { Q_OBJECT public: KexiMainWidget(); virtual ~KexiMainWidget(); void setParent(KexiMainWindow* mainWindow); KexiMainWindowTabWidget* tabWidget() const; protected: virtual bool queryClose(); protected Q_SLOTS: void slotCurrentTabIndexChanged(int index); Q_SIGNALS: void currentTabIndexChanged(int index); private: void setupCentralWidget(); KexiMainWindowTabWidget* m_tabWidget; KexiMainWindow *m_mainWindow; QPointer m_previouslyActiveWindow; friend class KexiMainWindow; friend class KexiMainWindowTabWidget; }; //------------------------------------------ //! @internal Dock widget with floating disabled but still collapsible class KexiDockWidget : public QDockWidget { Q_OBJECT public: KexiDockWidget(const QString &tabText, QWidget *parent); virtual ~KexiDockWidget(); virtual void setSizeHint(const QSize& hint); virtual QSize sizeHint() const; const QString tabText; //!< for tab bar tabs protected: virtual void paintEvent(QPaintEvent *pe); private: class Private; Private * const d; }; //------------------------------------------ //! @internal safer dictionary typedef QMap< int, KexiWindow* > KexiWindowDict; //! @internal class Q_DECL_HIDDEN KexiMainWindow::Private { public: explicit Private(KexiMainWindow* w); ~Private(); #ifndef KEXI_NO_PENDING_DIALOGS //! Job type. Currently used for marking items as being opened or closed. enum PendingJobType { NoJob = 0, WindowOpeningJob, WindowClosingJob }; KexiWindow *openedWindowFor(const KexiPart::Item* item, PendingJobType &pendingType); KexiWindow *openedWindowFor(int identifier, PendingJobType &pendingType); void addItemToPendingWindows(const KexiPart::Item* item, PendingJobType jobType); bool pendingWindowsExist(); void removePendingWindow(int identifier); #else KexiWindow *openedWindowFor(int identifier); #endif void insertWindow(KexiWindow *window); bool windowContainerExistsFor(int identifier) const; void setWindowContainerExistsFor(int identifier, bool set); void updateWindowId(KexiWindow *window, int oldItemID); void removeWindow(int identifier); int openedWindowsCount(); //! Used in KexiMainWindowe::closeProject() void clearWindows(); void showStartProcessMsg(const QStringList& args); //! Updates Property Editor Pane's visibility for the current window and the @a viewMode view mode. /*! @a info can be provided to hadle cases when current window is not yet defined (in openObject()). */ void updatePropEditorVisibility(Kexi::ViewMode viewMode, KexiPart::Info *info = 0); void setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position, int id, KexiDockWidget *dockWidget, bool visible); void setPropertyEditorTabBarVisible(bool visible); QObject *openedCustomObjectsForItem(KexiPart::Item* item, const char* name); void addOpenedCustomObjectForItem(KexiPart::Item* item, QObject* object, const char* name); KexiFindDialog *findDialog(); /*! Updates the find/replace dialog depending on the active view. Nothing is performed if the dialog is not instantiated yet or is invisible. */ void updateFindDialogContents(bool createIfDoesNotExist = false); //! \return the current view if it supports \a actionName, otherwise returns 0. KexiView *currentViewSupportingAction(const char* actionName) const; //! \return the current view if it supports KexiSearchAndReplaceViewInterface. KexiSearchAndReplaceViewInterface* currentViewSupportingSearchAndReplaceInterface() const; tristate showProjectMigrationWizard( const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata); KexiMainWindow *wnd; KexiMainWidget *mainWidget; KActionCollection *actionCollection; KHelpMenu *helpMenu; KexiProject *prj; KSharedConfig::Ptr config; #ifdef KEXI_SHOW_CONTEXT_HELP KexiContextHelp *ctxHelp; #endif KexiProjectNavigator *navigator; KexiTabbedToolBar *tabbedToolBar; QMap tabsToActivateOnShow; KexiDockWidget *navDockWidget; QTabWidget *propEditorTabWidget; KexiDockWidget *propEditorDockWidget; QPointer propEditorDockableWidget; //! poits to kexi part which has been previously used to setup proppanel's tabs using //! KexiPart::setupCustomPropertyPanelTabs(), in updateCustomPropertyPanelTabs(). QPointer partForPreviouslySetupPropertyPanelTabs; QMap recentlySelectedPropertyPanelPages; QPointer propEditor; QPointer propertySet; KexiNameDialog *nameDialog; QTimer timer; //!< helper timer QString appCaptionPrefix; // focus_before_popup; //! Set to true only in destructor, used by closeWindow() to know if //! user can cancel window closing. If true user even doesn't see any messages //! before closing a window. This is for extremely sanity... and shouldn't be even needed. bool forceWindowClosing; //! Indicates that we're inside closeWindow() method - to avoid inf. recursion //! on window removing bool insideCloseWindow; #ifndef KEXI_NO_PENDING_DIALOGS //! Used in executeActionWhenPendingJobsAreFinished(). enum ActionToExecuteWhenPendingJobsAreFinished { NoAction, QuitAction, CloseProjectAction }; ActionToExecuteWhenPendingJobsAreFinished actionToExecuteWhenPendingJobsAreFinished; void executeActionWhenPendingJobsAreFinished(); #endif //! Used for delayed windows closing for 'close all' QList windowsToClose; #ifdef KEXI_QUICK_PRINTING_SUPPORT //! Opened page setup dialogs, used by printOrPrintPreviewForItem(). QHash pageSetupWindows; /*! A map from Kexi dialog to "print setup" part item's ID of the data item used by closeWindow() to find an ID of the data item, so the entry can be removed from pageSetupWindows dictionary. */ QMap pageSetupWindowItemID2dataItemID_map; #endif //! Indicates if project is started in User Mode bool userMode; //! Indicates if project navigator should be visible bool isProjectNavigatorVisible; //! Indicates if the main menu should be visible bool isMainMenuVisible; //! Set in restoreSettings() and used in initNavigator() //! to customize navigator visibility on startup bool forceShowProjectNavigatorOnCreation; bool forceHideProjectNavigatorOnCreation; bool navWasVisibleBeforeProjectClosing; bool saveSettingsForShowProjectNavigator; //! Used by openedCustomObjectsForItem() and addOpenedCustomObjectForItem() QHash m_openedCustomObjectsForItem; int propEditorDockSeparatorPos, navDockSeparatorPos; bool wasAutoOpen; bool windowExistedBeforeCloseProject; QMap multiTabBars; bool propertyEditorCollapsed; bool enable_slotPropertyEditorVisibilityChanged; KexiUserFeedbackAgent userFeedback; KexiMigrateManagerInterface* migrateManager; private: //! @todo move to KexiProject KexiWindowDict windows; //! A set of item identifiers for whose there are KexiWindowContainer instances already. //! This lets to verify that KexiWindow is about to be constructed and opened so multiple //! opening can be avoided. QSet windowContainers; #ifndef KEXI_NO_PROCESS_EVENTS QHash pendingWindows; //!< part item identifiers for windows whoose opening has been started //! @todo QMutex dialogsMutex; //!< used for locking windows and pendingWindows dicts #endif KexiFindDialog *m_findDialog; }; //------------------------------------------ //! Action shortcut used by KexiMainWindow::setupMainMenuActionShortcut(QAction *) //! Activates action only if enabled. class KexiMainMenuActionShortcut : public QShortcut { Q_OBJECT public: KexiMainMenuActionShortcut(const QKeySequence& key, QAction *action, QWidget *parent); virtual ~KexiMainMenuActionShortcut(); protected Q_SLOTS: //! Triggers associated action only when this action is enabled void slotActivated(); private: QPointer m_action; }; #endif