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