File indexing completed on 2024-05-12 16:40:04
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 0023 #include <QPainter> 0024 #include <QDebug> 0025 0026 #include <KConfigGroup> 0027 0028 #include <KDbUtils> 0029 0030 #include <kexiutils/SmallToolButton.h> 0031 #include <kexiutils/KexiTester.h> 0032 #include <kexiutils/KexiFadeWidgetEffect.h> 0033 #include <KexiIcon.h> 0034 #include <core/kexipartmanager.h> 0035 #include <KexiAssistantWidget.h> 0036 0037 KexiWindowContainer::KexiWindowContainer(QWidget* parent) 0038 : QWidget(parent) 0039 , window(0) 0040 , lyr(new QVBoxLayout(this)) 0041 { 0042 lyr->setContentsMargins(0, 0, 0, 0); 0043 } 0044 KexiWindowContainer::~KexiWindowContainer() 0045 { 0046 //! @todo warning if saveSettings() failed? 0047 if (window) { 0048 window->saveSettings(); 0049 delete (KexiWindow*)window; 0050 } 0051 } 0052 0053 void KexiWindowContainer::setWindow(KexiWindow* w) 0054 { 0055 window = w; 0056 if (w) 0057 lyr->addWidget(w); 0058 } 0059 0060 // --- 0061 0062 EmptyMenuContentWidget::EmptyMenuContentWidget(QWidget* parent) 0063 : QWidget(parent) 0064 { 0065 setAutoFillBackground(true); 0066 alterBackground(); 0067 } 0068 0069 void EmptyMenuContentWidget::alterBackground() 0070 { 0071 QPalette pal(palette()); 0072 QColor bg(pal.color(QPalette::Window)); 0073 bg.setAlpha(200); 0074 pal.setColor(QPalette::Window, bg); 0075 setPalette(pal); 0076 } 0077 0078 void EmptyMenuContentWidget::changeEvent(QEvent *e) 0079 { 0080 if (e->type() == QEvent::PaletteChange) { 0081 alterBackground(); 0082 } 0083 QWidget::changeEvent(e); 0084 } 0085 0086 //! @todo KEXI3 is KexiMenuWidgetStyle needed? 0087 #if 0 0088 KexiMenuWidgetStyle::KexiMenuWidgetStyle(QStyle *style, QObject *parent) 0089 : KexiUtils::StyleProxy(style, parent) 0090 { 0091 } 0092 0093 KexiMenuWidgetStyle::~KexiMenuWidgetStyle() 0094 { 0095 } 0096 0097 void KexiMenuWidgetStyle::drawControl(ControlElement element, const QStyleOption *option, 0098 QPainter *painter, const QWidget *widget = 0) const 0099 { 0100 if (element == QStyle::CE_MenuItem 0101 && (option->state & QStyle::State_Selected) && (option->state & QStyle::State_Enabled) 0102 && parentStyle()->objectName() == QLatin1String("oxygen")) 0103 { 0104 // Ugly fix for visual glitch of oxygen; no chance for improvement since 0105 // we've forked QMenu and oxygen checks for qobject_cast<QMenu*> directly. 0106 QColor c(option->palette.color(QPalette::Window)); 0107 int h, s, v, a; 0108 c.getHsv(&h, &s, &v, &a); 0109 // Why 0.91208791? I knew you're curious. There are some algorithms in Oxygen 0110 // to make color a bit lighter. They are not in the public API nor they are simple. 0111 // So the number was computed by me to find the proper value for the color 0112 // (the accuracy is quite OK). 0113 // It's also related to the fact that Oxygen's menus have gradient background. 0114 // A lot of computation happens under the mask... 0115 c.setHsv(h, s, v * 0.91208791, a); 0116 painter->fillRect(option->rect.x() + 6, option->rect.y() + 6, 0117 option->rect.width() - 12, option->rect.height() - 12, 0118 c); 0119 } 0120 KexiUtils::StyleProxy::drawControl(element, option, painter, widget); 0121 } 0122 #endif 0123 0124 KexiMainMenu::KexiMainMenu(KexiTabbedToolBar *toolBar, QWidget* parent) 0125 : QWidget(parent), 0126 m_toolBar(toolBar), m_initialized(false) 0127 { 0128 m_content = 0; 0129 m_selectFirstItem = false; 0130 } 0131 0132 KexiMainMenu::~KexiMainMenu() 0133 { 0134 delete (QWidget*)m_contentWidget; 0135 } 0136 0137 bool KexiMainMenu::eventFilter(QObject * watched, QEvent* event) 0138 { 0139 if (event->type() == QEvent::MouseButtonPress && watched == m_content && !m_contentWidget) { 0140 emit contentAreaPressed(); 0141 } 0142 else if (event->type() == QEvent::KeyPress) { 0143 QKeyEvent* ke = static_cast<QKeyEvent*>(event); 0144 if ((ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) { 0145 emit hideContentsRequested(); 0146 return true; 0147 } 0148 } 0149 return QWidget::eventFilter(watched, event); 0150 } 0151 0152 void KexiMainMenu::setContent(QWidget *contentWidget) 0153 { 0154 if (m_menuWidget && m_persistentlySelectedAction) { 0155 m_menuWidget->setPersistentlySelectedAction( 0156 m_persistentlySelectedAction, 0157 m_persistentlySelectedAction->persistentlySelected()); 0158 } 0159 /*if (m_menuWidget->persistentlySelectedAction()) 0160 qDebug() << "****" << m_menuWidget->persistentlySelectedAction()->objectName();*/ 0161 KexiFadeWidgetEffect *fadeEffect = 0; 0162 0163 if (m_contentWidget && contentWidget) { 0164 fadeEffect = new KexiFadeWidgetEffect(m_content); 0165 } 0166 if (m_contentWidget) 0167 m_contentWidget->deleteLater(); 0168 m_contentWidget = contentWidget; 0169 if (m_contentWidget) { 0170 QPalette contentWidgetPalette(m_contentWidget->palette()); 0171 contentWidgetPalette.setBrush(QPalette::Active, QPalette::Window, contentWidgetPalette.brush(QPalette::Active, QPalette::Base)); 0172 contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::Window, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Base)); 0173 contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Window, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base)); 0174 contentWidgetPalette.setBrush(QPalette::Active, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Active, QPalette::Text)); 0175 contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Text)); 0176 contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Text)); 0177 const QColor highlightDisabled(KexiUtils::blendedColors( 0178 contentWidgetPalette.color(QPalette::Active, QPalette::Highlight), 0179 contentWidgetPalette.color(QPalette::Disabled, QPalette::Window), 1, 2)); 0180 contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlightDisabled); 0181 const QColor highlightedTextDisabled(KexiUtils::blendedColors( 0182 contentWidgetPalette.color(QPalette::Active, QPalette::HighlightedText), 0183 contentWidgetPalette.color(QPalette::Disabled, QPalette::WindowText), 1, 2)); 0184 contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::HighlightedText, highlightedTextDisabled); 0185 m_contentWidget->setPalette(contentWidgetPalette); 0186 for(QAbstractScrollArea *area : m_contentWidget->findChildren<QAbstractScrollArea*>()) { 0187 QPalette pal(area->viewport()->palette()); 0188 pal.setBrush(QPalette::Disabled, QPalette::Base, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base)); 0189 area->viewport()->setPalette(pal); 0190 } 0191 0192 m_contentWidget->setAutoFillBackground(true); 0193 m_contentWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); 0194 m_contentWidget->setContentsMargins(0, 0, 0, 0); 0195 m_contentLayout->addWidget(m_contentWidget); 0196 m_contentLayout->setCurrentWidget(m_contentWidget); 0197 m_contentWidget->setFocus(); 0198 m_contentWidget->installEventFilter(this); 0199 //connect(m_contentWidget, SIGNAL(destroyed()), this, SLOT(contentWidgetDestroyed())); 0200 } 0201 if (fadeEffect) { 0202 if (m_contentWidget) 0203 m_contentLayout->update(); 0204 0205 QTimer::singleShot(10, fadeEffect, SLOT(start())); 0206 } 0207 } 0208 0209 const QWidget *KexiMainMenu::contentWidget() const 0210 { 0211 return m_contentWidget; 0212 } 0213 0214 void KexiMainMenu::setPersistentlySelectedAction(KexiMenuWidgetAction* action, bool set) 0215 { 0216 m_persistentlySelectedAction = action; 0217 m_persistentlySelectedAction->setPersistentlySelected(set); 0218 } 0219 0220 /* 0221 void KexiMainMenu::setActiveAction(QAction* action = 0) 0222 { 0223 if (!action && !m_menuWidget->actions().isEmpty()) { 0224 action = actions().first(); 0225 } 0226 if (action) { 0227 m_menuWidget->setActiveAction(action); 0228 } 0229 } 0230 */ 0231 0232 void KexiMainMenu::selectFirstItem() 0233 { 0234 m_selectFirstItem = true; 0235 } 0236 0237 void KexiMainMenu::showEvent(QShowEvent * event) 0238 { 0239 if (!m_initialized) { 0240 m_initialized = true; 0241 KActionCollection *ac = KexiMainWindowIface::global()->actionCollection(); 0242 QHBoxLayout *hlyr = new QHBoxLayout(this); 0243 0244 hlyr->setSpacing(0); 0245 hlyr->setMargin(0); 0246 0247 m_menuWidget = new KexiMenuWidget; 0248 //! @todo KEXI3 is KexiMenuWidgetStyle needed? 0249 #if 0 0250 QString styleName(m_menuWidget->style()->objectName()); 0251 if (KDE::version() < KDE_MAKE_VERSION(4, 8, 0) // a fix is apparently needed for glitch in KDE < 4.8 0252 && styleName == "oxygen") 0253 { 0254 KexiMenuWidgetStyle *customStyle = new KexiMenuWidgetStyle(m_menuWidget->style()->objectName(), this); 0255 m_menuWidget->setStyle(customStyle); 0256 } 0257 #endif 0258 m_menuWidget->installEventFilter(this); 0259 m_menuWidget->setFocusPolicy(Qt::StrongFocus); 0260 setFocusProxy(m_menuWidget); 0261 m_menuWidget->setFrame(false); 0262 m_menuWidget->setAutoFillBackground(true); 0263 0264 m_menuWidget->addAction(ac->action("project_welcome")); 0265 m_menuWidget->addAction(ac->action("project_open")); 0266 m_menuWidget->addAction(ac->action("project_close")); 0267 m_menuWidget->addSeparator(); 0268 m_menuWidget->addAction(ac->action("project_new")); 0269 m_menuWidget->addAction(ac->action("project_import_export_send")); 0270 #ifdef KEXI_SHOW_UNIMPLEMENTED 0271 m_menuWidget->addAction(ac->action("project_properties")); 0272 //! @todo project information 0273 m_menuWidget->addAction(ac->action("settings")); 0274 #endif 0275 m_menuWidget->addSeparator(); 0276 m_menuWidget->addAction(ac->action("quit")); 0277 hlyr->addWidget(m_menuWidget); 0278 0279 m_content = new EmptyMenuContentWidget; 0280 m_content->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); 0281 m_content->installEventFilter(this); 0282 m_mainContentLayout = new QVBoxLayout; 0283 hlyr->addLayout(m_mainContentLayout); 0284 m_contentLayout = new QStackedLayout(m_content); 0285 m_contentLayout->setStackingMode(QStackedLayout::StackAll); 0286 m_contentLayout->setContentsMargins(0, 0, 0, 0); 0287 m_mainContentLayout->addWidget(m_content); 0288 hlyr->setStretchFactor(m_mainContentLayout, 1); 0289 } 0290 QWidget::showEvent(event); 0291 if (m_selectFirstItem && !m_menuWidget->actions().isEmpty()) { 0292 QAction* action = m_menuWidget->actions().first(); 0293 m_menuWidget->setActiveAction(action); 0294 m_selectFirstItem = false; 0295 } 0296 } 0297 0298 // --- 0299 0300 KexiTabbedToolBar::Private::Private(KexiTabbedToolBar *t) 0301 : q(t), createWidgetToolBar(0) 0302 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR 0303 , tabToRaise(-1) 0304 #endif 0305 , rolledUp(false) 0306 { 0307 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR 0308 tabRaiseTimer.setSingleShot(true); 0309 tabRaiseTimer.setInterval(300); 0310 #endif 0311 tabBarAnimation.setPropertyName("opacity"); 0312 tabBarAnimation.setDuration(500); 0313 connect(&tabBarAnimation, SIGNAL(finished()), q, SLOT(tabBarAnimationFinished())); 0314 tabIndex = 0; 0315 lowestIndex = 2; 0316 } 0317 0318 //! @return true if @a style name is specific regarding tab styling 0319 static bool isSpecificTabStyle(const QString &styleName) 0320 { 0321 return styleName == "oxygen" || styleName == "qtcurve" || styleName == "gtk+" 0322 || styleName == "gtk2"; 0323 } 0324 0325 KexiTabbedToolBarStyle::KexiTabbedToolBarStyle(const QString &baseStyleName) 0326 : QProxyStyle(baseStyleName) 0327 { 0328 } 0329 0330 KexiTabbedToolBarStyle::~KexiTabbedToolBarStyle() 0331 { 0332 } 0333 0334 void KexiTabbedToolBarStyle::drawControl(ControlElement element, const QStyleOption *option, 0335 QPainter *painter, const QWidget *widget) const 0336 { 0337 const QString styleName(baseStyle()->objectName()); 0338 qreal origOpacity = -1.0; 0339 if (element == CE_TabBarTab) { 0340 const QStyleOptionTab* opt 0341 = qstyleoption_cast<const QStyleOptionTab*>(option); 0342 const QTabBar* tabBar = qobject_cast<const QTabBar*>(widget); 0343 KexiTabbedToolBar* tbar = tabBar 0344 ? qobject_cast<KexiTabbedToolBar*>(tabBar->parentWidget()) : 0; 0345 if (opt && tbar) { 0346 const int index = tabBar->tabAt(opt->rect.center()); 0347 if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) 0348 return; 0349 bool mouseOver = opt->state & QStyle::State_MouseOver; 0350 bool unselectedOrMenuVisible 0351 = !(opt->state & State_Selected) || tbar->mainMenuVisible(); 0352 if (unselectedOrMenuVisible) { 0353 if (styleName == "bespin") { 0354 unselectedOrMenuVisible = false; 0355 } 0356 } 0357 0358 QStyleOptionTab newOpt(*opt); 0359 const bool specificStyle = isSpecificTabStyle(styleName); 0360 newOpt.text = (specificStyle ? " " : "") 0361 + tabBar->tabText(index) 0362 + (specificStyle ? " " : ""); 0363 if (!mouseOver 0364 && unselectedOrMenuVisible 0365 && index > 0) 0366 { 0367 if (tbar->mainMenuVisible()) 0368 newOpt.state &= ~QStyle::State_HasFocus; 0369 QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget); 0370 return; 0371 } 0372 else if (index == 0) { 0373 QBrush bg; 0374 newOpt.state |= State_Selected; 0375 if (tbar->mainMenuVisible()) { 0376 bg = newOpt.palette.brush(QPalette::Active, QPalette::Highlight); 0377 if (!specificStyle) { 0378 newOpt.palette.setBrush(QPalette::WindowText, 0379 newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText)); 0380 newOpt.palette.setBrush(QPalette::ButtonText, 0381 newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText)); 0382 } 0383 } 0384 else { 0385 if (styleName == "fusion") { 0386 bg = newOpt.palette.brush(QPalette::Active, QPalette::Button); 0387 } else { 0388 bg = Qt::transparent; 0389 } 0390 } 0391 QFont origFont(painter->font()); 0392 QFont f(origFont); 0393 f.setBold(true); 0394 painter->setFont(f); 0395 newOpt.palette.setBrush(QPalette::Window, bg); 0396 newOpt.palette.setBrush(QPalette::Button, // needed e.g. for Plastique style 0397 bg); 0398 QProxyStyle::drawControl(element, &newOpt, painter, widget); 0399 painter->setFont(origFont); 0400 if (!mouseOver || tbar->mainMenuVisible() || styleName == "gtk+") { 0401 return; 0402 } 0403 } 0404 if (index > 0 || mouseOver) { 0405 const QPalette::ColorGroup hbGroup = (styleName == "oxygen") 0406 ? QPalette::Active : QPalette::Inactive; 0407 const QBrush hb(newOpt.palette.brush(hbGroup, QPalette::Highlight)); 0408 newOpt.palette.setBrush(QPalette::Window, hb); 0409 newOpt.palette.setBrush(QPalette::Button, hb); // needed e.g. for Plastique style 0410 if (mouseOver && (index != tbar->currentIndex() || tbar->mainMenuVisible())) { 0411 // use lower opacity for diplaying hovered tabs 0412 origOpacity = painter->opacity(); 0413 painter->setOpacity(styleName == "qtcurve" ? 0.2 : 0.3); 0414 newOpt.state |= State_Selected; 0415 } 0416 else { 0417 if (!specificStyle) { 0418 newOpt.palette.setBrush(QPalette::WindowText, 0419 newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText)); 0420 newOpt.palette.setBrush(QPalette::ButtonText, 0421 newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText)); 0422 } 0423 } 0424 if (index == tbar->currentIndex() && styleName == "qtcurve") { 0425 origOpacity = painter->opacity(); 0426 painter->setOpacity(0.5); 0427 } 0428 (newOpt.state |= State_Active) ^= State_Active; 0429 QProxyStyle::drawControl(element, &newOpt, painter, widget); 0430 if (origOpacity != -1.0) { 0431 // restore opacity and draw labels using full this opacity 0432 painter->setOpacity(origOpacity); 0433 if (index > 0) { 0434 QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget); 0435 } 0436 } 0437 return; 0438 } 0439 } 0440 } 0441 else if (element == CE_ToolBar) { 0442 return; 0443 } 0444 QProxyStyle::drawControl(element, option, painter, widget); 0445 } 0446 0447 void KexiTabbedToolBarStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, 0448 QPainter *painter, const QWidget *widget) const 0449 { 0450 const QString styleName(baseStyle()->objectName()); 0451 if (element == PE_FrameTabWidget) { 0452 return; 0453 } 0454 if (element == PE_FrameTabBarBase) { 0455 const QTabBar* tabBar = qobject_cast<const QTabBar*>(widget); 0456 KexiTabbedToolBar* tbar = tabBar 0457 ? qobject_cast<KexiTabbedToolBar*>(tabBar->parentWidget()) : 0; 0458 if (tbar && tbar->mainMenuVisible() && styleName != "bespin") { 0459 return; 0460 } 0461 } 0462 if (element == QStyle::PE_PanelToolBar || element == QStyle::PE_FrameMenu) { 0463 return; 0464 } 0465 QProxyStyle::drawPrimitive(element, option, painter, widget); 0466 } 0467 0468 int KexiTabbedToolBarStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, 0469 const QWidget* widget) const 0470 { 0471 if (metric == QStyle::PM_SmallIconSize) 0472 return KIconLoader::SizeMedium; 0473 return QProxyStyle::pixelMetric(metric, option, widget); 0474 } 0475 0476 // --- 0477 0478 KexiTabbedToolBarTabBar::KexiTabbedToolBarTabBar(QWidget *parent) 0479 : QTabBar(parent) 0480 { 0481 setObjectName("tabbar"); 0482 customStyle = new KexiTabbedToolBarStyle(style()->objectName()); 0483 customStyle->setParent(this); 0484 setStyle(customStyle); 0485 installEventFilter(parent); 0486 QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); 0487 mainWindow->installEventFilter(parent); 0488 setAttribute(Qt::WA_Hover, true); 0489 } 0490 0491 QSize KexiTabbedToolBarTabBar::originalTabSizeHint(int index) const 0492 { 0493 return QTabBar::tabSizeHint(index); 0494 } 0495 0496 QSize KexiTabbedToolBarTabBar::tabSizeHint(int index) const 0497 { 0498 QSize s = QTabBar::tabSizeHint(index); 0499 QStyleOptionTab ot; 0500 ot.initFrom(this); 0501 QFont f(font()); 0502 f.setBold(true); 0503 ot.text = (isSpecificTabStyle(customStyle->baseStyle()->objectName()) ? " " : "") + tabText(index); 0504 ot.fontMetrics = QFontMetrics(f); 0505 int w = customStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, &ot, this); 0506 if (w <= 0) { // needed e.g. for oxygen 0507 w = fontMetrics().width(" "); 0508 } 0509 if (index == 0) { 0510 s.setWidth(QFontMetrics(f).width(ot.text) + w * 2); 0511 return s; 0512 } 0513 else if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) { 0514 // fix width of the spacer tab 0515 s.setWidth(w); 0516 } 0517 return s; 0518 } 0519 0520 void KexiTabbedToolBar::Private::toggleMainMenu() 0521 { 0522 if (q->mainMenuVisible()) 0523 hideMainMenu(); 0524 else 0525 showMainMenu(); 0526 } 0527 0528 void KexiTabbedToolBar::Private::showMainMenu(const char* actionName) 0529 { 0530 QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); 0531 if (!mainMenu) { 0532 mainMenu = new KexiMainMenu(q, mainWindow); 0533 connect(mainMenu, SIGNAL(contentAreaPressed()), this, SLOT(hideMainMenu())); 0534 connect(mainMenu, SIGNAL(hideContentsRequested()), this, SLOT(hideContentsOrMainMenu())); 0535 } 0536 updateMainMenuGeometry(); 0537 if (actionName) { 0538 q->selectMainMenuItem(actionName); 0539 } 0540 else { 0541 mainMenu->selectFirstItem(); 0542 } 0543 mainMenu->show(); 0544 mainMenu->setFocus(); 0545 q->update(); // tab bar could have a line that should be repainted 0546 } 0547 0548 void KexiTabbedToolBar::Private::updateMainMenuGeometry() 0549 { 0550 if (!mainMenu) 0551 return; 0552 QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); 0553 KexiTabbedToolBarTabBar *tabBar = static_cast<KexiTabbedToolBarTabBar*>(q->tabBar()); 0554 QPoint pos = q->mapToGlobal(QPoint(0, tabBar->originalTabSizeHint(0).height() - 1)); 0555 // qDebug() << "1." << pos; 0556 pos = mainWindow->mapFromGlobal(pos); 0557 // qDebug() << "2." << pos; 0558 // qDebug() << "3." << q->pos(); 0559 0560 QStyleOptionTab ot; 0561 ot.initFrom(tabBar); 0562 int overlap = tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &ot, tabBar) 0563 - tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseHeight, &ot, tabBar); 0564 // qDebug() << "4. overlap=" << overlap; 0565 0566 mainMenu->setGeometry(0, pos.y() - overlap /*- q->y()*/, 0567 mainWindow->width(), 0568 mainWindow->height() - pos.y() + overlap /*+ q->y()*/); 0569 } 0570 0571 void KexiTabbedToolBar::Private::initSearchLineEdit() 0572 { 0573 //! @todo use KexiConfig 0574 KConfigGroup mainWindowGroup(KSharedConfig::openConfig()->group("MainWindow")); 0575 const bool enabled = mainWindowGroup.readEntry("GlobalSearchBoxEnabled", true); 0576 if (enabled && !searchLineEdit) { 0577 searchLineEdit = new KexiSearchLineEdit; 0578 kexiTester() << KexiTestObject(searchLineEdit, "globalSearch.lineEdit"); 0579 searchLineEdit->installEventFilter(q); 0580 helpLayer->addWidget(searchLineEdit); 0581 } else if (!enabled && searchLineEdit) { 0582 helpLayer->removeWidget(searchLineEdit); 0583 delete searchLineEdit; 0584 searchLineEdit = nullptr; 0585 } 0586 } 0587 0588 void KexiTabbedToolBar::activateSearchLineEdit() 0589 { 0590 if (!d->searchLineEdit) { 0591 return; 0592 } 0593 d->searchLineEdit->selectAll(); 0594 d->searchLineEdit->setFocus(); 0595 } 0596 0597 void KexiTabbedToolBar::Private::hideMainMenu() 0598 { 0599 if (!mainMenu || !mainMenu->isVisible()) 0600 return; 0601 mainMenu->hide(); 0602 mainMenu->setContent(0); 0603 q->update(); // tab bar could have a line that should be repainted 0604 } 0605 0606 void KexiTabbedToolBar::Private::hideContentsOrMainMenu() 0607 { 0608 if (!mainMenu || !mainMenu->isVisible()) 0609 return; 0610 if (mainMenu->contentWidget()) { 0611 mainMenu->setContent(0); 0612 } 0613 else { 0614 hideMainMenu(); 0615 } 0616 } 0617 0618 KToolBar *KexiTabbedToolBar::Private::createToolBar(const char *name, const QString& caption) 0619 { 0620 KToolBar *tbar = new KToolBar(q, true /*main toolbar*/, false /*read config*/); 0621 tbar->setIconDimensions(22); //!< @todo make configurable or system-dependent? 0622 // needed e.g. for Windows style to remove the toolbar's frame 0623 tbar->setStyle(customTabBar->customStyle); 0624 toolbarsForName.insert(name, tbar); 0625 tbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); 0626 tbar->setObjectName(name); 0627 toolbarsCaptionForName.insert(name, caption); 0628 tabIndex = q->addTab(tbar, caption); 0629 toolbarsVisibleForIndex.append(true); 0630 toolbarsIndexForName.insert(name, tabIndex); 0631 return tbar; 0632 } 0633 0634 KexiTabbedToolBar::KexiTabbedToolBar(QWidget *parent) 0635 : QTabWidget(parent) 0636 , d(new Private(this)) 0637 { 0638 d->customTabBar = new KexiTabbedToolBarTabBar(this); 0639 setTabBar(d->customTabBar); 0640 setStyle(d->customTabBar->customStyle); 0641 0642 // from ktabwidget.cpp 0643 //! @todo QTabWidget::setTabBar() should be added with this code 0644 //! @todo KEXI3 Are these tabBar() connections useful to port? 0645 #if 0 0646 connect(tabBar(), SIGNAL(contextMenu(int,QPoint)), SLOT(contextMenu(int,QPoint&))); 0647 connect(tabBar(), SIGNAL(tabDoubleClicked(int)), SLOT(mouseDoubleClick(int))); 0648 connect(tabBar(), SIGNAL(newTabRequest()), this, SIGNAL(mouseDoubleClick())); // #185487 0649 connect(tabBar(), SIGNAL(mouseMiddleClick(int)), SLOT(mouseMiddleClick(int))); 0650 connect(tabBar(), SIGNAL(initiateDrag( int )), SLOT(initiateDrag( int ))); 0651 connect(tabBar(), SIGNAL(testCanDecode(QDragMoveEvent*,bool*)), SIGNAL(testCanDecode(QDragMoveEvent*,bool*))); 0652 connect(tabBar(), SIGNAL(receivedDropEvent(int,QDropEvent*)), SLOT(receivedDropEvent(int,QDropEvent*))); 0653 connect(tabBar(), SIGNAL(moveTab(int,int)), SLOT(moveTab(int,int))); 0654 connect(tabBar(), SIGNAL(tabCloseRequested(int)), SLOT(closeRequest(int))); 0655 #endif 0656 0657 setMouseTracking(true); // for mouseMoveEvent() 0658 setWhatsThis(xi18n("Task-oriented toolbar. Groups commands using tabs.")); 0659 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR 0660 connect(&d->tabRaiseTimer, SIGNAL(timeout()), this, SLOT(slotDelayedTabRaise())); 0661 #endif 0662 connect(tabBar(), SIGNAL(tabBarDoubleClicked(int)), this, SLOT(slotTabDoubleClicked(int))); 0663 0664 d->ac = KexiMainWindowIface::global()->actionCollection(); 0665 QWidget *mainWin = KexiMainWindowIface::global()->thisWidget(); 0666 const bool userMode = KexiMainWindowIface::global()->userMode(); 0667 KToolBar *tbar; 0668 0669 slotSettingsChanged(0);//KGlobalSettings::FontChanged 0670 //! @todo KEXI3 port from KGlobalSettings::Private::_k_slotNotifyChange: 0671 //! connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(slotSettingsChanged(int))); 0672 0673 // help area 0674 QWidget *helpWidget = new QWidget(this); 0675 helpWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); 0676 d->helpLayer = new QHBoxLayout(helpWidget); 0677 d->helpLayer->setContentsMargins(0, 0, 0, 0); 0678 0679 // * HELP MENU 0680 // add help menu actions... (KexiTabbedToolBar depends on them) 0681 d->helpMenu = new KHelpMenu(this, KAboutData::applicationData(), 0682 true/*showWhatsThis*/); 0683 QAction* help_report_bug_action = d->helpMenu->action(KHelpMenu::menuReportBug); 0684 d->ac->addAction(help_report_bug_action->objectName(), help_report_bug_action); 0685 QObject::disconnect(help_report_bug_action, 0, 0, 0); 0686 QObject::connect(help_report_bug_action, SIGNAL(triggered()), mainWin, SLOT(slotReportBug())); 0687 help_report_bug_action->setText(xi18nc("Report a bug or wish for Kexi application", "Report a &Bug or Wish...")); 0688 help_report_bug_action->setIcon(koIcon("tools-report-bug")); // good icon for toolbar 0689 help_report_bug_action->setWhatsThis(xi18n("Files a bug or wish for Kexi application.")); 0690 QAction* help_whats_this_action = d->helpMenu->action(KHelpMenu::menuWhatsThis); 0691 d->ac->addAction(help_whats_this_action->objectName(), help_whats_this_action); 0692 help_whats_this_action->setWhatsThis(xi18n("Activates a \"What's This?\" tool.")); 0693 QAction* help_contents_action = d->helpMenu->action(KHelpMenu::menuHelpContents); 0694 d->ac->addAction(help_contents_action->objectName(), help_contents_action); 0695 help_contents_action->setText(xi18n("Help")); 0696 help_contents_action->setWhatsThis(xi18n("Shows Kexi Handbook.")); 0697 QAction* help_about_app_action = d->helpMenu->action(KHelpMenu::menuAboutApp); 0698 d->ac->addAction(help_about_app_action->objectName(), help_about_app_action); 0699 help_about_app_action->setWhatsThis(xi18n("Shows information about Kexi application.")); 0700 QAction* help_about_kde_action = d->helpMenu->action(KHelpMenu::menuAboutKDE); 0701 d->ac->addAction(help_about_kde_action->objectName(), help_about_kde_action); 0702 help_about_kde_action->setWhatsThis(xi18n("Shows information about KDE.")); 0703 QAction* help_switch_language_action = d->helpMenu->action(KHelpMenu::menuSwitchLanguage); 0704 if (help_switch_language_action) { 0705 d->ac->addAction(help_switch_language_action->objectName(), help_switch_language_action); 0706 } 0707 // extra action such as help_donate may be confusing for the user or conflicting with existing so hide it 0708 QAction *extraAction = d->helpMenu->action(static_cast<KHelpMenu::MenuId>(KHelpMenu::menuSwitchLanguage + 1)); 0709 if (extraAction) { 0710 extraAction->setVisible(false); 0711 } 0712 0713 QAction *action_show_help_menu = d->ac->action("help_show_menu"); 0714 KexiSmallToolButton *btn = new KexiSmallToolButton(koIcon("help-about"), QString(), helpWidget); 0715 btn->setToolButtonStyle(Qt::ToolButtonIconOnly); 0716 btn->setPopupMode(QToolButton::InstantPopup); 0717 btn->setToolTip(action_show_help_menu->toolTip()); 0718 btn->setWhatsThis(action_show_help_menu->whatsThis()); 0719 btn->setFocusPolicy(Qt::NoFocus); 0720 QStyleOptionToolButton opt; 0721 opt.initFrom(btn); 0722 int w = btn->sizeHint().width(); 0723 int wAdd = btn->style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, btn); 0724 if (w <= (2 * (wAdd + 1))) { 0725 w += wAdd + 2; 0726 } 0727 btn->setMinimumWidth(w); 0728 connect(action_show_help_menu, SIGNAL(triggered()), btn, SLOT(showMenu())); 0729 d->helpLayer->addWidget(btn); 0730 btn->setMenu(d->helpMenu->menu()); 0731 setCornerWidget(helpWidget, Qt::TopRightCorner); 0732 d->initSearchLineEdit(); 0733 0734 // needed e.g. for Windows style to remove the toolbar's frame 0735 QWidget *dummyWidgetForMainMenu = new QWidget(this); 0736 dummyWidgetForMainMenu->setObjectName("kexi"); 0737 addTab(dummyWidgetForMainMenu, KAboutData::applicationData().displayName()); 0738 d->toolbarsVisibleForIndex.append(true); 0739 addTab(new QWidget(this), QString()); // dummy for spacer 0740 d->toolbarsVisibleForIndex.append(true); 0741 0742 if (!userMode) { 0743 d->createWidgetToolBar = d->createToolBar("create", xi18n("Create")); 0744 } 0745 0746 tbar = d->createToolBar("data", xi18n("Data")); 0747 addAction(tbar, "edit_cut"); 0748 addAction(tbar, "edit_copy"); 0749 addAction(tbar, "edit_paste"); 0750 if (!userMode) 0751 addAction(tbar, "edit_paste_special_data_table"); 0752 //! @todo move undo/redo to quickbar: 0753 0754 tbar = d->createToolBar("external", xi18n("External Data")); 0755 if (!userMode) { 0756 addAction(tbar, "project_import_data_table"); 0757 addAction(tbar, "tools_import_tables"); 0758 } 0759 0760 tbar = d->createToolBar("tools", xi18n("Tools")); 0761 addAction(tbar, "tools_compact_database"); 0762 0763 //! @todo move to form plugin 0764 tbar = d->createToolBar("form", xi18n("Form Design")); 0765 0766 //! @todo move to report plugin 0767 tbar = d->createToolBar("report", xi18n("Report Design")); 0768 0769 connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int))); 0770 setCurrentWidget(widget(KEXITABBEDTOOLBAR_SPACER_TAB_INDEX + 1)); // the default 0771 setFocusPolicy(Qt::NoFocus); 0772 } 0773 0774 void KexiTabbedToolBar::Private::setCurrentTab(const QString& name) 0775 { 0776 q->setCurrentWidget(q->toolBar(name)); 0777 } 0778 0779 void KexiTabbedToolBar::Private::hideTab(const QString& name) 0780 { 0781 q->removeTab(q->indexOf(toolbarsForName.value(name))); 0782 toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = false; 0783 } 0784 0785 bool KexiTabbedToolBar::Private::isTabVisible(const QString& name) const 0786 { 0787 return q->indexOf(toolbarsForName.value(name)) != -1 0788 && toolbarsVisibleForIndex[toolbarsIndexForName.value(name)]; 0789 } 0790 0791 #ifndef NDEBUG 0792 void KexiTabbedToolBar::Private::debugToolbars() const 0793 { 0794 qDebug() << "QHash<QString, KToolBar*> toolbarsForName:"; 0795 for (QHash<QString, KToolBar*>::ConstIterator it(toolbarsForName.constBegin()); 0796 it!=toolbarsForName.constEnd(); ++it) 0797 { 0798 qDebug() << it.key() << "->" << it.value(); 0799 } 0800 qDebug() << "QHash<QString, int> toolbarsIndexForName:"; 0801 for (QHash<QString, int>::ConstIterator it(toolbarsIndexForName.constBegin()); 0802 it!=toolbarsIndexForName.constEnd(); ++it) 0803 { 0804 qDebug() << it.key() << "->" << it.value(); 0805 } 0806 qDebug() << "QHash<QString, QString> toolbarsCaptionForName:"; 0807 for (QHash<QString, QString>::ConstIterator it(toolbarsCaptionForName.constBegin()); 0808 it!=toolbarsCaptionForName.constEnd(); ++it) 0809 { 0810 qDebug() << it.key() << "->" << it.value(); 0811 } 0812 qDebug() << "QVector<bool> toolbarsVisibleForIndex:"; 0813 for (int i = 0; i < toolbarsVisibleForIndex.size(); i++) { 0814 qDebug() << i << "->" << toolbarsVisibleForIndex[i]; 0815 } 0816 } 0817 #endif 0818 0819 void KexiTabbedToolBar::Private::showTab(const QString& name) 0820 { 0821 // qDebug() << "name:" << name; 0822 // qDebug() << "toolbarsForName.value(name):" << toolbarsForName.value(name); 0823 // qDebug() << "toolbarsIndexForName.value(name):" << toolbarsIndexForName.value(name); 0824 // qDebug() << "q->indexOf(toolbarsForName.value(name))" << q->indexOf(toolbarsForName.value(name)); 0825 #ifndef NDEBUG 0826 //debugToolbars(); 0827 #endif 0828 if (q->indexOf(toolbarsForName.value(name)) == -1) { 0829 int h = 0; 0830 // count h = invisible tabs before this 0831 for (int i = lowestIndex; i < toolbarsIndexForName.value(name); i++) { 0832 if (!toolbarsVisibleForIndex.at(i)) 0833 h++; 0834 } 0835 q->insertTab(toolbarsIndexForName.value(name) - h, 0836 toolbarsForName.value(name), toolbarsCaptionForName.value(name)); 0837 toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = true; 0838 } 0839 } 0840 0841 // --- 0842 0843 KexiTabbedToolBar::~KexiTabbedToolBar() 0844 { 0845 delete d; 0846 } 0847 0848 bool KexiTabbedToolBar::mainMenuVisible() const 0849 { 0850 return d->mainMenu && d->mainMenu->isVisible(); 0851 } 0852 0853 QRect KexiTabbedToolBar::tabRect(int index) const 0854 { 0855 return tabBar()->tabRect(index); 0856 } 0857 0858 KHelpMenu* KexiTabbedToolBar::helpMenu() const 0859 { 0860 return d->helpMenu; 0861 } 0862 0863 void KexiTabbedToolBar::slotSettingsChanged(int category) 0864 { 0865 Q_UNUSED(category); 0866 //! @todo if (category == KGlobalSettings::FontChanged) { 0867 //! @todo KEXI3 KGlobalSettings::menuFont() not available (using QFontDatabase::systemFont(QFontDatabase::GeneralFont) for now) 0868 //! https://community.kde.org/Frameworks/Porting_Notes#Global_Settings 0869 setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); // the toolbar acts like a menu 0870 //} 0871 } 0872 0873 KToolBar* KexiTabbedToolBar::createWidgetToolBar() const 0874 { 0875 return d->createWidgetToolBar; 0876 } 0877 0878 void KexiTabbedToolBar::mouseMoveEvent(QMouseEvent* event) 0879 { 0880 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR 0881 QPoint p = event->pos(); 0882 int tab = tabBar()->tabAt(p); 0883 if (d->tabToRaise != -1 && (tab == -1 || tab == currentIndex())) { 0884 d->tabRaiseTimer.stop(); 0885 d->tabToRaise = -1; 0886 } else if (d->tabToRaise != tab) { 0887 d->tabRaiseTimer.start(); 0888 0889 d->tabToRaise = tab; 0890 } 0891 #endif 0892 QTabWidget::mouseMoveEvent(event); 0893 } 0894 0895 void KexiTabbedToolBar::leaveEvent(QEvent* event) 0896 { 0897 #ifdef KEXI_AUTORISE_TABBED_TOOLBAR 0898 d->tabRaiseTimer.stop(); 0899 d->tabToRaise = -1; 0900 #endif 0901 QTabWidget::leaveEvent(event); 0902 } 0903 0904 bool KexiTabbedToolBar::eventFilter(QObject* watched, QEvent* event) 0905 { 0906 switch (event->type()) { 0907 case QEvent::MouseButtonPress: { 0908 QWidget *mainWin = KexiMainWindowIface::global()->thisWidget(); 0909 // qDebug() << "MouseButtonPress: watched:" << watched << "window()->focusWidget():" << window()->focusWidget(); 0910 if (d->searchLineEdit && watched == d->searchLineEdit) { 0911 activateSearchLineEdit(); // custom setFocus() for search box, so it's possible to focus 0912 // back on Escape key press 0913 return false; 0914 } 0915 else if (watched == tabBar()) { 0916 QMouseEvent* me = static_cast<QMouseEvent*>(event); 0917 QPoint p = me->pos(); 0918 KexiTabbedToolBarTabBar *tb = static_cast<KexiTabbedToolBarTabBar*>(tabBar()); 0919 int index = tb->tabAt(p); 0920 if (index == 0) { 0921 d->toggleMainMenu(); 0922 return true; 0923 } 0924 d->hideMainMenu(); 0925 if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) { 0926 return true; 0927 } 0928 } 0929 else if (watched == mainWin && d->mainMenu) { 0930 QMouseEvent* me = static_cast<QMouseEvent*>(event); 0931 if (!QRect(d->mainMenu->mapToGlobal(QPoint(0,0)), d->mainMenu->size()) 0932 .contains(mainWin->mapToGlobal(me->pos()))) 0933 { 0934 // hide if clicked outside of the menu 0935 d->hideMainMenu(); 0936 } 0937 } 0938 } 0939 break; 0940 case QEvent::KeyPress: { 0941 QKeyEvent* ke = static_cast<QKeyEvent*>(event); 0942 // qDebug() << "**********" << QString::number(ke->key(), 16) 0943 // << QKeySequence::mnemonic(tabText(0))[0]; 0944 if (QKeySequence::mnemonic(tabText(0)) == QKeySequence(ke->key())) { 0945 // qDebug() << "eat the &File accel"; 0946 if (!d->mainMenu || !d->mainMenu->isVisible()) { 0947 d->showMainMenu(); 0948 } 0949 /*this could be unexpected: 0950 else if (d->mainMenu && d->mainMenu->isVisible()) { 0951 d->hideMainMenu(); 0952 }*/ 0953 return true; 0954 } 0955 if (d->mainMenu && d->mainMenu->isVisible() && (ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) { 0956 d->hideContentsOrMainMenu(); 0957 return true; 0958 } 0959 break; 0960 } 0961 case QEvent::Resize: 0962 if (watched == KexiMainWindowIface::global()->thisWidget()) { 0963 d->updateMainMenuGeometry(); 0964 } 0965 break; 0966 case QEvent::Shortcut: { 0967 QShortcutEvent *se = static_cast<QShortcutEvent*>(event); 0968 if (watched == tabBar() && QKeySequence::mnemonic(tabText(0)) == se->key()) { 0969 // qDebug() << "eat the &File accel"; 0970 if (!d->mainMenu || !d->mainMenu->isVisible()) { 0971 d->showMainMenu(); 0972 return true; 0973 } 0974 } 0975 break; 0976 } 0977 default:; 0978 } 0979 return QTabWidget::eventFilter(watched, event); 0980 } 0981 0982 void KexiTabbedToolBar::slotCurrentChanged(int index) 0983 { 0984 if (index == indexOf(d->createWidgetToolBar) && index != -1) { 0985 if (d->createWidgetToolBar->actions().isEmpty()) { 0986 QTimer::singleShot(10, this, SLOT(setupCreateWidgetToolbar())); 0987 } 0988 } 0989 if (d->rolledUp) { // switching the tab rolls down 0990 slotTabDoubleClicked(index); 0991 } 0992 if (index == 0) { // main menu 0993 d->showMainMenu(); 0994 } 0995 else { 0996 d->hideMainMenu(); 0997 } 0998 } 0999 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 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 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 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 1077 KToolBar *KexiTabbedToolBar::toolBar(const QString& name) const 1078 { 1079 return d->toolbarsForName[name]; 1080 } 1081 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 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 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 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 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 1127 void KexiTabbedToolBar::showMainMenu(const char* actionName) 1128 { 1129 d->showMainMenu(actionName); 1130 } 1131 1132 void KexiTabbedToolBar::hideMainMenu() 1133 { 1134 d->hideMainMenu(); 1135 } 1136 1137 void KexiTabbedToolBar::toggleMainMenu() 1138 { 1139 d->toggleMainMenu(); 1140 } 1141 1142 void KexiTabbedToolBar::setMainMenuContent(QWidget *w) 1143 { 1144 d->mainMenu->setContent(w); 1145 } 1146 1147 const QWidget* KexiTabbedToolBar::mainMenuContent() 1148 { 1149 return d->mainMenu->contentWidget(); 1150 } 1151 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 1163 void KexiTabbedToolBar::addSearchableModel(KexiSearchableModel *model) 1164 { 1165 if (!d->searchLineEdit) { 1166 return; 1167 } 1168 d->searchLineEdit->addSearchableModel(model); 1169 } 1170 1171 void KexiTabbedToolBar::removeSearchableModel(KexiSearchableModel *model) 1172 { 1173 if (!d->searchLineEdit) { 1174 return; 1175 } 1176 d->searchLineEdit->removeSearchableModel(model); 1177 } 1178 1179 KToolBar* KexiTabbedToolBar::createToolBar(const char* name, const QString& caption) 1180 { 1181 return d->createToolBar(name, caption); 1182 } 1183 1184 void KexiTabbedToolBar::setCurrentTab(const QString& name) 1185 { 1186 //qDebug() << name; 1187 d->setCurrentTab(name); 1188 } 1189 1190 void KexiTabbedToolBar::setCurrentTab(int index) 1191 { 1192 setCurrentIndex(d->lowestIndex + index); 1193 } 1194 1195 void KexiTabbedToolBar::hideTab(const QString& name) 1196 { 1197 //qDebug() << name; 1198 d->hideTab(name); 1199 } 1200 1201 void KexiTabbedToolBar::showTab(const QString& name) 1202 { 1203 //qDebug() << name; 1204 d->showTab(name); 1205 } 1206 1207 bool KexiTabbedToolBar::isTabVisible(const QString& name) const 1208 { 1209 return d->isTabVisible(name); 1210 } 1211 1212 bool KexiTabbedToolBar::isRolledUp() 1213 { 1214 return d->rolledUp; 1215 } 1216 1217 void KexiTabbedToolBar::toggleRollDown() 1218 { 1219 slotTabDoubleClicked(-1);//use -1 just to rolldown/up the tabbar 1220 } 1221 1222 // --- 1223 1224 KexiMainWidget::KexiMainWidget() 1225 : KMainWindow(0, Qt::Widget) 1226 , m_mainWindow(0) 1227 { 1228 setupCentralWidget(); 1229 } 1230 1231 KexiMainWidget::~KexiMainWidget() 1232 { 1233 } 1234 1235 void KexiMainWidget::setParent(KexiMainWindow* mainWindow) 1236 { 1237 KMainWindow::setParent(mainWindow); 1238 m_mainWindow = mainWindow; 1239 } 1240 1241 KexiMainWindowTabWidget* KexiMainWidget::tabWidget() const 1242 { 1243 return m_tabWidget; 1244 } 1245 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 1260 bool KexiMainWidget::queryClose() 1261 { 1262 return m_mainWindow ? m_mainWindow->queryClose() : true; 1263 } 1264 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 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 1325 KexiMainWindow::Private::~Private() 1326 { 1327 qDeleteAll(m_openedCustomObjectsForItem); 1328 } 1329 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 1339 bool KexiMainWindow::Private::windowContainerExistsFor(int identifier) const 1340 { 1341 return windowContainers.contains(identifier); 1342 } 1343 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 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 1364 void KexiMainWindow::Private::removeWindow(int identifier) 1365 { 1366 //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); 1367 windows.remove(identifier); 1368 } 1369 1370 int KexiMainWindow::Private::openedWindowsCount() 1371 { 1372 //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); 1373 return windows.count(); 1374 } 1375 1376 //! Used in KexiMainWindowe::closeProject() 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 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 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 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 1436 void KexiMainWindow::Private::setPropertyEditorTabBarVisible(bool visible) 1437 { 1438 setTabBarVisible(KMultiTabBar::Right, PROPERTY_EDITOR_TABBAR_ID, 1439 propEditorDockWidget, visible); 1440 } 1441 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 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 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 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 1499 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 1512 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 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 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 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 1589 KexiWindow *KexiMainWindow::Private::openedWindowFor(const KexiPart::Item* item, PendingJobType &pendingType) 1590 { 1591 return openedWindowFor(item->identifier(), pendingType); 1592 } 1593 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 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 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 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 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