Subversion Repositories Scribus

Rev

Rev 12337 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 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 <QObject>
#include <QDebug>

#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"

StyleFlag& StyleFlag::operator&= (const StyleFlag& right){        
        int result = static_cast<int>(value) & static_cast<int>(right.value);        
        value = static_cast<StyleFlagValue>(result);
        return *this;
}

StyleFlag& StyleFlag::operator|= (const StyleFlag& right)
{
        int result = static_cast<int>(value) | static_cast<int>(right.value);
        value = static_cast<StyleFlagValue>(result);
        return *this;
}

StyleFlag StyleFlag::operator& (const StyleFlag& right)
{
        int val = static_cast<int>(value) & static_cast<int>(right.value);
        StyleFlag result(static_cast<StyleFlagValue>(val));
        return result;
}

StyleFlag StyleFlag::operator& (int right)
{
        int val = static_cast<int>(value) & right;
        StyleFlag result(static_cast<StyleFlagValue>(val));
        return result;
}

StyleFlag StyleFlag::operator| (const StyleFlag& right)
{        
        int val = static_cast<int>(value) | static_cast<int>(right.value);
        StyleFlag result(static_cast<StyleFlagValue>(val));
        return result;
}

StyleFlag StyleFlag::operator^ (const StyleFlag& right)
{
        int val = static_cast<int>(value) ^ static_cast<int>(right.value);
        StyleFlag result(static_cast<StyleFlagValue>(val));
        return result;
}

StyleFlag StyleFlag::operator^  (int right)
{
        int val = static_cast<int>(value) ^ right;
        StyleFlag result(static_cast<StyleFlagValue>(val));
        return result;
}

StyleFlag StyleFlag::operator~ ()
{
        int val = ~ static_cast<int>(value);
        StyleFlag result(static_cast<StyleFlagValue>(val));
        return result;
}

bool StyleFlag::operator== (const StyleFlag& right) const
{        
        int result = static_cast<int>( (value ^ right.value) & ScStyle_UserStyles);
        return (result == 0);
}

bool StyleFlag::operator== (const StyleFlagValue right) const
{
        int result = static_cast<int>( (value ^ right) & ScStyle_UserStyles);
        return (result == 0);
}

bool StyleFlag::operator== (int right) const
{
        int result = static_cast<int>( (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 QString& other)
{
        Style::applyStyle(other);
        CharStyle *pOther = StylesLibrary::Char(other);
#define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \
        if (! pOther->inh_##attr_NAME) \
        set##attr_NAME(pOther->m_##attr_NAME);

#include "charstyle.attrdefs.cxx"
#undef ATTRDEF
        updateFeatures();
}


void CharStyle::eraseCharStyle(const QString& other)
{
        Style::eraseStyle(other);
        CharStyle *pOther = StylesLibrary::Char(other);
        pOther->validate();
#define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \
        if (!inh_##attr_NAME && m_##attr_NAME == pOther->m_##attr_NAME) \
                reset##attr_NAME();

#include "charstyle.attrdefs.cxx"
#undef ATTRDEF
        updateFeatures();
}

bool CharStyle::equiv(const QString & other) const
{
        const CharStyle * oth = StylesLibrary::Char( 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 || 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();
}





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<const CharStyle*>(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<const CharStyle*>(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 QString& other)
{
        CharStyle *pOther = StylesLibrary::Char(other);
        pOther->validate();
        setParent(pOther->parent());
#define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \
        inh_##attr_NAME = pOther->inh_##attr_NAME; \
        m_##attr_NAME = pOther->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->uuid());
        lists.collectColor(fillColor());
        lists.collectColor(strokeColor());
        lists.collectFont(font().scName());
}


void CharStyle::replaceNamedResources(ResourceCollection& newNames)
{
        QMap<QString,QString>::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<unsigned int>(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 (!uuid().isEmpty())
                att["id"] = mkXMLName(elemtag + uuid());
        handler.begin(elemtag, att);
//      if (hasParent() && parentStyle())
//              parentStyle()->saxx(handler);  
        handler.end(elemtag);
}



template<>
StyleFlag parse<StyleFlag>(const Xml_string& str)
{
        return StyleFlag(parseInt(str));
}

template<>
ScFace parse<ScFace>(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<CharStyle>());
        ruleset.addRule(stylePrefix, IdRef<CharStyle>());
        Style::desaxeRules<CharStyle>(prefixPattern, ruleset, elemtag);
#define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT) \
        ruleset.addRule(stylePrefix, SetAttributeWithConversion<CharStyle, attr_TYPE> ( & CharStyle::set##attr_NAME,  # attr_NAME, &parse<attr_TYPE> ));

#include "charstyle.attrdefs.cxx"
#undef ATTRDEF         
}