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 
39 QT_BEGIN_NAMESPACE
40 
41 class QDesignerWidgetBoxWidgetData : public QSharedData
42 {
43 public:
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 
QDesignerWidgetBoxWidgetData(const QString & aname,const QString & xml,const QString & icon_name,QDesignerWidgetBoxInterface::Widget::Type atype)53 QDesignerWidgetBoxWidgetData::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 
Widget(const QString & aname,const QString & xml,const QString & icon_name,Type atype)61 QDesignerWidgetBoxInterface::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 
67 QDesignerWidgetBoxInterface::Widget::~Widget() = default;
68 
Widget(const Widget & w)69 QDesignerWidgetBoxInterface::Widget::Widget(const Widget &w) :
70     m_data(w.m_data)
71 {
72 }
73 
operator =(const Widget & rhs)74 QDesignerWidgetBoxInterface::Widget &QDesignerWidgetBoxInterface::Widget::operator=(const Widget &rhs)
75 {
76     if (this != &rhs) {
77         m_data = rhs.m_data;
78     }
79     return *this;
80 }
81 
name() const82 QString QDesignerWidgetBoxInterface::Widget::name() const
83 {
84     return m_data->m_name;
85 }
86 
setName(const QString & aname)87 void QDesignerWidgetBoxInterface::Widget::setName(const QString &aname)
88 {
89     m_data->m_name = aname;
90 }
91 
domXml() const92 QString QDesignerWidgetBoxInterface::Widget::domXml() const
93 {
94     return m_data->m_xml;
95 }
96 
setDomXml(const QString & xml)97 void QDesignerWidgetBoxInterface::Widget::setDomXml(const QString &xml)
98 {
99     m_data->m_xml = xml;
100 }
101 
iconName() const102 QString QDesignerWidgetBoxInterface::Widget::iconName() const
103 {
104     return m_data->m_icon_name;
105 }
106 
setIconName(const QString & icon_name)107 void QDesignerWidgetBoxInterface::Widget::setIconName(const QString &icon_name)
108 {
109     m_data->m_icon_name = icon_name;
110 }
111 
type() const112 QDesignerWidgetBoxInterface::Widget::Type QDesignerWidgetBoxInterface::Widget::type() const
113 {
114     return m_data->m_type;
115 }
116 
setType(Type atype)117 void QDesignerWidgetBoxInterface::Widget::setType(Type atype)
118 {
119     m_data->m_type = atype;
120 }
121 
isNull() const122 bool QDesignerWidgetBoxInterface::Widget::isNull() const
123 {
124     return m_data->m_name.isEmpty();
125 }
126 
127 namespace qdesigner_internal {
QDesignerWidgetBox(QWidget * parent,Qt::WindowFlags flags)128 QDesignerWidgetBox::QDesignerWidgetBox(QWidget *parent, Qt::WindowFlags flags)
129     : QDesignerWidgetBoxInterface(parent, flags)
130 {
131 
132 }
133 
loadMode() const134 QDesignerWidgetBox::LoadMode QDesignerWidgetBox::loadMode() const
135 {
136     return m_loadMode;
137 }
138 
setLoadMode(LoadMode lm)139 void QDesignerWidgetBox::setLoadMode(LoadMode lm)
140 {
141      m_loadMode = lm;
142 }
143 
144 // Convenience to find a widget by class name
findWidget(const QDesignerWidgetBoxInterface * wbox,const QString & className,const QString & category,Widget * widgetData)145 bool 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(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(w);
166                 QString xml = widget.domXml(); // Erase the <ui> tag that can be present starting from 4.4
167                 const int widgetTagIndex = xml.indexOf(widgetTag);
168                 if (widgetTagIndex != -1) {
169                     xml.remove(0, widgetTagIndex);
170                     if (regexp.match(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.
xmlToUi(const QString & name,const QString & xml,bool insertFakeTopLevel,QString * errorMessage)182 DomUI *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(tr("Unexpected element <%1>").arg(name.toString()));
196                 continue;
197             }
198 
199             if (name.compare(QStringLiteral("widget"), 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"), Qt::CaseInsensitive) == 0) { // 4.4
205                 ui = new DomUI;
206                 ui->read(reader);
207             } else {
208                 reader.raiseError(tr("Unexpected element <%1>").arg(name.toString()));
209             }
210         }
211    }
212 
213     if (reader.hasError()) {
214         delete ui;
215         *errorMessage = tr("A parse error occurred at line %1, column %2 of the XML code "
216                            "specified for the widget %3: %4\n%5")
217                            .arg(reader.lineNumber()).arg(reader.columnNumber())
218                            .arg(name, reader.errorString(), xml);
219         return nullptr;
220     }
221 
222     if (!ui || !ui->elementWidget()) {
223         delete ui;
224         *errorMessage = tr("The XML code specified for the widget %1 does not contain "
225                            "any widget elements.\n%2").arg(name, 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(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.
xmlToUi(const QString & name,const QString & xml,bool insertFakeTopLevel)242 DomUI *QDesignerWidgetBox::xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel)
243 {
244     QString errorMessage;
245     DomUI *rc = xmlToUi(name, xml, insertFakeTopLevel, &errorMessage);
246     if (!rc)
247         qdesigner_internal::designerWarning(errorMessage);
248     return rc;
249 }
250 
251 }  // namespace qdesigner_internal
252 
253 QT_END_NAMESPACE
254