/* For general Scribus (>=1.3.2) copyright and licensing information please refer to the COPYING file provided with the program. Following this notice may exist a copyright and/or license notice that predates the release of Scribus 1.3.2 for which a new license (GPL+exception) is in place. */ #include #include #include "commonstrings.h" #include "sctextstruct.h" #include "scfonts.h" #include "resourcecollection.h" #include "styles/style.h" #include "charstyle.h" #include "desaxe/saxiohelper.h" #include "desaxe/simple_actions.h" #include "prefsmanager.h" #include "util_math.h" StyleFlag& StyleFlag::operator&= (const StyleFlag& right){ int result = static_cast(value) & static_cast(right.value); value = static_cast(result); return *this; } StyleFlag& StyleFlag::operator|= (const StyleFlag& right) { int result = static_cast(value) | static_cast(right.value); value = static_cast(result); return *this; } StyleFlag StyleFlag::operator& (const StyleFlag& right) { int val = static_cast(value) & static_cast(right.value); StyleFlag result(static_cast(val)); return result; } StyleFlag StyleFlag::operator& (int right) { int val = static_cast(value) & right; StyleFlag result(static_cast(val)); return result; } StyleFlag StyleFlag::operator| (const StyleFlag& right) { int val = static_cast(value) | static_cast(right.value); StyleFlag result(static_cast(val)); return result; } StyleFlag StyleFlag::operator^ (const StyleFlag& right) { int val = static_cast(value) ^ static_cast(right.value); StyleFlag result(static_cast(val)); return result; } StyleFlag StyleFlag::operator^ (int right) { int val = static_cast(value) ^ right; StyleFlag result(static_cast(val)); return result; } StyleFlag StyleFlag::operator~ () { int val = ~ static_cast(value); StyleFlag result(static_cast(val)); return result; } bool StyleFlag::operator== (const StyleFlag& right) const { int result = static_cast( (value ^ right.value) & ScStyle_UserStyles); return (result == 0); } bool StyleFlag::operator== (const StyleFlagValue right) const { int result = static_cast( (value ^ right) & ScStyle_UserStyles); return (result == 0); } bool StyleFlag::operator== (int right) const { int result = static_cast( (value ^ right) & ScStyle_UserStyles); return (result == 0); } bool StyleFlag::operator!= (const StyleFlag& right) const { return !(*this==right); } bool StyleFlag::operator!= (const StyleFlagValue right) const { return !(*this==right); } void CharStyle::applyCharStyle(const CharStyle & other) { if (other.hasParent() && (other.parent() != Style::INHERIT_PARENT)) { setStyle(other); return; } Style::applyStyle(other); #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \ if (! other.inh_##attr_NAME) \ set##attr_NAME(other.m_##attr_NAME); #include "charstyle.attrdefs.cxx" #undef ATTRDEF updateFeatures(); } void CharStyle::eraseCharStyle(const CharStyle & other) { other.validate(); Style::eraseStyle(other); #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \ if (!inh_##attr_NAME && m_##attr_NAME == other.m_##attr_NAME) \ reset##attr_NAME(); #include "charstyle.attrdefs.cxx" #undef ATTRDEF updateFeatures(); } void CharStyle::eraseDirectFormatting() { #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \ if (!inh_##attr_NAME) \ reset##attr_NAME(); #include "charstyle.attrdefs.cxx" #undef ATTRDEF updateFeatures(); } bool CharStyle::equiv(const Style & other) const { other.validate(); const CharStyle * oth = dynamic_cast ( & other ); return oth && parent() == oth->parent() #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \ && (inh_##attr_NAME == oth->inh_##attr_NAME) \ && (inh_##attr_NAME || isequiv(m_##attr_NAME, oth->m_##attr_NAME)) #include "charstyle.attrdefs.cxx" #undef ATTRDEF ; } QString CharStyle::displayName() const { if ( isDefaultStyle() ) return CommonStrings::trDefaultCharacterStyle; if ( hasName() || !hasParent() || ! m_context) return name(); // else if ( inheritsAll() ) // return parent()->displayName(); else return parentStyle()->displayName() + "+"; } QString CharStyle::asString() const { QString result; if ( !inh_Font ) result += QObject::tr("font %1 ").arg(font().scName()); if ( !inh_FontSize ) result += QObject::tr("size %1 ").arg(fontSize()); if ( !inh_Features ) result += QObject::tr("+style "); if ( !inh_StrokeColor || !inh_StrokeShade || !inh_FillColor || !inh_FillShade ) result += QObject::tr("+color "); if ( !inh_UnderlineWidth || !inh_UnderlineOffset ) result += underlineWidth() > 0 ? QObject::tr("+underline ") : QObject::tr("-underline "); if ( !inh_StrikethruWidth || !inh_StrikethruOffset ) result += strikethruWidth() > 0 ? QObject::tr("+strikeout ") : QObject::tr("-strikeout "); if ( !inh_ShadowXOffset || !inh_ShadowYOffset ) result += shadowXOffset() != 0 || shadowYOffset() != 0 ? QObject::tr("+shadow ") : QObject::tr("-shadow "); if ( !inh_OutlineWidth ) result += outlineWidth() > 0 ? QObject::tr("+outline ") : QObject::tr("-outline "); if ( !inh_Tracking ) result += tracking() > 0 ? QObject::tr("+tracking %1 ").arg(tracking()) : QObject::tr("-tracking "); if ( !inh_BaselineOffset ) result += QObject::tr("+baseline %1 ").arg(baselineOffset()); if ( !inh_ScaleH || !inh_ScaleV ) result += QObject::tr("+stretch "); if ( hasParent() ) result += QObject::tr("parent= %1").arg(parent()); return result.trimmed(); } void CharStyle::update(const StyleContext* context) { Style::update(context); const CharStyle * oth = dynamic_cast ( parentStyle() ); if (oth) { #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \ if (inh_##attr_NAME) \ m_##attr_NAME = oth->attr_GETTER(); #include "charstyle.attrdefs.cxx" #undef ATTRDEF } updateFeatures(); } const QString CharStyle::INHERIT = "inherit"; const QString CharStyle::BOLD = "bold"; const QString CharStyle::ITALIC = "italic"; const QString CharStyle::UNDERLINE = "underline"; const QString CharStyle::UNDERLINEWORDS = "underlinewords"; const QString CharStyle::STRIKETHROUGH = "strike"; const QString CharStyle::SUPERSCRIPT = "superscript"; const QString CharStyle::SUBSCRIPT = "subscript"; const QString CharStyle::OUTLINE = "outline"; const QString CharStyle::SHADOWED = "shadowed"; const QString CharStyle::ALLCAPS = "allcaps"; const QString CharStyle::SMALLCAPS = "smallcaps"; // This is for loading legacy docs only. Scribus 1.3.4 should write smart hyphens in another way static const QString SHYPHEN = "shyphen"; QStringList StyleFlag::featureList() const { QStringList result(CharStyle::INHERIT); if (*this & ScStyle_Underline) result << CharStyle::UNDERLINE; if (*this & ScStyle_UnderlineWords) result << CharStyle::UNDERLINEWORDS; if (*this & ScStyle_Strikethrough) result << CharStyle::STRIKETHROUGH; if (*this & ScStyle_Superscript) result << CharStyle::SUPERSCRIPT; if (*this & ScStyle_Subscript) result << CharStyle::SUBSCRIPT; if (*this & ScStyle_Outline) result << CharStyle::OUTLINE; if (*this & ScStyle_Shadowed) result << CharStyle::SHADOWED; if (*this & ScStyle_AllCaps) result << CharStyle::ALLCAPS; if (*this & ScStyle_SmallCaps) result << CharStyle::SMALLCAPS; if (*this & ScStyle_HyphenationPossible) result << SHYPHEN; return result; } void CharStyle::updateFeatures() { m_Effects &= ~ScStyle_UserStyles; runFeatures(m_Features, dynamic_cast(parentStyle())); /* need to access global fontlist :-/ if (!font().name().endsWith(fontVariant())) { m_font = ScFonts.instance().findFont(font().family() + fontVariant()); } */ } void CharStyle::runFeatures(const QStringList& featureList, const CharStyle* parent) { QStringList::ConstIterator it; for (it = featureList.begin(); it != featureList.end(); ++it) { QString feature = it->trimmed(); if (feature == INHERIT) { if (parent) runFeatures(parent->features(), dynamic_cast(parent->parentStyle())); } else if (feature == BOLD) { // select bolder font } else if (feature == ITALIC) { // select italic font } else if (feature == UNDERLINE) { m_Effects |= ScStyle_Underline; } else if (feature == UNDERLINEWORDS) { m_Effects |= ScStyle_UnderlineWords; } else if (feature == STRIKETHROUGH) { m_Effects |= ScStyle_Strikethrough; } else if (feature == SUPERSCRIPT) { m_Effects |= ScStyle_Superscript; } else if (feature == SUBSCRIPT) { m_Effects |= ScStyle_Subscript; } else if (feature == OUTLINE) { m_Effects |= ScStyle_Outline; } else if (feature == SHADOWED) { m_Effects |= ScStyle_Shadowed; } else if (feature == ALLCAPS) { m_Effects |= ScStyle_AllCaps; } else if (feature == SMALLCAPS) { m_Effects |= ScStyle_SmallCaps; } else if (feature == SHYPHEN) { m_Effects |= ScStyle_HyphenationPossible; } else if (feature.startsWith("-")) { QString no_feature = feature.mid(1); if (no_feature == BOLD) { // deselect bolder font } else if (no_feature == ITALIC) { // deselect italic font } else if (no_feature == UNDERLINE) { m_Effects &= ~ScStyle_Underline; } else if (no_feature == UNDERLINEWORDS) { m_Effects &= ~ScStyle_UnderlineWords; } else if (no_feature == STRIKETHROUGH) { m_Effects &= ~ScStyle_Strikethrough; } else if (no_feature == SUPERSCRIPT) { m_Effects &= ~ScStyle_Superscript; } else if (no_feature == SUBSCRIPT) { m_Effects &= ~ScStyle_Subscript; } else if (no_feature == OUTLINE) { m_Effects &= ~ScStyle_Outline; } else if (no_feature == SHADOWED) { m_Effects &= ~ScStyle_Shadowed; } else if (no_feature == ALLCAPS) { m_Effects &= ~ScStyle_AllCaps; } else if (no_feature == SMALLCAPS) { m_Effects &= ~ScStyle_SmallCaps; } else { qDebug("CharStyle: unknown feature: %s", feature.toLocal8Bit().constData()); } } else { qDebug("CharStyle: unknown feature: %s", feature.toLocal8Bit().constData()); } } } void CharStyle::setStyle(const CharStyle& other) { other.validate(); setParent(other.parent()); m_contextversion = -1; #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \ inh_##attr_NAME = other.inh_##attr_NAME; \ m_##attr_NAME = other.m_##attr_NAME; #include "charstyle.attrdefs.cxx" #undef ATTRDEF updateFeatures(); } void CharStyle::getNamedResources(ResourceCollection& lists) const { for (const Style* sty = parentStyle(); sty != NULL; sty = sty->parentStyle()) lists.collectCharStyle(sty->name()); lists.collectColor(fillColor()); lists.collectColor(strokeColor()); lists.collectFont(font().scName()); } void CharStyle::replaceNamedResources(ResourceCollection& newNames) { QMap::ConstIterator it; if (!inh_FillColor && (it = newNames.colors().find(fillColor())) != newNames.colors().end()) setFillColor(it.value()); if (!inh_StrokeColor && (it = newNames.colors().find(strokeColor())) != newNames.colors().end()) setStrokeColor(it.value()); if (hasParent() && (it = newNames.charStyles().find(parent())) != newNames.charStyles().end()) setParent(it.value()); if (!inh_Font && (it = newNames.fonts().find(font().scName())) != newNames.fonts().end()) setFont(newNames.availableFonts->findFont(it.value(), NULL)); updateFeatures(); } /* bool CharStyle::definesAll() const { return definesLineSpacing() && definesLeftMargin() && definesRightMargin() && definesFirstIndent() && definesAlignment() && definesGapBefore() && definesLineSpacingMode() && definesGapAfter() && definesHasDropCap() && definesDropCapOffset() && definesDropCapLines() && definesUseBaselineGrid() && charStyle().definesAll() ; } // equiv. to "*this == CharStyle()" bool CharStyle::inheritsAll() const { return inheritsLineSpacing() && inheritsLeftMargin() && inheritsRightMargin() && inheritsFirstIndent() && inheritsAlignment() && inheritsGapBefore() && inheritsLineSpacingMode() && inheritsGapAfter() && inheritsHasDropCap() && inheritsDropCapOffset() && inheritsDropCapLines() && inheritsUseBaselineGrid() && charStyle().inheritsAll() ; } */ Xml_string toXMLString(StyleFlag val) { return toXMLString(static_cast(val & ScStyle_UserStyles)); } void CharStyle::saxx(SaxHandler& handler, const Xml_string& elemtag) const { Xml_attr att; Style::saxxAttributes(att); #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \ if (!inh_##attr_NAME) \ att.insert(# attr_NAME, toXMLString(m_##attr_NAME)); #include "charstyle.attrdefs.cxx" #undef ATTRDEF if (!name().isEmpty()) att["id"] = mkXMLName(elemtag + name()); handler.begin(elemtag, att); // if (hasParent() && parentStyle()) // parentStyle()->saxx(handler); handler.end(elemtag); } template<> StyleFlag parse(const Xml_string& str) { return StyleFlag(parseInt(str)); } template<> ScFace parse(const Xml_string& str) { // FIXME: enable font substitution here return PrefsManager::instance()->appPrefs.AvailFonts[str]; } using namespace desaxe; const Xml_string CharStyle::saxxDefaultElem("charstyle"); void CharStyle::desaxeRules(const Xml_string& prefixPattern, Digester& ruleset, Xml_string elemtag) { Xml_string stylePrefix(Digester::concat(prefixPattern, elemtag)); ruleset.addRule(stylePrefix, Factory()); ruleset.addRule(stylePrefix, IdRef()); Style::desaxeRules(prefixPattern, ruleset, elemtag); #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \ ruleset.addRule(stylePrefix, SetAttributeWithConversion ( & CharStyle::set##attr_NAME, # attr_NAME, &parse )); #include "charstyle.attrdefs.cxx" #undef ATTRDEF }