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