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