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 <QByteArray>
11 #include <QCursor>
12 #include <QDrag>
13 #include <QFile>
14 #include <QList>
15 #include <QMimeData>
16 #include <QRegExp>
17 #include <QStack>
18 #include <QDebug>
19 
20 #include <cstdlib>
21 
22 #include "importxfig.h"
23 
24 #include "commonstrings.h"
25 #include "loadsaveplugin.h"
26 #include "pageitem.h"
27 #include "pagesize.h"
28 #include "prefscontext.h"
29 #include "prefsfile.h"
30 #include "prefsmanager.h"
31 #include "prefstable.h"
32 #include "rawimage.h"
33 #include "scclocale.h"
34 #include "sccolorengine.h"
35 #include "scconfig.h"
36 #include "scmimedata.h"
37 #include "scpaths.h"
38 #include "scpattern.h"
39 #include "scribusXml.h"
40 #include "scribuscore.h"
41 #include "scribusdoc.h"
42 #include "scribusview.h"
43 #include "sctextstream.h"
44 #include "selection.h"
45 #include "ui/customfdialog.h"
46 #include "ui/missing.h"
47 #include "ui/multiprogressdialog.h"
48 #include "ui/propertiespalette.h"
49 #include "undomanager.h"
50 #include "util.h"
51 #include "util_formats.h"
52 #include "util_math.h"
53 
XfigPlug(ScribusDoc * doc,int flags)54 XfigPlug::XfigPlug(ScribusDoc* doc, int flags)
55 {
56 	tmpSel=new Selection(this, false);
57 	m_Doc=doc;
58 	importerFlags = flags;
59 	interactive = (flags & LoadSavePlugin::lfInteractive);
60 	progressDialog = nullptr;
61 }
62 
readThumbnail(const QString & fName)63 QImage XfigPlug::readThumbnail(const QString& fName)
64 {
65 	QFileInfo fi = QFileInfo(fName);
66 	baseFile = QDir::cleanPath(QDir::toNativeSeparators(fi.absolutePath()+"/"));
67 	double w=0.0, h=0.0, x=0.0, y=0.0;
68 	parseHeader(fName, x, y, w, h);
69 	docX = x;
70 	docY = y;
71 	if (w == 0.0)
72 		w = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
73 	if (h == 0.0)
74 		h = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
75 	docWidth = w - x;
76 	docHeight = h - y;
77 	progressDialog = nullptr;
78 	m_Doc = new ScribusDoc();
79 	m_Doc->setup(0, 1, 1, 1, 1, "Custom", "Custom");
80 	m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
81 	m_Doc->addPage(0);
82 	m_Doc->setGUI(false, ScCore->primaryMainWindow(), nullptr);
83 	baseX = m_Doc->currentPage()->xOffset();
84 	baseY = m_Doc->currentPage()->yOffset();
85 	Elements.clear();
86 	CustColors.clear();
87 	importedColors.insert(0, "Black");
88 	importedColors.insert(1, "Blue");
89 	importedColors.insert(2, "Green");
90 	importedColors.insert(3, "Cyan");
91 	importedColors.insert(4, "Red");
92 	importedColors.insert(5, "Magenta");
93 	importedColors.insert(6, "Yellow");
94 	importedColors.insert(7, "White");
95 	importedColors.insert(8, "Blue4");
96 	importedColors.insert(9, "Blue3");
97 	importedColors.insert(10, "Blue2");
98 	importedColors.insert(11, "LtBlue");
99 	importedColors.insert(12, "Green4");
100 	importedColors.insert(13, "Green3");
101 	importedColors.insert(14, "Green2");
102 	importedColors.insert(15, "Cyan4");
103 	importedColors.insert(16, "Cyan3");
104 	importedColors.insert(17, "Cyan2");
105 	importedColors.insert(18, "Red4");
106 	importedColors.insert(19, "Red3");
107 	importedColors.insert(20, "Red2");
108 	importedColors.insert(21, "Magenta4");
109 	importedColors.insert(22, "Magenta3");
110 	importedColors.insert(23, "Magenta2");
111 	importedColors.insert(24, "Brown4");
112 	importedColors.insert(25, "Brown3");
113 	importedColors.insert(26, "Brown2");
114 	importedColors.insert(27, "Pink4");
115 	importedColors.insert(28, "Pink3");
116 	importedColors.insert(29, "Pink2");
117 	importedColors.insert(30, "Pink");
118 	importedColors.insert(31, "Gold");
119 	CustColors.insert("Blue", ScColor(0, 0, 255));
120 	CustColors.insert("Blue4", ScColor(0, 0, 144));
121 	CustColors.insert("Blue3", ScColor(0, 0, 176));
122 	CustColors.insert("Blue2", ScColor(0, 0, 208));
123 	CustColors.insert("LtBlue", ScColor(135, 206, 255));
124 	CustColors.insert("Cyan", ScColor(255, 0, 0, 0));
125 	CustColors.insert("Cyan4", ScColor(0, 144, 144));
126 	CustColors.insert("Cyan3", ScColor(0, 176, 176));
127 	CustColors.insert("Cyan2", ScColor(0, 208, 208));
128 	CustColors.insert("Green", ScColor(255, 0, 255, 0));
129 	CustColors.insert("Green4", ScColor(0, 144, 0));
130 	CustColors.insert("Green3", ScColor(0, 176, 0));
131 	CustColors.insert("Green2", ScColor(0, 208, 0));
132 	CustColors.insert("Red", ScColor(0, 255, 255, 0));
133 	CustColors.insert("Red4", ScColor(144, 0, 0));
134 	CustColors.insert("Red3", ScColor(176, 0, 0));
135 	CustColors.insert("Red2", ScColor(208, 0, 0));
136 	CustColors.insert("Yellow", ScColor(0, 0, 255, 0));
137 	CustColors.insert("Magenta", ScColor(0, 255, 0, 0));
138 	CustColors.insert("Magenta4", ScColor(144, 0, 144));
139 	CustColors.insert("Magenta3", ScColor(176, 0, 176));
140 	CustColors.insert("Magenta2", ScColor(208, 0, 208));
141 	CustColors.insert("Brown4", ScColor(128, 48, 0));
142 	CustColors.insert("Brown3", ScColor(160, 64, 0));
143 	CustColors.insert("Brown2", ScColor(192, 96, 0));
144 	CustColors.insert("Pink4", ScColor(255, 128, 128));
145 	CustColors.insert("Pink3", ScColor(255, 160, 160));
146 	CustColors.insert("Pink2", ScColor(255, 192, 192));
147 	CustColors.insert("Pink", ScColor(255, 224, 224));
148 	CustColors.insert("Gold", ScColor(255, 215, 0));
149 	m_Doc->setLoading(true);
150 	m_Doc->DoDrawing = false;
151 	m_Doc->scMW()->setScriptRunning(true);
152 	QString CurDirP = QDir::currentPath();
153 	QDir::setCurrent(fi.path());
154 	if (convert(fName))
155 	{
156 		tmpSel->clear();
157 		QDir::setCurrent(CurDirP);
158 		if (Elements.count() > 1)
159 			m_Doc->groupObjectsList(Elements);
160 		m_Doc->DoDrawing = true;
161 		m_Doc->m_Selection->delaySignalsOn();
162 		QImage tmpImage;
163 		if (Elements.count() > 0)
164 		{
165 			for (int dre=0; dre<Elements.count(); ++dre)
166 			{
167 				tmpSel->addItem(Elements.at(dre), true);
168 			}
169 			tmpSel->setGroupRect();
170 			double xs = tmpSel->width();
171 			double ys = tmpSel->height();
172 			tmpImage = Elements.at(0)->DrawObj_toImage(500);
173 			tmpImage.setText("XSize", QString("%1").arg(xs));
174 			tmpImage.setText("YSize", QString("%1").arg(ys));
175 		}
176 		m_Doc->scMW()->setScriptRunning(false);
177 		m_Doc->setLoading(false);
178 		m_Doc->m_Selection->delaySignalsOff();
179 		delete m_Doc;
180 		return tmpImage;
181 	}
182 	QDir::setCurrent(CurDirP);
183 	m_Doc->DoDrawing = true;
184 	m_Doc->scMW()->setScriptRunning(false);
185 	delete m_Doc;
186 	return QImage();
187 }
188 
import(const QString & fNameIn,const TransactionSettings & trSettings,int flags,bool showProgress)189 bool XfigPlug::import(const QString& fNameIn, const TransactionSettings& trSettings, int flags, bool showProgress)
190 {
191 	bool success = false;
192 	interactive = (flags & LoadSavePlugin::lfInteractive);
193 	importerFlags = flags;
194 	cancel = false;
195 	double x, y, b, h;
196 	bool ret = false;
197 	CustColors.clear();
198 	importedColors.insert(0, "Black");
199 	importedColors.insert(1, "Blue");
200 	importedColors.insert(2, "Green");
201 	importedColors.insert(3, "Cyan");
202 	importedColors.insert(4, "Red");
203 	importedColors.insert(5, "Magenta");
204 	importedColors.insert(6, "Yellow");
205 	importedColors.insert(7, "White");
206 	importedColors.insert(8, "Blue4");
207 	importedColors.insert(9, "Blue3");
208 	importedColors.insert(10, "Blue2");
209 	importedColors.insert(11, "LtBlue");
210 	importedColors.insert(12, "Green4");
211 	importedColors.insert(13, "Green3");
212 	importedColors.insert(14, "Green2");
213 	importedColors.insert(15, "Cyan4");
214 	importedColors.insert(16, "Cyan3");
215 	importedColors.insert(17, "Cyan2");
216 	importedColors.insert(18, "Red4");
217 	importedColors.insert(19, "Red3");
218 	importedColors.insert(20, "Red2");
219 	importedColors.insert(21, "Magenta4");
220 	importedColors.insert(22, "Magenta3");
221 	importedColors.insert(23, "Magenta2");
222 	importedColors.insert(24, "Brown4");
223 	importedColors.insert(25, "Brown3");
224 	importedColors.insert(26, "Brown2");
225 	importedColors.insert(27, "Pink4");
226 	importedColors.insert(28, "Pink3");
227 	importedColors.insert(29, "Pink2");
228 	importedColors.insert(30, "Pink");
229 	importedColors.insert(31, "Gold");
230 	CustColors.insert("Blue", ScColor(0, 0, 255));
231 	CustColors.insert("Blue4", ScColor(0, 0, 144));
232 	CustColors.insert("Blue3", ScColor(0, 0, 176));
233 	CustColors.insert("Blue2", ScColor(0, 0, 208));
234 	CustColors.insert("LtBlue", ScColor(135, 206, 255));
235 	CustColors.insert("Cyan", ScColor(255, 0, 0, 0));
236 	CustColors.insert("Cyan4", ScColor(0, 144, 144));
237 	CustColors.insert("Cyan3", ScColor(0, 176, 176));
238 	CustColors.insert("Cyan2", ScColor(0, 208, 208));
239 	CustColors.insert("Green", ScColor(255, 0, 255, 0));
240 	CustColors.insert("Green4", ScColor(0, 144, 0));
241 	CustColors.insert("Green3", ScColor(0, 176, 0));
242 	CustColors.insert("Green2", ScColor(0, 208, 0));
243 	CustColors.insert("Red", ScColor(0, 255, 255, 0));
244 	CustColors.insert("Red4", ScColor(144, 0, 0));
245 	CustColors.insert("Red3", ScColor(176, 0, 0));
246 	CustColors.insert("Red2", ScColor(208, 0, 0));
247 	CustColors.insert("Yellow", ScColor(0, 0, 255, 0));
248 	CustColors.insert("Magenta", ScColor(0, 255, 0, 0));
249 	CustColors.insert("Magenta4", ScColor(144, 0, 144));
250 	CustColors.insert("Magenta3", ScColor(176, 0, 176));
251 	CustColors.insert("Magenta2", ScColor(208, 0, 208));
252 	CustColors.insert("Brown4", ScColor(128, 48, 0));
253 	CustColors.insert("Brown3", ScColor(160, 64, 0));
254 	CustColors.insert("Brown2", ScColor(192, 96, 0));
255 	CustColors.insert("Pink4", ScColor(255, 128, 128));
256 	CustColors.insert("Pink3", ScColor(255, 160, 160));
257 	CustColors.insert("Pink2", ScColor(255, 192, 192));
258 	CustColors.insert("Pink", ScColor(255, 224, 224));
259 	CustColors.insert("Gold", ScColor(255, 215, 0));
260 	QFileInfo fi = QFileInfo(fNameIn);
261 	if ( !ScCore->usingGUI() )
262 	{
263 		interactive = false;
264 		showProgress = false;
265 	}
266 	baseFile = QDir::cleanPath(QDir::toNativeSeparators(fi.absolutePath()+"/"));
267 	if ( showProgress )
268 	{
269 		ScribusMainWindow* mw=(m_Doc==nullptr) ? ScCore->primaryMainWindow() : m_Doc->scMW();
270 		progressDialog = new MultiProgressDialog( tr("Importing: %1").arg(fi.fileName()), CommonStrings::tr_Cancel, mw );
271 		QStringList barNames, barTexts;
272 		barNames << "GI";
273 		barTexts << tr("Analyzing File:");
274 		QList<bool> barsNumeric;
275 		barsNumeric << false;
276 		progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
277 		progressDialog->setOverallTotalSteps(3);
278 		progressDialog->setOverallProgress(0);
279 		progressDialog->setProgress("GI", 0);
280 		progressDialog->show();
281 		connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
282 		qApp->processEvents();
283 	}
284 	else
285 		progressDialog = nullptr;
286 /* Set default Page to size defined in Preferences */
287 	x = 0.0;
288 	y = 0.0;
289 	b = 0.0;
290 	h = 0.0;
291 	if (progressDialog)
292 	{
293 		progressDialog->setOverallProgress(1);
294 		qApp->processEvents();
295 	}
296 	parseHeader(fNameIn, x, y, b, h);
297 	docX = x;
298 	docY = y;
299 	if (b == 0.0)
300 		b = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
301 	if (h == 0.0)
302 		h = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
303 	docWidth = b - x;
304 	docHeight = h - y;
305 	baseX = 0;
306 	baseY = 0;
307 	if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
308 	{
309 		m_Doc->setPage(b-x, h-y, 0, 0, 0, 0, 0, 0, false, false);
310 		m_Doc->addPage(0);
311 		m_Doc->view()->addPage(0, true);
312 		baseX = 0;
313 		baseY = 0;
314 	}
315 	else
316 	{
317 		if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
318 		{
319 			m_Doc=ScCore->primaryMainWindow()->doFileNew(b-x, h-y, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
320 			ScCore->primaryMainWindow()->HaveNewDoc();
321 			ret = true;
322 			baseX = 0;
323 			baseY = 0;
324 		}
325 	}
326 	if (flags & LoadSavePlugin::lfCreateDoc)
327 	{
328 		m_Doc->documentInfo().setAuthor(docCreator);
329 		m_Doc->documentInfo().setPublisher(docOrganisation);
330 		m_Doc->documentInfo().setTitle(docTitle);
331 		m_Doc->documentInfo().setDate(docDate+" "+docTime);
332 	}
333 	if ((!ret) && (interactive))
334 	{
335 		baseX = m_Doc->currentPage()->xOffset();
336 		baseY = m_Doc->currentPage()->yOffset();
337 	}
338 	if ((ret) || (!interactive))
339 	{
340 		if (b-x > h-y)
341 			m_Doc->setPageOrientation(1);
342 		else
343 			m_Doc->setPageOrientation(0);
344 		m_Doc->setPageSize("Custom");
345 	}
346 	if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
347 		m_Doc->view()->deselectItems();
348 	Elements.clear();
349 	m_Doc->setLoading(true);
350 	m_Doc->DoDrawing = false;
351 	if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
352 		m_Doc->view()->updatesOn(false);
353 	m_Doc->scMW()->setScriptRunning(true);
354 	qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
355 	QString CurDirP = QDir::currentPath();
356 	QDir::setCurrent(fi.path());
357 	if (convert(fNameIn))
358 	{
359 		tmpSel->clear();
360 		QDir::setCurrent(CurDirP);
361 		if ((Elements.count() > 1) && (!(importerFlags & LoadSavePlugin::lfCreateDoc)))
362 			m_Doc->groupObjectsList(Elements);
363 		m_Doc->DoDrawing = true;
364 		m_Doc->scMW()->setScriptRunning(false);
365 		m_Doc->setLoading(false);
366 		qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
367 		if ((Elements.count() > 0) && (!ret) && (interactive))
368 		{
369 			if (flags & LoadSavePlugin::lfScripted)
370 			{
371 				bool loadF = m_Doc->isLoading();
372 				m_Doc->setLoading(false);
373 				m_Doc->changed();
374 				m_Doc->setLoading(loadF);
375 				if (!(flags & LoadSavePlugin::lfLoadAsPattern))
376 				{
377 					m_Doc->m_Selection->delaySignalsOn();
378 					for (int dre=0; dre<Elements.count(); ++dre)
379 					{
380 						m_Doc->m_Selection->addItem(Elements.at(dre), true);
381 					}
382 					m_Doc->m_Selection->delaySignalsOff();
383 					m_Doc->m_Selection->setGroupRect();
384 					if (m_Doc->view() != nullptr)
385 						m_Doc->view()->updatesOn(true);
386 				}
387 			}
388 			else
389 			{
390 				m_Doc->DragP = true;
391 				m_Doc->DraggedElem = nullptr;
392 				m_Doc->DragElements.clear();
393 				m_Doc->m_Selection->delaySignalsOn();
394 				for (int dre=0; dre<Elements.count(); ++dre)
395 				{
396 					tmpSel->addItem(Elements.at(dre), true);
397 				}
398 				tmpSel->setGroupRect();
399 				ScElemMimeData* md = ScriXmlDoc::writeToMimeData(m_Doc, tmpSel);
400 				m_Doc->itemSelection_DeleteItem(tmpSel);
401 				m_Doc->view()->updatesOn(true);
402 				m_Doc->m_Selection->delaySignalsOff();
403 				// We must copy the TransationSettings object as it is owned
404 				// by handleObjectImport method afterwards
405 				TransactionSettings* transacSettings = new TransactionSettings(trSettings);
406 				m_Doc->view()->handleObjectImport(md, transacSettings);
407 				m_Doc->DragP = false;
408 				m_Doc->DraggedElem = nullptr;
409 				m_Doc->DragElements.clear();
410 			}
411 		}
412 		else
413 		{
414 			m_Doc->changed();
415 			m_Doc->reformPages();
416 			if (!(flags & LoadSavePlugin::lfLoadAsPattern))
417 				m_Doc->view()->updatesOn(true);
418 		}
419 		success = true;
420 	}
421 	else
422 	{
423 		QDir::setCurrent(CurDirP);
424 		m_Doc->DoDrawing = true;
425 		m_Doc->scMW()->setScriptRunning(false);
426 		m_Doc->view()->updatesOn(true);
427 		qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
428 	}
429 	if (interactive)
430 		m_Doc->setLoading(false);
431 	//CB If we have a gui we must refresh it if we have used the progressbar
432 	if (!(flags & LoadSavePlugin::lfLoadAsPattern))
433 	{
434 		if ((showProgress) && (!interactive))
435 			m_Doc->view()->DrawNew();
436 	}
437 	qApp->restoreOverrideCursor();
438 	return success;
439 }
440 
~XfigPlug()441 XfigPlug::~XfigPlug()
442 {
443 	delete progressDialog;
444 	delete tmpSel;
445 }
446 
parseHeader(const QString & fName,double & x,double & y,double & b,double & h)447 bool XfigPlug::parseHeader(const QString& fName, double &x, double &y, double &b, double &h)
448 {
449 	bool found = false;
450 	QFile f(fName);
451 	if (f.open(QIODevice::ReadOnly))
452 	{
453 		QDataStream ts(&f);
454 		QString version = readLineFromDataStream(ts);
455 		if (!version.startsWith("#FIG 3"))
456 		{
457 			f.close();
458 			return false;
459 		}
460 		QString orientation = readLineFromDataStream(ts);
461 		QString justification = readLineFromDataStream(ts);
462 		QString units = readLineFromDataStream(ts);
463 		QString papersize = readLineFromDataStream(ts);
464 		PageSize ps(papersize);
465 		if (orientation.startsWith("Landscape"))
466 		{
467 			h = ps.width();
468 			b = ps.height();
469 		}
470 		else
471 		{
472 			b = ps.width();
473 			h = ps.height();
474 		}
475 		f.close();
476 		found = true;
477 	}
478 	return found;
479 }
480 
parseColor(QString data)481 void XfigPlug::parseColor(QString data)
482 {
483 	if (data.isEmpty())
484 		return;
485 	int colorNum, dummy;
486 	QString colorValues;
487 	ScColor tmp;
488 	ScTextStream Code(&data, QIODevice::ReadOnly);
489 	Code >> dummy >> colorNum >> colorValues;
490 	tmp.setNamedColor(colorValues);
491 	tmp.setSpotColor(false);
492 	tmp.setRegistrationColor(false);
493 	QString namPrefix = "FromXfig%1-"+colorValues;
494 	CustColors.insert(namPrefix.arg(colorNum), tmp);
495 	importedColors.insert(colorNum, namPrefix.arg(colorNum));
496 }
497 
useColor(int colorNum,int area_fill,bool forFill)498 void XfigPlug::useColor(int colorNum, int area_fill, bool forFill)
499 {
500 	QString color = CommonStrings::None;
501 	int shade = 100;
502 	if (forFill)
503 	{
504 		if (area_fill == -1)
505 			color = CommonStrings::None;
506 		else
507 		{
508 			if ((colorNum == -1) || (colorNum == 0))
509 			{
510 				if (area_fill == 0)
511 				{
512 					color = "White";
513 					shade = 100;
514 				}
515 				else if (area_fill == 20)
516 				{
517 					color = "Black";
518 					shade = 100;
519 				}
520 				else if ((area_fill > 0) && (area_fill < 20))
521 				{
522 					color = "Black";
523 					shade = qRound(100.0 / 19.0 * area_fill);
524 				}
525 			}
526 			else if (colorNum == 7)
527 			{
528 				if (area_fill == 0)
529 				{
530 					color = "Black";
531 					shade = 100;
532 				}
533 				else if (area_fill == 20)
534 				{
535 					color = "White";
536 					shade = 100;
537 				}
538 				else if ((area_fill > 0) && (area_fill < 20))
539 				{
540 					color = "Black";
541 					shade = qRound(100.0 / 19.0 * (20 - area_fill));
542 				}
543 			}
544 			else
545 			{
546 				if (importedColors.contains(colorNum))
547 				{
548 					color = importedColors[colorNum];
549 					if (!m_Doc->PageColors.contains(color))
550 						m_Doc->PageColors.insert(color, CustColors[color]);
551 					int sat = area_fill - 20;
552 					if ((sat > 0) && (sat < 20))
553 						shade = qRound(100.0 / 19.0 * sat);
554 				}
555 				else
556 					color = CommonStrings::None;
557 			}
558 		}
559 		CurrColorFill = color;
560 		CurrFillShade = shade;
561 	}
562 	else
563 	{
564 		if (area_fill == -1)
565 			CurrColorStroke = CommonStrings::None;
566 		else
567 		{
568 			if ((colorNum == -1) || (colorNum == 0))
569 				CurrColorStroke = "Black";
570 			else
571 			{
572 				if (importedColors.contains(colorNum))
573 				{
574 					CurrColorStroke = importedColors[colorNum];
575 					if (!m_Doc->PageColors.contains(CurrColorStroke))
576 						m_Doc->PageColors.insert(CurrColorStroke, CustColors[CurrColorStroke]);
577 				}
578 				else
579 					CurrColorStroke = CommonStrings::None;
580 			}
581 		}
582 	}
583 }
584 
getDashValues(double linewidth,int code)585 QVector<double> XfigPlug::getDashValues(double linewidth, int code)
586 {
587 	QVector<double> tmp;
588 	if (code == 1)
589 	{
590 		tmp << qMax(4.0 * linewidth, 0.1);
591 		tmp << qMax(2.0 * linewidth, 0.1);
592 	}
593 	else if (code == 2)
594 	{
595 		tmp << qMax(1.0 * linewidth, 0.1);
596 		tmp << qMax(2.0 * linewidth, 0.1);
597 	}
598 	else if (code == 3)
599 	{
600 		tmp << qMax(4.0 * linewidth, 0.1);
601 		tmp << qMax(2.0 * linewidth, 0.1);
602 		tmp << qMax(1.0 * linewidth, 0.1);
603 		tmp << qMax(2.0 * linewidth, 0.1);
604 	}
605 	else if (code == 4)
606 	{
607 		tmp << qMax(4.0 * linewidth, 0.1);
608 		tmp << qMax(2.0 * linewidth, 0.1);
609 		tmp << qMax(1.0 * linewidth, 0.1);
610 		tmp << qMax(2.0 * linewidth, 0.1);
611 		tmp << qMax(1.0 * linewidth, 0.1);
612 		tmp << qMax(2.0 * linewidth, 0.1);
613 	}
614 	else if (code == 5)
615 	{
616 		tmp << qMax(4.0 * linewidth, 0.1);
617 		tmp << qMax(2.0 * linewidth, 0.1);
618 		tmp << qMax(1.0 * linewidth, 0.1);
619 		tmp << qMax(2.0 * linewidth, 0.1);
620 		tmp << qMax(1.0 * linewidth, 0.1);
621 		tmp << qMax(2.0 * linewidth, 0.1);
622 		tmp << qMax(1.0 * linewidth, 0.1);
623 		tmp << qMax(2.0 * linewidth, 0.1);
624 	}
625 	return tmp;
626 }
627 
processArrows(int forward_arrow,QString fArrowData,int backward_arrow,QString bArrowData,int depth,PageItem * ite)628 void XfigPlug::processArrows(int forward_arrow, QString fArrowData, int backward_arrow, QString bArrowData, int depth, PageItem *ite)
629 {
630 	int		arrow_typeAF;			// (enumeration type)
631 	int		arrow_styleAF;			// (enumeration type)
632 	float	arrow_thicknessAF;		// (1/80 inch)
633 	float	arrow_widthAF;			// (Fig units)
634 	float	arrow_heightAF;			// (Fig units)
635 	int		arrow_typeAB;			// (enumeration type)
636 	int		arrow_styleAB;			// (enumeration type)
637 	float	arrow_thicknessAB;		// (1/80 inch)
638 	float	arrow_widthAB;			// (Fig units)
639 	float	arrow_heightAB;			// (Fig units)
640 	FPointArray arrow;
641 	int z = -1;
642 	PageItem::ItemType iteType;
643 	if (forward_arrow == 1)
644 	{
645 		arrow.resize(0);
646 		ScTextStream CodeAF(&fArrowData, QIODevice::ReadOnly);
647 		CodeAF >> arrow_typeAF >> arrow_styleAF >> arrow_thicknessAF >> arrow_widthAF >> arrow_heightAF;
648 		arrow_widthAF = fig2Pts(arrow_widthAF);
649 		arrow_heightAF = fig2Pts(arrow_heightAF);
650 		arrow_thicknessAF = arrow_thicknessAF / 80.0 * 72.0;
651 		FPoint End = ite->PoLine.point(ite->PoLine.size()-2);
652 		for (uint xx = ite->PoLine.size()-1; xx > 0; xx -= 2)
653 		{
654 			FPoint Vector = ite->PoLine.point(xx);
655 			if ((End.x() != Vector.x()) || (End.y() != Vector.y()))
656 			{
657 				double r = atan2(End.y()-Vector.y(),End.x()-Vector.x())*(180.0/M_PI);
658 				QTransform arrowTrans;
659 				if (arrow_typeAF == 0)
660 					arrow.parseSVG("M -1, -0.5 L 0, 0 L -1, 0.5");
661 				else if (arrow_typeAF == 1)
662 					arrow.parseSVG("M -1, -0.5 L 0, 0 L -1, 0.5 z");
663 				else if (arrow_typeAF == 2)
664 					arrow.parseSVG("M -1, -0.5 L 0, 0 L -1, 0.5 L -0.7 0 z");
665 				else if (arrow_typeAF == 3)
666 					arrow.parseSVG("M -0.7, -0.5 L 0, 0 L -0.7, 0.5 L -1 0 z");
667 				arrowTrans.translate(End.x(), End.y());
668 				arrowTrans.rotate(r);
669 				arrowTrans.scale(arrow_heightAF, arrow_widthAF);
670 				arrow.map(arrowTrans);
671 				break;
672 			}
673 		}
674 		QString fillC = "White";
675 		if (arrow_styleAF == 1)
676 			fillC = CurrColorStroke;
677 		if (arrow_typeAF == 0)
678 		{
679 			fillC = CommonStrings::None;
680 			iteType = PageItem::PolyLine;
681 		}
682 		else
683 			iteType = PageItem::Polygon;
684 		z = m_Doc->itemAdd(iteType, PageItem::Unspecified, ite->xPos(), ite->yPos(), 10, 10, arrow_thicknessAF, fillC, CurrColorStroke);
685 		if (z >= 0)
686 		{
687 			PageItem *item = m_Doc->Items->at(z);
688 			item->PoLine = arrow.copy();
689 			item->ClipEdited = true;
690 			item->FrameType = 3;
691 			item->setFillShade(CurrFillShade);
692 			item->setLineShade(CurrStrokeShade);
693 			FPoint wh = getMaxClipF(&item->PoLine);
694 			item->setWidthHeight(wh.x(),wh.y());
695 			item->setTextFlowMode(PageItem::TextFlowDisabled);
696 			m_Doc->adjustItemSize(item);
697 			item->setWidthHeight(qMax(item->width(), 1.0), qMax(item->height(), 1.0));
698 			depthMap.insert(999 - depth, currentItemNr);
699 			currentItemNr++;
700 		}
701 	}
702 	if (backward_arrow == 1)
703 	{
704 		arrow.resize(0);
705 		ScTextStream CodeAB(&bArrowData, QIODevice::ReadOnly);
706 		CodeAB >> arrow_typeAB >> arrow_styleAB >> arrow_thicknessAB >> arrow_widthAB >> arrow_heightAB;
707 		arrow_widthAB = fig2Pts(arrow_widthAB);
708 		arrow_heightAB = fig2Pts(arrow_heightAB);
709 		arrow_thicknessAB = arrow_thicknessAB / 80.0 * 72.0;
710 		FPointArray arrow;
711 		FPoint Start = ite->PoLine.point(0);
712 		for (int xx = 1; xx < ite->PoLine.size(); xx += 2)
713 		{
714 			FPoint Vector = ite->PoLine.point(xx);
715 			if ((Start.x() != Vector.x()) || (Start.y() != Vector.y()))
716 			{
717 				double r = atan2(Start.y()-Vector.y(),Start.x()-Vector.x())*(180.0/M_PI);
718 				QTransform arrowTrans;
719 				if (arrow_typeAB == 0)
720 					arrow.parseSVG("M -1, -0.5 L 0, 0 L -1, 0.5");
721 				else if (arrow_typeAB == 1)
722 					arrow.parseSVG("M -1, -0.5 L 0, 0 L -1, 0.5 z");
723 				else if (arrow_typeAB == 2)
724 					arrow.parseSVG("M -1, -0.5 L 0, 0 L -1, 0.5 L -0.7 0 z");
725 				else if (arrow_typeAB == 3)
726 					arrow.parseSVG("M -0.7, -0.5 L 0, 0 L -0.7, 0.5 L -1 0 z");
727 				arrowTrans.translate(Start.x(), Start.y());
728 				arrowTrans.rotate(r);
729 				arrowTrans.scale(arrow_heightAB, arrow_widthAB);
730 				arrow.map(arrowTrans);
731 				break;
732 			}
733 		}
734 		QString fillC = "White";
735 		if (arrow_styleAB == 1)
736 			fillC = CurrColorStroke;
737 		if (arrow_typeAB == 0)
738 		{
739 			fillC = CommonStrings::None;
740 			iteType = PageItem::PolyLine;
741 		}
742 		else
743 			iteType = PageItem::Polygon;
744 		z = m_Doc->itemAdd(iteType, PageItem::Unspecified, ite->xPos(), ite->yPos(), 10, 10, arrow_thicknessAB, fillC, CurrColorStroke);
745 		if (z >= 0)
746 		{
747 			PageItem *item = m_Doc->Items->at(z);
748 			item->PoLine = arrow.copy();
749 			item->ClipEdited = true;
750 			item->FrameType = 3;
751 			item->setFillShade(CurrFillShade);
752 			item->setLineShade(CurrStrokeShade);
753 			FPoint wh = getMaxClipF(&item->PoLine);
754 			item->setWidthHeight(wh.x(),wh.y());
755 			item->setTextFlowMode(PageItem::TextFlowDisabled);
756 			m_Doc->adjustItemSize(item);
757 			item->setWidthHeight(qMax(item->width(), 1.0), qMax(item->height(), 1.0));
758 			depthMap.insert(999 - depth, currentItemNr);
759 			currentItemNr++;
760 		}
761 	}
762 }
763 
processPolyline(QDataStream & ts,const QString & data)764 void XfigPlug::processPolyline(QDataStream &ts, const QString& data)
765 {
766 	QString tmp = data;
767 	QString fArrowData;
768 	QString bArrowData;
769 	int		command;
770 	int		subtype;				// (1: polyline, 2: box, 3: polygon, 4: arc-box, 5: imported-picture bounding-box)
771 	int		line_style;				// (enumeration type)
772 	int		thickness;				// (1/80 inch)
773 	int		pen_color;				// (enumeration type, pen color)
774 	int		fill_color;				// (enumeration type, fill color)
775 	int		depth;					// (enumeration type)
776 	int		pen_style;				// (pen style, not used)
777 	int		area_fill;				// (enumeration type, -1 = no fill)
778 	double	style_val;				// (1/80 inch)
779 	int		join_style; 			// (enumeration type)
780 	int		cap_style;				// (enumeration type, only used for POLYLINE)
781 	int		radius;					// (1/80 inch, radius of arc-boxes)
782 	int		forward_arrow;			// (0: off, 1: on)
783 	int		backward_arrow;			// (0: off, 1: on)
784 	int		npoints;				// (number of points in line)
785 	int pointsRead = 0;
786 	int imgFlipped;
787 	QString imgFile;
788 	double x, y;
789 	Coords.resize(0);
790 	Coords.svgInit();
791 	bool first = true;
792 	ScTextStream Code(&tmp, QIODevice::ReadOnly);
793 	Code >> command >> subtype >> line_style >> thickness >> pen_color >> fill_color >> depth >> pen_style;
794 	Code >> area_fill >> style_val >> join_style >> cap_style >> radius >> forward_arrow >> backward_arrow >> npoints;
795 	if (forward_arrow == 1)
796 		fArrowData = readLineFromDataStream(ts);
797 	if (backward_arrow == 1)
798 		bArrowData = readLineFromDataStream(ts);
799 	if (subtype == 5)
800 	{
801 		tmp = readLineFromDataStream(ts);
802 		ScTextStream imf(&tmp, QIODevice::ReadOnly);
803 		imf >> imgFlipped >> imgFile;
804 	}
805 	while (!ts.atEnd())
806 	{
807 		tmp = readLineFromDataStream(ts);
808 		ScTextStream pts(&tmp, QIODevice::ReadOnly);
809 		while (!pts.atEnd())
810 		{
811 			pts >> x >> y;
812 			x = fig2Pts(x) - docX;
813 			y = fig2Pts(y) - docY;
814 			if (first)
815 			{
816 				Coords.svgMoveTo(x, y);
817 				first = false;
818 			}
819 			else
820 				Coords.svgLineTo(x, y);
821 			pointsRead++;
822 		}
823 		if (pointsRead == npoints)
824 		{
825 			if (npoints == 1)
826 				Coords.svgLineTo(x, y);
827 			break;
828 		}
829 	}
830 	useColor(pen_color, 0, false);
831 	useColor(fill_color, area_fill, true);
832 	LineW = thickness / 80.0 * 72.0;
833 	int z = -1;
834 	PageItem *ite;
835 	if (subtype == 1)
836 		z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, LineW, CurrColorFill, CurrColorStroke);
837 	else if ((subtype == 2) || (subtype == 3) || (subtype == 4))
838 	{
839 		z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, LineW, CurrColorFill, CurrColorStroke);
840 		Coords.svgClosePath();
841 	}
842 	else if (subtype == 5)
843 	{
844 		z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Unspecified, baseX, baseY, 10, 10, LineW, CurrColorFill, CurrColorStroke);
845 		Coords.svgClosePath();
846 	}
847 	else
848 		z = -1;
849 	if (z >= 0)
850 	{
851 		ite = m_Doc->Items->at(z);
852 		ite->PoLine = Coords.copy();
853 		ite->PoLine.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
854 		ite->ClipEdited = true;
855 		ite->FrameType = 3;
856 		ite->setFillShade(CurrFillShade);
857 		ite->setLineShade(CurrStrokeShade);
858 		if (line_style > 0)
859 			ite->setDashes(getDashValues(LineW, line_style));
860 		if (subtype == 1)
861 		{
862 			if (join_style == 0)
863 				ite->setLineJoin(Qt::MiterJoin);
864 			else if (join_style == 1)
865 				ite->setLineJoin(Qt::RoundJoin);
866 			else if (join_style == 2)
867 				ite->setLineJoin(Qt::BevelJoin);
868 			if (cap_style == 0)
869 				ite->setLineEnd(Qt::FlatCap);
870 			else if (cap_style == 1)
871 				ite->setLineEnd(Qt::RoundCap);
872 			else if (cap_style == 2)
873 				ite->setLineEnd(Qt::SquareCap);
874 		}
875 		FPoint wh = getMaxClipF(&ite->PoLine);
876 		ite->setWidthHeight(wh.x(),wh.y());
877 		ite->setTextFlowMode(PageItem::TextFlowDisabled);
878 		m_Doc->adjustItemSize(ite);
879 		ite->setWidthHeight(qMax(ite->width(), 1.0), qMax(ite->height(), 1.0));
880 		if (subtype == 4)
881 		{
882 			ite->setCornerRadius(radius / 80.0 * 72.0);
883 			ite->FrameType = 2;
884 			ite->ClipEdited = false;
885 			ite->updateClip();
886 		}
887 		if (subtype == 5)
888 		{
889 			ite->Pfile = baseFile + "/" + imgFile;
890 			m_Doc->loadPict(ite->Pfile, ite, false);
891 			ite->setImageXYScale(72.0 / 80.0, 72.0 / 80.0);
892 			ite->setImageXYOffset(0, 0);
893 		}
894 		depthMap.insert(999 - depth, currentItemNr);
895 		currentItemNr++;
896 		if ((ite->itemType() == PageItem::PolyLine) && ((forward_arrow == 1) || (backward_arrow == 1)))
897 			processArrows(forward_arrow, fArrowData, backward_arrow, bArrowData, depth, ite);
898 	}
899 }
900 
processSpline(QDataStream & ts,const QString & data)901 void XfigPlug::processSpline(QDataStream &ts, const QString& data)
902 {
903 	QString tmp = data;
904 	QString fArrowData = "";
905 	QString bArrowData = "";
906 	int		command;
907 	int		subtype;				// 0: open approximated spline
908 									// 1: closed approximated spline
909 									// 2: open   interpolated spline
910 									// 3: closed interpolated spline
911 									// 4: open   x-spline
912 									// 5: closed x-spline
913 	int		line_style;				// (enumeration type)
914 	int		thickness;				// (1/80 inch)
915 	int		pen_color;				// (enumeration type, pen color)
916 	int		fill_color;				// (enumeration type, fill color)
917 	int		depth;					// (enumeration type)
918 	int		pen_style;				// (pen style, not used)
919 	int		area_fill;				// (enumeration type, -1 = no fill)
920 	double	style_val;				// (1/80 inch)
921 	int		cap_style;				// (enumeration type, only used for POLYLINE)
922 	int		forward_arrow;			// (0: off, 1: on)
923 	int		backward_arrow;			// (0: off, 1: on)
924 	int		npoints;				// (number of points in line)
925 	int pointsRead = 0;
926 	double x, y;
927 	Coords.resize(0);
928 	Coords.svgInit();
929 	bool first = true;
930 	ScTextStream Code(&tmp, QIODevice::ReadOnly);
931 	Code >> command >> subtype >> line_style >> thickness >> pen_color >> fill_color >> depth >> pen_style;
932 	Code >> area_fill >> style_val >> cap_style >> forward_arrow >> backward_arrow >> npoints;
933 	if (forward_arrow == 1)
934 		fArrowData = readLineFromDataStream(ts);
935 	if (backward_arrow == 1)
936 		bArrowData = readLineFromDataStream(ts);
937 	while (!ts.atEnd())
938 	{
939 		tmp = readLineFromDataStream(ts);
940 		ScTextStream pts(&tmp, QIODevice::ReadOnly);
941 		while (!pts.atEnd())
942 		{
943 			pts >> x >> y;
944 			x = fig2Pts(x) - docX;
945 			y = fig2Pts(y) - docY;
946 			if (first)
947 			{
948 				Coords.svgMoveTo(x, y);
949 				first = false;
950 			}
951 			else
952 				Coords.svgLineTo(x, y);
953 			pointsRead++;
954 		}
955 		if (pointsRead == npoints)
956 		{
957 			if (npoints == 1)
958 				Coords.svgLineTo(x, y);
959 			break;
960 		}
961 	}
962 	pointsRead = 0;
963 	while (!ts.atEnd())
964 	{
965 		tmp = readLineFromDataStream(ts);
966 		ScTextStream pts(&tmp, QIODevice::ReadOnly);
967 		while (!pts.atEnd())
968 		{
969 			pts >> x;
970 			pointsRead++;
971 		}
972 		if (pointsRead == npoints)
973 			break;
974 	}
975 	useColor(pen_color, 0, false);
976 	useColor(fill_color, area_fill, true);
977 	LineW = thickness / 80.0 * 72.0;
978 	int z = -1;
979 	PageItem *ite;
980 	if ((subtype == 0) || (subtype == 2) || (subtype == 4))
981 		z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, LineW, CurrColorFill, CurrColorStroke);
982 	else if ((subtype == 1) || (subtype == 3) || (subtype == 5))
983 	{
984 		z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, LineW, CurrColorFill, CurrColorStroke);
985 		Coords.svgClosePath();
986 	}
987 	if (z >= 0)
988 	{
989 		ite = m_Doc->Items->at(z);
990 		ite->PoLine = Coords.copy();
991 		ite->PoLine.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
992 		ite->ClipEdited = true;
993 		ite->FrameType = 3;
994 		ite->setFillShade(CurrFillShade);
995 		ite->setLineShade(CurrStrokeShade);
996 		if (line_style > 0)
997 			ite->setDashes(getDashValues(LineW, line_style));
998 		if ((subtype == 0) || (subtype == 2) || (subtype == 4))
999 		{
1000 			if (cap_style == 0)
1001 				ite->setLineEnd(Qt::FlatCap);
1002 			else if (cap_style == 1)
1003 				ite->setLineEnd(Qt::RoundCap);
1004 			else if (cap_style == 2)
1005 				ite->setLineEnd(Qt::SquareCap);
1006 		}
1007 		FPoint wh = getMaxClipF(&ite->PoLine);
1008 		ite->setWidthHeight(wh.x(),wh.y());
1009 		ite->setTextFlowMode(PageItem::TextFlowDisabled);
1010 		m_Doc->adjustItemSize(ite);
1011 		ite->setWidthHeight(qMax(ite->width(), 1.0), qMax(ite->height(), 1.0));
1012 		depthMap.insert(999 - depth, currentItemNr);
1013 		currentItemNr++;
1014 		if ((ite->itemType() == PageItem::PolyLine) && ((forward_arrow == 1) || (backward_arrow == 1)))
1015 			processArrows(forward_arrow, fArrowData, backward_arrow, bArrowData, depth, ite);
1016 	}
1017 }
1018 
processArc(QDataStream & ts,const QString & data)1019 void XfigPlug::processArc(QDataStream &ts, const QString& data)
1020 {
1021 	QString tmp = data;
1022 	QString fArrowData = "";
1023 	QString bArrowData = "";
1024 	int		command;
1025 	int		subtype;				// (1: open ended arc, 2: pie-wedge (closed))
1026 	int		line_style;				// (enumeration type)
1027 	int		thickness;				// (1/80 inch)
1028 	int		pen_color;				// (enumeration type, pen color)
1029 	int		fill_color;				// (enumeration type, fill color)
1030 	int		depth;					// (enumeration type)
1031 	int		pen_style;				// (pen style, not used)
1032 	int		area_fill;				// (enumeration type, -1 = no fill)
1033 	double	style_val;				// (1/80 inch)
1034 	int		cap_style;				// (enumeration type, only used for POLYLINE)
1035 	int		direction;				// (always 1)
1036 	int		forward_arrow;			// (0: off, 1: on)
1037 	int		backward_arrow;			// (0: off, 1: on)
1038 	double	center_x, center_y;		// (center of the arc)
1039 	int		x1, y1;					// (Fig units, the 1st point the user entered)
1040 	int		x2, y2;					// (Fig units, the 2nd point)
1041 	int		x3, y3;					// (Fig units, the last point)
1042 	ScTextStream Code(&tmp, QIODevice::ReadOnly);
1043 	Code >> command >> subtype >> line_style >> thickness >> pen_color >> fill_color >> depth >> pen_style;
1044 	Code >> area_fill >> style_val >> cap_style >> direction >> forward_arrow >> backward_arrow;
1045 	Code >> center_x >> center_y >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
1046 	if (forward_arrow == 1)
1047 		fArrowData = readLineFromDataStream(ts);
1048 	if (backward_arrow == 1)
1049 		bArrowData = readLineFromDataStream(ts);
1050 	useColor(pen_color, 0, false);
1051 	useColor(fill_color, area_fill, true);
1052 	LineW = thickness / 80.0 * 72.0;
1053 	int z = -1;
1054 	PageItem *ite;
1055 	if (subtype == 1)
1056 		z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, LineW, CurrColorFill, CurrColorStroke);
1057 	else if (subtype == 2)
1058 		z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, LineW, CurrColorFill, CurrColorStroke);
1059 	else
1060 		z = -1;
1061 	center_x = fig2Pts(center_x) - docX;
1062 	center_y = fig2Pts(center_y) - docY;
1063 	double x1R = fig2Pts(x1) - docX;
1064 	double y1R = fig2Pts(y1) - docY;
1065 	double x3R = fig2Pts(x3) - docX;
1066 	double y3R = fig2Pts(y3) - docY;
1067 	double r1 = distance(x1R - center_x, y1R - center_y);
1068 	double x0 = center_x - r1;
1069 	double y0 = center_y - r1;
1070 	QRectF bBox = QRectF(x0, y0, r1 * 2.0, r1 * 2.0);
1071 	double angle1 = -xy2Deg(x1R - center_x, y1R - center_y);
1072 	double angle2 = -xy2Deg(x3R - center_x, y3R - center_y);
1073 	double sweep;
1074 	if (direction == 0)
1075 	{
1076 		sweep = angle1 - angle2;
1077 		if (sweep < 0.0)
1078 			sweep = 360.0 + sweep;
1079 	}
1080 	else
1081 	{
1082 		sweep = angle2 - angle1;
1083 		if (sweep < 0.0)
1084 			sweep = 360.0 + sweep;
1085 		double an = angle1;
1086 		angle1 = angle2;
1087 		angle2 = an;
1088 	}
1089 	QPainterPath aPath;
1090 	if (subtype == 1)
1091 	{
1092 		aPath.arcMoveTo(bBox, angle2);
1093 		aPath.arcTo(bBox, angle2, sweep);
1094 	}
1095 	else
1096 	{
1097 		aPath.moveTo(center_x, center_y);
1098 		aPath.arcTo(bBox, angle2, sweep);
1099 		aPath.lineTo(center_x, center_y);
1100 	}
1101 	FPointArray points;
1102 	points.fromQPainterPath(aPath);
1103 
1104 	if (z >= 0)
1105 	{
1106 		ite = m_Doc->Items->at(z);
1107 		ite->PoLine = points.copy();
1108 		ite->PoLine.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
1109 		ite->ClipEdited = true;
1110 		ite->FrameType = 3;
1111 		ite->setFillShade(CurrFillShade);
1112 		ite->setLineShade(CurrStrokeShade);
1113 		if (line_style > 0)
1114 			ite->setDashes(getDashValues(LineW, line_style));
1115 		if (subtype == 1)
1116 		{
1117 			if (cap_style == 0)
1118 				ite->setLineEnd(Qt::FlatCap);
1119 			else if (cap_style == 1)
1120 				ite->setLineEnd(Qt::RoundCap);
1121 			else if (cap_style == 2)
1122 				ite->setLineEnd(Qt::SquareCap);
1123 		}
1124 		FPoint wh = getMaxClipF(&ite->PoLine);
1125 		ite->setWidthHeight(wh.x(),wh.y());
1126 		ite->setTextFlowMode(PageItem::TextFlowDisabled);
1127 		m_Doc->adjustItemSize(ite);
1128 		ite->setWidthHeight(qMax(ite->width(), 1.0), qMax(ite->height(), 1.0));
1129 		depthMap.insert(999 - depth, currentItemNr);
1130 		currentItemNr++;
1131 		if ((ite->itemType() == PageItem::PolyLine) && ((forward_arrow == 1) || (backward_arrow == 1)))
1132 		{
1133 			if (direction == 1)
1134 				processArrows(forward_arrow, fArrowData, backward_arrow, bArrowData, depth, ite);
1135 			else
1136 				processArrows(backward_arrow, bArrowData, forward_arrow, fArrowData, depth, ite);
1137 		}
1138 	}
1139 }
1140 
processEllipse(const QString & data)1141 void XfigPlug::processEllipse(const QString& data)
1142 {
1143 	QString tmp = data;
1144 	int		command;			// (always 1)
1145 	int		subtype;			// (1: ellipse defined by radii
1146 								//  2: ellipse defined by diameters
1147 								//  3: circle defined by radius
1148 								//  4: circle defined by diameter)
1149 	int		line_style;			// (enumeration type)
1150 	int		thickness;			// (1/80 inch)
1151 	int		pen_color;			// (enumeration type, pen color)
1152 	int		fill_color;			// (enumeration type, fill color)
1153 	int		depth;				// (enumeration type)
1154 	int		pen_style;			// (pen style, not used)
1155 	int		area_fill;			// (enumeration type, -1 = no fill)
1156 	double	style_val;			// (1/80 inch)
1157 	int		direction;			// (always 1)
1158 	double	angle;				// (radians, the angle of the x-axis)
1159 	int		center_x, center_y;	// (Fig units)
1160 	int		radius_x, radius_y;	// (Fig units)
1161 	int		start_x, start_y;	// (Fig units; the 1st point entered)
1162 	int		end_x, end_y;		// (Fig units; the last point entered)
1163 	double x, y, w, h;
1164 	ScTextStream Code(&tmp, QIODevice::ReadOnly);
1165 	Code >> command >> subtype >> line_style >> thickness >> pen_color >> fill_color >> depth >> pen_style;
1166 	Code >> area_fill >> style_val >> direction >> angle >> center_x >> center_y >> radius_x >> radius_y;
1167 	Code >> start_x >> start_y >> end_x >> end_y;
1168 	useColor(pen_color, 0, false);
1169 	useColor(fill_color, area_fill, true);
1170 	LineW = thickness / 80.0 * 72.0;
1171 	w = fig2Pts(radius_x);
1172 	h = fig2Pts(radius_y);
1173 	x = fig2Pts(center_x) - w;
1174 	y = fig2Pts(center_y) - h;
1175 	w *= 2.0;
1176 	h *= 2.0;
1177 	x -= docX;
1178 	x += m_Doc->currentPage()->xOffset();
1179 	y -= docY;
1180 	y += m_Doc->currentPage()->yOffset();
1181 	int z = -1;
1182 	PageItem *ite;
1183 	z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, baseX + x, baseY + y, w, h, LineW, CurrColorFill, CurrColorStroke);
1184 	if (z >= 0)
1185 	{
1186 		ite = m_Doc->Items->at(z);
1187 		ite->setFillShade(CurrFillShade);
1188 		ite->setLineShade(CurrStrokeShade);
1189 		if (line_style > 0)
1190 			ite->setDashes(getDashValues(LineW, line_style));
1191 		ite->setTextFlowMode(PageItem::TextFlowDisabled);
1192 		int rot = m_Doc->rotationMode();
1193 		m_Doc->setRotationMode ( 2);
1194 		m_Doc->rotateItem(-angle * 180.0 / M_PI, ite);
1195 		m_Doc->setRotationMode( rot);
1196 		depthMap.insert(999 - depth, currentItemNr);
1197 		currentItemNr++;
1198 	}
1199 }
1200 
cleanText(const QString & text)1201 QString XfigPlug::cleanText(const QString& text)
1202 {
1203 	QString ret;
1204 	QString tmp;
1205 	bool sep = false;
1206 	int sepcount = 0;
1207 	for (int a = 1; a < text.count(); ++a)
1208 	{
1209 		QString ch = text.mid(a,1);
1210 		if (sep)
1211 		{
1212 			if (ch == "\\")
1213 			{
1214 				ret += ch;
1215 				sep = false;
1216 			}
1217 			else
1218 			{
1219 				tmp += ch;
1220 				sepcount++;
1221 				if (sepcount == 3)
1222 				{
1223 					sep = false;
1224 					bool ok = false;
1225 					if (tmp != "001")
1226 					{
1227 						int code = tmp.toInt(&ok, 8);
1228 						if (ok)
1229 							ret += QChar(code);
1230 					}
1231 					tmp = "";
1232 				}
1233 			}
1234 		}
1235 		else
1236 		{
1237 			if (ch == "\\")
1238 			{
1239 				sep = true;
1240 				sepcount = 0;
1241 			}
1242 			else
1243 				ret += ch;
1244 		}
1245 	}
1246 	return ret;
1247 }
1248 
processText(const QString & data)1249 void XfigPlug::processText(const QString& data)
1250 {
1251 	QString tmp = data;
1252 	int		command;			// (always 4)
1253 	int		subtype;			// (0: Left justified
1254 								//  1: Center justified
1255 								//  2: Right justified)
1256 	int		color;				// (enumeration type)
1257 	int		depth;				// (enumeration type)
1258 	int		pen_style;			// (enumeration , not used)
1259 	int		font;				// (enumeration type)
1260 	float	font_size;			// (font size in points)
1261 	float	angle;				// (radians, the angle of the text)
1262 	int		font_flags;			// (bit vector)
1263 	float	height;				// (Fig units)
1264 	float	length;				// (Fig units)
1265 	int		xT, yT;				// (Fig units, coordinate of the origin
1266 								//  of the string.  If sub_type = 0, it is
1267 								//  the lower left corner of the string.
1268 								//  If sub_type = 1, it is the lower
1269 								//  center.  Otherwise it is the lower
1270 								//  right corner of the string.)
1271 	QString text;
1272 	double x, y, w, h;
1273 	ScTextStream Code(&tmp, QIODevice::ReadOnly);
1274 	Code >> command >> subtype >> color >> depth >> pen_style >> font >> font_size >> angle;
1275 	Code >> font_flags >> height >> length >> xT >> yT;
1276 	text = Code.readAll();
1277 	text = cleanText(text);
1278 	FPointArray textPath;
1279 	QPainterPath painterPath;
1280 	QString TFont(m_Doc->itemToolPrefs().textFont);
1281 	QFont::Weight weight = QFont::Normal;
1282 	bool isItalic = false;
1283 	if (font_flags & 4)
1284 	{
1285 		switch (font)
1286 		{
1287 			case 0:
1288 				TFont = "Times Roman";
1289 				weight = QFont::Normal;
1290 				break;
1291 			case 1:
1292 				TFont = "Times Italic";
1293 				weight = QFont::Normal;
1294 				isItalic = true;
1295 				break;
1296 			case 2:
1297 				TFont = "Times Bold";
1298 				weight = QFont::Bold;
1299 				break;
1300 			case 3:
1301 				TFont = "Times Bold Italic";
1302 				weight = QFont::Bold;
1303 				isItalic = true;
1304 				break;
1305 			case 4:
1306 				TFont = "AvantGarde Book";
1307 				weight = QFont::Normal;
1308 				break;
1309 			case 5:
1310 				TFont = "AvantGarde Book Oblique";
1311 				weight = QFont::Normal;
1312 				break;
1313 			case 6:
1314 				TFont = "AvantGarde Demi";
1315 				weight = QFont::DemiBold;
1316 				break;
1317 			case 7:
1318 				TFont = "AvantGarde Demi Oblique";
1319 				weight = QFont::DemiBold;
1320 				break;
1321 			case 8:
1322 				TFont = "Bookman Light";
1323 				weight = QFont::Light;
1324 				break;
1325 			case 9:
1326 				TFont = "Bookman Light Italic";
1327 				weight = QFont::Light;
1328 				isItalic = true;
1329 				break;
1330 			case 10:
1331 				TFont = "Bookman Demi";
1332 				weight = QFont::DemiBold;
1333 				break;
1334 			case 11:
1335 				TFont = "Bookman Demi Italic";
1336 				weight = QFont::DemiBold;
1337 				isItalic = true;
1338 				break;
1339 			case 12:
1340 				TFont = "Courier";
1341 				weight = QFont::Normal;
1342 				break;
1343 			case 13:
1344 				TFont = "Courier Oblique";
1345 				weight = QFont::Normal;
1346 				break;
1347 			case 14:
1348 				TFont = "Courier Bold";
1349 				weight = QFont::Bold;
1350 				break;
1351 			case 15:
1352 				TFont = "Courier Bold Oblique";
1353 				weight = QFont::Bold;
1354 				break;
1355 			case 16:
1356 				TFont = "Helvetica";
1357 				weight = QFont::Normal;
1358 				break;
1359 			case 17:
1360 				TFont = "Helvetica Oblique";
1361 				weight = QFont::Normal;
1362 				break;
1363 			case 18:
1364 				TFont = "Helvetica Bold";
1365 				weight = QFont::Bold;
1366 				break;
1367 			case 19:
1368 				TFont = "Helvetica Bold Oblique";
1369 				weight = QFont::Bold;
1370 				break;
1371 			case 20:
1372 				TFont = "Helvetica Narrow";
1373 				weight = QFont::Normal;
1374 				break;
1375 			case 21:
1376 				TFont = "Helvetica Narrow Oblique";
1377 				weight = QFont::Normal;
1378 				break;
1379 			case 22:
1380 				TFont = "Helvetica Narrow Bold";
1381 				weight = QFont::Bold;
1382 				break;
1383 			case 23:
1384 				TFont = "Helvetica Narrow Bold Oblique";
1385 				weight = QFont::Bold;
1386 				break;
1387 			case 24:
1388 				TFont = "New Century Schoolbook Roman";
1389 				weight = QFont::Normal;
1390 				break;
1391 			case 25:
1392 				TFont = "New Century Schoolbook Italic";
1393 				weight = QFont::Normal;
1394 				isItalic = true;
1395 				break;
1396 			case 26:
1397 				TFont = "New Century Schoolbook Bold";
1398 				weight = QFont::Bold;
1399 				break;
1400 			case 27:
1401 				TFont = "New Century Schoolbook Bold Italic";
1402 				weight = QFont::Bold;
1403 				isItalic = true;
1404 				break;
1405 			case 28:
1406 				TFont = "Palatino Roman";
1407 				weight = QFont::Normal;
1408 				break;
1409 			case 29:
1410 				TFont = "Palatino Italic";
1411 				weight = QFont::Normal;
1412 				isItalic = true;
1413 				break;
1414 			case 30:
1415 				TFont = "Palatino Bold";
1416 				weight = QFont::Bold;
1417 				break;
1418 			case 31:
1419 				TFont = "Palatino Bold Italic";
1420 				weight = QFont::Bold;
1421 				isItalic = true;
1422 				break;
1423 			case 32:
1424 				TFont = "Symbol";
1425 				weight = QFont::Normal;
1426 				break;
1427 			case 33:
1428 				TFont = "Zapf Chancery Medium Italic";
1429 				weight = QFont::Normal;
1430 				isItalic = true;
1431 				break;
1432 			case 34:
1433 				TFont = "Zapf Dingbats";
1434 				weight = QFont::Normal;
1435 				break;
1436 			default:
1437 				TFont = m_Doc->itemToolPrefs().textFont;
1438 				weight = QFont::Normal;
1439 				break;
1440 		}
1441 	}
1442 	else
1443 	{
1444 		switch (font)
1445 		{
1446 			case 1: // Roman
1447 				TFont = "Times";
1448 				weight = QFont::Normal;
1449 				break;
1450 			case 2: // Bold
1451 				TFont = "Times";
1452 				weight = QFont::Bold;
1453 				break;
1454 			case 3: // Italic
1455 				TFont = "Times";
1456 				weight = QFont::Normal;
1457 				isItalic = true;
1458 				break;
1459 			case 4: // Sans Serif
1460 				TFont = "Helvetica";
1461 				weight = QFont::Normal;
1462 				break;
1463 			case 5: // Typewriter
1464 				TFont = "Courier";
1465 				weight = QFont::Normal;
1466 				break;
1467 			default:
1468 				TFont = m_Doc->itemToolPrefs().textFont;
1469 				weight = QFont::Normal;
1470 				break;
1471 		}
1472 	}
1473 	w = fig2Pts(length);
1474 	h = fig2Pts(height);
1475 	x = fig2Pts(xT);
1476 	y = fig2Pts(yT);
1477 	x -= docX;
1478 	x += m_Doc->currentPage()->xOffset();
1479 	y -= docY;
1480 	y += m_Doc->currentPage()->yOffset();
1481 	QFont tf = QFont(TFont, 10, weight, isItalic);
1482 	tf.setPointSizeF(font_size / 80.0 * 72.0);
1483 	painterPath.addText( 0, 0, tf, text );
1484 	QRectF br = painterPath.boundingRect();
1485 	if ((angle == 0) && (br.width() > w))
1486 	{
1487 		QTransform m;
1488 		m.scale(w / br.width(), w / br.width());
1489 		painterPath = m.map(painterPath);
1490 	}
1491 	textPath.fromQPainterPath(painterPath);
1492 	useColor(color, 0, false);
1493 	int z = -1;
1494 	PageItem *ite;
1495 	z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX + x, baseY + y, w, h, 0, CurrColorStroke, CommonStrings::None);
1496 	if (z >= 0)
1497 	{
1498 		ite = m_Doc->Items->at(z);
1499 		ite->setRotation(-angle * 180.0 / M_PI);
1500 		ite->PoLine = textPath.copy();
1501 		ite->ClipEdited = true;
1502 		ite->FrameType = 3;
1503 		FPoint wh = getMaxClipF(&ite->PoLine);
1504 		ite->setWidthHeight(wh.x(),wh.y());
1505 		ite->setTextFlowMode(PageItem::TextFlowDisabled);
1506 		m_Doc->adjustItemSize(ite);
1507 		ite->setWidthHeight(qMax(ite->width(), 1.0), qMax(ite->height(), 1.0));
1508 		if (subtype == 1)
1509 			m_Doc->moveRotated(ite, FPoint(-br.width() / 2.0, 0.0));
1510 		else if (subtype == 2)
1511 			m_Doc->moveRotated(ite, FPoint(-br.width(), 0.0));
1512 		depthMap.insert(999 - depth, currentItemNr);
1513 		currentItemNr++;
1514 	}
1515 }
1516 
processData(QDataStream & ts,const QString & data)1517 void XfigPlug::processData(QDataStream &ts, const QString& data)
1518 {
1519 	QString tmp = data;
1520 	int command, subtype;
1521 	ScTextStream Code(&tmp, QIODevice::ReadOnly);
1522 	Code >> command >> subtype;
1523 	switch (command)
1524 	{
1525 		case 0:
1526 			parseColor(data);
1527 			break;
1528 		case 1:
1529 			processEllipse(data);
1530 			break;
1531 		case 2:
1532 			processPolyline(ts, data);
1533 			break;
1534 		case 3:
1535 			processSpline(ts, data);
1536 			break;
1537 		case 4:
1538 			processText(data);
1539 			break;
1540 		case 5:
1541 			processArc(ts, data);
1542 			break;
1543 		case 6:
1544 //			qDebug() << "Xfig-Import:: Unsupported Compound object";
1545 			break;
1546 		case -6:
1547 //			qDebug() << "Xfig-Import:: Unsupported End of Compound object";
1548 			break;
1549 	}
1550 }
1551 
resortItems()1552 void XfigPlug::resortItems()
1553 {
1554 	QList<PageItem*> itemList;
1555 	int newItemCount = m_Doc->Items->count();
1556 	itemList.reserve(newItemCount - oldDocItemCount);
1557 	for (int as = oldDocItemCount; as < newItemCount; ++as)
1558 	{
1559 		itemList.append(m_Doc->Items->takeAt(oldDocItemCount));
1560 	}
1561 
1562 	QList<int> keylist = depthMap.uniqueKeys();
1563 	int keysCount = keylist.count();
1564 	int currentLayer = 0;
1565 	for (int it = 0; it < keysCount; ++it)
1566 	{
1567 		if ((importerFlags & LoadSavePlugin::lfCreateDoc) && (it > 0))
1568 			currentLayer = m_Doc->addLayer(QString("Layer %1").arg(it), true);
1569 		QList<int> elems = depthMap.values(keylist.at(it));
1570 		std::sort(elems.begin(), elems.end());
1571 		int itemsCount = elems.count();
1572 		for (int i = 0; i < itemsCount; ++i)
1573 		{
1574 			PageItem* ite = itemList.at(elems.at(i));
1575 			Elements.append(ite);
1576 			m_Doc->Items->append(ite);
1577 			if ((importerFlags & LoadSavePlugin::lfCreateDoc) && (it > 0))
1578 				ite->m_layerID = currentLayer;
1579 		}
1580 	}
1581 }
1582 
1583 
fig2Pts(double in)1584 double XfigPlug::fig2Pts(double in)
1585 {
1586 	return in / 1200.0 * 72.0;
1587 }
1588 
convert(const QString & fn)1589 bool XfigPlug::convert(const QString& fn)
1590 {
1591 	QString tmp;
1592 	CurrColorFill = "White";
1593 	CurrFillShade = 100.0;
1594 	CurrColorStroke = "Black";
1595 	CurrStrokeShade = 100.0;
1596 	patternMode = false;
1597 	patternX1 = 0.0;
1598 	patternY1 = 0.0;
1599 	patternX2 = 0.0;
1600 	patternY2 = 0.0;
1601 	Coords.resize(0);
1602 	Coords.svgInit();
1603 	clipCoords.resize(0);
1604 	clipCoords.svgInit();
1605 	currentPatternName = "";
1606 	currentPatternX = 0.0;
1607 	currentPatternY = 0.0;
1608 	currentPatternXScale = 1.0;
1609 	currentPatternYScale = 1.0;
1610 	currentPatternRotation = 0.0;
1611 	QList<PageItem*> gElements;
1612 	groupStack.push(gElements);
1613 	currentItemNr = 0;
1614 	if (progressDialog)
1615 	{
1616 		progressDialog->setOverallProgress(2);
1617 		progressDialog->setLabel("GI", tr("Generating Items"));
1618 		qApp->processEvents();
1619 	}
1620 	QFile f(fn);
1621 	if (f.open(QIODevice::ReadOnly))
1622 	{
1623 		oldDocItemCount = m_Doc->Items->count();
1624 		int fSize = (int) f.size();
1625 		if (progressDialog)
1626 		{
1627 			progressDialog->setTotalSteps("GI", fSize);
1628 			qApp->processEvents();
1629 		}
1630 		QDataStream ts(&f);
1631 		QString version = readLineFromDataStream(ts);
1632 		QString orientation = readLineFromDataStream(ts);
1633 		QString justification = readLineFromDataStream(ts);
1634 		QString units = readLineFromDataStream(ts);
1635 		QString papersize = readLineFromDataStream(ts);
1636 		QString magnification = readLineFromDataStream(ts);
1637 		QString multiple = readLineFromDataStream(ts);
1638 		QString transparent = readLineFromDataStream(ts);
1639 		tmp = readLineFromDataStream(ts);
1640 		if (tmp.startsWith("#"))
1641 			tmp = readLineFromDataStream(ts);
1642 		QString resolution = tmp;
1643 		while (!ts.atEnd())
1644 		{
1645 			tmp = readLineFromDataStream(ts);
1646 			if (tmp.startsWith("#"))
1647 				continue;
1648 			processData(ts, tmp);
1649 			if (progressDialog)
1650 			{
1651 				progressDialog->setProgress("GI", ts.device()->pos());
1652 				qApp->processEvents();
1653 			}
1654 		}
1655 		resortItems();
1656 	}
1657 	if (progressDialog)
1658 		progressDialog->close();
1659 	return true;
1660 }
1661