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 "qdesigner_widgetbox_p.h"
30#include "qdesigner_utils_p.h"
31
32#include <QtDesigner/private/ui4_p.h>
33
34#include <QtCore/qregularexpression.h>
35#include <QtCore/qdebug.h>
36#include <QtCore/qxmlstream.h>
37#include <QtCore/qshareddata.h>
38
39QT_BEGIN_NAMESPACE
40
41class QDesignerWidgetBoxWidgetData : public QSharedData
42{
43public:
44 QDesignerWidgetBoxWidgetData(const QString &aname, const QString &xml,
45 const QString &icon_name,
46 QDesignerWidgetBoxInterface::Widget::Type atype);
47 QString m_name;
48 QString m_xml;
49 QString m_icon_name;
50 QDesignerWidgetBoxInterface::Widget::Type m_type;
51};
52
53QDesignerWidgetBoxWidgetData::QDesignerWidgetBoxWidgetData(const QString &aname,
54 const QString &xml,
55 const QString &icon_name,
56 QDesignerWidgetBoxInterface::Widget::Type atype) :
57 m_name(aname), m_xml(xml), m_icon_name(icon_name), m_type(atype)
58{
59}
60
61QDesignerWidgetBoxInterface::Widget::Widget(const QString &aname, const QString &xml,
62 const QString &icon_name, Type atype) :
63 m_data(new QDesignerWidgetBoxWidgetData(aname, xml, icon_name, atype))
64{
65}
66
67QDesignerWidgetBoxInterface::Widget::~Widget() = default;
68
69QDesignerWidgetBoxInterface::Widget::Widget(const Widget &w) :
70 m_data(w.m_data)
71{
72}
73
74QDesignerWidgetBoxInterface::Widget &QDesignerWidgetBoxInterface::Widget::operator=(const Widget &rhs)
75{
76 if (this != &rhs) {
77 m_data = rhs.m_data;
78 }
79 return *this;
80}
81
82QString QDesignerWidgetBoxInterface::Widget::name() const
83{
84 return m_data->m_name;
85}
86
87void QDesignerWidgetBoxInterface::Widget::setName(const QString &aname)
88{
89 m_data->m_name = aname;
90}
91
92QString QDesignerWidgetBoxInterface::Widget::domXml() const
93{
94 return m_data->m_xml;
95}
96
97void QDesignerWidgetBoxInterface::Widget::setDomXml(const QString &xml)
98{
99 m_data->m_xml = xml;
100}
101
102QString QDesignerWidgetBoxInterface::Widget::iconName() const
103{
104 return m_data->m_icon_name;
105}
106
107void QDesignerWidgetBoxInterface::Widget::setIconName(const QString &icon_name)
108{
109 m_data->m_icon_name = icon_name;
110}
111
112QDesignerWidgetBoxInterface::Widget::Type QDesignerWidgetBoxInterface::Widget::type() const
113{
114 return m_data->m_type;
115}
116
117void QDesignerWidgetBoxInterface::Widget::setType(Type atype)
118{
119 m_data->m_type = atype;
120}
121
122bool QDesignerWidgetBoxInterface::Widget::isNull() const
123{
124 return m_data->m_name.isEmpty();
125}
126
127namespace qdesigner_internal {
128QDesignerWidgetBox::QDesignerWidgetBox(QWidget *parent, Qt::WindowFlags flags)
129 : QDesignerWidgetBoxInterface(parent, flags)
130{
131
132}
133
134QDesignerWidgetBox::LoadMode QDesignerWidgetBox::loadMode() const
135{
136 return m_loadMode;
137}
138
139void QDesignerWidgetBox::setLoadMode(LoadMode lm)
140{
141 m_loadMode = lm;
142}
143
144// Convenience to find a widget by class name
145bool QDesignerWidgetBox::findWidget(const QDesignerWidgetBoxInterface *wbox,
146 const QString &className,
147 const QString &category,
148 Widget *widgetData)
149{
150 // Note that entry names do not necessarily match the class name
151 // (at least, not for the standard widgets), so,
152 // look in the XML for the class name of the first widget to appear
153 const QString widgetTag = QStringLiteral("<widget");
154 QString pattern = QStringLiteral("^<widget\\s+class\\s*=\\s*\"");
155 pattern += className;
156 pattern += QStringLiteral("\".*$");
157 const QRegularExpression regexp(pattern);
158 Q_ASSERT(regexp.isValid());
159 const int catCount = wbox->categoryCount();
160 for (int c = 0; c < catCount; c++) {
161 const Category cat = wbox->category(cat_idx: c);
162 if (category.isEmpty() || cat.name() == category) {
163 const int widgetCount = cat.widgetCount();
164 for (int w = 0; w < widgetCount; w++) {
165 const Widget widget = cat.widget(idx: w);
166 QString xml = widget.domXml(); // Erase the <ui> tag that can be present starting from 4.4
167 const int widgetTagIndex = xml.indexOf(s: widgetTag);
168 if (widgetTagIndex != -1) {
169 xml.remove(i: 0, len: widgetTagIndex);
170 if (regexp.match(subject: xml).hasMatch()) {
171 *widgetData = widget;
172 return true;
173 }
174 }
175 }
176 }
177 }
178 return false;
179}
180
181// Convenience to create a Dom Widget from widget box xml code.
182DomUI *QDesignerWidgetBox::xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel,
183 QString *errorMessage)
184{
185 QXmlStreamReader reader(xml);
186 DomUI *ui = nullptr;
187
188 // The xml description must either contain a root element "ui" with a child element "widget"
189 // or "widget" as the root element (4.3 legacy)
190
191 while (!reader.atEnd()) {
192 if (reader.readNext() == QXmlStreamReader::StartElement) {
193 const auto name = reader.name();
194 if (ui) {
195 reader.raiseError(message: tr(s: "Unexpected element <%1>").arg(a: name.toString()));
196 continue;
197 }
198
199 if (name.compare(QStringLiteral("widget"), cs: Qt::CaseInsensitive) == 0) { // 4.3 legacy, wrap into DomUI
200 ui = new DomUI;
201 DomWidget *widget = new DomWidget;
202 widget->read(reader);
203 ui->setElementWidget(widget);
204 } else if (name.compare(QStringLiteral("ui"), cs: Qt::CaseInsensitive) == 0) { // 4.4
205 ui = new DomUI;
206 ui->read(reader);
207 } else {
208 reader.raiseError(message: tr(s: "Unexpected element <%1>").arg(a: name.toString()));
209 }
210 }
211 }
212
213 if (reader.hasError()) {
214 delete ui;
215 *errorMessage = tr(s: "A parse error occurred at line %1, column %2 of the XML code "
216 "specified for the widget %3: %4\n%5")
217 .arg(a: reader.lineNumber()).arg(a: reader.columnNumber())
218 .arg(args: name, args: reader.errorString(), args: xml);
219 return nullptr;
220 }
221
222 if (!ui || !ui->elementWidget()) {
223 delete ui;
224 *errorMessage = tr(s: "The XML code specified for the widget %1 does not contain "
225 "any widget elements.\n%2").arg(a1: name, a2: xml);
226 return nullptr;
227 }
228
229 if (insertFakeTopLevel) {
230 DomWidget *fakeTopLevel = new DomWidget;
231 fakeTopLevel->setAttributeClass(QStringLiteral("QWidget"));
232 QVector<DomWidget *> children;
233 children.push_back(t: ui->takeElementWidget());
234 fakeTopLevel->setElementWidget(children);
235 ui->setElementWidget(fakeTopLevel);
236 }
237
238 return ui;
239}
240
241// Convenience to create a Dom Widget from widget box xml code.
242DomUI *QDesignerWidgetBox::xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel)
243{
244 QString errorMessage;
245 DomUI *rc = xmlToUi(name, xml, insertFakeTopLevel, errorMessage: &errorMessage);
246 if (!rc)
247 qdesigner_internal::designerWarning(message: errorMessage);
248 return rc;
249}
250
251} // namespace qdesigner_internal
252
253QT_END_NAMESPACE
254

source code of qttools/src/designer/src/lib/shared/qdesigner_widgetbox.cpp