Scribus Developer Documentation - API
logo-pen

Scribus Developer Documentation - API

serializer.cpp

Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 /***************************************************************************
00008                           serializer.cpp  -  description
00009                              -------------------
00010     begin                : Sat May 5 2001
00011     copyright            : (C) 2001 by Franz Schmid
00012     email                : Franz.Schmid@altmuehlnet.de
00013  ***************************************************************************/
00014 
00015 /***************************************************************************
00016  *                                                                         *
00017  *   This program is free software; you can redistribute it and/or modify  *
00018  *   it under the terms of the GNU General Public License as published by  *
00019  *   the Free Software Foundation; either version 2 of the License, or     *
00020  *   (at your option) any later version.                                   *
00021  *                                                                         *
00022  ***************************************************************************/
00023 
00024 #include "serializer.h"
00025 #include "scribusdoc.h"
00026 #include "scribusstructs.h"
00027 #include "pageitem.h"
00028 #include "sccolor.h"
00029 #include "scpattern.h"
00030 #include "util.h"
00031 #include "util_math.h"
00032 #include "util_color.h"
00033 #include "resourcecollection.h"
00034 
00035 #include "desaxe/simple_actions.h"
00036 #include "desaxe/saxXML.h"
00037 #include "desaxe/uniqueid.h"
00038 
00039 #include <QTextCodec>
00040 #include <QList>
00041 #include <QDebug>
00042 
00043 using namespace desaxe;
00044 
00045 
00046 struct Collection
00047 {
00048     QList<PageItem*> items;
00049     ColorList colors;
00050     StyleSet<ParagraphStyle> pstyles;
00051     StyleSet<CharStyle> cstyles;
00052     QMap<QString,multiLine> lstyles;
00053     QList<QString> fonts;
00054     QList<QString> patterns;
00055 
00056     void collectItem(PageItem* p)              { items.append(p); }
00057     void collectColor(QString name, ScColor c) { colors[name] = c; }
00058     void collectStyle(ParagraphStyle* style)   { if (style && !style->name().isEmpty()) pstyles.append(style); }
00059     void collectCharStyle(CharStyle* style)    { if (style && !style->name().isEmpty()) cstyles.append(style); }
00060     void collectLineStyle(QString name, multiLine& m) { lstyles[name] = m; }
00061     void collectFont(QString name)             { fonts.append(name); }
00062     void collectPattern(QString name)          { patterns.append(name); }
00063 };
00064 
00065 
00066 class CollectColor_body : public Action_body
00067 {
00068     void begin (const Xml_string& tagname, Xml_attr attr)
00069     {
00070         m_name = attr["name"];
00071     }
00072     
00073     void end (const Xml_string& tagname)
00074     {
00075 //      qDebug(QString("collect %1").arg(tagname));
00076         Collection* coll = this->dig->lookup<Collection>("<collection>");
00077         ScColor* color = this->dig->top<ScColor>();
00078         coll->collectColor(m_name, *color);
00079     }
00080 private:
00081     QString m_name;
00082 };
00083 
00084 class CollectColor : public MakeAction<CollectColor_body>
00085 {};
00086 
00087 class CollectMultiLine_body : public Action_body
00088 {
00089     void begin (const Xml_string& tagname, Xml_attr attr)
00090     {
00091         m_name = attr["Name"];
00092     }
00093     
00094     void end (const Xml_string& tagname)
00095     {
00096 //      qDebug(QString("collect %1").arg(tagname));
00097         Collection* coll  = this->dig->lookup<Collection>("<collection>");
00098         multiLine*  mline = this->dig->top<multiLine>();
00099         coll->collectLineStyle(m_name, *mline);
00100     }
00101 private:
00102     QString m_name;
00103 };
00104 
00105 class CollectMultiLine : public MakeAction<CollectMultiLine_body>
00106 {};
00107 
00108 class CollectSingleLine_body : public Action_body
00109 {
00110     void begin (const Xml_string& tagname, Xml_attr attr)
00111     {
00112     }
00113     
00114     void end (const Xml_string& tagname)
00115     {
00116 //      qDebug(QString("collect %1").arg(tagname));
00117 //      Collection* coll  = this->dig->lookup<Collection>("<collection>");
00118         multiLine*  mline = this->dig->lookup<multiLine>("<multiline>");
00119         SingleLine* sline = this->dig->top<SingleLine>();
00120         mline->append(*sline);
00121     }
00122 };
00123 
00124 class CollectSingleLine : public MakeAction<CollectSingleLine_body>
00125 {};
00126 
00127 Serializer::Serializer(ScribusDoc& doc) : Digester(), m_Doc(doc)
00128 {
00129     // register desaxe rules for styles, colors and elems
00130     addRule("/SCRIBUSFRAGMENT", Factory<Collection>());
00131     addRule("/SCRIBUSFRAGMENT", Store<Collection>("<collection>"));
00132     
00133     addRule("/SCRIBUSFRAGMENT/color", Factory<ScColor>());
00134     addRule("/SCRIBUSFRAGMENT/color", SetAttribute<ScColor, QString>( &ScColor::setNamedColor, "RGB" ));
00135     addRule("/SCRIBUSFRAGMENT/color", SetAttribute<ScColor, QString>( &ScColor::setNamedColor, "CMYK" ));
00136     addRule("/SCRIBUSFRAGMENT/color", SetAttributeWithConversion<ScColor, bool>( &ScColor::setSpotColor, "Spot", &parseBool ));
00137     addRule("/SCRIBUSFRAGMENT/color", SetAttributeWithConversion<ScColor, bool>( &ScColor::setRegistrationColor, "Register", &parseBool ));
00138     addRule("/SCRIBUSFRAGMENT/color", CollectColor());
00139 
00140     CharStyle::desaxeRules("/SCRIBUSFRAGMENT/", *this);
00141     addRule("/SCRIBUSFRAGMENT/charstyle", SetterP<Collection, CharStyle>( & Collection::collectCharStyle ));
00142     
00143     ParagraphStyle::desaxeRules("/SCRIBUSFRAGMENT/", *this);
00144     addRule("/SCRIBUSFRAGMENT/style", SetterP<Collection, ParagraphStyle>( & Collection::collectStyle ));
00145 
00146     addRule("/SCRIBUSFRAGMENT/MultiLine", Factory<multiLine>());
00147     addRule("/SCRIBUSFRAGMENT/MultiLine", Store<multiLine>("<multiline>"));
00148     addRule("/SCRIBUSFRAGMENT/MultiLine", CollectMultiLine());
00149 
00150     addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", Factory<SingleLine>());
00151     addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, const QString&> ( &SingleLine::setColor, "Color", &parse<const Xml_string&>, "Black"));
00152     addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, int>( &SingleLine::setShade, "Shade", &parseInt ));
00153     addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, int>( &SingleLine::setDash , "Dash", &parseInt ));
00154     addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, int>( &SingleLine::setLineEnd , "LineEnd", &parseInt ));
00155     addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, int>( &SingleLine::setLineJoin, "LineJoin", &parseInt ));
00156     addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, double>( &SingleLine::setLineWidth, "Width", &parseDouble ));
00157     addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", CollectSingleLine());
00158 
00159     addRule("/SCRIBUSFRAGMENT/font", SetAttribute<Collection, QString>( & Collection::collectFont, "name"));
00160 
00161     PageItem::desaxeRules("", *this, "item");
00162     addRule("/SCRIBUSFRAGMENT/item", SetterP<Collection,PageItem>( & Collection::collectItem ));
00163 }
00164 
00165 
00166 void Serializer::serializeObjects(const Selection& selection, SaxHandler& outputhandler)
00167 {
00168     Xml_attr attr;
00169     UniqueID handler( & outputhandler );
00170     handler.beginDoc();
00171     handler.begin("SCRIBUSFRAGMENT", attr);
00172     ScribusDoc* doc = selection.itemAt(0)->doc();
00173     
00174     
00175     QMap<QString,int>::Iterator itf;
00176     for (itf = doc->UsedFonts.begin(); itf != doc->UsedFonts.end(); ++itf)
00177     {
00178         attr["name"] = itf.key();
00179         handler.beginEnd("font", attr);
00180     }
00181     
00182     ColorList usedColors;
00183     doc->getUsedColors(usedColors, false);
00184     ColorList::Iterator itc;
00185     for (itc = usedColors.begin(); itc != usedColors.end(); ++itc)
00186     {
00187         Xml_attr cattr;
00188         cattr["name"] = itc.key();
00189         if (doc->PageColors[itc.key()].getColorModel() == colorModelRGB)
00190             cattr["RGB"] = doc->PageColors[itc.key()].nameRGB();
00191         else
00192             cattr["CMYK"] = doc->PageColors[itc.key()].nameCMYK();
00193         cattr["Spot"] = toXMLString(doc->PageColors[itc.key()].isSpotColor());
00194         cattr["Register"] = toXMLString(doc->PageColors[itc.key()].isRegistrationColor());
00195         handler.beginEnd("color", cattr);
00196     }
00197     
00198     ResourceCollection lists;
00199     for (int i=0; i < doc->Items->count(); ++i)
00200         doc->Items->at(i)->getNamedResources(lists);
00201     
00202     QList<QString>::Iterator it;
00203     QList<QString> names = lists.styleNames();
00204     for (it = names.begin(); it != names.end(); ++it)
00205         doc->paragraphStyles().get(*it).saxx(handler);
00206 
00207     names = lists.charStyleNames();
00208     for (it = names.begin(); it != names.end(); ++it)
00209         doc->charStyles().get(*it).saxx(handler);
00210     
00211     names = lists.lineStyleNames();
00212     for (it = names.begin(); it != names.end(); ++it)
00213     {
00214         Xml_attr multiattr;
00215         multiattr["Name"] = *it;
00216         handler.begin("MultiLine", multiattr);      
00217         multiLine ml = doc->MLineStyles[*it];
00218         
00219         multiLine::Iterator itMU2;
00220         for (itMU2 = ml.begin(); itMU2 != ml.end(); ++itMU2)
00221         {
00222             Xml_attr lineattr;
00223             lineattr["Color"] = (*itMU2).Color;
00224             lineattr["Shade"] = toXMLString((*itMU2).Shade);
00225             lineattr["Dash"] = toXMLString((*itMU2).Dash);
00226             lineattr["LineEnd"] = toXMLString((*itMU2).LineEnd);
00227             lineattr["LineJoin"] = toXMLString((*itMU2).LineJoin);
00228             lineattr["Width"] = toXMLString((*itMU2).Width);
00229             handler.beginEnd("SubLine", lineattr);
00230         }
00231         handler.end("MultiLine");
00232     }
00233 
00234     /*  names = lists.patterns();
00235     for (it = names.begin(); it != names.end(); ++it)
00236         doc->patterns[*it].saxx(handler);
00237 */
00238     
00239     for (int i=0; i < doc->Items->count(); ++i)
00240     {
00241         int k = selection.findItem(doc->Items->at(i));
00242         if (k >=0)
00243             doc->Items->at(i)->saxx(handler);
00244     }
00245 
00246     handler.end("SCRIBUSFRAGMENT");
00247     handler.endDoc();
00248 }
00249 
00250 
00251 Selection Serializer::deserializeObjects(const QByteArray & xml)
00252 {
00253     backUpColors = m_Doc.PageColors;
00254     store<ScribusDoc>("<scribusdoc>", &m_Doc);
00255 
00256     parseMemory(xml, xml.length());
00257 
00258     return importCollection();
00259 }
00260 
00261 Selection Serializer::deserializeObjects(const QFile & file)
00262 {
00263     backUpColors = m_Doc.PageColors;
00264     store<ScribusDoc>("<scribusdoc>", &m_Doc);
00265 
00266     QFileInfo fi(file);
00267     parseFile(fi.filePath());
00268 
00269     return importCollection();
00270 }
00271 
00272 
00273 Selection Serializer::importCollection()
00274 {
00275     Collection* coll = lookup<Collection>("<collection>");
00276     Selection result( &m_Doc, false);
00277 //  qDebug(QString("deserialize: collection %1 doc %2").arg((ulong)coll).arg((ulong)&m_Doc));
00278     if (coll == NULL)
00279         qDebug("deserialize: no objects collected");
00280     else
00281     {
00282         QMap<QString,QString> newNames;
00283 
00284         //TODO: fonts
00285 
00286         do {
00287             newNames.clear();
00288             for (int i = 0; i < coll->cstyles.count(); ++i)
00289             {
00290                 QString oldName = coll->cstyles[i].name();
00291                 int oldIndex = m_Doc.charStyles().find(oldName);
00292                 if (oldIndex >= 0 && m_Doc.charStyle(oldName) == coll->cstyles[i])
00293                     continue;
00294                 QString newName = oldName;
00295                 if (oldIndex >= 0 && !newNames.contains(oldName))
00296                 {
00297                     int counter = 0;
00298                     while (m_Doc.charStyles().find(newName) >= 0)
00299                         newName = (QObject::tr("Copy of %1 (%2)")).arg(oldName).arg(++counter);
00300                     newNames[oldName] = newName;
00301                 }
00302             }
00303             
00304             coll->cstyles.rename(newNames);
00305         }
00306         while (newNames.count() > 0);
00307         m_Doc.redefineCharStyles(coll->cstyles, false);     
00308 
00309         do {
00310             newNames.clear();
00311             for (int i = 0; i < coll->pstyles.count(); ++i)  // FIXME:  QValueList<QString> StyleSet::names()
00312             {
00313                 QString oldName = coll->pstyles[i].name();
00314                 int oldIndex = m_Doc.paragraphStyles().find(oldName);
00315 //              qDebug(QString("comparing %1 (old %2 new %3): parent '%4'='%5' cstyle %6 equiv %7").arg(oldName).arg(oldIndex).arg(i)
00316 //                     .arg(oldIndex>=0? m_Doc.paragraphStyle(oldName).parent() : "?").arg(coll->pstyles[i].parent())
00317 //                     .arg(oldIndex>=0? m_Doc.paragraphStyle(oldName).charStyle() == coll->pstyles[i].charStyle() : false)
00318 //                     .arg(oldIndex>=0? m_Doc.paragraphStyle(oldName).equiv(coll->pstyles[i]) : false));
00319             
00320                 if (oldIndex >= 0 && coll->pstyles[i] == m_Doc.paragraphStyle(oldName) )
00321                     continue;
00322                 QString newName = oldName;
00323                 if (oldIndex >= 0 && !newNames.contains(oldName))
00324                 {
00325                     int counter = 0;
00326                     while (m_Doc.paragraphStyles().find(newName) >= 0)
00327                         newName = (QObject::tr("Copy of %1 (%2)")).arg(oldName).arg(++counter);
00328                     newNames[oldName] = newName;
00329                 }
00330             }
00331             coll->pstyles.rename(newNames);
00332         }
00333         while(newNames.count() > 0);
00334         
00335         m_Doc.redefineStyles(coll->pstyles, false);     
00336 
00337         //TODO: linestyles : this is temporary code until MultiLine is replaced by LineStyle
00338         QMap<QString,multiLine>::Iterator mlit;
00339         for (mlit = coll->lstyles.begin(); mlit != coll->lstyles.end(); ++mlit)
00340         {
00341             multiLine& ml = mlit.value();
00342             QString    oldName = mlit.key();
00343             QString    newName = mlit.key();
00344             QMap<QString,multiLine>::ConstIterator mlitd = m_Doc.MLineStyles.find(oldName);
00345             if (mlitd != m_Doc.MLineStyles.end() && ml != mlitd.value())
00346             {
00347                 int counter = 0;
00348                 while (m_Doc.MLineStyles.contains(newName))
00349                     newName = (QObject::tr("Copy of %1 (%2)")).arg(oldName).arg(++counter);
00350             }
00351             m_Doc.MLineStyles.insert(newName, ml);
00352         }
00353 
00354         //TODO: patterns
00355         
00356         QList<PageItem*>* objects = &(coll->items);
00357         m_Doc.PageColors = backUpColors;
00358         m_Doc.PageColors.addColors(coll->colors, false);
00359         for (int i=0; i < objects->count(); ++i)
00360         {
00361             PageItem* currItem = objects->at(i);
00362             currItem->Clip = FlattenPath(currItem->PoLine, currItem->Segments);
00363             currItem->setFillQColor();
00364             currItem->setLineQColor();
00365             result.addItem(currItem);
00366         }
00367         updateGradientColors(coll->colors);
00368         delete coll;
00369     }
00370     return result;
00371 }
00372 
00373 
00374 bool Serializer::writeWithEncoding(const QString& filename, const QString& encoding, 
00375                                    const QString& txt)
00376 {
00377     QTextCodec *codec;
00378     if (encoding.isEmpty())
00379         codec = QTextCodec::codecForLocale();
00380     else
00381         codec = QTextCodec::codecForName(encoding.toLocal8Bit());
00382     QByteArray dec = codec->fromUnicode( txt );
00383     QFile f(filename);
00384     if (f.open(QIODevice::WriteOnly))
00385     {
00386         f.write(dec, dec.length());
00387         f.close();
00388         return true;
00389     }
00390     return false;
00391 }
00392 
00393 
00394 bool Serializer::readWithEncoding(const QString& filename, const QString& encoding, 
00395                                   QString &txt)
00396 {
00397     QByteArray file;
00398     QTextCodec *codec;
00399     if (encoding.isEmpty())
00400         codec = QTextCodec::codecForLocale();
00401     else
00402         codec = QTextCodec::codecForName(encoding.toLocal8Bit());
00403     if (loadRawText(filename, file))
00404     {
00405         txt = codec->toUnicode( file.data() );
00406         return true;
00407     }
00408     return false;
00409 }
00410 
00411 void Serializer::updateGradientColors(const ColorList& colors)
00412 {
00413     VColorStop* grStop;
00414     uint itemsCount = m_Doc.Items->count();
00415     for (uint c=0; c < itemsCount; ++c)
00416     {
00417         PageItem *ite = m_Doc.Items->at(c);
00418         QList<VColorStop*> cstops = ite->fill_gradient.colorStops();
00419         for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst)
00420         {
00421             grStop = cstops.at(cst);
00422             if (colors.contains(grStop->name))
00423                 grStop->color = SetColor(&m_Doc, grStop->name, grStop->shade);
00424         }
00425     }
00426     uint masterItemsCount =  m_Doc.MasterItems.count();
00427     for (uint c=0; c < masterItemsCount; ++c)
00428     {
00429         PageItem *ite = m_Doc.MasterItems.at(c);
00430         QList<VColorStop*> cstops = ite->fill_gradient.colorStops();
00431         for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst)
00432         {
00433             grStop = cstops.at(cst);
00434             if (colors.contains(grStop->name))
00435                 grStop->color = SetColor(&m_Doc, grStop->name, grStop->shade);
00436         }
00437     }
00438     uint frameItemsCount = m_Doc.FrameItems.count();
00439     for (uint c=0; c < frameItemsCount; ++c)
00440     {
00441         PageItem *ite = m_Doc.FrameItems.at(c);
00442         QList<VColorStop*> cstops = ite->fill_gradient.colorStops();
00443         for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst)
00444         {
00445             grStop = cstops.at(cst);
00446             if (colors.contains(grStop->name))
00447                 grStop->color = SetColor(&m_Doc, grStop->name, grStop->shade);
00448         }
00449     }
00450     QStringList patterns =m_Doc.docPatterns.keys();
00451     for (int c = 0; c < patterns.count(); ++c)
00452     {
00453         ScPattern& pa = m_Doc.docPatterns[patterns[c]];
00454         for (int o = 0; o < pa.items.count(); o++)
00455         {
00456             PageItem *ite = pa.items.at(o);
00457             QList<VColorStop*> cstops = ite->fill_gradient.colorStops();
00458             for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst)
00459             {
00460                 grStop = cstops.at(cst);
00461                 if (colors.contains(grStop->name))
00462                     grStop->color = SetColor(&m_Doc, grStop->name, grStop->shade);
00463             }
00464         }
00465     }
00466 }
Created with personalized Doxygen. This is documentation for GPL software Scribus - Open Source Desktop Publishing.