1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "button_taskmenu.h"
30#include "inplace_editor.h"
31#include <qdesigner_formwindowcommand_p.h>
32#include <formwindowbase_p.h>
33
34#include <QtDesigner/abstractformwindow.h>
35#include <QtDesigner/abstractformwindowcursor.h>
36#include <QtDesigner/abstractformeditor.h>
37#include <QtDesigner/abstractmetadatabase.h>
38#include <QtDesigner/abstractobjectinspector.h>
39#include <QtDesigner/abstractpropertyeditor.h>
40
41#include <QtWidgets/qaction.h>
42#include <QtWidgets/qactiongroup.h>
43#include <QtWidgets/qmenu.h>
44#include <QtWidgets/qstyle.h>
45#include <QtWidgets/qstyleoption.h>
46#include <QtWidgets/qabstractbutton.h>
47#include <QtWidgets/qbuttongroup.h>
48#include <QtWidgets/qapplication.h>
49#include <QtCore/qdebug.h>
50
51Q_DECLARE_METATYPE(QButtonGroup*)
52
53QT_BEGIN_NAMESPACE
54
55namespace qdesigner_internal {
56
57enum { debugButtonMenu = 0 };
58
59using ButtonList = QList<QAbstractButton *>;
60using ButtonGroupList = QList<QButtonGroup *>;
61
62// ButtonGroupCommand: Base for commands handling button groups and button lists
63// addButtonsToGroup() and removeButtonsFromGroup() are low-level helpers for
64// adding/removing members to/from existing groups.
65//
66// createButtonGroup()/breakButtonGroup() create and remove the groups from scratch.
67// When using them in a command, the command must be executed within
68// a macro since it makes the form emit objectRemoved() which might cause other components
69// to add commands (for example, removal of signals and slots)
70class ButtonGroupCommand : public QDesignerFormWindowCommand {
71
72protected:
73 ButtonGroupCommand(const QString &description, QDesignerFormWindowInterface *formWindow);
74
75 void initialize(const ButtonList &bl, QButtonGroup *buttonGroup);
76
77 // Helper: Add the buttons to the group
78 void addButtonsToGroup();
79 // Helper; Remove the buttons
80 void removeButtonsFromGroup();
81
82 // Create the button group in Designer
83 void createButtonGroup();
84 // Remove the button group from Designer
85 void breakButtonGroup();
86
87public:
88 static QString nameList(const ButtonList& bl);
89 static ButtonGroupList managedButtonGroups(const QDesignerFormWindowInterface *formWindow);
90
91private:
92 ButtonList m_buttonList;
93 QButtonGroup *m_buttonGroup;
94};
95
96ButtonGroupCommand::ButtonGroupCommand(const QString &description, QDesignerFormWindowInterface *formWindow) :
97 QDesignerFormWindowCommand(description, formWindow),
98 m_buttonGroup(nullptr)
99{
100}
101
102void ButtonGroupCommand::initialize(const ButtonList &bl, QButtonGroup *buttonGroup)
103{
104 m_buttonList = bl;
105 m_buttonGroup = buttonGroup;
106}
107
108void ButtonGroupCommand::addButtonsToGroup()
109{
110 if (debugButtonMenu)
111 qDebug() << "Adding " << m_buttonList << " to " << m_buttonGroup;
112 const ButtonList::const_iterator cend = m_buttonList.constEnd();
113 for (ButtonList::const_iterator it = m_buttonList.constBegin(); it != cend; ++it)
114 m_buttonGroup->addButton(*it);
115}
116
117void ButtonGroupCommand::removeButtonsFromGroup()
118{
119 if (debugButtonMenu)
120 qDebug() << "Removing " << m_buttonList << " from " << m_buttonGroup;
121 const ButtonList::const_iterator cend = m_buttonList.constEnd();
122 for (ButtonList::const_iterator it = m_buttonList.constBegin(); it != cend; ++it)
123 m_buttonGroup->removeButton(*it);
124}
125
126void ButtonGroupCommand::createButtonGroup()
127{
128 if (debugButtonMenu)
129 qDebug() << "Creating " << m_buttonGroup << " from " << m_buttonList;
130
131 QDesignerFormWindowInterface *fw = formWindow();
132 QDesignerFormEditorInterface *core = fw->core();
133 core->metaDataBase()->add(object: m_buttonGroup);
134 addButtonsToGroup();
135 // Make button group visible
136 core->objectInspector()->setFormWindow(fw);
137}
138
139void ButtonGroupCommand::breakButtonGroup()
140{
141 if (debugButtonMenu)
142 qDebug() << "Removing " << m_buttonGroup << " consisting of " << m_buttonList;
143
144 QDesignerFormWindowInterface *fw = formWindow();
145 QDesignerFormEditorInterface *core = fw->core();
146 // Button group was selected, that is, break was invoked via its context menu. Remove it from property editor, select the buttons
147 if (core->propertyEditor()->object() == m_buttonGroup) {
148 fw->clearSelection(changePropertyDisplay: false);
149 const ButtonList::const_iterator cend = m_buttonList.constEnd();
150 for (ButtonList::const_iterator it = m_buttonList.constBegin(); it != cend; ++it)
151 fw->selectWidget(w: *it, select: true);
152 }
153 // Now remove and refresh object inspector
154 removeButtonsFromGroup();
155 // Notify components (for example, signal slot editor)
156 if (qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(object: fw))
157 fwb->emitObjectRemoved(o: m_buttonGroup);
158 core->metaDataBase()->remove(object: m_buttonGroup);
159 core->objectInspector()->setFormWindow(fw);
160}
161
162QString ButtonGroupCommand::nameList(const ButtonList& bl)
163{
164 QString rc;
165 const QChar quote = QLatin1Char('\'');
166 const QString separator = QStringLiteral(", ");
167 const int size = bl.size();
168 for (int i = 0; i < size; i++) {
169 if (i)
170 rc += separator;
171 rc += quote;
172 rc += bl[i]->objectName();
173 rc += quote;
174 }
175 return rc;
176
177}
178
179ButtonGroupList ButtonGroupCommand::managedButtonGroups(const QDesignerFormWindowInterface *formWindow)
180{
181 const QDesignerMetaDataBaseInterface *mdb = formWindow->core()->metaDataBase();
182 ButtonGroupList bl;
183 // Check 1st order children for managed button groups
184 const QObjectList children = formWindow->mainContainer()->children();
185 const QObjectList::const_iterator cend = children.constEnd();
186 for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) {
187 if (!(*it)->isWidgetType())
188 if (QButtonGroup *bg = qobject_cast<QButtonGroup *>(object: *it))
189 if (mdb->item(object: bg))
190 bl.push_back(t: bg);
191 }
192 return bl;
193}
194
195// --------------- CreateButtonGroupCommand
196// This command might be executed in a macro with a remove
197// command to move buttons from one group to a new one.
198class CreateButtonGroupCommand : public ButtonGroupCommand {
199public:
200 CreateButtonGroupCommand(QDesignerFormWindowInterface *formWindow);
201 bool init(const ButtonList &bl);
202
203 void undo() override { breakButtonGroup(); }
204 void redo() override { createButtonGroup(); }
205};
206
207CreateButtonGroupCommand::CreateButtonGroupCommand(QDesignerFormWindowInterface *formWindow) :
208 ButtonGroupCommand(QApplication::translate(context: "Command", key: "Create button group"), formWindow)
209{
210}
211
212bool CreateButtonGroupCommand::init(const ButtonList &bl)
213{
214 if (bl.isEmpty())
215 return false;
216 QDesignerFormWindowInterface *fw = formWindow();
217 QButtonGroup *buttonGroup = new QButtonGroup(fw->mainContainer());
218 buttonGroup->setObjectName(QStringLiteral("buttonGroup"));
219 fw->ensureUniqueObjectName(object: buttonGroup);
220 initialize(bl, buttonGroup);
221 return true;
222}
223
224// --------------- BreakButtonGroupCommand
225class BreakButtonGroupCommand : public ButtonGroupCommand {
226public:
227 BreakButtonGroupCommand(QDesignerFormWindowInterface *formWindow);
228 bool init(QButtonGroup *group);
229
230 void undo() override { createButtonGroup(); }
231 void redo() override { breakButtonGroup(); }
232};
233
234BreakButtonGroupCommand::BreakButtonGroupCommand(QDesignerFormWindowInterface *formWindow) :
235 ButtonGroupCommand(QApplication::translate(context: "Command", key: "Break button group"), formWindow)
236{
237}
238
239bool BreakButtonGroupCommand::init(QButtonGroup *group)
240{
241 if (!group)
242 return false;
243 initialize(bl: group->buttons(), buttonGroup: group);
244 setText(QApplication::translate(context: "Command", key: "Break button group '%1'").arg(a: group->objectName()));
245 return true;
246}
247
248// --------------- AddButtonsToGroupCommand
249// This command might be executed in a macro with a remove
250// command to move buttons from one group to a new one.
251class AddButtonsToGroupCommand : public ButtonGroupCommand {
252public:
253 AddButtonsToGroupCommand(QDesignerFormWindowInterface *formWindow);
254 void init(const ButtonList &bl, QButtonGroup *group);
255
256 void undo() override { removeButtonsFromGroup(); }
257 void redo() override { addButtonsToGroup(); }
258};
259
260AddButtonsToGroupCommand::AddButtonsToGroupCommand(QDesignerFormWindowInterface *formWindow) :
261 ButtonGroupCommand(QApplication::translate(context: "Command", key: "Add buttons to group"), formWindow)
262{
263}
264
265void AddButtonsToGroupCommand::init(const ButtonList &bl, QButtonGroup *group)
266{
267 initialize(bl, buttonGroup: group);
268 //: Command description for adding buttons to a QButtonGroup
269 setText(QApplication::translate(context: "Command", key: "Add '%1' to '%2'").arg(args: nameList(bl), args: group->objectName()));
270}
271
272//-------------------- RemoveButtonsFromGroupCommand
273class RemoveButtonsFromGroupCommand : public ButtonGroupCommand {
274public:
275 RemoveButtonsFromGroupCommand(QDesignerFormWindowInterface *formWindow);
276 bool init(const ButtonList &bl);
277
278 void undo() override { addButtonsToGroup(); }
279 void redo() override { removeButtonsFromGroup(); }
280};
281
282RemoveButtonsFromGroupCommand::RemoveButtonsFromGroupCommand(QDesignerFormWindowInterface *formWindow) :
283 ButtonGroupCommand(QApplication::translate(context: "Command", key: "Remove buttons from group"), formWindow)
284{
285}
286
287bool RemoveButtonsFromGroupCommand::init(const ButtonList &bl)
288{
289 if (bl.isEmpty())
290 return false;
291 QButtonGroup *group = bl.constFirst()->group();
292 if (!group)
293 return false;
294 if (bl.size() >= group->buttons().size())
295 return false;
296 initialize(bl, buttonGroup: group);
297 //: Command description for removing buttons from a QButtonGroup
298 setText(QApplication::translate(context: "Command", key: "Remove '%1' from '%2'").arg(args: nameList(bl), args: group->objectName()));
299 return true;
300}
301
302// -------- ButtonGroupMenu
303ButtonGroupMenu::ButtonGroupMenu(QObject *parent) :
304 QObject(parent),
305 m_selectGroupAction(new QAction(tr(s: "Select members"), this)),
306 m_breakGroupAction(new QAction(tr(s: "Break"), this))
307{
308 connect(sender: m_breakGroupAction, signal: &QAction::triggered, receiver: this, slot: &ButtonGroupMenu::breakGroup);
309 connect(sender: m_selectGroupAction, signal: &QAction::triggered, receiver: this, slot: &ButtonGroupMenu::selectGroup);
310}
311
312void ButtonGroupMenu::initialize(QDesignerFormWindowInterface *formWindow, QButtonGroup *buttonGroup, QAbstractButton *currentButton)
313{
314 m_buttonGroup = buttonGroup;
315 m_currentButton = currentButton;
316 m_formWindow = formWindow;
317 Q_ASSERT(m_formWindow);
318
319 const bool canBreak = buttonGroup != nullptr;
320 m_breakGroupAction->setEnabled(canBreak);
321 m_selectGroupAction->setEnabled(canBreak);
322}
323
324void ButtonGroupMenu::selectGroup()
325{
326 // Select and make current button "current" again by selecting it last (if there is any)
327 const ButtonList buttons = m_buttonGroup->buttons();
328 m_formWindow->clearSelection(changePropertyDisplay: false);
329 const ButtonList::const_iterator cend = buttons.constEnd();
330 for (ButtonList::const_iterator it = buttons.constBegin(); it != cend; ++it)
331 if (*it != m_currentButton)
332 m_formWindow->selectWidget(w: *it, select: true);
333 if (m_currentButton)
334 m_formWindow->selectWidget(w: m_currentButton, select: true);
335}
336
337void ButtonGroupMenu::breakGroup()
338{
339 BreakButtonGroupCommand *cmd = new BreakButtonGroupCommand(m_formWindow);
340 if (cmd->init(group: m_buttonGroup)) {
341 // Need a macro since the command might trigger additional commands
342 QUndoStack *history = m_formWindow->commandHistory();
343 history->beginMacro(text: cmd->text());
344 history->push(cmd);
345 history->endMacro();
346 } else {
347 qWarning(msg: "** WARNING Failed to initialize BreakButtonGroupCommand!");
348 delete cmd;
349 }
350}
351
352// ButtonGroupTaskMenu
353ButtonGroupTaskMenu::ButtonGroupTaskMenu(QButtonGroup *buttonGroup, QObject *parent) :
354 QObject(parent),
355 m_buttonGroup(buttonGroup)
356{
357 m_taskActions.push_back(t: m_menu.breakGroupAction());
358 m_taskActions.push_back(t: m_menu.selectGroupAction());
359}
360
361QAction *ButtonGroupTaskMenu::preferredEditAction() const
362{
363 return m_menu.selectGroupAction();
364}
365
366QList<QAction*> ButtonGroupTaskMenu::taskActions() const
367{
368 m_menu.initialize(formWindow: QDesignerFormWindowInterface::findFormWindow(obj: m_buttonGroup), buttonGroup: m_buttonGroup);
369 return m_taskActions;
370}
371
372// -------- Text area editor
373class ButtonTextTaskMenuInlineEditor : public TaskMenuInlineEditor
374{
375public:
376 ButtonTextTaskMenuInlineEditor(QAbstractButton *button, QObject *parent);
377
378protected:
379 QRect editRectangle() const override;
380};
381
382ButtonTextTaskMenuInlineEditor::ButtonTextTaskMenuInlineEditor(QAbstractButton *button, QObject *parent) :
383 TaskMenuInlineEditor(button, ValidationMultiLine, QStringLiteral("text"), parent)
384{
385}
386
387QRect ButtonTextTaskMenuInlineEditor::editRectangle() const
388{
389 QWidget *w = widget();
390 QStyleOptionButton opt;
391 opt.init(w);
392 return w->style()->subElementRect(subElement: QStyle::SE_PushButtonContents, option: &opt, widget: w);
393}
394
395// -------- Command link button description editor
396class LinkDescriptionTaskMenuInlineEditor : public TaskMenuInlineEditor
397{
398public:
399 LinkDescriptionTaskMenuInlineEditor(QAbstractButton *button, QObject *parent);
400
401protected:
402 QRect editRectangle() const override;
403};
404
405LinkDescriptionTaskMenuInlineEditor::LinkDescriptionTaskMenuInlineEditor(QAbstractButton *button, QObject *parent) :
406 TaskMenuInlineEditor(button, ValidationMultiLine, QStringLiteral("description"), parent)
407{
408}
409
410QRect LinkDescriptionTaskMenuInlineEditor::editRectangle() const
411{
412 QWidget *w = widget(); // TODO: What is the exact description area?
413 QStyleOptionButton opt;
414 opt.init(w);
415 return w->style()->subElementRect(subElement: QStyle::SE_PushButtonContents, option: &opt, widget: w);
416}
417
418// ----------- ButtonTaskMenu:
419
420ButtonTaskMenu::ButtonTaskMenu(QAbstractButton *button, QObject *parent) :
421 QDesignerTaskMenu(button, parent),
422 m_assignGroupSubMenu(new QMenu),
423 m_assignActionGroup(nullptr),
424 m_assignToGroupSubMenuAction(new QAction(tr(s: "Assign to button group"), this)),
425 m_currentGroupSubMenu(new QMenu),
426 m_currentGroupSubMenuAction(new QAction(tr(s: "Button group"), this)),
427 m_createGroupAction(new QAction(tr(s: "New button group"), this)),
428 m_preferredEditAction(new QAction(tr(s: "Change text..."), this)),
429 m_removeFromGroupAction(new QAction(tr(s: "None"), this))
430{
431 connect(sender: m_createGroupAction, signal: &QAction::triggered, receiver: this, slot: &ButtonTaskMenu::createGroup);
432 TaskMenuInlineEditor *textEditor = new ButtonTextTaskMenuInlineEditor(button, this);
433 connect(sender: m_preferredEditAction, signal: &QAction::triggered, receiver: textEditor, slot: &TaskMenuInlineEditor::editText);
434 connect(sender: m_removeFromGroupAction, signal: &QAction::triggered, receiver: this, slot: &ButtonTaskMenu::removeFromGroup);
435
436 m_assignToGroupSubMenuAction->setMenu(m_assignGroupSubMenu);
437
438 m_currentGroupSubMenu->addAction(action: m_groupMenu.breakGroupAction());
439 m_currentGroupSubMenu->addAction(action: m_groupMenu.selectGroupAction());
440 m_currentGroupSubMenuAction->setMenu(m_currentGroupSubMenu);
441
442
443 m_taskActions.append(t: m_preferredEditAction);
444 m_taskActions.append(t: m_assignToGroupSubMenuAction);
445 m_taskActions.append(t: m_currentGroupSubMenuAction);
446 m_taskActions.append(t: createSeparator());
447}
448
449ButtonTaskMenu::~ButtonTaskMenu()
450{
451 delete m_assignGroupSubMenu;
452 delete m_currentGroupSubMenu;
453}
454
455QAction *ButtonTaskMenu::preferredEditAction() const
456{
457 return m_preferredEditAction;
458}
459
460bool ButtonTaskMenu::refreshAssignMenu(const QDesignerFormWindowInterface *fw, int buttonCount, SelectionType st, QButtonGroup *currentGroup)
461{
462 // clear
463 if (m_assignActionGroup) {
464 delete m_assignActionGroup;
465 m_assignActionGroup = nullptr;
466 }
467 m_assignGroupSubMenu->clear();
468 if (st == OtherSelection)
469 return false;
470
471
472 // Assign to new: Need several
473 const bool canAssignToNewGroup = buttonCount > 1;
474 m_createGroupAction->setEnabled(canAssignToNewGroup);
475 if (canAssignToNewGroup)
476 m_assignGroupSubMenu->addAction(action: m_createGroupAction);
477
478 // Assign to other
479 const ButtonGroupList bl = ButtonGroupCommand::managedButtonGroups(formWindow: fw);
480 // Groups: Any groups to add to except the current?
481 const int groupCount = bl.size();
482 const bool hasAddGroups = groupCount > 1 || (groupCount == 1 && !bl.contains(t: currentGroup));
483 if (hasAddGroups) {
484 if (!m_assignGroupSubMenu->isEmpty())
485 m_assignGroupSubMenu->addSeparator();
486 // Create a new action group
487 m_assignActionGroup = new QActionGroup(this);
488 connect(sender: m_assignActionGroup, signal: &QActionGroup::triggered, receiver: this, slot: &ButtonTaskMenu::addToGroup);
489
490 const ButtonGroupList::const_iterator cend = bl.constEnd();
491 for (ButtonGroupList::const_iterator it = bl.constBegin(); it != cend; ++it) {
492 QButtonGroup *bg = *it;
493 if (*it != currentGroup) {
494 QAction *a = new QAction(bg->objectName(), m_assignGroupSubMenu);
495 a->setData(QVariant::fromValue(value: bg));
496 m_assignActionGroup->addAction(a);
497 m_assignGroupSubMenu->addAction(action: a);
498 }
499 }
500 }
501 // Can remove: A homogenous selection of another group that does not completely break it.
502 const bool canRemoveFromGroup = st == GroupedButtonSelection;
503 m_removeFromGroupAction->setEnabled(canRemoveFromGroup);
504 if (canRemoveFromGroup) {
505 if (!m_assignGroupSubMenu->isEmpty())
506 m_assignGroupSubMenu->addSeparator();
507 m_assignGroupSubMenu->addAction(action: m_removeFromGroupAction);
508 }
509 return !m_assignGroupSubMenu->isEmpty();
510}
511
512QList<QAction*> ButtonTaskMenu::taskActions() const
513{
514 ButtonTaskMenu *ncThis = const_cast<ButtonTaskMenu*>(this);
515 QButtonGroup *buttonGroup = nullptr;
516
517 QDesignerFormWindowInterface *fw = formWindow();
518 const SelectionType st = selectionType(cursor: fw->cursor(), ptrToGroup: &buttonGroup);
519
520 m_groupMenu.initialize(formWindow: fw, buttonGroup, currentButton: button());
521 const bool hasAssignOptions = ncThis->refreshAssignMenu(fw, buttonCount: fw->cursor()->selectedWidgetCount(), st, currentGroup: buttonGroup);
522 m_assignToGroupSubMenuAction->setVisible(hasAssignOptions);
523 // add/remove
524 switch (st) {
525 case UngroupedButtonSelection:
526 case OtherSelection:
527 m_currentGroupSubMenuAction->setVisible(false);
528 break;
529 case GroupedButtonSelection:
530 m_currentGroupSubMenuAction->setText(tr(s: "Button group '%1'").arg(a: buttonGroup->objectName()));
531 m_currentGroupSubMenuAction->setVisible(true);
532 break;
533 }
534
535 return m_taskActions + QDesignerTaskMenu::taskActions();
536}
537
538
539void ButtonTaskMenu::insertAction(int index, QAction *a)
540{
541 m_taskActions.insert(i: index, t: a);
542}
543
544/* Create a button list from the cursor selection */
545static ButtonList buttonList(const QDesignerFormWindowCursorInterface *cursor)
546{
547 ButtonList rc;
548 const int selectionCount = cursor->selectedWidgetCount();
549 for (int i = 0; i < selectionCount; i++) {
550 QAbstractButton *ab = qobject_cast<QAbstractButton *>(object: cursor->selectedWidget(index: i));
551 Q_ASSERT(ab);
552 rc += ab;
553 }
554 return rc;
555}
556
557// Create a command to remove the buttons from their group
558// If it would leave an empty or 1-member group behind, create a break command instead
559
560static QUndoCommand *createRemoveButtonsCommand(QDesignerFormWindowInterface *fw, const ButtonList &bl)
561{
562
563 QButtonGroup *bg = bl.constFirst()->group();
564 // Complete group or 1-member group?
565 if (bl.size() >= bg->buttons().size() - 1) {
566 BreakButtonGroupCommand *breakCmd = new BreakButtonGroupCommand(fw);
567 if (!breakCmd->init(group: bg)) {
568 qWarning(msg: "** WARNING Failed to initialize BreakButtonGroupCommand!");
569 delete breakCmd;
570 return nullptr;
571 }
572 return breakCmd;
573 }
574 // Just remove the buttons
575
576 RemoveButtonsFromGroupCommand *removeCmd = new RemoveButtonsFromGroupCommand(fw);
577 if (!removeCmd->init(bl)) {
578 qWarning(msg: "** WARNING Failed to initialize RemoveButtonsFromGroupCommand!");
579 delete removeCmd;
580 return nullptr;
581 }
582 return removeCmd;
583}
584
585void ButtonTaskMenu::createGroup()
586{
587 QDesignerFormWindowInterface *fw = formWindow();
588 const ButtonList bl = buttonList(cursor: fw->cursor());
589 // Do we need to remove the buttons from an existing group?
590 QUndoCommand *removeCmd = nullptr;
591 if (bl.constFirst()->group()) {
592 removeCmd = createRemoveButtonsCommand(fw, bl);
593 if (!removeCmd)
594 return;
595 }
596 // Add cmd
597 CreateButtonGroupCommand *addCmd = new CreateButtonGroupCommand(fw);
598 if (!addCmd->init(bl)) {
599 qWarning(msg: "** WARNING Failed to initialize CreateButtonGroupCommand!");
600 delete addCmd;
601 return;
602 }
603 // Need a macro [even if we only have the add command] since the command might trigger additional commands
604 QUndoStack *history = fw->commandHistory();
605 history->beginMacro(text: addCmd->text());
606 if (removeCmd)
607 history->push(cmd: removeCmd);
608 history->push(cmd: addCmd);
609 history->endMacro();
610}
611
612QAbstractButton *ButtonTaskMenu::button() const
613{
614 return qobject_cast<QAbstractButton *>(object: widget());
615}
616
617// Figure out if we have a homogenous selections (buttons of the same group or no group)
618ButtonTaskMenu::SelectionType ButtonTaskMenu::selectionType(const QDesignerFormWindowCursorInterface *cursor, QButtonGroup **ptrToGroup) const
619{
620 const int selectionCount = cursor->selectedWidgetCount();
621 if (!selectionCount)
622 return OtherSelection;
623
624 QButtonGroup *commonGroup = nullptr;
625 for (int i = 0; i < selectionCount; i++) {
626 if (const QAbstractButton *ab = qobject_cast<const QAbstractButton *>(object: cursor->selectedWidget(index: i))) {
627 QButtonGroup *buttonGroup = ab->group();
628 if (i) {
629 if (buttonGroup != commonGroup)
630 return OtherSelection;
631 } else {
632 commonGroup = buttonGroup;
633 }
634 } else {
635 return OtherSelection;
636 }
637 }
638
639 if (ptrToGroup)
640 *ptrToGroup = commonGroup;
641
642 return commonGroup ? GroupedButtonSelection : UngroupedButtonSelection;
643}
644
645void ButtonTaskMenu::addToGroup(QAction *a)
646{
647 QButtonGroup *bg = qvariant_cast<QButtonGroup *>(v: a->data());
648 Q_ASSERT(bg);
649
650 QDesignerFormWindowInterface *fw = formWindow();
651 const ButtonList bl = buttonList(cursor: fw->cursor());
652 // Do we need to remove the buttons from an existing group?
653 QUndoCommand *removeCmd = nullptr;
654 if (bl.constFirst()->group()) {
655 removeCmd = createRemoveButtonsCommand(fw, bl);
656 if (!removeCmd)
657 return;
658 }
659 AddButtonsToGroupCommand *addCmd = new AddButtonsToGroupCommand(fw);
660 addCmd->init(bl, group: bg);
661
662 QUndoStack *history = fw->commandHistory();
663 if (removeCmd) {
664 history->beginMacro(text: addCmd->text());
665 history->push(cmd: removeCmd);
666 history->push(cmd: addCmd);
667 history->endMacro();
668 } else {
669 history->push(cmd: addCmd);
670 }
671}
672
673void ButtonTaskMenu::removeFromGroup()
674{
675 QDesignerFormWindowInterface *fw = formWindow();
676 if (QUndoCommand *cmd = createRemoveButtonsCommand(fw, bl: buttonList(cursor: fw->cursor())))
677 fw->commandHistory()->push(cmd);
678}
679
680// -------------- CommandLinkButtonTaskMenu
681
682CommandLinkButtonTaskMenu::CommandLinkButtonTaskMenu(QCommandLinkButton *button, QObject *parent) :
683 ButtonTaskMenu(button, parent)
684{
685 TaskMenuInlineEditor *descriptonEditor = new LinkDescriptionTaskMenuInlineEditor(button, this);
686 QAction *descriptionAction = new QAction(tr(s: "Change description..."), this);
687 connect(sender: descriptionAction, signal: &QAction::triggered, receiver: descriptonEditor, slot: &TaskMenuInlineEditor::editText);
688 insertAction(index: 1, a: descriptionAction);
689}
690
691}
692
693QT_END_NAMESPACE
694

source code of qttools/src/designer/src/components/taskmenu/button_taskmenu.cpp