Back to index

scribus-ng  1.3.4.dfsg+svn20071115
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 "pageitem.h"
00027 #include <cassert>
00028 #include <qfile.h>
00029 #include <qtextstream.h>
00030 #include <qtextcodec.h>
00031 #include "sccolor.h"
00032 #include "util.h"
00033 #include "colorutil.h"
00034 #include "resourcecollection.h"
00035 
00036 #include "desaxe/simple_actions.h"
00037 #include "desaxe/saxXML.h"
00038 #include "desaxe/uniqueid.h"
00039 
00040 
00041 using namespace desaxe;
00042 
00043 
00044 struct Collection
00045 {
00046        QPtrList<PageItem> items;
00047        ColorList colors;
00048        StyleSet<ParagraphStyle> pstyles;
00049        StyleSet<CharStyle> cstyles;
00050        QMap<QString,multiLine> lstyles;
00051        QValueList<QString> fonts;
00052        QValueList<QString> patterns;
00053 
00054        void collectItem(PageItem* p)              { items.append(p); }
00055        void collectColor(QString name, ScColor c) { colors[name] = c; }
00056        void collectStyle(ParagraphStyle* style)   { if (style && !style->name().isEmpty()) pstyles.append(style); }
00057        void collectCharStyle(CharStyle* style)    { if (style && !style->name().isEmpty()) cstyles.append(style); }
00058        void collectLineStyle(QString name, multiLine& m) { lstyles[name] = m; }
00059        void collectFont(QString name)             { fonts.append(name); }
00060        void collectPattern(QString name)          { patterns.append(name); }
00061 };
00062 
00063 
00064 class CollectColor_body : public Action_body
00065 {
00066        void begin (const Xml_string& tagname, Xml_attr attr)
00067        {
00068               m_name = attr["name"];
00069        }
00070        
00071        void end (const Xml_string& tagname)
00072        {
00073 //            qDebug(QString("collect %1").arg(tagname));
00074               Collection* coll = this->dig->lookup<Collection>("<collection>");
00075               ScColor* color = this->dig->top<ScColor>();
00076               coll->collectColor(m_name, *color);
00077        }
00078 private:
00079        QString m_name;
00080 };
00081 
00082 class CollectColor : public MakeAction<CollectColor_body>
00083 {};
00084 
00085 class CollectMultiLine_body : public Action_body
00086 {
00087        void begin (const Xml_string& tagname, Xml_attr attr)
00088        {
00089               m_name = attr["Name"];
00090        }
00091        
00092        void end (const Xml_string& tagname)
00093        {
00094 //            qDebug(QString("collect %1").arg(tagname));
00095               Collection* coll  = this->dig->lookup<Collection>("<collection>");
00096               multiLine*  mline = this->dig->top<multiLine>();
00097               coll->collectLineStyle(m_name, *mline);
00098        }
00099 private:
00100        QString m_name;
00101 };
00102 
00103 class CollectMultiLine : public MakeAction<CollectMultiLine_body>
00104 {};
00105 
00106 class CollectSingleLine_body : public Action_body
00107 {
00108        void begin (const Xml_string& tagname, Xml_attr attr)
00109        {
00110        }
00111        
00112        void end (const Xml_string& tagname)
00113        {
00114 //            qDebug(QString("collect %1").arg(tagname));
00115 //            Collection* coll  = this->dig->lookup<Collection>("<collection>");
00116               multiLine*  mline = this->dig->lookup<multiLine>("<multiline>");
00117               SingleLine* sline = this->dig->top<SingleLine>();
00118               mline->append(*sline);
00119        }
00120 };
00121 
00122 class CollectSingleLine : public MakeAction<CollectSingleLine_body>
00123 {};
00124 
00125 
00126 Serializer::Serializer(ScribusDoc& doc) : Digester(), m_Doc(doc)
00127 {
00128        // register desaxe rules for styles, colors and elems
00129        addRule("/SCRIBUSFRAGMENT", Factory<Collection>());
00130        addRule("/SCRIBUSFRAGMENT", Store<Collection>("<collection>"));
00131        
00132        addRule("/SCRIBUSFRAGMENT/color", Factory<ScColor>());
00133        addRule("/SCRIBUSFRAGMENT/color", SetAttribute<ScColor, QString>( &ScColor::setNamedColor, "RGB" ));
00134        addRule("/SCRIBUSFRAGMENT/color", SetAttribute<ScColor, QString>( &ScColor::setNamedColor, "CMYK" ));
00135        addRule("/SCRIBUSFRAGMENT/color", SetAttributeWithConversion<ScColor, bool>( &ScColor::setSpotColor, "Spot", &parseBool ));
00136        addRule("/SCRIBUSFRAGMENT/color", SetAttributeWithConversion<ScColor, bool>( &ScColor::setRegistrationColor, "Register", &parseBool ));
00137        addRule("/SCRIBUSFRAGMENT/color", CollectColor());
00138 
00139        CharStyle::desaxeRules("/SCRIBUSFRAGMENT/", *this);
00140        addRule("/SCRIBUSFRAGMENT/charstyle", SetterP<Collection, CharStyle>( & Collection::collectCharStyle ));
00141        
00142        ParagraphStyle::desaxeRules("/SCRIBUSFRAGMENT/", *this);
00143        addRule("/SCRIBUSFRAGMENT/style", SetterP<Collection, ParagraphStyle>( & Collection::collectStyle ));
00144 
00145        addRule("/SCRIBUSFRAGMENT/MultiLine", Factory<multiLine>());
00146        addRule("/SCRIBUSFRAGMENT/MultiLine", Store<multiLine>("<multiline>"));
00147        addRule("/SCRIBUSFRAGMENT/MultiLine", CollectMultiLine());
00148 
00149        addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", Factory<SingleLine>());
00150        addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, const QString&> ( &SingleLine::setColor, "Color", &parse<const Xml_string&>, "Black"));
00151        addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, int>( &SingleLine::setShade, "Shade", &parseInt ));
00152        addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, int>( &SingleLine::setDash , "Dash", &parseInt ));
00153        addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, int>( &SingleLine::setLineEnd , "LineEnd", &parseInt ));
00154        addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, int>( &SingleLine::setLineJoin, "LineJoin", &parseInt ));
00155        addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", SetAttributeWithConversion<SingleLine, double>( &SingleLine::setLineWidth, "Width", &parseDouble ));
00156        addRule("/SCRIBUSFRAGMENT/MultiLine/SubLine", CollectSingleLine());
00157 
00158        addRule("/SCRIBUSFRAGMENT/font", SetAttribute<Collection, QString>( & Collection::collectFont, "name"));
00159 
00160        PageItem::desaxeRules("", *this, "item");
00161        addRule("/SCRIBUSFRAGMENT/item", SetterP<Collection,PageItem>( & Collection::collectItem ));
00162 }
00163 
00164 
00165 void Serializer::serializeObjects(const Selection& selection, SaxHandler& outputhandler)
00166 {
00167        assert (selection.count() > 0);
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 (uint i=0; i < doc->Items->count(); ++i)
00200               doc->Items->at(i)->getNamedResources(lists);
00201        
00202        QValueList<QString>::Iterator it;
00203        QValueList<QString> names = lists.styleNames();
00204        for (it = names.begin(); it != names.end(); ++it)
00205               doc->paragraphStyles()[*it].saxx(handler);
00206 
00207        names = lists.charStyleNames();
00208        for (it = names.begin(); it != names.end(); ++it)
00209               doc->charStyles()[*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               QValueVector<SingleLine>::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 (uint 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 QCString & xml)
00252 {
00253        store<ScribusDoc>("<scribusdoc>", &m_Doc);
00254 
00255        parseMemory(xml, xml.length());
00256 
00257        return importCollection();
00258 }
00259 
00260 Selection Serializer::deserializeObjects(const QFile & file)
00261 {
00262        store<ScribusDoc>("<scribusdoc>", &m_Doc);
00263 
00264        QFileInfo fi(file);
00265        parseFile(fi.filePath());
00266 
00267        return importCollection();
00268 }
00269 
00270 
00271 Selection Serializer::importCollection()
00272 {      
00273        Collection* coll = lookup<Collection>("<collection>");
00274        Selection result( &m_Doc, false);
00275 //     qDebug(QString("deserialize: collection %1 doc %2").arg((ulong)coll).arg((ulong)&m_Doc));
00276        if (coll == NULL)
00277               qDebug("deserialize: no objects collected");
00278        else
00279        {
00280               QMap<QString,QString> newNames;
00281 
00282               //TODO: fonts
00283 
00284               do {
00285                      newNames.clear();
00286                      for (uint i = 0; i < coll->cstyles.count(); ++i)  
00287                      {
00288                             QString oldName = coll->cstyles[i].name();
00289                             int oldIndex = m_Doc.charStyles().find(oldName);
00290                             if (oldIndex >= 0 && m_Doc.charStyle(oldName) == coll->cstyles[i])
00291                                    continue;
00292                             QString newName = oldName;
00293                             if (oldIndex >= 0 && !newNames.contains(oldName))
00294                             {
00295                                    int counter = 0;
00296                                    while (m_Doc.charStyles().find(newName) >= 0)
00297                                           newName = (QObject::tr("Copy of %1 (%2)")).arg(oldName).arg(++counter);
00298                                    newNames[oldName] = newName;
00299                             }
00300                      }
00301                      
00302                      coll->cstyles.rename(newNames);
00303               }
00304               while (newNames.count() > 0);
00305               m_Doc.redefineCharStyles(coll->cstyles, false);
00306               
00307               do {
00308                      newNames.clear();
00309                      for (uint i = 0; i < coll->pstyles.count(); ++i)  // FIXME:  QValueList<QString> StyleSet::names()
00310                      {
00311                             QString oldName = coll->pstyles[i].name();
00312                             int oldIndex = m_Doc.paragraphStyles().find(oldName);
00313 //                          qDebug(QString("comparing %1 (old %2 new %3): parent '%4'='%5' cstyle %6 equiv %7").arg(oldName).arg(oldIndex).arg(i)
00314 //                                    .arg(oldIndex>=0? m_Doc.paragraphStyle(oldName).parent() : "?").arg(coll->pstyles[i].parent())
00315 //                                    .arg(oldIndex>=0? m_Doc.paragraphStyle(oldName).charStyle() == coll->pstyles[i].charStyle() : false)
00316 //                                    .arg(oldIndex>=0? m_Doc.paragraphStyle(oldName).equiv(coll->pstyles[i]) : false));
00317                             
00318                             if (oldIndex >= 0 && coll->pstyles[i] == m_Doc.paragraphStyle(oldName) )
00319                                    continue;
00320                             QString newName = oldName;
00321                             if (oldIndex >= 0 && !newNames.contains(oldName))
00322                             {
00323                                    int counter = 0;
00324                                    while (m_Doc.paragraphStyles().find(newName) >= 0)
00325                                           newName = (QObject::tr("Copy of %1 (%2)")).arg(oldName).arg(++counter);
00326                                    newNames[oldName] = newName;
00327                             }
00328                      }
00329                      coll->pstyles.rename(newNames);
00330               }
00331               while(newNames.count() > 0);
00332               
00333               m_Doc.redefineStyles(coll->pstyles, false);
00334               
00335               //TODO: linestyles : this is temporary code until MultiLine is replaced by LineStyle
00336               QMap<QString,multiLine>::Iterator mlit;
00337               for (mlit = coll->lstyles.begin(); mlit != coll->lstyles.end(); ++mlit)
00338               {
00339                      multiLine& ml = mlit.data();
00340                      QString    oldName = mlit.key();
00341                      QString    newName = mlit.key();
00342                      QMap<QString,multiLine>::ConstIterator mlitd = m_Doc.MLineStyles.find(oldName);
00343                      if (mlitd != m_Doc.MLineStyles.end() && ml != mlitd.data())
00344                      {
00345                             int counter = 0;
00346                             while (m_Doc.MLineStyles.contains(newName))
00347                                    newName = (QObject::tr("Copy of %1 (%2)")).arg(oldName).arg(++counter);
00348                      }
00349                      m_Doc.MLineStyles.insert(newName, ml);
00350               }
00351 
00352               //TODO: patterns
00353               
00354               QPtrList<PageItem>* objects = &(coll->items);
00355               
00356 //            qDebug(QString("deserialize: objects %1").arg((ulong)objects));
00357               
00358               for (uint i=0; i < objects->count(); ++i)
00359               {
00360 //                   qDebug(QString("deserialized item: %1,%2").arg(objects->at(i)->xPos()).arg(objects->at(i)->yPos()));
00361                      PageItem* currItem = objects->at(i);
00362                      currItem->Clip = FlattenPath(currItem->PoLine, currItem->Segments);
00363                      result.addItem(currItem);
00364               }
00365 //            qDebug(QString("deserialize: %1 objects, colors %2 %3").arg(objects->count()).arg((ulong)&(m_Doc.PageColors)).arg((ulong)&(coll->colors)));        
00366               m_Doc.PageColors.addColors(coll->colors, false);
00367 //            qDebug(QString("deserialize: delete collection... %1").arg(result.count()));
00368               updateGradientColors(coll->colors);
00369               delete coll;
00370        }
00371 //     qDebug(QString("deserialize done: %1 items").arg(result.count()));
00372        return result;
00373 }
00374 
00375 
00376 bool Serializer::writeWithEncoding(const QString& filename, const QString& encoding, 
00377                                                            const QString& txt)
00378 {
00379        QTextCodec *codec;
00380        if (encoding.isEmpty())
00381               codec = QTextCodec::codecForLocale();
00382        else
00383               codec = QTextCodec::codecForName(encoding);
00384        QCString dec = codec->fromUnicode( txt );
00385        QFile f(filename);
00386        if (f.open(IO_WriteOnly))
00387        {
00388               f.writeBlock(dec, dec.length());
00389               f.close();
00390               return true;
00391        }
00392        return false;
00393 }
00394 
00395 
00396 bool Serializer::readWithEncoding(const QString& filename, const QString& encoding, 
00397                                                           QString &txt)
00398 {
00399        QCString file;
00400        QTextCodec *codec;
00401        if (encoding.isEmpty())
00402               codec = QTextCodec::codecForLocale();
00403        else
00404               codec = QTextCodec::codecForName(encoding);
00405        if (loadRawText(filename, file))
00406        {
00407               txt = codec->toUnicode( file.data() );
00408               return true;
00409        }
00410        return false;
00411 }
00412 
00413 void Serializer::updateGradientColors(const ColorList& colors)
00414 {
00415        VColorStop* grStop;
00416        uint itemsCount = m_Doc.Items->count();
00417        for (uint c=0; c < itemsCount; ++c)
00418        {
00419               PageItem *ite = m_Doc.Items->at(c);
00420               QPtrVector<VColorStop> cstops = ite->fill_gradient.colorStops();
00421               for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst)
00422               {
00423                      grStop = cstops.at(cst);
00424                      if (colors.contains(grStop->name))
00425                             grStop->color = SetColor(&m_Doc, grStop->name, grStop->shade);
00426               }
00427        }
00428        uint masterItemsCount =  m_Doc.MasterItems.count();
00429        for (uint c=0; c<masterItemsCount; ++c)
00430        {
00431               PageItem *ite = m_Doc.MasterItems.at(c);
00432               QPtrVector<VColorStop> cstops = ite->fill_gradient.colorStops();
00433               for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst)
00434               {
00435                      grStop = cstops.at(cst);
00436                      if (colors.contains(grStop->name))
00437                             grStop->color = SetColor(&m_Doc, grStop->name, grStop->shade);
00438               }
00439        }
00440        uint frameItemsCount = m_Doc.FrameItems.count();
00441        for (uint c=0; c<frameItemsCount; ++c)
00442        {
00443               PageItem *ite = m_Doc.FrameItems.at(c);
00444               QPtrVector<VColorStop> cstops = ite->fill_gradient.colorStops();
00445               for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst)
00446               {
00447                      grStop = cstops.at(cst);
00448                      if (colors.contains(grStop->name))
00449                             grStop->color = SetColor(&m_Doc, grStop->name, grStop->shade);
00450               }
00451        }
00452        QStringList patterns =m_Doc.docPatterns.keys();
00453        for (uint c = 0; c < patterns.count(); ++c)
00454        {
00455               ScPattern& pa = m_Doc.docPatterns[patterns[c]];
00456               for (uint o = 0; o < pa.items.count(); o++)
00457               {
00458                      PageItem *ite = pa.items.at(o);
00459                      QPtrVector<VColorStop> cstops = ite->fill_gradient.colorStops();
00460                      for (uint cst = 0; cst < ite->fill_gradient.Stops(); ++cst)
00461                      {
00462                             grStop = cstops.at(cst);
00463                             if (colors.contains(grStop->name))
00464                                    grStop->color = SetColor(&m_Doc, grStop->name, grStop->shade);
00465                      }
00466               }
00467        }
00468 }