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 <QByteArray>
9 #include <QCursor>
10 #include <QDrag>
11 #include <QFile>
12 #include <QList>
13 #include <QMessageBox>
14 #include <QMimeData>
15 #include <QRegExp>
16 #include <QStack>
17 #include <QTextDocument>
18 #include <QDebug>
19 
20 #include <cstdlib>
21 
22 #include "importpub.h"
23 #include "../revenge/rawpainter.h"
24 #include <libmspub/libmspub.h>
25 
26 #include "commonstrings.h"
27 #include "fileloader.h"
28 #include "loadsaveplugin.h"
29 #include "pagesize.h"
30 #include "prefscontext.h"
31 #include "prefsfile.h"
32 #include "prefsmanager.h"
33 #include "prefstable.h"
34 #include "rawimage.h"
35 #include "scclocale.h"
36 #include "sccolorengine.h"
37 #include "scconfig.h"
38 #include "scmimedata.h"
39 #include "scpaths.h"
40 #include "scpattern.h"
41 #include "scribus.h"
42 #include "scribusXml.h"
43 #include "scribuscore.h"
44 #include "scribusdoc.h"
45 #include "scribusview.h"
46 #include "sctextstream.h"
47 #include "selection.h"
48 #include "ui/customfdialog.h"
49 #include "ui/missing.h"
50 #include "ui/multiprogressdialog.h"
51 #include "ui/propertiespalette.h"
52 #include "undomanager.h"
53 #include "util.h"
54 #include "util_formats.h"
55 #include "util_math.h"
56 
PubPlug(ScribusDoc * doc,int flags)57 PubPlug::PubPlug(ScribusDoc* doc, int flags)
58 {
59 	baseX = baseY = 0;
60 	docWidth = docHeight = 1;
61 
62 	tmpSel = new Selection(this, false);
63 	m_Doc = doc;
64 	importerFlags = flags;
65 	interactive = (flags & LoadSavePlugin::lfInteractive);
66 	progressDialog = nullptr;
67 	cancel = false;
68 }
69 
readThumbnail(const QString & fName)70 QImage PubPlug::readThumbnail(const QString& fName)
71 {
72 	QFileInfo fi = QFileInfo(fName);
73 	docWidth = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
74 	docHeight = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
75 	progressDialog = nullptr;
76 	m_Doc = new ScribusDoc();
77 	m_Doc->setup(0, 1, 1, 1, 1, "Custom", "Custom");
78 	m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
79 	m_Doc->addPage(0);
80 	m_Doc->setGUI(false, ScCore->primaryMainWindow(), nullptr);
81 	baseX = m_Doc->currentPage()->xOffset();
82 	baseY = m_Doc->currentPage()->yOffset();
83 	Elements.clear();
84 	m_Doc->setLoading(true);
85 	m_Doc->DoDrawing = false;
86 	m_Doc->scMW()->setScriptRunning(true);
87 	QString CurDirP = QDir::currentPath();
88 	QDir::setCurrent(fi.path());
89 	if (convert(fName))
90 	{
91 		tmpSel->clear();
92 		QDir::setCurrent(CurDirP);
93 		if (Elements.count() > 1)
94 			m_Doc->groupObjectsList(Elements);
95 		m_Doc->DoDrawing = true;
96 		m_Doc->m_Selection->delaySignalsOn();
97 		QImage tmpImage;
98 		if (Elements.count() > 0)
99 		{
100 			for (int dre=0; dre<Elements.count(); ++dre)
101 			{
102 				tmpSel->addItem(Elements.at(dre), true);
103 			}
104 			tmpSel->setGroupRect();
105 			double xs = tmpSel->width();
106 			double ys = tmpSel->height();
107 			tmpImage = Elements.at(0)->DrawObj_toImage(500);
108 			tmpImage.setText("XSize", QString("%1").arg(xs));
109 			tmpImage.setText("YSize", QString("%1").arg(ys));
110 		}
111 		m_Doc->scMW()->setScriptRunning(false);
112 		m_Doc->setLoading(false);
113 		m_Doc->m_Selection->delaySignalsOff();
114 		delete m_Doc;
115 		return tmpImage;
116 	}
117 	QDir::setCurrent(CurDirP);
118 	m_Doc->DoDrawing = true;
119 	m_Doc->scMW()->setScriptRunning(false);
120 	delete m_Doc;
121 	return QImage();
122 }
123 
import(const QString & fNameIn,const TransactionSettings & trSettings,int flags,bool showProgress)124 bool PubPlug::import(const QString& fNameIn, const TransactionSettings& trSettings, int flags, bool showProgress)
125 {
126 	bool success = false;
127 	interactive = (flags & LoadSavePlugin::lfInteractive);
128 	importerFlags = flags;
129 	cancel = false;
130 	bool ret = false;
131 	QFileInfo fi = QFileInfo(fNameIn);
132 	if ( !ScCore->usingGUI() )
133 	{
134 		interactive = false;
135 		showProgress = false;
136 	}
137 	if ( showProgress )
138 	{
139 		ScribusMainWindow* mw=(m_Doc==nullptr) ? ScCore->primaryMainWindow() : m_Doc->scMW();
140 		progressDialog = new MultiProgressDialog( tr("Importing: %1").arg(fi.fileName()), CommonStrings::tr_Cancel, mw );
141 		QStringList barNames, barTexts;
142 		barNames << "GI";
143 		barTexts << tr("Analyzing File:");
144 		QList<bool> barsNumeric;
145 		barsNumeric << false;
146 		progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
147 		progressDialog->setOverallTotalSteps(3);
148 		progressDialog->setOverallProgress(0);
149 		progressDialog->setProgress("GI", 0);
150 		progressDialog->show();
151 		connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
152 		qApp->processEvents();
153 	}
154 	else
155 		progressDialog = nullptr;
156 /* Set default Page to size defined in Preferences */
157 	double w = 0.0;
158 	double h = 0.0;
159 	if (progressDialog)
160 	{
161 		progressDialog->setOverallProgress(1);
162 		qApp->processEvents();
163 	}
164 	if (w == 0.0)
165 		w = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
166 	if (h == 0.0)
167 		h = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
168 	docWidth = w;
169 	docHeight = h;
170 	baseX = 0;
171 	baseY = 0;
172 	if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
173 	{
174 		m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
175 		m_Doc->addPage(0);
176 		m_Doc->view()->addPage(0, true);
177 		baseX = 0;
178 		baseY = 0;
179 	}
180 	else
181 	{
182 		if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
183 		{
184 			m_Doc=ScCore->primaryMainWindow()->doFileNew(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
185 			ScCore->primaryMainWindow()->HaveNewDoc();
186 			ret = true;
187 			baseX = 0;
188 			baseY = 0;
189 			baseX = m_Doc->currentPage()->xOffset();
190 			baseY = m_Doc->currentPage()->yOffset();
191 		}
192 	}
193 	if ((!ret) && (interactive))
194 	{
195 		baseX = m_Doc->currentPage()->xOffset();
196 		baseY = m_Doc->currentPage()->yOffset();
197 	}
198 	if ((ret) || (!interactive))
199 	{
200 		if (docWidth > docHeight)
201 			m_Doc->setPageOrientation(1);
202 		else
203 			m_Doc->setPageOrientation(0);
204 		m_Doc->setPageSize("Custom");
205 	}
206 	if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
207 		m_Doc->view()->deselectItems();
208 	Elements.clear();
209 	m_Doc->setLoading(true);
210 	m_Doc->DoDrawing = false;
211 	if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
212 		m_Doc->view()->updatesOn(false);
213 	m_Doc->scMW()->setScriptRunning(true);
214 	qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
215 	QString CurDirP = QDir::currentPath();
216 	QDir::setCurrent(fi.path());
217 	if (convert(fNameIn))
218 	{
219 		tmpSel->clear();
220 		QDir::setCurrent(CurDirP);
221 		if ((Elements.count() > 1) && (!(importerFlags & LoadSavePlugin::lfCreateDoc)))
222 			m_Doc->groupObjectsList(Elements);
223 		m_Doc->DoDrawing = true;
224 		m_Doc->scMW()->setScriptRunning(false);
225 		m_Doc->setLoading(false);
226 		qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
227 		if ((Elements.count() > 0) && (!ret) && (interactive))
228 		{
229 			if (flags & LoadSavePlugin::lfScripted)
230 			{
231 				bool loadF = m_Doc->isLoading();
232 				m_Doc->setLoading(false);
233 				m_Doc->changed();
234 				m_Doc->setLoading(loadF);
235 				if (!(flags & LoadSavePlugin::lfLoadAsPattern))
236 				{
237 					m_Doc->m_Selection->delaySignalsOn();
238 					for (int dre=0; dre<Elements.count(); ++dre)
239 					{
240 						m_Doc->m_Selection->addItem(Elements.at(dre), true);
241 					}
242 					m_Doc->m_Selection->delaySignalsOff();
243 					m_Doc->m_Selection->setGroupRect();
244 					if (m_Doc->view() != nullptr)
245 						m_Doc->view()->updatesOn(true);
246 				}
247 			}
248 			else
249 			{
250 				m_Doc->DragP = true;
251 				m_Doc->DraggedElem = nullptr;
252 				m_Doc->DragElements.clear();
253 				m_Doc->m_Selection->delaySignalsOn();
254 				for (int dre=0; dre<Elements.count(); ++dre)
255 				{
256 					tmpSel->addItem(Elements.at(dre), true);
257 				}
258 				tmpSel->setGroupRect();
259 				ScElemMimeData* md = ScriXmlDoc::writeToMimeData(m_Doc, tmpSel);
260 				m_Doc->itemSelection_DeleteItem(tmpSel);
261 				m_Doc->view()->updatesOn(true);
262 				if (importedPatterns.count() != 0)
263 				{
264 					for (int cd = 0; cd < importedPatterns.count(); cd++)
265 					{
266 						m_Doc->docPatterns.remove(importedPatterns[cd]);
267 					}
268 				}
269 				if (importedColors.count() != 0)
270 				{
271 					for (int cd = 0; cd < importedColors.count(); cd++)
272 					{
273 						m_Doc->PageColors.remove(importedColors[cd]);
274 					}
275 				}
276 				m_Doc->m_Selection->delaySignalsOff();
277 				// We must copy the TransationSettings object as it is owned
278 				// by handleObjectImport method afterwards
279 				TransactionSettings* transacSettings = new TransactionSettings(trSettings);
280 				m_Doc->view()->handleObjectImport(md, transacSettings);
281 				m_Doc->DragP = false;
282 				m_Doc->DraggedElem = nullptr;
283 				m_Doc->DragElements.clear();
284 			}
285 		}
286 		else
287 		{
288 			m_Doc->changed();
289 			m_Doc->reformPages();
290 			if (!(flags & LoadSavePlugin::lfLoadAsPattern))
291 				m_Doc->view()->updatesOn(true);
292 		}
293 		success = true;
294 	}
295 	else
296 	{
297 		QDir::setCurrent(CurDirP);
298 		m_Doc->DoDrawing = true;
299 		m_Doc->scMW()->setScriptRunning(false);
300 		m_Doc->view()->updatesOn(true);
301 		qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
302 	}
303 	if (interactive)
304 		m_Doc->setLoading(false);
305 	//CB If we have a gui we must refresh it if we have used the progressbar
306 	if (!(flags & LoadSavePlugin::lfLoadAsPattern))
307 	{
308 		if ((showProgress) && (!interactive))
309 			m_Doc->view()->DrawNew();
310 	}
311 	qApp->restoreOverrideCursor();
312 	return success;
313 }
314 
~PubPlug()315 PubPlug::~PubPlug()
316 {
317 	delete progressDialog;
318 	delete tmpSel;
319 }
320 
convert(const QString & fn)321 bool PubPlug::convert(const QString& fn)
322 {
323 	importedColors.clear();
324 	importedPatterns.clear();
325 
326 	QFile file(fn);
327 	if (!file.exists())
328 	{
329 		qDebug() << "File " << QFile::encodeName(fn).data() << " does not exist";
330 		return false;
331 	}
332 
333 #if HAVE_REVENGE
334 	librevenge::RVNGFileStream input(QFile::encodeName(fn).data());
335 #else
336 	WPXFileStream input(QFile::encodeName(fn).data());
337 #endif
338 	if (!libmspub::MSPUBDocument::isSupported(&input))
339 	{
340 		qDebug() << "ERROR: Unsupported file format!";
341 		return false;
342 	}
343 	RawPainter painter(m_Doc, baseX, baseY, docWidth, docHeight, importerFlags, &Elements, &importedColors, &importedPatterns, tmpSel, "pub");
344 	if (!libmspub::MSPUBDocument::parse(&input, &painter))
345 	{
346 		qDebug() << "ERROR: Parsing failed!";
347 		if (progressDialog)
348 			progressDialog->close();
349 		if (importerFlags & LoadSavePlugin::lfCreateDoc)
350 		{
351 			ScribusMainWindow* mw=(m_Doc==nullptr) ? ScCore->primaryMainWindow() : m_Doc->scMW();
352 			qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
353 			ScMessageBox::warning(mw, CommonStrings::trWarning, tr("Parsing failed!\n\nPlease submit your file (if possible) to the\nDocument Liberation Project http://www.documentliberation.org"));
354 			qApp->changeOverrideCursor(QCursor(Qt::WaitCursor));
355 		}
356 		return false;
357 	}
358 	if (Elements.count() == 0)
359 	{
360 		if (importedColors.count() != 0)
361 		{
362 			for (int cd = 0; cd < importedColors.count(); cd++)
363 			{
364 				m_Doc->PageColors.remove(importedColors[cd]);
365 			}
366 		}
367 		if (importedPatterns.count() != 0)
368 		{
369 			for (int cd = 0; cd < importedPatterns.count(); cd++)
370 			{
371 				m_Doc->docPatterns.remove(importedPatterns[cd]);
372 			}
373 		}
374 	}
375 	if (progressDialog)
376 		progressDialog->close();
377 	return true;
378 }
379