16#include <metadatabase_p.h>
17#include <qdesigner_tabwidget_p.h>
18#include <qdesigner_toolbox_p.h>
19#include <qdesigner_stackedbox_p.h>
20#include <qdesigner_resource.h>
21#include <qdesigner_command_p.h>
22#include <qdesigner_command2_p.h>
23#include <qdesigner_propertycommand_p.h>
24#include <qdesigner_taskmenu_p.h>
25#include <qdesigner_widget_p.h>
26#include <qdesigner_utils_p.h>
27#include <qlayout_widget_p.h>
28#include <spacer_widget_p.h>
29#include <invisible_widget_p.h>
30#include <layoutinfo_p.h>
31#include <qdesigner_objectinspector_p.h>
32#include <connectionedit_p.h>
33#include <actionprovider_p.h>
34#include <private/ui4_p.h>
35#include <deviceprofile_p.h>
36#include <shared_settings_p.h>
39#include <QtDesigner/qextensionmanager.h>
40#include <QtDesigner/abstractwidgetdatabase.h>
41#include <QtDesigner/propertysheet.h>
42#include <QtDesigner/abstractwidgetfactory.h>
43#include <QtDesigner/container.h>
44#include <QtDesigner/taskmenu.h>
45#include <QtDesigner/abstractwidgetbox.h>
46#include <QtDesigner/private/ui4_p.h>
48#include <abstractdialoggui_p.h>
50#include <QtWidgets/qmenu.h>
51#include <QtWidgets/qscrollarea.h>
52#include <QtWidgets/qrubberband.h>
53#include <QtWidgets/qapplication.h>
54#include <QtWidgets/qsplitter.h>
55#include <QtWidgets/qgroupbox.h>
56#include <QtWidgets/qdockwidget.h>
57#include <QtWidgets/qtoolbox.h>
58#include <QtWidgets/qstackedwidget.h>
59#include <QtWidgets/qtabwidget.h>
60#include <QtWidgets/qbuttongroup.h>
62#include <QtGui/qaction.h>
63#include <QtGui/qactiongroup.h>
64#if QT_CONFIG(clipboard)
65# include <QtGui/qclipboard.h>
67#include <QtGui/qpainter.h>
68#include <QtGui/qundogroup.h>
70#include <QtCore/qdebug.h>
71#include <QtCore/qbuffer.h>
72#include <QtCore/qtimer.h>
73#include <QtCore/qlist.h>
74#include <QtCore/qxmlstream.h>
78Q_DECLARE_METATYPE(QWidget*)
82using namespace Qt::StringLiterals;
87 Q_DISABLE_COPY_MOVE(BlockSelection)
89 BlockSelection(qdesigner_internal::FormWindow *fw)
91 m_blocked(m_formWindow->blockSelectionChanged(
true))
98 m_formWindow->blockSelectionChanged(m_blocked);
102 QPointer<qdesigner_internal::FormWindow> m_formWindow;
103 const bool m_blocked;
106enum { debugFormWindow = 0 };
148 SelectionPool m_selectionPool;
150 QHash<QWidget *, WidgetSelection *> m_usedSelections;
162 if (!m_usedSelections.isEmpty()) {
163 for (
auto it = m_usedSelections.begin(), mend = m_usedSelections.end(); it != mend; ++it)
164 it.value()->setWidget(
nullptr);
165 m_usedSelections.clear();
172 qDeleteAll(m_selectionPool);
173 m_selectionPool.clear();
185 for (
auto *s : std::as_const(m_selectionPool)) {
193 rc =
new WidgetSelection(fw);
194 m_selectionPool.push_back(rc);
197 m_usedSelections.insert(w, rc);
209 m_usedSelections.remove(w);
211 if (m_usedSelections.isEmpty())
214 return (*m_usedSelections.begin())->widget();
225 for (
auto it = m_usedSelections.begin(), mend = m_usedSelections.end(); it != mend; ++it)
226 it.value()->update();
230 return m_usedSelections.contains(w);
235 return m_usedSelections.keys();
240 for (
auto it = m_usedSelections.constBegin(), mend = m_usedSelections.constEnd(); it != mend; ++it) {
275 m_mouseState(NoMouseState),
282 deviceProfile().apply(core, m_widgetStack
->formContainer(), qdesigner_internal::DeviceProfile::ApplyFormParent);
284 setLayout(m_widgetStack->layout());
287 m_cursor =
new FormWindowCursor(
this,
this);
289 core->formWindowManager()->addFormWindow(
this);
292 setAcceptDrops(
true);
297 auto *core =
this->FormWindow::core();
298 Q_ASSERT(core !=
nullptr);
299 Q_ASSERT(core->metaDataBase() !=
nullptr);
300 auto *fwm = core->formWindowManager();
301 Q_ASSERT(fwm !=
nullptr);
303 core->formWindowManager()->removeFormWindow(
this);
304 core->metaDataBase()->remove(
this);
306 const QWidgetList &l = widgets();
308 core->metaDataBase()->remove(w);
310 m_widgetStack =
nullptr;
311 m_rubberBand =
nullptr;
313 core->resourceModel()->removeResourceSet(resourceSet());
316 if (
auto *manager = qobject_cast<FormWindowManager*>(fwm))
317 manager->undoGroup()->removeStack(&m_undoStack);
318 m_undoStack.disconnect();
333 if (!m_mainContainer)
340 while (w && !w->isWindow()) {
342 w = w->parentWidget();
353 c = c->parentWidget();
362 const QWidgetList widgets = start->findChildren<QWidget*>();
363 for (QWidget *widget : widgets) {
364 if (!qobject_cast<WidgetHandle*>(widget)) {
365 widget->setCursor(c);
373 auto *core =
this->FormWindow::core();
374 if (
auto *manager = qobject_cast<FormWindowManager*>(core->formWindowManager()))
375 manager->undoGroup()->addStack(&m_undoStack);
377 m_blockSelectionChanged =
false;
379 m_defaultMargin = INT_MIN;
380 m_defaultSpacing = INT_MIN;
382 connect(m_widgetStack, &FormWindowWidgetStack::currentToolChanged,
383 this, &QDesignerFormWindowInterface::toolChanged);
385 m_selectionChangedTimer =
new QTimer(
this);
386 m_selectionChangedTimer->setSingleShot(
true);
387 connect(m_selectionChangedTimer, &QTimer::timeout,
this,
388 &FormWindow::selectionChangedTimerDone);
390 m_checkSelectionTimer =
new QTimer(
this);
391 m_checkSelectionTimer->setSingleShot(
true);
392 connect(m_checkSelectionTimer, &QTimer::timeout,
395 m_geometryChangedTimer =
new QTimer(
this);
396 m_geometryChangedTimer->setSingleShot(
true);
397 connect(m_geometryChangedTimer, &QTimer::timeout,
398 this, &QDesignerFormWindowInterface::geometryChanged);
400 m_rubberBand =
nullptr;
402 setFocusPolicy(Qt::StrongFocus);
404 m_mainContainer =
nullptr;
405 m_currentWidget =
nullptr;
407 connect(&m_undoStack, &QUndoStack::indexChanged,
408 this, &QDesignerFormWindowInterface::changed);
409 connect(&m_undoStack, &QUndoStack::cleanChanged,
411 connect(
this, &QDesignerFormWindowInterface::changed,
414 core->metaDataBase()->add(
this);
416 initializeCoreTools();
418 auto *a =
new QAction(
this);
419 a->setText(tr(
"Edit contents"));
420 a->setShortcut(tr(
"F2"));
427 return m_mainContainer;
433 if (m_mainContainer) {
436 core()->metaDataBase()->remove(m_mainContainer);
438 delete m_mainContainer;
439 m_mainContainer =
nullptr;
445 if (w == m_mainContainer) {
450 clearMainContainer();
453 const QSize sz = m_mainContainer->size();
456 m_widgetStack->setCurrentTool(m_widgetEditor);
458 setCurrentWidget(m_mainContainer);
462 sheet->setVisible(sheet->indexOf(u"windowTitle"_s),
true);
463 sheet->setVisible(sheet->indexOf(u"windowIcon"_s),
true);
464 sheet->setVisible(sheet->indexOf(u"windowModality"_s),
true);
465 sheet->setVisible(sheet->indexOf(u"windowOpacity"_s),
true);
466 sheet->setVisible(sheet->indexOf(u"windowFilePath"_s),
true);
470 m_mainContainer->setFocusPolicy(Qt::StrongFocus);
471 m_mainContainer->resize(sz);
473 emit mainContainerChanged(m_mainContainer);
480 while (
QWidget *parentWidget = widget->parentWidget()) {
481 if (LayoutInfo::layoutType(m_core, parentWidget) == LayoutInfo::NoLayout && isManaged(widget))
484 widget = parentWidget;
492 if (
auto *oi = qobject_cast<QDesignerObjectInspector *>(core->objectInspector()))
493 oi->clearSelection();
499 const QDesignerFormWindowCursorInterface *cursor = fw->cursor();
500 QWidget *mainContainer = fw->mainContainer();
501 for (
QWidget *p = w->parentWidget(); p && p != mainContainer; p = p->parentWidget())
502 if (fw->isManaged(p))
503 if (cursor->isWidgetSelected(p) == selected)
515 case Qt::ShiftModifier:
519 case Qt::AltModifier:
520 return CopyDragModifier;
522 case Qt::ControlModifier:
535 const bool sameWidget = managedWidget == m_lastClickedWidget;
536 m_lastClickedWidget = managedWidget;
540 qDebug() <<
"handleClickSelection" << managedWidget <<
" same=" << sameWidget <<
" mouse= " << mouseMode <<
" selected=" << selected;
548 QWidget *selectionCandidate =
nullptr;
552 if (
QWidget *currentlySelectedParent = selected ? managedWidget : findSelectedParent(
this, managedWidget,
true))
553 selectionCandidate = findSelectedParent(
this, currentlySelectedParent,
false);
555 if (!selectionCandidate && !selected)
556 selectionCandidate = managedWidget;
558 if (selectionCandidate)
559 selectSingleWidget(selectionCandidate);
571 m_mouseState = NoMouseState;
572 m_startPos = QPoint();
575 BlockSelection blocker(
this);
577 if (core()->formWindowManager()->activeFormWindow() !=
this)
578 core()->formWindowManager()->setActiveFormWindow(
this);
580 const Qt::MouseButtons buttons = e->buttons();
581 if (buttons != Qt::LeftButton && buttons != Qt::MiddleButton)
584 m_startPos = mapFromGlobal(e->globalPosition().toPoint());
587 qDebug() <<
"handleMousePressEvent:" << widget <<
',' << managedWidget;
589 if (buttons == Qt::MiddleButton || isMainContainer(managedWidget)) {
590 clearObjectInspectorSelection(m_core);
593 m_mouseState = MouseDrawRubber;
594 m_currRect = QRect();
595 startRectDraw(mapFromGlobal(e->globalPosition().toPoint()),
this, Rubber);
598 if (buttons != Qt::LeftButton)
601 const unsigned mouseMode = mouseFlags(e->modifiers());
604
605
606
607
608
609
610
611 const bool deferSelection =
isWidgetSelected(managedWidget
) || findSelectedParent(
this, managedWidget,
true);
612 if (deferSelection) {
613 m_mouseState = MouseDeferredSelection;
617 handleClickSelection(managedWidget, effectiveMouseMode);
625 bool managed =
false;
626 const LayoutInfo::Type type = LayoutInfo::laidoutWidgetType(core ,w, &managed);
630 case LayoutInfo::NoLayout:
631 case LayoutInfo::HSplitter:
632 case LayoutInfo::VSplitter:
643 if (m_startPos.isNull())
646 const QPoint pos = mapFromGlobal(e->globalPosition().toPoint());
648 switch (m_mouseState) {
649 case MouseDrawRubber:
650 continueRectDraw(pos,
this, Rubber);
658 if (e->buttons() != Qt::LeftButton)
661 const bool canStartDrag = (m_startPos - pos).manhattanLength() > QApplication::startDragDistance();
666 m_mouseState = MouseMoveDrag;
669 QWidgetList sel = selectedWidgets();
670 const QWidgetList originalSelection = sel;
671 simplifySelection(&sel);
673 QSet<QWidget*> widget_set;
675 for (QWidget *child : std::as_const(sel)) {
676 QWidget *current = child;
679 while (!isMainContainer(current) && !done) {
680 if (!isManaged(current)) {
681 current = current->parentWidget();
684 if (LayoutInfo::isWidgetLaidout(core(), current)) {
686 if (!canDragWidgetInLayout(core(), current)) {
687 current = current->parentWidget();
694 if (current == mainContainer())
697 widget_set.insert(current);
700 sel = widget_set.values();
701 QDesignerFormWindowCursorInterface *c = cursor();
702 QWidget *current = c->current();
703 if (sel.contains(current)) {
704 sel.removeAll(current);
705 sel.prepend(current);
708 QList<QDesignerDnDItemInterface*> item_list;
709 const QPoint globalPos = mapToGlobal(m_startPos);
710 const QDesignerDnDItemInterface::DropType dropType = (mouseFlags(e->modifiers()) & CopyDragModifier) ?
711 QDesignerDnDItemInterface::CopyDrop : QDesignerDnDItemInterface::MoveDrop;
712 for (QWidget *widget : std::as_const(sel)) {
713 item_list.append(
new FormWindowDnDItem(dropType,
this, widget, globalPos));
714 if (dropType == QDesignerDnDItemInterface::MoveDrop) {
715 m_selection->hide(widget);
722 for (
auto *widget : originalSelection)
723 m_selection->hide(widget);
728 if (QDesignerMimeData::execDrag(item_list, core()->topLevel()) == Qt::IgnoreAction && dropType == QDesignerDnDItemInterface::MoveDrop)
729 for (QWidget *widget : std::as_const(sel))
730 m_selection->show(widget);
732 m_startPos = QPoint();
739 const MouseState oldState = m_mouseState;
740 m_mouseState = NoMouseState;
743 qDebug() <<
"handleMouseeleaseEvent:" << w <<
',' << mw <<
"state=" << oldState;
745 if (oldState == MouseDoubleClicked)
751 case MouseDrawRubber: {
759 case MouseDeferredSelection:
760 handleClickSelection(mw, mouseFlags(e->modifiers()));
766 m_startPos = QPoint();
769
770
771 switch (e->button()) {
773 case Qt::MiddleButton:
774 case Qt::RightButton:
784void FormWindow::checkPreviewGeometry(QRect &r)
786 if (!rect().contains(r)) {
787 if (r.left() < rect().left())
788 r.moveTopLeft(QPoint(0, r.top()));
789 if (r.right() > rect().right())
790 r.moveBottomRight(QPoint(rect().right(), r.bottom()));
791 if (r.top() < rect().top())
792 r.moveTopLeft(QPoint(r.left(), rect().top()));
793 if (r.bottom() > rect().bottom())
794 r.moveBottomRight(QPoint(r.right(), rect().bottom()));
800 m_rectAnchor = (t == Insert) ? designerGrid().snapPoint(pos) : pos;
802 m_currRect = QRect(m_rectAnchor, QSize(0, 0));
804 m_rubberBand =
new QRubberBand(QRubberBand::Rectangle,
this);
805 m_rubberBand->setGeometry(m_currRect);
806 m_rubberBand->show();
811 const QPoint p2 = (t == Insert) ? designerGrid().snapPoint(pos) : pos;
813 QRect r(m_rectAnchor, p2);
819 if (r.width() > 1 || r.height() > 1) {
822 m_rubberBand->setGeometry(m_currRect);
830 m_rubberBand =
nullptr;
836 return m_currentWidget;
842 qDebug() <<
"setCurrentWidget:" << m_currentWidget <<
" --> " << currentWidget;
843 if (currentWidget == m_currentWidget)
850 m_currentWidget = currentWidget;
859 if (trySelectWidget(w, select))
867 qDebug() <<
"trySelectWidget:" << w << select;
889 setCurrentWidget(newCurrent);
897 qDebug() <<
"clearSelection(" << changePropertyDisplay <<
')';
902 if (changePropertyDisplay)
908 if (m_blockSelectionChanged)
911 m_selectionChangedTimer->start(0);
916 emit selectionChanged();
931 const QWidgetList l = w->findChildren<
QWidget*>();
950 if (!w->isVisibleTo(
this)) {
960 w = w->parentWidget();
967 if (
auto *mainWindow = qobject_cast<QMainWindow*>(mainContainer()))
968 return w == mainWindow->centralWidget();
975 QString name = object->objectName();
976 if (name.isEmpty()) {
977 QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase();
978 if (QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(object)))
979 name = qdesigner_internal::qtify(item->name());
981 unify(object, name,
true);
982 object->setObjectName(name);
985template <
class Iterator>
986static inline void insertNames(
const QDesignerMetaDataBaseInterface *metaDataBase,
987 Iterator it,
const Iterator &end,
988 QObject *excludedObject, QSet<QString> &nameSet)
990 for ( ; it != end; ++it)
991 if (excludedObject != *it && metaDataBase->item(*it))
992 nameSet.insert((*it)->objectName());
997 static const QSet<QString> keywords = {
1043 u"reinterpret_cast"_s,
1094 using StringSet = QSet<QString>;
1100 StringSet existingNames = languageKeywords();
1103 existingNames.insert(main->objectName());
1105 const QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase();
1106 const QWidgetList widgetChildren = main->findChildren<
QWidget*>();
1107 if (!widgetChildren.isEmpty())
1108 insertNames(metaDataBase, widgetChildren.constBegin(), widgetChildren.constEnd(), w, existingNames);
1110 const auto layoutChildren = main->findChildren<QLayout*>();
1111 if (!layoutChildren.isEmpty())
1112 insertNames(metaDataBase, layoutChildren.constBegin(), layoutChildren.constEnd(), w, existingNames);
1114 const auto actionChildren = main->findChildren<QAction*>();
1115 if (!actionChildren.isEmpty())
1116 insertNames(metaDataBase, actionChildren.constBegin(), actionChildren.constEnd(), w, existingNames);
1118 const auto buttonGroupChildren = main->findChildren<QButtonGroup*>();
1119 if (!buttonGroupChildren.isEmpty())
1120 insertNames(metaDataBase, buttonGroupChildren.constBegin(), buttonGroupChildren.constEnd(), w, existingNames);
1122 if (!existingNames.contains(s))
1129 qlonglong factor = 1;
1130 qsizetype idx = s.size() - 1;
1131 const char16_t zeroUnicode = u'0';
1132 for ( ; idx > 0 && s.at(idx).isDigit(); --idx) {
1133 num += (s.at(idx).unicode() - zeroUnicode) * factor;
1137 const QChar underscore = u'_';
1138 if (idx >= 0 && s.at(idx) == underscore) {
1146 for (num++ ; ;num++) {
1148 s += QString::number(num);
1149 if (!existingNames.contains(s))
1155
1161 beginCommand(tr(
"Insert widget '%1'").arg(WidgetFactory::classNameOf(m_core, w)));
1164
1165
1167 Q_ASSERT(r.isValid());
1168 auto *geom_cmd =
new SetPropertyCommand(
this);
1169 geom_cmd->init(w, u"geometry"_s, r);
1171 if (w->parentWidget() != container) {
1172 auto *cmd =
new ReparentWidgetCommand(
this);
1173 cmd->init(w, container);
1174 m_undoStack.push(cmd);
1177 m_undoStack.push(geom_cmd);
1179 QUndoCommand *cmd =
nullptr;
1180 if (
auto *dockWidget = qobject_cast<QDockWidget *>(w)) {
1181 if (
auto *mainWindow = qobject_cast<QMainWindow *>(container)) {
1182 auto *addDockCmd =
new AddDockWidgetCommand(
this);
1183 addDockCmd->init(mainWindow, dockWidget);
1187 if (cmd ==
nullptr) {
1188 auto *insertCmd =
new InsertWidgetCommand(
this);
1189 insertCmd->init(w, already_in_form);
1192 m_undoStack.push(cmd);
1205 if (
auto *mw = qobject_cast<QMainWindow*>(container)) {
1206 Q_ASSERT(mw->centralWidget() !=
nullptr);
1207 container = mw->centralWidget();
1211 const FormBuilderClipboard clipboard = resource.paste(ui, container);
1212 if (clipboard.m_widgets.size() != 1)
1214 QWidget *widget = clipboard.m_widgets.first();
1215 insertWidget(widget, rc, container);
1221 for (; child !=
nullptr; child = child->parentWidget()) {
1222 if (child == parent)
1230 Q_ASSERT(isDescendant(
this, widget));
1233 auto *cmd =
new SetPropertyCommand(
this);
1234 cmd->init(widget, u"geometry"_s, r);
1235 cmd->setText(tr(
"Resize"));
1236 m_undoStack.push(cmd);
1241 const QWidgetList l = w->findChildren<
QWidget*>();
1244 m_selection->raiseList(l);
1251 const QWidgetList selected = selectedWidgets();
1252 if (rect().contains(mapFromGlobal(pos))) {
1254 depth = widgetDepth(container);
1257 for (QWidget *wit : std::as_const(m_widgets)) {
1258 if (qobject_cast<QLayoutWidget*>(wit) || qobject_cast<QSplitter*>(wit))
1260 if (!wit->isVisibleTo(
this))
1262 if (selected.indexOf(wit) != -1)
1264 if (!core()->widgetDataBase()->isContainer(wit) &&
1265 wit != mainContainer())
1270 while (w && !w->isWindow()) {
1271 if (!w->rect().contains((w->mapFromGlobal(pos))))
1273 w = w->parentWidget();
1275 if (!(w ==
nullptr || w->isWindow()))
1278 int wd = widgetDepth(wit);
1279 if (wd == depth && container) {
1280 if (wit->parentWidget()->children().indexOf(wit) >
1281 container->parentWidget()->children().indexOf(container))
1284 if (wd > depth && !isChildOf(wit, notParentOf)) {
1294 return m_selection->selectedWidgets();
1299 bool selectionChanged =
false;
1301 const QRect selRect(mapToGlobal(m_currRect.topLeft()), m_currRect.size());
1302 for (QWidget *w : l) {
1303 if (w->isVisibleTo(
this) && isManaged(w)) {
1304 const QPoint p = w->mapToGlobal(QPoint(0,0));
1305 const QRect r(p, w->size());
1306 if (r.intersects(selRect) && !r.contains(selRect) && trySelectWidget(w,
true))
1307 selectionChanged =
true;
1311 if (selectionChanged)
1317 if (qobject_cast<
const FormWindow*>(widget) || qobject_cast<
const QMenu*>(widget))
1325 case Qt::Key_Delete:
1326 case Qt::Key_Backspace:
1327 if (e->modifiers() == Qt::NoModifier)
1332 if (e->modifiers() == Qt::NoModifier)
1333 cursor()->movePosition(QDesignerFormWindowCursorInterface::Next);
1336 case Qt::Key_Backtab:
1337 if (e->modifiers() == Qt::NoModifier)
1338 cursor()->movePosition(QDesignerFormWindowCursorInterface::Prev);
1345 handleArrowKeyEvent(e->key(), e->modifiers());
1352int FormWindow::getValue(QRect rect,
int key,
bool size)
const
1355 if (key == Qt::Key_Left || key == Qt::Key_Right)
1356 return rect.width();
1357 return rect.height();
1359 if (key == Qt::Key_Left || key == Qt::Key_Right)
1364int FormWindow::calcValue(
int val,
bool forward,
bool snap,
int snapOffset)
const
1367 const int rest = val % snapOffset;
1369 const int offset = forward ? snapOffset : 0;
1370 const int newOffset = rest < 0 ? offset - snapOffset : offset;
1371 return val + newOffset - rest;
1373 return (forward ? val + snapOffset : val - snapOffset);
1375 return (forward ? val + 1 : val - 1);
1392Q_DECLARE_METATYPE(qdesigner_internal::ArrowKeyOperation)
1395namespace qdesigner_internal {
1397QRect ArrowKeyOperation::apply(QRect rect)
const
1401 if (arrowKey == Qt::Key_Left || arrowKey == Qt::Key_Right)
1402 r.setWidth(r.width() + distance);
1404 r.setHeight(r.height() + distance);
1406 if (arrowKey == Qt::Key_Left || arrowKey == Qt::Key_Right)
1407 r.moveLeft(r.x() + distance);
1409 r.moveTop(r.y() + distance);
1414QDebug operator<<(QDebug in, ArrowKeyOperation op)
1416 in.nospace() <<
"Resize=" << op.resize <<
" dist=" << op.distance <<
" Key=" << op.arrowKey <<
' ';
1428class ArrowKeyPropertyHelper :
public PropertyHelper {
1430 ArrowKeyPropertyHelper(QObject* o, SpecialProperty sp,
1431 QDesignerPropertySheetExtension *s,
int i) :
1432 PropertyHelper(o, sp, s, i) {}
1434 Value setValue(QDesignerFormWindowInterface *fw,
const QVariant &value,
bool changed,
1435 quint64 subPropertyMask) override;
1438PropertyHelper::Value ArrowKeyPropertyHelper::setValue(QDesignerFormWindowInterface *fw,
const QVariant &value,
1439 bool changed, quint64 subPropertyMask)
1442 auto *w = qobject_cast<QWidget*>(object());
1443 const auto operation = qvariant_cast<ArrowKeyOperation>(value);
1444 const QRect newGeom = operation.apply(w->geometry());
1445 return PropertyHelper::setValue(fw, QVariant(newGeom), changed, subPropertyMask);
1451class ArrowKeyPropertyCommand:
public SetPropertyCommand {
1453 explicit ArrowKeyPropertyCommand(QDesignerFormWindowInterface *fw,
1454 QUndoCommand *p =
nullptr);
1456 void init(QWidgetList &l, ArrowKeyOperation op);
1459 std::unique_ptr<PropertyHelper>
1460 createPropertyHelper(QObject *o, SpecialProperty sp,
1461 QDesignerPropertySheetExtension *s,
int i)
const override
1462 {
return std::make_unique<ArrowKeyPropertyHelper>(o, sp, s, i); }
1463 QVariant mergeValue(
const QVariant &newValue) override;
1466ArrowKeyPropertyCommand::ArrowKeyPropertyCommand(QDesignerFormWindowInterface *fw,
1468 SetPropertyCommand(fw, p)
1470 static const int mid = qRegisterMetaType<qdesigner_internal::ArrowKeyOperation>();
1474void ArrowKeyPropertyCommand::init(QWidgetList &l, ArrowKeyOperation op)
1477 for (QWidget *w : std::as_const(l))
1479 SetPropertyCommand::init(ol, u"geometry"_s, QVariant::fromValue(op));
1481 setText(op.resize ? FormWindow::tr(
"Key Resize") : FormWindow::tr(
"Key Move"));
1484QVariant ArrowKeyPropertyCommand::mergeValue(
const QVariant &newMergeValue)
1487 if (!newMergeValue.canConvert<ArrowKeyOperation>())
1489 auto mergedOperation = qvariant_cast<ArrowKeyOperation>(newValue());
1490 const auto newMergeOperation = qvariant_cast<ArrowKeyOperation>(newMergeValue);
1491 if (mergedOperation.resize != newMergeOperation.resize || mergedOperation.arrowKey != newMergeOperation.arrowKey)
1493 mergedOperation.distance += newMergeOperation.distance;
1494 return QVariant::fromValue(mergedOperation);
1497void FormWindow::handleArrowKeyEvent(
int key, Qt::KeyboardModifiers modifiers)
1499 const QDesignerFormWindowCursorInterface *c = cursor();
1500 if (!c->hasSelection())
1503 QWidgetList selection;
1506 const int count = c->selectedWidgetCount();
1507 for (
int index = 0; index < count; ++index) {
1508 QWidget *w = c->selectedWidget(index);
1509 if (!LayoutInfo::isWidgetLaidout(m_core, w))
1510 selection.append(w);
1513 simplifySelection(&selection);
1515 if (selection.isEmpty())
1518 QWidget *current = c->current();
1519 if (!current || LayoutInfo::isWidgetLaidout(m_core, current)) {
1520 current = selection.first();
1523 const bool size = modifiers & Qt::ShiftModifier;
1525 const bool snap = !(modifiers & Qt::ControlModifier);
1526 const bool forward = (key == Qt::Key_Right || key == Qt::Key_Down);
1527 const int snapPoint = (key == Qt::Key_Left || key == Qt::Key_Right) ? grid().x() : grid().y();
1529 const int oldValue = getValue(current->geometry(), key, size);
1531 const int newValue = calcValue(oldValue, forward, snap, snapPoint);
1533 ArrowKeyOperation operation;
1534 operation.resize = modifiers & Qt::ShiftModifier;
1535 operation.distance = newValue - oldValue;
1536 operation.arrowKey = key;
1538 auto *cmd =
new ArrowKeyPropertyCommand(
this);
1539 cmd->init(selection, operation);
1540 m_undoStack.push(cmd);
1543bool FormWindow::handleKeyReleaseEvent(QWidget *, QWidget *, QKeyEvent *e)
1549void FormWindow::selectAll()
1551 bool selectionChanged =
false;
1552 for (QWidget *widget : std::as_const(m_widgets)) {
1553 if (widget->isVisibleTo(
this) && trySelectWidget(widget,
true))
1554 selectionChanged =
true;
1556 if (selectionChanged)
1557 emitSelectionChanged();
1560void FormWindow::createLayout(
int type, QWidget *container)
1563 layoutContainer(container, type);
1565 auto *cmd =
new LayoutCommand(
this);
1566 cmd->init(mainContainer(), selectedWidgets(),
static_cast<LayoutInfo::Type>(type));
1567 commandHistory()->push(cmd);
1571void FormWindow::morphLayout(QWidget *container,
int newType)
1573 auto *cmd =
new MorphLayoutCommand(
this);
1574 if (cmd->init(container, newType)) {
1575 commandHistory()->push(cmd);
1577 qDebug() <<
"** WARNING Unable to morph layout.";
1582void FormWindow::deleteWidgets()
1584 QWidgetList selection = selectedWidgets();
1585 simplifySelection(&selection);
1587 deleteWidgetList(selection);
1590QString FormWindow::fileName()
const
1595void FormWindow::setFileName(
const QString &fileName)
1597 if (m_fileName == fileName)
1600 m_fileName = fileName;
1601 emit fileNameChanged(fileName);
1604QString FormWindow::contents()
const
1607 if (!mainContainer() || !b.open(QIODevice::WriteOnly))
1610 QDesignerResource resource(
const_cast<FormWindow*>(
this));
1611 resource.save(&b, mainContainer());
1613 return QString::fromUtf8(b.buffer());
1616#if QT_CONFIG(clipboard)
1617void FormWindow::copy()
1620 if (!b.open(QIODevice::WriteOnly))
1623 FormBuilderClipboard clipboard;
1624 QDesignerResource resource(
this);
1625 resource.setSaveRelative(
false);
1626 clipboard.m_widgets = selectedWidgets();
1627 simplifySelection(&clipboard.m_widgets);
1628 resource.copy(&b, clipboard);
1630 qApp->clipboard()->setText(QString::fromUtf8(b.buffer()), QClipboard::Clipboard);
1633void FormWindow::cut()
1639void FormWindow::paste()
1646QWidget *FormWindow::innerContainer(QWidget *outerContainer)
const
1648 if (m_core->widgetDataBase()->isContainer(outerContainer))
1649 if (
const QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(m_core->extensionManager(), outerContainer)) {
1650 const int currentIndex = container->currentIndex();
1651 return currentIndex >= 0 ? container->widget(currentIndex) :
nullptr;
1653 return outerContainer;
1656QWidget *FormWindow::containerForPaste()
const
1658 QWidget *w = mainContainer();
1664 QWidgetList selection = selectedWidgets();
1665 if (selection.isEmpty())
1667 simplifySelection(&selection);
1669 QWidget *containerOfW = findContainer(selection.first(),
true);
1670 if (!containerOfW || containerOfW == mainContainer())
1673 containerOfW = innerContainer(containerOfW);
1676 if (LayoutInfo::layoutType(m_core, containerOfW) != LayoutInfo::NoLayout || !m_core->widgetDataBase()->isContainer(containerOfW))
1683 w = innerContainer(w);
1686 if (LayoutInfo::layoutType(m_core, w) != LayoutInfo::NoLayout)
1689 w = m_core->widgetFactory()->containerOfWidget(w);
1690 if (w ==
nullptr || LayoutInfo::layoutType(m_core, w) != LayoutInfo::NoLayout)
1693 if (debugFormWindow)
1694 qDebug() <<
"containerForPaste() " << w;
1698#if QT_CONFIG(clipboard)
1700static inline DomUI *domUIFromClipboard(
int *widgetCount,
int *actionCount)
1702 *widgetCount = *actionCount = 0;
1703 const QString clipboardText = qApp->clipboard()->text();
1704 if (clipboardText.isEmpty() || clipboardText.indexOf(u'<') == -1)
1707 QXmlStreamReader reader(clipboardText);
1708 DomUI *ui =
nullptr;
1709 while (!reader.atEnd()) {
1710 if (reader.readNext() == QXmlStreamReader::StartElement) {
1711 if (reader.name().compare(
"ui"_L1, Qt::CaseInsensitive) == 0 && !ui) {
1716 reader.raiseError(QCoreApplication::translate(
"FormWindow",
"Unexpected element <%1>").arg(reader.name().toString()));
1719 if (reader.hasError()) {
1722 designerWarning(QCoreApplication::translate(
"FormWindow",
"Error while pasting clipboard contents at line %1, column %2: %3").
1723 arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
1727 if (
const DomWidget *topLevel = ui->elementWidget()) {
1728 *widgetCount = topLevel->elementWidget().size();
1729 *actionCount = topLevel->elementAction().size();
1731 if (*widgetCount == 0 && *actionCount == 0) {
1739static inline QString pasteCommandDescription(
int widgetCount,
int actionCount)
1741 if (widgetCount == 0)
1742 return FormWindow::tr(
"Paste %n action(s)",
nullptr, actionCount);
1743 if (actionCount == 0)
1744 return FormWindow::tr(
"Paste %n widget(s)",
nullptr, widgetCount);
1745 return FormWindow::tr(
"Paste (%1 widgets, %2 actions)").arg(widgetCount).arg(actionCount);
1748#if QT_CONFIG(clipboard)
1749static void positionPastedWidgetsAtMousePosition(FormWindow *fw, QPoint contextMenuPosition, QWidget *parent,
const QWidgetList &l)
1754 QPoint currentPos = contextMenuPosition.x() >=0 ? parent->mapFrom(fw, contextMenuPosition) : parent->mapFromGlobal(QCursor::pos());
1755 const Grid &grid = fw->designerGrid();
1756 QPoint cursorPos = grid.snapPoint(currentPos);
1757 const QRect parentGeometry = QRect(QPoint(0, 0), parent->size());
1758 const bool outside = !parentGeometry.contains(cursorPos);
1760 cursorPos = grid.snapPoint(QPoint(0, 0));
1764 pasteArea = pasteArea.isNull() ? w->geometry() : pasteArea.united(w->geometry());
1769 const QPoint bottomRight = cursorPos + QPoint(pasteArea.width(), pasteArea.height()) - QPoint(1, 1);
1770 if (bottomRight.y() > parentGeometry.bottom() || parent->childAt(bottomRight) ==
nullptr)
1772 cursorPos += QPoint(grid.deltaX(), grid.deltaY());
1775 const QPoint offset = cursorPos - pasteArea.topLeft();
1777 w->move(w->pos() + offset);
1780void FormWindow::paste(PasteMode pasteMode)
1784 DomUI *ui =
nullptr;
1786 int widgetCount = 0;
1787 int actionCount = 0;
1788 ui = domUIFromClipboard(&widgetCount, &actionCount);
1793 if (pasteMode == PasteActionsOnly)
1794 if (widgetCount != 0 || actionCount == 0)
1798 QWidget *pasteContainer = widgetCount ? containerForPaste() :
nullptr;
1799 if (widgetCount && pasteContainer ==
nullptr) {
1801 const QString message = tr(
"Cannot paste widgets. Designer could not find a container "
1802 "without a layout to paste into.");
1803 const QString infoMessage = tr(
"Break the layout of the "
1804 "container you want to paste into, select this container "
1805 "and then paste again.");
1806 core()->dialogGui()->message(
this, QDesignerDialogGuiInterface::FormEditorMessage, QMessageBox::Information,
1807 tr(
"Paste error"), message, infoMessage, QMessageBox::Ok);
1811 QDesignerResource resource(
this);
1815 const FormBuilderClipboard clipboard = resource.paste(ui, pasteContainer,
this);
1817 clearSelection(
false);
1819 beginCommand(pasteCommandDescription(widgetCount, actionCount));
1822 positionPastedWidgetsAtMousePosition(
this, m_contextMenuPosition, pasteContainer, clipboard.m_widgets);
1823 for (QWidget *w : clipboard.m_widgets) {
1824 auto *cmd =
new InsertWidgetCommand(
this);
1826 m_undoStack.push(cmd);
1832 for (QAction *a : clipboard.m_actions) {
1833 ensureUniqueObjectName(a);
1834 auto *cmd =
new AddActionCommand(
this);
1836 m_undoStack.push(cmd);
1845bool FormWindow::frameNeeded(QWidget *w)
const
1847 if (!core()->widgetDataBase()->isContainer(w))
1849 if (qobject_cast<QGroupBox *>(w))
1851 if (qobject_cast<QToolBox *>(w))
1853 if (qobject_cast<QTabWidget *>(w))
1855 if (qobject_cast<QStackedWidget *>(w))
1857 if (qobject_cast<QDockWidget *>(w))
1859 if (qobject_cast<QDesignerWidget *>(w))
1861 if (qobject_cast<QMainWindow *>(w))
1863 if (qobject_cast<QDialog *>(w))
1865 if (qobject_cast<QLayoutWidget *>(w))
1870bool FormWindow::eventFilter(QObject *watched, QEvent *event)
1872 const bool ret = FormWindowBase::eventFilter(watched, event);
1873 if (event->type() != QEvent::Paint)
1876 Q_ASSERT(watched->isWidgetType());
1877 auto *w =
static_cast<QWidget *>(watched);
1878 auto *pe =
static_cast<QPaintEvent*>(event);
1879 const QRect widgetRect = w->rect();
1880 const QRect paintRect = pe->rect();
1882 if (paintRect.x() > widgetRect.x() && paintRect.y() > widgetRect.y() &&
1883 paintRect.right() < widgetRect.right() && paintRect.bottom() < widgetRect.bottom())
1886 const QPen pen(QColor(0, 0, 0, 32), 0, Qt::DotLine);
1888 p.setBrush(QBrush(Qt::NoBrush));
1889 p.drawRect(widgetRect.adjusted(0, 0, -1, -1));
1893void FormWindow::manageWidget(QWidget *w)
1898 Q_ASSERT(qobject_cast<QMenu*>(w) == 0);
1903 core()->metaDataBase()->add(w);
1905 m_insertedWidgets.insert(w);
1906 m_widgets.append(w);
1908#if QT_CONFIG(cursor)
1909 setCursorToAll(Qt::ArrowCursor, w);
1913 emit widgetManaged(w);
1916 w->installEventFilter(
this);
1919void FormWindow::unmanageWidget(QWidget *w)
1924 m_selection->removeWidget(w);
1926 emit aboutToUnmanageWidget(w);
1928 if (w == m_currentWidget)
1929 setCurrentWidget(mainContainer());
1931 core()->metaDataBase()->remove(w);
1933 m_insertedWidgets.remove(w);
1934 m_widgets.removeAt(m_widgets.indexOf(w));
1937 emit widgetUnmanaged(w);
1940 w->removeEventFilter(
this);
1943bool FormWindow::isManaged(QWidget *w)
const
1945 return m_insertedWidgets.contains(w);
1948void FormWindow::breakLayout(QWidget *w)
1951 w = mainContainer();
1953 QWidgetList widgets;
1955 const QDesignerMetaDataBaseInterface *mdb = core()->metaDataBase();
1956 for (
auto *o : w->children()) {
1957 if (o->isWidgetType()) {
1958 auto *w =
static_cast<QWidget*>(o);
1960 widgets.push_back(w);
1964 auto *cmd =
new BreakLayoutCommand(
this);
1965 cmd->init(widgets, w);
1966 commandHistory()->push(cmd);
1967 clearSelection(
false);
1970void FormWindow::beginCommand(
const QString &description)
1972 m_undoStack.beginMacro(description);
1975void FormWindow::endCommand()
1977 m_undoStack.endMacro();
1980void FormWindow::raiseWidgets()
1982 QWidgetList widgets = selectedWidgets();
1983 simplifySelection(&widgets);
1985 if (widgets.isEmpty())
1988 beginCommand(tr(
"Raise widgets"));
1989 for (QWidget *widget : std::as_const(widgets)) {
1990 auto *cmd =
new RaiseWidgetCommand(
this);
1992 m_undoStack.push(cmd);
1997void FormWindow::lowerWidgets()
1999 QWidgetList widgets = selectedWidgets();
2000 simplifySelection(&widgets);
2002 if (widgets.isEmpty())
2005 beginCommand(tr(
"Lower widgets"));
2006 for (QWidget *widget : std::as_const(widgets)) {
2007 auto *cmd =
new LowerWidgetCommand(
this);
2009 m_undoStack.push(cmd);
2014bool FormWindow::handleMouseButtonDblClickEvent(QWidget *w, QWidget *managedWidget, QMouseEvent *e)
2016 if (debugFormWindow)
2017 qDebug() <<
"handleMouseButtonDblClickEvent:" << w <<
',' << managedWidget <<
"state=" << m_mouseState;
2023 if (isWidgetSelected(managedWidget))
2024 emit activated(managedWidget);
2026 m_mouseState = MouseDoubleClicked;
2031QMenu *FormWindow::initializePopupMenu(QWidget *managedWidget)
2033 if (!isManaged(managedWidget) || currentTool())
2040 const bool selected = isWidgetSelected(managedWidget);
2041 bool update =
false;
2043 update = setCurrentWidget(managedWidget);
2045 clearObjectInspectorSelection(m_core);
2046 clearSelection(
false);
2047 update = trySelectWidget(managedWidget,
true);
2048 raiseChildSelections(managedWidget);
2052 emitSelectionChanged();
2053 QMetaObject::invokeMethod(core()->formWindowManager(),
"slotUpdateActions");
2056 QWidget *contextMenuWidget =
nullptr;
2058 if (isMainContainer(managedWidget)) {
2059 contextMenuWidget = mainContainer();
2062 QWidget *realWidget = managedWidget;
2063 auto *mw = qobject_cast<QMainWindow*>(mainContainer());
2065 if (mw && mw->centralWidget() == realWidget) {
2066 contextMenuWidget = managedWidget;
2068 contextMenuWidget = realWidget;
2072 if (!contextMenuWidget)
2075 QMenu *contextMenu = createPopupMenu(contextMenuWidget);
2079 emit contextMenuRequested(contextMenu, contextMenuWidget);
2083bool FormWindow::handleContextMenu(QWidget *, QWidget *managedWidget, QContextMenuEvent *e)
2085 QMenu *contextMenu = initializePopupMenu(managedWidget);
2088 const QPoint globalPos = e->globalPos();
2089 m_contextMenuPosition = mapFromGlobal (globalPos);
2090 contextMenu->exec(globalPos);
2093 m_contextMenuPosition = QPoint(-1, -1);
2097bool FormWindow::setContents(QIODevice *dev, QString *errorMessageIn )
2099 QDesignerResource r(
this);
2100 std::unique_ptr<DomUI> ui(r.readUi(dev));
2103 *errorMessageIn = r.errorString();
2107 UpdateBlocker ub(
this);
2109 m_selection->clearSelectionPool();
2110 m_insertedWidgets.clear();
2114 clearMainContainer();
2115 m_undoStack.clear();
2118 QWidget *w = r.loadUi(ui.get(), formContainer());
2120 setMainContainer(w);
2124 *errorMessageIn = r.errorString();
2125 return w !=
nullptr;
2128bool FormWindow::setContents(
const QString &contents)
2130 QString errorMessage;
2131 QByteArray data = contents.toUtf8();
2133 const bool success = b.open(QIODevice::ReadOnly) && setContents(&b, &errorMessage);
2134 if (!success && !errorMessage.isEmpty())
2135 designerWarning(errorMessage);
2139void FormWindow::layoutContainer(QWidget *w,
int type)
2142 w = mainContainer();
2144 w = core()->widgetFactory()->containerOfWidget(w);
2147 QWidgetList widgets;
2148 for (
auto *o : w->children()) {
2149 if (o->isWidgetType() ) {
2150 auto *widget =
static_cast<QWidget*>(o);
2151 if (widget->isVisibleTo(
this) && isManaged(widget))
2152 widgets.append(widget);
2156 if (widgets.isEmpty())
2159 auto *cmd =
new LayoutCommand(
this);
2160 cmd->init(mainContainer(), widgets,
static_cast<LayoutInfo::Type>(type), w);
2161 clearSelection(
false);
2162 commandHistory()->push(cmd);
2165bool FormWindow::hasInsertedChildren(QWidget *widget)
const
2167 if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
2168 const int index = container->currentIndex();
2171 widget = container->widget(index);
2174 const QWidgetList l = widgets(widget);
2176 auto pred = [
this](QWidget *child) {
2177 return isManaged(child) && !LayoutInfo::isWidgetLaidout(core(), child) && child->isVisibleTo(
this);
2179 return std::any_of(l.cbegin(), l.cend(), pred);
2183void FormWindow::slotSelectWidget(QAction *a)
2185 if (
auto *w = qvariant_cast<QWidget*>(a->data()))
2186 selectSingleWidget(w);
2189void FormWindow::slotCleanChanged(
bool clean)
2195static inline QString objectNameOf(
const QWidget *w)
2197 if (
const auto *lw = qobject_cast<
const QLayoutWidget *>(w)) {
2198 const QLayout *layout = lw->layout();
2199 const QString rc = layout->objectName();
2203 return QString::fromUtf8(layout->metaObject()->className());
2205 return w->objectName();
2208QAction *FormWindow::createSelectAncestorSubMenu(QWidget *w)
2211 QWidgetList parents;
2212 QWidget *mc = mainContainer();
2213 for (QWidget *p = w->parentWidget(); p && p != mc; p = p->parentWidget())
2214 if (isManaged(p) && !isWidgetSelected(p))
2215 parents.push_back(p);
2216 if (parents.isEmpty())
2219 auto *menu =
new QMenu;
2220 auto *ag =
new QActionGroup(menu);
2221 QObject::connect(ag, &QActionGroup::triggered,
this, &FormWindow::slotSelectWidget);
2222 for (
auto *w : std::as_const(parents)) {
2223 QAction *a = ag->addAction(objectNameOf(w));
2224 a->setData(QVariant::fromValue(w));
2227 auto *ma =
new QAction(tr(
"Select Ancestor"),
nullptr);
2232QMenu *FormWindow::createPopupMenu(QWidget *w)
2234 QMenu *popup = createExtensionTaskMenu(
this, w,
true);
2240 QDesignerFormWindowManagerInterface *manager = core()->formWindowManager();
2241 const bool isFormWindow = qobject_cast<
const FormWindow*>(w);
2244 if (!isFormWindow) {
2245 if (
auto *stackedWidget = qobject_cast<QStackedWidget*>(w)) {
2246 QStackedWidgetEventFilter::addStackedWidgetContextMenuActions(stackedWidget, popup);
2247 }
else if (
auto *tabWidget = qobject_cast<QTabWidget*>(w)) {
2248 QTabWidgetEventFilter::addTabWidgetContextMenuActions(tabWidget, popup);
2249 }
else if (
auto *toolBox = qobject_cast<QToolBox*>(w)) {
2250 QToolBoxHelper::addToolBoxContextMenuActions(toolBox, popup);
2253 if (manager->action(QDesignerFormWindowManagerInterface::LowerAction)->isEnabled()) {
2254 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::LowerAction));
2255 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::RaiseAction));
2256 popup->addSeparator();
2258#if QT_CONFIG(clipboard)
2259 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::CutAction));
2260 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::CopyAction));
2264#if QT_CONFIG(clipboard)
2265 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::PasteAction));
2268 if (QAction *selectAncestorAction = createSelectAncestorSubMenu(w))
2269 popup->addAction(selectAncestorAction);
2270 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::SelectAllAction));
2272 if (!isFormWindow) {
2273 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::DeleteAction));
2276 popup->addSeparator();
2277 QMenu *layoutMenu = popup->addMenu(tr(
"Lay out"));
2278 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::AdjustSizeAction));
2279 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::HorizontalLayoutAction));
2280 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::VerticalLayoutAction));
2281 if (!isFormWindow) {
2282 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::SplitHorizontalAction));
2283 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::SplitVerticalAction));
2285 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::GridLayoutAction));
2286 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::FormLayoutAction));
2287 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::BreakLayoutAction));
2288 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::SimplifyLayoutAction));
2293void FormWindow::resizeEvent(QResizeEvent *e)
2295 m_geometryChangedTimer->start(10);
2297 QWidget::resizeEvent(e);
2301
2302
2303
2304
2305
2306QPoint FormWindow::mapToForm(
const QWidget *w, QPoint pos)
const
2309 const QWidget* i = w;
2310 while (i && !i->isWindow() && !isMainContainer(i)) {
2311 p = i->mapToParent(p);
2312 i = i->parentWidget();
2315 return mapFromGlobal(w->mapToGlobal(pos));
2318bool FormWindow::canBeBuddy(QWidget *w)
const
2320 if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), w)) {
2321 const int index = sheet->indexOf(u"focusPolicy"_s);
2324 const Qt::FocusPolicy q =
static_cast<Qt::FocusPolicy>(Utils::valueOf(sheet->property(index), &ok));
2325 return ok && q != Qt::NoFocus;
2332QWidget *FormWindow::findContainer(QWidget *w,
bool excludeLayout)
const
2334 if (!isChildOf(w,
this)
2335 ||
const_cast<
const QWidget *>(w) ==
this)
2338 QDesignerWidgetFactoryInterface *widgetFactory = core()->widgetFactory();
2339 QDesignerWidgetDataBaseInterface *widgetDataBase = core()->widgetDataBase();
2340 QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase();
2342 QWidget *container = widgetFactory->containerOfWidget(mainContainer());
2343 if (!isMainContainer(w)) {
2345 if (qobject_cast<InvisibleWidget*>(w) || !metaDataBase->item(w)) {
2346 w = w->parentWidget();
2350 const bool isContainer = widgetDataBase->isContainer(w,
true) || w == mainContainer();
2352 if (!isContainer || (excludeLayout && qobject_cast<QLayoutWidget*>(w))) {
2353 w = w->parentWidget();
2364void FormWindow::simplifySelection(QWidgetList *sel)
const
2366 if (sel->size() < 2)
2373 QWidget *mainC = mainContainer();
2374 if (sel->contains(mainC)) {
2376 sel->push_back(mainC);
2379 QWidgetList toBeRemoved;
2380 toBeRemoved.reserve(sel->size());
2381 for (
auto *child : std::as_const(*sel)) {
2382 for (QWidget *w = child;
true ; ) {
2383 QWidget *parent = w->parentWidget();
2384 if (!parent || parent == mainC)
2386 if (sel->contains(parent)) {
2387 toBeRemoved.append(child);
2395 for (
auto *r : std::as_const(toBeRemoved))
2399FormWindow *FormWindow::findFormWindow(QWidget *w)
2401 return qobject_cast<FormWindow*>(QDesignerFormWindowInterface::findFormWindow(w));
2404bool FormWindow::isDirty()
const
2406 return !m_undoStack.isClean();
2409void FormWindow::setDirty(
bool dirty)
2412 m_undoStack.resetClean();
2414 m_undoStack.setClean();
2417QWidget *FormWindow::containerAt(
const QPoint &pos)
2419 QWidget *widget = widgetAt(pos);
2420 return findContainer(widget,
true);
2423static QWidget *childAt_SkipDropLine(QWidget *w, QPoint pos)
2425 const QObjectList &child_list = w->children();
2426 for (
auto i = child_list.size() - 1; i >= 0; --i) {
2427 QObject *child_obj = child_list.at(i);
2428 if (qobject_cast<WidgetHandle*>(child_obj) !=
nullptr)
2430 QWidget *child = qobject_cast<QWidget*>(child_obj);
2431 if (!child || child->isWindow() || !child->isVisible() ||
2432 !child->geometry().contains(pos) || child->testAttribute(Qt::WA_TransparentForMouseEvents))
2434 const QPoint childPos = child->mapFromParent(pos);
2435 if (QWidget *res = childAt_SkipDropLine(child, childPos))
2437 if (child->testAttribute(Qt::WA_MouseNoMask) || child->mask().contains(pos)
2438 || child->mask().isEmpty())
2445QWidget *FormWindow::widgetAt(
const QPoint &pos)
2447 QWidget *w = childAt(pos);
2448 if (qobject_cast<
const WidgetHandle*>(w) != 0)
2449 w = childAt_SkipDropLine(
this, pos);
2450 return (w ==
nullptr || w == formContainer()) ?
this : w;
2453void FormWindow::highlightWidget(QWidget *widget,
const QPoint &pos, HighlightMode mode)
2457 if (
auto *mainWindow = qobject_cast<QMainWindow*> (widget))
2458 widget = mainWindow->centralWidget();
2460 QWidget *container = findContainer(widget,
false);
2462 if (container ==
nullptr || core()->metaDataBase()->item(container) ==
nullptr)
2465 if (QDesignerActionProviderExtension *g = qt_extension<QDesignerActionProviderExtension*>(core()->extensionManager(), container)) {
2466 if (mode == Restore) {
2467 g->adjustIndicator(QPoint());
2469 const QPoint pt = widget->mapTo(container, pos);
2470 g->adjustIndicator(pt);
2472 }
else if (QDesignerLayoutDecorationExtension *g = qt_extension<QDesignerLayoutDecorationExtension*>(core()->extensionManager(), container)) {
2473 if (mode == Restore) {
2474 g->adjustIndicator(QPoint(), -1);
2476 const QPoint pt = widget->mapTo(container, pos);
2477 const int index = g->findItemAt(pt);
2478 g->adjustIndicator(pt, index);
2482 auto *mw = qobject_cast<QMainWindow*> (container);
2483 if (container == mainContainer() || (mw && mw->centralWidget() && mw->centralWidget() == container))
2486 if (mode == Restore) {
2487 const auto pit = m_palettesBeforeHighlight.find(container);
2488 if (pit != m_palettesBeforeHighlight.end()) {
2489 container->setPalette(pit.value().first);
2490 container->setAutoFillBackground(pit.value().second);
2491 m_palettesBeforeHighlight.erase(pit);
2494 QPalette p = container->palette();
2495 if (!m_palettesBeforeHighlight.contains(container)) {
2496 PaletteAndFill paletteAndFill;
2497 if (container->testAttribute(Qt::WA_SetPalette))
2498 paletteAndFill.first = p;
2499 paletteAndFill.second = container->autoFillBackground();
2500 m_palettesBeforeHighlight.insert(container, paletteAndFill);
2503 p.setColor(backgroundRole(), p.midlight().color());
2504 container->setPalette(p);
2505 container->setAutoFillBackground(
true);
2509QWidgetList FormWindow::widgets(QWidget *widget)
const
2511 if (widget->children().isEmpty())
2514 for (QObject *o : widget->children()) {
2515 if (o->isWidgetType()) {
2516 QWidget *w = qobject_cast<QWidget*>(o);
2524int FormWindow::toolCount()
const
2526 return m_widgetStack->count();
2529QDesignerFormWindowToolInterface *FormWindow::tool(
int index)
const
2531 return m_widgetStack->tool(index);
2534void FormWindow::registerTool(QDesignerFormWindowToolInterface *tool)
2536 Q_ASSERT(tool !=
nullptr);
2538 m_widgetStack->addTool(tool);
2540 if (m_mainContainer)
2541 m_mainContainer->update();
2544void FormWindow::setCurrentTool(
int index)
2546 m_widgetStack->setCurrentTool(index);
2549int FormWindow::currentTool()
const
2551 return m_widgetStack->currentIndex();
2554bool FormWindow::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event)
2556 if (m_widgetStack ==
nullptr)
2559 QDesignerFormWindowToolInterface *tool = m_widgetStack->currentTool();
2560 if (tool ==
nullptr)
2563 return tool->handleEvent(widget, managedWidget, event);
2566void FormWindow::initializeCoreTools()
2568 m_widgetEditor =
new WidgetEditorTool(
this);
2569 this->FormWindow::registerTool(m_widgetEditor);
2572void FormWindow::checkSelection()
2574 m_checkSelectionTimer->start(0);
2577void FormWindow::checkSelectionNow()
2579 m_checkSelectionTimer->stop();
2581 const QWidgetList &sel = selectedWidgets();
2582 for (QWidget *widget : sel) {
2583 updateSelection(widget);
2585 if (LayoutInfo::layoutType(core(), widget) != LayoutInfo::NoLayout)
2586 updateChildSelections(widget);
2590QString FormWindow::author()
const
2595QString FormWindow::comment()
const
2600void FormWindow::setAuthor(
const QString &author)
2605void FormWindow::setComment(
const QString &comment)
2607 m_comment = comment;
2610void FormWindow::editWidgets()
2612 m_widgetEditor->action()->trigger();
2615QStringList FormWindow::resourceFiles()
const
2617 return m_resourceFiles;
2620void FormWindow::addResourceFile(
const QString &path)
2622 if (!m_resourceFiles.contains(path)) {
2623 m_resourceFiles.append(path);
2625 emit resourceFilesChanged();
2629void FormWindow::removeResourceFile(
const QString &path)
2631 if (m_resourceFiles.removeAll(path) > 0) {
2633 emit resourceFilesChanged();
2637bool FormWindow::blockSelectionChanged(
bool b)
2639 const bool blocked = m_blockSelectionChanged;
2640 m_blockSelectionChanged = b;
2644void FormWindow::editContents()
2646 const QWidgetList sel = selectedWidgets();
2647 if (sel.size() == 1) {
2648 QWidget *widget = sel.first();
2650 if (QAction *a = preferredEditAction(core(), widget))
2655void FormWindow::dragWidgetWithinForm(QWidget *widget, QRect targetGeometry, QWidget *targetContainer)
2657 const bool fromLayout = canDragWidgetInLayout(core(), widget);
2658 const QDesignerLayoutDecorationExtension *targetDeco = qt_extension<QDesignerLayoutDecorationExtension*>(core()->extensionManager(), targetContainer);
2659 const bool toLayout = targetDeco !=
nullptr;
2665 auto *cmd =
new DeleteWidgetCommand(
this);
2666 unsigned deleteFlags = DeleteWidgetCommand::DoNotUnmanage;
2668 deleteFlags |= DeleteWidgetCommand::DoNotSimplifyLayout;
2669 cmd->init(widget, deleteFlags);
2670 commandHistory()->push(cmd);
2675 insertWidget(widget, targetGeometry, targetContainer,
true);
2678 if (targetContainer != widget->parent()) {
2679 auto *cmd =
new ReparentWidgetCommand(
this);
2680 cmd->init(widget, targetContainer );
2681 commandHistory()->push(cmd);
2683 resizeWidget(widget, targetGeometry);
2684 selectWidget(widget,
true);
2689static Qt::DockWidgetArea detectDropArea(QMainWindow *mainWindow, QRect area, QPoint drop)
2691 QPoint offset = area.topLeft();
2693 rect.moveTopLeft(QPoint(0, 0));
2694 QPoint point = drop - offset;
2695 const int x = point.x();
2696 const int y = point.y();
2697 const int w = rect.width();
2698 const int h = rect.height();
2700 if (rect.contains(point)) {
2701 bool topRight =
false;
2702 bool topLeft =
false;
2705 if (w * y < h * (w - x))
2708 if (topRight && topLeft)
2709 return Qt::TopDockWidgetArea;
2710 if (topRight && !topLeft)
2711 return Qt::RightDockWidgetArea;
2712 if (!topRight && topLeft)
2713 return Qt::LeftDockWidgetArea;
2714 return Qt::BottomDockWidgetArea;
2719 return mainWindow->corner(Qt::TopLeftCorner);
2720 return y > h ? mainWindow->corner(Qt::BottomLeftCorner) : Qt::LeftDockWidgetArea;
2724 return mainWindow->corner(Qt::TopRightCorner);
2725 return y > h ? mainWindow->corner(Qt::BottomRightCorner) : Qt::RightDockWidgetArea;
2727 return y < 0 ? Qt::TopDockWidgetArea :Qt::LeftDockWidgetArea;
2730bool FormWindow::dropDockWidget(QDesignerDnDItemInterface *item, QPoint global_mouse_pos)
2732 DomUI *dom_ui = item->domUi();
2734 auto *mw = qobject_cast<QMainWindow *>(mainContainer());
2738 QDesignerResource resource(
this);
2739 const FormBuilderClipboard clipboard = resource.paste(dom_ui, mw);
2740 if (clipboard.m_widgets.size() != 1)
2743 QWidget *centralWidget = mw->centralWidget();
2744 QPoint localPos = centralWidget->mapFromGlobal(global_mouse_pos);
2745 const QRect centralWidgetAreaRect = centralWidget->rect();
2746 Qt::DockWidgetArea area = detectDropArea(mw, centralWidgetAreaRect, localPos);
2748 beginCommand(tr(
"Drop widget"));
2750 clearSelection(
false);
2751 highlightWidget(mw, QPoint(0, 0), FormWindow::Restore);
2753 QWidget *widget = clipboard.m_widgets.first();
2755 insertWidget(widget, QRect(0, 0, 1, 1), mw);
2757 selectWidget(widget,
true);
2758 mw->setFocus(Qt::MouseFocusReason);
2760 core()->formWindowManager()->setActiveFormWindow(
this);
2761 mainContainer()->activateWindow();
2763 auto *propertySheet = qobject_cast<QDesignerPropertySheetExtension*>(m_core->extensionManager()->extension(widget, Q_TYPEID(QDesignerPropertySheetExtension)));
2764 if (propertySheet) {
2765 const QString dockWidgetAreaName = u"dockWidgetArea"_s;
2766 auto e = qvariant_cast<PropertySheetEnumValue>(propertySheet->property(propertySheet->indexOf(dockWidgetAreaName)));
2770 auto *cmd =
new SetPropertyCommand(
this);
2771 cmd->init(widget, dockWidgetAreaName, v);
2772 m_undoStack.push(cmd);
2779bool FormWindow::dropWidgets(
const QList<QDesignerDnDItemInterface*> &item_list, QWidget *target,
2780 const QPoint &global_mouse_pos)
2783 QWidget *parent = target;
2784 if (parent ==
nullptr)
2785 parent = mainContainer();
2788 if (
auto *main_win = qobject_cast<QMainWindow*>(target)) {
2789 if (!main_win->centralWidget()) {
2790 designerWarning(tr(
"A QMainWindow-based form does not contain a central widget."));
2793 const QPoint main_win_pos = main_win->mapFromGlobal(global_mouse_pos);
2794 const QRect central_wgt_geo = main_win->centralWidget()->geometry();
2795 if (!central_wgt_geo.contains(main_win_pos))
2799 QWidget *container = findContainer(parent,
false);
2800 if (container ==
nullptr)
2803 beginCommand(tr(
"Drop widget"));
2805 clearSelection(
false);
2806 highlightWidget(target, target->mapFromGlobal(global_mouse_pos), FormWindow::Restore);
2809 QDesignerDnDItemInterface *current =
nullptr;
2810 QDesignerFormWindowCursorInterface *c = cursor();
2811 for (QDesignerDnDItemInterface *item : std::as_const(item_list)) {
2812 QWidget *w = item->widget();
2815 if (c->current() == w) {
2821 QRect geom = current->decoration()->geometry();
2822 QPoint topLeft = container->mapFromGlobal(geom.topLeft());
2823 offset = designerGrid().snapPoint(topLeft) - topLeft;
2826 for (QDesignerDnDItemInterface *item : std::as_const(item_list)) {
2827 DomUI *dom_ui = item->domUi();
2828 QRect geometry = item->decoration()->geometry();
2829 Q_ASSERT(dom_ui !=
nullptr);
2831 geometry.moveTopLeft(container->mapFromGlobal(geometry.topLeft()) + offset);
2832 if (item->type() == QDesignerDnDItemInterface::CopyDrop) {
2833 QWidget *widget = createWidget(dom_ui, geometry, parent);
2838 selectWidget(widget,
true);
2839 mainContainer()->setFocus(Qt::MouseFocusReason);
2841 QWidget *widget = item->widget();
2842 Q_ASSERT(widget !=
nullptr);
2843 QDesignerFormWindowInterface *dest = findFormWindow(widget);
2845 dragWidgetWithinForm(widget, geometry, container);
2847 auto *source = qobject_cast<FormWindow*>(item->source());
2848 Q_ASSERT(source !=
nullptr);
2850 source->deleteWidgetList(QWidgetList() << widget);
2851 auto *new_widget = createWidget(dom_ui, geometry, parent);
2853 selectWidget(new_widget,
true);
2858 core()->formWindowManager()->setActiveFormWindow(
this);
2859 mainContainer()->activateWindow();
2864QDir FormWindow::absoluteDir()
const
2866 if (fileName().isEmpty())
2867 return QDir::current();
2869 return QFileInfo(fileName()).absoluteDir();
2872void FormWindow::layoutDefault(
int *margin,
int *spacing)
2874 *margin = m_defaultMargin;
2875 *spacing = m_defaultSpacing;
2878void FormWindow::setLayoutDefault(
int margin,
int spacing)
2880 m_defaultMargin = margin;
2881 m_defaultSpacing = spacing;
2884void FormWindow::layoutFunction(QString *margin, QString *spacing)
2886 *margin = m_marginFunction;
2887 *spacing = m_spacingFunction;
2890void FormWindow::setLayoutFunction(
const QString &margin,
const QString &spacing)
2892 m_marginFunction = margin;
2893 m_spacingFunction = spacing;
2896QString FormWindow::pixmapFunction()
const
2898 return m_pixmapFunction;
2901void FormWindow::setPixmapFunction(
const QString &pixmapFunction)
2903 m_pixmapFunction = pixmapFunction;
2906QStringList FormWindow::includeHints()
const
2908 return m_includeHints;
2911void FormWindow::setIncludeHints(
const QStringList &includeHints)
2913 m_includeHints = includeHints;
2916QString FormWindow::exportMacro()
const
2918 return m_exportMacro;
2921void FormWindow::setExportMacro(
const QString &exportMacro)
2923 m_exportMacro = exportMacro;
2926QEditorFormBuilder *FormWindow::createFormBuilder()
2928 return new QDesignerResource(
this);
2931QWidget *FormWindow::formContainer()
const
2933 return m_widgetStack->formContainer();
2936QUndoStack *FormWindow::commandHistory()
const
2938 return &
const_cast<QUndoStack &>(m_undoStack);
QDesignerResource(FormWindow *fw)
Auxiliary methods to store/retrieve settings.
static unsigned mouseFlags(Qt::KeyboardModifiers mod)
static void insertNames(const QDesignerMetaDataBaseInterface *metaDataBase, Iterator it, const Iterator &end, QObject *excludedObject, QSet< QString > &nameSet)
static void clearObjectInspectorSelection(const QDesignerFormEditorInterface *core)
static bool canDragWidgetInLayout(const QDesignerFormEditorInterface *core, QWidget *w)
@ ToggleSelectionModifier
static bool isDescendant(const QWidget *parent, const QWidget *child)
static QSet< QString > languageKeywords()
static QWidget * findSelectedParent(QDesignerFormWindowInterface *fw, const QWidget *w, bool selected)
QRect apply(QRect rect) const