source: trunk/tools/designer/src/lib/shared/deviceprofile.cpp@ 1168

Last change on this file since 1168 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 13.3 KB
Line 
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
62static const char *dpiXPropertyC = "_q_customDpiX";
63static const char *dpiYPropertyC = "_q_customDpiY";
64
65// XML serialization
66static const char *xmlVersionC="1.0";
67static const char *rootElementC="deviceprofile";
68static const char *nameElementC = "name";
69static const char *fontFamilyElementC = "fontfamily";
70static const char *fontPointSizeElementC = "fontpointsize";
71static const char *dPIXElementC = "dpix";
72static const char *dPIYElementC = "dpiy";
73static 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
85QT_BEGIN_NAMESPACE
86
87namespace qdesigner_internal {
88
89// ---------------- DeviceProfileData
90class DeviceProfileData : public QSharedData {
91public:
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
104DeviceProfileData::DeviceProfileData() :
105 m_fontPointSize(-1),
106 m_dpiX(-1),
107 m_dpiY(-1)
108{
109}
110
111void 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
120void 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
130DeviceProfile::DeviceProfile() :
131 m_d(new DeviceProfileData)
132{
133}
134
135DeviceProfile::DeviceProfile(const DeviceProfile &o) :
136 m_d(o.m_d)
137
138{
139}
140
141DeviceProfile& DeviceProfile::operator=(const DeviceProfile &o)
142{
143 m_d.operator=(o.m_d);
144 return *this;
145}
146
147DeviceProfile::~DeviceProfile()
148{
149}
150
151void DeviceProfile::clear()
152{
153 m_d->clear();
154}
155
156bool DeviceProfile::isEmpty() const
157{
158 return m_d->m_name.isEmpty();
159}
160
161QString DeviceProfile::fontFamily() const
162{
163 return m_d->m_fontFamily;
164}
165
166void DeviceProfile::setFontFamily(const QString &f)
167{
168 m_d->m_fontFamily = f;
169}
170
171int DeviceProfile::fontPointSize() const
172{
173 return m_d->m_fontPointSize;
174}
175
176void DeviceProfile::setFontPointSize(int p)
177{
178 m_d->m_fontPointSize = p;
179}
180
181QString DeviceProfile::style() const
182{
183 return m_d->m_style;
184}
185
186void DeviceProfile::setStyle(const QString &s)
187{
188 m_d->m_style = s;
189}
190
191int DeviceProfile::dpiX() const
192{
193 return m_d->m_dpiX;
194}
195
196void DeviceProfile::setDpiX(int d)
197{
198 m_d->m_dpiX = d;
199}
200
201int DeviceProfile::dpiY() const
202{
203 return m_d->m_dpiY;
204}
205
206void DeviceProfile::setDpiY(int d)
207{
208 m_d->m_dpiY = d;
209}
210
211void DeviceProfile::fromSystem()
212{
213 m_d->fromSystem();
214}
215
216QString DeviceProfile::name() const
217{
218 return m_d->m_name;
219}
220
221void DeviceProfile::setName(const QString &n)
222{
223 m_d->m_name = n;
224}
225
226void DeviceProfile::systemResolution(int *dpiX, int *dpiY)
227{
228 const QDesktopWidget *dw = qApp->desktop();
229 *dpiX = dw->logicalDpiX();
230 *dpiY = dw->logicalDpiY();
231}
232
233class FriendlyWidget : public QWidget {
234 friend class DeviceProfile;
235};
236
237void 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
244QString 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
254static 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
283void 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
293void 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
311bool 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
320static 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
327QString 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) */
353enum ParseStage { ParseBeginning, ParseWithinRoot,
354 ParseName, ParseFontFamily, ParseFontPointSize, ParseDPIX, ParseDPIY, ParseStyle,
355 ParseError };
356
357static 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
390static 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
401bool 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
466QT_END_NAMESPACE
467
Note: See TracBrowser for help on using the repository browser.