diff --git a/libs/flake/KoToolManager.h b/libs/flake/KoToolManager.h --- a/libs/flake/KoToolManager.h +++ b/libs/flake/KoToolManager.h @@ -35,23 +35,53 @@ class KoCreateShapesTool; class KActionCollection; class KoShape; -class QToolButton; class KoInputDeviceHandlerEvent; class KoShapeLayer; class ToolHelper; +class KShortcut; class QCursor; -/// Struct for the createToolList return type. -struct KoToolButton { - QToolButton *button; ///< a newly created button. - QString section; ///< The section the button wants to be in. - int priority; ///< Lower number (higher priority) means coming first in the section. - int buttonGroupId; ///< A unique ID for this tool as passed by changedTool(), >= 0 - QString visibilityCode; ///< This button should become visible when we emit this string in toolCodesSelected() -}; +/** + * This class serves as a QAction-like control object for activation of a tool. + * + * It allows to implement a custom UI to control the activation of tools. + * See KoToolBox & KoModeBox in the kowidgets library. + * + * KoToolAction objects are indirectly owned by the KoToolManager singleton + * and live until the end of its lifetime. + */ +class FLAKE_EXPORT KoToolAction : public QObject +{ + Q_OBJECT +public: + // toolHelper takes over ownership, and those live till the end of KoToolManager. + explicit KoToolAction(ToolHelper *toolHelper); + ~KoToolAction(); + +public: + QString id() const; ///< The id of the tool + QString iconText() const; ///< The icontext of the tool + QString toolTip() const; ///< The tooltip of the tool + QString iconName() const; ///< The icon name of the tool + KShortcut shortcut() const; ///< The shortcut to activate the tool -Q_DECLARE_TYPEINFO(KoToolButton, Q_MOVABLE_TYPE); + QString section() const; ///< The section the tool wants to be in. + int priority() const; ///< Lower number (higher priority) means coming first in the section. + int buttonGroupId() const; ///< A unique ID for this tool as passed by changedTool(), >= 0 + QString visibilityCode() const; ///< This tool should become visible when we emit this string in toolCodesSelected() + +public Q_SLOTS: + void trigger(); ///< Request the activation of the tool + +Q_SIGNALS: + void changed(); ///< Emitted when a property changes (shortcut ATM) + +private: + friend class ToolHelper; + class Private; + Private *const d; +}; /** @@ -188,11 +218,10 @@ QString preferredToolForSelection(const QList &shapes); /** - * Create a list of buttons to represent all the tools. - * @returns a list of Buttons. - * This is a factory method for buttons and meta information on the button to better display the button. + * Returns the list of toolActions for the current tools. + * @returns lists of toolActions for the current tools. */ - QVector createToolList() const; + QList toolActionList() const; /// Request tool activation for the given canvas controller void requestToolActivation(KoCanvasController *controller); @@ -287,7 +316,7 @@ /** * emitted whenever a new tool is dynamically added for the given canvas */ - void addedTool(const KoToolButton &button, KoCanvasController *canvas); + void addedTool(KoToolAction *toolAction, KoCanvasController *canvas); private: KoToolManager(); diff --git a/libs/flake/KoToolManager.cpp b/libs/flake/KoToolManager.cpp --- a/libs/flake/KoToolManager.cpp +++ b/libs/flake/KoToolManager.cpp @@ -57,9 +57,81 @@ #include #include #include +#include #include #include +class Q_DECL_HIDDEN KoToolAction::Private +{ +public: + ToolHelper* toolHelper; +}; + +KoToolAction::KoToolAction(ToolHelper* toolHelper) + : QObject(toolHelper) + , d(new Private) +{ + d->toolHelper = toolHelper; +} + +KoToolAction::~KoToolAction() +{ + delete d; +} + +void KoToolAction::trigger() +{ + d->toolHelper->activate(); +} + + +QString KoToolAction::iconText() const +{ + return d->toolHelper->iconText(); +} + +QString KoToolAction::toolTip() const +{ + return d->toolHelper->toolTip(); +} + +QString KoToolAction::id() const +{ + return d->toolHelper->id(); +} + +QString KoToolAction::iconName() const +{ + return d->toolHelper->iconName(); +} + +KShortcut KoToolAction::shortcut() const +{ + return d->toolHelper->shortcut(); +} + + +QString KoToolAction::section() const +{ + return d->toolHelper->toolType(); +} + +int KoToolAction::priority() const +{ + return d->toolHelper->priority(); +} + +int KoToolAction::buttonGroupId() const +{ + return d->toolHelper->uniqueId(); +} + +QString KoToolAction::visibilityCode() const +{ + return d->toolHelper->activationShapeId(); +} + + class CanvasData { public: @@ -742,20 +814,14 @@ delete d; } -QVector KoToolManager::createToolList() const +QList KoToolManager::toolActionList() const { - QVector answer; + QList answer; answer.reserve(d->tools.count()); foreach(ToolHelper *tool, d->tools) { if (tool->id() == KoCreateShapesTool_ID) continue; // don't show this one. - KoToolButton button; - button.button = tool->createButton(); - button.section = tool->toolType(); - button.priority = tool->priority(); - button.buttonGroupId = tool->uniqueId(); - button.visibilityCode = tool->activationShapeId(); - answer.append(button); + answer.append(tool->toolAction()); } return answer; } @@ -800,13 +866,13 @@ } } - // Actions used to switch tools; connect slot to keep button tooltips updated + // Actions used to switch tools via shortcuts foreach(ToolHelper * th, d->tools) { - ToolAction* action = new ToolAction(this, th->id(), th->toolTip(), ac); - action->setShortcut(th->shortcut()); + if (ac->action(th->id())) { + continue; + } + ShortcutToolAction* action = th->createShortcutToolAction(ac); ac->addAction(th->id(), action); - th->setAction(action); - connect(action, SIGNAL(changed()), th, SLOT(actionUpdated())); } } @@ -988,16 +1054,8 @@ continue; } - KoToolButton button; - button.button = tool->createButton(); - button.section = tool->toolType(); - button.priority = tool->priority(); - button.buttonGroupId = tool->uniqueId(); - button.visibilityCode = tool->activationShapeId(); - - emit addedTool(button, controller); + emit addedTool(tool->toolAction(), controller); } - } QPair KoToolManager::createTools(KoCanvasController *controller, ToolHelper *tool) diff --git a/libs/flake/KoToolManager_p.h b/libs/flake/KoToolManager_p.h --- a/libs/flake/KoToolManager_p.h +++ b/libs/flake/KoToolManager_p.h @@ -41,7 +41,6 @@ class KoShapeLayer; class ToolHelper; class CanvasData; -class QToolButton; class KoToolProxy; class Q_DECL_HIDDEN KoToolManager::Private @@ -106,48 +105,56 @@ bool layerExplicitlyDisabled; }; +class ShortcutToolAction; + /// \internal class ToolHelper : public QObject { Q_OBJECT public: explicit ToolHelper(KoToolFactoryBase *tool); - QToolButton *createButton(); + KoToolAction *toolAction(); /// wrapper around KoToolFactoryBase::id(); QString id() const; - /// wrapper around KoToolFactoryBase::toolTip(); + /// wrapper around KoToolFactoryBase::iconName(); + QString iconName() const; + /// descriptive text, as ; + QString text() const; + /// descriptive icon text, e.g. use on a button next to an icon or without one; + QString iconText() const; + /// tooltip of the tool, e.g. for tooltip of a button; QString toolTip() const; /// wrapper around KoToolFactoryBase::toolType(); QString toolType() const; /// wrapper around KoToolFactoryBase::activationShapeId(); QString activationShapeId() const; /// wrapper around KoToolFactoryBase::priority(); int priority() const; KoToolBase *createTool(KoCanvasBase *canvas) const; + ShortcutToolAction *createShortcutToolAction(QObject *parent); /// unique id, >= 0 int uniqueId() const { return m_uniqueId; } /// KAction->shortcut() if it exists, otherwise KoToolFactoryBase::shortcut() KShortcut shortcut() const; - /// Writes a tooltip for a button, appending the keyboard shortcut if we have one - QString buttonToolTip() const; - /// Associate an action with this tool - void setAction(KAction *a); + +public Q_SLOTS: + void activate(); Q_SIGNALS: - /// Emitted when the generated toolbox button is pressed. + /// Emitted when the tool should be activated, e.g. by pressing the tool's assigned button in the toolbox void toolActivated(ToolHelper *tool); private Q_SLOTS: - void buttonPressed(); - void actionUpdated(); + void shortcutToolActionUpdated(); private: - KoToolFactoryBase *m_toolFactory; + KoToolFactoryBase * const m_toolFactory; const int m_uniqueId; - QToolButton *button; - KAction *action; + KShortcut m_customShortcut; + bool m_hasCustomShortcut; + KoToolAction *m_toolAction; }; /// \internal @@ -170,18 +177,17 @@ /// \internal /// Helper class to provide a action for tool shortcuts -class ToolAction : public KAction +class ShortcutToolAction : public KAction { Q_OBJECT public: - ToolAction(KoToolManager* toolManager, const QString &id, const QString &name, QObject *parent); - virtual ~ToolAction(); + ShortcutToolAction(const QString &id, const QString &name, QObject *parent); + virtual ~ShortcutToolAction(); private Q_SLOTS: void actionTriggered(); private: - KoToolManager* m_toolManager; QString m_toolID; }; diff --git a/libs/flake/KoToolManager_p.cpp b/libs/flake/KoToolManager_p.cpp --- a/libs/flake/KoToolManager_p.cpp +++ b/libs/flake/KoToolManager_p.cpp @@ -23,9 +23,7 @@ #include #include #include -#include -#include -#include + static int newUniqueToolHelperId() { @@ -42,25 +40,24 @@ ToolHelper::ToolHelper(KoToolFactoryBase *tool) : m_toolFactory(tool), m_uniqueId(newUniqueToolHelperId()), - button(0), - action(0) -{ -} - -QToolButton* ToolHelper::createButton() + m_hasCustomShortcut(false), + m_toolAction(0) { - button = new QToolButton(); - button->setObjectName(m_toolFactory->id()); - button->setIcon(KIcon(m_toolFactory->iconName())); - button->setToolTip(buttonToolTip()); - - connect(button, SIGNAL(clicked()), this, SLOT(buttonPressed())); - return button; + // TODO: how to get an existing custom shortcut in the beginning here? + // Once the first ShortcutToolAction is added to the actionCollection, + // it will get any custom shortcut set by the actionCollection and + // by that trigger shortcutToolActionUpdated(). + // But until then shortcut() will report a wrong shortcut and e.g. show + // that in the tooltips of the KoToolBox. } -void ToolHelper::buttonPressed() +KoToolAction *ToolHelper::toolAction() { - emit toolActivated(this); + // create lazily + if (!m_toolAction) { + m_toolAction = new KoToolAction(this); + } + return m_toolAction; } QString ToolHelper::id() const @@ -73,23 +70,50 @@ return m_toolFactory->activationShapeId(); } -QString ToolHelper::toolTip() const +QString ToolHelper::iconName() const { + return m_toolFactory->iconName(); +} + +QString ToolHelper::text() const +{ + // TODO: add text property to KoToolFactoryBase return m_toolFactory->toolTip(); } -QString ToolHelper::buttonToolTip() const +QString ToolHelper::iconText() const { - return shortcut().isEmpty() ? - i18nc("@info:tooltip", "%1", toolTip()) : - i18nc("@info:tooltip %2 is shortcut", "%1 (%2)", toolTip(), - shortcut().toString()); + // TODO: add text iconText to KoToolFactoryBase + return m_toolFactory->toolTip(); } -void ToolHelper::actionUpdated() +QString ToolHelper::toolTip() const { - if (button) - button->setToolTip(buttonToolTip()); + return m_toolFactory->toolTip(); +} + +void ToolHelper::activate() +{ + emit toolActivated(this); +} + +void ToolHelper::shortcutToolActionUpdated() +{ + ShortcutToolAction *action = static_cast(sender()); + // check if shortcut changed + const KShortcut actionShortcut = action->shortcut(); + const KShortcut currentShortcut = shortcut(); + if (actionShortcut != currentShortcut) { + m_hasCustomShortcut = true; + m_customShortcut = actionShortcut; + if (m_toolAction) { + emit m_toolAction->changed(); + } + // no need to forward the new shortcut to the other ShortcutToolAction objects, + // they are synchronized behind the scenes + // Thus they will also trigger this method, but due to them having + // the same shortcut not result in any further action. + } } KoToolBase *ToolHelper::createTool(KoCanvasBase *canvas) const @@ -101,6 +125,16 @@ return tool; } +ShortcutToolAction* ToolHelper::createShortcutToolAction(QObject *parent) +{ + ShortcutToolAction* action = new ShortcutToolAction(id(), text(), parent); + action->setShortcut(shortcut()); + + connect(action, SIGNAL(changed()), SLOT(shortcutToolActionUpdated())); + + return action; +} + QString ToolHelper::toolType() const { return m_toolFactory->toolType(); @@ -113,18 +147,13 @@ KShortcut ToolHelper::shortcut() const { - if (action) { - return action->shortcut(); + if (m_hasCustomShortcut) { + return m_customShortcut; } return m_toolFactory->shortcut(); } -void ToolHelper::setAction(KAction *a) -{ - action = a; -} - // ************ Connector ********** Connector::Connector(KoShapeManager *parent) : QObject(parent), @@ -138,22 +167,22 @@ emit selectionChanged(m_shapeManager->selection()->selectedShapes()); } -// ************ ToolAction ********** -ToolAction::ToolAction(KoToolManager* toolManager, const QString &id, const QString &name, QObject *parent) - : KAction(name, parent), - m_toolManager(toolManager), - m_toolID(id) +// ************ ShortcutToolAction ********** +ShortcutToolAction::ShortcutToolAction(const QString &id, const QString &name, QObject *parent) + : KAction(name, parent) + , m_toolID(id) { connect(this, SIGNAL(triggered(bool)), this, SLOT(actionTriggered())); } -ToolAction::~ToolAction() +ShortcutToolAction::~ShortcutToolAction() { } -void ToolAction::actionTriggered() +void ShortcutToolAction::actionTriggered() { - m_toolManager->switchToolRequested(m_toolID); + // TODO: why not ToolHelper::activate(); and thus a slightly different behaviour? + KoToolManager::instance()->switchToolRequested(m_toolID); } diff --git a/libs/widgets/CMakeLists.txt b/libs/widgets/CMakeLists.txt --- a/libs/widgets/CMakeLists.txt +++ b/libs/widgets/CMakeLists.txt @@ -71,6 +71,7 @@ KoResourceFiltering.cpp KoResourceModelBase.cpp + KoToolBoxButton.cpp KoToolBox.cpp KoToolBoxDocker.cpp KoToolBoxFactory.cpp diff --git a/libs/widgets/KoModeBox.cpp b/libs/widgets/KoModeBox.cpp --- a/libs/widgets/KoModeBox.cpp +++ b/libs/widgets/KoModeBox.cpp @@ -36,7 +36,6 @@ #include #include -#include #include #include #include @@ -68,8 +67,8 @@ KoCanvasBase *canvas; QGridLayout *layout; - QList buttons; // buttons maintained by toolmanager - QList addedButtons; //buttons in the order added to QToolBox + QList toolActions; // toolActions maintained by toolmanager + QList addedToolActions; //tools in the order added to QToolBox QMap addedWidgets; QSet currentAuxWidgets; int activeId; @@ -85,28 +84,28 @@ QString KoModeBox::applicationName; -static bool compareButton(const KoToolButton &b1, const KoToolButton &b2) +static bool compareToolActions(const KoToolAction *b1, const KoToolAction *b2) { int b1Level; int b2Level; - if (b1.section.contains(KoModeBox::applicationName)) { + if (b1->section().contains(KoModeBox::applicationName)) { b1Level = 0; - } else if (b1.section.contains("main")) { + } else if (b1->section().contains("main")) { b1Level = 1; } else { b1Level = 2; } - if (b2.section.contains(KoModeBox::applicationName)) { + if (b2->section().contains(KoModeBox::applicationName)) { b2Level = 0; - } else if (b2.section.contains("main")) { + } else if (b2->section().contains("main")) { b2Level = 1; } else { b2Level = 2; } if (b1Level == b2Level) { - return b1.priority < b2.priority; + return b1->priority() < b2->priority(); } else { return b1Level < b2Level; } @@ -149,13 +148,13 @@ d->layout->setContentsMargins(0,0,0,0); setLayout(d->layout); - foreach(const KoToolButton &button, KoToolManager::instance()->createToolList()) { - addButton(button); + foreach(KoToolAction *toolAction, KoToolManager::instance()->toolActionList()) { + addToolAction(toolAction); } - qSort(d->buttons.begin(), d->buttons.end(), compareButton); + qSort(d->toolActions.begin(), d->toolActions.end(), compareToolActions); - // Update visibility of buttons + // Update visibility of toolActions updateShownTools(QList()); d->tabBar->setContextMenuPolicy(Qt::CustomContextMenu); @@ -168,8 +167,8 @@ this, SLOT(setCurrentLayer(const KoCanvasController *,const KoShapeLayer *))); connect(KoToolManager::instance(), SIGNAL(toolCodesSelected(QList)), this, SLOT(updateShownTools(QList))); connect(KoToolManager::instance(), - SIGNAL(addedTool(KoToolButton,KoCanvasController*)), - this, SLOT(toolAdded(KoToolButton,KoCanvasController*))); + SIGNAL(addedTool(KoToolAction*,KoCanvasController*)), + this, SLOT(toolAdded(KoToolAction*,KoCanvasController*))); connect(canvas, SIGNAL(toolOptionWidgetsChanged(const QList > &)), this, SLOT(setOptionWidgets(const QList > &))); @@ -180,10 +179,9 @@ delete d; } -void KoModeBox::addButton(const KoToolButton &button) +void KoModeBox::addToolAction(KoToolAction *toolAction) { - d->buttons.append(button); - button.button->setVisible(false); + d->toolActions.append(toolAction); } void KoModeBox::locationChanged(Qt::DockWidgetArea area) @@ -243,8 +241,8 @@ d->activeId = id; d->tabBar->blockSignals(true); int i = 0; - foreach (const KoToolButton &button, d->addedButtons) { - if (button.buttonGroupId == d->activeId) { + foreach (KoToolAction *toolAction, d->addedToolActions) { + if (toolAction->buttonGroupId() == d->activeId) { d->tabBar->setCurrentIndex(i); d->stack->setCurrentIndex(i); break; @@ -256,7 +254,7 @@ } } -QIcon KoModeBox::createTextIcon(const KoToolButton &button) const +QIcon KoModeBox::createTextIcon(KoToolAction *toolAction) const { QSize iconSize = d->tabBar->iconSize(); QFont smallFont = KGlobalSettings::generalFont(); @@ -277,9 +275,9 @@ } } - button.button->icon().paint(&p, 0, 0, iconSize.height(), 22); + KIcon(toolAction->iconName()).paint(&p, 0, 0, iconSize.height(), 22); - QTextLayout textLayout(button.button->toolTip(), smallFont, p.device()); + QTextLayout textLayout(toolAction->iconText(), smallFont, p.device()); QTextOption option; if (d->horizontalMode) { option = QTextOption(Qt::AlignVCenter | Qt::AlignHCenter); @@ -319,7 +317,7 @@ return QIcon(QPixmap::fromImage(pm)); } -QIcon KoModeBox::createSimpleIcon(const KoToolButton &button) const +QIcon KoModeBox::createSimpleIcon(KoToolAction *toolAction) const { QSize iconSize = d->tabBar->iconSize(); @@ -338,14 +336,14 @@ } } - button.button->icon().paint(&p, 0, 0, iconSize.height(), iconSize.width()); + KIcon(toolAction->iconName()).paint(&p, 0, 0, iconSize.height(), iconSize.width()); return QIcon(QPixmap::fromImage(pm)); } -void KoModeBox::addItem(const KoToolButton &button) +void KoModeBox::addItem(KoToolAction *toolAction) { - QWidget *oldwidget = d->addedWidgets[button.buttonGroupId]; + QWidget *oldwidget = d->addedWidgets[toolAction->buttonGroupId()]; QWidget *widget; // We need to create a new widget in all cases as QToolBox seeems to crash if we reuse @@ -360,14 +358,14 @@ widget->setLayout(layout); layout->setContentsMargins(0,0,0,0); layout->setSizeConstraint(QLayout::SetMinAndMaxSize); - d->addedWidgets[button.buttonGroupId] = widget; + d->addedWidgets[toolAction->buttonGroupId()] = widget; // Create a rotated icon with text if (d->iconMode == IconAndText) { - d->tabBar->addTab(createTextIcon(button), QString()); + d->tabBar->addTab(createTextIcon(toolAction), QString()); } else { - int index = d->tabBar->addTab(createSimpleIcon(button), QString()); - d->tabBar->setTabToolTip(index, button.button->toolTip()); + int index = d->tabBar->addTab(createSimpleIcon(toolAction), QString()); + d->tabBar->setTabToolTip(index, toolAction->toolTip()); } d->tabBar->blockSignals(false); ScrollArea *sa = new ScrollArea(); @@ -384,7 +382,7 @@ sa->setFrameShape(QFrame::NoFrame); sa->setFocusPolicy(Qt::NoFocus); d->stack->addWidget(sa); - d->addedButtons.append(button); + d->addedToolActions.append(toolAction); } void KoModeBox::updateShownTools(const QList &codes) @@ -401,36 +399,36 @@ d->stack->removeWidget(d->stack->widget(0)); } - d->addedButtons.clear(); + d->addedToolActions.clear(); int newIndex = -1; - foreach (const KoToolButton &button, d->buttons) { - QString toolCodes = button.visibilityCode; - if (button.buttonGroupId == d->activeId) { - newIndex = d->addedButtons.length(); + foreach (KoToolAction *toolAction, d->toolActions) { + const QString toolCodes = toolAction->visibilityCode(); + if (toolAction->buttonGroupId() == d->activeId) { + newIndex = d->addedToolActions.length(); } - if (button.section.contains(applicationName)) { - addItem(button); + if (toolAction->section().contains(applicationName)) { + addItem(toolAction); continue; - } else if (!button.section.contains("dynamic") - && !button.section.contains("main")) { + } else if (!toolAction->section().contains("dynamic") + && !toolAction->section().contains("main")) { continue; } if (toolCodes.startsWith(QLatin1String("flake/"))) { - addItem(button); + addItem(toolAction); continue; } if (toolCodes.endsWith( QLatin1String( "/always"))) { - addItem(button); + addItem(toolAction); continue; } else if (toolCodes.isEmpty() && codes.count() != 0) { - addItem(button); + addItem(toolAction); continue; } else { foreach (const QString &shapeCode, codes) { if (toolCodes.contains(shapeCode)) { - addItem(button); + addItem(toolAction); break; } } @@ -575,21 +573,21 @@ d->canvas = 0; } -void KoModeBox::toolAdded(const KoToolButton &button, KoCanvasController *canvas) +void KoModeBox::toolAdded(KoToolAction *toolAction, KoCanvasController *canvas) { if (canvas->canvas() == d->canvas) { - addButton(button); + addToolAction(toolAction); - qStableSort(d->buttons.begin(), d->buttons.end(), compareButton); + qStableSort(d->toolActions.begin(), d->toolActions.end(), compareToolActions); updateShownTools(QList()); } } void KoModeBox::toolSelected(int index) { if (index != -1) { - d->addedButtons[index].button->click(); + d->addedToolActions.at(index)->trigger(); } } diff --git a/libs/widgets/KoModeBox_p.h b/libs/widgets/KoModeBox_p.h --- a/libs/widgets/KoModeBox_p.h +++ b/libs/widgets/KoModeBox_p.h @@ -53,9 +53,6 @@ * The ModeBox is a container for tool buttons which are themselves * divided into sections. * - * Adding buttons using addButton() will allow you to show those buttons. You should connect - * the button to your handling method yourself. - * * @see KoToolManager */ class KoModeBox : public QWidget { @@ -66,21 +63,6 @@ ~KoModeBox(); /** - * Add a button to the modebox. - * The buttons should all be added before the first showing since adding will not really add - * them to the UI until setup() is called. - * - * @param button the new button. Please make sure you connect to the button yourself. - * @param section the section in which this button will be shown. Each section will be its own - * widget. - * @param priority the priority in the section. Lowest value means it will be shown first. - * @param buttonGroupId if passed this will allow you to use setActiveTool() to trigger - * this button - * @see setup() - */ - void addButton(const KoToolButton &button); - - /** * Should been called when the docker position has changed. * Organise widgets and icons and orientation of the tabs. * @@ -115,7 +97,7 @@ void setCurrentLayer(const KoCanvasController *canvas, const KoShapeLayer* newLayer); /// add a tool post-initialization. The tool will also be activated. - void toolAdded(const KoToolButton &button, KoCanvasController *canvas); + void toolAdded(KoToolAction *toolAction, KoCanvasController *canvas); /// slot for when a new item have been selected in the QToolBox void toolSelected(int index); @@ -129,6 +111,16 @@ /// switch tabs side void switchTabsSide(int); + /** + * Add a tool to the modebox. + * The tools should all be added before the first showing since adding will not really add + * them to the UI until setup() is called. + * + * @param toolAction the action of the tool + * @see setup() + */ + void addToolAction(KoToolAction *toolAction); + public: static QString applicationName; @@ -148,9 +140,9 @@ RightSide }; - QIcon createTextIcon(const KoToolButton &button) const; - QIcon createSimpleIcon(const KoToolButton &button) const; - void addItem(const KoToolButton &button); + QIcon createTextIcon(KoToolAction *toolAction) const; + QIcon createSimpleIcon(KoToolAction *toolAction) const; + void addItem(KoToolAction *toolAction); private: class Private; diff --git a/libs/widgets/KoToolBox.cpp b/libs/widgets/KoToolBox.cpp --- a/libs/widgets/KoToolBox.cpp +++ b/libs/widgets/KoToolBox.cpp @@ -21,6 +21,7 @@ #include "KoToolBox_p.h" #include "KoToolBoxLayout_p.h" +#include "KoToolBoxButton_p.h" #include #include @@ -35,7 +36,6 @@ #include #include -#include #include #include @@ -104,8 +104,8 @@ d->buttonGroup = new QButtonGroup(this); setLayout(d->layout); - foreach(const KoToolButton & button, KoToolManager::instance()->createToolList()) { - addButton(button); + foreach(KoToolAction *toolAction, KoToolManager::instance()->toolActionList()) { + addButton(toolAction); } // Update visibility of buttons @@ -117,8 +117,8 @@ this, SLOT(setCurrentLayer(const KoCanvasController*,const KoShapeLayer*))); connect(KoToolManager::instance(), SIGNAL(toolCodesSelected(QList)), this, SLOT(setButtonsVisible(QList))); connect(KoToolManager::instance(), - SIGNAL(addedTool(KoToolButton,KoCanvasController*)), - this, SLOT(toolAdded(KoToolButton,KoCanvasController*))); + SIGNAL(addedTool(KoToolAction*,KoCanvasController*)), + this, SLOT(toolAdded(KoToolAction*,KoCanvasController*))); QTimer::singleShot(0, this, SLOT(adjustToFit())); } @@ -128,42 +128,42 @@ delete d; } -void KoToolBox::addButton(const KoToolButton &button) +void KoToolBox::addButton(KoToolAction *toolAction) { - d->buttons << button.button; - // ensure same L&F - button.button->setCheckable(true); - button.button->setAutoRaise(true); + KoToolBoxButton *button = new KoToolBoxButton(toolAction, this); + + d->buttons << button; int toolbuttonSize = buttonSize(qApp->desktop()->screenNumber(this)); KConfigGroup cfg = KGlobal::config()->group("KoToolBox"); int iconSize = cfg.readEntry("iconSize", toolbuttonSize); - button.button->setIconSize(QSize(iconSize, iconSize)); + button->setIconSize(QSize(iconSize, iconSize)); foreach (Section *section, d->sections.values()) { section->setButtonSize(QSize(iconSize + BUTTON_MARGIN, iconSize + BUTTON_MARGIN)); } QString sectionToBeAddedTo; - if (button.section.contains(qApp->applicationName())) { + const QString section = toolAction->section(); + if (section.contains(qApp->applicationName())) { sectionToBeAddedTo = "main"; - } else if (button.section.contains("main")) { + } else if (section.contains("main")) { sectionToBeAddedTo = "main"; - } else if (button.section.contains("dynamic")) { + } else if (section.contains("dynamic")) { sectionToBeAddedTo = "dynamic"; } else { - sectionToBeAddedTo = button.section; + sectionToBeAddedTo = section; } Section *sectionWidget = d->sections.value(sectionToBeAddedTo); if (sectionWidget == 0) { sectionWidget = new Section(this); d->addSection(sectionWidget, sectionToBeAddedTo); } - sectionWidget->addButton(button.button, button.priority); + sectionWidget->addButton(button, toolAction->priority()); - d->buttonGroup->addButton(button.button, button.buttonGroupId); + d->buttonGroup->addButton(button, toolAction->buttonGroupId()); - d->visibilityCodes.insert(button.button, button.visibilityCode); + d->visibilityCodes.insert(button, toolAction->visibilityCode()); } void KoToolBox::setActiveTool(KoCanvasController *canvas, int id) @@ -275,10 +275,10 @@ d->floating = v; } -void KoToolBox::toolAdded(const KoToolButton &button, KoCanvasController *canvas) +void KoToolBox::toolAdded(KoToolAction *toolAction, KoCanvasController *canvas) { Q_UNUSED(canvas); - addButton(button); + addButton(toolAction); setButtonsVisible(QList()); } diff --git a/libs/widgets/KoToolBoxButton.cpp b/libs/widgets/KoToolBoxButton.cpp new file mode 100644 --- /dev/null +++ b/libs/widgets/KoToolBoxButton.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015 Friedrich W. H. Kossebau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "KoToolBoxButton_p.h" + +#include +#include +#include +#include + + +KoToolBoxButton::KoToolBoxButton(KoToolAction *toolAction, QWidget *parent) + : QToolButton(parent) + , m_toolAction(toolAction) +{ + setObjectName(m_toolAction->id()); + // ensure same L&F + setCheckable(true); + setAutoRaise(true); + setIcon(KIcon(m_toolAction->iconName())); + + setDataFromToolAction(); + + connect(this, SIGNAL(clicked(bool)), m_toolAction, SLOT(trigger())); + connect(m_toolAction, SIGNAL(changed()), SLOT(setDataFromToolAction())); +} + + +void KoToolBoxButton::setDataFromToolAction() +{ + const QString plainToolTip = m_toolAction->toolTip(); + const KShortcut shortcut = m_toolAction->shortcut(); + const QString toolTip = + shortcut.isEmpty() ? + i18nc("@info:tooltip", "%1", plainToolTip) : + i18nc("@info:tooltip %2 is shortcut", "%1 (%2)", plainToolTip, + shortcut.toString()); + + setToolTip(toolTip); +} diff --git a/libs/widgets/KoToolBoxButton_p.h b/libs/widgets/KoToolBoxButton_p.h new file mode 100644 --- /dev/null +++ b/libs/widgets/KoToolBoxButton_p.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 Friedrich W. H. Kossebau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KO_TOOLBOXBUTTON_H_ +#define _KO_TOOLBOXBUTTON_H_ + +#include + +class KoToolAction; + +class KoToolBoxButton : public QToolButton +{ + Q_OBJECT +public: + explicit KoToolBoxButton(KoToolAction *toolAction, QWidget * parent); + +private Q_SLOTS: + void setDataFromToolAction(); + +private: + KoToolAction *m_toolAction; +}; + +#endif // _KO_TOOLBOXBUTTON_H_ diff --git a/libs/widgets/KoToolBox_p.h b/libs/widgets/KoToolBox_p.h --- a/libs/widgets/KoToolBox_p.h +++ b/libs/widgets/KoToolBox_p.h @@ -29,7 +29,6 @@ #include -class QToolButton; class KoCanvasController; class KoShapeLayer; @@ -85,16 +84,16 @@ * The buttons should all be added before the first showing since adding will not really add * them to the UI until setup() is called. * - * @param button the new button. Please make sure you connect to the button yourself. + * @param toolAction the action of the tool * @see setup() */ - void addButton(const KoToolButton &button); + void addButton(KoToolAction *toolAction); private Q_SLOTS: void setCurrentLayer(const KoCanvasController *canvas, const KoShapeLayer* newLayer); /// add a tool post-initialization. The tool will also be activated. - void toolAdded(const KoToolButton &button, KoCanvasController *canvas); + void toolAdded(KoToolAction *toolAction, KoCanvasController *canvas); /// resize the toolbox to show the icons without any gap at the edge void adjustToFit();