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

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_p.h"
0022 #include "KexiObjectViewWidget.h"
0023 
0024 #include <KToggleAction>
0025 
0026 #include <QPainter>
0027 #include <QDebug>
0028 #include <QSplitter>
0029 
0030 #include <KConfigGroup>
0031 
0032 #include <KDbUtils>
0033 
0034 #include <KexiPropertyPaneWidget.h>
0035 #include <kexiutils/SmallToolButton.h>
0036 #include <kexiutils/KexiTester.h>
0037 #include <kexiutils/KexiFadeWidgetEffect.h>
0038 #include <KexiIcon.h>
0039 #include <KexiStyle.h>
0040 #include <KexiProjectNavigator.h>
0041 #include <core/kexipartmanager.h>
0042 #include <KexiAssistantWidget.h>
0043 
0044 EmptyMenuContentWidget::EmptyMenuContentWidget(QWidget* parent)
0045  : QWidget(parent)
0046 {
0047     setAutoFillBackground(true);
0048     alterBackground();
0049 }
0050 
0051 void EmptyMenuContentWidget::alterBackground()
0052 {
0053     QPalette pal(palette());
0054     QColor bg(pal.color(QPalette::Window));
0055     bg.setAlpha(200);
0056     pal.setColor(QPalette::Window, bg);
0057     setPalette(pal);
0058 }
0059 
0060 void EmptyMenuContentWidget::changeEvent(QEvent *e)
0061 {
0062     if (e->type() == QEvent::PaletteChange) {
0063         alterBackground();
0064     }
0065     QWidget::changeEvent(e);
0066 }
0067 
0068 //! @todo KEXI3 is KexiMenuWidgetStyle needed?
0069 #if 0
0070 KexiMenuWidgetStyle::KexiMenuWidgetStyle(QStyle *style, QObject *parent)
0071     : KexiUtils::StyleProxy(style, parent)
0072 {
0073 }
0074 
0075 KexiMenuWidgetStyle::~KexiMenuWidgetStyle()
0076 {
0077 }
0078 
0079 void KexiMenuWidgetStyle::drawControl(ControlElement element, const QStyleOption *option,
0080                          QPainter *painter, const QWidget *widget = 0) const
0081 {
0082     if (element == QStyle::CE_MenuItem
0083         && (option->state & QStyle::State_Selected) && (option->state & QStyle::State_Enabled)
0084         && parentStyle()->objectName() == QLatin1String("oxygen"))
0085     {
0086         // Ugly fix for visual glitch of oxygen; no chance for improvement since
0087         // we've forked QMenu and oxygen checks for qobject_cast<QMenu*> directly.
0088         QColor c(option->palette.color(QPalette::Window));
0089         int h, s, v, a;
0090         c.getHsv(&h, &s, &v, &a);
0091         // Why 0.91208791? I knew you're curious. There are some algorithms in Oxygen
0092         // to make color a bit lighter. They are not in the public API nor they are simple.
0093         // So the number was computed by me to find the proper value for the color
0094         // (the accuracy is quite OK).
0095         // It's also related to the fact that Oxygen's menus have gradient background.
0096         // A lot of computation happens under the mask...
0097         c.setHsv(h, s, v * 0.91208791, a);
0098         painter->fillRect(option->rect.x() + 6, option->rect.y() + 6,
0099                           option->rect.width() - 12, option->rect.height() - 12,
0100                           c);
0101     }
0102     KexiUtils::StyleProxy::drawControl(element, option, painter, widget);
0103 }
0104 #endif
0105 
0106 KexiMainMenu::KexiMainMenu(KexiTabbedToolBar *toolBar, QWidget* parent)
0107  : QWidget(parent),
0108     m_toolBar(toolBar), m_initialized(false)
0109 {
0110     m_content = 0;
0111     m_selectFirstItem = false;
0112 }
0113 
0114 KexiMainMenu::~KexiMainMenu()
0115 {
0116     delete (QWidget*)m_contentWidget;
0117 }
0118 
0119 bool KexiMainMenu::eventFilter(QObject * watched, QEvent* event)
0120 {
0121     if (event->type() == QEvent::MouseButtonPress && watched == m_content && !m_contentWidget) {
0122         emit contentAreaPressed();
0123     }
0124     else if (event->type() == QEvent::KeyPress) {
0125         QKeyEvent* ke = static_cast<QKeyEvent*>(event);
0126         if ((ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) {
0127             emit hideContentsRequested();
0128             return true;
0129         }
0130     }
0131     return QWidget::eventFilter(watched, event);
0132 }
0133 
0134 void KexiMainMenu::setContent(QWidget *contentWidget)
0135 {
0136     if (m_menuWidget && m_persistentlySelectedAction) {
0137         m_menuWidget->setPersistentlySelectedAction(
0138             m_persistentlySelectedAction,
0139             m_persistentlySelectedAction->persistentlySelected());
0140     }
0141     /*if (m_menuWidget->persistentlySelectedAction())
0142         qDebug() << "****" << m_menuWidget->persistentlySelectedAction()->objectName();*/
0143     KexiFadeWidgetEffect *fadeEffect = 0;
0144 
0145     if (m_contentWidget && contentWidget) {
0146         fadeEffect = new KexiFadeWidgetEffect(m_content);
0147     }
0148     if (m_contentWidget)
0149         m_contentWidget->deleteLater();
0150     m_contentWidget = contentWidget;
0151     if (m_contentWidget) {
0152         QPalette contentWidgetPalette(m_contentWidget->palette());
0153         contentWidgetPalette.setBrush(QPalette::Active, QPalette::Window, contentWidgetPalette.brush(QPalette::Active, QPalette::Base));
0154         contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::Window, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Base));
0155         contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Window, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base));
0156         contentWidgetPalette.setBrush(QPalette::Active, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Active, QPalette::Text));
0157         contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Text));
0158         contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Text));
0159         const QColor highlightDisabled(KexiUtils::blendedColors(
0160                                      contentWidgetPalette.color(QPalette::Active, QPalette::Highlight),
0161                                      contentWidgetPalette.color(QPalette::Disabled, QPalette::Window), 1, 2));
0162         contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlightDisabled);
0163         const QColor highlightedTextDisabled(KexiUtils::blendedColors(
0164                                      contentWidgetPalette.color(QPalette::Active, QPalette::HighlightedText),
0165                                      contentWidgetPalette.color(QPalette::Disabled, QPalette::WindowText), 1, 2));
0166         contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::HighlightedText, highlightedTextDisabled);
0167         m_contentWidget->setPalette(contentWidgetPalette);
0168         for(QAbstractScrollArea *area : m_contentWidget->findChildren<QAbstractScrollArea*>()) {
0169             QPalette pal(area->viewport()->palette());
0170             pal.setBrush(QPalette::Disabled, QPalette::Base, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base));
0171             area->viewport()->setPalette(pal);
0172         }
0173 
0174         m_contentWidget->setAutoFillBackground(true);
0175         m_contentWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
0176         m_contentWidget->setContentsMargins(0, 0, 0, 0);
0177         m_contentLayout->addWidget(m_contentWidget);
0178         m_contentLayout->setCurrentWidget(m_contentWidget);
0179         m_contentWidget->setFocus();
0180         m_contentWidget->installEventFilter(this);
0181         //connect(m_contentWidget, SIGNAL(destroyed()), this, SLOT(contentWidgetDestroyed()));
0182     }
0183     if (fadeEffect) {
0184         if (m_contentWidget)
0185             m_contentLayout->update();
0186 
0187         QTimer::singleShot(10, fadeEffect, SLOT(start()));
0188     }
0189 }
0190 
0191 const QWidget *KexiMainMenu::contentWidget() const
0192 {
0193     return m_contentWidget;
0194 }
0195 
0196 void KexiMainMenu::setPersistentlySelectedAction(KexiMenuWidgetAction* action, bool set)
0197 {
0198     m_persistentlySelectedAction = action;
0199     m_persistentlySelectedAction->setPersistentlySelected(set);
0200 }
0201 
0202 /*
0203 void KexiMainMenu::setActiveAction(QAction* action = 0)
0204 {
0205     if (!action && !m_menuWidget->actions().isEmpty()) {
0206         action = actions().first();
0207     }
0208     if (action) {
0209         m_menuWidget->setActiveAction(action);
0210     }
0211 }
0212 */
0213 
0214 void KexiMainMenu::selectFirstItem()
0215 {
0216     m_selectFirstItem = true;
0217 }
0218 
0219 void KexiMainMenu::showEvent(QShowEvent * event)
0220 {
0221     if (!m_initialized) {
0222         m_initialized = true;
0223         KActionCollection *ac = KexiMainWindowIface::global()->actionCollection();
0224         QHBoxLayout *hlyr = new QHBoxLayout(this);
0225 
0226         hlyr->setSpacing(0);
0227         hlyr->setMargin(0);
0228 
0229         m_menuWidget = new KexiMenuWidget;
0230 //! @todo KEXI3 is KexiMenuWidgetStyle needed?
0231 #if 0
0232         QString styleName(m_menuWidget->style()->objectName());
0233         if (KDE::version() < KDE_MAKE_VERSION(4, 8, 0) // a fix is apparently needed for glitch in KDE < 4.8
0234             && styleName == "oxygen")
0235         {
0236             KexiMenuWidgetStyle *customStyle = new KexiMenuWidgetStyle(m_menuWidget->style()->objectName(), this);
0237             m_menuWidget->setStyle(customStyle);
0238         }
0239 #endif
0240         m_menuWidget->installEventFilter(this);
0241         m_menuWidget->setFocusPolicy(Qt::StrongFocus);
0242         setFocusProxy(m_menuWidget);
0243         m_menuWidget->setFrame(false);
0244         m_menuWidget->setAutoFillBackground(true);
0245 
0246         m_menuWidget->addAction(ac->action("project_welcome"));
0247         m_menuWidget->addAction(ac->action("project_open"));
0248         m_menuWidget->addAction(ac->action("project_close"));
0249         m_menuWidget->addSeparator();
0250         m_menuWidget->addAction(ac->action("project_new"));
0251         m_menuWidget->addAction(ac->action("project_import_export_send"));
0252 #ifdef KEXI_SHOW_UNIMPLEMENTED
0253         m_menuWidget->addAction(ac->action("project_properties"));
0254         //! @todo project information
0255         m_menuWidget->addAction(ac->action("settings"));
0256 #endif
0257         m_menuWidget->addSeparator();
0258         m_menuWidget->addAction(ac->action("quit"));
0259         hlyr->addWidget(m_menuWidget);
0260 
0261         m_content = new EmptyMenuContentWidget;
0262         m_content->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
0263         m_content->installEventFilter(this);
0264         m_mainContentLayout = new QVBoxLayout;
0265         hlyr->addLayout(m_mainContentLayout);
0266         m_contentLayout = new QStackedLayout(m_content);
0267         m_contentLayout->setStackingMode(QStackedLayout::StackAll);
0268         m_contentLayout->setContentsMargins(0, 0, 0, 0);
0269         m_mainContentLayout->addWidget(m_content);
0270         hlyr->setStretchFactor(m_mainContentLayout, 1);
0271     }
0272     QWidget::showEvent(event);
0273     if (m_selectFirstItem && !m_menuWidget->actions().isEmpty()) {
0274         QAction* action = m_menuWidget->actions().first();
0275         m_menuWidget->setActiveAction(action);
0276         m_selectFirstItem = false;
0277     }
0278 }
0279 
0280 // ---
0281 
0282 KexiTabbedToolBar::Private::Private(KexiTabbedToolBar *t)
0283             : q(t), createWidgetToolBar(0)
0284 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
0285             , tabToRaise(-1)
0286 #endif
0287             , rolledUp(false)
0288 {
0289 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
0290     tabRaiseTimer.setSingleShot(true);
0291     tabRaiseTimer.setInterval(300);
0292 #endif
0293     tabBarAnimation.setPropertyName("opacity");
0294     tabBarAnimation.setDuration(500);
0295     connect(&tabBarAnimation, SIGNAL(finished()), q, SLOT(tabBarAnimationFinished()));
0296     tabIndex = 0;
0297     lowestIndex = 2;
0298 }
0299 
0300 //! @return true if @a style name is specific regarding tab styling
0301 static bool isSpecificTabStyle(const QString &styleName)
0302 {
0303     return styleName == "oxygen" || styleName == "qtcurve" || styleName == "gtk+"
0304            || styleName == "gtk2";
0305 }
0306 
0307 KexiTabbedToolBarStyle::KexiTabbedToolBarStyle(const QString &baseStyleName)
0308   : QProxyStyle(baseStyleName)
0309 {
0310 }
0311 
0312 KexiTabbedToolBarStyle::~KexiTabbedToolBarStyle()
0313 {
0314 }
0315 
0316 void KexiTabbedToolBarStyle::drawControl(ControlElement element, const QStyleOption *option,
0317                                          QPainter *painter, const QWidget *widget) const
0318 {
0319     const QString styleName(baseStyle()->objectName());
0320     qreal origOpacity = -1.0;
0321     if (element == CE_TabBarTab) {
0322         const QStyleOptionTab* opt
0323             = qstyleoption_cast<const QStyleOptionTab*>(option);
0324         const QTabBar* tabBar = qobject_cast<const QTabBar*>(widget);
0325         KexiTabbedToolBar* tbar = tabBar
0326             ? qobject_cast<KexiTabbedToolBar*>(tabBar->parentWidget()) : 0;
0327         if (opt && tbar) {
0328             const int index = tabBar->tabAt(opt->rect.center());
0329             if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX)
0330                 return;
0331             bool mouseOver = opt->state & QStyle::State_MouseOver;
0332             bool unselectedOrMenuVisible
0333                 = !(opt->state & State_Selected) || tbar->mainMenuVisible();
0334             if (unselectedOrMenuVisible) {
0335                 if (styleName == "bespin") {
0336                     unselectedOrMenuVisible = false;
0337                 }
0338             }
0339 
0340             QStyleOptionTab newOpt(*opt);
0341             const bool specificStyle = isSpecificTabStyle(styleName);
0342             newOpt.text = (specificStyle ? " " : "")
0343                     + tabBar->tabText(index)
0344                     + (specificStyle ? " " : "");
0345             if (!mouseOver
0346                 && unselectedOrMenuVisible
0347                 && index > 0)
0348             {
0349                 if (tbar->mainMenuVisible())
0350                     newOpt.state &= ~QStyle::State_HasFocus;
0351                 QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget);
0352                 return;
0353             }
0354             else if (index == 0) {
0355                 QBrush bg;
0356                 newOpt.state |= State_Selected;
0357                 if (tbar->mainMenuVisible()) {
0358                     bg = newOpt.palette.brush(QPalette::Active, QPalette::Highlight);
0359                     if (!specificStyle) {
0360                         newOpt.palette.setBrush(QPalette::WindowText,
0361                                                 newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText));
0362                         newOpt.palette.setBrush(QPalette::ButtonText,
0363                                                 newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText));
0364                     }
0365                 }
0366                 else {
0367                     if (styleName == "fusion") {
0368                         bg = newOpt.palette.brush(QPalette::Active, QPalette::Button);
0369                     } else {
0370                         bg = Qt::transparent;
0371                     }
0372                 }
0373                 QFont origFont(painter->font());
0374                 QFont f(origFont);
0375                 f.setBold(true);
0376                 painter->setFont(f);
0377                 newOpt.palette.setBrush(QPalette::Window, bg);
0378                 newOpt.palette.setBrush(QPalette::Button, // needed e.g. for Plastique style
0379                                         bg);
0380                 QProxyStyle::drawControl(element, &newOpt, painter, widget);
0381                 painter->setFont(origFont);
0382                 if (!mouseOver || tbar->mainMenuVisible() || styleName == "gtk+") {
0383                     return;
0384                 }
0385             }
0386             if (index > 0 || mouseOver) {
0387                 const QPalette::ColorGroup hbGroup =  (styleName == "oxygen")
0388                         ? QPalette::Active : QPalette::Inactive;
0389                 const QBrush hb(newOpt.palette.brush(hbGroup, QPalette::Highlight));
0390                 newOpt.palette.setBrush(QPalette::Window, hb);
0391                 newOpt.palette.setBrush(QPalette::Button, hb); // needed e.g. for Plastique style
0392                 if (mouseOver && (index != tbar->currentIndex() || tbar->mainMenuVisible())) {
0393                     // use lower opacity for diplaying hovered tabs
0394                     origOpacity = painter->opacity();
0395                     painter->setOpacity(styleName == "qtcurve" ? 0.2 : 0.3);
0396                     newOpt.state |= State_Selected;
0397                 }
0398                 else {
0399                     if (!specificStyle) {
0400                         newOpt.palette.setBrush(QPalette::WindowText,
0401                                                 newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText));
0402                         newOpt.palette.setBrush(QPalette::ButtonText,
0403                                                 newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText));
0404                     }
0405                 }
0406                 if (index == tbar->currentIndex() && styleName == "qtcurve") {
0407                     origOpacity = painter->opacity();
0408                     painter->setOpacity(0.5);
0409                 }
0410                 (newOpt.state |= State_Active) ^= State_Active;
0411                 QProxyStyle::drawControl(element, &newOpt, painter, widget);
0412                 if (origOpacity != -1.0) {
0413                     // restore opacity and draw labels using full this opacity
0414                     painter->setOpacity(origOpacity);
0415                     if (index > 0) {
0416                         QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget);
0417                     }
0418                 }
0419                 return;
0420             }
0421         }
0422     }
0423     else if (element == CE_ToolBar) {
0424         return;
0425     }
0426     QProxyStyle::drawControl(element, option, painter, widget);
0427 }
0428 
0429 void KexiTabbedToolBarStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
0430                                            QPainter *painter, const QWidget *widget) const
0431 {
0432     const QString styleName(baseStyle()->objectName());
0433     if (element == PE_FrameTabWidget) {
0434         return;
0435     }
0436     if (element == PE_FrameTabBarBase) {
0437         const QTabBar* tabBar = qobject_cast<const QTabBar*>(widget);
0438         KexiTabbedToolBar* tbar = tabBar
0439             ? qobject_cast<KexiTabbedToolBar*>(tabBar->parentWidget()) : 0;
0440         if (tbar && tbar->mainMenuVisible() && styleName != "bespin") {
0441             return;
0442         }
0443     }
0444     if (element == QStyle::PE_PanelToolBar || element == QStyle::PE_FrameMenu) {
0445         return;
0446     }
0447     QProxyStyle::drawPrimitive(element, option, painter, widget);
0448 }
0449 
0450 int KexiTabbedToolBarStyle::pixelMetric(PixelMetric metric, const QStyleOption* option,
0451                                         const QWidget* widget) const
0452 {
0453     if (metric == QStyle::PM_SmallIconSize)
0454         return KIconLoader::SizeMedium;
0455     return QProxyStyle::pixelMetric(metric, option, widget);
0456 }
0457 
0458 // ---
0459 
0460 KexiTabbedToolBarTabBar::KexiTabbedToolBarTabBar(QWidget *parent)
0461     : QTabBar(parent)
0462 {
0463     setObjectName("tabbar");
0464     customStyle = new KexiTabbedToolBarStyle(style()->objectName());
0465     customStyle->setParent(this);
0466     setStyle(customStyle);
0467     installEventFilter(parent);
0468     QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget();
0469     mainWindow->installEventFilter(parent);
0470     setAttribute(Qt::WA_Hover, true);
0471 }
0472 
0473 QSize KexiTabbedToolBarTabBar::originalTabSizeHint(int index) const
0474 {
0475     return QTabBar::tabSizeHint(index);
0476 }
0477 
0478 QSize KexiTabbedToolBarTabBar::tabSizeHint(int index) const
0479 {
0480     QSize s = QTabBar::tabSizeHint(index);
0481     QStyleOptionTab ot;
0482     ot.initFrom(this);
0483     QFont f(font());
0484     f.setBold(true);
0485     ot.text = (isSpecificTabStyle(customStyle->baseStyle()->objectName()) ? "  " : "") + tabText(index);
0486     ot.fontMetrics = QFontMetrics(f);
0487     int w = customStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, &ot, this);
0488     if (w <= 0) { // needed e.g. for oxygen
0489         w = fontMetrics().width("   ");
0490     }
0491     if (index == 0) {
0492         s.setWidth(QFontMetrics(f).width(ot.text) + w * 2);
0493         return s;
0494     }
0495     else if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) {
0496         // fix width of the spacer tab
0497         s.setWidth(w);
0498     }
0499     return s;
0500 }
0501 
0502 void KexiTabbedToolBar::Private::toggleMainMenu()
0503 {
0504     if (q->mainMenuVisible())
0505         hideMainMenu();
0506     else
0507         showMainMenu();
0508 }
0509 
0510 void KexiTabbedToolBar::Private::showMainMenu(const char* actionName)
0511 {
0512     QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget();
0513     if (!mainMenu) {
0514         mainMenu = new KexiMainMenu(q, mainWindow);
0515         connect(mainMenu, SIGNAL(contentAreaPressed()), this, SLOT(hideMainMenu()));
0516         connect(mainMenu, SIGNAL(hideContentsRequested()), this, SLOT(hideContentsOrMainMenu()));
0517     }
0518     updateMainMenuGeometry();
0519     if (actionName) {
0520         q->selectMainMenuItem(actionName);
0521     }
0522     else {
0523         mainMenu->selectFirstItem();
0524     }
0525     mainMenu->show();
0526     mainMenu->setFocus();
0527     q->update(); // tab bar could have a line that should be repainted
0528 }
0529 
0530 void KexiTabbedToolBar::Private::updateMainMenuGeometry()
0531 {
0532     if (!mainMenu)
0533         return;
0534     QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget();
0535     KexiTabbedToolBarTabBar *tabBar = static_cast<KexiTabbedToolBarTabBar*>(q->tabBar());
0536     QPoint pos = q->mapToGlobal(QPoint(0, tabBar->originalTabSizeHint(0).height() - 1));
0537 //     qDebug() << "1." << pos;
0538     pos = mainWindow->mapFromGlobal(pos);
0539 //     qDebug() << "2." << pos;
0540 //     qDebug() << "3." << q->pos();
0541 
0542     QStyleOptionTab ot;
0543     ot.initFrom(tabBar);
0544     int overlap = tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &ot, tabBar)
0545                   - tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseHeight, &ot, tabBar);
0546 //     qDebug() << "4. overlap=" << overlap;
0547 
0548     mainMenu->setGeometry(0, pos.y() - overlap /*- q->y()*/,
0549                           mainWindow->width(),
0550                           mainWindow->height() - pos.y() + overlap /*+ q->y()*/);
0551 }
0552 
0553 void KexiTabbedToolBar::Private::initSearchLineEdit()
0554 {
0555     //! @todo use KexiConfig
0556     KConfigGroup mainWindowGroup(KSharedConfig::openConfig()->group("MainWindow"));
0557     const bool enabled = mainWindowGroup.readEntry("GlobalSearchBoxEnabled", true);
0558     if (enabled && !searchLineEdit) {
0559         searchLineEdit = new KexiSearchLineEdit;
0560         kexiTester() << KexiTestObject(searchLineEdit, "globalSearch.lineEdit");
0561         searchLineEdit->installEventFilter(q);
0562         helpLayer->addWidget(searchLineEdit);
0563     } else if (!enabled && searchLineEdit) {
0564         helpLayer->removeWidget(searchLineEdit);
0565         delete searchLineEdit;
0566         searchLineEdit = nullptr;
0567     }
0568 }
0569 
0570 void KexiTabbedToolBar::activateSearchLineEdit()
0571 {
0572     if (!d->searchLineEdit) {
0573         return;
0574     }
0575     d->searchLineEdit->selectAll();
0576     d->searchLineEdit->setFocus();
0577 }
0578 
0579 void KexiTabbedToolBar::Private::hideMainMenu()
0580 {
0581     if (!mainMenu || !mainMenu->isVisible())
0582         return;
0583     mainMenu->hide();
0584     mainMenu->setContent(0);
0585     q->update();  // tab bar could have a line that should be repainted
0586 }
0587 
0588 void KexiTabbedToolBar::Private::hideContentsOrMainMenu()
0589 {
0590     if (!mainMenu || !mainMenu->isVisible())
0591         return;
0592     if (mainMenu->contentWidget()) {
0593         mainMenu->setContent(0);
0594     }
0595     else {
0596         hideMainMenu();
0597     }
0598 }
0599 
0600 KToolBar *KexiTabbedToolBar::Private::createToolBar(const char *name, const QString& caption)
0601 {
0602     KToolBar *tbar = new KToolBar(q, true /*main toolbar*/, false /*read config*/);
0603     tbar->setIconDimensions(22); //!< @todo make configurable or system-dependent?
0604     // needed e.g. for Windows style to remove the toolbar's frame
0605     tbar->setStyle(customTabBar->customStyle);
0606     toolbarsForName.insert(name, tbar);
0607     tbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
0608     tbar->setObjectName(name);
0609     toolbarsCaptionForName.insert(name, caption);
0610     tabIndex = q->addTab(tbar, caption);
0611     toolbarsVisibleForIndex.append(true);
0612     toolbarsIndexForName.insert(name, tabIndex);
0613     return tbar;
0614 }
0615 
0616 KexiTabbedToolBar::KexiTabbedToolBar(QWidget *parent)
0617         : QTabWidget(parent)
0618         , d(new Private(this))
0619 {
0620     d->customTabBar = new KexiTabbedToolBarTabBar(this);
0621     setTabBar(d->customTabBar);
0622     setStyle(d->customTabBar->customStyle);
0623 
0624     // from ktabwidget.cpp
0625     //! @todo QTabWidget::setTabBar() should be added with this code
0626     //! @todo KEXI3 Are these tabBar() connections useful to port?
0627 #if 0
0628     connect(tabBar(), SIGNAL(contextMenu(int,QPoint)), SLOT(contextMenu(int,QPoint&)));
0629     connect(tabBar(), SIGNAL(tabDoubleClicked(int)), SLOT(mouseDoubleClick(int)));
0630     connect(tabBar(), SIGNAL(newTabRequest()), this, SIGNAL(mouseDoubleClick())); // #185487
0631     connect(tabBar(), SIGNAL(mouseMiddleClick(int)), SLOT(mouseMiddleClick(int)));
0632     connect(tabBar(), SIGNAL(initiateDrag( int )), SLOT(initiateDrag( int )));
0633     connect(tabBar(), SIGNAL(testCanDecode(QDragMoveEvent*,bool*)), SIGNAL(testCanDecode(QDragMoveEvent*,bool*)));
0634     connect(tabBar(), SIGNAL(receivedDropEvent(int,QDropEvent*)), SLOT(receivedDropEvent(int,QDropEvent*)));
0635     connect(tabBar(), SIGNAL(moveTab(int,int)), SLOT(moveTab(int,int)));
0636     connect(tabBar(), SIGNAL(tabCloseRequested(int)), SLOT(closeRequest(int)));
0637 #endif
0638 
0639     setMouseTracking(true); // for mouseMoveEvent()
0640     setWhatsThis(xi18n("Task-oriented toolbar. Groups commands using tabs."));
0641 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
0642     connect(&d->tabRaiseTimer, SIGNAL(timeout()), this, SLOT(slotDelayedTabRaise()));
0643 #endif
0644     connect(tabBar(), SIGNAL(tabBarDoubleClicked(int)), this, SLOT(slotTabDoubleClicked(int)));
0645 
0646     d->ac = KexiMainWindowIface::global()->actionCollection();
0647     const bool userMode = KexiMainWindowIface::global()->userMode();
0648     KToolBar *tbar;
0649 
0650     slotSettingsChanged(0);//KGlobalSettings::FontChanged
0651     //! @todo KEXI3 port from KGlobalSettings::Private::_k_slotNotifyChange:
0652     //! connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(slotSettingsChanged(int)));
0653 
0654     // help area
0655     QWidget *helpWidget = new QWidget(this);
0656     helpWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
0657     d->helpLayer = new QHBoxLayout(helpWidget);
0658     d->helpLayer->setContentsMargins(0, 0, 0, 0);
0659     setCornerWidget(helpWidget, Qt::TopRightCorner);
0660     d->initSearchLineEdit();
0661 
0662     // needed e.g. for Windows style to remove the toolbar's frame
0663     QWidget *dummyWidgetForMainMenu = new QWidget(this);
0664     dummyWidgetForMainMenu->setObjectName("kexi");
0665     addTab(dummyWidgetForMainMenu, KAboutData::applicationData().displayName());
0666     d->toolbarsVisibleForIndex.append(true);
0667     addTab(new QWidget(this), QString()); // dummy for spacer
0668     d->toolbarsVisibleForIndex.append(true);
0669 
0670     if (!userMode) {
0671         d->createWidgetToolBar = d->createToolBar("create", xi18n("Create"));
0672     }
0673 
0674 //! @todo move to form plugin
0675     tbar = d->createToolBar("form", xi18n("Form Design"));
0676 
0677 //! @todo move to report plugin
0678     tbar = d->createToolBar("report", xi18n("Report Design"));
0679     Q_UNUSED(tbar)
0680 
0681     connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int)));
0682     setCurrentWidget(widget(KEXITABBEDTOOLBAR_SPACER_TAB_INDEX + 1)); // the default
0683     setFocusPolicy(Qt::NoFocus);
0684 }
0685 
0686 void KexiTabbedToolBar::Private::setCurrentTab(const QString& name)
0687 {
0688     q->setCurrentWidget(q->toolBar(name));
0689 }
0690 
0691 void KexiTabbedToolBar::Private::hideTab(const QString& name)
0692 {
0693     q->removeTab(q->indexOf(toolbarsForName.value(name)));
0694     toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = false;
0695 }
0696 
0697 bool KexiTabbedToolBar::Private::isTabVisible(const QString& name) const
0698 {
0699     return q->indexOf(toolbarsForName.value(name)) != -1
0700            && toolbarsVisibleForIndex[toolbarsIndexForName.value(name)];
0701 }
0702 
0703 #ifndef NDEBUG
0704 void KexiTabbedToolBar::Private::debugToolbars() const
0705 {
0706     qDebug() << "QHash<QString, KToolBar*> toolbarsForName:";
0707     for (QHash<QString, KToolBar*>::ConstIterator it(toolbarsForName.constBegin());
0708          it!=toolbarsForName.constEnd(); ++it)
0709     {
0710         qDebug() << it.key() << "->" << it.value();
0711     }
0712     qDebug() << "QHash<QString, int> toolbarsIndexForName:";
0713     for (QHash<QString, int>::ConstIterator it(toolbarsIndexForName.constBegin());
0714          it!=toolbarsIndexForName.constEnd(); ++it)
0715     {
0716         qDebug() << it.key() << "->" << it.value();
0717     }
0718     qDebug() << "QHash<QString, QString> toolbarsCaptionForName:";
0719     for (QHash<QString, QString>::ConstIterator it(toolbarsCaptionForName.constBegin());
0720          it!=toolbarsCaptionForName.constEnd(); ++it)
0721     {
0722         qDebug() << it.key() << "->" << it.value();
0723     }
0724     qDebug() << "QVector<bool> toolbarsVisibleForIndex:";
0725     for (int i = 0; i < toolbarsVisibleForIndex.size(); i++) {
0726         qDebug() << i << "->" << toolbarsVisibleForIndex[i];
0727     }
0728 }
0729 #endif
0730 
0731 void KexiTabbedToolBar::Private::showTab(const QString& name)
0732 {
0733 //    qDebug() << "name:" << name;
0734 //    qDebug() << "toolbarsForName.value(name):" << toolbarsForName.value(name);
0735 //    qDebug() << "toolbarsIndexForName.value(name):" << toolbarsIndexForName.value(name);
0736 //    qDebug() << "q->indexOf(toolbarsForName.value(name))" << q->indexOf(toolbarsForName.value(name));
0737 #ifndef NDEBUG
0738     //debugToolbars();
0739 #endif
0740     if (q->indexOf(toolbarsForName.value(name)) == -1) {
0741         int h = 0;
0742         // count h = invisible tabs before this
0743         for (int i = lowestIndex; i < toolbarsIndexForName.value(name); i++) {
0744             if (!toolbarsVisibleForIndex.at(i))
0745                 h++;
0746         }
0747         q->insertTab(toolbarsIndexForName.value(name) - h,
0748                      toolbarsForName.value(name), toolbarsCaptionForName.value(name));
0749         toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = true;
0750     }
0751 }
0752 
0753 // ---
0754 
0755 KexiTabbedToolBar::~KexiTabbedToolBar()
0756 {
0757     delete d;
0758 }
0759 
0760 bool KexiTabbedToolBar::mainMenuVisible() const
0761 {
0762     return d->mainMenu && d->mainMenu->isVisible();
0763 }
0764 
0765 QRect KexiTabbedToolBar::tabRect(int index) const
0766 {
0767     return tabBar()->tabRect(index);
0768 }
0769 
0770 void KexiTabbedToolBar::slotSettingsChanged(int category)
0771 {
0772     Q_UNUSED(category);
0773     //! @todo if (category == KGlobalSettings::FontChanged) {
0774         //! @todo KEXI3 KGlobalSettings::menuFont() not available (using QFontDatabase::systemFont(QFontDatabase::GeneralFont) for now)
0775         //!       https://community.kde.org/Frameworks/Porting_Notes#Global_Settings
0776         setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); // the toolbar acts like a menu
0777     //}
0778 }
0779 
0780 KToolBar* KexiTabbedToolBar::createWidgetToolBar() const
0781 {
0782     return d->createWidgetToolBar;
0783 }
0784 
0785 void KexiTabbedToolBar::mouseMoveEvent(QMouseEvent* event)
0786 {
0787 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
0788     QPoint p = event->pos();
0789     int tab = tabBar()->tabAt(p);
0790     if (d->tabToRaise != -1 && (tab == -1 || tab == currentIndex())) {
0791         d->tabRaiseTimer.stop();
0792         d->tabToRaise = -1;
0793     } else if (d->tabToRaise != tab) {
0794         d->tabRaiseTimer.start();
0795 
0796         d->tabToRaise = tab;
0797     }
0798 #endif
0799     QTabWidget::mouseMoveEvent(event);
0800 }
0801 
0802 void KexiTabbedToolBar::leaveEvent(QEvent* event)
0803 {
0804 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
0805     d->tabRaiseTimer.stop();
0806     d->tabToRaise = -1;
0807 #endif
0808     QTabWidget::leaveEvent(event);
0809 }
0810 
0811 bool KexiTabbedToolBar::eventFilter(QObject* watched, QEvent* event)
0812 {
0813     switch (event->type()) {
0814     case QEvent::MouseButtonPress: {
0815         QWidget *mainWin = KexiMainWindowIface::global()->thisWidget();
0816         // qDebug() << "MouseButtonPress: watched:" << watched << "window()->focusWidget():" << window()->focusWidget();
0817         if (d->searchLineEdit && watched == d->searchLineEdit) {
0818             activateSearchLineEdit(); // custom setFocus() for search box, so it's possible to focus
0819                                       // back on Escape key press
0820             return false;
0821         }
0822         else if (watched == tabBar()) {
0823             QMouseEvent* me = static_cast<QMouseEvent*>(event);
0824             QPoint p = me->pos();
0825             KexiTabbedToolBarTabBar *tb = static_cast<KexiTabbedToolBarTabBar*>(tabBar());
0826             int index = tb->tabAt(p);
0827             if (index == 0) {
0828                 d->toggleMainMenu();
0829                 return true;
0830             }
0831             d->hideMainMenu();
0832             if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) {
0833                 return true;
0834             }
0835         }
0836         else if (watched == mainWin && d->mainMenu) {
0837             QMouseEvent* me = static_cast<QMouseEvent*>(event);
0838             if (!QRect(d->mainMenu->mapToGlobal(QPoint(0,0)), d->mainMenu->size())
0839                     .contains(mainWin->mapToGlobal(me->pos())))
0840             {
0841                 // hide if clicked outside of the menu
0842                 d->hideMainMenu();
0843             }
0844         }
0845         }
0846         break;
0847     case QEvent::KeyPress: {
0848         QKeyEvent* ke = static_cast<QKeyEvent*>(event);
0849 //         qDebug() << "**********" << QString::number(ke->key(), 16)
0850 //                  << QKeySequence::mnemonic(tabText(0))[0];
0851         if (QKeySequence::mnemonic(tabText(0)) == QKeySequence(ke->key())) {
0852 //             qDebug() << "eat the &File accel";
0853             if (!d->mainMenu || !d->mainMenu->isVisible()) {
0854                 d->showMainMenu();
0855             }
0856             /*this could be unexpected:
0857             else if (d->mainMenu && d->mainMenu->isVisible()) {
0858                 d->hideMainMenu();
0859             }*/
0860             return true;
0861         }
0862         if (d->mainMenu && d->mainMenu->isVisible() && (ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) {
0863             d->hideContentsOrMainMenu();
0864             return true;
0865         }
0866         break;
0867     }
0868     case QEvent::Resize:
0869         if (watched == KexiMainWindowIface::global()->thisWidget()) {
0870             d->updateMainMenuGeometry();
0871         }
0872         break;
0873     case QEvent::Shortcut: {
0874         QShortcutEvent *se = static_cast<QShortcutEvent*>(event);
0875         if (watched == tabBar() && QKeySequence::mnemonic(tabText(0)) == se->key()) {
0876 //             qDebug() << "eat the &File accel";
0877             if (!d->mainMenu || !d->mainMenu->isVisible()) {
0878                 d->showMainMenu();
0879                 return true;
0880             }
0881         }
0882         break;
0883     }
0884     default:;
0885     }
0886     return QTabWidget::eventFilter(watched, event);
0887 }
0888 
0889 void KexiTabbedToolBar::slotCurrentChanged(int index)
0890 {
0891     if (index == indexOf(d->createWidgetToolBar) && index != -1) {
0892         if (d->createWidgetToolBar->actions().isEmpty()) {
0893             QTimer::singleShot(10, this, SLOT(setupCreateWidgetToolbar()));
0894         }
0895     }
0896     if (d->rolledUp) { // switching the tab rolls down
0897         slotTabDoubleClicked(index);
0898     }
0899     if (index == 0) { // main menu
0900         d->showMainMenu();
0901     }
0902     else {
0903         d->hideMainMenu();
0904     }
0905 }
0906 
0907 void KexiTabbedToolBar::slotTabDoubleClicked(int index)
0908 {
0909     if (index <= 0) {
0910         return; // main item does not count here
0911     }
0912     d->rolledUp = !d->rolledUp;
0913     d->tabBarAnimation.stop();
0914     QWidget *w = widget(index);
0915     if (!w) {
0916         return;
0917     }
0918     w->setGraphicsEffect(&d->tabBarOpacityEffect);
0919     if (d->rolledUp) {
0920         d->tabBarOpacityEffect.setOpacity(1.0);
0921         d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect);
0922         d->tabBarAnimation.setStartValue(1.0);
0923         d->tabBarAnimation.setEndValue(0.0);
0924         d->tabBarAnimation.start();
0925     }
0926     else { // roll down
0927         d->tabBarOpacityEffect.setOpacity(0.0);
0928         setMaximumHeight(QWIDGETSIZE_MAX);
0929         widget(d->rolledUpIndex)->show();
0930         widget(d->rolledUpIndex)->setMaximumHeight(QWIDGETSIZE_MAX);
0931         w->setMaximumHeight(QWIDGETSIZE_MAX);
0932         w->show();
0933         d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect);
0934         d->tabBarAnimation.setStartValue(0.0);
0935         d->tabBarAnimation.setEndValue(1.0);
0936         d->tabBarAnimation.start();
0937     }
0938 }
0939 
0940 void KexiTabbedToolBar::tabBarAnimationFinished()
0941 {
0942     if (d->rolledUp) {
0943         // hide and collapse the area
0944         widget(currentIndex())->hide();
0945         KexiTabbedToolBarTabBar *tb = static_cast<KexiTabbedToolBarTabBar*>(tabBar());
0946         setFixedHeight(tb->tabSizeHint(currentIndex()).height());
0947         widget(currentIndex())->setFixedHeight(0);
0948         d->rolledUpIndex = currentIndex();
0949     }
0950 }
0951 
0952 void KexiTabbedToolBar::setupCreateWidgetToolbar()
0953 {
0954     if (!d->createWidgetToolBar->actions().isEmpty())
0955         return;
0956 //! @todo separate core object types from custom....
0957     KexiPart::PartInfoList *plist = Kexi::partManager().infoList(); //this list is properly sorted
0958     if (plist) {
0959         foreach(KexiPart::Info *info, *plist) {
0960             QAction* a = info->newObjectAction();
0961             if (a) {
0962                 d->createWidgetToolBar->addAction(a);
0963             } else {
0964                 //! @todo err
0965             }
0966         }
0967     }
0968 }
0969 
0970 void KexiTabbedToolBar::slotDelayedTabRaise()
0971 {
0972 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
0973     QPoint p = mapFromGlobal(QCursor::pos()); // make sure cursor is still over the tab
0974     int tab = tabBar()->tabAt(p);
0975     if (tab != d->tabToRaise) {
0976         d->tabToRaise = -1;
0977     } else if (d->tabToRaise != -1) {
0978         setCurrentIndex(d->tabToRaise);
0979         d->tabToRaise = -1;
0980     }
0981 #endif
0982 }
0983 
0984 KToolBar *KexiTabbedToolBar::toolBar(const QString& name) const
0985 {
0986     return d->toolbarsForName[name];
0987 }
0988 
0989 void KexiTabbedToolBar::addAction(KToolBar *tbar, const char* actionName)
0990 {
0991     QAction *a = d->ac->action(actionName);
0992     if (a)
0993         tbar->addAction(a);
0994 }
0995 
0996 void KexiTabbedToolBar::addAction(const QString& toolBarName, QAction *action)
0997 {
0998     if (!action)
0999         return;
1000     KToolBar *tbar = d->toolbarsForName[toolBarName];
1001     if (!tbar)
1002         return;
1003     tbar->addAction(action);
1004 }
1005 
1006 void KexiTabbedToolBar::addSeparatorAndAction(KToolBar *tbar, const char* actionName)
1007 {
1008     QAction *a = d->ac->action(actionName);
1009     if (a) {
1010         tbar->addSeparator();
1011         tbar->addAction(a);
1012     }
1013 }
1014 
1015 void KexiTabbedToolBar::appendWidgetToToolbar(const QString& name, QWidget* widget)
1016 {
1017     KToolBar *tbar = d->toolbarsForName[name];
1018     if (!tbar) {
1019         return;
1020     }
1021     QAction *action = tbar->addWidget(widget);
1022     d->extraActions.insert(widget, action);
1023 }
1024 
1025 void KexiTabbedToolBar::setWidgetVisibleInToolbar(QWidget* widget, bool visible)
1026 {
1027     QAction *action = d->extraActions[widget];
1028     if (!action) {
1029         return;
1030     }
1031     action->setVisible(visible);
1032 }
1033 
1034 void KexiTabbedToolBar::showMainMenu(const char* actionName)
1035 {
1036     d->showMainMenu(actionName);
1037 }
1038 
1039 void KexiTabbedToolBar::hideMainMenu()
1040 {
1041     d->hideMainMenu();
1042 }
1043 
1044 void KexiTabbedToolBar::toggleMainMenu()
1045 {
1046     d->toggleMainMenu();
1047 }
1048 
1049 void KexiTabbedToolBar::setMainMenuContent(QWidget *w)
1050 {
1051     d->mainMenu->setContent(w);
1052 }
1053 
1054 const QWidget* KexiTabbedToolBar::mainMenuContent()
1055 {
1056     return d->mainMenu->contentWidget();
1057 }
1058 
1059 void KexiTabbedToolBar::selectMainMenuItem(const char *actionName)
1060 {
1061     if (actionName) {
1062         KActionCollection *ac = KexiMainWindowIface::global()->actionCollection();
1063         KexiMenuWidgetAction *a = qobject_cast<KexiMenuWidgetAction*>(ac->action(actionName));
1064         if (a) {
1065             d->mainMenu->setPersistentlySelectedAction(a, true);
1066         }
1067     }
1068 }
1069 
1070 void KexiTabbedToolBar::addSearchableModel(KexiSearchableModel *model)
1071 {
1072     if (!d->searchLineEdit) {
1073         return;
1074     }
1075     d->searchLineEdit->addSearchableModel(model);
1076 }
1077 
1078 void KexiTabbedToolBar::removeSearchableModel(KexiSearchableModel *model)
1079 {
1080     if (!d->searchLineEdit) {
1081         return;
1082     }
1083     d->searchLineEdit->removeSearchableModel(model);
1084 }
1085 
1086 KToolBar* KexiTabbedToolBar::createToolBar(const char* name, const QString& caption)
1087 {
1088     return d->createToolBar(name, caption);
1089 }
1090 
1091 void KexiTabbedToolBar::setCurrentTab(const QString& name)
1092 {
1093     //qDebug() << name;
1094     d->setCurrentTab(name);
1095 }
1096 
1097 void KexiTabbedToolBar::setCurrentTab(int index)
1098 {
1099     setCurrentIndex(d->lowestIndex + index);
1100 }
1101 
1102 void KexiTabbedToolBar::hideTab(const QString& name)
1103 {
1104     //qDebug() << name;
1105     d->hideTab(name);
1106 }
1107 
1108 void KexiTabbedToolBar::showTab(const QString& name)
1109 {
1110     //qDebug() << name;
1111     d->showTab(name);
1112 }
1113 
1114 bool KexiTabbedToolBar::isTabVisible(const QString& name) const
1115 {
1116     return d->isTabVisible(name);
1117 }
1118 
1119 bool KexiTabbedToolBar::isRolledUp()
1120 {
1121     return d->rolledUp;
1122 }
1123 
1124 void KexiTabbedToolBar::toggleRollDown()
1125 {
1126     slotTabDoubleClicked(-1);//use -1 just to rolldown/up the tabbar
1127 }
1128 
1129 //------------------------------------------
1130 
1131 KexiMainWindow::Private::Private(KexiMainWindow* w)
1132     : wnd(w)
1133 {
1134     objectViewWidget = 0;
1135     actionCollection = new KActionCollection(w);
1136     KexiProjectData *pdata = KexiStartupHandler::global()->projectData();
1137     userMode = KexiStartupHandler::global()->forcedUserMode() /* <-- simply forced the user mode */
1138                /* project has 'user mode' set as default and not 'design mode' override is found: */
1139                || (pdata && pdata->userMode() && !KexiStartupHandler::global()->forcedDesignMode());
1140     isProjectNavigatorVisible = KexiStartupHandler::global()->isProjectNavigatorVisible();
1141     isMainMenuVisible = KexiStartupHandler::global()->isMainMenuVisible();
1142     prj = 0;
1143     config = KSharedConfig::openConfig();
1144     nameDialog = 0;
1145     m_findDialog = 0;
1146     focus_before_popup = 0;
1147     action_show_nav = 0;
1148     action_show_propeditor = 0;
1149     action_activate_nav = 0;
1150     action_activate_propeditor = 0;
1151     forceWindowClosing = false;
1152     insideCloseWindow = false;
1153 #ifndef KEXI_NO_PENDING_DIALOGS
1154     actionToExecuteWhenPendingJobsAreFinished = NoAction;
1155 #endif
1156     propEditorDockSeparatorPos = -1;
1157     navDockSeparatorPos = -1;
1158     wasAutoOpen = false;
1159     windowExistedBeforeCloseProject = false;
1160 #ifndef KEXI_SHOW_UNIMPLEMENTED
1161     dummy_action = new KActionMenu(QString(), wnd);
1162 #endif
1163     forceShowProjectNavigatorOnCreation = false;
1164     forceHideProjectNavigatorOnCreation = false;
1165     navWasVisibleBeforeProjectClosing = false;
1166     saveSettingsForShowProjectNavigator = true;
1167     propertyEditorCollapsed = false;
1168     enable_slotPropertyEditorVisibilityChanged = true;
1169     migrateManager = 0;
1170 }
1171 
1172 KexiMainWindow::Private::~Private()
1173 {
1174     qDeleteAll(m_openedCustomObjectsForItem);
1175 }
1176 
1177 void KexiMainWindow::Private::insertWindow(KexiWindow *window)
1178 {
1179 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1180     windows.insert(window->id(), window);
1181 #ifndef KEXI_NO_PENDING_DIALOGS
1182     pendingWindows.remove(window->id());
1183 #endif
1184 }
1185 
1186 bool KexiMainWindow::Private::windowContainerExistsFor(int identifier) const
1187 {
1188     return windowContainers.contains(identifier);
1189 }
1190 
1191 void KexiMainWindow::Private::setWindowContainerExistsFor(int identifier, bool set)
1192 {
1193     if (set) {
1194         windowContainers.insert(identifier);
1195     }
1196     else {
1197         windowContainers.remove(identifier);
1198     }
1199 }
1200 
1201 void KexiMainWindow::Private::updateWindowId(KexiWindow *window, int oldItemID)
1202 {
1203 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1204     windows.remove(oldItemID);
1205 #ifndef KEXI_NO_PENDING_DIALOGS
1206     pendingWindows.remove(oldItemID);
1207 #endif
1208     windows.insert(window->id(), window);
1209 }
1210 
1211 void KexiMainWindow::Private::removeWindow(int identifier)
1212 {
1213 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1214     windows.remove(identifier);
1215 }
1216 
1217 int KexiMainWindow::Private::openedWindowsCount()
1218 {
1219 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1220     return windows.count();
1221 }
1222 
1223 //! Used in KexiMainWindowe::closeProject()
1224 void KexiMainWindow::Private::clearWindows()
1225 {
1226 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1227     windows.clear();
1228 #ifndef KEXI_NO_PENDING_DIALOGS
1229     pendingWindows.clear();
1230 #endif
1231 }
1232 
1233 void KexiMainWindow::Private::showStartProcessMsg(const QStringList& args)
1234 {
1235     wnd->showErrorMessage(xi18nc("@info", "Could not start <application>%1</application> application.",
1236                                  QApplication::applicationDisplayName()),
1237                           xi18nc("@info",
1238                                  "Command <command>%1</command> failed.", args.join(" ")));
1239 }
1240 
1241 void KexiMainWindow::Private::updatePropEditorVisibility(Kexi::ViewMode viewMode, KexiPart::Info *info)
1242 {
1243     if (!objectViewWidget || !objectViewWidget->propertyPane()) {
1244         return;
1245     }
1246     KexiWindow *currentWindow = wnd->currentWindow();
1247     if (!info && currentWindow) {
1248         info = currentWindow->part()->info();
1249     }
1250     const bool visible = (viewMode == Kexi::DesignViewMode)
1251         && ((currentWindow && currentWindow->propertySet()) || (info && info->isPropertyEditorAlwaysVisibleInDesignMode()));
1252     //qDebug() << "visible ==" << visible;
1253     enable_slotPropertyEditorVisibilityChanged = false;
1254     bool set;
1255     if (visible && propertyEditorCollapsed) { // used when we're switching back to a window with propeditor available but collapsed
1256         set = !visible;
1257     }
1258     else {
1259         set = visible;
1260     }
1261     objectViewWidget->propertyPane()->setVisible(set);
1262     action_show_propeditor->setChecked(set);
1263     action_show_propeditor->setEnabled(set);
1264     objectViewWidget->updateSidebarWidths();
1265     enable_slotPropertyEditorVisibilityChanged = true;
1266 }
1267 
1268 /*
1269 void KexiMainWindow::Private::setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position, int id,
1270                                                KexiDockWidget *dockWidget, bool visible)
1271 {
1272     KMultiTabBar *mtbar = multiTabBars.value(position);
1273     if (!mtbar) {
1274         return;
1275     }
1276     if (!visible) {
1277         mtbar->removeTab(id);
1278     }
1279     else if (!mtbar->tab(id)) {
1280         mtbar->appendTab(koIcon("document-properties"), id, dockWidget->tabText);
1281         KMultiTabBarTab *tab = mtbar->tab(id);
1282         QObject::connect(tab, SIGNAL(clicked(int)),
1283                          wnd, SLOT(slotMultiTabBarTabClicked(int)),
1284                          Qt::UniqueConnection);
1285     }
1286 }
1287 
1288 void KexiMainWindow::Private::setPropertyEditorTabBarVisible(bool visible)
1289 {
1290     setTabBarVisible(KMultiTabBar::Right, PROPERTY_EDITOR_TABBAR_ID,
1291                      objectViewWidget->propertyEditorTabWidget(), visible);
1292 }*/
1293 
1294 QObject *KexiMainWindow::Private::openedCustomObjectsForItem(KexiPart::Item* item, const char* name)
1295 {
1296     if (!item || !name) {
1297         qWarning() << "!item || !name";
1298         return 0;
1299     }
1300     QByteArray key(QByteArray::number(item->identifier()) + name);
1301     return m_openedCustomObjectsForItem.value(key);
1302 }
1303 
1304 void KexiMainWindow::Private::addOpenedCustomObjectForItem(KexiPart::Item* item, QObject* object, const char* name)
1305 {
1306     QByteArray key(QByteArray::number(item->identifier()) + name);
1307     m_openedCustomObjectsForItem.insert(key, object);
1308 }
1309 
1310 KexiFindDialog *KexiMainWindow::Private::findDialog()
1311 {
1312     if (!m_findDialog) {
1313         m_findDialog = new KexiFindDialog(wnd);
1314         m_findDialog->setActions(action_edit_findnext, action_edit_findprev,
1315                                  action_edit_replace, action_edit_replace_all);
1316     }
1317     return m_findDialog;
1318 }
1319 
1320 void KexiMainWindow::Private::updateFindDialogContents(bool createIfDoesNotExist)
1321 {
1322     if (!wnd->currentWindow())
1323         return;
1324     if (!createIfDoesNotExist && (!m_findDialog || !m_findDialog->isVisible()))
1325         return;
1326     KexiSearchAndReplaceViewInterface* iface = currentViewSupportingSearchAndReplaceInterface();
1327     if (!iface) {
1328         if (m_findDialog) {
1329             m_findDialog->setButtonsEnabled(false);
1330             m_findDialog->setLookInColumnList(QStringList(), QStringList());
1331         }
1332         return;
1333     }
1334 //! @todo use ->caption() here, depending on global settings related to displaying captions
1335     findDialog()->setObjectNameForCaption(wnd->currentWindow()->partItem()->name());
1336 
1337     QStringList columnNames;
1338     QStringList columnCaptions;
1339     QString currentColumnName; // for 'look in'
1340     if (!iface->setupFindAndReplace(columnNames, columnCaptions, currentColumnName)) {
1341         m_findDialog->setButtonsEnabled(false);
1342         m_findDialog->setLookInColumnList(QStringList(), QStringList());
1343         return;
1344     }
1345     m_findDialog->setButtonsEnabled(true);
1346     const QString prevColumnName(m_findDialog->currentLookInColumnName());
1347     m_findDialog->setLookInColumnList(columnNames, columnCaptions);
1348     m_findDialog->setCurrentLookInColumnName(prevColumnName);
1349 }
1350 
1351 KexiView *KexiMainWindow::Private::currentViewSupportingAction(const char* actionName) const
1352 {
1353     if (!wnd->currentWindow())
1354         return 0;
1355     KexiView *view = wnd->currentWindow()->selectedView();
1356     if (!view)
1357         return 0;
1358     QAction *action = view->sharedAction(actionName);
1359     if (!action || !action->isEnabled())
1360         return 0;
1361     return view;
1362 }
1363 
1364 KexiSearchAndReplaceViewInterface* KexiMainWindow::Private::currentViewSupportingSearchAndReplaceInterface() const
1365 {
1366     if (!wnd->currentWindow())
1367         return 0;
1368     KexiView *view = wnd->currentWindow()->selectedView();
1369     if (!view)
1370         return 0;
1371     return dynamic_cast<KexiSearchAndReplaceViewInterface*>(view);
1372 }
1373 
1374 tristate KexiMainWindow::Private::showProjectMigrationWizard(
1375     const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata)
1376 {
1377     //pass arguments
1378     QMap<QString, QString> args;
1379     args.insert("mimeType", mimeType);
1380     args.insert("databaseName", databaseName);
1381     if (cdata) { //pass KDbConnectionData serialized as a string...
1382         QString str;
1383         KDbUtils::serializeMap(cdata->toMap(), &str);
1384         args.insert("connectionData", str);
1385     }
1386 
1387     QDialog *dlg = KexiInternalPart::createModalDialogInstance("org.kexi-project.migration", "migration", wnd, 0, &args);
1388     if (!dlg)
1389         return false; //error msg has been shown by KexiInternalPart
1390 
1391     const int result = dlg->exec();
1392     delete dlg;
1393     if (result != QDialog::Accepted)
1394         return cancelled;
1395 
1396     //open imported project in a new Kexi instance
1397     QString destinationDatabaseName(args["destinationDatabaseName"]);
1398     QString fileName, destinationConnectionShortcut;
1399     if (!destinationDatabaseName.isEmpty()) {
1400         if (args.contains("destinationConnectionShortcut")) {
1401             // server-based
1402             destinationConnectionShortcut = args["destinationConnectionShortcut"];
1403         } else {
1404             // file-based
1405             fileName = destinationDatabaseName;
1406             destinationDatabaseName.clear();
1407         }
1408         tristate res = wnd->openProject(fileName, destinationConnectionShortcut,
1409                                         destinationDatabaseName);
1410         wnd->raise();
1411         return res;
1412     }
1413     return true;
1414 }
1415 
1416 KPropertyEditorView* KexiMainWindow::Private::propertyEditor() const
1417 {
1418     return (objectViewWidget && objectViewWidget->propertyPane() && objectViewWidget->propertyPane()->editor())
1419             ? objectViewWidget->propertyPane()->editor() : 0;
1420 }
1421 
1422 void KexiMainWindow::Private::setProjectNavigatorVisible(bool set, ShowMode mode)
1423 {
1424     if (objectViewWidget && objectViewWidget->projectNavigator()) {
1425         if (mode == ShowAnimated) {
1426             objectViewWidget->setProjectNavigatorVisible(set);
1427             if (set) { // on showing, arrow should be updated immediately
1428                 wnd->slotProjectNavigatorVisibilityChanged(set);
1429             }
1430         } else {
1431             objectViewWidget->projectNavigator()->setVisible(set);
1432             action_show_nav->setChecked(set);
1433             wnd->slotProjectNavigatorVisibilityChanged(set);
1434         }
1435     }
1436 }
1437 
1438 KexiAssistantPage *KexiMainWindow::Private::visibleMainMenuWidgetPage()
1439 {
1440     const KexiAssistantWidget *widget = qobject_cast<const KexiAssistantWidget*>(tabbedToolBar->mainMenuContent());
1441     if (widget && widget->isVisible()) {
1442         return widget->currentPage();
1443     }
1444     return nullptr;
1445 }
1446 
1447 #ifndef KEXI_NO_PENDING_DIALOGS
1448 void KexiMainWindow::Private::executeActionWhenPendingJobsAreFinished()
1449 {
1450     ActionToExecuteWhenPendingJobsAreFinished a = actionToExecuteWhenPendingJobsAreFinished;
1451     actionToExecuteWhenPendingJobsAreFinished = NoAction;
1452     switch (a) {
1453     case QuitAction:
1454         qApp->quit();
1455         break;
1456     case CloseProjectAction:
1457         wnd->closeProject();
1458         break;
1459     default:;
1460     }
1461 }
1462 
1463 KexiWindow *KexiMainWindow::Private::openedWindowFor(const KexiPart::Item* item, PendingJobType &pendingType)
1464 {
1465     return openedWindowFor(item->identifier(), pendingType);
1466 }
1467 
1468 KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier, PendingJobType &pendingType)
1469 {
1470 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1471     QHash<int, PendingJobType>::ConstIterator it = pendingWindows.find(identifier);
1472     if (it == pendingWindows.end())
1473         pendingType = NoJob;
1474     else
1475         pendingType = it.value();
1476 
1477     if (pendingType == WindowOpeningJob) {
1478         return 0;
1479     }
1480     return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0;
1481 }
1482 
1483 void KexiMainWindow::Private::addItemToPendingWindows(const KexiPart::Item* item, PendingJobType jobType)
1484 {
1485 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1486     pendingWindows.insert(item->identifier(), jobType);
1487 }
1488 
1489 bool KexiMainWindow::Private::pendingWindowsExist()
1490 {
1491     if (pendingWindows.begin() != pendingWindows.end())
1492         qDebug() <<  pendingWindows.constBegin().key() << (int)pendingWindows.constBegin().value();
1493 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1494     return !pendingWindows.isEmpty();
1495 }
1496 
1497 void KexiMainWindow::Private::removePendingWindow(int identifier)
1498 {
1499 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1500     pendingWindows.remove(identifier);
1501 }
1502 
1503 #else // KEXI_NO_PENDING_DIALOGS
1504 
1505 KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier)
1506 {
1507 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1508     return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0;
1509 }
1510 #endif