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 "qdesigner_taskmenu_p.h"
30 #include "qdesigner_command_p.h"
31 #include "qdesigner_command2_p.h"
32 #include "richtexteditor_p.h"
33 #include "plaintexteditor_p.h"
34 #include "stylesheeteditor_p.h"
35 #include "qlayout_widget_p.h"
36 #include "layout_p.h"
37 #include "selectsignaldialog_p.h"
38 #include "spacer_widget_p.h"
39 #include "textpropertyeditor_p.h"
40 #include "promotiontaskmenu_p.h"
41 #include "metadatabase_p.h"
42 #include "signalslotdialog_p.h"
43 #include "qdesigner_membersheet_p.h"
44 #include "qdesigner_propertycommand_p.h"
45 #include "qdesigner_utils_p.h"
46 #include "qdesigner_objectinspector_p.h"
47 #include "morphmenu_p.h"
48 #include "formlayoutmenu_p.h"
49 #include "widgetfactory_p.h"
50 #include "abstractintrospection_p.h"
51 #include "widgetdatabase_p.h"
52
53 #include <shared_enums_p.h>
54
55 #include <QtDesigner/abstractformwindow.h>
56 #include <QtDesigner/abstractformwindowcursor.h>
57 #include <QtDesigner/propertysheet.h>
58 #include <QtDesigner/abstractformeditor.h>
59 #include <QtDesigner/abstractlanguage.h>
60 #include <QtDesigner/abstractintegration.h>
61 #include <QtDesigner/qextensionmanager.h>
62
63 #include <QtWidgets/qaction.h>
64 #include <QtWidgets/qactiongroup.h>
65 #include <QtWidgets/qwidget.h>
66 #include <QtWidgets/qmenubar.h>
67 #include <QtWidgets/qmainwindow.h>
68 #include <QtWidgets/qstatusbar.h>
69 #include <QtWidgets/qdialogbuttonbox.h>
70 #include <QtWidgets/qboxlayout.h>
71 #include <QtWidgets/qpushbutton.h>
72 #include <QtWidgets/qundostack.h>
73 #include <QtCore/qdebug.h>
74 #include <QtCore/qcoreapplication.h>
75
76 QT_BEGIN_NAMESPACE
77
createSeparatorHelper(QObject * parent)78 static inline QAction *createSeparatorHelper(QObject *parent) {
79 QAction *rc = new QAction(parent);
80 rc->setSeparator(true);
81 return rc;
82 }
83
objName(const QDesignerFormEditorInterface * core,QObject * object)84 static QString objName(const QDesignerFormEditorInterface *core, QObject *object) {
85 QDesignerPropertySheetExtension *sheet
86 = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), object);
87 Q_ASSERT(sheet != nullptr);
88
89 const QString objectNameProperty = QStringLiteral("objectName");
90 const int index = sheet->indexOf(objectNameProperty);
91 const QVariant v = sheet->property(index);
92 if (v.canConvert<qdesigner_internal::PropertySheetStringValue>())
93 return v.value<qdesigner_internal::PropertySheetStringValue>().value();
94 return v.toString();
95 }
96
97 enum { ApplyMinimumWidth = 0x1, ApplyMinimumHeight = 0x2, ApplyMaximumWidth = 0x4, ApplyMaximumHeight = 0x8 };
98
99 namespace {
100 // --------------- ObjectNameDialog
101 class ObjectNameDialog : public QDialog
102 {
103 public:
104 ObjectNameDialog(QWidget *parent, const QString &oldName);
105 QString newObjectName() const;
106
107 private:
108 qdesigner_internal::TextPropertyEditor *m_editor;
109 };
110
ObjectNameDialog(QWidget * parent,const QString & oldName)111 ObjectNameDialog::ObjectNameDialog(QWidget *parent, const QString &oldName)
112 : QDialog(parent),
113 m_editor( new qdesigner_internal::TextPropertyEditor(this, qdesigner_internal::TextPropertyEditor::EmbeddingNone,
114 qdesigner_internal::ValidationObjectName))
115 {
116 setWindowTitle(QCoreApplication::translate("ObjectNameDialog", "Change Object Name"));
117 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
118
119 QVBoxLayout *vboxLayout = new QVBoxLayout(this);
120 vboxLayout->addWidget(new QLabel(QCoreApplication::translate("ObjectNameDialog", "Object Name")));
121
122 m_editor->setText(oldName);
123 m_editor->selectAll();
124 m_editor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
125 vboxLayout->addWidget(m_editor);
126
127 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
128 Qt::Horizontal, this);
129 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
130 okButton->setDefault(true);
131 vboxLayout->addWidget(buttonBox);
132
133 connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
134 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
135 }
136
newObjectName() const137 QString ObjectNameDialog::newObjectName() const
138 {
139 return m_editor->text();
140 }
141 } // namespace
142
143 namespace qdesigner_internal {
144
145 // Sub menu displaying the alignment options of a widget in a managed
146 // grid/box layout cell.
147 class LayoutAlignmentMenu {
148 public:
149 explicit LayoutAlignmentMenu(QObject *parent);
150
subMenuAction() const151 QAction *subMenuAction() const { return m_subMenuAction; }
152
153 void connect(QObject *receiver, const char *aSlot);
154
155 // Set up enabled state and checked actions according to widget (managed box/grid)
156 bool setAlignment(const QDesignerFormEditorInterface *core, QWidget *w);
157
158 // Return the currently checked alignment
159 Qt::Alignment alignment() const;
160
161 private:
162 enum Actions { HorizNone, Left, HorizCenter, Right, VerticalNone, Top, VerticalCenter, Bottom };
163 static QAction *createAction(const QString &text, int data, QMenu *menu, QActionGroup *ag);
164
165 QAction *m_subMenuAction;
166 QActionGroup *m_horizGroup;
167 QActionGroup *m_verticalGroup;
168 QAction *m_actions[Bottom + 1];
169 };
170
createAction(const QString & text,int data,QMenu * menu,QActionGroup * ag)171 QAction *LayoutAlignmentMenu::createAction(const QString &text, int data, QMenu *menu, QActionGroup *ag)
172 {
173 QAction * a = new QAction(text, nullptr);
174 a->setCheckable(true);
175 a->setData(QVariant(data));
176 menu->addAction(a);
177 ag->addAction(a);
178 return a;
179 }
180
LayoutAlignmentMenu(QObject * parent)181 LayoutAlignmentMenu::LayoutAlignmentMenu(QObject *parent) :
182 m_subMenuAction(new QAction(QDesignerTaskMenu::tr("Layout Alignment"), parent)),
183 m_horizGroup(new QActionGroup(parent)),
184 m_verticalGroup(new QActionGroup(parent))
185 {
186 m_horizGroup->setExclusive(true);
187 m_verticalGroup->setExclusive(true);
188
189 QMenu *menu = new QMenu;
190 m_subMenuAction->setMenu(menu);
191
192 m_actions[HorizNone] = createAction(QDesignerTaskMenu::tr("No Horizontal Alignment"), 0, menu, m_horizGroup);
193 m_actions[Left] = createAction(QDesignerTaskMenu::tr("Left"), Qt::AlignLeft, menu, m_horizGroup);
194 m_actions[HorizCenter] = createAction(QDesignerTaskMenu::tr("Center Horizontally"), Qt::AlignHCenter, menu, m_horizGroup);
195 m_actions[Right] = createAction(QDesignerTaskMenu::tr("Right"), Qt::AlignRight, menu, m_horizGroup);
196 menu->addSeparator();
197 m_actions[VerticalNone] = createAction(QDesignerTaskMenu::tr("No Vertical Alignment"), 0, menu, m_verticalGroup);
198 m_actions[Top] = createAction(QDesignerTaskMenu::tr("Top"), Qt::AlignTop, menu, m_verticalGroup);
199 m_actions[VerticalCenter] = createAction(QDesignerTaskMenu::tr("Center Vertically"), Qt::AlignVCenter, menu, m_verticalGroup);
200 m_actions[Bottom] = createAction(QDesignerTaskMenu::tr("Bottom"), Qt::AlignBottom, menu, m_verticalGroup);
201 }
202
connect(QObject * receiver,const char * aSlot)203 void LayoutAlignmentMenu::connect(QObject *receiver, const char *aSlot)
204 {
205 QObject::connect(m_horizGroup, SIGNAL(triggered(QAction*)), receiver, aSlot);
206 QObject::connect(m_verticalGroup, SIGNAL(triggered(QAction*)), receiver, aSlot);
207 }
208
setAlignment(const QDesignerFormEditorInterface * core,QWidget * w)209 bool LayoutAlignmentMenu::setAlignment(const QDesignerFormEditorInterface *core, QWidget *w)
210 {
211 bool enabled;
212 const Qt::Alignment alignment = LayoutAlignmentCommand::alignmentOf(core, w, &enabled);
213 if (!enabled) {
214 m_subMenuAction->setEnabled(false);
215 m_actions[HorizNone]->setChecked(true);
216 m_actions[VerticalNone]->setChecked(true);
217 return false;
218 }
219 // Get alignment
220 switch (alignment & Qt::AlignHorizontal_Mask) {
221 case Qt::AlignLeft:
222 m_actions[Left]->setChecked(true);
223 break;
224 case Qt::AlignHCenter:
225 m_actions[HorizCenter]->setChecked(true);
226 break;
227 case Qt::AlignRight:
228 m_actions[Right]->setChecked(true);
229 break;
230 default:
231 m_actions[HorizNone]->setChecked(true);
232 break;
233 }
234 switch (alignment & Qt::AlignVertical_Mask) {
235 case Qt::AlignTop:
236 m_actions[Top]->setChecked(true);
237 break;
238 case Qt::AlignVCenter:
239 m_actions[VerticalCenter]->setChecked(true);
240 break;
241 case Qt::AlignBottom:
242 m_actions[Bottom]->setChecked(true);
243 break;
244 default:
245 m_actions[VerticalNone]->setChecked(true);
246 break;
247 }
248 return true;
249 }
250
alignment() const251 Qt::Alignment LayoutAlignmentMenu::alignment() const
252 {
253 Qt::Alignment alignment;
254 if (const QAction *horizAction = m_horizGroup->checkedAction())
255 if (const int horizAlign = horizAction->data().toInt())
256 alignment |= static_cast<Qt::Alignment>(horizAlign);
257 if (const QAction *vertAction = m_verticalGroup->checkedAction())
258 if (const int vertAlign = vertAction->data().toInt())
259 alignment |= static_cast<Qt::Alignment>(vertAlign);
260 return alignment;
261 }
262
263 // -------------- QDesignerTaskMenuPrivate
264 class QDesignerTaskMenuPrivate {
265 public:
266 QDesignerTaskMenuPrivate(QWidget *widget, QObject *parent);
267
268 QDesignerTaskMenu *m_q;
269 QPointer<QWidget> m_widget;
270 QAction *m_separator;
271 QAction *m_separator2;
272 QAction *m_separator3;
273 QAction *m_separator4;
274 QAction *m_separator5;
275 QAction *m_separator6;
276 QAction *m_separator7;
277 QAction *m_changeObjectNameAction;
278 QAction *m_changeToolTip;
279 QAction *m_changeWhatsThis;
280 QAction *m_changeStyleSheet;
281 MorphMenu *m_morphMenu;
282 FormLayoutMenu *m_formLayoutMenu;
283
284 QAction *m_addMenuBar;
285 QAction *m_addToolBar;
286 QAction *m_addAreaSubMenu;
287 QAction *m_addStatusBar;
288 QAction *m_removeStatusBar;
289 QAction *m_containerFakeMethods;
290 QAction *m_navigateToSlot;
291 PromotionTaskMenu* m_promotionTaskMenu;
292 QActionGroup *m_sizeActionGroup;
293 LayoutAlignmentMenu m_layoutAlignmentMenu;
294 QAction *m_sizeActionsSubMenu;
295 };
296
QDesignerTaskMenuPrivate(QWidget * widget,QObject * parent)297 QDesignerTaskMenuPrivate::QDesignerTaskMenuPrivate(QWidget *widget, QObject *parent) :
298 m_q(nullptr),
299 m_widget(widget),
300 m_separator(createSeparatorHelper(parent)),
301 m_separator2(createSeparatorHelper(parent)),
302 m_separator3(createSeparatorHelper(parent)),
303 m_separator4(createSeparatorHelper(parent)),
304 m_separator5(createSeparatorHelper(parent)),
305 m_separator6(createSeparatorHelper(parent)),
306 m_separator7(createSeparatorHelper(parent)),
307 m_changeObjectNameAction(new QAction(QDesignerTaskMenu::tr("Change objectName..."), parent)),
308 m_changeToolTip(new QAction(QDesignerTaskMenu::tr("Change toolTip..."), parent)),
309 m_changeWhatsThis(new QAction(QDesignerTaskMenu::tr("Change whatsThis..."), parent)),
310 m_changeStyleSheet(new QAction(QDesignerTaskMenu::tr("Change styleSheet..."), parent)),
311 m_morphMenu(new MorphMenu(parent)),
312 m_formLayoutMenu(new FormLayoutMenu(parent)),
313 m_addMenuBar(new QAction(QDesignerTaskMenu::tr("Create Menu Bar"), parent)),
314 m_addToolBar(new QAction(QDesignerTaskMenu::tr("Add Tool Bar"), parent)),
315 m_addAreaSubMenu(new QAction(QDesignerTaskMenu::tr("Add Tool Bar to Other Area"), parent)),
316 m_addStatusBar(new QAction(QDesignerTaskMenu::tr("Create Status Bar"), parent)),
317 m_removeStatusBar(new QAction(QDesignerTaskMenu::tr("Remove Status Bar"), parent)),
318 m_containerFakeMethods(new QAction(QDesignerTaskMenu::tr("Change signals/slots..."), parent)),
319 m_navigateToSlot(new QAction(QDesignerTaskMenu::tr("Go to slot..."), parent)),
320 m_promotionTaskMenu(new PromotionTaskMenu(widget, PromotionTaskMenu::ModeManagedMultiSelection, parent)),
321 m_sizeActionGroup(new QActionGroup(parent)),
322 m_layoutAlignmentMenu(parent),
323 m_sizeActionsSubMenu(new QAction(QDesignerTaskMenu::tr("Size Constraints"), parent))
324 {
325 QMenu *sizeMenu = new QMenu;
326 m_sizeActionsSubMenu->setMenu(sizeMenu);
327 QAction *sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Minimum Width"));
328 sizeAction->setData(ApplyMinimumWidth);
329 sizeMenu->addAction(sizeAction);
330
331 sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Minimum Height"));
332 sizeAction->setData(ApplyMinimumHeight);
333 sizeMenu->addAction(sizeAction);
334
335 sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Minimum Size"));
336 sizeAction->setData(ApplyMinimumWidth|ApplyMinimumHeight);
337 sizeMenu->addAction(sizeAction);
338
339 sizeMenu->addSeparator();
340
341 sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Maximum Width"));
342 sizeAction->setData(ApplyMaximumWidth);
343 sizeMenu->addAction(sizeAction);
344
345 sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Maximum Height"));
346 sizeAction->setData(ApplyMaximumHeight);
347 sizeMenu->addAction(sizeAction);
348
349 sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Maximum Size"));
350 sizeAction->setData(ApplyMaximumWidth|ApplyMaximumHeight);
351 sizeMenu->addAction(sizeAction);
352 }
353
354 // --------- QDesignerTaskMenu
QDesignerTaskMenu(QWidget * widget,QObject * parent)355 QDesignerTaskMenu::QDesignerTaskMenu(QWidget *widget, QObject *parent) :
356 QObject(parent),
357 d(new QDesignerTaskMenuPrivate(widget, parent))
358 {
359 d->m_q = this;
360 Q_ASSERT(qobject_cast<QDesignerFormWindowInterface*>(widget) == 0);
361
362 connect(d->m_changeObjectNameAction, &QAction::triggered, this, &QDesignerTaskMenu::changeObjectName);
363 connect(d->m_changeToolTip, &QAction::triggered, this, &QDesignerTaskMenu::changeToolTip);
364 connect(d->m_changeWhatsThis, &QAction::triggered, this, &QDesignerTaskMenu::changeWhatsThis);
365 connect(d->m_changeStyleSheet, &QAction::triggered, this, &QDesignerTaskMenu::changeStyleSheet);
366 connect(d->m_addMenuBar, &QAction::triggered, this, &QDesignerTaskMenu::createMenuBar);
367 connect(d->m_addToolBar, &QAction::triggered, this,
368 [this] () { this->addToolBar(Qt::TopToolBarArea); });
369 auto areaMenu = new QMenu;
370 d->m_addAreaSubMenu->setMenu(areaMenu);
371 areaMenu->addAction(QDesignerTaskMenu::tr("Left"),
372 [this] () { this->addToolBar(Qt::LeftToolBarArea); });
373 areaMenu->addAction(QDesignerTaskMenu::tr("Right"),
374 [this] () { this->addToolBar(Qt::RightToolBarArea); });
375 areaMenu->addAction(QDesignerTaskMenu::tr("Bottom"),
376 [this] () { this->addToolBar(Qt::BottomToolBarArea); });
377 connect(d->m_addStatusBar, &QAction::triggered, this, &QDesignerTaskMenu::createStatusBar);
378 connect(d->m_removeStatusBar, &QAction::triggered, this, &QDesignerTaskMenu::removeStatusBar);
379 connect(d->m_containerFakeMethods, &QAction::triggered, this, &QDesignerTaskMenu::containerFakeMethods);
380 connect(d->m_navigateToSlot, &QAction::triggered, this, &QDesignerTaskMenu::slotNavigateToSlot);
381 connect(d->m_sizeActionGroup, &QActionGroup::triggered, this, &QDesignerTaskMenu::applySize);
382 d->m_layoutAlignmentMenu.connect(this, SLOT(slotLayoutAlignment()));
383 }
384
~QDesignerTaskMenu()385 QDesignerTaskMenu::~QDesignerTaskMenu()
386 {
387 delete d;
388 }
389
createSeparator()390 QAction *QDesignerTaskMenu::createSeparator()
391 {
392 return createSeparatorHelper(this);
393 }
394
widget() const395 QWidget *QDesignerTaskMenu::widget() const
396 {
397 return d->m_widget;
398 }
399
formWindow() const400 QDesignerFormWindowInterface *QDesignerTaskMenu::formWindow() const
401 {
402 QDesignerFormWindowInterface *result = QDesignerFormWindowInterface::findFormWindow(widget());
403 Q_ASSERT(result != nullptr);
404 return result;
405 }
406
createMenuBar()407 void QDesignerTaskMenu::createMenuBar()
408 {
409 if (QDesignerFormWindowInterface *fw = formWindow()) {
410 QMainWindow *mw = qobject_cast<QMainWindow*>(fw->mainContainer());
411 if (!mw) {
412 // ### warning message
413 return;
414 }
415
416 CreateMenuBarCommand *cmd = new CreateMenuBarCommand(fw);
417 cmd->init(mw);
418 fw->commandHistory()->push(cmd);
419 }
420 }
421
addToolBar(Qt::ToolBarArea area)422 void QDesignerTaskMenu::addToolBar(Qt::ToolBarArea area)
423 {
424 if (QDesignerFormWindowInterface *fw = formWindow()) {
425 QMainWindow *mw = qobject_cast<QMainWindow*>(fw->mainContainer());
426 if (!mw) {
427 // ### warning message
428 return;
429 }
430
431 AddToolBarCommand *cmd = new AddToolBarCommand(fw);
432 cmd->init(mw, area);
433 fw->commandHistory()->push(cmd);
434 }
435 }
436
createStatusBar()437 void QDesignerTaskMenu::createStatusBar()
438 {
439 if (QDesignerFormWindowInterface *fw = formWindow()) {
440 QMainWindow *mw = qobject_cast<QMainWindow*>(fw->mainContainer());
441 if (!mw) {
442 // ### warning message
443 return;
444 }
445
446 CreateStatusBarCommand *cmd = new CreateStatusBarCommand(fw);
447 cmd->init(mw);
448 fw->commandHistory()->push(cmd);
449 }
450 }
451
removeStatusBar()452 void QDesignerTaskMenu::removeStatusBar()
453 {
454 if (QDesignerFormWindowInterface *fw = formWindow()) {
455 QMainWindow *mw = qobject_cast<QMainWindow*>(fw->mainContainer());
456 if (!mw) {
457 // ### warning message
458 return;
459 }
460
461 DeleteStatusBarCommand *cmd = new DeleteStatusBarCommand(fw);
462 cmd->init(mw->findChild<QStatusBar *>(QString(), Qt::FindDirectChildrenOnly));
463 fw->commandHistory()->push(cmd);
464 }
465 }
466
taskActions() const467 QList<QAction*> QDesignerTaskMenu::taskActions() const
468 {
469 QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(widget());
470 Q_ASSERT(formWindow);
471
472 const bool isMainContainer = formWindow->mainContainer() == widget();
473
474 QList<QAction*> actions;
475
476 if (const QMainWindow *mw = qobject_cast<const QMainWindow*>(formWindow->mainContainer())) {
477 if (isMainContainer || mw->centralWidget() == widget()) {
478 if (mw->findChild<QMenuBar *>(QString(), Qt::FindDirectChildrenOnly) == nullptr)
479 actions.append(d->m_addMenuBar);
480
481 actions.append(d->m_addToolBar);
482 actions.append(d->m_addAreaSubMenu);
483 // ### create the status bar
484 if (mw->findChild<QStatusBar *>(QString(), Qt::FindDirectChildrenOnly))
485 actions.append(d->m_removeStatusBar);
486 else
487 actions.append(d->m_addStatusBar);
488
489 actions.append(d->m_separator);
490 }
491 }
492 actions.append(d->m_changeObjectNameAction);
493 d->m_morphMenu->populate(d->m_widget, formWindow, actions);
494 d->m_formLayoutMenu->populate(d->m_widget, formWindow, actions);
495 actions.append(d->m_separator2);
496 actions.append(d->m_changeToolTip);
497 actions.append(d->m_changeWhatsThis);
498 actions.append(d->m_changeStyleSheet);
499 actions.append(d->m_separator6);
500 actions.append(d->m_sizeActionsSubMenu);
501 if (d->m_layoutAlignmentMenu.setAlignment(formWindow->core(), d->m_widget))
502 actions.append(d->m_layoutAlignmentMenu.subMenuAction());
503
504 d->m_promotionTaskMenu->setMode(formWindow->isManaged(d->m_widget) ?
505 PromotionTaskMenu::ModeManagedMultiSelection : PromotionTaskMenu::ModeUnmanagedMultiSelection);
506 d->m_promotionTaskMenu->addActions(formWindow, PromotionTaskMenu::LeadingSeparator, actions);
507
508 if (isMainContainer && !qt_extension<QDesignerLanguageExtension*>(formWindow->core()->extensionManager(), formWindow->core())) {
509 actions.append(d->m_separator5);
510 actions.append(d->m_containerFakeMethods);
511 }
512
513 if (isSlotNavigationEnabled(formWindow->core())) {
514 actions.append(d->m_separator7);
515 actions.append(d->m_navigateToSlot);
516 }
517
518 return actions;
519 }
520
changeObjectName()521 void QDesignerTaskMenu::changeObjectName()
522 {
523 QDesignerFormWindowInterface *fw = formWindow();
524 Q_ASSERT(fw != nullptr);
525
526 const QString oldObjectName = objName(fw->core(), widget());
527
528 ObjectNameDialog dialog(fw, oldObjectName);
529 if (dialog.exec() == QDialog::Accepted) {
530 const QString newObjectName = dialog.newObjectName();
531 if (!newObjectName.isEmpty() && newObjectName != oldObjectName ) {
532 const QString objectNameProperty = QStringLiteral("objectName");
533 PropertySheetStringValue objectNameValue;
534 objectNameValue.setValue(newObjectName);
535 setProperty(fw, CurrentWidgetMode, objectNameProperty, QVariant::fromValue(objectNameValue));
536 }
537 }
538 }
539
changeTextProperty(const QString & propertyName,const QString & windowTitle,PropertyMode pm,Qt::TextFormat desiredFormat)540 void QDesignerTaskMenu::changeTextProperty(const QString &propertyName, const QString &windowTitle, PropertyMode pm, Qt::TextFormat desiredFormat)
541 {
542 QDesignerFormWindowInterface *fw = formWindow();
543 if (!fw)
544 return;
545 Q_ASSERT(d->m_widget->parentWidget() != nullptr);
546
547 const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(fw->core()->extensionManager(), d->m_widget);
548 const int index = sheet->indexOf(propertyName);
549 if (index == -1) {
550 qDebug() << "** WARNING Invalid property" << propertyName << " passed to changeTextProperty!";
551 return;
552 }
553 PropertySheetStringValue textValue = qvariant_cast<PropertySheetStringValue>(sheet->property(index));
554 const QString oldText = textValue.value();
555 // Pop up respective dialog
556 bool accepted = false;
557 QString newText;
558 switch (desiredFormat) {
559 case Qt::PlainText: {
560 PlainTextEditorDialog dlg(fw->core(), fw);
561 if (!windowTitle.isEmpty())
562 dlg.setWindowTitle(windowTitle);
563 dlg.setDefaultFont(d->m_widget->font());
564 dlg.setText(oldText);
565 accepted = dlg.showDialog() == QDialog::Accepted;
566 newText = dlg.text();
567 }
568 break;
569 default: {
570 RichTextEditorDialog dlg(fw->core(), fw);
571 if (!windowTitle.isEmpty())
572 dlg.setWindowTitle(windowTitle);
573 dlg.setDefaultFont(d->m_widget->font());
574 dlg.setText(oldText);
575 accepted = dlg.showDialog() == QDialog::Accepted;
576 newText = dlg.text(desiredFormat);
577 }
578 break;
579 }
580 // change property
581 if (!accepted || oldText == newText)
582 return;
583
584
585 textValue.setValue(newText);
586 setProperty(fw, pm, propertyName, QVariant::fromValue(textValue));
587 }
588
changeToolTip()589 void QDesignerTaskMenu::changeToolTip()
590 {
591 changeTextProperty(QStringLiteral("toolTip"), tr("Edit ToolTip"), MultiSelectionMode, Qt::AutoText);
592 }
593
changeWhatsThis()594 void QDesignerTaskMenu::changeWhatsThis()
595 {
596 changeTextProperty(QStringLiteral("whatsThis"), tr("Edit WhatsThis"), MultiSelectionMode, Qt::AutoText);
597 }
598
changeStyleSheet()599 void QDesignerTaskMenu::changeStyleSheet()
600 {
601 if (QDesignerFormWindowInterface *fw = formWindow()) {
602 StyleSheetPropertyEditorDialog dlg(fw, fw, d->m_widget);
603 dlg.exec();
604 }
605 }
606
containerFakeMethods()607 void QDesignerTaskMenu::containerFakeMethods()
608 {
609 QDesignerFormWindowInterface *fw = formWindow();
610 if (!fw)
611 return;
612 SignalSlotDialog::editMetaDataBase(fw, d->m_widget, fw);
613 }
614
isSlotNavigationEnabled(const QDesignerFormEditorInterface * core)615 bool QDesignerTaskMenu::isSlotNavigationEnabled(const QDesignerFormEditorInterface *core)
616 {
617 return core->integration()->hasFeature(QDesignerIntegration::SlotNavigationFeature);
618 }
619
slotNavigateToSlot()620 void QDesignerTaskMenu::slotNavigateToSlot()
621 {
622 QDesignerFormEditorInterface *core = formWindow()->core();
623 Q_ASSERT(core);
624 navigateToSlot(core, widget());
625 }
626
navigateToSlot(QDesignerFormEditorInterface * core,QObject * object,const QString & defaultSignal)627 void QDesignerTaskMenu::navigateToSlot(QDesignerFormEditorInterface *core,
628 QObject *object,
629 const QString &defaultSignal)
630 {
631 SelectSignalDialog dialog;
632 dialog.populate(core, object, defaultSignal);
633 if (dialog.exec() != QDialog::Accepted)
634 return;
635 // TODO: Check whether signal is connected to slot
636 const SelectSignalDialog::Method method = dialog.selectedMethod();
637 if (method.isValid()) {
638 core->integration()->emitNavigateToSlot(objName(core, object),
639 method.signature,
640 method.parameterNames);
641 }
642 }
643
644 // Add a command that takes over the value of the current geometry as
645 // minimum/maximum size according to the flags.
createSizeCommand(QDesignerFormWindowInterface * fw,QWidget * w,int flags)646 static void createSizeCommand(QDesignerFormWindowInterface *fw, QWidget *w, int flags)
647 {
648 const QSize size = w->size();
649 if (flags & (ApplyMinimumWidth|ApplyMinimumHeight)) {
650 QSize minimumSize = w-> minimumSize();
651 if (flags & ApplyMinimumWidth)
652 minimumSize.setWidth(size.width());
653 if (flags & ApplyMinimumHeight)
654 minimumSize.setHeight(size.height());
655 SetPropertyCommand* cmd = new SetPropertyCommand(fw);
656 cmd->init(w, QStringLiteral("minimumSize"), minimumSize);
657 fw->commandHistory()->push(cmd);
658 }
659 if (flags & (ApplyMaximumWidth|ApplyMaximumHeight)) {
660 QSize maximumSize = w-> maximumSize();
661 if (flags & ApplyMaximumWidth)
662 maximumSize.setWidth(size.width());
663 if (flags & ApplyMaximumHeight)
664 maximumSize.setHeight(size.height());
665 SetPropertyCommand* cmd = new SetPropertyCommand(fw);
666 cmd->init(w, QStringLiteral("maximumSize"), maximumSize);
667 fw->commandHistory()->push(cmd);
668 }
669 }
670
applySize(QAction * a)671 void QDesignerTaskMenu::applySize(QAction *a)
672 {
673 QDesignerFormWindowInterface *fw = formWindow();
674 if (!fw)
675 return;
676
677 const QWidgetList selection = applicableWidgets(fw, MultiSelectionMode);
678 if (selection.isEmpty())
679 return;
680
681 const int mask = a->data().toInt();
682 const int size = selection.size();
683 fw->commandHistory()->beginMacro(tr("Set size constraint on %n widget(s)", nullptr, size));
684 for (int i = 0; i < size; i++)
685 createSizeCommand(fw, selection.at(i), mask);
686 fw->commandHistory()->endMacro();
687 }
688
689 template <class Container>
getApplicableObjects(const QDesignerFormWindowInterface * fw,QWidget * current,QDesignerTaskMenu::PropertyMode pm,Container * c)690 static void getApplicableObjects(const QDesignerFormWindowInterface *fw, QWidget *current,
691 QDesignerTaskMenu::PropertyMode pm, Container *c)
692 {
693 // Current is always first
694 c->push_back(current);
695 if (pm == QDesignerTaskMenu::CurrentWidgetMode)
696 return;
697 QDesignerObjectInspector *designerObjectInspector = qobject_cast<QDesignerObjectInspector *>(fw->core()->objectInspector());
698 if (!designerObjectInspector)
699 return; // Ooops, someone plugged an old-style Object Inspector
700 // Add managed or unmanaged selection according to current type, make current first
701 Selection s;
702 designerObjectInspector->getSelection(s);
703 const QWidgetList &source = fw->isManaged(current) ? s.managed : s.unmanaged;
704 const QWidgetList::const_iterator cend = source.constEnd();
705 for ( QWidgetList::const_iterator it = source.constBegin(); it != cend; ++it)
706 if (*it != current) // was first
707 c->push_back(*it);
708 }
709
applicableObjects(const QDesignerFormWindowInterface * fw,PropertyMode pm) const710 QObjectList QDesignerTaskMenu::applicableObjects(const QDesignerFormWindowInterface *fw, PropertyMode pm) const
711 {
712 QObjectList rc;
713 getApplicableObjects(fw, d->m_widget, pm, &rc);
714 return rc;
715 }
716
applicableWidgets(const QDesignerFormWindowInterface * fw,PropertyMode pm) const717 QWidgetList QDesignerTaskMenu::applicableWidgets(const QDesignerFormWindowInterface *fw, PropertyMode pm) const
718 {
719 QWidgetList rc;
720 getApplicableObjects(fw, d->m_widget, pm, &rc);
721 return rc;
722 }
723
setProperty(QDesignerFormWindowInterface * fw,PropertyMode pm,const QString & name,const QVariant & newValue)724 void QDesignerTaskMenu::setProperty(QDesignerFormWindowInterface *fw, PropertyMode pm, const QString &name, const QVariant &newValue)
725 {
726 SetPropertyCommand* setPropertyCommand = new SetPropertyCommand(fw);
727 if (setPropertyCommand->init(applicableObjects(fw, pm), name, newValue, d->m_widget)) {
728 fw->commandHistory()->push(setPropertyCommand);
729 } else {
730 delete setPropertyCommand;
731 qDebug() << "Unable to set property " << name << '.';
732 }
733 }
734
slotLayoutAlignment()735 void QDesignerTaskMenu::slotLayoutAlignment()
736 {
737 QDesignerFormWindowInterface *fw = formWindow();
738 const Qt::Alignment newAlignment = d->m_layoutAlignmentMenu.alignment();
739 LayoutAlignmentCommand *cmd = new LayoutAlignmentCommand(fw);
740 if (cmd->init(d->m_widget, newAlignment)) {
741 fw->commandHistory()->push(cmd);
742 } else {
743 delete cmd;
744 }
745 }
746 } // namespace qdesigner_internal
747
748 QT_END_NAMESPACE
749