1 /* This file is part of the KDE project
2    Copyright (C) 2003 Lucijan Busch <lucijan@kde.org>
3    Copyright (C) 2003-2018 Jarosław Staniek <staniek@kde.org>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19 */
20 
21 #include "KexiMainWindow_p.h"
22 
23 #include <QPainter>
24 #include <QDebug>
25 
26 #include <KConfigGroup>
27 
28 #include <KDbUtils>
29 
30 #include <kexiutils/SmallToolButton.h>
31 #include <kexiutils/KexiTester.h>
32 #include <kexiutils/KexiFadeWidgetEffect.h>
33 #include <KexiIcon.h>
34 #include <core/kexipartmanager.h>
35 #include <KexiAssistantWidget.h>
36 
KexiWindowContainer(QWidget * parent)37 KexiWindowContainer::KexiWindowContainer(QWidget* parent)
38     : QWidget(parent)
39     , window(0)
40     , lyr(new QVBoxLayout(this))
41 {
42     lyr->setContentsMargins(0, 0, 0, 0);
43 }
~KexiWindowContainer()44 KexiWindowContainer::~KexiWindowContainer()
45 {
46     //! @todo warning if saveSettings() failed?
47     if (window) {
48         window->saveSettings();
49         delete (KexiWindow*)window;
50     }
51 }
52 
setWindow(KexiWindow * w)53 void KexiWindowContainer::setWindow(KexiWindow* w)
54 {
55     window = w;
56     if (w)
57         lyr->addWidget(w);
58 }
59 
60 // ---
61 
EmptyMenuContentWidget(QWidget * parent)62 EmptyMenuContentWidget::EmptyMenuContentWidget(QWidget* parent)
63  : QWidget(parent)
64 {
65     setAutoFillBackground(true);
66     alterBackground();
67 }
68 
alterBackground()69 void EmptyMenuContentWidget::alterBackground()
70 {
71     QPalette pal(palette());
72     QColor bg(pal.color(QPalette::Window));
73     bg.setAlpha(200);
74     pal.setColor(QPalette::Window, bg);
75     setPalette(pal);
76 }
77 
changeEvent(QEvent * e)78 void EmptyMenuContentWidget::changeEvent(QEvent *e)
79 {
80     if (e->type() == QEvent::PaletteChange) {
81         alterBackground();
82     }
83     QWidget::changeEvent(e);
84 }
85 
86 //! @todo KEXI3 is KexiMenuWidgetStyle needed?
87 #if 0
88 KexiMenuWidgetStyle::KexiMenuWidgetStyle(QStyle *style, QObject *parent)
89     : KexiUtils::StyleProxy(style, parent)
90 {
91 }
92 
93 KexiMenuWidgetStyle::~KexiMenuWidgetStyle()
94 {
95 }
96 
97 void KexiMenuWidgetStyle::drawControl(ControlElement element, const QStyleOption *option,
98                          QPainter *painter, const QWidget *widget = 0) const
99 {
100     if (element == QStyle::CE_MenuItem
101         && (option->state & QStyle::State_Selected) && (option->state & QStyle::State_Enabled)
102         && parentStyle()->objectName() == QLatin1String("oxygen"))
103     {
104         // Ugly fix for visual glitch of oxygen; no chance for improvement since
105         // we've forked QMenu and oxygen checks for qobject_cast<QMenu*> directly.
106         QColor c(option->palette.color(QPalette::Window));
107         int h, s, v, a;
108         c.getHsv(&h, &s, &v, &a);
109         // Why 0.91208791? I knew you're curious. There are some algorithms in Oxygen
110         // to make color a bit lighter. They are not in the public API nor they are simple.
111         // So the number was computed by me to find the proper value for the color
112         // (the accuracy is quite OK).
113         // It's also related to the fact that Oxygen's menus have gradient background.
114         // A lot of computation happens under the mask...
115         c.setHsv(h, s, v * 0.91208791, a);
116         painter->fillRect(option->rect.x() + 6, option->rect.y() + 6,
117                           option->rect.width() - 12, option->rect.height() - 12,
118                           c);
119     }
120     KexiUtils::StyleProxy::drawControl(element, option, painter, widget);
121 }
122 #endif
123 
KexiMainMenu(KexiTabbedToolBar * toolBar,QWidget * parent)124 KexiMainMenu::KexiMainMenu(KexiTabbedToolBar *toolBar, QWidget* parent)
125  : QWidget(parent),
126     m_toolBar(toolBar), m_initialized(false)
127 {
128     m_content = 0;
129     m_selectFirstItem = false;
130 }
131 
~KexiMainMenu()132 KexiMainMenu::~KexiMainMenu()
133 {
134     delete (QWidget*)m_contentWidget;
135 }
136 
eventFilter(QObject * watched,QEvent * event)137 bool KexiMainMenu::eventFilter(QObject * watched, QEvent* event)
138 {
139     if (event->type() == QEvent::MouseButtonPress && watched == m_content && !m_contentWidget) {
140         emit contentAreaPressed();
141     }
142     else if (event->type() == QEvent::KeyPress) {
143         QKeyEvent* ke = static_cast<QKeyEvent*>(event);
144         if ((ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) {
145             emit hideContentsRequested();
146             return true;
147         }
148     }
149     return QWidget::eventFilter(watched, event);
150 }
151 
setContent(QWidget * contentWidget)152 void KexiMainMenu::setContent(QWidget *contentWidget)
153 {
154     if (m_menuWidget && m_persistentlySelectedAction) {
155         m_menuWidget->setPersistentlySelectedAction(
156             m_persistentlySelectedAction,
157             m_persistentlySelectedAction->persistentlySelected());
158     }
159     /*if (m_menuWidget->persistentlySelectedAction())
160         qDebug() << "****" << m_menuWidget->persistentlySelectedAction()->objectName();*/
161     KexiFadeWidgetEffect *fadeEffect = 0;
162 
163     if (m_contentWidget && contentWidget) {
164         fadeEffect = new KexiFadeWidgetEffect(m_content);
165     }
166     if (m_contentWidget)
167         m_contentWidget->deleteLater();
168     m_contentWidget = contentWidget;
169     if (m_contentWidget) {
170         QPalette contentWidgetPalette(m_contentWidget->palette());
171         contentWidgetPalette.setBrush(QPalette::Active, QPalette::Window, contentWidgetPalette.brush(QPalette::Active, QPalette::Base));
172         contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::Window, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Base));
173         contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Window, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base));
174         contentWidgetPalette.setBrush(QPalette::Active, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Active, QPalette::Text));
175         contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Text));
176         contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Text));
177         const QColor highlightDisabled(KexiUtils::blendedColors(
178                                      contentWidgetPalette.color(QPalette::Active, QPalette::Highlight),
179                                      contentWidgetPalette.color(QPalette::Disabled, QPalette::Window), 1, 2));
180         contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlightDisabled);
181         const QColor highlightedTextDisabled(KexiUtils::blendedColors(
182                                      contentWidgetPalette.color(QPalette::Active, QPalette::HighlightedText),
183                                      contentWidgetPalette.color(QPalette::Disabled, QPalette::WindowText), 1, 2));
184         contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::HighlightedText, highlightedTextDisabled);
185         m_contentWidget->setPalette(contentWidgetPalette);
186         for(QAbstractScrollArea *area : m_contentWidget->findChildren<QAbstractScrollArea*>()) {
187             QPalette pal(area->viewport()->palette());
188             pal.setBrush(QPalette::Disabled, QPalette::Base, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base));
189             area->viewport()->setPalette(pal);
190         }
191 
192         m_contentWidget->setAutoFillBackground(true);
193         m_contentWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
194         m_contentWidget->setContentsMargins(0, 0, 0, 0);
195         m_contentLayout->addWidget(m_contentWidget);
196         m_contentLayout->setCurrentWidget(m_contentWidget);
197         m_contentWidget->setFocus();
198         m_contentWidget->installEventFilter(this);
199         //connect(m_contentWidget, SIGNAL(destroyed()), this, SLOT(contentWidgetDestroyed()));
200     }
201     if (fadeEffect) {
202         if (m_contentWidget)
203             m_contentLayout->update();
204 
205         QTimer::singleShot(10, fadeEffect, SLOT(start()));
206     }
207 }
208 
contentWidget() const209 const QWidget *KexiMainMenu::contentWidget() const
210 {
211     return m_contentWidget;
212 }
213 
setPersistentlySelectedAction(KexiMenuWidgetAction * action,bool set)214 void KexiMainMenu::setPersistentlySelectedAction(KexiMenuWidgetAction* action, bool set)
215 {
216     m_persistentlySelectedAction = action;
217     m_persistentlySelectedAction->setPersistentlySelected(set);
218 }
219 
220 /*
221 void KexiMainMenu::setActiveAction(QAction* action = 0)
222 {
223     if (!action && !m_menuWidget->actions().isEmpty()) {
224         action = actions().first();
225     }
226     if (action) {
227         m_menuWidget->setActiveAction(action);
228     }
229 }
230 */
231 
selectFirstItem()232 void KexiMainMenu::selectFirstItem()
233 {
234     m_selectFirstItem = true;
235 }
236 
showEvent(QShowEvent * event)237 void KexiMainMenu::showEvent(QShowEvent * event)
238 {
239     if (!m_initialized) {
240         m_initialized = true;
241         KActionCollection *ac = KexiMainWindowIface::global()->actionCollection();
242         QHBoxLayout *hlyr = new QHBoxLayout(this);
243 
244         hlyr->setSpacing(0);
245         hlyr->setMargin(0);
246 
247         m_menuWidget = new KexiMenuWidget;
248 //! @todo KEXI3 is KexiMenuWidgetStyle needed?
249 #if 0
250         QString styleName(m_menuWidget->style()->objectName());
251         if (KDE::version() < KDE_MAKE_VERSION(4, 8, 0) // a fix is apparently needed for glitch in KDE < 4.8
252             && styleName == "oxygen")
253         {
254             KexiMenuWidgetStyle *customStyle = new KexiMenuWidgetStyle(m_menuWidget->style()->objectName(), this);
255             m_menuWidget->setStyle(customStyle);
256         }
257 #endif
258         m_menuWidget->installEventFilter(this);
259         m_menuWidget->setFocusPolicy(Qt::StrongFocus);
260         setFocusProxy(m_menuWidget);
261         m_menuWidget->setFrame(false);
262         m_menuWidget->setAutoFillBackground(true);
263 
264         m_menuWidget->addAction(ac->action("project_welcome"));
265         m_menuWidget->addAction(ac->action("project_open"));
266         m_menuWidget->addAction(ac->action("project_close"));
267         m_menuWidget->addSeparator();
268         m_menuWidget->addAction(ac->action("project_new"));
269         m_menuWidget->addAction(ac->action("project_import_export_send"));
270 #ifdef KEXI_SHOW_UNIMPLEMENTED
271         m_menuWidget->addAction(ac->action("project_properties"));
272         //! @todo project information
273         m_menuWidget->addAction(ac->action("settings"));
274 #endif
275         m_menuWidget->addSeparator();
276         m_menuWidget->addAction(ac->action("quit"));
277         hlyr->addWidget(m_menuWidget);
278 
279         m_content = new EmptyMenuContentWidget;
280         m_content->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
281         m_content->installEventFilter(this);
282         m_mainContentLayout = new QVBoxLayout;
283         hlyr->addLayout(m_mainContentLayout);
284         m_contentLayout = new QStackedLayout(m_content);
285         m_contentLayout->setStackingMode(QStackedLayout::StackAll);
286         m_contentLayout->setContentsMargins(0, 0, 0, 0);
287         m_mainContentLayout->addWidget(m_content);
288         hlyr->setStretchFactor(m_mainContentLayout, 1);
289     }
290     QWidget::showEvent(event);
291     if (m_selectFirstItem && !m_menuWidget->actions().isEmpty()) {
292         QAction* action = m_menuWidget->actions().first();
293         m_menuWidget->setActiveAction(action);
294         m_selectFirstItem = false;
295     }
296 }
297 
298 // ---
299 
Private(KexiTabbedToolBar * t)300 KexiTabbedToolBar::Private::Private(KexiTabbedToolBar *t)
301             : q(t), createWidgetToolBar(0)
302 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
303             , tabToRaise(-1)
304 #endif
305             , rolledUp(false)
306 {
307 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
308     tabRaiseTimer.setSingleShot(true);
309     tabRaiseTimer.setInterval(300);
310 #endif
311     tabBarAnimation.setPropertyName("opacity");
312     tabBarAnimation.setDuration(500);
313     connect(&tabBarAnimation, SIGNAL(finished()), q, SLOT(tabBarAnimationFinished()));
314     tabIndex = 0;
315     lowestIndex = 2;
316 }
317 
318 //! @return true if @a style name is specific regarding tab styling
isSpecificTabStyle(const QString & styleName)319 static bool isSpecificTabStyle(const QString &styleName)
320 {
321     return styleName == "oxygen" || styleName == "qtcurve" || styleName == "gtk+"
322            || styleName == "gtk2";
323 }
324 
KexiTabbedToolBarStyle(const QString & baseStyleName)325 KexiTabbedToolBarStyle::KexiTabbedToolBarStyle(const QString &baseStyleName)
326   : QProxyStyle(baseStyleName)
327 {
328 }
329 
~KexiTabbedToolBarStyle()330 KexiTabbedToolBarStyle::~KexiTabbedToolBarStyle()
331 {
332 }
333 
drawControl(ControlElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const334 void KexiTabbedToolBarStyle::drawControl(ControlElement element, const QStyleOption *option,
335                                          QPainter *painter, const QWidget *widget) const
336 {
337     const QString styleName(baseStyle()->objectName());
338     qreal origOpacity = -1.0;
339     if (element == CE_TabBarTab) {
340         const QStyleOptionTab* opt
341             = qstyleoption_cast<const QStyleOptionTab*>(option);
342         const QTabBar* tabBar = qobject_cast<const QTabBar*>(widget);
343         KexiTabbedToolBar* tbar = tabBar
344             ? qobject_cast<KexiTabbedToolBar*>(tabBar->parentWidget()) : 0;
345         if (opt && tbar) {
346             const int index = tabBar->tabAt(opt->rect.center());
347             if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX)
348                 return;
349             bool mouseOver = opt->state & QStyle::State_MouseOver;
350             bool unselectedOrMenuVisible
351                 = !(opt->state & State_Selected) || tbar->mainMenuVisible();
352             if (unselectedOrMenuVisible) {
353                 if (styleName == "bespin") {
354                     unselectedOrMenuVisible = false;
355                 }
356             }
357 
358             QStyleOptionTab newOpt(*opt);
359             const bool specificStyle = isSpecificTabStyle(styleName);
360             newOpt.text = (specificStyle ? " " : "")
361                     + tabBar->tabText(index)
362                     + (specificStyle ? " " : "");
363             if (!mouseOver
364                 && unselectedOrMenuVisible
365                 && index > 0)
366             {
367                 if (tbar->mainMenuVisible())
368                     newOpt.state &= ~QStyle::State_HasFocus;
369                 QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget);
370                 return;
371             }
372             else if (index == 0) {
373                 QBrush bg;
374                 newOpt.state |= State_Selected;
375                 if (tbar->mainMenuVisible()) {
376                     bg = newOpt.palette.brush(QPalette::Active, QPalette::Highlight);
377                     if (!specificStyle) {
378                         newOpt.palette.setBrush(QPalette::WindowText,
379                                                 newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText));
380                         newOpt.palette.setBrush(QPalette::ButtonText,
381                                                 newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText));
382                     }
383                 }
384                 else {
385                     if (styleName == "fusion") {
386                         bg = newOpt.palette.brush(QPalette::Active, QPalette::Button);
387                     } else {
388                         bg = Qt::transparent;
389                     }
390                 }
391                 QFont origFont(painter->font());
392                 QFont f(origFont);
393                 f.setBold(true);
394                 painter->setFont(f);
395                 newOpt.palette.setBrush(QPalette::Window, bg);
396                 newOpt.palette.setBrush(QPalette::Button, // needed e.g. for Plastique style
397                                         bg);
398                 QProxyStyle::drawControl(element, &newOpt, painter, widget);
399                 painter->setFont(origFont);
400                 if (!mouseOver || tbar->mainMenuVisible() || styleName == "gtk+") {
401                     return;
402                 }
403             }
404             if (index > 0 || mouseOver) {
405                 const QPalette::ColorGroup hbGroup =  (styleName == "oxygen")
406                         ? QPalette::Active : QPalette::Inactive;
407                 const QBrush hb(newOpt.palette.brush(hbGroup, QPalette::Highlight));
408                 newOpt.palette.setBrush(QPalette::Window, hb);
409                 newOpt.palette.setBrush(QPalette::Button, hb); // needed e.g. for Plastique style
410                 if (mouseOver && (index != tbar->currentIndex() || tbar->mainMenuVisible())) {
411                     // use lower opacity for diplaying hovered tabs
412                     origOpacity = painter->opacity();
413                     painter->setOpacity(styleName == "qtcurve" ? 0.2 : 0.3);
414                     newOpt.state |= State_Selected;
415                 }
416                 else {
417                     if (!specificStyle) {
418                         newOpt.palette.setBrush(QPalette::WindowText,
419                                                 newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText));
420                         newOpt.palette.setBrush(QPalette::ButtonText,
421                                                 newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText));
422                     }
423                 }
424                 if (index == tbar->currentIndex() && styleName == "qtcurve") {
425                     origOpacity = painter->opacity();
426                     painter->setOpacity(0.5);
427                 }
428                 (newOpt.state |= State_Active) ^= State_Active;
429                 QProxyStyle::drawControl(element, &newOpt, painter, widget);
430                 if (origOpacity != -1.0) {
431                     // restore opacity and draw labels using full this opacity
432                     painter->setOpacity(origOpacity);
433                     if (index > 0) {
434                         QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget);
435                     }
436                 }
437                 return;
438             }
439         }
440     }
441     else if (element == CE_ToolBar) {
442         return;
443     }
444     QProxyStyle::drawControl(element, option, painter, widget);
445 }
446 
drawPrimitive(PrimitiveElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const447 void KexiTabbedToolBarStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
448                                            QPainter *painter, const QWidget *widget) const
449 {
450     const QString styleName(baseStyle()->objectName());
451     if (element == PE_FrameTabWidget) {
452         return;
453     }
454     if (element == PE_FrameTabBarBase) {
455         const QTabBar* tabBar = qobject_cast<const QTabBar*>(widget);
456         KexiTabbedToolBar* tbar = tabBar
457             ? qobject_cast<KexiTabbedToolBar*>(tabBar->parentWidget()) : 0;
458         if (tbar && tbar->mainMenuVisible() && styleName != "bespin") {
459             return;
460         }
461     }
462     if (element == QStyle::PE_PanelToolBar || element == QStyle::PE_FrameMenu) {
463         return;
464     }
465     QProxyStyle::drawPrimitive(element, option, painter, widget);
466 }
467 
pixelMetric(PixelMetric metric,const QStyleOption * option,const QWidget * widget) const468 int KexiTabbedToolBarStyle::pixelMetric(PixelMetric metric, const QStyleOption* option,
469                                         const QWidget* widget) const
470 {
471     if (metric == QStyle::PM_SmallIconSize)
472         return KIconLoader::SizeMedium;
473     return QProxyStyle::pixelMetric(metric, option, widget);
474 }
475 
476 // ---
477 
KexiTabbedToolBarTabBar(QWidget * parent)478 KexiTabbedToolBarTabBar::KexiTabbedToolBarTabBar(QWidget *parent)
479     : QTabBar(parent)
480 {
481     setObjectName("tabbar");
482     customStyle = new KexiTabbedToolBarStyle(style()->objectName());
483     customStyle->setParent(this);
484     setStyle(customStyle);
485     installEventFilter(parent);
486     QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget();
487     mainWindow->installEventFilter(parent);
488     setAttribute(Qt::WA_Hover, true);
489 }
490 
originalTabSizeHint(int index) const491 QSize KexiTabbedToolBarTabBar::originalTabSizeHint(int index) const
492 {
493     return QTabBar::tabSizeHint(index);
494 }
495 
tabSizeHint(int index) const496 QSize KexiTabbedToolBarTabBar::tabSizeHint(int index) const
497 {
498     QSize s = QTabBar::tabSizeHint(index);
499     QStyleOptionTab ot;
500     ot.initFrom(this);
501     QFont f(font());
502     f.setBold(true);
503     ot.text = (isSpecificTabStyle(customStyle->baseStyle()->objectName()) ? "  " : "") + tabText(index);
504     ot.fontMetrics = QFontMetrics(f);
505     int w = customStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, &ot, this);
506     if (w <= 0) { // needed e.g. for oxygen
507         w = fontMetrics().width("   ");
508     }
509     if (index == 0) {
510         s.setWidth(QFontMetrics(f).width(ot.text) + w * 2);
511         return s;
512     }
513     else if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) {
514         // fix width of the spacer tab
515         s.setWidth(w);
516     }
517     return s;
518 }
519 
toggleMainMenu()520 void KexiTabbedToolBar::Private::toggleMainMenu()
521 {
522     if (q->mainMenuVisible())
523         hideMainMenu();
524     else
525         showMainMenu();
526 }
527 
showMainMenu(const char * actionName)528 void KexiTabbedToolBar::Private::showMainMenu(const char* actionName)
529 {
530     QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget();
531     if (!mainMenu) {
532         mainMenu = new KexiMainMenu(q, mainWindow);
533         connect(mainMenu, SIGNAL(contentAreaPressed()), this, SLOT(hideMainMenu()));
534         connect(mainMenu, SIGNAL(hideContentsRequested()), this, SLOT(hideContentsOrMainMenu()));
535     }
536     updateMainMenuGeometry();
537     if (actionName) {
538         q->selectMainMenuItem(actionName);
539     }
540     else {
541         mainMenu->selectFirstItem();
542     }
543     mainMenu->show();
544     mainMenu->setFocus();
545     q->update(); // tab bar could have a line that should be repainted
546 }
547 
updateMainMenuGeometry()548 void KexiTabbedToolBar::Private::updateMainMenuGeometry()
549 {
550     if (!mainMenu)
551         return;
552     QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget();
553     KexiTabbedToolBarTabBar *tabBar = static_cast<KexiTabbedToolBarTabBar*>(q->tabBar());
554     QPoint pos = q->mapToGlobal(QPoint(0, tabBar->originalTabSizeHint(0).height() - 1));
555 //     qDebug() << "1." << pos;
556     pos = mainWindow->mapFromGlobal(pos);
557 //     qDebug() << "2." << pos;
558 //     qDebug() << "3." << q->pos();
559 
560     QStyleOptionTab ot;
561     ot.initFrom(tabBar);
562     int overlap = tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &ot, tabBar)
563                   - tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseHeight, &ot, tabBar);
564 //     qDebug() << "4. overlap=" << overlap;
565 
566     mainMenu->setGeometry(0, pos.y() - overlap /*- q->y()*/,
567                           mainWindow->width(),
568                           mainWindow->height() - pos.y() + overlap /*+ q->y()*/);
569 }
570 
initSearchLineEdit()571 void KexiTabbedToolBar::Private::initSearchLineEdit()
572 {
573     //! @todo use KexiConfig
574     KConfigGroup mainWindowGroup(KSharedConfig::openConfig()->group("MainWindow"));
575     const bool enabled = mainWindowGroup.readEntry("GlobalSearchBoxEnabled", true);
576     if (enabled && !searchLineEdit) {
577         searchLineEdit = new KexiSearchLineEdit;
578         kexiTester() << KexiTestObject(searchLineEdit, "globalSearch.lineEdit");
579         searchLineEdit->installEventFilter(q);
580         helpLayer->addWidget(searchLineEdit);
581     } else if (!enabled && searchLineEdit) {
582         helpLayer->removeWidget(searchLineEdit);
583         delete searchLineEdit;
584         searchLineEdit = nullptr;
585     }
586 }
587 
activateSearchLineEdit()588 void KexiTabbedToolBar::activateSearchLineEdit()
589 {
590     if (!d->searchLineEdit) {
591         return;
592     }
593     d->searchLineEdit->selectAll();
594     d->searchLineEdit->setFocus();
595 }
596 
hideMainMenu()597 void KexiTabbedToolBar::Private::hideMainMenu()
598 {
599     if (!mainMenu || !mainMenu->isVisible())
600         return;
601     mainMenu->hide();
602     mainMenu->setContent(0);
603     q->update();  // tab bar could have a line that should be repainted
604 }
605 
hideContentsOrMainMenu()606 void KexiTabbedToolBar::Private::hideContentsOrMainMenu()
607 {
608     if (!mainMenu || !mainMenu->isVisible())
609         return;
610     if (mainMenu->contentWidget()) {
611         mainMenu->setContent(0);
612     }
613     else {
614         hideMainMenu();
615     }
616 }
617 
createToolBar(const char * name,const QString & caption)618 KToolBar *KexiTabbedToolBar::Private::createToolBar(const char *name, const QString& caption)
619 {
620     KToolBar *tbar = new KToolBar(q, true /*main toolbar*/, false /*read config*/);
621     tbar->setIconDimensions(22); //!< @todo make configurable or system-dependent?
622     // needed e.g. for Windows style to remove the toolbar's frame
623     tbar->setStyle(customTabBar->customStyle);
624     toolbarsForName.insert(name, tbar);
625     tbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
626     tbar->setObjectName(name);
627     toolbarsCaptionForName.insert(name, caption);
628     tabIndex = q->addTab(tbar, caption);
629     toolbarsVisibleForIndex.append(true);
630     toolbarsIndexForName.insert(name, tabIndex);
631     return tbar;
632 }
633 
KexiTabbedToolBar(QWidget * parent)634 KexiTabbedToolBar::KexiTabbedToolBar(QWidget *parent)
635         : QTabWidget(parent)
636         , d(new Private(this))
637 {
638     d->customTabBar = new KexiTabbedToolBarTabBar(this);
639     setTabBar(d->customTabBar);
640     setStyle(d->customTabBar->customStyle);
641 
642     // from ktabwidget.cpp
643     //! @todo QTabWidget::setTabBar() should be added with this code
644     //! @todo KEXI3 Are these tabBar() connections useful to port?
645 #if 0
646     connect(tabBar(), SIGNAL(contextMenu(int,QPoint)), SLOT(contextMenu(int,QPoint&)));
647     connect(tabBar(), SIGNAL(tabDoubleClicked(int)), SLOT(mouseDoubleClick(int)));
648     connect(tabBar(), SIGNAL(newTabRequest()), this, SIGNAL(mouseDoubleClick())); // #185487
649     connect(tabBar(), SIGNAL(mouseMiddleClick(int)), SLOT(mouseMiddleClick(int)));
650     connect(tabBar(), SIGNAL(initiateDrag( int )), SLOT(initiateDrag( int )));
651     connect(tabBar(), SIGNAL(testCanDecode(QDragMoveEvent*,bool*)), SIGNAL(testCanDecode(QDragMoveEvent*,bool*)));
652     connect(tabBar(), SIGNAL(receivedDropEvent(int,QDropEvent*)), SLOT(receivedDropEvent(int,QDropEvent*)));
653     connect(tabBar(), SIGNAL(moveTab(int,int)), SLOT(moveTab(int,int)));
654     connect(tabBar(), SIGNAL(tabCloseRequested(int)), SLOT(closeRequest(int)));
655 #endif
656 
657     setMouseTracking(true); // for mouseMoveEvent()
658     setWhatsThis(xi18n("Task-oriented toolbar. Groups commands using tabs."));
659 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
660     connect(&d->tabRaiseTimer, SIGNAL(timeout()), this, SLOT(slotDelayedTabRaise()));
661 #endif
662     connect(tabBar(), SIGNAL(tabBarDoubleClicked(int)), this, SLOT(slotTabDoubleClicked(int)));
663 
664     d->ac = KexiMainWindowIface::global()->actionCollection();
665     QWidget *mainWin = KexiMainWindowIface::global()->thisWidget();
666     const bool userMode = KexiMainWindowIface::global()->userMode();
667     KToolBar *tbar;
668 
669     slotSettingsChanged(0);//KGlobalSettings::FontChanged
670     //! @todo KEXI3 port from KGlobalSettings::Private::_k_slotNotifyChange:
671     //! connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(slotSettingsChanged(int)));
672 
673     // help area
674     QWidget *helpWidget = new QWidget(this);
675     helpWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
676     d->helpLayer = new QHBoxLayout(helpWidget);
677     d->helpLayer->setContentsMargins(0, 0, 0, 0);
678 
679     // * HELP MENU
680     // add help menu actions... (KexiTabbedToolBar depends on them)
681     d->helpMenu = new KHelpMenu(this, KAboutData::applicationData(),
682                                 true/*showWhatsThis*/);
683     QAction* help_report_bug_action = d->helpMenu->action(KHelpMenu::menuReportBug);
684     d->ac->addAction(help_report_bug_action->objectName(), help_report_bug_action);
685     QObject::disconnect(help_report_bug_action, 0, 0, 0);
686     QObject::connect(help_report_bug_action, SIGNAL(triggered()), mainWin, SLOT(slotReportBug()));
687     help_report_bug_action->setText(xi18nc("Report a bug or wish for Kexi application", "Report a &Bug or Wish..."));
688     help_report_bug_action->setIcon(koIcon("tools-report-bug")); // good icon for toolbar
689     help_report_bug_action->setWhatsThis(xi18n("Files a bug or wish for Kexi application."));
690     QAction* help_whats_this_action =  d->helpMenu->action(KHelpMenu::menuWhatsThis);
691     d->ac->addAction(help_whats_this_action->objectName(), help_whats_this_action);
692     help_whats_this_action->setWhatsThis(xi18n("Activates a \"What's This?\" tool."));
693     QAction* help_contents_action = d->helpMenu->action(KHelpMenu::menuHelpContents);
694     d->ac->addAction(help_contents_action->objectName(), help_contents_action);
695     help_contents_action->setText(xi18n("Help"));
696     help_contents_action->setWhatsThis(xi18n("Shows Kexi Handbook."));
697     QAction* help_about_app_action = d->helpMenu->action(KHelpMenu::menuAboutApp);
698     d->ac->addAction(help_about_app_action->objectName(), help_about_app_action);
699     help_about_app_action->setWhatsThis(xi18n("Shows information about Kexi application."));
700     QAction* help_about_kde_action = d->helpMenu->action(KHelpMenu::menuAboutKDE);
701     d->ac->addAction(help_about_kde_action->objectName(), help_about_kde_action);
702     help_about_kde_action->setWhatsThis(xi18n("Shows information about KDE."));
703     QAction* help_switch_language_action = d->helpMenu->action(KHelpMenu::menuSwitchLanguage);
704     if (help_switch_language_action) {
705         d->ac->addAction(help_switch_language_action->objectName(), help_switch_language_action);
706     }
707     // extra action such as help_donate may be confusing for the user or conflicting with existing so hide it
708     QAction *extraAction = d->helpMenu->action(static_cast<KHelpMenu::MenuId>(KHelpMenu::menuSwitchLanguage + 1));
709     if (extraAction) {
710         extraAction->setVisible(false);
711     }
712 
713     QAction *action_show_help_menu = d->ac->action("help_show_menu");
714     KexiSmallToolButton *btn = new KexiSmallToolButton(koIcon("help-about"), QString(), helpWidget);
715     btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
716     btn->setPopupMode(QToolButton::InstantPopup);
717     btn->setToolTip(action_show_help_menu->toolTip());
718     btn->setWhatsThis(action_show_help_menu->whatsThis());
719     btn->setFocusPolicy(Qt::NoFocus);
720     QStyleOptionToolButton opt;
721     opt.initFrom(btn);
722     int w = btn->sizeHint().width();
723     int wAdd = btn->style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, btn);
724     if (w <= (2 * (wAdd + 1))) {
725         w += wAdd + 2;
726     }
727     btn->setMinimumWidth(w);
728     connect(action_show_help_menu, SIGNAL(triggered()), btn, SLOT(showMenu()));
729     d->helpLayer->addWidget(btn);
730     btn->setMenu(d->helpMenu->menu());
731     setCornerWidget(helpWidget, Qt::TopRightCorner);
732     d->initSearchLineEdit();
733 
734     // needed e.g. for Windows style to remove the toolbar's frame
735     QWidget *dummyWidgetForMainMenu = new QWidget(this);
736     dummyWidgetForMainMenu->setObjectName("kexi");
737     addTab(dummyWidgetForMainMenu, KAboutData::applicationData().displayName());
738     d->toolbarsVisibleForIndex.append(true);
739     addTab(new QWidget(this), QString()); // dummy for spacer
740     d->toolbarsVisibleForIndex.append(true);
741 
742     if (!userMode) {
743         d->createWidgetToolBar = d->createToolBar("create", xi18n("Create"));
744     }
745 
746     tbar = d->createToolBar("data", xi18n("Data"));
747     addAction(tbar, "edit_cut");
748     addAction(tbar, "edit_copy");
749     addAction(tbar, "edit_paste");
750     if (!userMode)
751         addAction(tbar, "edit_paste_special_data_table");
752 //! @todo move undo/redo to quickbar:
753 
754     tbar = d->createToolBar("external", xi18n("External Data"));
755     if (!userMode) {
756         addAction(tbar, "project_import_data_table");
757         addAction(tbar, "tools_import_tables");
758     }
759 
760     tbar = d->createToolBar("tools", xi18n("Tools"));
761     addAction(tbar, "tools_compact_database");
762 
763 //! @todo move to form plugin
764     tbar = d->createToolBar("form", xi18n("Form Design"));
765 
766 //! @todo move to report plugin
767     tbar = d->createToolBar("report", xi18n("Report Design"));
768 
769     connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int)));
770     setCurrentWidget(widget(KEXITABBEDTOOLBAR_SPACER_TAB_INDEX + 1)); // the default
771     setFocusPolicy(Qt::NoFocus);
772 }
773 
setCurrentTab(const QString & name)774 void KexiTabbedToolBar::Private::setCurrentTab(const QString& name)
775 {
776     q->setCurrentWidget(q->toolBar(name));
777 }
778 
hideTab(const QString & name)779 void KexiTabbedToolBar::Private::hideTab(const QString& name)
780 {
781     q->removeTab(q->indexOf(toolbarsForName.value(name)));
782     toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = false;
783 }
784 
isTabVisible(const QString & name) const785 bool KexiTabbedToolBar::Private::isTabVisible(const QString& name) const
786 {
787     return q->indexOf(toolbarsForName.value(name)) != -1
788            && toolbarsVisibleForIndex[toolbarsIndexForName.value(name)];
789 }
790 
791 #ifndef NDEBUG
debugToolbars() const792 void KexiTabbedToolBar::Private::debugToolbars() const
793 {
794     qDebug() << "QHash<QString, KToolBar*> toolbarsForName:";
795     for (QHash<QString, KToolBar*>::ConstIterator it(toolbarsForName.constBegin());
796          it!=toolbarsForName.constEnd(); ++it)
797     {
798         qDebug() << it.key() << "->" << it.value();
799     }
800     qDebug() << "QHash<QString, int> toolbarsIndexForName:";
801     for (QHash<QString, int>::ConstIterator it(toolbarsIndexForName.constBegin());
802          it!=toolbarsIndexForName.constEnd(); ++it)
803     {
804         qDebug() << it.key() << "->" << it.value();
805     }
806     qDebug() << "QHash<QString, QString> toolbarsCaptionForName:";
807     for (QHash<QString, QString>::ConstIterator it(toolbarsCaptionForName.constBegin());
808          it!=toolbarsCaptionForName.constEnd(); ++it)
809     {
810         qDebug() << it.key() << "->" << it.value();
811     }
812     qDebug() << "QVector<bool> toolbarsVisibleForIndex:";
813     for (int i = 0; i < toolbarsVisibleForIndex.size(); i++) {
814         qDebug() << i << "->" << toolbarsVisibleForIndex[i];
815     }
816 }
817 #endif
818 
showTab(const QString & name)819 void KexiTabbedToolBar::Private::showTab(const QString& name)
820 {
821 //    qDebug() << "name:" << name;
822 //    qDebug() << "toolbarsForName.value(name):" << toolbarsForName.value(name);
823 //    qDebug() << "toolbarsIndexForName.value(name):" << toolbarsIndexForName.value(name);
824 //    qDebug() << "q->indexOf(toolbarsForName.value(name))" << q->indexOf(toolbarsForName.value(name));
825 #ifndef NDEBUG
826     //debugToolbars();
827 #endif
828     if (q->indexOf(toolbarsForName.value(name)) == -1) {
829         int h = 0;
830         // count h = invisible tabs before this
831         for (int i = lowestIndex; i < toolbarsIndexForName.value(name); i++) {
832             if (!toolbarsVisibleForIndex.at(i))
833                 h++;
834         }
835         q->insertTab(toolbarsIndexForName.value(name) - h,
836                      toolbarsForName.value(name), toolbarsCaptionForName.value(name));
837         toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = true;
838     }
839 }
840 
841 // ---
842 
~KexiTabbedToolBar()843 KexiTabbedToolBar::~KexiTabbedToolBar()
844 {
845     delete d;
846 }
847 
mainMenuVisible() const848 bool KexiTabbedToolBar::mainMenuVisible() const
849 {
850     return d->mainMenu && d->mainMenu->isVisible();
851 }
852 
tabRect(int index) const853 QRect KexiTabbedToolBar::tabRect(int index) const
854 {
855     return tabBar()->tabRect(index);
856 }
857 
helpMenu() const858 KHelpMenu* KexiTabbedToolBar::helpMenu() const
859 {
860     return d->helpMenu;
861 }
862 
slotSettingsChanged(int category)863 void KexiTabbedToolBar::slotSettingsChanged(int category)
864 {
865     Q_UNUSED(category);
866     //! @todo if (category == KGlobalSettings::FontChanged) {
867         //! @todo KEXI3 KGlobalSettings::menuFont() not available (using QFontDatabase::systemFont(QFontDatabase::GeneralFont) for now)
868         //!       https://community.kde.org/Frameworks/Porting_Notes#Global_Settings
869         setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); // the toolbar acts like a menu
870     //}
871 }
872 
createWidgetToolBar() const873 KToolBar* KexiTabbedToolBar::createWidgetToolBar() const
874 {
875     return d->createWidgetToolBar;
876 }
877 
mouseMoveEvent(QMouseEvent * event)878 void KexiTabbedToolBar::mouseMoveEvent(QMouseEvent* event)
879 {
880 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
881     QPoint p = event->pos();
882     int tab = tabBar()->tabAt(p);
883     if (d->tabToRaise != -1 && (tab == -1 || tab == currentIndex())) {
884         d->tabRaiseTimer.stop();
885         d->tabToRaise = -1;
886     } else if (d->tabToRaise != tab) {
887         d->tabRaiseTimer.start();
888 
889         d->tabToRaise = tab;
890     }
891 #endif
892     QTabWidget::mouseMoveEvent(event);
893 }
894 
leaveEvent(QEvent * event)895 void KexiTabbedToolBar::leaveEvent(QEvent* event)
896 {
897 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
898     d->tabRaiseTimer.stop();
899     d->tabToRaise = -1;
900 #endif
901     QTabWidget::leaveEvent(event);
902 }
903 
eventFilter(QObject * watched,QEvent * event)904 bool KexiTabbedToolBar::eventFilter(QObject* watched, QEvent* event)
905 {
906     switch (event->type()) {
907     case QEvent::MouseButtonPress: {
908         QWidget *mainWin = KexiMainWindowIface::global()->thisWidget();
909         // qDebug() << "MouseButtonPress: watched:" << watched << "window()->focusWidget():" << window()->focusWidget();
910         if (d->searchLineEdit && watched == d->searchLineEdit) {
911             activateSearchLineEdit(); // custom setFocus() for search box, so it's possible to focus
912                                       // back on Escape key press
913             return false;
914         }
915         else if (watched == tabBar()) {
916             QMouseEvent* me = static_cast<QMouseEvent*>(event);
917             QPoint p = me->pos();
918             KexiTabbedToolBarTabBar *tb = static_cast<KexiTabbedToolBarTabBar*>(tabBar());
919             int index = tb->tabAt(p);
920             if (index == 0) {
921                 d->toggleMainMenu();
922                 return true;
923             }
924             d->hideMainMenu();
925             if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) {
926                 return true;
927             }
928         }
929         else if (watched == mainWin && d->mainMenu) {
930             QMouseEvent* me = static_cast<QMouseEvent*>(event);
931             if (!QRect(d->mainMenu->mapToGlobal(QPoint(0,0)), d->mainMenu->size())
932                     .contains(mainWin->mapToGlobal(me->pos())))
933             {
934                 // hide if clicked outside of the menu
935                 d->hideMainMenu();
936             }
937         }
938         }
939         break;
940     case QEvent::KeyPress: {
941         QKeyEvent* ke = static_cast<QKeyEvent*>(event);
942 //         qDebug() << "**********" << QString::number(ke->key(), 16)
943 //                  << QKeySequence::mnemonic(tabText(0))[0];
944         if (QKeySequence::mnemonic(tabText(0)) == QKeySequence(ke->key())) {
945 //             qDebug() << "eat the &File accel";
946             if (!d->mainMenu || !d->mainMenu->isVisible()) {
947                 d->showMainMenu();
948             }
949             /*this could be unexpected:
950             else if (d->mainMenu && d->mainMenu->isVisible()) {
951                 d->hideMainMenu();
952             }*/
953             return true;
954         }
955         if (d->mainMenu && d->mainMenu->isVisible() && (ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) {
956             d->hideContentsOrMainMenu();
957             return true;
958         }
959         break;
960     }
961     case QEvent::Resize:
962         if (watched == KexiMainWindowIface::global()->thisWidget()) {
963             d->updateMainMenuGeometry();
964         }
965         break;
966     case QEvent::Shortcut: {
967         QShortcutEvent *se = static_cast<QShortcutEvent*>(event);
968         if (watched == tabBar() && QKeySequence::mnemonic(tabText(0)) == se->key()) {
969 //             qDebug() << "eat the &File accel";
970             if (!d->mainMenu || !d->mainMenu->isVisible()) {
971                 d->showMainMenu();
972                 return true;
973             }
974         }
975         break;
976     }
977     default:;
978     }
979     return QTabWidget::eventFilter(watched, event);
980 }
981 
slotCurrentChanged(int index)982 void KexiTabbedToolBar::slotCurrentChanged(int index)
983 {
984     if (index == indexOf(d->createWidgetToolBar) && index != -1) {
985         if (d->createWidgetToolBar->actions().isEmpty()) {
986             QTimer::singleShot(10, this, SLOT(setupCreateWidgetToolbar()));
987         }
988     }
989     if (d->rolledUp) { // switching the tab rolls down
990         slotTabDoubleClicked(index);
991     }
992     if (index == 0) { // main menu
993         d->showMainMenu();
994     }
995     else {
996         d->hideMainMenu();
997     }
998 }
999 
slotTabDoubleClicked(int index)1000 void KexiTabbedToolBar::slotTabDoubleClicked(int index)
1001 {
1002     if (index <= 0) {
1003         return; // main item does not count here
1004     }
1005     d->rolledUp = !d->rolledUp;
1006     d->tabBarAnimation.stop();
1007     QWidget *w = widget(index);
1008     if (!w) {
1009         return;
1010     }
1011     w->setGraphicsEffect(&d->tabBarOpacityEffect);
1012     if (d->rolledUp) {
1013         d->tabBarOpacityEffect.setOpacity(1.0);
1014         d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect);
1015         d->tabBarAnimation.setStartValue(1.0);
1016         d->tabBarAnimation.setEndValue(0.0);
1017         d->tabBarAnimation.start();
1018     }
1019     else { // roll down
1020         d->tabBarOpacityEffect.setOpacity(0.0);
1021         setMaximumHeight(QWIDGETSIZE_MAX);
1022         widget(d->rolledUpIndex)->show();
1023         widget(d->rolledUpIndex)->setMaximumHeight(QWIDGETSIZE_MAX);
1024         w->setMaximumHeight(QWIDGETSIZE_MAX);
1025         w->show();
1026         d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect);
1027         d->tabBarAnimation.setStartValue(0.0);
1028         d->tabBarAnimation.setEndValue(1.0);
1029         d->tabBarAnimation.start();
1030     }
1031 }
1032 
tabBarAnimationFinished()1033 void KexiTabbedToolBar::tabBarAnimationFinished()
1034 {
1035     if (d->rolledUp) {
1036         // hide and collapse the area
1037         widget(currentIndex())->hide();
1038         KexiTabbedToolBarTabBar *tb = static_cast<KexiTabbedToolBarTabBar*>(tabBar());
1039         setFixedHeight(tb->tabSizeHint(currentIndex()).height());
1040         widget(currentIndex())->setFixedHeight(0);
1041         d->rolledUpIndex = currentIndex();
1042     }
1043 }
1044 
setupCreateWidgetToolbar()1045 void KexiTabbedToolBar::setupCreateWidgetToolbar()
1046 {
1047     if (!d->createWidgetToolBar->actions().isEmpty())
1048         return;
1049 //! @todo separate core object types from custom....
1050     KexiPart::PartInfoList *plist = Kexi::partManager().infoList(); //this list is properly sorted
1051     if (plist) {
1052         foreach(KexiPart::Info *info, *plist) {
1053             QAction* a = info->newObjectAction();
1054             if (a) {
1055                 d->createWidgetToolBar->addAction(a);
1056             } else {
1057                 //! @todo err
1058             }
1059         }
1060     }
1061 }
1062 
slotDelayedTabRaise()1063 void KexiTabbedToolBar::slotDelayedTabRaise()
1064 {
1065 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR
1066     QPoint p = mapFromGlobal(QCursor::pos()); // make sure cursor is still over the tab
1067     int tab = tabBar()->tabAt(p);
1068     if (tab != d->tabToRaise) {
1069         d->tabToRaise = -1;
1070     } else if (d->tabToRaise != -1) {
1071         setCurrentIndex(d->tabToRaise);
1072         d->tabToRaise = -1;
1073     }
1074 #endif
1075 }
1076 
toolBar(const QString & name) const1077 KToolBar *KexiTabbedToolBar::toolBar(const QString& name) const
1078 {
1079     return d->toolbarsForName[name];
1080 }
1081 
addAction(KToolBar * tbar,const char * actionName)1082 void KexiTabbedToolBar::addAction(KToolBar *tbar, const char* actionName)
1083 {
1084     QAction *a = d->ac->action(actionName);
1085     if (a)
1086         tbar->addAction(a);
1087 }
1088 
addAction(const QString & toolBarName,QAction * action)1089 void KexiTabbedToolBar::addAction(const QString& toolBarName, QAction *action)
1090 {
1091     if (!action)
1092         return;
1093     KToolBar *tbar = d->toolbarsForName[toolBarName];
1094     if (!tbar)
1095         return;
1096     tbar->addAction(action);
1097 }
1098 
addSeparatorAndAction(KToolBar * tbar,const char * actionName)1099 void KexiTabbedToolBar::addSeparatorAndAction(KToolBar *tbar, const char* actionName)
1100 {
1101     QAction *a = d->ac->action(actionName);
1102     if (a) {
1103         tbar->addSeparator();
1104         tbar->addAction(a);
1105     }
1106 }
1107 
appendWidgetToToolbar(const QString & name,QWidget * widget)1108 void KexiTabbedToolBar::appendWidgetToToolbar(const QString& name, QWidget* widget)
1109 {
1110     KToolBar *tbar = d->toolbarsForName[name];
1111     if (!tbar) {
1112         return;
1113     }
1114     QAction *action = tbar->addWidget(widget);
1115     d->extraActions.insert(widget, action);
1116 }
1117 
setWidgetVisibleInToolbar(QWidget * widget,bool visible)1118 void KexiTabbedToolBar::setWidgetVisibleInToolbar(QWidget* widget, bool visible)
1119 {
1120     QAction *action = d->extraActions[widget];
1121     if (!action) {
1122         return;
1123     }
1124     action->setVisible(visible);
1125 }
1126 
showMainMenu(const char * actionName)1127 void KexiTabbedToolBar::showMainMenu(const char* actionName)
1128 {
1129     d->showMainMenu(actionName);
1130 }
1131 
hideMainMenu()1132 void KexiTabbedToolBar::hideMainMenu()
1133 {
1134     d->hideMainMenu();
1135 }
1136 
toggleMainMenu()1137 void KexiTabbedToolBar::toggleMainMenu()
1138 {
1139     d->toggleMainMenu();
1140 }
1141 
setMainMenuContent(QWidget * w)1142 void KexiTabbedToolBar::setMainMenuContent(QWidget *w)
1143 {
1144     d->mainMenu->setContent(w);
1145 }
1146 
mainMenuContent()1147 const QWidget* KexiTabbedToolBar::mainMenuContent()
1148 {
1149     return d->mainMenu->contentWidget();
1150 }
1151 
selectMainMenuItem(const char * actionName)1152 void KexiTabbedToolBar::selectMainMenuItem(const char *actionName)
1153 {
1154     if (actionName) {
1155         KActionCollection *ac = KexiMainWindowIface::global()->actionCollection();
1156         KexiMenuWidgetAction *a = qobject_cast<KexiMenuWidgetAction*>(ac->action(actionName));
1157         if (a) {
1158             d->mainMenu->setPersistentlySelectedAction(a, true);
1159         }
1160     }
1161 }
1162 
addSearchableModel(KexiSearchableModel * model)1163 void KexiTabbedToolBar::addSearchableModel(KexiSearchableModel *model)
1164 {
1165     if (!d->searchLineEdit) {
1166         return;
1167     }
1168     d->searchLineEdit->addSearchableModel(model);
1169 }
1170 
removeSearchableModel(KexiSearchableModel * model)1171 void KexiTabbedToolBar::removeSearchableModel(KexiSearchableModel *model)
1172 {
1173     if (!d->searchLineEdit) {
1174         return;
1175     }
1176     d->searchLineEdit->removeSearchableModel(model);
1177 }
1178 
createToolBar(const char * name,const QString & caption)1179 KToolBar* KexiTabbedToolBar::createToolBar(const char* name, const QString& caption)
1180 {
1181     return d->createToolBar(name, caption);
1182 }
1183 
setCurrentTab(const QString & name)1184 void KexiTabbedToolBar::setCurrentTab(const QString& name)
1185 {
1186     //qDebug() << name;
1187     d->setCurrentTab(name);
1188 }
1189 
setCurrentTab(int index)1190 void KexiTabbedToolBar::setCurrentTab(int index)
1191 {
1192     setCurrentIndex(d->lowestIndex + index);
1193 }
1194 
hideTab(const QString & name)1195 void KexiTabbedToolBar::hideTab(const QString& name)
1196 {
1197     //qDebug() << name;
1198     d->hideTab(name);
1199 }
1200 
showTab(const QString & name)1201 void KexiTabbedToolBar::showTab(const QString& name)
1202 {
1203     //qDebug() << name;
1204     d->showTab(name);
1205 }
1206 
isTabVisible(const QString & name) const1207 bool KexiTabbedToolBar::isTabVisible(const QString& name) const
1208 {
1209     return d->isTabVisible(name);
1210 }
1211 
isRolledUp()1212 bool KexiTabbedToolBar::isRolledUp()
1213 {
1214     return d->rolledUp;
1215 }
1216 
toggleRollDown()1217 void KexiTabbedToolBar::toggleRollDown()
1218 {
1219     slotTabDoubleClicked(-1);//use -1 just to rolldown/up the tabbar
1220 }
1221 
1222 // ---
1223 
KexiMainWidget()1224 KexiMainWidget::KexiMainWidget()
1225         : KMainWindow(0, Qt::Widget)
1226         , m_mainWindow(0)
1227 {
1228     setupCentralWidget();
1229 }
1230 
~KexiMainWidget()1231 KexiMainWidget::~KexiMainWidget()
1232 {
1233 }
1234 
setParent(KexiMainWindow * mainWindow)1235 void KexiMainWidget::setParent(KexiMainWindow* mainWindow)
1236 {
1237     KMainWindow::setParent(mainWindow);
1238     m_mainWindow = mainWindow;
1239 }
1240 
tabWidget() const1241 KexiMainWindowTabWidget* KexiMainWidget::tabWidget() const
1242 {
1243     return m_tabWidget;
1244 }
1245 
setupCentralWidget()1246 void KexiMainWidget::setupCentralWidget()
1247 {
1248     QWidget *centralWidget = new QWidget(this);
1249     QVBoxLayout *centralWidgetLyr = new QVBoxLayout(centralWidget);
1250     m_tabWidget = new KexiMainWindowTabWidget(centralWidget, this);
1251     connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentTabIndexChanged(int)));
1252     centralWidgetLyr->setContentsMargins(0, 0, 0, 0);
1253     centralWidgetLyr->setSpacing(0);
1254     centralWidgetLyr->addWidget(m_tabWidget);
1255     setCentralWidget(centralWidget);
1256     layout()->setContentsMargins(0, 0, 0, 0);
1257     layout()->setSpacing(0);
1258 }
1259 
queryClose()1260 bool KexiMainWidget::queryClose()
1261 {
1262     return m_mainWindow ? m_mainWindow->queryClose() : true;
1263 }
1264 
slotCurrentTabIndexChanged(int index)1265 void KexiMainWidget::slotCurrentTabIndexChanged(int index)
1266 {
1267     KexiWindowContainer* cont = dynamic_cast<KexiWindowContainer*>(m_tabWidget->widget(index));
1268     if (! cont || (KexiWindow*)m_previouslyActiveWindow == cont->window)
1269         return;
1270     if (m_mainWindow)
1271         m_mainWindow->activeWindowChanged(cont->window, (KexiWindow*)m_previouslyActiveWindow);
1272     m_previouslyActiveWindow = cont->window;
1273     emit currentTabIndexChanged(index);
1274 }
1275 
1276 //------------------------------------------
1277 
Private(KexiMainWindow * w)1278 KexiMainWindow::Private::Private(KexiMainWindow* w)
1279     : wnd(w)
1280 {
1281     actionCollection = new KActionCollection(w);
1282     propEditor = 0;
1283     propEditorDockWidget = 0;
1284     navDockWidget = 0;
1285     propEditorTabWidget = 0;
1286     KexiProjectData *pdata = KexiStartupHandler::global()->projectData();
1287     userMode = KexiStartupHandler::global()->forcedUserMode() /* <-- simply forced the user mode */
1288                /* project has 'user mode' set as default and not 'design mode' override is found: */
1289                || (pdata && pdata->userMode() && !KexiStartupHandler::global()->forcedDesignMode());
1290     isProjectNavigatorVisible = KexiStartupHandler::global()->isProjectNavigatorVisible();
1291     isMainMenuVisible = KexiStartupHandler::global()->isMainMenuVisible();
1292     navigator = 0;
1293     prj = 0;
1294     config = KSharedConfig::openConfig();
1295     nameDialog = 0;
1296     m_findDialog = 0;
1297     focus_before_popup = 0;
1298     action_show_nav = 0;
1299     action_show_propeditor = 0;
1300     action_activate_nav = 0;
1301     action_activate_propeditor = 0;
1302     action_welcome_projects_title_id = -1;
1303     action_welcome_connections_title_id = -1;
1304     forceWindowClosing = false;
1305     insideCloseWindow = false;
1306 #ifndef KEXI_NO_PENDING_DIALOGS
1307     actionToExecuteWhenPendingJobsAreFinished = NoAction;
1308 #endif
1309     propEditorDockSeparatorPos = -1;
1310     navDockSeparatorPos = -1;
1311     wasAutoOpen = false;
1312     windowExistedBeforeCloseProject = false;
1313 #ifndef KEXI_SHOW_UNIMPLEMENTED
1314     dummy_action = new KActionMenu(QString(), wnd);
1315 #endif
1316     forceShowProjectNavigatorOnCreation = false;
1317     forceHideProjectNavigatorOnCreation = false;
1318     navWasVisibleBeforeProjectClosing = false;
1319     saveSettingsForShowProjectNavigator = true;
1320     propertyEditorCollapsed = false;
1321     enable_slotPropertyEditorVisibilityChanged = true;
1322     migrateManager = 0;
1323 }
1324 
~Private()1325 KexiMainWindow::Private::~Private()
1326 {
1327     qDeleteAll(m_openedCustomObjectsForItem);
1328 }
1329 
insertWindow(KexiWindow * window)1330 void KexiMainWindow::Private::insertWindow(KexiWindow *window)
1331 {
1332 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1333     windows.insert(window->id(), window);
1334 #ifndef KEXI_NO_PENDING_DIALOGS
1335     pendingWindows.remove(window->id());
1336 #endif
1337 }
1338 
windowContainerExistsFor(int identifier) const1339 bool KexiMainWindow::Private::windowContainerExistsFor(int identifier) const
1340 {
1341     return windowContainers.contains(identifier);
1342 }
1343 
setWindowContainerExistsFor(int identifier,bool set)1344 void KexiMainWindow::Private::setWindowContainerExistsFor(int identifier, bool set)
1345 {
1346     if (set) {
1347         windowContainers.insert(identifier);
1348     }
1349     else {
1350         windowContainers.remove(identifier);
1351     }
1352 }
1353 
updateWindowId(KexiWindow * window,int oldItemID)1354 void KexiMainWindow::Private::updateWindowId(KexiWindow *window, int oldItemID)
1355 {
1356 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1357     windows.remove(oldItemID);
1358 #ifndef KEXI_NO_PENDING_DIALOGS
1359     pendingWindows.remove(oldItemID);
1360 #endif
1361     windows.insert(window->id(), window);
1362 }
1363 
removeWindow(int identifier)1364 void KexiMainWindow::Private::removeWindow(int identifier)
1365 {
1366 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1367     windows.remove(identifier);
1368 }
1369 
openedWindowsCount()1370 int KexiMainWindow::Private::openedWindowsCount()
1371 {
1372 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1373     return windows.count();
1374 }
1375 
1376 //! Used in KexiMainWindowe::closeProject()
clearWindows()1377 void KexiMainWindow::Private::clearWindows()
1378 {
1379 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1380     windows.clear();
1381 #ifndef KEXI_NO_PENDING_DIALOGS
1382     pendingWindows.clear();
1383 #endif
1384 }
1385 
showStartProcessMsg(const QStringList & args)1386 void KexiMainWindow::Private::showStartProcessMsg(const QStringList& args)
1387 {
1388     wnd->showErrorMessage(xi18nc("@info", "Could not start <application>%1</application> application.",
1389                                  QString::fromLatin1(KEXI_APP_NAME)),
1390                           xi18nc("@info",
1391                                  "Command <command>%1</command> failed.", args.join(" ")));
1392 }
1393 
updatePropEditorVisibility(Kexi::ViewMode viewMode,KexiPart::Info * info)1394 void KexiMainWindow::Private::updatePropEditorVisibility(Kexi::ViewMode viewMode, KexiPart::Info *info)
1395 {
1396     if (!propEditorDockWidget)
1397         return;
1398     KexiWindow *currentWindow = wnd->currentWindow();
1399     if (!info && currentWindow) {
1400         info = currentWindow->part()->info();
1401     }
1402     const bool visible = (viewMode == Kexi::DesignViewMode)
1403         && ((currentWindow && currentWindow->propertySet()) || (info && info->isPropertyEditorAlwaysVisibleInDesignMode()));
1404     //qDebug() << "visible == " << visible;
1405     enable_slotPropertyEditorVisibilityChanged = false;
1406     if (visible && propertyEditorCollapsed) { // used when we're switching back to a window with propeditor available but collapsed
1407         propEditorDockWidget->setVisible(!visible);
1408         setPropertyEditorTabBarVisible(true);
1409     }
1410     else {
1411         propEditorDockWidget->setVisible(visible);
1412         setPropertyEditorTabBarVisible(false);
1413     }
1414     enable_slotPropertyEditorVisibilityChanged = true;
1415 }
1416 
setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position,int id,KexiDockWidget * dockWidget,bool visible)1417 void KexiMainWindow::Private::setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position, int id,
1418                                                KexiDockWidget *dockWidget, bool visible)
1419 {
1420     KMultiTabBar *mtbar = multiTabBars.value(position);
1421     if (!mtbar) {
1422         return;
1423     }
1424     if (!visible) {
1425         mtbar->removeTab(id);
1426     }
1427     else if (!mtbar->tab(id)) {
1428         mtbar->appendTab(koIcon("document-properties"), id, dockWidget->tabText);
1429         KMultiTabBarTab *tab = mtbar->tab(id);
1430         QObject::connect(tab, SIGNAL(clicked(int)),
1431                          wnd, SLOT(slotMultiTabBarTabClicked(int)),
1432                          Qt::UniqueConnection);
1433     }
1434 }
1435 
setPropertyEditorTabBarVisible(bool visible)1436 void KexiMainWindow::Private::setPropertyEditorTabBarVisible(bool visible)
1437 {
1438     setTabBarVisible(KMultiTabBar::Right, PROPERTY_EDITOR_TABBAR_ID,
1439                      propEditorDockWidget, visible);
1440 }
1441 
openedCustomObjectsForItem(KexiPart::Item * item,const char * name)1442 QObject *KexiMainWindow::Private::openedCustomObjectsForItem(KexiPart::Item* item, const char* name)
1443 {
1444     if (!item || !name) {
1445         qWarning() << "!item || !name";
1446         return 0;
1447     }
1448     QByteArray key(QByteArray::number(item->identifier()) + name);
1449     return m_openedCustomObjectsForItem.value(key);
1450 }
1451 
addOpenedCustomObjectForItem(KexiPart::Item * item,QObject * object,const char * name)1452 void KexiMainWindow::Private::addOpenedCustomObjectForItem(KexiPart::Item* item, QObject* object, const char* name)
1453 {
1454     QByteArray key(QByteArray::number(item->identifier()) + name);
1455     m_openedCustomObjectsForItem.insert(key, object);
1456 }
1457 
findDialog()1458 KexiFindDialog *KexiMainWindow::Private::findDialog()
1459 {
1460     if (!m_findDialog) {
1461         m_findDialog = new KexiFindDialog(wnd);
1462         m_findDialog->setActions(action_edit_findnext, action_edit_findprev,
1463                                  action_edit_replace, action_edit_replace_all);
1464     }
1465     return m_findDialog;
1466 }
1467 
updateFindDialogContents(bool createIfDoesNotExist)1468 void KexiMainWindow::Private::updateFindDialogContents(bool createIfDoesNotExist)
1469 {
1470     if (!wnd->currentWindow())
1471         return;
1472     if (!createIfDoesNotExist && (!m_findDialog || !m_findDialog->isVisible()))
1473         return;
1474     KexiSearchAndReplaceViewInterface* iface = currentViewSupportingSearchAndReplaceInterface();
1475     if (!iface) {
1476         if (m_findDialog) {
1477             m_findDialog->setButtonsEnabled(false);
1478             m_findDialog->setLookInColumnList(QStringList(), QStringList());
1479         }
1480         return;
1481     }
1482 //! @todo use ->caption() here, depending on global settings related to displaying captions
1483     findDialog()->setObjectNameForCaption(wnd->currentWindow()->partItem()->name());
1484 
1485     QStringList columnNames;
1486     QStringList columnCaptions;
1487     QString currentColumnName; // for 'look in'
1488     if (!iface->setupFindAndReplace(columnNames, columnCaptions, currentColumnName)) {
1489         m_findDialog->setButtonsEnabled(false);
1490         m_findDialog->setLookInColumnList(QStringList(), QStringList());
1491         return;
1492     }
1493     m_findDialog->setButtonsEnabled(true);
1494     const QString prevColumnName(m_findDialog->currentLookInColumnName());
1495     m_findDialog->setLookInColumnList(columnNames, columnCaptions);
1496     m_findDialog->setCurrentLookInColumnName(prevColumnName);
1497 }
1498 
currentViewSupportingAction(const char * actionName) const1499 KexiView *KexiMainWindow::Private::currentViewSupportingAction(const char* actionName) const
1500 {
1501     if (!wnd->currentWindow())
1502         return 0;
1503     KexiView *view = wnd->currentWindow()->selectedView();
1504     if (!view)
1505         return 0;
1506     QAction *action = view->sharedAction(actionName);
1507     if (!action || !action->isEnabled())
1508         return 0;
1509     return view;
1510 }
1511 
currentViewSupportingSearchAndReplaceInterface() const1512 KexiSearchAndReplaceViewInterface* KexiMainWindow::Private::currentViewSupportingSearchAndReplaceInterface() const
1513 {
1514     if (!wnd->currentWindow())
1515         return 0;
1516     KexiView *view = wnd->currentWindow()->selectedView();
1517     if (!view)
1518         return 0;
1519     return dynamic_cast<KexiSearchAndReplaceViewInterface*>(view);
1520 }
1521 
showProjectMigrationWizard(const QString & mimeType,const QString & databaseName,const KDbConnectionData * cdata)1522 tristate KexiMainWindow::Private::showProjectMigrationWizard(
1523     const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata)
1524 {
1525     //pass arguments
1526     QMap<QString, QString> args;
1527     args.insert("mimeType", mimeType);
1528     args.insert("databaseName", databaseName);
1529     if (cdata) { //pass KDbConnectionData serialized as a string...
1530         QString str;
1531         KDbUtils::serializeMap(cdata->toMap(), &str);
1532         args.insert("connectionData", str);
1533     }
1534 
1535     QDialog *dlg = KexiInternalPart::createModalDialogInstance("org.kexi-project.migration", "migration", wnd, 0, &args);
1536     if (!dlg)
1537         return false; //error msg has been shown by KexiInternalPart
1538 
1539     const int result = dlg->exec();
1540     delete dlg;
1541     if (result != QDialog::Accepted)
1542         return cancelled;
1543 
1544     //open imported project in a new Kexi instance
1545     QString destinationDatabaseName(args["destinationDatabaseName"]);
1546     QString fileName, destinationConnectionShortcut;
1547     if (!destinationDatabaseName.isEmpty()) {
1548         if (args.contains("destinationConnectionShortcut")) {
1549             // server-based
1550             destinationConnectionShortcut = args["destinationConnectionShortcut"];
1551         } else {
1552             // file-based
1553             fileName = destinationDatabaseName;
1554             destinationDatabaseName.clear();
1555         }
1556         tristate res = wnd->openProject(fileName, destinationConnectionShortcut,
1557                                         destinationDatabaseName);
1558         wnd->raise();
1559         return res;
1560     }
1561     return true;
1562 }
1563 
visibleMainMenuWidgetPage()1564 KexiAssistantPage *KexiMainWindow::Private::visibleMainMenuWidgetPage()
1565 {
1566     const KexiAssistantWidget *widget = qobject_cast<const KexiAssistantWidget*>(tabbedToolBar->mainMenuContent());
1567     if (widget && widget->isVisible()) {
1568         return widget->currentPage();
1569     }
1570     return nullptr;
1571 }
1572 
1573 #ifndef KEXI_NO_PENDING_DIALOGS
executeActionWhenPendingJobsAreFinished()1574 void KexiMainWindow::Private::executeActionWhenPendingJobsAreFinished()
1575 {
1576     ActionToExecuteWhenPendingJobsAreFinished a = actionToExecuteWhenPendingJobsAreFinished;
1577     actionToExecuteWhenPendingJobsAreFinished = NoAction;
1578     switch (a) {
1579     case QuitAction:
1580         qApp->quit();
1581         break;
1582     case CloseProjectAction:
1583         wnd->closeProject();
1584         break;
1585     default:;
1586     }
1587 }
1588 
openedWindowFor(const KexiPart::Item * item,PendingJobType & pendingType)1589 KexiWindow *KexiMainWindow::Private::openedWindowFor(const KexiPart::Item* item, PendingJobType &pendingType)
1590 {
1591     return openedWindowFor(item->identifier(), pendingType);
1592 }
1593 
openedWindowFor(int identifier,PendingJobType & pendingType)1594 KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier, PendingJobType &pendingType)
1595 {
1596 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1597     QHash<int, PendingJobType>::ConstIterator it = pendingWindows.find(identifier);
1598     if (it == pendingWindows.end())
1599         pendingType = NoJob;
1600     else
1601         pendingType = it.value();
1602 
1603     if (pendingType == WindowOpeningJob) {
1604         return 0;
1605     }
1606     return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0;
1607 }
1608 
addItemToPendingWindows(const KexiPart::Item * item,PendingJobType jobType)1609 void KexiMainWindow::Private::addItemToPendingWindows(const KexiPart::Item* item, PendingJobType jobType)
1610 {
1611 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1612     pendingWindows.insert(item->identifier(), jobType);
1613 }
1614 
pendingWindowsExist()1615 bool KexiMainWindow::Private::pendingWindowsExist()
1616 {
1617     if (pendingWindows.begin() != pendingWindows.end())
1618         qDebug() <<  pendingWindows.constBegin().key() << " " << (int)pendingWindows.constBegin().value();
1619 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1620     return !pendingWindows.isEmpty();
1621 }
1622 
removePendingWindow(int identifier)1623 void KexiMainWindow::Private::removePendingWindow(int identifier)
1624 {
1625 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1626     pendingWindows.remove(identifier);
1627 }
1628 
1629 #else // KEXI_NO_PENDING_DIALOGS
1630 
openedWindowFor(int identifier)1631 KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier)
1632 {
1633 //! @todo (threads)  QMutexLocker dialogsLocker( &dialogsMutex );
1634     return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0;
1635 }
1636 #endif
1637