1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the Qt Designer of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "deviceprofile_p.h"
|
---|
43 |
|
---|
44 | #include <QtDesigner/QDesignerFormEditorInterface>
|
---|
45 | #include <widgetfactory_p.h>
|
---|
46 | #include <qdesigner_utils_p.h>
|
---|
47 |
|
---|
48 | #include <QtGui/QApplication>
|
---|
49 | #include <QtGui/QFont>
|
---|
50 | #include <QtGui/QDesktopWidget>
|
---|
51 | #include <QtGui/QStyle>
|
---|
52 | #include <QtGui/QStyleFactory>
|
---|
53 | #include <QtGui/QApplication>
|
---|
54 |
|
---|
55 | #include <QtCore/QSharedData>
|
---|
56 | #include <QtCore/QTextStream>
|
---|
57 |
|
---|
58 | #include <QtCore/QXmlStreamWriter>
|
---|
59 | #include <QtCore/QXmlStreamReader>
|
---|
60 |
|
---|
61 |
|
---|
62 | static const char *dpiXPropertyC = "_q_customDpiX";
|
---|
63 | static const char *dpiYPropertyC = "_q_customDpiY";
|
---|
64 |
|
---|
65 | // XML serialization
|
---|
66 | static const char *xmlVersionC="1.0";
|
---|
67 | static const char *rootElementC="deviceprofile";
|
---|
68 | static const char *nameElementC = "name";
|
---|
69 | static const char *fontFamilyElementC = "fontfamily";
|
---|
70 | static const char *fontPointSizeElementC = "fontpointsize";
|
---|
71 | static const char *dPIXElementC = "dpix";
|
---|
72 | static const char *dPIYElementC = "dpiy";
|
---|
73 | static const char *styleElementC = "style";
|
---|
74 |
|
---|
75 | /* DeviceProfile:
|
---|
76 | * For preview purposes (preview, widget box, new form dialog), the
|
---|
77 | * QDesignerFormBuilder applies the settings to the form main container
|
---|
78 | * (Point being here that the DPI must be set directly for size calculations
|
---|
79 | * to be correct).
|
---|
80 | * For editing purposes, FormWindow applies the settings to the form container
|
---|
81 | * as not to interfere with the font settings of the form main container.
|
---|
82 | * In addition, the widgetfactory maintains the system settings style
|
---|
83 | * and applies it when creating widgets. */
|
---|
84 |
|
---|
85 | QT_BEGIN_NAMESPACE
|
---|
86 |
|
---|
87 | namespace qdesigner_internal {
|
---|
88 |
|
---|
89 | // ---------------- DeviceProfileData
|
---|
90 | class DeviceProfileData : public QSharedData {
|
---|
91 | public:
|
---|
92 | DeviceProfileData();
|
---|
93 | void fromSystem();
|
---|
94 | void clear();
|
---|
95 |
|
---|
96 | QString m_fontFamily;
|
---|
97 | int m_fontPointSize;
|
---|
98 | QString m_style;
|
---|
99 | int m_dpiX;
|
---|
100 | int m_dpiY;
|
---|
101 | QString m_name;
|
---|
102 | };
|
---|
103 |
|
---|
104 | DeviceProfileData::DeviceProfileData() :
|
---|
105 | m_fontPointSize(-1),
|
---|
106 | m_dpiX(-1),
|
---|
107 | m_dpiY(-1)
|
---|
108 | {
|
---|
109 | }
|
---|
110 |
|
---|
111 | void DeviceProfileData::clear()
|
---|
112 | {
|
---|
113 | m_fontPointSize = -1;
|
---|
114 | m_dpiX = 0;
|
---|
115 | m_dpiY = 0;
|
---|
116 | m_name.clear();
|
---|
117 | m_style.clear();
|
---|
118 | }
|
---|
119 |
|
---|
120 | void DeviceProfileData::fromSystem()
|
---|
121 | {
|
---|
122 | const QFont appFont = QApplication::font();
|
---|
123 | m_fontFamily = appFont.family();
|
---|
124 | m_fontPointSize = appFont.pointSize();
|
---|
125 | DeviceProfile::systemResolution(&m_dpiX, &m_dpiY);
|
---|
126 | m_style.clear();
|
---|
127 | }
|
---|
128 |
|
---|
129 | // ---------------- DeviceProfile
|
---|
130 | DeviceProfile::DeviceProfile() :
|
---|
131 | m_d(new DeviceProfileData)
|
---|
132 | {
|
---|
133 | }
|
---|
134 |
|
---|
135 | DeviceProfile::DeviceProfile(const DeviceProfile &o) :
|
---|
136 | m_d(o.m_d)
|
---|
137 |
|
---|
138 | {
|
---|
139 | }
|
---|
140 |
|
---|
141 | DeviceProfile& DeviceProfile::operator=(const DeviceProfile &o)
|
---|
142 | {
|
---|
143 | m_d.operator=(o.m_d);
|
---|
144 | return *this;
|
---|
145 | }
|
---|
146 |
|
---|
147 | DeviceProfile::~DeviceProfile()
|
---|
148 | {
|
---|
149 | }
|
---|
150 |
|
---|
151 | void DeviceProfile::clear()
|
---|
152 | {
|
---|
153 | m_d->clear();
|
---|
154 | }
|
---|
155 |
|
---|
156 | bool DeviceProfile::isEmpty() const
|
---|
157 | {
|
---|
158 | return m_d->m_name.isEmpty();
|
---|
159 | }
|
---|
160 |
|
---|
161 | QString DeviceProfile::fontFamily() const
|
---|
162 | {
|
---|
163 | return m_d->m_fontFamily;
|
---|
164 | }
|
---|
165 |
|
---|
166 | void DeviceProfile::setFontFamily(const QString &f)
|
---|
167 | {
|
---|
168 | m_d->m_fontFamily = f;
|
---|
169 | }
|
---|
170 |
|
---|
171 | int DeviceProfile::fontPointSize() const
|
---|
172 | {
|
---|
173 | return m_d->m_fontPointSize;
|
---|
174 | }
|
---|
175 |
|
---|
176 | void DeviceProfile::setFontPointSize(int p)
|
---|
177 | {
|
---|
178 | m_d->m_fontPointSize = p;
|
---|
179 | }
|
---|
180 |
|
---|
181 | QString DeviceProfile::style() const
|
---|
182 | {
|
---|
183 | return m_d->m_style;
|
---|
184 | }
|
---|
185 |
|
---|
186 | void DeviceProfile::setStyle(const QString &s)
|
---|
187 | {
|
---|
188 | m_d->m_style = s;
|
---|
189 | }
|
---|
190 |
|
---|
191 | int DeviceProfile::dpiX() const
|
---|
192 | {
|
---|
193 | return m_d->m_dpiX;
|
---|
194 | }
|
---|
195 |
|
---|
196 | void DeviceProfile::setDpiX(int d)
|
---|
197 | {
|
---|
198 | m_d->m_dpiX = d;
|
---|
199 | }
|
---|
200 |
|
---|
201 | int DeviceProfile::dpiY() const
|
---|
202 | {
|
---|
203 | return m_d->m_dpiY;
|
---|
204 | }
|
---|
205 |
|
---|
206 | void DeviceProfile::setDpiY(int d)
|
---|
207 | {
|
---|
208 | m_d->m_dpiY = d;
|
---|
209 | }
|
---|
210 |
|
---|
211 | void DeviceProfile::fromSystem()
|
---|
212 | {
|
---|
213 | m_d->fromSystem();
|
---|
214 | }
|
---|
215 |
|
---|
216 | QString DeviceProfile::name() const
|
---|
217 | {
|
---|
218 | return m_d->m_name;
|
---|
219 | }
|
---|
220 |
|
---|
221 | void DeviceProfile::setName(const QString &n)
|
---|
222 | {
|
---|
223 | m_d->m_name = n;
|
---|
224 | }
|
---|
225 |
|
---|
226 | void DeviceProfile::systemResolution(int *dpiX, int *dpiY)
|
---|
227 | {
|
---|
228 | const QDesktopWidget *dw = qApp->desktop();
|
---|
229 | *dpiX = dw->logicalDpiX();
|
---|
230 | *dpiY = dw->logicalDpiY();
|
---|
231 | }
|
---|
232 |
|
---|
233 | class FriendlyWidget : public QWidget {
|
---|
234 | friend class DeviceProfile;
|
---|
235 | };
|
---|
236 |
|
---|
237 | void DeviceProfile::widgetResolution(const QWidget *w, int *dpiX, int *dpiY)
|
---|
238 | {
|
---|
239 | const FriendlyWidget *fw = static_cast<const FriendlyWidget*>(w);
|
---|
240 | *dpiX = fw->metric(QPaintDevice::PdmDpiX);
|
---|
241 | *dpiY = fw->metric(QPaintDevice::PdmDpiY);
|
---|
242 | }
|
---|
243 |
|
---|
244 | QString DeviceProfile::toString() const
|
---|
245 | {
|
---|
246 | const DeviceProfileData &d = *m_d;
|
---|
247 | QString rc;
|
---|
248 | QTextStream(&rc) << "DeviceProfile:name=" << d.m_name << " Font=" << d.m_fontFamily << ' '
|
---|
249 | << d.m_fontPointSize << " Style=" << d.m_style << " DPI=" << d.m_dpiX << ',' << d.m_dpiY;
|
---|
250 | return rc;
|
---|
251 | }
|
---|
252 |
|
---|
253 | // Apply font to widget
|
---|
254 | static void applyFont(const QString &family, int size, DeviceProfile::ApplyMode am, QWidget *widget)
|
---|
255 | {
|
---|
256 | QFont currentFont = widget->font();
|
---|
257 | if (currentFont.pointSize() == size && currentFont.family() == family)
|
---|
258 | return;
|
---|
259 | switch (am) {
|
---|
260 | case DeviceProfile::ApplyFormParent:
|
---|
261 | // Invisible form parent: Apply all
|
---|
262 | widget->setFont(QFont(family, size));
|
---|
263 | break;
|
---|
264 | case DeviceProfile::ApplyPreview: {
|
---|
265 | // Preview: Apply only subproperties that have not been changed by designer properties
|
---|
266 | bool apply = false;
|
---|
267 | const uint resolve = currentFont.resolve();
|
---|
268 | if (!(resolve & QFont::FamilyResolved)) {
|
---|
269 | currentFont.setFamily(family);
|
---|
270 | apply = true;
|
---|
271 | }
|
---|
272 | if (!(resolve & QFont::SizeResolved)) {
|
---|
273 | currentFont.setPointSize(size);
|
---|
274 | apply = true;
|
---|
275 | }
|
---|
276 | if (apply)
|
---|
277 | widget->setFont(currentFont);
|
---|
278 | }
|
---|
279 | break;
|
---|
280 | }
|
---|
281 | }
|
---|
282 |
|
---|
283 | void DeviceProfile::applyDPI(int dpiX, int dpiY, QWidget *widget)
|
---|
284 | {
|
---|
285 | int sysDPIX, sysDPIY; // Set dynamic variables in case values are different from system DPI
|
---|
286 | systemResolution(&sysDPIX, &sysDPIY);
|
---|
287 | if (dpiX != sysDPIX && dpiY != sysDPIY) {
|
---|
288 | widget->setProperty(dpiXPropertyC, QVariant(dpiX));
|
---|
289 | widget->setProperty(dpiYPropertyC, QVariant(dpiY));
|
---|
290 | }
|
---|
291 | }
|
---|
292 |
|
---|
293 | void DeviceProfile::apply(const QDesignerFormEditorInterface *core, QWidget *widget, ApplyMode am) const
|
---|
294 | {
|
---|
295 | if (isEmpty())
|
---|
296 | return;
|
---|
297 |
|
---|
298 | const DeviceProfileData &d = *m_d;
|
---|
299 |
|
---|
300 | if (!d.m_fontFamily.isEmpty())
|
---|
301 | applyFont(d.m_fontFamily, d.m_fontPointSize, am, widget);
|
---|
302 |
|
---|
303 | applyDPI(d.m_dpiX, d.m_dpiY, widget);
|
---|
304 |
|
---|
305 | if (!d.m_style.isEmpty()) {
|
---|
306 | if (WidgetFactory *wf = qobject_cast<qdesigner_internal::WidgetFactory *>(core->widgetFactory()))
|
---|
307 | wf->applyStyleTopLevel(d.m_style, widget);
|
---|
308 | }
|
---|
309 | }
|
---|
310 |
|
---|
311 | bool DeviceProfile::equals(const DeviceProfile& rhs) const
|
---|
312 | {
|
---|
313 | const DeviceProfileData &d = *m_d;
|
---|
314 | const DeviceProfileData &rhs_d = *rhs.m_d;
|
---|
315 | return d.m_fontPointSize == rhs_d.m_fontPointSize &&
|
---|
316 | d.m_dpiX == rhs_d.m_dpiX && d.m_dpiY == rhs_d.m_dpiY && d.m_fontFamily == rhs_d.m_fontFamily &&
|
---|
317 | d.m_style == rhs_d.m_style && d.m_name == rhs_d.m_name;
|
---|
318 | }
|
---|
319 |
|
---|
320 | static inline void writeElement(QXmlStreamWriter &writer, const QString &element, const QString &cdata)
|
---|
321 | {
|
---|
322 | writer.writeStartElement(element);
|
---|
323 | writer.writeCharacters(cdata);
|
---|
324 | writer.writeEndElement();
|
---|
325 | }
|
---|
326 |
|
---|
327 | QString DeviceProfile::toXml() const
|
---|
328 | {
|
---|
329 | const DeviceProfileData &d = *m_d;
|
---|
330 | QString rc;
|
---|
331 | QXmlStreamWriter writer(&rc);
|
---|
332 | writer.writeStartDocument(QLatin1String(xmlVersionC));
|
---|
333 | writer.writeStartElement(QLatin1String(rootElementC));
|
---|
334 | writeElement(writer, QLatin1String(nameElementC), d.m_name);
|
---|
335 |
|
---|
336 | if (!d.m_fontFamily.isEmpty())
|
---|
337 | writeElement(writer, QLatin1String(fontFamilyElementC), d.m_fontFamily);
|
---|
338 | if (d.m_fontPointSize >= 0)
|
---|
339 | writeElement(writer, QLatin1String(fontPointSizeElementC), QString::number(d.m_fontPointSize));
|
---|
340 | if (d.m_dpiX > 0)
|
---|
341 | writeElement(writer, QLatin1String(dPIXElementC), QString::number(d.m_dpiX));
|
---|
342 | if (d.m_dpiY > 0)
|
---|
343 | writeElement(writer, QLatin1String(dPIYElementC), QString::number(d.m_dpiY));
|
---|
344 | if (!d.m_style.isEmpty())
|
---|
345 | writeElement(writer, QLatin1String(styleElementC), d.m_style);
|
---|
346 |
|
---|
347 | writer.writeEndElement();
|
---|
348 | writer.writeEndDocument();
|
---|
349 | return rc;
|
---|
350 | }
|
---|
351 |
|
---|
352 | /* Switch stages when encountering a start element (state table) */
|
---|
353 | enum ParseStage { ParseBeginning, ParseWithinRoot,
|
---|
354 | ParseName, ParseFontFamily, ParseFontPointSize, ParseDPIX, ParseDPIY, ParseStyle,
|
---|
355 | ParseError };
|
---|
356 |
|
---|
357 | static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement)
|
---|
358 | {
|
---|
359 | switch (currentStage) {
|
---|
360 | case ParseBeginning:
|
---|
361 | if (startElement == QLatin1String(rootElementC))
|
---|
362 | return ParseWithinRoot;
|
---|
363 | break;
|
---|
364 | case ParseWithinRoot:
|
---|
365 | case ParseName:
|
---|
366 | case ParseFontFamily:
|
---|
367 | case ParseFontPointSize:
|
---|
368 | case ParseDPIX:
|
---|
369 | case ParseDPIY:
|
---|
370 | case ParseStyle:
|
---|
371 | if (startElement == QLatin1String(nameElementC))
|
---|
372 | return ParseName;
|
---|
373 | if (startElement == QLatin1String(fontFamilyElementC))
|
---|
374 | return ParseFontFamily;
|
---|
375 | if (startElement == QLatin1String(fontPointSizeElementC))
|
---|
376 | return ParseFontPointSize;
|
---|
377 | if (startElement == QLatin1String(dPIXElementC))
|
---|
378 | return ParseDPIX;
|
---|
379 | if (startElement == QLatin1String(dPIYElementC))
|
---|
380 | return ParseDPIY;
|
---|
381 | if (startElement == QLatin1String(styleElementC))
|
---|
382 | return ParseStyle;
|
---|
383 | break;
|
---|
384 | case ParseError:
|
---|
385 | break;
|
---|
386 | }
|
---|
387 | return ParseError;
|
---|
388 | }
|
---|
389 |
|
---|
390 | static bool readIntegerElement(QXmlStreamReader &reader, int *v)
|
---|
391 | {
|
---|
392 | const QString e = reader.readElementText();
|
---|
393 | bool ok;
|
---|
394 | *v = e.toInt(&ok);
|
---|
395 | //: Reading a number for an embedded device profile
|
---|
396 | if (!ok)
|
---|
397 | reader.raiseError(QApplication::translate("DeviceProfile", "'%1' is not a number.").arg(e));
|
---|
398 | return ok;
|
---|
399 | }
|
---|
400 |
|
---|
401 | bool DeviceProfile::fromXml(const QString &xml, QString *errorMessage)
|
---|
402 | {
|
---|
403 | DeviceProfileData &d = *m_d;
|
---|
404 | d.fromSystem();
|
---|
405 |
|
---|
406 | QXmlStreamReader reader(xml);
|
---|
407 |
|
---|
408 | ParseStage ps = ParseBeginning;
|
---|
409 | QXmlStreamReader::TokenType tt = QXmlStreamReader::NoToken;
|
---|
410 | int iv = 0;
|
---|
411 | do {
|
---|
412 | tt = reader.readNext();
|
---|
413 | if (tt == QXmlStreamReader::StartElement) {
|
---|
414 | ps = nextStage(ps, reader.name());
|
---|
415 | switch (ps) {
|
---|
416 | case ParseBeginning:
|
---|
417 | case ParseWithinRoot:
|
---|
418 | break;
|
---|
419 | case ParseError:
|
---|
420 | reader.raiseError(QApplication::translate("DeviceProfile", "An invalid tag <%1> was encountered.").arg(reader.name().toString()));
|
---|
421 | tt = QXmlStreamReader::Invalid;
|
---|
422 | break;
|
---|
423 | case ParseName:
|
---|
424 | d.m_name = reader.readElementText();
|
---|
425 | break;
|
---|
426 | case ParseFontFamily:
|
---|
427 | d.m_fontFamily = reader.readElementText();
|
---|
428 | break;
|
---|
429 | case ParseFontPointSize:
|
---|
430 | if (readIntegerElement(reader, &iv)) {
|
---|
431 | d.m_fontPointSize = iv;
|
---|
432 | } else {
|
---|
433 | tt = QXmlStreamReader::Invalid;
|
---|
434 | }
|
---|
435 | break;
|
---|
436 | case ParseDPIX:
|
---|
437 | if (readIntegerElement(reader, &iv)) {
|
---|
438 | d.m_dpiX = iv;
|
---|
439 | } else {
|
---|
440 | tt = QXmlStreamReader::Invalid;
|
---|
441 | }
|
---|
442 | break;
|
---|
443 | case ParseDPIY:
|
---|
444 | if (readIntegerElement(reader, &iv)) {
|
---|
445 | d.m_dpiY = iv;
|
---|
446 | } else {
|
---|
447 | tt = QXmlStreamReader::Invalid;
|
---|
448 | }
|
---|
449 | break;
|
---|
450 | case ParseStyle:
|
---|
451 | d.m_style = reader.readElementText();
|
---|
452 | break;
|
---|
453 | }
|
---|
454 | }
|
---|
455 | } while (tt != QXmlStreamReader::Invalid && tt != QXmlStreamReader::EndDocument);
|
---|
456 |
|
---|
457 | if (reader.hasError()) {
|
---|
458 | *errorMessage = reader.errorString();
|
---|
459 | return false;
|
---|
460 | }
|
---|
461 |
|
---|
462 | return true;
|
---|
463 | }
|
---|
464 | }
|
---|
465 |
|
---|
466 | QT_END_NAMESPACE
|
---|
467 |
|
---|