1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Designer of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28
29 #include "qaxwidgetpropertysheet.h"
30 #include "qdesigneraxwidget.h"
31
32 #include <QtDesigner/membersheet.h>
33 #include <QtDesigner/abstractformwindow.h>
34 #include <QtDesigner/abstractformeditor.h>
35 #include <QtDesigner/abstractpropertyeditor.h>
36
37 #include <QtDesigner/qextensionmanager.h>
38 #include <private/qdesigner_utils_p.h>
39 #include <QtCore/qdebug.h>
40 #include <QtCore/qtimer.h>
41
42 static const char *geometryPropertyC = "geometry";
43
44 QT_BEGIN_NAMESPACE
45
46 const char *QAxWidgetPropertySheet::controlPropertyName = "control";
47
designerPropertyToString(const QVariant & value)48 static QString designerPropertyToString(const QVariant &value)
49 {
50 return value.canConvert<qdesigner_internal::PropertySheetStringValue>() ?
51 qvariant_cast<qdesigner_internal::PropertySheetStringValue>(value).value() :
52 value.toString();
53 }
54
QAxWidgetPropertySheet(QDesignerAxWidget * object,QObject * parent)55 QAxWidgetPropertySheet::QAxWidgetPropertySheet(QDesignerAxWidget *object, QObject *parent) :
56 QDesignerPropertySheet(object, parent),
57 m_controlProperty(controlPropertyName),
58 m_propertyGroup(QStringLiteral("QAxWidget"))
59 {
60 if (!axWidget()->loaded()) { // For some obscure reason....
61 const int controlIndex = QDesignerPropertySheet::indexOf(m_controlProperty);
62 setPropertyGroup(controlIndex, m_propertyGroup);
63 }
64 }
65
isEnabled(int index) const66 bool QAxWidgetPropertySheet::isEnabled(int index) const
67 {
68 if (propertyName(index) == m_controlProperty)
69 return false;
70 return QDesignerPropertySheet::isEnabled(index);
71 }
72
dynamicPropertiesAllowed() const73 bool QAxWidgetPropertySheet::dynamicPropertiesAllowed() const
74 {
75 return false;
76 }
77
axWidget() const78 QDesignerAxWidget *QAxWidgetPropertySheet::axWidget() const
79 {
80 return static_cast<QDesignerAxWidget*>(object());
81 }
82
83 // Reload as the meta object changes.
reset(int index)84 bool QAxWidgetPropertySheet::reset(int index)
85 {
86 const QString name = propertyName(index);
87 QMap<QString, QVariant>::iterator it = m_currentProperties.changedProperties.find(name);
88 if (it != m_currentProperties.changedProperties.end())
89 m_currentProperties.changedProperties.erase(it);
90 if (name != m_controlProperty)
91 return QDesignerPropertySheet::reset(index);
92 axWidget()->resetControl();
93 QTimer::singleShot(0, this, &QAxWidgetPropertySheet::updatePropertySheet);
94 return true;
95 }
96
property(int index) const97 QVariant QAxWidgetPropertySheet::property(int index) const
98 {
99 // QTBUG-34592, accessing the 'control' property via meta object system
100 // may cause crashes during loading for some controls.
101 return propertyName(index) == m_controlProperty ?
102 QVariant(axWidget()->control()) :
103 QDesignerPropertySheet::property(index);
104 }
105
setProperty(int index,const QVariant & value)106 void QAxWidgetPropertySheet::setProperty(int index, const QVariant &value)
107 {
108
109 // take care of all changed properties
110 const QString name = propertyName(index);
111 m_currentProperties.changedProperties[name] = value;
112 if (name != m_controlProperty) {
113 QDesignerPropertySheet::setProperty(index, value);
114 return;
115 }
116 // Loading forms: Reload
117 if (name == m_controlProperty) {
118 const QString clsid = designerPropertyToString(value);
119 if (clsid.isEmpty() || !axWidget()->loadControl(clsid))
120 reset(index);
121 else
122 QTimer::singleShot(100, this, &QAxWidgetPropertySheet::updatePropertySheet);
123 }
124 }
125
indexOf(const QString & name) const126 int QAxWidgetPropertySheet::indexOf(const QString &name) const
127 {
128 const int index = QDesignerPropertySheet::indexOf(name);
129 if (index != -1)
130 return index;
131 // Loading before recreation of sheet in timer slot: Add a fake property to store the value
132 const QVariant dummValue(0);
133 auto that = const_cast<QAxWidgetPropertySheet *>(this);
134 const int newIndex = that->createFakeProperty(name, dummValue);
135 that->setPropertyGroup(newIndex, m_propertyGroup);
136 return newIndex;
137 }
138
updatePropertySheet()139 void QAxWidgetPropertySheet::updatePropertySheet()
140 {
141 // refresh the property sheet (we are deleting m_currentProperties)
142 struct SavedProperties tmp = m_currentProperties;
143 QDesignerAxWidget *axw = axWidget();
144 QDesignerFormWindowInterface *formWin = QDesignerFormWindowInterface::findFormWindow(axw);
145 Q_ASSERT(formWin != nullptr);
146 tmp.widget = axw;
147 tmp.clsid = axw->control();
148 // Delete the sheets as they cache the meta object and other information
149 delete this;
150 delete qt_extension<QDesignerMemberSheetExtension *>(formWin->core()->extensionManager(), axw);
151 reloadPropertySheet(tmp, formWin);
152 }
153
reloadPropertySheet(const struct SavedProperties & properties,QDesignerFormWindowInterface * formWin)154 void QAxWidgetPropertySheet::reloadPropertySheet(const struct SavedProperties &properties,
155 QDesignerFormWindowInterface *formWin)
156 {
157 QDesignerFormEditorInterface *core = formWin->core();
158 //Recreation of the property sheet
159 auto sheet = qt_extension<QDesignerPropertySheetExtension *>(core->extensionManager(),
160 properties.widget);
161
162 bool foundGeometry = false;
163 const QString geometryProperty = QLatin1String(geometryPropertyC);
164 for (auto i = properties.changedProperties.cbegin(), cend = properties.changedProperties.cend();
165 i != cend; ++i) {
166 const QString name = i.key();
167 const int index = sheet->indexOf(name);
168 if (index == -1)
169 continue;
170 // filter out geometry as this will resize the control
171 // to is default size even if it is attached to an layout
172 // but set the changed flag to work around preview bug...
173 if (name == geometryProperty) {
174 sheet->setChanged(index, true);
175 foundGeometry = true;
176 continue;
177 }
178 if (name == QLatin1String(controlPropertyName)) {
179 sheet->setChanged(index, !designerPropertyToString(i.value()).isEmpty());
180 continue;
181 }
182 sheet->setChanged(index, true);
183 sheet->setProperty(index, i.value());
184 }
185
186 if (!foundGeometry) // Make sure geometry is always changed in Designer
187 sheet->setChanged(sheet->indexOf(geometryProperty), true);
188
189 if (core->propertyEditor()->object() == properties.widget) {
190 formWin->clearSelection(true);
191 formWin->selectWidget(properties.widget);
192 }
193 }
194
195 QT_END_NAMESPACE
196