1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7
8 #include <algorithm>
9
10 #include "loadsaveplugin.h"
11 #include "commonstrings.h"
12 #include "scribuscore.h"
13
14 #include "plugins/formatidlist.h"
15
16 #include <QList>
17 #include <QMessageBox>
18
19 QList<FileFormat> LoadSavePlugin::formats;
20
LoadSavePlugin()21 LoadSavePlugin::LoadSavePlugin() :
22 undoManager(UndoManager::instance())
23 {
24 }
25
~LoadSavePlugin()26 LoadSavePlugin::~LoadSavePlugin()
27 {
28 }
29
30 // STATIC method - return a list of all existing formats
supportedFormats()31 const QList<FileFormat> & LoadSavePlugin::supportedFormats()
32 {
33 return formats;
34 }
35
getFormatById(const int id)36 const FileFormat * LoadSavePlugin::getFormatById(const int id)
37 {
38 QList<FileFormat>::iterator it(findFormat(id));
39 if (it == formats.end())
40 return nullptr;
41 return &(*it);
42 }
43
getFormatByID(int id)44 FileFormat * LoadSavePlugin::getFormatByID(int id)
45 {
46 QList<FileFormat>::iterator it(findFormat(id));
47 if (it == formats.end())
48 return nullptr;
49 return &(*it);
50 }
51
getFormatByExt(const QString & ext)52 FileFormat* LoadSavePlugin::getFormatByExt(const QString& ext)
53 {
54 QList<FileFormat>::iterator it(findFormat(ext));
55 if (it == formats.end())
56 return nullptr;
57 return &(*it);
58 }
59
fileDialogLoadFilter()60 QStringList LoadSavePlugin::fileDialogLoadFilter()
61 {
62 return getDialogFilter(true);
63 }
64
fileDialogSaveFilter()65 QStringList LoadSavePlugin::fileDialogSaveFilter()
66 {
67 return getDialogFilter(false);
68 }
69
getExtensionsForColors(const int id)70 QStringList LoadSavePlugin::getExtensionsForColors(const int id)
71 {
72 QList<FileFormat>::const_iterator it(findFormat(id));
73 QList<FileFormat>::const_iterator itEnd(formats.constEnd());
74 QStringList filterList;
75 // We know the list is sorted by id, then priority, so we can just take the
76 // highest priority entry for each ID, and we can start with the first entry
77 // in the list.
78 //First, check if we even have any plugins to load with
79 if (it != itEnd)
80 {
81 if ((it->load) && (it->colorReading))
82 filterList.append(it->fileExtensions);
83 unsigned int lastID = it->formatId;
84 ++it;
85 for ( ; it != itEnd ; ++it)
86 {
87 // Find the next load/save (as appropriate) plugin for the next format type
88 if (((it->load) && (it->colorReading)) && (it->formatId > lastID))
89 {
90 // And add it to the filter list, since we know it's
91 // the highest priority because of the sort order.
92 filterList.append(it->fileExtensions);
93 lastID = it->formatId;
94 }
95 }
96 }
97 else
98 qDebug("%s", tr("No File Loader Plugins Found").toLocal8Bit().data());
99 // Avoid duplicate entries in the list
100 QSet<QString> fSet(filterList.begin(), filterList.end());
101 filterList = fSet.values();
102 std::sort(filterList.begin(), filterList.end());
103 return filterList;
104 }
105
getExtensionsForImport(const int id)106 QStringList LoadSavePlugin::getExtensionsForImport(const int id)
107 {
108 QList<FileFormat>::const_iterator it(findFormat(id));
109 QList<FileFormat>::const_iterator itEnd(formats.constEnd());
110 QStringList filterList;
111 // We know the list is sorted by id, then priority, so we can just take the
112 // highest priority entry for each ID, and we can start with the first entry
113 // in the list.
114 //First, check if we even have any plugins to load with
115 if (it != itEnd)
116 {
117 if (it->load)
118 filterList.append(it->fileExtensions);
119 unsigned int lastID = it->formatId;
120 ++it;
121 for ( ; it != itEnd ; ++it)
122 {
123 // Find the next load/save (as appropriate) plugin for the next format type
124 if ((it->load) && (it->formatId > lastID))
125 {
126 // And add it to the filter list, since we know it's
127 // the highest priority because of the sort order.
128 filterList.append(it->fileExtensions);
129 lastID = it->formatId;
130 }
131 }
132 }
133 else
134 qDebug("%s", tr("No File Loader Plugins Found").toLocal8Bit().data());
135 // Avoid duplicate entries in the list
136 QSet<QString> fSet(filterList.begin(), filterList.end());
137 filterList = fSet.values();
138 std::sort(filterList.begin(), filterList.end());
139 return filterList;
140 }
141
getExtensionsForPreview(const int id)142 QStringList LoadSavePlugin::getExtensionsForPreview(const int id)
143 {
144 QList<FileFormat>::const_iterator it(findFormat(id));
145 QList<FileFormat>::const_iterator itEnd(formats.constEnd());
146 QStringList filterList;
147 // We know the list is sorted by id, then priority, so we can just take the
148 // highest priority entry for each ID, and we can start with the first entry
149 // in the list.
150 //First, check if we even have any plugins to load with
151 if (it != itEnd)
152 {
153 if ((it->load) && (it->thumb))
154 filterList.append(it->fileExtensions);
155 unsigned int lastID = it->formatId;
156 ++it;
157 for ( ; it != itEnd ; ++it)
158 {
159 // Find the next load/save (as appropriate) plugin for the next format type
160 if (((it->load) && (it->thumb)) && (it->formatId > lastID))
161 {
162 // And add it to the filter list, since we know it's
163 // the highest priority because of the sort order.
164 filterList.append(it->fileExtensions);
165 lastID = it->formatId;
166 }
167 }
168 }
169 else
170 qDebug("%s", tr("No File Loader Plugins Found").toLocal8Bit().data());
171 // Avoid duplicate entries in the list
172 QSet<QString> fSet(filterList.begin(), filterList.end());
173 filterList = fSet.values();
174 std::sort(filterList.begin(), filterList.end());
175 return filterList;
176 }
177
getDialogFilter(bool forLoad)178 const QStringList LoadSavePlugin::getDialogFilter(bool forLoad)
179 {
180 QList<FileFormat>::const_iterator it(formats.constBegin());
181 QList<FileFormat>::const_iterator itEnd(formats.constEnd());
182 QStringList filterList;
183 // We know the list is sorted by id, then priority, so we can just take the
184 // highest priority entry for each ID, and we can start with the first entry
185 // in the list.
186 //First, check if we even have any plugins to load with
187 if (it == itEnd)
188 {
189 qDebug("%s", tr("No File Loader Plugins Found").toLocal8Bit().data());
190 return filterList;
191 }
192 unsigned int lastID = 0;
193 QStringList scribusList;
194 while (it != itEnd)
195 {
196 // Find the next load/save (as appropriate) plugin for the next format type
197 if ((forLoad ? it->load : it->save) && (it->formatId > lastID))
198 {
199 // And add it to the filter list, since we know it's
200 // the highest priority because of the sort order.
201 // #11294, sort them and keep Scribus ones at the top
202 if(it->nativeScribus)
203 scribusList.append(it->filter);
204 else
205 filterList.append(it->filter);
206 lastID = it->formatId;
207 }
208 ++it;
209 }
210 filterList.sort(Qt::CaseInsensitive);
211 filterList.append( tr("All Files (*)"));
212 return scribusList+filterList;
213 }
214
saveFile(const QString &,const FileFormat &)215 bool LoadSavePlugin::saveFile(const QString & /* fileName */,
216 const FileFormat & /* fmt */)
217 {
218 return false;
219 }
220
loadElements(const QString &,const QString &,int,double,double,bool)221 bool LoadSavePlugin::loadElements(const QString & /*data*/, const QString& /*fileDir*/, int /*toLayer*/, double /*Xp_in*/, double /*Yp_in*/, bool /*loc*/)
222 {
223 return false;
224 }
225
savePalette(const QString &)226 bool LoadSavePlugin::savePalette(const QString & /*fileName*/)
227 {
228 return false;
229 }
230
saveElements(double,double,double,double,Selection *,QByteArray &)231 QString LoadSavePlugin::saveElements(double /*xp*/, double /*yp*/, double /*wp*/, double /*hp*/, Selection* /*selection*/, QByteArray & /*prevData*/)
232 {
233 return "";
234 }
235
loadPalette(const QString &)236 bool LoadSavePlugin::loadPalette(const QString & /*fileName*/)
237 {
238 return false;
239 }
240
setFileReadError()241 void LoadSavePlugin::setFileReadError()
242 {
243 m_lastError = tr("An error occurred while opening file or file is damaged");
244 }
245
setDomParsingError(const QString & msg,int line,int column)246 void LoadSavePlugin::setDomParsingError(const QString& msg, int line, int column)
247 {
248 m_lastError = tr("An error occurred while parsing file at line %1, column %2 :\n%3").arg(line).arg(column).arg(msg);
249 }
250
lastSavedFile()251 const QString& LoadSavePlugin::lastSavedFile()
252 {
253 return m_lastSavedFile;
254 }
255
loadFile(const QString &,const FileFormat &,int,int)256 bool LoadSavePlugin::loadFile(const QString & /* fileName */,
257 const FileFormat & /* fmt */,
258 int /* flags */,
259 int /* index */)
260 {
261 return false;
262 }
263
checkFlags(int flags)264 bool LoadSavePlugin::checkFlags(int flags)
265 {
266 int numFlags = 0;
267 // Only one of the following flags must be set:
268 // lfCreateDoc, lfUseCurrentPage, lfInsertPage
269 if( flags & lfCreateDoc )
270 numFlags++;
271 if( flags & lfUseCurrentPage )
272 numFlags++;
273 if( flags & lfInsertPage )
274 numFlags++;
275 return numFlags <= 1;
276 }
277
registerFormat(FileFormat & fmt)278 void LoadSavePlugin::registerFormat(FileFormat & fmt)
279 {
280 // We insert the format in a very specific location so that the formats
281 // list is sorted by ascending id, then descending priority.
282 // We first look for entries with equal or greater ID, then equal or
283 // lesser priority, and insert before the first item that is of either:
284 // - Equal ID and lesser or equal priority; or
285 // - Greater ID
286 // If we don't find one, we insert before the end iterator, ie append.
287 if (fmt.formatId == 0) // only for custom plugins
288 {
289 uint id = FORMATID_FIRSTUSER;
290 if (!formats.isEmpty())
291 {
292 QList<FileFormat>::iterator it(formats.begin());
293 QList<FileFormat>::iterator itEnd(formats.end());
294 id = FORMATID_FIRSTUSER - 1;
295 while (it != itEnd)
296 {
297 id = qMax(it->formatId, id);
298 ++it;
299 }
300 id++;
301 }
302 fmt.formatId = id;
303 formats.append(fmt);
304 }
305 else
306 {
307 QList<FileFormat>::iterator it(formats.begin());
308 QList<FileFormat>::iterator itEnd(formats.end());
309 while (it != itEnd)
310 {
311 if ( ( (it->formatId == fmt.formatId) && (it->priority <= fmt.priority) ) ||
312 (it->formatId > fmt.formatId))
313 break;
314 ++it;
315 }
316 formats.insert(it, fmt);
317 }
318 //qDebug("Format: Id: %3u, Prio: %3hu, Name: %s", fmt.formatId, fmt.priority, fmt.trName.toLocal8Bit().data() );
319 //printFormatList(); // DEBUG
320 }
321
322 // static debugging function - prints the human readable format list
printFormatList()323 void LoadSavePlugin::printFormatList()
324 {
325 qDebug("Current format list:");
326 QList<FileFormat>::const_iterator it(formats.constBegin());
327 QList<FileFormat>::const_iterator itEnd(formats.constEnd());
328 for ( ; it != itEnd ; ++it)
329 {
330 qDebug(" Format: Id: %3u, Prio: %3hu, Name: %s", it->formatId, it->priority, it->trName.toLocal8Bit().data() );
331 }
332 qDebug("Done");
333 }
334
unregisterFormat(unsigned int id)335 void LoadSavePlugin::unregisterFormat(unsigned int id)
336 {
337 QList<FileFormat>::iterator it(findFormat(id, this));
338 Q_ASSERT(it != formats.end());
339 formats.erase(it);
340 }
341
unregisterAll()342 void LoadSavePlugin::unregisterAll()
343 {
344 QList<FileFormat>::iterator it(formats.begin());
345 while (it != formats.end())
346 {
347 if (it->plug == this)
348 it = formats.erase(it);
349 else
350 ++it;
351 }
352 }
353
354 QList<FileFormat>::iterator
findFormat(unsigned int id,LoadSavePlugin * plug,QList<FileFormat>::iterator it)355 LoadSavePlugin::findFormat(unsigned int id, LoadSavePlugin* plug, QList<FileFormat>::iterator it)
356 {
357 QList<FileFormat>::iterator itEnd(formats.end());
358 for ( ; it != itEnd ; ++it)
359 {
360 if ((it->formatId == id) && ((plug == nullptr) || (plug == it->plug)))
361 return it;
362 }
363 return itEnd;
364 }
365
366 QList<FileFormat>::iterator
findFormat(const QString & extension,LoadSavePlugin * plug,QList<FileFormat>::iterator it)367 LoadSavePlugin::findFormat(const QString& extension, LoadSavePlugin* plug, QList<FileFormat>::iterator it)
368 {
369 QList<FileFormat>::iterator itEnd(formats.end());
370 for ( ; it != itEnd ; ++it)
371 {
372 if ((it->fileExtensions.contains(extension.toLower())) && ((plug == nullptr) || (plug == it->plug)) )
373 return it;
374 }
375 return itEnd;
376 }
377
378
setupTargets(ScribusDoc * targetDoc,ScribusView * targetView,ScribusMainWindow * targetMW,QProgressBar * targetMWPRogressBar,SCFonts * targetAvailableFonts)379 void LoadSavePlugin::setupTargets(ScribusDoc *targetDoc, ScribusView* targetView, ScribusMainWindow* targetMW, QProgressBar* targetMWPRogressBar, SCFonts* targetAvailableFonts)
380 {
381 m_Doc = targetDoc;
382 m_View = targetView;
383 m_ScMW = targetMW;
384 m_mwProgressBar = targetMWPRogressBar;
385 m_AvailableFonts = targetAvailableFonts;
386 }
387
getReplacedFontData(bool &,QMap<QString,QString> &,QList<ScFace> &)388 void LoadSavePlugin::getReplacedFontData(bool & /*getNewReplacement*/, QMap<QString,QString> &/*getReplacedFonts*/, QList<ScFace> &/*getDummyScFaces*/)
389 {
390 }
391
loadPage(const QString &,int,bool,const QString &)392 bool LoadSavePlugin::loadPage(const QString& /*fileName*/, int /*pageNumber*/, bool /*Mpage*/, const QString& /*renamedPageName*/)
393 {
394 return false;
395 }
396
readStyles(const QString &,ScribusDoc *,StyleSet<ParagraphStyle> &)397 bool LoadSavePlugin::readStyles(const QString& /*fileName*/, ScribusDoc* /*doc*/, StyleSet<ParagraphStyle> &/*docParagraphStyles*/)
398 {
399 return false;
400 }
401
readCharStyles(const QString &,ScribusDoc *,StyleSet<CharStyle> &)402 bool LoadSavePlugin::readCharStyles(const QString& /*fileName*/, ScribusDoc* /*doc*/, StyleSet<CharStyle> &/*docCharStyles*/)
403 {
404 return false;
405 }
406
readLineStyles(const QString &,QHash<QString,multiLine> *)407 bool LoadSavePlugin::readLineStyles(const QString& /*fileName*/, QHash<QString,multiLine>* /*Sty*/)
408 {
409 return false;
410 }
411
readColors(const QString &,ColorList &)412 bool LoadSavePlugin::readColors(const QString& /*fileName*/, ColorList & /*colors*/)
413 {
414 return false;
415 }
416
readPageCount(const QString &,int *,int *,QStringList &)417 bool LoadSavePlugin::readPageCount(const QString& /*fileName*/, int* /*num1*/, int* /*num2*/, QStringList & /*masterPageNames*/)
418 {
419 return false;
420 }
421
readThumbnail(const QString &)422 QImage LoadSavePlugin::readThumbnail(const QString& /*fileName*/)
423 {
424 return QImage();
425 }
426
loadStory(const QByteArray &,StoryText &,PageItem *)427 bool LoadSavePlugin::loadStory(const QByteArray& /*data*/, StoryText& /*story*/, PageItem* /*item*/)
428 {
429 return false;
430 }
431
saveStory(StoryText &,PageItem *,QByteArray &)432 bool LoadSavePlugin::saveStory(StoryText& /*story*/, PageItem* /*item*/, QByteArray& /*data*/)
433 {
434 return false;
435 }
436
loadFile(const QString & fileName,int flags,int index) const437 bool FileFormat::loadFile(const QString & fileName, int flags, int index) const
438 {
439 if (plug && load)
440 {
441 plug->clearLastError();
442 bool success = plug->loadFile(fileName, *this, flags, index);
443 if (!success && plug->hasLastError())
444 {
445 if (ScCore->usingGUI())
446 {
447 ScMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning, plug->lastError());
448 }
449 else
450 {
451 qDebug() << plug->lastError();
452 }
453 }
454 return success;
455 }
456 return false;
457 }
458
saveFile(const QString & fileName) const459 bool FileFormat::saveFile(const QString & fileName) const
460 {
461 return (plug && save) ? plug->saveFile(fileName, *this) : false;
462 }
463
savePalette(const QString & fileName) const464 bool FileFormat::savePalette(const QString & fileName) const
465 {
466 return (plug && save) ? plug->savePalette(fileName) : false;
467 }
468
saveElements(double xp,double yp,double wp,double hp,Selection * selection,QByteArray & prevData) const469 QString FileFormat::saveElements(double xp, double yp, double wp, double hp, Selection* selection, QByteArray &prevData) const
470 {
471 return (plug && save) ? plug->saveElements(xp, yp, wp, hp, selection, prevData) : "";
472 }
473
FileFormat()474 FileFormat::FileFormat()
475 {
476 }
477
FileFormat(LoadSavePlugin * plug)478 FileFormat::FileFormat(LoadSavePlugin* plug) :
479 plug(plug)
480 {
481 }
482
loadElements(const QString & data,const QString & fileDir,int toLayer,double Xp_in,double Yp_in,bool loc) const483 bool FileFormat::loadElements(const QString& data, const QString& fileDir, int toLayer, double Xp_in, double Yp_in, bool loc) const
484 {
485 return (plug && load) ? plug->loadElements(data, fileDir, toLayer, Xp_in, Yp_in, loc) : false;
486 }
487
loadPalette(const QString & fileName) const488 bool FileFormat::loadPalette(const QString & fileName) const
489 {
490 return (plug && load) ? plug->loadPalette(fileName) : false;
491 }
492
lastSavedFile() const493 QString FileFormat::lastSavedFile() const
494 {
495 if (plug)
496 return plug->lastSavedFile();
497 return QString();
498 }
499
setupTargets(ScribusDoc * targetDoc,ScribusView * targetView,ScribusMainWindow * targetMW,QProgressBar * targetMWPRogressBar,SCFonts * targetAvailableFonts) const500 void FileFormat::setupTargets(ScribusDoc *targetDoc, ScribusView* targetView, ScribusMainWindow* targetMW, QProgressBar* targetMWPRogressBar, SCFonts* targetAvailableFonts) const
501 {
502 if (plug)
503 plug->setupTargets(targetDoc, targetView, targetMW, targetMWPRogressBar, targetAvailableFonts);
504 }
505
getReplacedFontData(bool & getNewReplacement,QMap<QString,QString> & getReplacedFonts,QList<ScFace> & getDummyScFaces) const506 void FileFormat::getReplacedFontData(bool & getNewReplacement, QMap<QString,QString> &getReplacedFonts, QList<ScFace> &getDummyScFaces) const
507 {
508 if (plug)
509 plug->getReplacedFontData(getNewReplacement, getReplacedFonts, getDummyScFaces);
510 }
511
loadPage(const QString & fileName,int pageNumber,bool Mpage,const QString & renamedPageName) const512 bool FileFormat::loadPage(const QString & fileName, int pageNumber, bool Mpage, const QString& renamedPageName) const
513 {
514 if (!plug || !load)
515 return false;
516 plug->clearLastError();
517 bool success = plug->loadPage(fileName, pageNumber, Mpage, renamedPageName);
518 if (!success && plug->hasLastError())
519 {
520 if (ScCore->usingGUI())
521 ScMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning, plug->lastError());
522 else
523 qDebug() << plug->lastError();
524 }
525 return success;
526 }
527
readStyles(const QString & fileName,ScribusDoc * doc,StyleSet<ParagraphStyle> & docParagraphStyles) const528 bool FileFormat::readStyles(const QString& fileName, ScribusDoc* doc, StyleSet<ParagraphStyle> &docParagraphStyles) const
529 {
530 return (plug && load) ? plug->readStyles(fileName, doc, docParagraphStyles) : false;
531 }
532
readCharStyles(const QString & fileName,ScribusDoc * doc,StyleSet<CharStyle> & docCharStyles) const533 bool FileFormat::readCharStyles(const QString& fileName, ScribusDoc* doc, StyleSet<CharStyle> &docCharStyles) const
534 {
535 return (plug && load) ? plug->readCharStyles(fileName, doc, docCharStyles) : false;
536 }
537
readLineStyles(const QString & fileName,QHash<QString,multiLine> * Sty) const538 bool FileFormat::readLineStyles(const QString& fileName, QHash<QString, multiLine> *Sty) const
539 {
540 return (plug && load) ? plug->readLineStyles(fileName, Sty) : false;
541 }
542
readColors(const QString & fileName,ColorList & colors) const543 bool FileFormat::readColors(const QString& fileName, ColorList & colors) const
544 {
545 return (plug && load) ? plug->readColors(fileName, colors) : false;
546 }
547
readPageCount(const QString & fileName,int * num1,int * num2,QStringList & masterPageNames) const548 bool FileFormat::readPageCount(const QString& fileName, int *num1, int *num2, QStringList & masterPageNames) const
549 {
550 return (plug && load) ? plug->readPageCount(fileName, num1, num2, masterPageNames) : false;
551 }
552
readThumbnail(const QString & fileName) const553 QImage FileFormat::readThumbnail(const QString& fileName) const
554 {
555 return (plug && load && thumb) ? plug->readThumbnail(fileName) : QImage();
556 }
557
loadStory(const QByteArray & data,StoryText & story,PageItem * item) const558 bool FileFormat::loadStory(const QByteArray& data, StoryText& story, PageItem* item) const
559 {
560 return (plug && load) ? plug->loadStory(data, story, item) : false;
561 }
562
saveStory(StoryText & story,PageItem * item,QByteArray & data) const563 bool FileFormat::saveStory(StoryText& story, PageItem* item, QByteArray& data) const
564 {
565 return plug ? plug->saveStory(story, item, data) : false;
566 }
567