File indexing completed on 2024-12-01 12:40:41
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2000 Reginald Stadlbauer <reggie@kde.org> 0004 SPDX-FileCopyrightText: 1997, 1998 Stephan Kulow <coolo@kde.org> 0005 SPDX-FileCopyrightText: 1997, 1998 Mark Donohoe <donohoe@kde.org> 0006 SPDX-FileCopyrightText: 1997, 1998 Sven Radej <radej@kde.org> 0007 SPDX-FileCopyrightText: 1997, 1998 Matthias Ettrich <ettrich@kde.org> 0008 SPDX-FileCopyrightText: 1999 Chris Schlaeger <cs@kde.org> 0009 SPDX-FileCopyrightText: 1999 Kurt Granroth <granroth@kde.org> 0010 SPDX-FileCopyrightText: 2005-2006 Hamish Rodda <rodda@kde.org> 0011 0012 SPDX-License-Identifier: LGPL-2.0-only 0013 */ 0014 0015 #include "ktoolbar.h" 0016 0017 #include <QAction> 0018 #include <QActionGroup> 0019 #include <QApplication> 0020 #include <QDomElement> 0021 #include <QDrag> 0022 #include <QFrame> 0023 #include <QLayout> 0024 #include <QMenu> 0025 #include <QMimeData> 0026 #include <QMouseEvent> 0027 #include <QPointer> 0028 #ifdef QT_DBUS_LIB 0029 #include <QDBusConnection> 0030 #include <QDBusMessage> 0031 #endif 0032 0033 #include <KAuthorized> 0034 #include <KConfig> 0035 #include <KConfigGroup> 0036 #include <KIconTheme> 0037 #include <KLocalizedString> 0038 #include <KSharedConfig> 0039 #include <KStandardAction> 0040 #include <KToggleAction> 0041 0042 #include "kactioncollection.h" 0043 #include "kedittoolbar.h" 0044 #include "kxmlguifactory.h" 0045 #include "kxmlguiwindow.h" 0046 0047 #include "ktoolbarhelper_p.h" 0048 0049 /* 0050 Toolbar settings (e.g. icon size or toolButtonStyle) 0051 ===================================================== 0052 0053 We have the following stack of settings (in order of priority) : 0054 - user-specified settings (loaded/saved in KConfig) 0055 - developer-specified settings in the XMLGUI file (if using xmlgui) (cannot change at runtime) 0056 - KDE-global default (user-configurable; can change at runtime) 0057 and when switching between kparts, they are saved as xml in memory, 0058 which, in the unlikely case of no-kmainwindow-autosaving, could be 0059 different from the user-specified settings saved in KConfig and would have 0060 priority over it. 0061 0062 So, in summary, without XML: 0063 Global config / User settings (loaded/saved in kconfig) 0064 and with XML: 0065 Global config / App-XML attributes / User settings (loaded/saved in kconfig) 0066 0067 And all those settings (except the KDE-global defaults) have to be stored in memory 0068 since we cannot retrieve them at random points in time, not knowing the xml document 0069 nor config file that holds these settings. Hence the iconSizeSettings and toolButtonStyleSettings arrays. 0070 0071 For instance, if you change the KDE-global default, whether this makes a change 0072 on a given toolbar depends on whether there are settings at Level_AppXML or Level_UserSettings. 0073 Only if there are no settings at those levels, should the change of KDEDefault make a difference. 0074 */ 0075 enum SettingLevel { Level_KDEDefault, Level_AppXML, Level_UserSettings, NSettingLevels }; 0076 enum { Unset = -1 }; 0077 0078 class KToolBarPrivate 0079 { 0080 public: 0081 KToolBarPrivate(KToolBar *qq) 0082 : q(qq) 0083 , isMainToolBar(false) 0084 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0) 0085 , enableContext(true) 0086 #endif 0087 , unlockedMovable(true) 0088 , contextOrient(nullptr) 0089 , contextMode(nullptr) 0090 , contextSize(nullptr) 0091 , contextButtonTitle(nullptr) 0092 , contextShowText(nullptr) 0093 , contextButtonAction(nullptr) 0094 , contextTop(nullptr) 0095 , contextLeft(nullptr) 0096 , contextRight(nullptr) 0097 , contextBottom(nullptr) 0098 , contextIcons(nullptr) 0099 , contextTextRight(nullptr) 0100 , contextText(nullptr) 0101 , contextTextUnder(nullptr) 0102 , contextLockAction(nullptr) 0103 , dropIndicatorAction(nullptr) 0104 , context(nullptr) 0105 , dragAction(nullptr) 0106 { 0107 } 0108 0109 void slotAppearanceChanged(); 0110 void slotContextAboutToShow(); 0111 void slotContextAboutToHide(); 0112 void slotContextLeft(); 0113 void slotContextRight(); 0114 void slotContextShowText(); 0115 void slotContextTop(); 0116 void slotContextBottom(); 0117 void slotContextIcons(); 0118 void slotContextText(); 0119 void slotContextTextRight(); 0120 void slotContextTextUnder(); 0121 void slotContextIconSize(QAction *action); 0122 void slotLockToolBars(bool lock); 0123 0124 void init(bool readConfig = true, bool isMainToolBar = false); 0125 QString getPositionAsString() const; 0126 QMenu *contextMenu(const QPoint &globalPos); 0127 void setLocked(bool locked); 0128 void adjustSeparatorVisibility(); 0129 void loadKDESettings(); 0130 void applyCurrentSettings(); 0131 0132 QAction *findAction(const QString &actionName, KXMLGUIClient **client = nullptr) const; 0133 0134 static Qt::ToolButtonStyle toolButtonStyleFromString(const QString &style); 0135 static QString toolButtonStyleToString(Qt::ToolButtonStyle); 0136 static Qt::ToolBarArea positionFromString(const QString &position); 0137 static Qt::ToolButtonStyle toolButtonStyleSetting(); 0138 0139 KToolBar *const q; 0140 bool isMainToolBar : 1; 0141 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0) 0142 bool enableContext : 1; 0143 #endif 0144 bool unlockedMovable : 1; 0145 static bool s_editable; 0146 static bool s_locked; 0147 0148 QSet<KXMLGUIClient *> xmlguiClients; 0149 0150 QMenu *contextOrient; 0151 QMenu *contextMode; 0152 QMenu *contextSize; 0153 0154 QAction *contextButtonTitle; 0155 QAction *contextShowText; 0156 QAction *contextButtonAction; 0157 QAction *contextTop; 0158 QAction *contextLeft; 0159 QAction *contextRight; 0160 QAction *contextBottom; 0161 QAction *contextIcons; 0162 QAction *contextTextRight; 0163 QAction *contextText; 0164 QAction *contextTextUnder; 0165 KToggleAction *contextLockAction; 0166 0167 struct ContextIconInfo { 0168 QAction *iconAction = nullptr; 0169 int iconSize = 0; 0170 }; 0171 0172 std::vector<ContextIconInfo> m_contextIconSizes; 0173 0174 class IntSetting 0175 { 0176 public: 0177 IntSetting() 0178 { 0179 for (int &value : values) { 0180 value = Unset; 0181 } 0182 } 0183 int currentValue() const 0184 { 0185 int val = Unset; 0186 for (int value : values) { 0187 if (value != Unset) { 0188 val = value; 0189 } 0190 } 0191 return val; 0192 } 0193 // Default value as far as the user is concerned is kde-global + app-xml. 0194 // If currentValue()==defaultValue() then nothing to write into kconfig. 0195 int defaultValue() const 0196 { 0197 int val = Unset; 0198 for (int level = 0; level < Level_UserSettings; ++level) { 0199 if (values[level] != Unset) { 0200 val = values[level]; 0201 } 0202 } 0203 return val; 0204 } 0205 QString toString() const 0206 { 0207 QString str; 0208 for (int value : values) { 0209 str += QString::number(value) + QLatin1Char(' '); 0210 } 0211 return str; 0212 } 0213 int &operator[](int index) 0214 { 0215 return values[index]; 0216 } 0217 0218 private: 0219 int values[NSettingLevels]; 0220 }; 0221 IntSetting iconSizeSettings; 0222 IntSetting toolButtonStyleSettings; // either Qt::ToolButtonStyle or -1, hence "int". 0223 0224 QList<QAction *> actionsBeingDragged; 0225 QAction *dropIndicatorAction; 0226 0227 QMenu *context; 0228 QAction *dragAction; 0229 QPoint dragStartPosition; 0230 }; 0231 0232 bool KToolBarPrivate::s_editable = false; 0233 bool KToolBarPrivate::s_locked = true; 0234 0235 void KToolBarPrivate::init(bool readConfig, bool _isMainToolBar) 0236 { 0237 isMainToolBar = _isMainToolBar; 0238 loadKDESettings(); 0239 0240 // also read in our configurable settings (for non-xmlgui toolbars) 0241 if (readConfig) { 0242 KConfigGroup cg(KSharedConfig::openConfig(), QString()); 0243 q->applySettings(cg); 0244 } 0245 0246 if (q->mainWindow()) { 0247 // Get notified when settings change 0248 QObject::connect(q, &QToolBar::allowedAreasChanged, q->mainWindow(), &KMainWindow::setSettingsDirty); 0249 QObject::connect(q, &QToolBar::iconSizeChanged, q->mainWindow(), &KMainWindow::setSettingsDirty); 0250 QObject::connect(q, &QToolBar::toolButtonStyleChanged, q->mainWindow(), &KMainWindow::setSettingsDirty); 0251 QObject::connect(q, &QToolBar::movableChanged, q->mainWindow(), &KMainWindow::setSettingsDirty); 0252 QObject::connect(q, &QToolBar::orientationChanged, q->mainWindow(), &KMainWindow::setSettingsDirty); 0253 } 0254 0255 if (!KAuthorized::authorize(QStringLiteral("movable_toolbars"))) { 0256 q->setMovable(false); 0257 } else { 0258 q->setMovable(!KToolBar::toolBarsLocked()); 0259 } 0260 0261 q->toggleViewAction()->setEnabled(KAuthorized::authorizeAction(QStringLiteral("options_show_toolbar"))); 0262 0263 QObject::connect(q, &QToolBar::movableChanged, q, &KToolBar::slotMovableChanged); 0264 0265 q->setAcceptDrops(true); 0266 0267 #ifdef QT_DBUS_LIB 0268 QDBusConnection::sessionBus() 0269 .connect(QString(), QStringLiteral("/KToolBar"), QStringLiteral("org.kde.KToolBar"), QStringLiteral("styleChanged"), q, SLOT(slotAppearanceChanged())); 0270 #endif 0271 QObject::connect(KIconLoader::global(), &KIconLoader::iconLoaderSettingsChanged, q, [this]() { 0272 slotAppearanceChanged(); 0273 }); 0274 } 0275 0276 QString KToolBarPrivate::getPositionAsString() const 0277 { 0278 if (!q->mainWindow()) { 0279 return QStringLiteral("None"); 0280 } 0281 // get all of the stuff to save 0282 switch (q->mainWindow()->toolBarArea(const_cast<KToolBar *>(q))) { 0283 case Qt::BottomToolBarArea: 0284 return QStringLiteral("Bottom"); 0285 case Qt::LeftToolBarArea: 0286 return QStringLiteral("Left"); 0287 case Qt::RightToolBarArea: 0288 return QStringLiteral("Right"); 0289 case Qt::TopToolBarArea: 0290 default: 0291 return QStringLiteral("Top"); 0292 } 0293 } 0294 0295 QMenu *KToolBarPrivate::contextMenu(const QPoint &globalPos) 0296 { 0297 if (!context) { 0298 context = new QMenu(q); 0299 context->setIcon(QIcon::fromTheme(QStringLiteral("configure-toolbars"))); 0300 context->setTitle(i18nc("@title:menu", "Toolbar Settings")); 0301 0302 contextButtonTitle = context->addSection(i18nc("@title:menu", "Show Text")); 0303 contextShowText = context->addAction(QString(), q, [this]() { 0304 slotContextShowText(); 0305 }); 0306 0307 context->addSection(i18nc("@title:menu", "Toolbar Settings")); 0308 0309 contextOrient = new QMenu(i18nc("Toolbar orientation", "Orientation"), context); 0310 0311 contextTop = contextOrient->addAction(i18nc("toolbar position string", "Top"), q, [this]() { 0312 slotContextTop(); 0313 }); 0314 contextTop->setChecked(true); 0315 contextLeft = contextOrient->addAction(i18nc("toolbar position string", "Left"), q, [this]() { 0316 slotContextLeft(); 0317 }); 0318 contextRight = contextOrient->addAction(i18nc("toolbar position string", "Right"), q, [this]() { 0319 slotContextRight(); 0320 }); 0321 contextBottom = contextOrient->addAction(i18nc("toolbar position string", "Bottom"), q, [this]() { 0322 slotContextBottom(); 0323 }); 0324 0325 QActionGroup *positionGroup = new QActionGroup(contextOrient); 0326 const auto orientActions = contextOrient->actions(); 0327 for (QAction *action : orientActions) { 0328 action->setActionGroup(positionGroup); 0329 action->setCheckable(true); 0330 } 0331 0332 contextMode = new QMenu(i18n("Text Position"), context); 0333 0334 contextIcons = contextMode->addAction(i18nc("@item:inmenu", "Icons Only"), q, [this]() { 0335 slotContextIcons(); 0336 }); 0337 contextText = contextMode->addAction(i18nc("@item:inmenu", "Text Only"), q, [this]() { 0338 slotContextText(); 0339 }); 0340 contextTextRight = contextMode->addAction(i18nc("@item:inmenu", "Text Alongside Icons"), q, [this]() { 0341 slotContextTextRight(); 0342 }); 0343 contextTextUnder = contextMode->addAction(i18nc("@item:inmenu", "Text Under Icons"), q, [this]() { 0344 slotContextTextUnder(); 0345 }); 0346 0347 QActionGroup *textGroup = new QActionGroup(contextMode); 0348 const auto modeActions = contextMode->actions(); 0349 for (QAction *action : modeActions) { 0350 action->setActionGroup(textGroup); 0351 action->setCheckable(true); 0352 } 0353 0354 contextSize = new QMenu(i18n("Icon Size"), context); 0355 0356 auto *act = contextSize->addAction(i18nc("@item:inmenu Icon size", "Default")); 0357 q->connect(act, &QAction::triggered, q, [this, act]() { 0358 slotContextIconSize(act); 0359 }); 0360 m_contextIconSizes.push_back({act, iconSizeSettings.defaultValue()}); 0361 0362 // Query the current theme for available sizes 0363 KIconTheme *theme = KIconLoader::global()->theme(); 0364 QList<int> avSizes; 0365 if (theme) { 0366 avSizes = theme->querySizes(isMainToolBar ? KIconLoader::MainToolbar : KIconLoader::Toolbar); 0367 } 0368 0369 std::sort(avSizes.begin(), avSizes.end()); 0370 0371 if (avSizes.count() < 10) { 0372 // Fixed or threshold type icons 0373 for (int it : std::as_const(avSizes)) { 0374 QString text; 0375 if (it < 19) { 0376 text = i18n("Small (%1x%2)", it, it); 0377 } else if (it < 25) { 0378 text = i18n("Medium (%1x%2)", it, it); 0379 } else if (it < 35) { 0380 text = i18n("Large (%1x%2)", it, it); 0381 } else { 0382 text = i18n("Huge (%1x%2)", it, it); 0383 } 0384 0385 auto *act = contextSize->addAction(text); 0386 q->connect(act, &QAction::triggered, q, [this, act]() { 0387 slotContextIconSize(act); 0388 }); 0389 m_contextIconSizes.push_back({act, it}); 0390 } 0391 } else { 0392 // Scalable icons. 0393 const int progression[] = {16, 22, 32, 48, 64, 96, 128, 192, 256}; 0394 0395 for (int p : progression) { 0396 for (int it : std::as_const(avSizes)) { 0397 if (it >= p) { 0398 QString text; 0399 if (it < 19) { 0400 text = i18n("Small (%1x%2)", it, it); 0401 } else if (it < 25) { 0402 text = i18n("Medium (%1x%2)", it, it); 0403 } else if (it < 35) { 0404 text = i18n("Large (%1x%2)", it, it); 0405 } else { 0406 text = i18n("Huge (%1x%2)", it, it); 0407 } 0408 0409 auto *act = contextSize->addAction(text); 0410 q->connect(act, &QAction::triggered, q, [this, act]() { 0411 slotContextIconSize(act); 0412 }); 0413 m_contextIconSizes.push_back({act, it}); 0414 break; 0415 } 0416 } 0417 } 0418 } 0419 0420 QActionGroup *sizeGroup = new QActionGroup(contextSize); 0421 const auto sizeActions = contextSize->actions(); 0422 for (QAction *action : sizeActions) { 0423 action->setActionGroup(sizeGroup); 0424 action->setCheckable(true); 0425 } 0426 0427 if (!q->toolBarsLocked() && !q->isMovable()) { 0428 unlockedMovable = false; 0429 } 0430 0431 delete contextLockAction; 0432 contextLockAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("system-lock-screen")), i18n("Lock Toolbar Positions"), q); 0433 contextLockAction->setChecked(q->toolBarsLocked()); 0434 QObject::connect(contextLockAction, &KToggleAction::toggled, q, [this](bool checked) { 0435 slotLockToolBars(checked); 0436 }); 0437 0438 // Now add the actions to the menu 0439 context->addMenu(contextMode); 0440 context->addMenu(contextSize); 0441 context->addMenu(contextOrient); 0442 context->addSeparator(); 0443 0444 QObject::connect(context, &QMenu::aboutToShow, q, [this]() { 0445 slotContextAboutToShow(); 0446 }); 0447 } 0448 0449 contextButtonAction = q->actionAt(q->mapFromGlobal(globalPos)); 0450 if (contextButtonAction) { 0451 contextShowText->setText(contextButtonAction->text()); 0452 contextShowText->setIcon(contextButtonAction->icon()); 0453 contextShowText->setCheckable(true); 0454 } 0455 0456 contextOrient->menuAction()->setVisible(!q->toolBarsLocked()); 0457 // Unplugging a submenu from abouttohide leads to the popupmenu floating around 0458 // So better simply call that code from after exec() returns (DF) 0459 // connect(context, SIGNAL(aboutToHide()), this, SLOT(slotContextAboutToHide())); 0460 0461 // For tool buttons with delay popup or menu button popup (split button) 0462 // show the actions of that button for ease of access. 0463 // (no need to wait for the menu to open or aim at the arrow) 0464 if (auto *contextToolButton = qobject_cast<QToolButton *>(q->widgetForAction(contextButtonAction))) { 0465 if (contextToolButton->popupMode() == QToolButton::DelayedPopup || contextToolButton->popupMode() == QToolButton::MenuButtonPopup) { 0466 if (auto *actionMenu = contextButtonAction->menu()) { 0467 // In case it is populated on demand 0468 Q_EMIT actionMenu->aboutToShow(); 0469 0470 auto *contextMenu = new QMenu(q); 0471 contextMenu->setAttribute(Qt::WA_DeleteOnClose); 0472 0473 const auto actions = actionMenu->actions(); 0474 if (!actions.isEmpty()) { 0475 for (QAction *action : actions) { 0476 contextMenu->addAction(action); 0477 } 0478 0479 // Now add the configure actions as submenu 0480 contextMenu->addSeparator(); 0481 contextMenu->addMenu(context); 0482 return contextMenu; 0483 } 0484 } 0485 } 0486 } 0487 0488 return context; 0489 } 0490 0491 void KToolBarPrivate::setLocked(bool locked) 0492 { 0493 if (unlockedMovable) { 0494 q->setMovable(!locked); 0495 } 0496 } 0497 0498 void KToolBarPrivate::adjustSeparatorVisibility() 0499 { 0500 bool visibleNonSeparator = false; 0501 int separatorToShow = -1; 0502 0503 for (int index = 0; index < q->actions().count(); ++index) { 0504 QAction *action = q->actions().at(index); 0505 if (action->isSeparator()) { 0506 if (visibleNonSeparator) { 0507 separatorToShow = index; 0508 visibleNonSeparator = false; 0509 } else { 0510 action->setVisible(false); 0511 } 0512 } else if (!visibleNonSeparator) { 0513 if (action->isVisible()) { 0514 visibleNonSeparator = true; 0515 if (separatorToShow != -1) { 0516 q->actions().at(separatorToShow)->setVisible(true); 0517 separatorToShow = -1; 0518 } 0519 } 0520 } 0521 } 0522 0523 if (separatorToShow != -1) { 0524 q->actions().at(separatorToShow)->setVisible(false); 0525 } 0526 } 0527 0528 Qt::ToolButtonStyle KToolBarPrivate::toolButtonStyleFromString(const QString &_style) 0529 { 0530 QString style = _style.toLower(); 0531 if (style == QLatin1String("textbesideicon") || style == QLatin1String("icontextright")) { 0532 return Qt::ToolButtonTextBesideIcon; 0533 } else if (style == QLatin1String("textundericon") || style == QLatin1String("icontextbottom")) { 0534 return Qt::ToolButtonTextUnderIcon; 0535 } else if (style == QLatin1String("textonly")) { 0536 return Qt::ToolButtonTextOnly; 0537 } else { 0538 return Qt::ToolButtonIconOnly; 0539 } 0540 } 0541 0542 QString KToolBarPrivate::toolButtonStyleToString(Qt::ToolButtonStyle style) 0543 { 0544 switch (style) { 0545 case Qt::ToolButtonIconOnly: 0546 default: 0547 return QStringLiteral("IconOnly"); 0548 case Qt::ToolButtonTextBesideIcon: 0549 return QStringLiteral("TextBesideIcon"); 0550 case Qt::ToolButtonTextOnly: 0551 return QStringLiteral("TextOnly"); 0552 case Qt::ToolButtonTextUnderIcon: 0553 return QStringLiteral("TextUnderIcon"); 0554 } 0555 } 0556 0557 Qt::ToolBarArea KToolBarPrivate::positionFromString(const QString &position) 0558 { 0559 Qt::ToolBarArea newposition = Qt::TopToolBarArea; 0560 if (position == QLatin1String("left")) { 0561 newposition = Qt::LeftToolBarArea; 0562 } else if (position == QLatin1String("bottom")) { 0563 newposition = Qt::BottomToolBarArea; 0564 } else if (position == QLatin1String("right")) { 0565 newposition = Qt::RightToolBarArea; 0566 } else if (position == QLatin1String("none")) { 0567 newposition = Qt::NoToolBarArea; 0568 } 0569 return newposition; 0570 } 0571 0572 // Global setting was changed 0573 void KToolBarPrivate::slotAppearanceChanged() 0574 { 0575 loadKDESettings(); 0576 applyCurrentSettings(); 0577 } 0578 0579 Qt::ToolButtonStyle KToolBarPrivate::toolButtonStyleSetting() 0580 { 0581 KConfigGroup group(KSharedConfig::openConfig(), "Toolbar style"); 0582 const QString fallback = KToolBarPrivate::toolButtonStyleToString(Qt::ToolButtonTextBesideIcon); 0583 return KToolBarPrivate::toolButtonStyleFromString(group.readEntry("ToolButtonStyle", fallback)); 0584 } 0585 0586 void KToolBarPrivate::loadKDESettings() 0587 { 0588 iconSizeSettings[Level_KDEDefault] = q->iconSizeDefault(); 0589 0590 if (isMainToolBar) { 0591 toolButtonStyleSettings[Level_KDEDefault] = toolButtonStyleSetting(); 0592 } else { 0593 const QString fallBack = toolButtonStyleToString(Qt::ToolButtonTextBesideIcon); 0594 /** 0595 TODO: if we get complaints about text beside icons on small screens, 0596 try the following code out on such systems - aseigo. 0597 // if we are on a small screen with a non-landscape ratio, then 0598 // we revert to text under icons since width is probably not our 0599 // friend in such cases 0600 QDesktopWidget *desktop = QApplication::desktop(); 0601 QRect screenGeom = desktop->screenGeometry(desktop->primaryScreen()); 0602 qreal ratio = screenGeom.width() / qreal(screenGeom.height()); 0603 0604 if (screenGeom.width() < 1024 && ratio <= 1.4) { 0605 fallBack = "TextUnderIcon"; 0606 } 0607 **/ 0608 0609 KConfigGroup group(KSharedConfig::openConfig(), "Toolbar style"); 0610 const QString value = group.readEntry("ToolButtonStyleOtherToolbars", fallBack); 0611 toolButtonStyleSettings[Level_KDEDefault] = KToolBarPrivate::toolButtonStyleFromString(value); 0612 } 0613 } 0614 0615 // Call this after changing something in d->iconSizeSettings or d->toolButtonStyleSettings 0616 void KToolBarPrivate::applyCurrentSettings() 0617 { 0618 // qCDebug(DEBUG_KXMLGUI) << q->objectName() << "iconSizeSettings:" << iconSizeSettings.toString() << "->" << iconSizeSettings.currentValue(); 0619 const int currentIconSize = iconSizeSettings.currentValue(); 0620 q->setIconSize(QSize(currentIconSize, currentIconSize)); 0621 // qCDebug(DEBUG_KXMLGUI) << q->objectName() << "toolButtonStyleSettings:" << toolButtonStyleSettings.toString() << "->" << 0622 // toolButtonStyleSettings.currentValue(); 0623 q->setToolButtonStyle(static_cast<Qt::ToolButtonStyle>(toolButtonStyleSettings.currentValue())); 0624 0625 // And remember to save the new look later 0626 KMainWindow *kmw = q->mainWindow(); 0627 if (kmw) { 0628 kmw->setSettingsDirty(); 0629 } 0630 } 0631 0632 QAction *KToolBarPrivate::findAction(const QString &actionName, KXMLGUIClient **clientOut) const 0633 { 0634 for (KXMLGUIClient *client : xmlguiClients) { 0635 QAction *action = client->actionCollection()->action(actionName); 0636 if (action) { 0637 if (clientOut) { 0638 *clientOut = client; 0639 } 0640 return action; 0641 } 0642 } 0643 return nullptr; 0644 } 0645 0646 void KToolBarPrivate::slotContextAboutToShow() 0647 { 0648 /** 0649 * The idea here is to reuse the "static" part of the menu to save time. 0650 * But the "Toolbars" action is dynamic (can be a single action or a submenu) 0651 * and ToolBarHandler::setupActions() deletes it, so better not keep it around. 0652 * So we currently plug/unplug the last two actions of the menu. 0653 * Another way would be to keep around the actions and plug them all into a (new each time) popupmenu. 0654 */ 0655 0656 KXmlGuiWindow *kmw = qobject_cast<KXmlGuiWindow *>(q->mainWindow()); 0657 0658 // try to find "configure toolbars" action 0659 QAction *configureAction = nullptr; 0660 const char *actionName = KStandardAction::name(KStandardAction::ConfigureToolbars); 0661 configureAction = findAction(QLatin1String(actionName)); 0662 0663 if (!configureAction && kmw) { 0664 configureAction = kmw->actionCollection()->action(QLatin1String(actionName)); 0665 } 0666 0667 if (configureAction) { 0668 context->addAction(configureAction); 0669 } 0670 0671 context->addAction(contextLockAction); 0672 0673 if (kmw) { 0674 kmw->setupToolbarMenuActions(); 0675 // Only allow hiding a toolbar if the action is also plugged somewhere else (e.g. menubar) 0676 QAction *tbAction = kmw->toolBarMenuAction(); 0677 if (!q->toolBarsLocked() && tbAction && !tbAction->associatedWidgets().isEmpty()) { 0678 context->addAction(tbAction); 0679 } 0680 } 0681 0682 KEditToolBar::setGlobalDefaultToolBar(q->QObject::objectName().toLatin1().constData()); 0683 0684 // Check the actions that should be checked 0685 switch (q->toolButtonStyle()) { 0686 case Qt::ToolButtonIconOnly: 0687 default: 0688 contextIcons->setChecked(true); 0689 break; 0690 case Qt::ToolButtonTextBesideIcon: 0691 contextTextRight->setChecked(true); 0692 break; 0693 case Qt::ToolButtonTextOnly: 0694 contextText->setChecked(true); 0695 break; 0696 case Qt::ToolButtonTextUnderIcon: 0697 contextTextUnder->setChecked(true); 0698 break; 0699 } 0700 0701 auto it = std::find_if(m_contextIconSizes.cbegin(), m_contextIconSizes.cend(), [this](const ContextIconInfo &info) { 0702 return info.iconSize == q->iconSize().width(); 0703 }); 0704 if (it != m_contextIconSizes.cend()) { 0705 it->iconAction->setChecked(true); 0706 } 0707 0708 switch (q->mainWindow()->toolBarArea(q)) { 0709 case Qt::BottomToolBarArea: 0710 contextBottom->setChecked(true); 0711 break; 0712 case Qt::LeftToolBarArea: 0713 contextLeft->setChecked(true); 0714 break; 0715 case Qt::RightToolBarArea: 0716 contextRight->setChecked(true); 0717 break; 0718 default: 0719 case Qt::TopToolBarArea: 0720 contextTop->setChecked(true); 0721 break; 0722 } 0723 0724 const bool showButtonSettings = contextButtonAction // 0725 && !contextShowText->text().isEmpty() // 0726 && contextTextRight->isChecked(); 0727 contextButtonTitle->setVisible(showButtonSettings); 0728 contextShowText->setVisible(showButtonSettings); 0729 if (showButtonSettings) { 0730 contextShowText->setChecked(contextButtonAction->priority() >= QAction::NormalPriority); 0731 } 0732 } 0733 0734 void KToolBarPrivate::slotContextAboutToHide() 0735 { 0736 // We have to unplug whatever slotContextAboutToShow plugged into the menu. 0737 // Unplug the toolbar menu action 0738 KXmlGuiWindow *kmw = qobject_cast<KXmlGuiWindow *>(q->mainWindow()); 0739 if (kmw && kmw->toolBarMenuAction()) { 0740 if (kmw->toolBarMenuAction()->associatedWidgets().count() > 1) { 0741 context->removeAction(kmw->toolBarMenuAction()); 0742 } 0743 } 0744 0745 // Unplug the configure toolbars action too, since it's afterwards anyway 0746 QAction *configureAction = nullptr; 0747 const char *actionName = KStandardAction::name(KStandardAction::ConfigureToolbars); 0748 configureAction = findAction(QLatin1String(actionName)); 0749 0750 if (!configureAction && kmw) { 0751 configureAction = kmw->actionCollection()->action(QLatin1String(actionName)); 0752 } 0753 0754 if (configureAction) { 0755 context->removeAction(configureAction); 0756 } 0757 0758 context->removeAction(contextLockAction); 0759 } 0760 0761 void KToolBarPrivate::slotContextLeft() 0762 { 0763 q->mainWindow()->addToolBar(Qt::LeftToolBarArea, q); 0764 } 0765 0766 void KToolBarPrivate::slotContextRight() 0767 { 0768 q->mainWindow()->addToolBar(Qt::RightToolBarArea, q); 0769 } 0770 0771 void KToolBarPrivate::slotContextShowText() 0772 { 0773 Q_ASSERT(contextButtonAction); 0774 const QAction::Priority priority = contextShowText->isChecked() ? QAction::NormalPriority : QAction::LowPriority; 0775 contextButtonAction->setPriority(priority); 0776 0777 // Find to which xml file and componentData the action belongs to 0778 QString componentName; 0779 QString filename; 0780 KXMLGUIClient *client; 0781 if (findAction(contextButtonAction->objectName(), &client)) { 0782 componentName = client->componentName(); 0783 filename = client->xmlFile(); 0784 } 0785 if (filename.isEmpty()) { 0786 componentName = QCoreApplication::applicationName(); 0787 filename = componentName + QLatin1String("ui.rc"); 0788 } 0789 0790 // Save the priority state of the action 0791 const QString configFile = KXMLGUIFactory::readConfigFile(filename, componentName); 0792 0793 QDomDocument document; 0794 document.setContent(configFile); 0795 QDomElement elem = KXMLGUIFactory::actionPropertiesElement(document); 0796 QDomElement actionElem = KXMLGUIFactory::findActionByName(elem, contextButtonAction->objectName(), true); 0797 actionElem.setAttribute(QStringLiteral("priority"), priority); 0798 KXMLGUIFactory::saveConfigFile(document, filename, componentName); 0799 } 0800 0801 void KToolBarPrivate::slotContextTop() 0802 { 0803 q->mainWindow()->addToolBar(Qt::TopToolBarArea, q); 0804 } 0805 0806 void KToolBarPrivate::slotContextBottom() 0807 { 0808 q->mainWindow()->addToolBar(Qt::BottomToolBarArea, q); 0809 } 0810 0811 void KToolBarPrivate::slotContextIcons() 0812 { 0813 q->setToolButtonStyle(Qt::ToolButtonIconOnly); 0814 toolButtonStyleSettings[Level_UserSettings] = q->toolButtonStyle(); 0815 } 0816 0817 void KToolBarPrivate::slotContextText() 0818 { 0819 q->setToolButtonStyle(Qt::ToolButtonTextOnly); 0820 toolButtonStyleSettings[Level_UserSettings] = q->toolButtonStyle(); 0821 } 0822 0823 void KToolBarPrivate::slotContextTextUnder() 0824 { 0825 q->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); 0826 toolButtonStyleSettings[Level_UserSettings] = q->toolButtonStyle(); 0827 } 0828 0829 void KToolBarPrivate::slotContextTextRight() 0830 { 0831 q->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0832 toolButtonStyleSettings[Level_UserSettings] = q->toolButtonStyle(); 0833 } 0834 0835 void KToolBarPrivate::slotContextIconSize(QAction *action) 0836 { 0837 if (action) { 0838 auto it = std::find_if(m_contextIconSizes.cbegin(), m_contextIconSizes.cend(), [action](const ContextIconInfo &info) { 0839 return info.iconAction == action; 0840 }); 0841 if (it != m_contextIconSizes.cend()) { 0842 q->setIconDimensions(it->iconSize); 0843 } 0844 } 0845 } 0846 0847 void KToolBarPrivate::slotLockToolBars(bool lock) 0848 { 0849 q->setToolBarsLocked(lock); 0850 } 0851 0852 KToolBar::KToolBar(QWidget *parent, bool isMainToolBar, bool readConfig) 0853 : QToolBar(parent) 0854 , d(new KToolBarPrivate(this)) 0855 { 0856 d->init(readConfig, isMainToolBar); 0857 0858 // KToolBar is auto-added to the top area of the main window if parent is a QMainWindow 0859 if (QMainWindow *mw = qobject_cast<QMainWindow *>(parent)) { 0860 mw->addToolBar(this); 0861 } 0862 } 0863 0864 KToolBar::KToolBar(const QString &objectName, QWidget *parent, bool readConfig) 0865 : QToolBar(parent) 0866 , d(new KToolBarPrivate(this)) 0867 { 0868 setObjectName(objectName); 0869 // mainToolBar -> isMainToolBar = true -> buttonStyle is configurable 0870 // others -> isMainToolBar = false -> ### hardcoded default for buttonStyle !!! should be configurable? -> hidden key added 0871 d->init(readConfig, (objectName == QLatin1String("mainToolBar"))); 0872 0873 // KToolBar is auto-added to the top area of the main window if parent is a QMainWindow 0874 if (QMainWindow *mw = qobject_cast<QMainWindow *>(parent)) { 0875 mw->addToolBar(this); 0876 } 0877 } 0878 0879 KToolBar::KToolBar(const QString &objectName, QMainWindow *parent, Qt::ToolBarArea area, bool newLine, bool isMainToolBar, bool readConfig) 0880 : QToolBar(parent) 0881 , d(new KToolBarPrivate(this)) 0882 { 0883 setObjectName(objectName); 0884 d->init(readConfig, isMainToolBar); 0885 0886 if (newLine) { 0887 mainWindow()->addToolBarBreak(area); 0888 } 0889 0890 mainWindow()->addToolBar(area, this); 0891 0892 if (newLine) { 0893 mainWindow()->addToolBarBreak(area); 0894 } 0895 } 0896 0897 KToolBar::~KToolBar() 0898 { 0899 delete d->contextLockAction; 0900 } 0901 0902 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0) 0903 void KToolBar::setContextMenuEnabled(bool enable) 0904 { 0905 d->enableContext = enable; 0906 } 0907 #endif 0908 0909 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0) 0910 bool KToolBar::contextMenuEnabled() const 0911 { 0912 return d->enableContext; 0913 } 0914 #endif 0915 0916 void KToolBar::saveSettings(KConfigGroup &cg) 0917 { 0918 Q_ASSERT(!cg.name().isEmpty()); 0919 0920 const int currentIconSize = iconSize().width(); 0921 // qCDebug(DEBUG_KXMLGUI) << objectName() << currentIconSize << d->iconSizeSettings.toString() << "defaultValue=" << d->iconSizeSettings.defaultValue(); 0922 if (!cg.hasDefault("IconSize") && currentIconSize == d->iconSizeSettings.defaultValue()) { 0923 cg.revertToDefault("IconSize"); 0924 d->iconSizeSettings[Level_UserSettings] = Unset; 0925 } else { 0926 cg.writeEntry("IconSize", currentIconSize); 0927 d->iconSizeSettings[Level_UserSettings] = currentIconSize; 0928 } 0929 0930 const Qt::ToolButtonStyle currentToolButtonStyle = toolButtonStyle(); 0931 if (!cg.hasDefault("ToolButtonStyle") && currentToolButtonStyle == d->toolButtonStyleSettings.defaultValue()) { 0932 cg.revertToDefault("ToolButtonStyle"); 0933 d->toolButtonStyleSettings[Level_UserSettings] = Unset; 0934 } else { 0935 cg.writeEntry("ToolButtonStyle", d->toolButtonStyleToString(currentToolButtonStyle)); 0936 d->toolButtonStyleSettings[Level_UserSettings] = currentToolButtonStyle; 0937 } 0938 } 0939 0940 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0) 0941 void KToolBar::setXMLGUIClient(KXMLGUIClient *client) 0942 { 0943 d->xmlguiClients.clear(); 0944 d->xmlguiClients << client; 0945 } 0946 #endif 0947 0948 void KToolBar::addXMLGUIClient(KXMLGUIClient *client) 0949 { 0950 d->xmlguiClients << client; 0951 } 0952 0953 void KToolBar::removeXMLGUIClient(KXMLGUIClient *client) 0954 { 0955 d->xmlguiClients.remove(client); 0956 } 0957 0958 void KToolBar::contextMenuEvent(QContextMenuEvent *event) 0959 { 0960 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0) 0961 if (mainWindow() && d->enableContext) { 0962 QPointer<KToolBar> guard(this); 0963 const QPoint globalPos = event->globalPos(); 0964 d->contextMenu(globalPos)->exec(globalPos); 0965 0966 // "Configure Toolbars" recreates toolbars, so we might not exist anymore. 0967 if (guard) { 0968 d->slotContextAboutToHide(); 0969 } 0970 return; 0971 } 0972 #endif 0973 0974 QToolBar::contextMenuEvent(event); 0975 } 0976 0977 void KToolBar::loadState(const QDomElement &element) 0978 { 0979 QMainWindow *mw = mainWindow(); 0980 if (!mw) { 0981 return; 0982 } 0983 0984 { 0985 const QString &i18nText = KToolbarHelper::i18nToolBarName(element); 0986 if (!i18nText.isEmpty()) { 0987 setWindowTitle(i18nText); 0988 } 0989 } 0990 0991 /* 0992 This method is called in order to load toolbar settings from XML. 0993 However this can be used in two rather different cases: 0994 - for the initial loading of the app's XML. In that case the settings 0995 are only the defaults (Level_AppXML), the user's KConfig settings will override them 0996 0997 - for later re-loading when switching between parts in KXMLGUIFactory. 0998 In that case the XML contains the final settings, not the defaults. 0999 We do need the defaults, and the toolbar might have been completely 1000 deleted and recreated meanwhile. So we store the app-default settings 1001 into the XML. 1002 */ 1003 bool loadingAppDefaults = true; 1004 if (element.hasAttribute(QStringLiteral("tempXml"))) { 1005 // this isn't the first time, so the app-xml defaults have been saved into the (in-memory) XML 1006 loadingAppDefaults = false; 1007 const QString iconSizeDefault = element.attribute(QStringLiteral("iconSizeDefault")); 1008 if (!iconSizeDefault.isEmpty()) { 1009 d->iconSizeSettings[Level_AppXML] = iconSizeDefault.toInt(); 1010 } 1011 const QString toolButtonStyleDefault = element.attribute(QStringLiteral("toolButtonStyleDefault")); 1012 if (!toolButtonStyleDefault.isEmpty()) { 1013 d->toolButtonStyleSettings[Level_AppXML] = d->toolButtonStyleFromString(toolButtonStyleDefault); 1014 } 1015 } else { 1016 // loading app defaults 1017 bool newLine = false; 1018 QString attrNewLine = element.attribute(QStringLiteral("newline")).toLower(); 1019 if (!attrNewLine.isEmpty()) { 1020 newLine = (attrNewLine == QLatin1String("true")); 1021 } 1022 if (newLine && mw) { 1023 mw->insertToolBarBreak(this); 1024 } 1025 } 1026 1027 int newIconSize = -1; 1028 if (element.hasAttribute(QStringLiteral("iconSize"))) { 1029 bool ok; 1030 newIconSize = element.attribute(QStringLiteral("iconSize")).trimmed().toInt(&ok); 1031 if (!ok) { 1032 newIconSize = -1; 1033 } 1034 } 1035 if (newIconSize != -1) { 1036 d->iconSizeSettings[loadingAppDefaults ? Level_AppXML : Level_UserSettings] = newIconSize; 1037 } 1038 1039 const QString newToolButtonStyle = element.attribute(QStringLiteral("iconText")); 1040 if (!newToolButtonStyle.isEmpty()) { 1041 d->toolButtonStyleSettings[loadingAppDefaults ? Level_AppXML : Level_UserSettings] = d->toolButtonStyleFromString(newToolButtonStyle); 1042 } 1043 1044 bool hidden = false; 1045 { 1046 QString attrHidden = element.attribute(QStringLiteral("hidden")).toLower(); 1047 if (!attrHidden.isEmpty()) { 1048 hidden = (attrHidden == QLatin1String("true")); 1049 } 1050 } 1051 1052 Qt::ToolBarArea pos = Qt::NoToolBarArea; 1053 { 1054 QString attrPosition = element.attribute(QStringLiteral("position")).toLower(); 1055 if (!attrPosition.isEmpty()) { 1056 pos = KToolBarPrivate::positionFromString(attrPosition); 1057 } 1058 } 1059 if (pos != Qt::NoToolBarArea) { 1060 mw->addToolBar(pos, this); 1061 } 1062 1063 setVisible(!hidden); 1064 1065 d->applyCurrentSettings(); 1066 } 1067 1068 // Called when switching between xmlgui clients, in order to find any unsaved settings 1069 // again when switching back to the current xmlgui client. 1070 void KToolBar::saveState(QDomElement ¤t) const 1071 { 1072 Q_ASSERT(!current.isNull()); 1073 1074 current.setAttribute(QStringLiteral("tempXml"), QStringLiteral("true")); 1075 1076 current.setAttribute(QStringLiteral("noMerge"), QStringLiteral("1")); 1077 current.setAttribute(QStringLiteral("position"), d->getPositionAsString().toLower()); 1078 current.setAttribute(QStringLiteral("hidden"), isHidden() ? QStringLiteral("true") : QStringLiteral("false")); 1079 1080 const int currentIconSize = iconSize().width(); 1081 if (currentIconSize == d->iconSizeSettings.defaultValue()) { 1082 current.removeAttribute(QStringLiteral("iconSize")); 1083 } else { 1084 current.setAttribute(QStringLiteral("iconSize"), iconSize().width()); 1085 } 1086 1087 if (toolButtonStyle() == d->toolButtonStyleSettings.defaultValue()) { 1088 current.removeAttribute(QStringLiteral("iconText")); 1089 } else { 1090 current.setAttribute(QStringLiteral("iconText"), d->toolButtonStyleToString(toolButtonStyle())); 1091 } 1092 1093 // Note: if this method is used by more than KXMLGUIBuilder, e.g. to save XML settings to *disk*, 1094 // then the stuff below shouldn't always be done. This is not the case currently though. 1095 if (d->iconSizeSettings[Level_AppXML] != Unset) { 1096 current.setAttribute(QStringLiteral("iconSizeDefault"), d->iconSizeSettings[Level_AppXML]); 1097 } 1098 if (d->toolButtonStyleSettings[Level_AppXML] != Unset) { 1099 const Qt::ToolButtonStyle bs = static_cast<Qt::ToolButtonStyle>(d->toolButtonStyleSettings[Level_AppXML]); 1100 current.setAttribute(QStringLiteral("toolButtonStyleDefault"), d->toolButtonStyleToString(bs)); 1101 } 1102 } 1103 1104 // called by KMainWindow::applyMainWindowSettings to read from the user settings 1105 void KToolBar::applySettings(const KConfigGroup &cg) 1106 { 1107 Q_ASSERT(!cg.name().isEmpty()); 1108 1109 if (cg.hasKey("IconSize")) { 1110 d->iconSizeSettings[Level_UserSettings] = cg.readEntry("IconSize", 0); 1111 } 1112 if (cg.hasKey("ToolButtonStyle")) { 1113 d->toolButtonStyleSettings[Level_UserSettings] = d->toolButtonStyleFromString(cg.readEntry("ToolButtonStyle", QString())); 1114 } 1115 1116 d->applyCurrentSettings(); 1117 } 1118 1119 KMainWindow *KToolBar::mainWindow() const 1120 { 1121 return qobject_cast<KMainWindow *>(const_cast<QObject *>(parent())); 1122 } 1123 1124 void KToolBar::setIconDimensions(int size) 1125 { 1126 QToolBar::setIconSize(QSize(size, size)); 1127 d->iconSizeSettings[Level_UserSettings] = size; 1128 } 1129 1130 int KToolBar::iconSizeDefault() const 1131 { 1132 return KIconLoader::global()->currentSize(d->isMainToolBar ? KIconLoader::MainToolbar : KIconLoader::Toolbar); 1133 } 1134 1135 void KToolBar::slotMovableChanged(bool movable) 1136 { 1137 if (movable && !KAuthorized::authorize(QStringLiteral("movable_toolbars"))) { 1138 setMovable(false); 1139 } 1140 } 1141 1142 void KToolBar::dragEnterEvent(QDragEnterEvent *event) 1143 { 1144 if (toolBarsEditable() && event->proposedAction() & (Qt::CopyAction | Qt::MoveAction) 1145 && event->mimeData()->hasFormat(QStringLiteral("application/x-kde-action-list"))) { 1146 QByteArray data = event->mimeData()->data(QStringLiteral("application/x-kde-action-list")); 1147 1148 QDataStream stream(data); 1149 1150 QStringList actionNames; 1151 1152 stream >> actionNames; 1153 1154 const auto allCollections = KActionCollection::allCollections(); 1155 for (const QString &actionName : std::as_const(actionNames)) { 1156 for (KActionCollection *ac : allCollections) { 1157 QAction *newAction = ac->action(actionName); 1158 if (newAction) { 1159 d->actionsBeingDragged.append(newAction); 1160 break; 1161 } 1162 } 1163 } 1164 1165 if (!d->actionsBeingDragged.isEmpty()) { 1166 QAction *overAction = actionAt(event->pos()); 1167 1168 QFrame *dropIndicatorWidget = new QFrame(this); 1169 dropIndicatorWidget->resize(8, height() - 4); 1170 dropIndicatorWidget->setFrameShape(QFrame::VLine); 1171 dropIndicatorWidget->setLineWidth(3); 1172 1173 d->dropIndicatorAction = insertWidget(overAction, dropIndicatorWidget); 1174 1175 insertAction(overAction, d->dropIndicatorAction); 1176 1177 event->acceptProposedAction(); 1178 return; 1179 } 1180 } 1181 1182 QToolBar::dragEnterEvent(event); 1183 } 1184 1185 void KToolBar::dragMoveEvent(QDragMoveEvent *event) 1186 { 1187 if (toolBarsEditable()) { 1188 Q_FOREVER { 1189 if (d->dropIndicatorAction) { 1190 QAction *overAction = nullptr; 1191 const auto actions = this->actions(); 1192 for (QAction *action : actions) { 1193 // want to make it feel that half way across an action you're dropping on the other side of it 1194 QWidget *widget = widgetForAction(action); 1195 if (event->pos().x() < widget->pos().x() + (widget->width() / 2)) { 1196 overAction = action; 1197 break; 1198 } 1199 } 1200 1201 if (overAction != d->dropIndicatorAction) { 1202 // Check to see if the indicator is already in the right spot 1203 int dropIndicatorIndex = actions.indexOf(d->dropIndicatorAction); 1204 if (dropIndicatorIndex + 1 < actions.count()) { 1205 if (actions.at(dropIndicatorIndex + 1) == overAction) { 1206 break; 1207 } 1208 } else if (!overAction) { 1209 break; 1210 } 1211 1212 insertAction(overAction, d->dropIndicatorAction); 1213 } 1214 1215 event->accept(); 1216 return; 1217 } 1218 break; 1219 } 1220 } 1221 1222 QToolBar::dragMoveEvent(event); 1223 } 1224 1225 void KToolBar::dragLeaveEvent(QDragLeaveEvent *event) 1226 { 1227 // Want to clear this even if toolBarsEditable was changed mid-drag (unlikely) 1228 delete d->dropIndicatorAction; 1229 d->dropIndicatorAction = nullptr; 1230 d->actionsBeingDragged.clear(); 1231 1232 if (toolBarsEditable()) { 1233 event->accept(); 1234 return; 1235 } 1236 1237 QToolBar::dragLeaveEvent(event); 1238 } 1239 1240 void KToolBar::dropEvent(QDropEvent *event) 1241 { 1242 if (toolBarsEditable()) { 1243 for (QAction *action : std::as_const(d->actionsBeingDragged)) { 1244 if (actions().contains(action)) { 1245 removeAction(action); 1246 } 1247 insertAction(d->dropIndicatorAction, action); 1248 } 1249 } 1250 1251 // Want to clear this even if toolBarsEditable was changed mid-drag (unlikely) 1252 delete d->dropIndicatorAction; 1253 d->dropIndicatorAction = nullptr; 1254 d->actionsBeingDragged.clear(); 1255 1256 if (toolBarsEditable()) { 1257 event->accept(); 1258 return; 1259 } 1260 1261 QToolBar::dropEvent(event); 1262 } 1263 1264 void KToolBar::mousePressEvent(QMouseEvent *event) 1265 { 1266 if (toolBarsEditable() && event->button() == Qt::LeftButton) { 1267 if (QAction *action = actionAt(event->pos())) { 1268 d->dragAction = action; 1269 d->dragStartPosition = event->pos(); 1270 event->accept(); 1271 return; 1272 } 1273 } 1274 1275 QToolBar::mousePressEvent(event); 1276 } 1277 1278 void KToolBar::mouseMoveEvent(QMouseEvent *event) 1279 { 1280 if (!toolBarsEditable() || !d->dragAction) { 1281 QToolBar::mouseMoveEvent(event); 1282 return; 1283 } 1284 1285 if ((event->pos() - d->dragStartPosition).manhattanLength() < QApplication::startDragDistance()) { 1286 event->accept(); 1287 return; 1288 } 1289 1290 QDrag *drag = new QDrag(this); 1291 QMimeData *mimeData = new QMimeData; 1292 1293 QByteArray data; 1294 { 1295 QDataStream stream(&data, QIODevice::WriteOnly); 1296 1297 QStringList actionNames; 1298 actionNames << d->dragAction->objectName(); 1299 1300 stream << actionNames; 1301 } 1302 1303 mimeData->setData(QStringLiteral("application/x-kde-action-list"), data); 1304 1305 drag->setMimeData(mimeData); 1306 1307 Qt::DropAction dropAction = drag->exec(Qt::MoveAction); 1308 1309 if (dropAction == Qt::MoveAction) { 1310 // Only remove from this toolbar if it was moved to another toolbar 1311 // Otherwise the receiver moves it. 1312 if (drag->target() != this) { 1313 removeAction(d->dragAction); 1314 } 1315 } 1316 1317 d->dragAction = nullptr; 1318 event->accept(); 1319 } 1320 1321 void KToolBar::mouseReleaseEvent(QMouseEvent *event) 1322 { 1323 // Want to clear this even if toolBarsEditable was changed mid-drag (unlikely) 1324 if (d->dragAction) { 1325 d->dragAction = nullptr; 1326 event->accept(); 1327 return; 1328 } 1329 1330 QToolBar::mouseReleaseEvent(event); 1331 } 1332 1333 bool KToolBar::eventFilter(QObject *watched, QEvent *event) 1334 { 1335 // Generate context menu events for disabled buttons too... 1336 if (event->type() == QEvent::MouseButtonPress) { 1337 QMouseEvent *me = static_cast<QMouseEvent *>(event); 1338 if (me->buttons() & Qt::RightButton) { 1339 if (QWidget *ww = qobject_cast<QWidget *>(watched)) { 1340 if (ww->parent() == this && !ww->isEnabled()) { 1341 QCoreApplication::postEvent(this, new QContextMenuEvent(QContextMenuEvent::Mouse, me->pos(), me->globalPos())); 1342 } 1343 } 1344 } 1345 1346 } else if (event->type() == QEvent::ParentChange) { 1347 // Make sure we're not leaving stale event filters around, 1348 // when a child is reparented somewhere else 1349 if (QWidget *ww = qobject_cast<QWidget *>(watched)) { 1350 if (!this->isAncestorOf(ww)) { 1351 // New parent is not a subwidget - remove event filter 1352 ww->removeEventFilter(this); 1353 const auto children = ww->findChildren<QWidget *>(); 1354 for (QWidget *child : children) { 1355 child->removeEventFilter(this); 1356 } 1357 } 1358 } 1359 } 1360 1361 // Redirect mouse events to the toolbar when drag + drop editing is enabled 1362 if (toolBarsEditable()) { 1363 if (QWidget *ww = qobject_cast<QWidget *>(watched)) { 1364 switch (event->type()) { 1365 case QEvent::MouseButtonPress: { 1366 QMouseEvent *me = static_cast<QMouseEvent *>(event); 1367 QMouseEvent newEvent(me->type(), mapFromGlobal(ww->mapToGlobal(me->pos())), me->globalPos(), me->button(), me->buttons(), me->modifiers()); 1368 mousePressEvent(&newEvent); 1369 return true; 1370 } 1371 case QEvent::MouseMove: { 1372 QMouseEvent *me = static_cast<QMouseEvent *>(event); 1373 QMouseEvent newEvent(me->type(), mapFromGlobal(ww->mapToGlobal(me->pos())), me->globalPos(), me->button(), me->buttons(), me->modifiers()); 1374 mouseMoveEvent(&newEvent); 1375 return true; 1376 } 1377 case QEvent::MouseButtonRelease: { 1378 QMouseEvent *me = static_cast<QMouseEvent *>(event); 1379 QMouseEvent newEvent(me->type(), mapFromGlobal(ww->mapToGlobal(me->pos())), me->globalPos(), me->button(), me->buttons(), me->modifiers()); 1380 mouseReleaseEvent(&newEvent); 1381 return true; 1382 } 1383 default: 1384 break; 1385 } 1386 } 1387 } 1388 1389 return QToolBar::eventFilter(watched, event); 1390 } 1391 1392 void KToolBar::actionEvent(QActionEvent *event) 1393 { 1394 if (event->type() == QEvent::ActionRemoved) { 1395 QWidget *widget = widgetForAction(event->action()); 1396 if (widget) { 1397 widget->removeEventFilter(this); 1398 1399 const auto children = widget->findChildren<QWidget *>(); 1400 for (QWidget *child : children) { 1401 child->removeEventFilter(this); 1402 } 1403 } 1404 } 1405 1406 QToolBar::actionEvent(event); 1407 1408 if (event->type() == QEvent::ActionAdded) { 1409 QWidget *widget = widgetForAction(event->action()); 1410 if (widget) { 1411 widget->installEventFilter(this); 1412 1413 const auto children = widget->findChildren<QWidget *>(); 1414 for (QWidget *child : children) { 1415 child->installEventFilter(this); 1416 } 1417 // Center widgets that do not have any use for more space. See bug 165274 1418 if (!(widget->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag) 1419 // ... but do not center when using text besides icon in vertical toolbar. See bug 243196 1420 && !(orientation() == Qt::Vertical && toolButtonStyle() == Qt::ToolButtonTextBesideIcon)) { 1421 const int index = layout()->indexOf(widget); 1422 if (index != -1) { 1423 layout()->itemAt(index)->setAlignment(Qt::AlignJustify); 1424 } 1425 } 1426 } 1427 } 1428 1429 d->adjustSeparatorVisibility(); 1430 } 1431 1432 bool KToolBar::toolBarsEditable() 1433 { 1434 return KToolBarPrivate::s_editable; 1435 } 1436 1437 void KToolBar::setToolBarsEditable(bool editable) 1438 { 1439 if (KToolBarPrivate::s_editable != editable) { 1440 KToolBarPrivate::s_editable = editable; 1441 } 1442 } 1443 1444 void KToolBar::setToolBarsLocked(bool locked) 1445 { 1446 if (KToolBarPrivate::s_locked != locked) { 1447 KToolBarPrivate::s_locked = locked; 1448 1449 const auto windows = KMainWindow::memberList(); 1450 for (KMainWindow *mw : windows) { 1451 const auto toolbars = mw->findChildren<KToolBar *>(); 1452 for (KToolBar *toolbar : toolbars) { 1453 toolbar->d->setLocked(locked); 1454 } 1455 } 1456 } 1457 } 1458 1459 bool KToolBar::toolBarsLocked() 1460 { 1461 return KToolBarPrivate::s_locked; 1462 } 1463 1464 void KToolBar::emitToolbarStyleChanged() 1465 { 1466 #ifdef QT_DBUS_LIB 1467 QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KToolBar"), QStringLiteral("org.kde.KToolBar"), QStringLiteral("styleChanged")); 1468 QDBusConnection::sessionBus().send(message); 1469 #endif 1470 } 1471 1472 #include "moc_ktoolbar.cpp"