/****************************************************************************
**
** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (developer.feedback@nokia.com)
**
** This file is part of the HbCore module of the UI Extensions for Mobile.
**
** GNU Lesser General Public License Usage
** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at developer.feedback@nokia.com.
**
****************************************************************************/
#include "hbcssformatter_p.h"
/*!
\class HbCssFormatter
\brief Internal class for converting in-memory CSS structures (declarations and rules)
to string representations.
These functions only work in builds configured with the --developer flag; in other
builds the implementation is defined-out to reduce ROM size, and an empty string
is returned from all functions.
Example usage would be:
HbVector<HbCss::WeightedRule> rules;
[...]
qDebug() << HbCssFormatter::weightedStyleRulesToString(rules);
*/
static QString LAST_FILENAME_WRITTEN = "";
/*!
@internal
*/
QString HbCssFormatter::weightedStyleRulesToString(const HbVector<HbCss::WeightedRule> &rules)
{
QString str;
#ifdef HB_DEVELOPER
foreach (const HbCss::WeightedRule &rule, rules) {
if (str.length() > 0) {
str.append("\n");
}
str.append(styleRuleToString(rule.second, rule.first));
}
#else
Q_UNUSED( rules );
#endif
return str;
}
/*!
@internal
*/
QString HbCssFormatter::weightedDeclarationsToString(
const HbVector<HbCss::WeightedDeclaration> &decls)
{
QString str;
#ifdef HB_DEVELOPER
foreach (const HbCss::WeightedDeclaration &decl, decls) {
if (str.length() > 0) {
str.append("\n");
}
str.append(declarationToString(decl.second));
str.append("(");
str.append(QString::number(decl.first));
str.append(")");
}
#else
Q_UNUSED( decls );
#endif
return str;
}
/*!
@internal
*/
QString HbCssFormatter::styleRulesToString(const HbVector<HbCss::StyleRule> &rules)
{
QString str;
#ifdef HB_DEVELOPER
foreach (const HbCss::StyleRule &rule, rules) {
if (str.length() > 0) {
str.append("\n\n");
}
str.append(styleRuleToString(rule));
}
#else
Q_UNUSED( rules );
#endif
return str;
}
/*!
@internal
*/
QString HbCssFormatter::styleRulesToHtml(const HbVector<HbCss::StyleRule> &rules)
{
QString str;
#ifdef HB_DEVELOPER
QMap<QString, QVector<QString> > usedProperties;
QVector<const HbCss::Declaration*> usedDecls;
for (int i=rules.count()-1; i>=0; i--) {
const HbCss::StyleRule &rule = rules.at(i);
foreach (const HbCss::Selector &sel, rule.selectors) {
foreach (const HbCss::BasicSelector &basi, sel.basicSelectors ) {
QVector<QString> names;
if (basi.pseudos.count() == 0) {
names.append("*");
} else {
foreach (const HbCss::Pseudo &pseu, basi.pseudos) {
names.append(pseu.name);
}
}
foreach (const QString &name, names) {
for (int j=rule.declarations.count()-1; j>=0; j--) {
const HbCss::Declaration &decl = rule.declarations.at(j);
QString prop = decl.property;
if (usedProperties[name].contains(prop)) {
usedDecls.append(&decl);
} else {
usedProperties[name].append(prop);
// TODO: Add grouped properties here, eg border-left
}
}
}
}
}
}
LAST_FILENAME_WRITTEN = "";
foreach (const HbCss::StyleRule &rule, rules) {
if (str.length() > 0) {
str.append("<br/><br/>");
}
str.append(styleRuleToHtml(rule, usedDecls));
}
#else
Q_UNUSED(rules);
#endif
return str;
}
/*!
@internal
*/
QString HbCssFormatter::declarationsToString(const HbVector<HbCss::Declaration> &decls)
{
QString str;
#ifdef HB_DEVELOPER
foreach (const HbCss::Declaration &decl, decls ) {
str.append("\n ");
str.append(declarationToString(decl));
}
#else
Q_UNUSED( decls );
#endif
return str;
}
// Worker function
QString HbCssFormatter::styleRuleToString(const HbCss::StyleRule &rule, int specificity)
{
QString str;
#ifdef HB_DEVELOPER
str.append(selectorsToString(rule.selectors, specificity));
str.append("\n{");
str.append(declarationsToString(rule.declarations));
str.append("\n}");
#else
Q_UNUSED(rule);
Q_UNUSED(specificity);
#endif
return str;
}
// Worker function
QString HbCssFormatter::styleRuleToHtml(
const HbCss::StyleRule &rule,
QVector<const HbCss::Declaration*> usedDecls,
int specificity)
{
QString str;
#ifdef HB_DEVELOPER
#ifdef HB_CSS_INSPECTOR
if (rule.owningStyleSheet.get()) {
if (rule.owningStyleSheet->fileName != LAST_FILENAME_WRITTEN) {
str.append("<p class=\"filename\">");
str.append(rule.owningStyleSheet->fileName);
str.append("</p>");
LAST_FILENAME_WRITTEN = rule.owningStyleSheet->fileName;
}
} else {
str.append("<p class=\"filename\">[Unknown origin]</p>");
}
#endif
str.append("<p class=\"selectors\">");
str.append(selectorsToString(rule.selectors, specificity, true));
str.append("</p>{");
for (int i=0; i<rule.declarations.count(); i++) {
str.append("<br/> ");
const HbCss::Declaration &decl = rule.declarations.at(i);
bool overridden = usedDecls.contains(&decl);
if(overridden) str.append("<span class=\"overridden\">");
str.append(declarationToString(decl, true));
if(overridden) str.append("</span>");
}
str.append("<br/>}");
#else
Q_UNUSED(rule);
Q_UNUSED(usedDecls);
Q_UNUSED(specificity);
#endif
return str;
}
// Worker function
QString HbCssFormatter::selectorsToString(
const HbVector<HbCss::Selector> &selectors,
int specificity,
bool html)
{
QString str;
#ifdef HB_DEVELOPER
foreach (const HbCss::Selector &sel, selectors) {
if (str.length() > 0) {
str.append(',');
}
if (html) str.append("<span class=\"selector\">");
str.append(selectorToString(sel, html));
if (specificity >= 0) {
str.append(" (specificity: 0x");
str.append(QString::number(specificity, 16));
str.append(")");
}
if (html) str.append("</span>");
}
#else
Q_UNUSED( selectors );
Q_UNUSED( specificity );
Q_UNUSED( html );
#endif
return str;
}
// Worker function
QString HbCssFormatter::declarationToString(const HbCss::Declaration &decl, bool html)
{
QString str;
#ifdef HB_DEVELOPER
if(html) str.append("<span class=\"property\">");
str.append(decl.property);
if(html) str.append("</span>");
str.append(":");
if(html) str.append("<span class=\"value\">");
foreach (const HbCss::Value &val, decl.values) {
str.append(" ");
switch (val.type) {
case HbCss::Value::ExpressionNegative:
str.append("-");
case HbCss::Value::Expression:
str.append("expr(");
str.append(val.original);
str.append(")");
break;
case HbCss::Value::VariableNegative:
str.append("-");
case HbCss::Value::Variable:
str.append("var(");
str.append(val.original);
str.append(")");
break;
case HbCss::Value::KnownIdentifier:
str.append(val.original);
break;
case HbCss::Value::LengthInUnits:
str.append(val.variant.toString());
str.append("un");
break;
case HbCss::Value::LengthInPixels:
str.append(val.variant.toString());
str.append("px");
break;
case HbCss::Value::LengthInMillimeters:
str.append(val.variant.toString());
str.append("mm");
break;
default:
str.append(val.variant.toString());
}
}
if(html) str.append("</span>");
str.append(";");
#else
Q_UNUSED( decl );
Q_UNUSED( html );
#endif
return str;
}
// Worker function
QString HbCssFormatter::selectorToString(const HbCss::Selector &sel, bool html)
{
QString str;
#ifdef HB_DEVELOPER
foreach (const HbCss::BasicSelector &basi, sel.basicSelectors ) {
if (basi.elementName.length() > 0) {
str.append( basi.elementName );
}else{
str.append("*");
}
foreach (const HbString &iidd, basi.ids ) {
str.append('#');
str.append(iidd);
}
foreach (const HbCss::AttributeSelector &atri, basi.attributeSelectors) {
if(html) str.append("<span class=\"attr\">");
str.append('[');
if (atri.negated) {
str.append('!');
}
if (atri.valueMatchCriterium == HbCss::AttributeSelector::MatchEqual) {
str.append(atri.name);
str.append('=');
str.append(atri.value);
} else if (atri.valueMatchCriterium == HbCss::AttributeSelector::MatchBeginsWith) {
str.append("startsWith(@");
str.append(atri.name);
str.append(',');
str.append(atri.value);
str.append(')');
} else if (atri.valueMatchCriterium == HbCss::AttributeSelector::MatchContains) {
str.append("contains(@");
str.append(atri.name);
str.append(',');
str.append(atri.value);
str.append(')');
} else {
str.append(atri.name);
}
str.append(']');
if(html) str.append("</span>");
}
foreach (const HbCss::Pseudo &pseu, basi.pseudos) {
if(html) str.append("<span class=\"pseudo\">");
if (pseu.type == HbCss::PseudoClass_Unknown) {
str.append("::");
} else {
str.append(":");
}
if (pseu.negated) {
str.append('!');
}
str.append(pseu.name);
if(html) str.append("</span>");
}
if (basi.relationToNext == HbCss::BasicSelector::MatchNextSelectorIfAncestor) {
str.append(' ');
} else if (basi.relationToNext == HbCss::BasicSelector::MatchNextSelectorIfParent) {
str.append(html ? " > " : " > ");
} else if (basi.relationToNext == HbCss::BasicSelector::MatchNextSelectorIfPreceeds) {
str.append(" + ");
}
}
#else
Q_UNUSED( sel );
Q_UNUSED( html );
#endif
return str;
}