|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Designer of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
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 |