Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
abstractintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant reason:default
4
13#include "propertysheet.h"
16
17#include <qtresourcemodel_p.h>
18
19#include <qdesigner_propertycommand_p.h>
20#include <qdesigner_propertyeditor_p.h>
21#include <qdesigner_objectinspector_p.h>
22#include <qdesigner_utils_p.h>
23#include <widgetdatabase_p.h>
24#include <pluginmanager_p.h>
25#include <widgetfactory_p.h>
26#include <qdesigner_widgetbox_p.h>
27#include <qtgradientmanager_p.h>
28#include <qtgradientutils_p.h>
29#include <qtresourcemodel_p.h>
30
31#include <QtCore/qvariant.h>
32#include <QtCore/qfile.h>
33#include <QtCore/qdir.h>
34#include <QtCore/qlibraryinfo.h>
35
36#include <QtCore/qdebug.h>
37
39
40using namespace Qt::StringLiterals;
41
42/*!
43 \class QDesignerIntegrationInterface
44
45 \brief The QDesignerIntegrationInterface glues together parts of \QD
46 and allows for overwriting functionality for IDE integration.
47
48 \internal
49
50 \inmodule QtDesigner
51
52 \sa QDesignerFormEditorInterface
53*/
54
55/*!
56 \enum QDesignerIntegrationInterface::ResourceFileWatcherBehaviour
57
58 \internal
59
60 This enum describes if and how resource files are watched.
61
62 \value NoResourceFileWatcher Do not watch for changes
63 \value ReloadResourceFileSilently Reload files silently.
64 \value PromptToReloadResourceFile Prompt the user to reload.
65*/
66
67/*!
68 \enum QDesignerIntegrationInterface::FeatureFlag
69
70 \internal
71
72 This enum describes the features that are available and can be
73 controlled by the integration.
74
75 \value ResourceEditorFeature The resource editor is enabled.
76 \value SlotNavigationFeature Provide context menu entry offering 'Go to slot'.
77 \value DefaultWidgetActionFeature Trigger the preferred action of
78 QDesignerTaskMenuExtension when widget is activated.
79 \value DefaultFeature Default for \QD
80
81 \sa hasFeature(), features()
82*/
83
84/*!
85 \property QDesignerIntegrationInterface::headerSuffix
86
87 Returns the suffix of the header of promoted widgets.
88*/
89
90/*!
91 \property QDesignerIntegrationInterface::headerLowercase
92
93 Returns whether headers of promoted widgets should be lower-cased (as the user types the class name).
94*/
95
96/*!
97 \property QDesignerIntegrationInterface::qtVersion
98
99 Determines the Qt version used when writing out forms.
100
101 \since 6.9
102*/
103
104/*!
105 \fn virtual void QDesignerIntegrationInterface::updateSelection()
106
107 \brief Sets the selected widget of the form window in various components.
108
109 \internal
110
111 In IDE integrations, the method can be overwritten to move the selection handles
112 of the form's main window, should it be selected.
113*/
114
115/*!
116 \fn virtual QWidget *QDesignerIntegrationInterface::containerWindow(QWidget *widget) const
117
118 \brief Returns the outer window containing a form for applying main container geometries.
119
120 \internal
121
122 Should be implemented by IDE integrations.
123*/
124
125/*!
126 \fn virtual QDesignerResourceBrowserInterface *QDesignerIntegrationInterface::createResourceBrowser(QWidget *parent = 0)
127
128 \brief Creates a resource browser depending on IDE integration.
129
130 \internal
131
132 \note Language integration takes precedence.
133*/
134
135/*!
136 \fn virtual void QDesignerIntegrationInterface::updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling)
137
138 \brief Triggered by the property editor to update a property value.
139
140 \internal
141
142 If a different property editor is used, it should invoke this function.
143*/
144
145/*!
146 \fn virtual void QDesignerIntegrationInterface::updateProperty(const QString &name, const QVariant &value)
147
148 \brief Triggered by the property editor to update a property value without subproperty handling.
149
150 \internal
151
152 If a different property editor is used, it should invoke this function.
153*/
154
155/*!
156 \fn virtual void QDesignerIntegrationInterface::resetProperty(const QString &name)
157
158 \brief Triggered by the property editor to reset a property value.
159
160 \internal
161
162 If a different property editor is used, it should invoke this function.
163*/
164
165/*!
166 \fn virtual void QDesignerIntegrationInterface::addDynamicProperty(const QString &name, const QVariant &value)
167
168 \brief Triggered by the property editor to add a dynamic property value.
169
170 \internal
171
172 If a different property editor is used, it should invoke this function.
173*/
174
175/*!
176 \fn virtual void QDesignerIntegrationInterface::removeDynamicProperty(const QString &name)
177
178 \brief Triggered by the property editor to remove a dynamic property.
179
180 \internal
181
182 If a different property editor is used, it should invoke this function.
183*/
184
185/*!
186 \fn virtual void QDesignerIntegrationInterface::updateActiveFormWindow(QDesignerFormWindowInterface *formWindow)
187
188 \brief Sets up the active form window.
189
190 \internal
191*/
192
193/*!
194 \fn virtual void QDesignerIntegrationInterface::setupFormWindow(QDesignerFormWindowInterface *formWindow)
195
196 \brief Sets up the new form window.
197
198 \internal
199*/
200
201/*!
202 \fn virtual void QDesignerIntegrationInterface::updateCustomWidgetPlugins()
203
204 \brief Triggers a reload of the custom widget plugins.
205
206 \internal
207*/
208
210{
211public:
212 QDesignerIntegrationInterfacePrivate(QDesignerFormEditorInterface *core) :
213 m_core(core) {}
214
215 QDesignerFormEditorInterface *m_core;
217};
218
219QDesignerIntegrationInterface::QDesignerIntegrationInterface(QDesignerFormEditorInterface *core, QObject *parent)
220 : QObject(parent), d(new QDesignerIntegrationInterfacePrivate(core))
221{
222 core->setIntegration(this);
223}
224
225QDesignerIntegrationInterface::~QDesignerIntegrationInterface() = default;
226
227QDesignerFormEditorInterface *QDesignerIntegrationInterface::core() const
228{
229 return d->m_core;
230}
231
232bool QDesignerIntegrationInterface::hasFeature(Feature f) const
233{
234 return (features() & f) != 0;
235}
236
237QVersionNumber QDesignerIntegrationInterface::qtVersion() const
238{
239 return d->qtVersion;
240}
241
242void QDesignerIntegrationInterface::setQtVersion(const QVersionNumber &qtVersion)
243{
244 d->qtVersion = qtVersion;
245}
246
247void QDesignerIntegrationInterface::emitObjectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, const QString &newName, const QString &oldName)
248{
249 emit objectNameChanged(formWindow, object, newName, oldName);
250}
251
252void QDesignerIntegrationInterface::emitNavigateToSlot(const QString &objectName,
253 const QString &signalSignature,
254 const QStringList &parameterNames)
255{
256 emit navigateToSlot(objectName, signalSignature, parameterNames);
257}
258
259void QDesignerIntegrationInterface::emitNavigateToSlot(const QString &slotSignature)
260{
261 emit navigateToSlot(slotSignature);
262}
263
264void QDesignerIntegrationInterface::emitHelpRequested(const QString &manual, const QString &document)
265{
266 emit helpRequested(manual, document);
267}
268
269/*!
270 \class QDesignerIntegration
271
272 \brief The QDesignerIntegration class is \QD's implementation of
273 QDesignerIntegrationInterface.
274
275 \internal
276
277 \inmodule QtDesigner
278
279 IDE integrations should register classes derived from QDesignerIntegration
280 with QDesignerFormEditorInterface.
281*/
282
283namespace qdesigner_internal {
284
286public:
287 explicit QDesignerIntegrationPrivate(QDesignerIntegration *qq);
288
290
291 // Load plugins into widget database and factory.
292 static void initializePlugins(QDesignerFormEditorInterface *formEditor);
293
294 QString contextHelpId() const;
295
296 void updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling);
297 void resetProperty(const QString &name);
298 void addDynamicProperty(const QString &name, const QVariant &value);
299 void removeDynamicProperty(const QString &name);
300
301 void setupFormWindow(QDesignerFormWindowInterface *formWindow);
304
306 void getSelection(qdesigner_internal::Selection &s);
308
309 QDesignerIntegration *q;
316};
317
327
329{
330 //
331 // integrate the `Form Editor component'
332 //
333
334 // Extensions
335 QDesignerFormEditorInterface *core = q->core();
336 if (QDesignerPropertyEditor *designerPropertyEditor= qobject_cast<QDesignerPropertyEditor *>(core->propertyEditor())) {
337 QObject::connect(designerPropertyEditor, &QDesignerPropertyEditor::propertyValueChanged,
338 q, QOverload<const QString &, const QVariant &, bool>::of(&QDesignerIntegration::updateProperty));
339 QObject::connect(designerPropertyEditor, &QDesignerPropertyEditor::resetProperty,
340 q, &QDesignerIntegration::resetProperty);
341 QObject::connect(designerPropertyEditor, &QDesignerPropertyEditor::addDynamicProperty,
342 q, &QDesignerIntegration::addDynamicProperty);
343 QObject::connect(designerPropertyEditor, &QDesignerPropertyEditor::removeDynamicProperty,
344 q, &QDesignerIntegration::removeDynamicProperty);
345 }
346
347 QObject::connect(core->formWindowManager(), &QDesignerFormWindowManagerInterface::formWindowAdded,
348 q, &QDesignerIntegrationInterface::setupFormWindow);
349
350 QObject::connect(core->formWindowManager(), &QDesignerFormWindowManagerInterface::activeFormWindowChanged,
351 q, &QDesignerIntegrationInterface::updateActiveFormWindow);
352
353 m_gradientManager = new QtGradientManager(q);
354 core->setGradientManager(m_gradientManager);
355
356 const QString gradientsFile = u"/gradients.xml"_s;
357 m_gradientsPath = dataDirectory() + gradientsFile;
358
359 // Migrate from legacy to standard data directory in Qt 7
360 // ### FIXME Qt 8: Remove (QTBUG-96005)
361#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
362 const QString source = QFileInfo::exists(m_gradientsPath)
363 ? m_gradientsPath : legacyDataDirectory() + gradientsFile;
364#else
365 const QString source = m_gradientsPath;
366#endif
367
368 QFile f(source);
369 if (f.open(QIODevice::ReadOnly)) {
370 QtGradientUtils::restoreState(m_gradientManager, QString::fromLatin1(f.readAll()));
371 f.close();
372 } else {
373 QFile defaultGradients(u":/qt-project.org/designer/defaultgradients.xml"_s);
374 if (defaultGradients.open(QIODevice::ReadOnly)) {
375 QtGradientUtils::restoreState(m_gradientManager, QString::fromLatin1(defaultGradients.readAll()));
376 defaultGradients.close();
377 }
378 }
379
380 if (WidgetDataBase *widgetDataBase = qobject_cast<WidgetDataBase*>(core->widgetDataBase()))
381 widgetDataBase->grabStandardWidgetBoxIcons();
382}
383
384void QDesignerIntegrationPrivate::updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling)
385{
386 QDesignerFormWindowInterface *formWindow = q->core()->formWindowManager()->activeFormWindow();
387 if (!formWindow)
388 return;
389
390 Selection selection;
391 getSelection(selection);
392 if (selection.empty())
393 return;
394
395 SetPropertyCommand *cmd = new SetPropertyCommand(formWindow);
396 // find a reference object to compare to and to find the right group
397 if (cmd->init(selection.selection(), name, value, propertyEditorObject(), enableSubPropertyHandling)) {
398 formWindow->commandHistory()->push(cmd);
399 } else {
400 delete cmd;
401 qDebug() << "Unable to set property " << name << '.';
402 }
403}
404
406{
407 QDesignerFormWindowInterface *formWindow = q->core()->formWindowManager()->activeFormWindow();
408 if (!formWindow)
409 return;
410
411 Selection selection;
412 getSelection(selection);
413 if (selection.empty())
414 return;
415
416 ResetPropertyCommand *cmd = new ResetPropertyCommand(formWindow);
417 // find a reference object to find the right group
418 if (cmd->init(selection.selection(), name, propertyEditorObject())) {
419 formWindow->commandHistory()->push(cmd);
420 } else {
421 delete cmd;
422 qDebug() << "** WARNING Unable to reset property " << name << '.';
423 }
424}
425
426void QDesignerIntegrationPrivate::addDynamicProperty(const QString &name, const QVariant &value)
427{
428 QDesignerFormWindowInterface *formWindow = q->core()->formWindowManager()->activeFormWindow();
429 if (!formWindow)
430 return;
431
432 Selection selection;
433 getSelection(selection);
434 if (selection.empty())
435 return;
436
437 AddDynamicPropertyCommand *cmd = new AddDynamicPropertyCommand(formWindow);
438 if (cmd->init(selection.selection(), propertyEditorObject(), name, value)) {
439 formWindow->commandHistory()->push(cmd);
440 } else {
441 delete cmd;
442 qDebug() << "** WARNING Unable to add dynamic property " << name << '.';
443 }
444}
445
447{
448 QDesignerFormWindowInterface *formWindow = q->core()->formWindowManager()->activeFormWindow();
449 if (!formWindow)
450 return;
451
452 Selection selection;
453 getSelection(selection);
454 if (selection.empty())
455 return;
456
457 RemoveDynamicPropertyCommand *cmd = new RemoveDynamicPropertyCommand(formWindow);
458 if (cmd->init(selection.selection(), propertyEditorObject(), name)) {
459 formWindow->commandHistory()->push(cmd);
460 } else {
461 delete cmd;
462 qDebug() << "** WARNING Unable to remove dynamic property " << name << '.';
463 }
464
465}
466
467void QDesignerIntegrationPrivate::setupFormWindow(QDesignerFormWindowInterface *formWindow)
468{
469 QObject::connect(formWindow, &QDesignerFormWindowInterface::selectionChanged,
470 q, &QDesignerIntegrationInterface::updateSelection);
471}
472
474{
475 QDesignerFormEditorInterface *core = q->core();
476 QDesignerFormWindowInterface *formWindow = core->formWindowManager()->activeFormWindow();
477 QWidget *selection = nullptr;
478
479 if (formWindow) {
480 selection = formWindow->cursor()->current();
481 }
482
483 if (QDesignerActionEditorInterface *actionEditor = core->actionEditor())
484 actionEditor->setFormWindow(formWindow);
485
486 if (QDesignerPropertyEditorInterface *propertyEditor = core->propertyEditor())
487 propertyEditor->setObject(selection);
488
489 if (QDesignerObjectInspectorInterface *objectInspector = core->objectInspector())
490 objectInspector->setFormWindow(formWindow);
491
492}
493
495{
496 // Find the parent window to apply a geometry to.
497 while (widget) {
498 if (widget->isWindow())
499 break;
500 if (!qstrcmp(widget->metaObject()->className(), "QMdiSubWindow"))
501 break;
502
503 widget = widget->parentWidget();
504 }
505
506 return widget;
507}
508
510{
512 // Get multiselection from object inspector
515 // Action editor puts actions that are not on the form yet
516 // into the property editor only.
517 if (s.empty())
520
521 } else {
522 // Just in case someone plugs in an old-style object inspector: Emulate selection
523 s.clear();
525 if (!formWindow)
526 return;
527
529 if (object->isWidgetType()) {
530 QWidget *widget = static_cast<QWidget*>(object);
534 } else {
536 }
537 } else {
539 }
540 }
541}
542
544{
545 if (QDesignerPropertyEditorInterface *propertyEditor = q->core()->propertyEditor())
546 return propertyEditor->object();
547 return nullptr;
548}
549
550// Load plugins into widget database and factory.
551void QDesignerIntegrationPrivate::initializePlugins(QDesignerFormEditorInterface *formEditor)
552{
553 // load the plugins
554 qdesigner_internal::WidgetDataBase *widgetDataBase = qobject_cast<qdesigner_internal::WidgetDataBase*>(formEditor->widgetDataBase());
555 if (widgetDataBase) {
556 widgetDataBase->loadPlugins();
557 }
558
559 if (qdesigner_internal::WidgetFactory *widgetFactory = qobject_cast<qdesigner_internal::WidgetFactory*>(formEditor->widgetFactory())) {
560 widgetFactory->loadPlugins();
561 }
562
563 if (widgetDataBase) {
564 widgetDataBase->grabDefaultPropertyValues();
565 }
566}
567
569{
570 QDesignerFormEditorInterface *formEditor = q->core();
571 if (QDesignerPluginManager *pm = formEditor->pluginManager())
572 pm->registerNewPlugins();
573
574 initializePlugins(formEditor);
575
576 // Do not just reload the last file as the WidgetBox merges the compiled-in resources
577 // and $HOME/.designer/widgetbox.xml. This would also double the scratchpad.
578 if (QDesignerWidgetBox *wb = qobject_cast<QDesignerWidgetBox*>(formEditor->widgetBox())) {
579 const QDesignerWidgetBox::LoadMode oldLoadMode = wb->loadMode();
580 wb->setLoadMode(QDesignerWidgetBox::LoadCustomWidgetsOnly);
581 wb->load();
582 wb->setLoadMode(oldLoadMode);
583 }
584}
585
586static QString fixHelpClassName(const QString &className)
587{
588 // ### generalize using the Widget Data Base
589 if (className == "Line"_L1)
590 return u"QFrame"_s;
591 if (className == "Spacer"_L1)
592 return u"QSpacerItem"_s;
593 if (className == "QLayoutWidget"_L1)
594 return u"QLayout"_s;
595 return className;
596}
597
598// Return class in which the property is defined
599static QString classForProperty(QDesignerFormEditorInterface *core,
600 QObject *object,
601 const QString &property)
602{
603 if (const QDesignerPropertySheetExtension *ps = qt_extension<QDesignerPropertySheetExtension *>(core->extensionManager(), object)) {
604 const int index = ps->indexOf(property);
605 if (index >= 0)
606 return ps->propertyGroup(index);
607 }
608 return QString();
609}
610
612{
613 QDesignerFormEditorInterface *core = q->core();
614 QObject *currentObject = core->propertyEditor()->object();
615 if (!currentObject)
616 return QString();
617 // Return a help index id consisting of "class::property"
618 QString className;
619 QString currentPropertyName = core->propertyEditor()->currentPropertyName();
620 if (!currentPropertyName.isEmpty())
621 className = classForProperty(core, currentObject, currentPropertyName);
622 if (className.isEmpty()) {
623 currentPropertyName.clear(); // We hit on some fake property.
624 className = qdesigner_internal::WidgetFactory::classNameOf(core, currentObject);
625 }
626 QString helpId = fixHelpClassName(className);
627 if (!currentPropertyName.isEmpty()) {
628 helpId += "::"_L1;
629 helpId += currentPropertyName;
630 }
631 return helpId;
632}
633
634} // namespace qdesigner_internal
635
636// -------------- QDesignerIntegration
637// As of 4.4, the header will be distributed with the Eclipse plugin.
638
639QDesignerIntegration::QDesignerIntegration(QDesignerFormEditorInterface *core, QObject *parent) :
640 QDesignerIntegrationInterface(core, parent),
641 d(new qdesigner_internal::QDesignerIntegrationPrivate(this))
642{
643 d->initialize();
644}
645
646QDesignerIntegration::~QDesignerIntegration()
647{
648 QFile f(d->m_gradientsPath);
649 if (f.open(QIODevice::WriteOnly)) {
650 f.write(QtGradientUtils::saveState(d->m_gradientManager).toUtf8());
651 f.close();
652 }
653}
654
655QString QDesignerIntegration::headerSuffix() const
656{
657 return d->headerSuffix;
658}
659
660void QDesignerIntegration::setHeaderSuffix(const QString &headerSuffix)
661{
662 d->headerSuffix = headerSuffix;
663}
664
665bool QDesignerIntegration::isHeaderLowercase() const
666{
667 return d->headerLowercase;
668}
669
670void QDesignerIntegration::setHeaderLowercase(bool headerLowercase)
671{
672 d->headerLowercase = headerLowercase;
673}
674
675QDesignerIntegrationInterface::Feature QDesignerIntegration::features() const
676{
677 return d->m_features;
678}
679
680void QDesignerIntegration::setFeatures(Feature f)
681{
682 d->m_features = f;
683}
684
685QDesignerIntegrationInterface::ResourceFileWatcherBehaviour QDesignerIntegration::resourceFileWatcherBehaviour() const
686{
687 return d->m_resourceFileWatcherBehaviour;
688}
689
690void QDesignerIntegration::setResourceFileWatcherBehaviour(ResourceFileWatcherBehaviour behaviour)
691{
692 if (d->m_resourceFileWatcherBehaviour != behaviour) {
693 d->m_resourceFileWatcherBehaviour = behaviour;
694 core()->resourceModel()->setWatcherEnabled(behaviour != QDesignerIntegrationInterface::NoResourceFileWatcher);
695 }
696}
697
698void QDesignerIntegration::updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling)
699{
700 d->updateProperty(name, value, enableSubPropertyHandling);
701 emit propertyChanged(core()->formWindowManager()->activeFormWindow(), name, value);
702}
703
704void QDesignerIntegration::updateProperty(const QString &name, const QVariant &value)
705{
706 updateProperty(name, value, true);
707}
708
709void QDesignerIntegration::resetProperty(const QString &name)
710{
711 d->resetProperty(name);
712}
713
714void QDesignerIntegration::addDynamicProperty(const QString &name, const QVariant &value)
715{
716 d->addDynamicProperty(name, value);
717}
718
719void QDesignerIntegration::removeDynamicProperty(const QString &name)
720{
721 d->removeDynamicProperty(name);
722}
723
724void QDesignerIntegration::updateActiveFormWindow(QDesignerFormWindowInterface *)
725{
726 d->updateSelection();
727}
728
729void QDesignerIntegration::setupFormWindow(QDesignerFormWindowInterface *formWindow)
730{
731 d->setupFormWindow(formWindow);
732 connect(formWindow, &QDesignerFormWindowInterface::selectionChanged,
733 this, &QDesignerIntegrationInterface::updateSelection);
734}
735
736void QDesignerIntegration::updateSelection()
737{
738 d->updateSelection();
739}
740
741QWidget *QDesignerIntegration::containerWindow(QWidget *widget) const
742{
743 return d->containerWindow(widget);
744}
745
746// Load plugins into widget database and factory.
747void QDesignerIntegration::initializePlugins(QDesignerFormEditorInterface *formEditor)
748{
749 qdesigner_internal::QDesignerIntegrationPrivate::initializePlugins(formEditor);
750}
751
752void QDesignerIntegration::updateCustomWidgetPlugins()
753{
754 d->updateCustomWidgetPlugins();
755}
756
757QDesignerResourceBrowserInterface *QDesignerIntegration::createResourceBrowser(QWidget *)
758{
759 return nullptr;
760}
761
762QString QDesignerIntegration::contextHelpId() const
763{
764 return d->contextHelpId();
765}
766
767QT_END_NAMESPACE
QDesignerIntegrationInterfacePrivate(QDesignerFormEditorInterface *core)
QDesignerFormEditorInterface * m_core
virtual QString propertyGroup(int index) const =0
virtual int indexOf(const QString &name) const =0
friend class QWidget
Definition qpainter.h:432
static void restoreState(QtGradientManager *manager, const QString &state)
void getSelection(qdesigner_internal::Selection &s)
static void initializePlugins(QDesignerFormEditorInterface *formEditor)
QDesignerIntegrationInterface::Feature m_features
void setupFormWindow(QDesignerFormWindowInterface *formWindow)
void addDynamicProperty(const QString &name, const QVariant &value)
void updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling)
QDesignerIntegrationInterface::ResourceFileWatcherBehaviour m_resourceFileWatcherBehaviour
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.
static QString fixHelpClassName(const QString &className)
static QString classForProperty(QDesignerFormEditorInterface *core, QObject *object, const QString &property)