17#include <metadatabase_p.h>
18#include <qdesigner_tabwidget_p.h>
19#include <qdesigner_toolbox_p.h>
20#include <qdesigner_stackedbox_p.h>
21#include <qdesigner_resource.h>
22#include <qdesigner_command_p.h>
23#include <qdesigner_command2_p.h>
24#include <qdesigner_propertycommand_p.h>
25#include <qdesigner_taskmenu_p.h>
26#include <qdesigner_widget_p.h>
27#include <qdesigner_utils_p.h>
28#include <qlayout_widget_p.h>
29#include <spacer_widget_p.h>
30#include <invisible_widget_p.h>
31#include <layoutinfo_p.h>
32#include <qdesigner_objectinspector_p.h>
33#include <connectionedit_p.h>
34#include <actionprovider_p.h>
35#include <private/ui4_p.h>
36#include <deviceprofile_p.h>
37#include <shared_settings_p.h>
40#include <QtDesigner/qextensionmanager.h>
41#include <QtDesigner/abstractwidgetdatabase.h>
42#include <QtDesigner/propertysheet.h>
43#include <QtDesigner/abstractwidgetfactory.h>
44#include <QtDesigner/container.h>
45#include <QtDesigner/taskmenu.h>
46#include <QtDesigner/abstractwidgetbox.h>
47#include <QtDesigner/private/ui4_p.h>
49#include <abstractdialoggui_p.h>
51#include <QtWidgets/qmenu.h>
52#include <QtWidgets/qscrollarea.h>
53#include <QtWidgets/qrubberband.h>
54#include <QtWidgets/qapplication.h>
55#include <QtWidgets/qsplitter.h>
56#include <QtWidgets/qgroupbox.h>
57#include <QtWidgets/qdockwidget.h>
58#include <QtWidgets/qtoolbox.h>
59#include <QtWidgets/qstackedwidget.h>
60#include <QtWidgets/qtabwidget.h>
61#include <QtWidgets/qbuttongroup.h>
63#include <QtGui/qaction.h>
64#include <QtGui/qactiongroup.h>
65#if QT_CONFIG(clipboard)
66# include <QtGui/qclipboard.h>
68#include <QtGui/qpainter.h>
69#include <QtGui/qundogroup.h>
71#include <QtCore/qdebug.h>
72#include <QtCore/qbuffer.h>
73#include <QtCore/qtimer.h>
74#include <QtCore/qlist.h>
75#include <QtCore/qxmlstream.h>
79Q_DECLARE_METATYPE(QWidget*)
83using namespace Qt::StringLiterals;
88 Q_DISABLE_COPY_MOVE(BlockSelection)
90 BlockSelection(qdesigner_internal::FormWindow *fw)
92 m_blocked(m_formWindow->blockSelectionChanged(
true))
99 m_formWindow->blockSelectionChanged(m_blocked);
103 QPointer<qdesigner_internal::FormWindow> m_formWindow;
104 const bool m_blocked;
107enum { debugFormWindow = 0 };
149 SelectionPool m_selectionPool;
151 QHash<QWidget *, WidgetSelection *> m_usedSelections;
163 if (!m_usedSelections.isEmpty()) {
164 for (
auto it = m_usedSelections.begin(), mend = m_usedSelections.end(); it != mend; ++it)
165 it.value()->setWidget(
nullptr);
166 m_usedSelections.clear();
173 qDeleteAll(m_selectionPool);
174 m_selectionPool.clear();
186 for (
auto *s : std::as_const(m_selectionPool)) {
194 rc =
new WidgetSelection(fw);
195 m_selectionPool.push_back(rc);
198 m_usedSelections.insert(w, rc);
210 m_usedSelections.remove(w);
212 if (m_usedSelections.isEmpty())
215 return (*m_usedSelections.begin())->widget();
226 for (
auto it = m_usedSelections.begin(), mend = m_usedSelections.end(); it != mend; ++it)
227 it.value()->update();
231 return m_usedSelections.contains(w);
236 return m_usedSelections.keys();
241 for (
auto it = m_usedSelections.constBegin(), mend = m_usedSelections.constEnd(); it != mend; ++it) {
276 m_mouseState(NoMouseState),
283 deviceProfile().apply(core, m_widgetStack
->formContainer(), qdesigner_internal::DeviceProfile::ApplyFormParent);
285 setLayout(m_widgetStack->layout());
288 m_cursor =
new FormWindowCursor(
this,
this);
290 core->formWindowManager()->addFormWindow(
this);
293 setAcceptDrops(
true);
298 auto *core =
this->FormWindow::core();
299 Q_ASSERT(core !=
nullptr);
300 Q_ASSERT(core->metaDataBase() !=
nullptr);
301 auto *fwm = core->formWindowManager();
302 Q_ASSERT(fwm !=
nullptr);
304 core->formWindowManager()->removeFormWindow(
this);
305 core->metaDataBase()->remove(
this);
307 const QWidgetList &l = widgets();
309 core->metaDataBase()->remove(w);
311 m_widgetStack =
nullptr;
312 m_rubberBand =
nullptr;
314 core->resourceModel()->removeResourceSet(resourceSet());
317 if (
auto *manager = qobject_cast<FormWindowManager*>(fwm))
318 manager->undoGroup()->removeStack(&m_undoStack);
319 m_undoStack.disconnect();
334 if (!m_mainContainer)
341 while (w && !w->isWindow()) {
343 w = w->parentWidget();
354 c = c->parentWidget();
363 const QWidgetList widgets = start->findChildren<QWidget*>();
364 for (QWidget *widget : widgets) {
365 if (!qobject_cast<WidgetHandle*>(widget)) {
366 widget->setCursor(c);
374 auto *core =
this->FormWindow::core();
375 if (
auto *manager = qobject_cast<FormWindowManager*>(core->formWindowManager()))
376 manager->undoGroup()->addStack(&m_undoStack);
378 m_blockSelectionChanged =
false;
380 m_defaultMargin = INT_MIN;
381 m_defaultSpacing = INT_MIN;
383 connect(m_widgetStack, &FormWindowWidgetStack::currentToolChanged,
384 this, &QDesignerFormWindowInterface::toolChanged);
386 m_selectionChangedTimer =
new QTimer(
this);
387 m_selectionChangedTimer->setSingleShot(
true);
388 connect(m_selectionChangedTimer, &QTimer::timeout,
this,
389 &FormWindow::selectionChangedTimerDone);
391 m_checkSelectionTimer =
new QTimer(
this);
392 m_checkSelectionTimer->setSingleShot(
true);
393 connect(m_checkSelectionTimer, &QTimer::timeout,
396 m_geometryChangedTimer =
new QTimer(
this);
397 m_geometryChangedTimer->setSingleShot(
true);
398 connect(m_geometryChangedTimer, &QTimer::timeout,
399 this, &QDesignerFormWindowInterface::geometryChanged);
401 m_rubberBand =
nullptr;
403 setFocusPolicy(Qt::StrongFocus);
405 m_mainContainer =
nullptr;
406 m_currentWidget =
nullptr;
408 connect(&m_undoStack, &QUndoStack::indexChanged,
409 this, &QDesignerFormWindowInterface::changed);
410 connect(&m_undoStack, &QUndoStack::cleanChanged,
412 connect(
this, &QDesignerFormWindowInterface::changed,
415 core->metaDataBase()->add(
this);
417 initializeCoreTools();
419 auto *a =
new QAction(
this);
420 a->setText(tr(
"Edit contents"));
421 a->setShortcut(tr(
"F2"));
428 return m_mainContainer;
434 if (m_mainContainer) {
437 core()->metaDataBase()->remove(m_mainContainer);
439 delete m_mainContainer;
440 m_mainContainer =
nullptr;
446 if (w == m_mainContainer) {
451 clearMainContainer();
454 const QSize sz = m_mainContainer->size();
457 m_widgetStack->setCurrentTool(m_widgetEditor);
459 setCurrentWidget(m_mainContainer);
463 sheet->setVisible(sheet->indexOf(u"windowTitle"_s),
true);
464 sheet->setVisible(sheet->indexOf(u"windowIcon"_s),
true);
465 sheet->setVisible(sheet->indexOf(u"windowModality"_s),
true);
466 sheet->setVisible(sheet->indexOf(u"windowOpacity"_s),
true);
467 sheet->setVisible(sheet->indexOf(u"windowFilePath"_s),
true);
471 m_mainContainer->setFocusPolicy(Qt::StrongFocus);
472 m_mainContainer->resize(sz);
474 emit mainContainerChanged(m_mainContainer);
481 while (
QWidget *parentWidget = widget->parentWidget()) {
482 if (LayoutInfo::layoutType(m_core, parentWidget) == LayoutInfo::NoLayout && isManaged(widget))
485 widget = parentWidget;
493 if (
auto *oi = qobject_cast<QDesignerObjectInspector *>(core->objectInspector()))
494 oi->clearSelection();
500 const QDesignerFormWindowCursorInterface *cursor = fw->cursor();
501 QWidget *mainContainer = fw->mainContainer();
502 for (
QWidget *p = w->parentWidget(); p && p != mainContainer; p = p->parentWidget())
503 if (fw->isManaged(p))
504 if (cursor->isWidgetSelected(p) == selected)
516 case Qt::ShiftModifier:
520 case Qt::AltModifier:
521 return CopyDragModifier;
523 case Qt::ControlModifier:
536 const bool sameWidget = managedWidget == m_lastClickedWidget;
537 m_lastClickedWidget = managedWidget;
541 qDebug() <<
"handleClickSelection" << managedWidget <<
" same=" << sameWidget <<
" mouse= " << mouseMode <<
" selected=" << selected;
549 QWidget *selectionCandidate =
nullptr;
553 if (
QWidget *currentlySelectedParent = selected ? managedWidget : findSelectedParent(
this, managedWidget,
true))
554 selectionCandidate = findSelectedParent(
this, currentlySelectedParent,
false);
556 if (!selectionCandidate && !selected)
557 selectionCandidate = managedWidget;
559 if (selectionCandidate)
560 selectSingleWidget(selectionCandidate);
572 m_mouseState = NoMouseState;
573 m_startPos = QPoint();
576 BlockSelection blocker(
this);
578 if (core()->formWindowManager()->activeFormWindow() !=
this)
579 core()->formWindowManager()->setActiveFormWindow(
this);
581 const Qt::MouseButtons buttons = e->buttons();
582 if (buttons != Qt::LeftButton && buttons != Qt::MiddleButton)
585 m_startPos = mapFromGlobal(e->globalPosition().toPoint());
588 qDebug() <<
"handleMousePressEvent:" << widget <<
',' << managedWidget;
590 if (buttons == Qt::MiddleButton || isMainContainer(managedWidget)) {
591 clearObjectInspectorSelection(m_core);
594 m_mouseState = MouseDrawRubber;
595 m_currRect = QRect();
596 startRectDraw(mapFromGlobal(e->globalPosition().toPoint()),
this, Rubber);
599 if (buttons != Qt::LeftButton)
602 const unsigned mouseMode = mouseFlags(e->modifiers());
605
606
607
608
609
610
611
612 const bool deferSelection =
isWidgetSelected(managedWidget
) || findSelectedParent(
this, managedWidget,
true);
613 if (deferSelection) {
614 m_mouseState = MouseDeferredSelection;
618 handleClickSelection(managedWidget, effectiveMouseMode);
626 bool managed =
false;
627 const LayoutInfo::Type type = LayoutInfo::laidoutWidgetType(core ,w, &managed);
631 case LayoutInfo::NoLayout:
632 case LayoutInfo::HSplitter:
633 case LayoutInfo::VSplitter:
644 if (m_startPos.isNull())
647 const QPoint pos = mapFromGlobal(e->globalPosition().toPoint());
649 switch (m_mouseState) {
650 case MouseDrawRubber:
651 continueRectDraw(pos,
this, Rubber);
659 if (e->buttons() != Qt::LeftButton)
662 const bool canStartDrag = (m_startPos - pos).manhattanLength() > QApplication::startDragDistance();
667 m_mouseState = MouseMoveDrag;
670 QWidgetList sel = selectedWidgets();
671 const QWidgetList originalSelection = sel;
672 simplifySelection(&sel);
674 QSet<QWidget*> widget_set;
676 for (QWidget *child : std::as_const(sel)) {
677 QWidget *current = child;
680 while (!isMainContainer(current) && !done) {
681 if (!isManaged(current)) {
682 current = current->parentWidget();
685 if (LayoutInfo::isWidgetLaidout(core(), current)) {
687 if (!canDragWidgetInLayout(core(), current)) {
688 current = current->parentWidget();
695 if (current == mainContainer())
698 widget_set.insert(current);
701 sel = widget_set.values();
702 QDesignerFormWindowCursorInterface *c = cursor();
703 QWidget *current = c->current();
704 if (sel.contains(current)) {
705 sel.removeAll(current);
706 sel.prepend(current);
709 QList<QDesignerDnDItemInterface*> item_list;
710 const QPoint globalPos = mapToGlobal(m_startPos);
711 const QDesignerDnDItemInterface::DropType dropType = (mouseFlags(e->modifiers()) & CopyDragModifier) ?
712 QDesignerDnDItemInterface::CopyDrop : QDesignerDnDItemInterface::MoveDrop;
713 for (QWidget *widget : std::as_const(sel)) {
714 item_list.append(
new FormWindowDnDItem(dropType,
this, widget, globalPos));
715 if (dropType == QDesignerDnDItemInterface::MoveDrop) {
716 m_selection->hide(widget);
723 for (
auto *widget : originalSelection)
724 m_selection->hide(widget);
729 if (QDesignerMimeData::execDrag(item_list, core()->topLevel()) == Qt::IgnoreAction && dropType == QDesignerDnDItemInterface::MoveDrop)
730 for (QWidget *widget : std::as_const(sel))
731 m_selection->show(widget);
733 m_startPos = QPoint();
740 const MouseState oldState = m_mouseState;
741 m_mouseState = NoMouseState;
744 qDebug() <<
"handleMouseeleaseEvent:" << w <<
',' << mw <<
"state=" << oldState;
746 if (oldState == MouseDoubleClicked)
752 case MouseDrawRubber: {
760 case MouseDeferredSelection:
761 handleClickSelection(mw, mouseFlags(e->modifiers()));
767 m_startPos = QPoint();
770
771
772 switch (e->button()) {
774 case Qt::MiddleButton:
775 case Qt::RightButton:
785void FormWindow::checkPreviewGeometry(QRect &r)
787 if (!rect().contains(r)) {
788 if (r.left() < rect().left())
789 r.moveTopLeft(QPoint(0, r.top()));
790 if (r.right() > rect().right())
791 r.moveBottomRight(QPoint(rect().right(), r.bottom()));
792 if (r.top() < rect().top())
793 r.moveTopLeft(QPoint(r.left(), rect().top()));
794 if (r.bottom() > rect().bottom())
795 r.moveBottomRight(QPoint(r.right(), rect().bottom()));
801 m_rectAnchor = (t == Insert) ? designerGrid().snapPoint(pos) : pos;
803 m_currRect = QRect(m_rectAnchor, QSize(0, 0));
805 m_rubberBand =
new QRubberBand(QRubberBand::Rectangle,
this);
806 m_rubberBand->setGeometry(m_currRect);
807 m_rubberBand->show();
812 const QPoint p2 = (t == Insert) ? designerGrid().snapPoint(pos) : pos;
814 QRect r(m_rectAnchor, p2);
820 if (r.width() > 1 || r.height() > 1) {
823 m_rubberBand->setGeometry(m_currRect);
831 m_rubberBand =
nullptr;
837 return m_currentWidget;
843 qDebug() <<
"setCurrentWidget:" << m_currentWidget <<
" --> " << currentWidget;
844 if (currentWidget == m_currentWidget)
851 m_currentWidget = currentWidget;
860 if (trySelectWidget(w, select))
868 qDebug() <<
"trySelectWidget:" << w << select;
890 setCurrentWidget(newCurrent);
898 qDebug() <<
"clearSelection(" << changePropertyDisplay <<
')';
903 if (changePropertyDisplay)
909 if (m_blockSelectionChanged)
912 m_selectionChangedTimer->start(0);
917 emit selectionChanged();
932 const QWidgetList l = w->findChildren<
QWidget*>();
951 if (!w->isVisibleTo(
this)) {
961 w = w->parentWidget();
968 if (
auto *mainWindow = qobject_cast<QMainWindow*>(mainContainer()))
969 return w == mainWindow->centralWidget();
976 QString name = object->objectName();
977 if (name.isEmpty()) {
978 QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase();
979 if (QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(object)))
980 name = qdesigner_internal::qtify(item->name());
982 unify(object, name,
true);
983 object->setObjectName(name);
986template <
class Iterator>
987static inline void insertNames(
const QDesignerMetaDataBaseInterface *metaDataBase,
988 Iterator it,
const Iterator &end,
989 QObject *excludedObject, QSet<QString> &nameSet)
991 for ( ; it != end; ++it)
992 if (excludedObject != *it && metaDataBase->item(*it))
993 nameSet.insert((*it)->objectName());
998 static const QSet<QString> keywords = {
1044 u"reinterpret_cast"_s,
1095 using StringSet = QSet<QString>;
1101 StringSet existingNames = languageKeywords();
1104 existingNames.insert(main->objectName());
1106 const QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase();
1107 const QWidgetList widgetChildren = main->findChildren<
QWidget*>();
1108 if (!widgetChildren.isEmpty())
1109 insertNames(metaDataBase, widgetChildren.constBegin(), widgetChildren.constEnd(), w, existingNames);
1111 const auto layoutChildren = main->findChildren<QLayout*>();
1112 if (!layoutChildren.isEmpty())
1113 insertNames(metaDataBase, layoutChildren.constBegin(), layoutChildren.constEnd(), w, existingNames);
1115 const auto actionChildren = main->findChildren<QAction*>();
1116 if (!actionChildren.isEmpty())
1117 insertNames(metaDataBase, actionChildren.constBegin(), actionChildren.constEnd(), w, existingNames);
1119 const auto buttonGroupChildren = main->findChildren<QButtonGroup*>();
1120 if (!buttonGroupChildren.isEmpty())
1121 insertNames(metaDataBase, buttonGroupChildren.constBegin(), buttonGroupChildren.constEnd(), w, existingNames);
1123 if (!existingNames.contains(s))
1130 qlonglong factor = 1;
1131 qsizetype idx = s.size() - 1;
1132 const char16_t zeroUnicode = u'0';
1133 for ( ; idx > 0 && s.at(idx).isDigit(); --idx) {
1134 num += (s.at(idx).unicode() - zeroUnicode) * factor;
1138 const QChar underscore = u'_';
1139 if (idx >= 0 && s.at(idx) == underscore) {
1147 for (num++ ; ;num++) {
1149 s += QString::number(num);
1150 if (!existingNames.contains(s))
1156
1162 beginCommand(tr(
"Insert widget '%1'").arg(WidgetFactory::classNameOf(m_core, w)));
1165
1166
1168 Q_ASSERT(r.isValid());
1169 auto *geom_cmd =
new SetPropertyCommand(
this);
1170 geom_cmd->init(w, u"geometry"_s, r);
1172 if (w->parentWidget() != container) {
1173 auto *cmd =
new ReparentWidgetCommand(
this);
1174 cmd->init(w, container);
1175 m_undoStack.push(cmd);
1178 m_undoStack.push(geom_cmd);
1180 QUndoCommand *cmd =
nullptr;
1181 if (
auto *dockWidget = qobject_cast<QDockWidget *>(w)) {
1182 if (
auto *mainWindow = qobject_cast<QMainWindow *>(container)) {
1183 auto *addDockCmd =
new AddDockWidgetCommand(
this);
1184 addDockCmd->init(mainWindow, dockWidget);
1188 if (cmd ==
nullptr) {
1189 auto *insertCmd =
new InsertWidgetCommand(
this);
1190 insertCmd->init(w, already_in_form);
1193 m_undoStack.push(cmd);
1206 if (
auto *mw = qobject_cast<QMainWindow*>(container)) {
1207 Q_ASSERT(mw->centralWidget() !=
nullptr);
1208 container = mw->centralWidget();
1212 const FormBuilderClipboard clipboard = resource.paste(ui, container);
1213 if (clipboard.m_widgets.size() != 1)
1215 QWidget *widget = clipboard.m_widgets.first();
1216 insertWidget(widget, rc, container);
1222 for (; child !=
nullptr; child = child->parentWidget()) {
1223 if (child == parent)
1231 Q_ASSERT(isDescendant(
this, widget));
1234 auto *cmd =
new SetPropertyCommand(
this);
1235 cmd->init(widget, u"geometry"_s, r);
1236 cmd->setText(tr(
"Resize"));
1237 m_undoStack.push(cmd);
1242 const QWidgetList l = w->findChildren<
QWidget*>();
1245 m_selection->raiseList(l);
1252 const QWidgetList selected = selectedWidgets();
1253 if (rect().contains(mapFromGlobal(pos))) {
1255 depth = widgetDepth(container);
1258 for (QWidget *wit : std::as_const(m_widgets)) {
1259 if (qobject_cast<QLayoutWidget*>(wit) || qobject_cast<QSplitter*>(wit))
1261 if (!wit->isVisibleTo(
this))
1263 if (selected.indexOf(wit) != -1)
1265 if (!core()->widgetDataBase()->isContainer(wit) &&
1266 wit != mainContainer())
1271 while (w && !w->isWindow()) {
1272 if (!w->rect().contains((w->mapFromGlobal(pos))))
1274 w = w->parentWidget();
1276 if (!(w ==
nullptr || w->isWindow()))
1279 int wd = widgetDepth(wit);
1280 if (wd == depth && container) {
1281 if (wit->parentWidget()->children().indexOf(wit) >
1282 container->parentWidget()->children().indexOf(container))
1285 if (wd > depth && !isChildOf(wit, notParentOf)) {
1295 return m_selection->selectedWidgets();
1300 bool selectionChanged =
false;
1302 const QRect selRect(mapToGlobal(m_currRect.topLeft()), m_currRect.size());
1303 for (QWidget *w : l) {
1304 if (w->isVisibleTo(
this) && isManaged(w)) {
1305 const QPoint p = w->mapToGlobal(QPoint(0,0));
1306 const QRect r(p, w->size());
1307 if (r.intersects(selRect) && !r.contains(selRect) && trySelectWidget(w,
true))
1308 selectionChanged =
true;
1312 if (selectionChanged)
1318 if (qobject_cast<
const FormWindow*>(widget) || qobject_cast<
const QMenu*>(widget))
1326 case Qt::Key_Delete:
1327 case Qt::Key_Backspace:
1328 if (e->modifiers() == Qt::NoModifier)
1333 if (e->modifiers() == Qt::NoModifier)
1334 cursor()->movePosition(QDesignerFormWindowCursorInterface::Next);
1337 case Qt::Key_Backtab:
1338 if (e->modifiers() == Qt::NoModifier)
1339 cursor()->movePosition(QDesignerFormWindowCursorInterface::Prev);
1346 handleArrowKeyEvent(e->key(), e->modifiers());
1353int FormWindow::getValue(QRect rect,
int key,
bool size)
const
1356 if (key == Qt::Key_Left || key == Qt::Key_Right)
1357 return rect.width();
1358 return rect.height();
1360 if (key == Qt::Key_Left || key == Qt::Key_Right)
1365int FormWindow::calcValue(
int val,
bool forward,
bool snap,
int snapOffset)
const
1368 const int rest = val % snapOffset;
1370 const int offset = forward ? snapOffset : 0;
1371 const int newOffset = rest < 0 ? offset - snapOffset : offset;
1372 return val + newOffset - rest;
1374 return (forward ? val + snapOffset : val - snapOffset);
1376 return (forward ? val + 1 : val - 1);
1393Q_DECLARE_METATYPE(qdesigner_internal::ArrowKeyOperation)
1396namespace qdesigner_internal {
1398QRect ArrowKeyOperation::apply(QRect rect)
const
1402 if (arrowKey == Qt::Key_Left || arrowKey == Qt::Key_Right)
1403 r.setWidth(r.width() + distance);
1405 r.setHeight(r.height() + distance);
1407 if (arrowKey == Qt::Key_Left || arrowKey == Qt::Key_Right)
1408 r.moveLeft(r.x() + distance);
1410 r.moveTop(r.y() + distance);
1415QDebug operator<<(QDebug in, ArrowKeyOperation op)
1417 in.nospace() <<
"Resize=" << op.resize <<
" dist=" << op.distance <<
" Key=" << op.arrowKey <<
' ';
1429class ArrowKeyPropertyHelper :
public PropertyHelper {
1431 ArrowKeyPropertyHelper(QObject* o, SpecialProperty sp,
1432 QDesignerPropertySheetExtension *s,
int i) :
1433 PropertyHelper(o, sp, s, i) {}
1435 Value setValue(QDesignerFormWindowInterface *fw,
const QVariant &value,
bool changed,
1436 quint64 subPropertyMask) override;
1439PropertyHelper::Value ArrowKeyPropertyHelper::setValue(QDesignerFormWindowInterface *fw,
const QVariant &value,
1440 bool changed, quint64 subPropertyMask)
1443 auto *w = qobject_cast<QWidget*>(object());
1444 const auto operation = qvariant_cast<ArrowKeyOperation>(value);
1445 const QRect newGeom = operation.apply(w->geometry());
1446 return PropertyHelper::setValue(fw, QVariant(newGeom), changed, subPropertyMask);
1452class ArrowKeyPropertyCommand:
public SetPropertyCommand {
1454 explicit ArrowKeyPropertyCommand(QDesignerFormWindowInterface *fw,
1455 QUndoCommand *p =
nullptr);
1457 void init(QWidgetList &l, ArrowKeyOperation op);
1460 std::unique_ptr<PropertyHelper>
1461 createPropertyHelper(QObject *o, SpecialProperty sp,
1462 QDesignerPropertySheetExtension *s,
int i)
const override
1463 {
return std::make_unique<ArrowKeyPropertyHelper>(o, sp, s, i); }
1464 QVariant mergeValue(
const QVariant &newValue) override;
1467ArrowKeyPropertyCommand::ArrowKeyPropertyCommand(QDesignerFormWindowInterface *fw,
1469 SetPropertyCommand(fw, p)
1471 static const int mid = qRegisterMetaType<qdesigner_internal::ArrowKeyOperation>();
1475void ArrowKeyPropertyCommand::init(QWidgetList &l, ArrowKeyOperation op)
1478 for (QWidget *w : std::as_const(l))
1480 SetPropertyCommand::init(ol, u"geometry"_s, QVariant::fromValue(op));
1482 setText(op.resize ? FormWindow::tr(
"Key Resize") : FormWindow::tr(
"Key Move"));
1485QVariant ArrowKeyPropertyCommand::mergeValue(
const QVariant &newMergeValue)
1488 if (!newMergeValue.canConvert<ArrowKeyOperation>())
1490 auto mergedOperation = qvariant_cast<ArrowKeyOperation>(newValue());
1491 const auto newMergeOperation = qvariant_cast<ArrowKeyOperation>(newMergeValue);
1492 if (mergedOperation.resize != newMergeOperation.resize || mergedOperation.arrowKey != newMergeOperation.arrowKey)
1494 mergedOperation.distance += newMergeOperation.distance;
1495 return QVariant::fromValue(mergedOperation);
1498void FormWindow::handleArrowKeyEvent(
int key, Qt::KeyboardModifiers modifiers)
1500 const QDesignerFormWindowCursorInterface *c = cursor();
1501 if (!c->hasSelection())
1504 QWidgetList selection;
1507 const int count = c->selectedWidgetCount();
1508 for (
int index = 0; index < count; ++index) {
1509 QWidget *w = c->selectedWidget(index);
1510 if (!LayoutInfo::isWidgetLaidout(m_core, w))
1511 selection.append(w);
1514 simplifySelection(&selection);
1516 if (selection.isEmpty())
1519 QWidget *current = c->current();
1520 if (!current || LayoutInfo::isWidgetLaidout(m_core, current)) {
1521 current = selection.first();
1524 const bool size = modifiers & Qt::ShiftModifier;
1526 const bool snap = !(modifiers & Qt::ControlModifier);
1527 const bool forward = (key == Qt::Key_Right || key == Qt::Key_Down);
1528 const int snapPoint = (key == Qt::Key_Left || key == Qt::Key_Right) ? grid().x() : grid().y();
1530 const int oldValue = getValue(current->geometry(), key, size);
1532 const int newValue = calcValue(oldValue, forward, snap, snapPoint);
1534 ArrowKeyOperation operation;
1535 operation.resize = modifiers & Qt::ShiftModifier;
1536 operation.distance = newValue - oldValue;
1537 operation.arrowKey = key;
1539 auto *cmd =
new ArrowKeyPropertyCommand(
this);
1540 cmd->init(selection, operation);
1541 m_undoStack.push(cmd);
1544bool FormWindow::handleKeyReleaseEvent(QWidget *, QWidget *, QKeyEvent *e)
1550void FormWindow::selectAll()
1552 bool selectionChanged =
false;
1553 for (QWidget *widget : std::as_const(m_widgets)) {
1554 if (widget->isVisibleTo(
this) && trySelectWidget(widget,
true))
1555 selectionChanged =
true;
1557 if (selectionChanged)
1558 emitSelectionChanged();
1561void FormWindow::createLayout(
int type, QWidget *container)
1564 layoutContainer(container, type);
1566 auto *cmd =
new LayoutCommand(
this);
1567 cmd->init(mainContainer(), selectedWidgets(),
static_cast<LayoutInfo::Type>(type));
1568 commandHistory()->push(cmd);
1572void FormWindow::morphLayout(QWidget *container,
int newType)
1574 auto *cmd =
new MorphLayoutCommand(
this);
1575 if (cmd->init(container, newType)) {
1576 commandHistory()->push(cmd);
1578 qDebug() <<
"** WARNING Unable to morph layout.";
1583void FormWindow::deleteWidgets()
1585 QWidgetList selection = selectedWidgets();
1586 simplifySelection(&selection);
1588 deleteWidgetList(selection);
1591QString FormWindow::fileName()
const
1596void FormWindow::setFileName(
const QString &fileName)
1598 if (m_fileName == fileName)
1601 m_fileName = fileName;
1602 emit fileNameChanged(fileName);
1605QString FormWindow::contents()
const
1608 if (!mainContainer() || !b.open(QIODevice::WriteOnly))
1611 QDesignerResource resource(
const_cast<FormWindow*>(
this));
1612 resource.save(&b, mainContainer());
1614 return QString::fromUtf8(b.buffer());
1617#if QT_CONFIG(clipboard)
1618void FormWindow::copy()
1621 if (!b.open(QIODevice::WriteOnly))
1624 FormBuilderClipboard clipboard;
1625 QDesignerResource resource(
this);
1626 resource.setSaveRelative(
false);
1627 clipboard.m_widgets = selectedWidgets();
1628 simplifySelection(&clipboard.m_widgets);
1629 resource.copy(&b, clipboard);
1631 qApp->clipboard()->setText(QString::fromUtf8(b.buffer()), QClipboard::Clipboard);
1634void FormWindow::cut()
1640void FormWindow::paste()
1647QWidget *FormWindow::innerContainer(QWidget *outerContainer)
const
1649 if (m_core->widgetDataBase()->isContainer(outerContainer))
1650 if (
const QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(m_core->extensionManager(), outerContainer)) {
1651 const int currentIndex = container->currentIndex();
1652 return currentIndex >= 0 ? container->widget(currentIndex) :
nullptr;
1654 return outerContainer;
1657QWidget *FormWindow::containerForPaste()
const
1659 QWidget *w = mainContainer();
1665 QWidgetList selection = selectedWidgets();
1666 if (selection.isEmpty())
1668 simplifySelection(&selection);
1670 QWidget *containerOfW = findContainer(selection.first(),
true);
1671 if (!containerOfW || containerOfW == mainContainer())
1674 containerOfW = innerContainer(containerOfW);
1677 if (LayoutInfo::layoutType(m_core, containerOfW) != LayoutInfo::NoLayout || !m_core->widgetDataBase()->isContainer(containerOfW))
1684 w = innerContainer(w);
1687 if (LayoutInfo::layoutType(m_core, w) != LayoutInfo::NoLayout)
1690 w = m_core->widgetFactory()->containerOfWidget(w);
1691 if (w ==
nullptr || LayoutInfo::layoutType(m_core, w) != LayoutInfo::NoLayout)
1694 if (debugFormWindow)
1695 qDebug() <<
"containerForPaste() " << w;
1699#if QT_CONFIG(clipboard)
1701static inline DomUI *domUIFromClipboard(
int *widgetCount,
int *actionCount)
1703 *widgetCount = *actionCount = 0;
1704 const QString clipboardText = qApp->clipboard()->text();
1705 if (clipboardText.isEmpty() || clipboardText.indexOf(u'<') == -1)
1708 QXmlStreamReader reader(clipboardText);
1709 DomUI *ui =
nullptr;
1710 while (!reader.atEnd()) {
1711 if (reader.readNext() == QXmlStreamReader::StartElement) {
1712 if (reader.name().compare(
"ui"_L1, Qt::CaseInsensitive) == 0 && !ui) {
1717 reader.raiseError(QCoreApplication::translate(
"FormWindow",
"Unexpected element <%1>").arg(reader.name().toString()));
1720 if (reader.hasError()) {
1723 designerWarning(QCoreApplication::translate(
"FormWindow",
"Error while pasting clipboard contents at line %1, column %2: %3").
1724 arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
1728 if (
const DomWidget *topLevel = ui->elementWidget()) {
1729 *widgetCount = topLevel->elementWidget().size();
1730 *actionCount = topLevel->elementAction().size();
1732 if (*widgetCount == 0 && *actionCount == 0) {
1740static inline QString pasteCommandDescription(
int widgetCount,
int actionCount)
1742 if (widgetCount == 0)
1743 return FormWindow::tr(
"Paste %n action(s)",
nullptr, actionCount);
1744 if (actionCount == 0)
1745 return FormWindow::tr(
"Paste %n widget(s)",
nullptr, widgetCount);
1746 return FormWindow::tr(
"Paste (%1 widgets, %2 actions)").arg(widgetCount).arg(actionCount);
1749#if QT_CONFIG(clipboard)
1750static void positionPastedWidgetsAtMousePosition(FormWindow *fw, QPoint contextMenuPosition, QWidget *parent,
const QWidgetList &l)
1755 QPoint currentPos = contextMenuPosition.x() >=0 ? parent->mapFrom(fw, contextMenuPosition) : parent->mapFromGlobal(QCursor::pos());
1756 const Grid &grid = fw->designerGrid();
1757 QPoint cursorPos = grid.snapPoint(currentPos);
1758 const QRect parentGeometry = QRect(QPoint(0, 0), parent->size());
1759 const bool outside = !parentGeometry.contains(cursorPos);
1761 cursorPos = grid.snapPoint(QPoint(0, 0));
1765 pasteArea = pasteArea.isNull() ? w->geometry() : pasteArea.united(w->geometry());
1770 const QPoint bottomRight = cursorPos + QPoint(pasteArea.width(), pasteArea.height()) - QPoint(1, 1);
1771 if (bottomRight.y() > parentGeometry.bottom() || parent->childAt(bottomRight) ==
nullptr)
1773 cursorPos += QPoint(grid.deltaX(), grid.deltaY());
1776 const QPoint offset = cursorPos - pasteArea.topLeft();
1778 w->move(w->pos() + offset);
1781void FormWindow::paste(PasteMode pasteMode)
1785 DomUI *ui =
nullptr;
1787 int widgetCount = 0;
1788 int actionCount = 0;
1789 ui = domUIFromClipboard(&widgetCount, &actionCount);
1794 if (pasteMode == PasteActionsOnly)
1795 if (widgetCount != 0 || actionCount == 0)
1799 QWidget *pasteContainer = widgetCount ? containerForPaste() :
nullptr;
1800 if (widgetCount && pasteContainer ==
nullptr) {
1802 const QString message = tr(
"Cannot paste widgets. Designer could not find a container "
1803 "without a layout to paste into.");
1804 const QString infoMessage = tr(
"Break the layout of the "
1805 "container you want to paste into, select this container "
1806 "and then paste again.");
1807 core()->dialogGui()->message(
this, QDesignerDialogGuiInterface::FormEditorMessage, QMessageBox::Information,
1808 tr(
"Paste error"), message, infoMessage, QMessageBox::Ok);
1812 QDesignerResource resource(
this);
1816 const FormBuilderClipboard clipboard = resource.paste(ui, pasteContainer,
this);
1818 clearSelection(
false);
1820 beginCommand(pasteCommandDescription(widgetCount, actionCount));
1823 positionPastedWidgetsAtMousePosition(
this, m_contextMenuPosition, pasteContainer, clipboard.m_widgets);
1824 for (QWidget *w : clipboard.m_widgets) {
1825 auto *cmd =
new InsertWidgetCommand(
this);
1827 m_undoStack.push(cmd);
1833 for (QAction *a : clipboard.m_actions) {
1834 ensureUniqueObjectName(a);
1835 auto *cmd =
new AddActionCommand(
this);
1837 m_undoStack.push(cmd);
1846bool FormWindow::frameNeeded(QWidget *w)
const
1848 if (!core()->widgetDataBase()->isContainer(w))
1850 if (qobject_cast<QGroupBox *>(w))
1852 if (qobject_cast<QToolBox *>(w))
1854 if (qobject_cast<QTabWidget *>(w))
1856 if (qobject_cast<QStackedWidget *>(w))
1858 if (qobject_cast<QDockWidget *>(w))
1860 if (qobject_cast<QDesignerWidget *>(w))
1862 if (qobject_cast<QMainWindow *>(w))
1864 if (qobject_cast<QDialog *>(w))
1866 if (qobject_cast<QLayoutWidget *>(w))
1871bool FormWindow::eventFilter(QObject *watched, QEvent *event)
1873 const bool ret = FormWindowBase::eventFilter(watched, event);
1874 if (event->type() != QEvent::Paint)
1877 Q_ASSERT(watched->isWidgetType());
1878 auto *w =
static_cast<QWidget *>(watched);
1879 auto *pe =
static_cast<QPaintEvent*>(event);
1880 const QRect widgetRect = w->rect();
1881 const QRect paintRect = pe->rect();
1883 if (paintRect.x() > widgetRect.x() && paintRect.y() > widgetRect.y() &&
1884 paintRect.right() < widgetRect.right() && paintRect.bottom() < widgetRect.bottom())
1887 const QPen pen(QColor(0, 0, 0, 32), 0, Qt::DotLine);
1889 p.setBrush(QBrush(Qt::NoBrush));
1890 p.drawRect(widgetRect.adjusted(0, 0, -1, -1));
1894void FormWindow::manageWidget(QWidget *w)
1899 Q_ASSERT(qobject_cast<QMenu*>(w) == 0);
1904 core()->metaDataBase()->add(w);
1906 m_insertedWidgets.insert(w);
1907 m_widgets.append(w);
1909#if QT_CONFIG(cursor)
1910 setCursorToAll(Qt::ArrowCursor, w);
1914 emit widgetManaged(w);
1917 w->installEventFilter(
this);
1920void FormWindow::unmanageWidget(QWidget *w)
1925 m_selection->removeWidget(w);
1927 emit aboutToUnmanageWidget(w);
1929 if (w == m_currentWidget)
1930 setCurrentWidget(mainContainer());
1932 core()->metaDataBase()->remove(w);
1934 m_insertedWidgets.remove(w);
1935 m_widgets.removeAt(m_widgets.indexOf(w));
1938 emit widgetUnmanaged(w);
1941 w->removeEventFilter(
this);
1944bool FormWindow::isManaged(QWidget *w)
const
1946 return m_insertedWidgets.contains(w);
1949void FormWindow::breakLayout(QWidget *w)
1952 w = mainContainer();
1954 QWidgetList widgets;
1956 const QDesignerMetaDataBaseInterface *mdb = core()->metaDataBase();
1957 for (
auto *o : w->children()) {
1958 if (o->isWidgetType()) {
1959 auto *w =
static_cast<QWidget*>(o);
1961 widgets.push_back(w);
1965 auto *cmd =
new BreakLayoutCommand(
this);
1966 cmd->init(widgets, w);
1967 commandHistory()->push(cmd);
1968 clearSelection(
false);
1971void FormWindow::beginCommand(
const QString &description)
1973 m_undoStack.beginMacro(description);
1976void FormWindow::endCommand()
1978 m_undoStack.endMacro();
1981void FormWindow::raiseWidgets()
1983 QWidgetList widgets = selectedWidgets();
1984 simplifySelection(&widgets);
1986 if (widgets.isEmpty())
1989 beginCommand(tr(
"Raise widgets"));
1990 for (QWidget *widget : std::as_const(widgets)) {
1991 auto *cmd =
new RaiseWidgetCommand(
this);
1993 m_undoStack.push(cmd);
1998void FormWindow::lowerWidgets()
2000 QWidgetList widgets = selectedWidgets();
2001 simplifySelection(&widgets);
2003 if (widgets.isEmpty())
2006 beginCommand(tr(
"Lower widgets"));
2007 for (QWidget *widget : std::as_const(widgets)) {
2008 auto *cmd =
new LowerWidgetCommand(
this);
2010 m_undoStack.push(cmd);
2015bool FormWindow::handleMouseButtonDblClickEvent(QWidget *w, QWidget *managedWidget, QMouseEvent *e)
2017 if (debugFormWindow)
2018 qDebug() <<
"handleMouseButtonDblClickEvent:" << w <<
',' << managedWidget <<
"state=" << m_mouseState;
2024 if (isWidgetSelected(managedWidget))
2025 emit activated(managedWidget);
2027 m_mouseState = MouseDoubleClicked;
2032QMenu *FormWindow::initializePopupMenu(QWidget *managedWidget)
2034 if (!isManaged(managedWidget) || currentTool())
2041 const bool selected = isWidgetSelected(managedWidget);
2042 bool update =
false;
2044 update = setCurrentWidget(managedWidget);
2046 clearObjectInspectorSelection(m_core);
2047 clearSelection(
false);
2048 update = trySelectWidget(managedWidget,
true);
2049 raiseChildSelections(managedWidget);
2053 emitSelectionChanged();
2054 QMetaObject::invokeMethod(core()->formWindowManager(),
"slotUpdateActions");
2057 QWidget *contextMenuWidget =
nullptr;
2059 if (isMainContainer(managedWidget)) {
2060 contextMenuWidget = mainContainer();
2063 QWidget *realWidget = managedWidget;
2064 auto *mw = qobject_cast<QMainWindow*>(mainContainer());
2066 if (mw && mw->centralWidget() == realWidget) {
2067 contextMenuWidget = managedWidget;
2069 contextMenuWidget = realWidget;
2073 if (!contextMenuWidget)
2076 QMenu *contextMenu = createPopupMenu(contextMenuWidget);
2080 emit contextMenuRequested(contextMenu, contextMenuWidget);
2084bool FormWindow::handleContextMenu(QWidget *, QWidget *managedWidget, QContextMenuEvent *e)
2086 QMenu *contextMenu = initializePopupMenu(managedWidget);
2089 const QPoint globalPos = e->globalPos();
2090 m_contextMenuPosition = mapFromGlobal (globalPos);
2091 contextMenu->exec(globalPos);
2094 m_contextMenuPosition = QPoint(-1, -1);
2098bool FormWindow::setContents(QIODevice *dev, QString *errorMessageIn )
2100 QDesignerResource r(
this);
2101 std::unique_ptr<DomUI> ui(r.readUi(dev));
2104 *errorMessageIn = r.errorString();
2108 UpdateBlocker ub(
this);
2110 m_selection->clearSelectionPool();
2111 m_insertedWidgets.clear();
2115 clearMainContainer();
2116 m_undoStack.clear();
2119 QWidget *w = r.loadUi(ui.get(), formContainer());
2121 setMainContainer(w);
2125 *errorMessageIn = r.errorString();
2126 return w !=
nullptr;
2129bool FormWindow::setContents(
const QString &contents)
2131 QString errorMessage;
2132 QByteArray data = contents.toUtf8();
2134 const bool success = b.open(QIODevice::ReadOnly) && setContents(&b, &errorMessage);
2135 if (!success && !errorMessage.isEmpty())
2136 designerWarning(errorMessage);
2140void FormWindow::layoutContainer(QWidget *w,
int type)
2143 w = mainContainer();
2145 w = core()->widgetFactory()->containerOfWidget(w);
2148 QWidgetList widgets;
2149 for (
auto *o : w->children()) {
2150 if (o->isWidgetType() ) {
2151 auto *widget =
static_cast<QWidget*>(o);
2152 if (widget->isVisibleTo(
this) && isManaged(widget))
2153 widgets.append(widget);
2157 if (widgets.isEmpty())
2160 auto *cmd =
new LayoutCommand(
this);
2161 cmd->init(mainContainer(), widgets,
static_cast<LayoutInfo::Type>(type), w);
2162 clearSelection(
false);
2163 commandHistory()->push(cmd);
2166bool FormWindow::hasInsertedChildren(QWidget *widget)
const
2168 if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
2169 const int index = container->currentIndex();
2172 widget = container->widget(index);
2175 const QWidgetList l = widgets(widget);
2177 auto pred = [
this](QWidget *child) {
2178 return isManaged(child) && !LayoutInfo::isWidgetLaidout(core(), child) && child->isVisibleTo(
this);
2180 return std::any_of(l.cbegin(), l.cend(), pred);
2184void FormWindow::slotSelectWidget(QAction *a)
2186 if (
auto *w = qvariant_cast<QWidget*>(a->data()))
2187 selectSingleWidget(w);
2190void FormWindow::slotCleanChanged(
bool clean)
2196static inline QString objectNameOf(
const QWidget *w)
2198 if (
const auto *lw = qobject_cast<
const QLayoutWidget *>(w)) {
2199 const QLayout *layout = lw->layout();
2200 const QString rc = layout->objectName();
2204 return QString::fromUtf8(layout->metaObject()->className());
2206 return w->objectName();
2209QAction *FormWindow::createSelectAncestorSubMenu(QWidget *w)
2212 QWidgetList parents;
2213 QWidget *mc = mainContainer();
2214 for (QWidget *p = w->parentWidget(); p && p != mc; p = p->parentWidget())
2215 if (isManaged(p) && !isWidgetSelected(p))
2216 parents.push_back(p);
2217 if (parents.isEmpty())
2220 auto *menu =
new QMenu;
2221 auto *ag =
new QActionGroup(menu);
2222 QObject::connect(ag, &QActionGroup::triggered,
this, &FormWindow::slotSelectWidget);
2223 for (
auto *w : std::as_const(parents)) {
2224 QAction *a = ag->addAction(objectNameOf(w));
2225 a->setData(QVariant::fromValue(w));
2228 auto *ma =
new QAction(tr(
"Select Ancestor"),
nullptr);
2233QMenu *FormWindow::createPopupMenu(QWidget *w)
2235 QMenu *popup = createExtensionTaskMenu(
this, w,
true);
2237 popup =
new QMenu(w);
2241 QDesignerFormWindowManagerInterface *manager = core()->formWindowManager();
2242 const bool isFormWindow = qobject_cast<
const FormWindow*>(w);
2245 if (!isFormWindow) {
2246 if (
auto *stackedWidget = qobject_cast<QStackedWidget*>(w)) {
2247 QStackedWidgetEventFilter::addStackedWidgetContextMenuActions(stackedWidget, popup);
2248 }
else if (
auto *tabWidget = qobject_cast<QTabWidget*>(w)) {
2249 QTabWidgetEventFilter::addTabWidgetContextMenuActions(tabWidget, popup);
2250 }
else if (
auto *toolBox = qobject_cast<QToolBox*>(w)) {
2251 QToolBoxHelper::addToolBoxContextMenuActions(toolBox, popup);
2254 if (manager->action(QDesignerFormWindowManagerInterface::LowerAction)->isEnabled()) {
2255 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::LowerAction));
2256 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::RaiseAction));
2257 popup->addSeparator();
2259#if QT_CONFIG(clipboard)
2260 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::CutAction));
2261 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::CopyAction));
2265#if QT_CONFIG(clipboard)
2266 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::PasteAction));
2269 if (QAction *selectAncestorAction = createSelectAncestorSubMenu(w))
2270 popup->addAction(selectAncestorAction);
2271 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::SelectAllAction));
2273 if (!isFormWindow) {
2274 popup->addAction(manager->action(QDesignerFormWindowManagerInterface::DeleteAction));
2277 popup->addSeparator();
2278 QMenu *layoutMenu = popup->addMenu(tr(
"Lay out"));
2279 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::AdjustSizeAction));
2280 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::HorizontalLayoutAction));
2281 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::VerticalLayoutAction));
2282 if (!isFormWindow) {
2283 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::SplitHorizontalAction));
2284 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::SplitVerticalAction));
2286 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::GridLayoutAction));
2287 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::FormLayoutAction));
2288 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::BreakLayoutAction));
2289 layoutMenu->addAction(manager->action(QDesignerFormWindowManagerInterface::SimplifyLayoutAction));
2294void FormWindow::resizeEvent(QResizeEvent *e)
2296 m_geometryChangedTimer->start(10);
2298 QWidget::resizeEvent(e);
2302
2303
2304
2305
2306
2307QPoint FormWindow::mapToForm(
const QWidget *w, QPoint pos)
const
2310 const QWidget* i = w;
2311 while (i && !i->isWindow() && !isMainContainer(i)) {
2312 p = i->mapToParent(p);
2313 i = i->parentWidget();
2316 return mapFromGlobal(w->mapToGlobal(pos));
2319bool FormWindow::canBeBuddy(QWidget *w)
const
2321 if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), w)) {
2322 const int index = sheet->indexOf(u"focusPolicy"_s);
2325 const Qt::FocusPolicy q =
static_cast<Qt::FocusPolicy>(Utils::valueOf(sheet->property(index), &ok));
2326 return ok && q != Qt::NoFocus;
2333QWidget *FormWindow::findContainer(QWidget *w,
bool excludeLayout)
const
2335 if (!isChildOf(w,
this)
2336 ||
const_cast<
const QWidget *>(w) ==
this)
2339 QDesignerWidgetFactoryInterface *widgetFactory = core()->widgetFactory();
2340 QDesignerWidgetDataBaseInterface *widgetDataBase = core()->widgetDataBase();
2341 QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase();
2343 QWidget *container = widgetFactory->containerOfWidget(mainContainer());
2344 if (!isMainContainer(w)) {
2346 if (qobject_cast<InvisibleWidget*>(w) || !metaDataBase->item(w)) {
2347 w = w->parentWidget();
2351 const bool isContainer = widgetDataBase->isContainer(w,
true) || w == mainContainer();
2353 if (!isContainer || (excludeLayout && qobject_cast<QLayoutWidget*>(w))) {
2354 w = w->parentWidget();
2365void FormWindow::simplifySelection(QWidgetList *sel)
const
2367 if (sel->size() < 2)
2374 QWidget *mainC = mainContainer();
2375 if (sel->contains(mainC)) {
2377 sel->push_back(mainC);
2380 QWidgetList toBeRemoved;
2381 toBeRemoved.reserve(sel->size());
2382 for (
auto *child : std::as_const(*sel)) {
2383 for (QWidget *w = child;
true ; ) {
2384 QWidget *parent = w->parentWidget();
2385 if (!parent || parent == mainC)
2387 if (sel->contains(parent)) {
2388 toBeRemoved.append(child);
2396 for (
auto *r : std::as_const(toBeRemoved))
2400FormWindow *FormWindow::findFormWindow(QWidget *w)
2402 return qobject_cast<FormWindow*>(QDesignerFormWindowInterface::findFormWindow(w));
2405bool FormWindow::isDirty()
const
2407 return !m_undoStack.isClean();
2410void FormWindow::setDirty(
bool dirty)
2413 m_undoStack.resetClean();
2415 m_undoStack.setClean();
2418QWidget *FormWindow::containerAt(
const QPoint &pos)
2420 QWidget *widget = widgetAt(pos);
2421 return findContainer(widget,
true);
2424static QWidget *childAt_SkipDropLine(QWidget *w, QPoint pos)
2426 const QObjectList &child_list = w->children();
2427 for (
auto i = child_list.size() - 1; i >= 0; --i) {
2428 QObject *child_obj = child_list.at(i);
2429 if (qobject_cast<WidgetHandle*>(child_obj) !=
nullptr)
2431 QWidget *child = qobject_cast<QWidget*>(child_obj);
2432 if (!child || child->isWindow() || !child->isVisible() ||
2433 !child->geometry().contains(pos) || child->testAttribute(Qt::WA_TransparentForMouseEvents))
2435 const QPoint childPos = child->mapFromParent(pos);
2436 if (QWidget *res = childAt_SkipDropLine(child, childPos))
2438 if (child->testAttribute(Qt::WA_MouseNoMask) || child->mask().contains(pos)
2439 || child->mask().isEmpty())
2446QWidget *FormWindow::widgetAt(
const QPoint &pos)
2448 QWidget *w = childAt(pos);
2449 if (qobject_cast<
const WidgetHandle*>(w) != 0)
2450 w = childAt_SkipDropLine(
this, pos);
2451 return (w ==
nullptr || w == formContainer()) ?
this : w;
2454void FormWindow::highlightWidget(QWidget *widget,
const QPoint &pos, HighlightMode mode)
2458 if (
auto *mainWindow = qobject_cast<QMainWindow*> (widget))
2459 widget = mainWindow->centralWidget();
2461 QWidget *container = findContainer(widget,
false);
2463 if (container ==
nullptr || core()->metaDataBase()->item(container) ==
nullptr)
2466 if (QDesignerActionProviderExtension *g = qt_extension<QDesignerActionProviderExtension*>(core()->extensionManager(), container)) {
2467 if (mode == Restore) {
2468 g->adjustIndicator(QPoint());
2470 const QPoint pt = widget->mapTo(container, pos);
2471 g->adjustIndicator(pt);
2473 }
else if (QDesignerLayoutDecorationExtension *g = qt_extension<QDesignerLayoutDecorationExtension*>(core()->extensionManager(), container)) {
2474 if (mode == Restore) {
2475 g->adjustIndicator(QPoint(), -1);
2477 const QPoint pt = widget->mapTo(container, pos);
2478 const int index = g->findItemAt(pt);
2479 g->adjustIndicator(pt, index);
2483 auto *mw = qobject_cast<QMainWindow*> (container);
2484 if (container == mainContainer() || (mw && mw->centralWidget() && mw->centralWidget() == container))
2487 if (mode == Restore) {
2488 const auto pit = m_palettesBeforeHighlight.find(container);
2489 if (pit != m_palettesBeforeHighlight.end()) {
2490 container->setPalette(pit.value().first);
2491 container->setAutoFillBackground(pit.value().second);
2492 m_palettesBeforeHighlight.erase(pit);
2495 QPalette p = container->palette();
2496 if (!m_palettesBeforeHighlight.contains(container)) {
2497 PaletteAndFill paletteAndFill;
2498 if (container->testAttribute(Qt::WA_SetPalette))
2499 paletteAndFill.first = p;
2500 paletteAndFill.second = container->autoFillBackground();
2501 m_palettesBeforeHighlight.insert(container, paletteAndFill);
2504 p.setColor(backgroundRole(), p.midlight().color());
2505 container->setPalette(p);
2506 container->setAutoFillBackground(
true);
2510QWidgetList FormWindow::widgets(QWidget *widget)
const
2512 if (widget->children().isEmpty())
2515 for (QObject *o : widget->children()) {
2516 if (o->isWidgetType()) {
2517 QWidget *w = qobject_cast<QWidget*>(o);
2525int FormWindow::toolCount()
const
2527 return m_widgetStack->count();
2530QDesignerFormWindowToolInterface *FormWindow::tool(
int index)
const
2532 return m_widgetStack->tool(index);
2535void FormWindow::registerTool(QDesignerFormWindowToolInterface *tool)
2537 Q_ASSERT(tool !=
nullptr);
2539 m_widgetStack->addTool(tool);
2541 if (m_mainContainer)
2542 m_mainContainer->update();
2545void FormWindow::setCurrentTool(
int index)
2547 m_widgetStack->setCurrentTool(index);
2550int FormWindow::currentTool()
const
2552 return m_widgetStack->currentIndex();
2555bool FormWindow::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event)
2557 if (m_widgetStack ==
nullptr)
2560 QDesignerFormWindowToolInterface *tool = m_widgetStack->currentTool();
2561 if (tool ==
nullptr)
2564 return tool->handleEvent(widget, managedWidget, event);
2567void FormWindow::initializeCoreTools()
2569 m_widgetEditor =
new WidgetEditorTool(
this);
2570 this->FormWindow::registerTool(m_widgetEditor);
2573void FormWindow::checkSelection()
2575 m_checkSelectionTimer->start(0);
2578void FormWindow::checkSelectionNow()
2580 m_checkSelectionTimer->stop();
2582 const QWidgetList &sel = selectedWidgets();
2583 for (QWidget *widget : sel) {
2584 updateSelection(widget);
2586 if (LayoutInfo::layoutType(core(), widget) != LayoutInfo::NoLayout)
2587 updateChildSelections(widget);
2591QString FormWindow::author()
const
2596QString FormWindow::comment()
const
2601void FormWindow::setAuthor(
const QString &author)
2606void FormWindow::setComment(
const QString &comment)
2608 m_comment = comment;
2611void FormWindow::editWidgets()
2613 m_widgetEditor->action()->trigger();
2616QStringList FormWindow::resourceFiles()
const
2618 return m_resourceFiles;
2621void FormWindow::addResourceFile(
const QString &path)
2623 if (!m_resourceFiles.contains(path)) {
2624 m_resourceFiles.append(path);
2626 emit resourceFilesChanged();
2630void FormWindow::removeResourceFile(
const QString &path)
2632 if (m_resourceFiles.removeAll(path) > 0) {
2634 emit resourceFilesChanged();
2638bool FormWindow::blockSelectionChanged(
bool b)
2640 const bool blocked = m_blockSelectionChanged;
2641 m_blockSelectionChanged = b;
2645void FormWindow::editContents()
2647 const QWidgetList sel = selectedWidgets();
2648 if (sel.size() == 1) {
2649 QWidget *widget = sel.first();
2651 if (QAction *a = preferredEditAction(core(), widget))
2656void FormWindow::dragWidgetWithinForm(QWidget *widget, QRect targetGeometry, QWidget *targetContainer)
2658 const bool fromLayout = canDragWidgetInLayout(core(), widget);
2659 const QDesignerLayoutDecorationExtension *targetDeco = qt_extension<QDesignerLayoutDecorationExtension*>(core()->extensionManager(), targetContainer);
2660 const bool toLayout = targetDeco !=
nullptr;
2666 auto *cmd =
new DeleteWidgetCommand(
this);
2667 unsigned deleteFlags = DeleteWidgetCommand::DoNotUnmanage;
2669 deleteFlags |= DeleteWidgetCommand::DoNotSimplifyLayout;
2670 cmd->init(widget, deleteFlags);
2671 commandHistory()->push(cmd);
2676 insertWidget(widget, targetGeometry, targetContainer,
true);
2679 if (targetContainer != widget->parent()) {
2680 auto *cmd =
new ReparentWidgetCommand(
this);
2681 cmd->init(widget, targetContainer );
2682 commandHistory()->push(cmd);
2684 resizeWidget(widget, targetGeometry);
2685 selectWidget(widget,
true);
2690static Qt::DockWidgetArea detectDropArea(QMainWindow *mainWindow, QRect area, QPoint drop)
2692 QPoint offset = area.topLeft();
2694 rect.moveTopLeft(QPoint(0, 0));
2695 QPoint point = drop - offset;
2696 const int x = point.x();
2697 const int y = point.y();
2698 const int w = rect.width();
2699 const int h = rect.height();
2701 if (rect.contains(point)) {
2702 bool topRight =
false;
2703 bool topLeft =
false;
2706 if (w * y < h * (w - x))
2709 if (topRight && topLeft)
2710 return Qt::TopDockWidgetArea;
2711 if (topRight && !topLeft)
2712 return Qt::RightDockWidgetArea;
2713 if (!topRight && topLeft)
2714 return Qt::LeftDockWidgetArea;
2715 return Qt::BottomDockWidgetArea;
2720 return mainWindow->corner(Qt::TopLeftCorner);
2721 return y > h ? mainWindow->corner(Qt::BottomLeftCorner) : Qt::LeftDockWidgetArea;
2725 return mainWindow->corner(Qt::TopRightCorner);
2726 return y > h ? mainWindow->corner(Qt::BottomRightCorner) : Qt::RightDockWidgetArea;
2728 return y < 0 ? Qt::TopDockWidgetArea :Qt::LeftDockWidgetArea;
2731bool FormWindow::dropDockWidget(QDesignerDnDItemInterface *item, QPoint global_mouse_pos)
2733 DomUI *dom_ui = item->domUi();
2735 auto *mw = qobject_cast<QMainWindow *>(mainContainer());
2739 QDesignerResource resource(
this);
2740 const FormBuilderClipboard clipboard = resource.paste(dom_ui, mw);
2741 if (clipboard.m_widgets.size() != 1)
2744 QWidget *centralWidget = mw->centralWidget();
2745 QPoint localPos = centralWidget->mapFromGlobal(global_mouse_pos);
2746 const QRect centralWidgetAreaRect = centralWidget->rect();
2747 Qt::DockWidgetArea area = detectDropArea(mw, centralWidgetAreaRect, localPos);
2749 beginCommand(tr(
"Drop widget"));
2751 clearSelection(
false);
2752 highlightWidget(mw, QPoint(0, 0), FormWindow::Restore);
2754 QWidget *widget = clipboard.m_widgets.first();
2756 insertWidget(widget, QRect(0, 0, 1, 1), mw);
2758 selectWidget(widget,
true);
2759 mw->setFocus(Qt::MouseFocusReason);
2761 core()->formWindowManager()->setActiveFormWindow(
this);
2762 mainContainer()->activateWindow();
2764 auto *propertySheet = qobject_cast<QDesignerPropertySheetExtension*>(m_core->extensionManager()->extension(widget, Q_TYPEID(QDesignerPropertySheetExtension)));
2765 if (propertySheet) {
2766 const QString dockWidgetAreaName = u"dockWidgetArea"_s;
2767 auto e = qvariant_cast<PropertySheetEnumValue>(propertySheet->property(propertySheet->indexOf(dockWidgetAreaName)));
2771 auto *cmd =
new SetPropertyCommand(
this);
2772 cmd->init(widget, dockWidgetAreaName, v);
2773 m_undoStack.push(cmd);
2780bool FormWindow::dropWidgets(
const QList<QDesignerDnDItemInterface*> &item_list, QWidget *target,
2781 const QPoint &global_mouse_pos)
2784 QWidget *parent = target;
2785 if (parent ==
nullptr)
2786 parent = mainContainer();
2789 if (
auto *main_win = qobject_cast<QMainWindow*>(target)) {
2790 if (!main_win->centralWidget()) {
2791 designerWarning(tr(
"A QMainWindow-based form does not contain a central widget."));
2794 const QPoint main_win_pos = main_win->mapFromGlobal(global_mouse_pos);
2795 const QRect central_wgt_geo = main_win->centralWidget()->geometry();
2796 if (!central_wgt_geo.contains(main_win_pos))
2800 QWidget *container = findContainer(parent,
false);
2801 if (container ==
nullptr)
2804 beginCommand(tr(
"Drop widget"));
2806 clearSelection(
false);
2807 highlightWidget(target, target->mapFromGlobal(global_mouse_pos), FormWindow::Restore);
2810 QDesignerDnDItemInterface *current =
nullptr;
2811 QDesignerFormWindowCursorInterface *c = cursor();
2812 for (QDesignerDnDItemInterface *item : std::as_const(item_list)) {
2813 QWidget *w = item->widget();
2816 if (c->current() == w) {
2822 QRect geom = current->decoration()->geometry();
2823 QPoint topLeft = container->mapFromGlobal(geom.topLeft());
2824 offset = designerGrid().snapPoint(topLeft) - topLeft;
2827 for (QDesignerDnDItemInterface *item : std::as_const(item_list)) {
2828 DomUI *dom_ui = item->domUi();
2829 QRect geometry = item->decoration()->geometry();
2830 Q_ASSERT(dom_ui !=
nullptr);
2832 geometry.moveTopLeft(container->mapFromGlobal(geometry.topLeft()) + offset);
2833 if (item->type() == QDesignerDnDItemInterface::CopyDrop) {
2834 QWidget *widget = createWidget(dom_ui, geometry, parent);
2839 selectWidget(widget,
true);
2840 mainContainer()->setFocus(Qt::MouseFocusReason);
2842 QWidget *widget = item->widget();
2843 Q_ASSERT(widget !=
nullptr);
2844 QDesignerFormWindowInterface *dest = findFormWindow(widget);
2846 dragWidgetWithinForm(widget, geometry, container);
2848 auto *source = qobject_cast<FormWindow*>(item->source());
2849 Q_ASSERT(source !=
nullptr);
2851 source->deleteWidgetList(QWidgetList() << widget);
2852 auto *new_widget = createWidget(dom_ui, geometry, parent);
2854 selectWidget(new_widget,
true);
2859 core()->formWindowManager()->setActiveFormWindow(
this);
2860 mainContainer()->activateWindow();
2865QDir FormWindow::absoluteDir()
const
2867 if (fileName().isEmpty())
2868 return QDir::current();
2870 return QFileInfo(fileName()).absoluteDir();
2873void FormWindow::layoutDefault(
int *margin,
int *spacing)
2875 *margin = m_defaultMargin;
2876 *spacing = m_defaultSpacing;
2879void FormWindow::setLayoutDefault(
int margin,
int spacing)
2881 m_defaultMargin = margin;
2882 m_defaultSpacing = spacing;
2885void FormWindow::layoutFunction(QString *margin, QString *spacing)
2887 *margin = m_marginFunction;
2888 *spacing = m_spacingFunction;
2891void FormWindow::setLayoutFunction(
const QString &margin,
const QString &spacing)
2893 m_marginFunction = margin;
2894 m_spacingFunction = spacing;
2897QString FormWindow::pixmapFunction()
const
2899 return m_pixmapFunction;
2902void FormWindow::setPixmapFunction(
const QString &pixmapFunction)
2904 m_pixmapFunction = pixmapFunction;
2907QStringList FormWindow::includeHints()
const
2909 return m_includeHints;
2912void FormWindow::setIncludeHints(
const QStringList &includeHints)
2914 m_includeHints = includeHints;
2917QString FormWindow::exportMacro()
const
2919 return m_exportMacro;
2922void FormWindow::setExportMacro(
const QString &exportMacro)
2924 m_exportMacro = exportMacro;
2927QEditorFormBuilder *FormWindow::createFormBuilder()
2929 return new QDesignerResource(
this);
2932QWidget *FormWindow::formContainer()
const
2934 return m_widgetStack->formContainer();
2937QUndoStack *FormWindow::commandHistory()
const
2939 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