/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the Qt Designer of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "deviceprofile_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include static const char *dpiXPropertyC = "_q_customDpiX"; static const char *dpiYPropertyC = "_q_customDpiY"; // XML serialization static const char *xmlVersionC="1.0"; static const char *rootElementC="deviceprofile"; static const char *nameElementC = "name"; static const char *fontFamilyElementC = "fontfamily"; static const char *fontPointSizeElementC = "fontpointsize"; static const char *dPIXElementC = "dpix"; static const char *dPIYElementC = "dpiy"; static const char *styleElementC = "style"; /* DeviceProfile: * For preview purposes (preview, widget box, new form dialog), the * QDesignerFormBuilder applies the settings to the form main container * (Point being here that the DPI must be set directly for size calculations * to be correct). * For editing purposes, FormWindow applies the settings to the form container * as not to interfere with the font settings of the form main container. * In addition, the widgetfactory maintains the system settings style * and applies it when creating widgets. */ QT_BEGIN_NAMESPACE namespace qdesigner_internal { // ---------------- DeviceProfileData class DeviceProfileData : public QSharedData { public: DeviceProfileData(); void fromSystem(); void clear(); QString m_fontFamily; int m_fontPointSize; QString m_style; int m_dpiX; int m_dpiY; QString m_name; }; DeviceProfileData::DeviceProfileData() : m_fontPointSize(-1), m_dpiX(-1), m_dpiY(-1) { } void DeviceProfileData::clear() { m_fontPointSize = -1; m_dpiX = 0; m_dpiY = 0; m_name.clear(); m_style.clear(); } void DeviceProfileData::fromSystem() { const QFont appFont = QApplication::font(); m_fontFamily = appFont.family(); m_fontPointSize = appFont.pointSize(); DeviceProfile::systemResolution(&m_dpiX, &m_dpiY); m_style.clear(); } // ---------------- DeviceProfile DeviceProfile::DeviceProfile() : m_d(new DeviceProfileData) { } DeviceProfile::DeviceProfile(const DeviceProfile &o) : m_d(o.m_d) { } DeviceProfile& DeviceProfile::operator=(const DeviceProfile &o) { m_d.operator=(o.m_d); return *this; } DeviceProfile::~DeviceProfile() { } void DeviceProfile::clear() { m_d->clear(); } bool DeviceProfile::isEmpty() const { return m_d->m_name.isEmpty(); } QString DeviceProfile::fontFamily() const { return m_d->m_fontFamily; } void DeviceProfile::setFontFamily(const QString &f) { m_d->m_fontFamily = f; } int DeviceProfile::fontPointSize() const { return m_d->m_fontPointSize; } void DeviceProfile::setFontPointSize(int p) { m_d->m_fontPointSize = p; } QString DeviceProfile::style() const { return m_d->m_style; } void DeviceProfile::setStyle(const QString &s) { m_d->m_style = s; } int DeviceProfile::dpiX() const { return m_d->m_dpiX; } void DeviceProfile::setDpiX(int d) { m_d->m_dpiX = d; } int DeviceProfile::dpiY() const { return m_d->m_dpiY; } void DeviceProfile::setDpiY(int d) { m_d->m_dpiY = d; } void DeviceProfile::fromSystem() { m_d->fromSystem(); } QString DeviceProfile::name() const { return m_d->m_name; } void DeviceProfile::setName(const QString &n) { m_d->m_name = n; } void DeviceProfile::systemResolution(int *dpiX, int *dpiY) { const QDesktopWidget *dw = qApp->desktop(); *dpiX = dw->logicalDpiX(); *dpiY = dw->logicalDpiY(); } class FriendlyWidget : public QWidget { friend class DeviceProfile; }; void DeviceProfile::widgetResolution(const QWidget *w, int *dpiX, int *dpiY) { const FriendlyWidget *fw = static_cast(w); *dpiX = fw->metric(QPaintDevice::PdmDpiX); *dpiY = fw->metric(QPaintDevice::PdmDpiY); } QString DeviceProfile::toString() const { const DeviceProfileData &d = *m_d; QString rc; QTextStream(&rc) << "DeviceProfile:name=" << d.m_name << " Font=" << d.m_fontFamily << ' ' << d.m_fontPointSize << " Style=" << d.m_style << " DPI=" << d.m_dpiX << ',' << d.m_dpiY; return rc; } // Apply font to widget static void applyFont(const QString &family, int size, DeviceProfile::ApplyMode am, QWidget *widget) { QFont currentFont = widget->font(); if (currentFont.pointSize() == size && currentFont.family() == family) return; switch (am) { case DeviceProfile::ApplyFormParent: // Invisible form parent: Apply all widget->setFont(QFont(family, size)); break; case DeviceProfile::ApplyPreview: { // Preview: Apply only subproperties that have not been changed by designer properties bool apply = false; const uint resolve = currentFont.resolve(); if (!(resolve & QFont::FamilyResolved)) { currentFont.setFamily(family); apply = true; } if (!(resolve & QFont::SizeResolved)) { currentFont.setPointSize(size); apply = true; } if (apply) widget->setFont(currentFont); } break; } } void DeviceProfile::applyDPI(int dpiX, int dpiY, QWidget *widget) { int sysDPIX, sysDPIY; // Set dynamic variables in case values are different from system DPI systemResolution(&sysDPIX, &sysDPIY); if (dpiX != sysDPIX && dpiY != sysDPIY) { widget->setProperty(dpiXPropertyC, QVariant(dpiX)); widget->setProperty(dpiYPropertyC, QVariant(dpiY)); } } void DeviceProfile::apply(const QDesignerFormEditorInterface *core, QWidget *widget, ApplyMode am) const { if (isEmpty()) return; const DeviceProfileData &d = *m_d; if (!d.m_fontFamily.isEmpty()) applyFont(d.m_fontFamily, d.m_fontPointSize, am, widget); applyDPI(d.m_dpiX, d.m_dpiY, widget); if (!d.m_style.isEmpty()) { if (WidgetFactory *wf = qobject_cast(core->widgetFactory())) wf->applyStyleTopLevel(d.m_style, widget); } } bool DeviceProfile::equals(const DeviceProfile& rhs) const { const DeviceProfileData &d = *m_d; const DeviceProfileData &rhs_d = *rhs.m_d; return d.m_fontPointSize == rhs_d.m_fontPointSize && d.m_dpiX == rhs_d.m_dpiX && d.m_dpiY == rhs_d.m_dpiY && d.m_fontFamily == rhs_d.m_fontFamily && d.m_style == rhs_d.m_style && d.m_name == rhs_d.m_name; } static inline void writeElement(QXmlStreamWriter &writer, const QString &element, const QString &cdata) { writer.writeStartElement(element); writer.writeCharacters(cdata); writer.writeEndElement(); } QString DeviceProfile::toXml() const { const DeviceProfileData &d = *m_d; QString rc; QXmlStreamWriter writer(&rc); writer.writeStartDocument(QLatin1String(xmlVersionC)); writer.writeStartElement(QLatin1String(rootElementC)); writeElement(writer, QLatin1String(nameElementC), d.m_name); if (!d.m_fontFamily.isEmpty()) writeElement(writer, QLatin1String(fontFamilyElementC), d.m_fontFamily); if (d.m_fontPointSize >= 0) writeElement(writer, QLatin1String(fontPointSizeElementC), QString::number(d.m_fontPointSize)); if (d.m_dpiX > 0) writeElement(writer, QLatin1String(dPIXElementC), QString::number(d.m_dpiX)); if (d.m_dpiY > 0) writeElement(writer, QLatin1String(dPIYElementC), QString::number(d.m_dpiY)); if (!d.m_style.isEmpty()) writeElement(writer, QLatin1String(styleElementC), d.m_style); writer.writeEndElement(); writer.writeEndDocument(); return rc; } /* Switch stages when encountering a start element (state table) */ enum ParseStage { ParseBeginning, ParseWithinRoot, ParseName, ParseFontFamily, ParseFontPointSize, ParseDPIX, ParseDPIY, ParseStyle, ParseError }; static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement) { switch (currentStage) { case ParseBeginning: if (startElement == QLatin1String(rootElementC)) return ParseWithinRoot; break; case ParseWithinRoot: case ParseName: case ParseFontFamily: case ParseFontPointSize: case ParseDPIX: case ParseDPIY: case ParseStyle: if (startElement == QLatin1String(nameElementC)) return ParseName; if (startElement == QLatin1String(fontFamilyElementC)) return ParseFontFamily; if (startElement == QLatin1String(fontPointSizeElementC)) return ParseFontPointSize; if (startElement == QLatin1String(dPIXElementC)) return ParseDPIX; if (startElement == QLatin1String(dPIYElementC)) return ParseDPIY; if (startElement == QLatin1String(styleElementC)) return ParseStyle; break; case ParseError: break; } return ParseError; } static bool readIntegerElement(QXmlStreamReader &reader, int *v) { const QString e = reader.readElementText(); bool ok; *v = e.toInt(&ok); //: Reading a number for an embedded device profile if (!ok) reader.raiseError(QApplication::translate("DeviceProfile", "'%1' is not a number.").arg(e)); return ok; } bool DeviceProfile::fromXml(const QString &xml, QString *errorMessage) { DeviceProfileData &d = *m_d; d.fromSystem(); QXmlStreamReader reader(xml); ParseStage ps = ParseBeginning; QXmlStreamReader::TokenType tt = QXmlStreamReader::NoToken; int iv = 0; do { tt = reader.readNext(); if (tt == QXmlStreamReader::StartElement) { ps = nextStage(ps, reader.name()); switch (ps) { case ParseBeginning: case ParseWithinRoot: break; case ParseError: reader.raiseError(QApplication::translate("DeviceProfile", "An invalid tag <%1> was encountered.").arg(reader.name().toString())); tt = QXmlStreamReader::Invalid; break; case ParseName: d.m_name = reader.readElementText(); break; case ParseFontFamily: d.m_fontFamily = reader.readElementText(); break; case ParseFontPointSize: if (readIntegerElement(reader, &iv)) { d.m_fontPointSize = iv; } else { tt = QXmlStreamReader::Invalid; } break; case ParseDPIX: if (readIntegerElement(reader, &iv)) { d.m_dpiX = iv; } else { tt = QXmlStreamReader::Invalid; } break; case ParseDPIY: if (readIntegerElement(reader, &iv)) { d.m_dpiY = iv; } else { tt = QXmlStreamReader::Invalid; } break; case ParseStyle: d.m_style = reader.readElementText(); break; } } } while (tt != QXmlStreamReader::Invalid && tt != QXmlStreamReader::EndDocument); if (reader.hasError()) { *errorMessage = reader.errorString(); return false; } return true; } } QT_END_NAMESPACE