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