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 
9 #include "../formatidlist.h"
10 #include "barcodegenerator.h"
11 #include "commonstrings.h"
12 #include "iconmanager.h"
13 #include "loadsaveplugin.h"
14 #include "scpaths.h"
15 #include "scribuscore.h"
16 #include "ui/colorsandfills.h"
17 #include "undomanager.h"
18 
19 #include <QDebug>
20 #include <QTextStream>
21 #include <QStandardItemModel>
22 #include <QTimer>
23 #include <QThread>
24 
BarcodeType(const QString & cmd,const QString & exa,const QString & exaop)25 BarcodeType::BarcodeType(const QString &cmd, const QString &exa, const QString &exaop)
26 {
27 	command = cmd;
28 	exampleContents = exa;
29 	exampleOptions = exaop;
30 }
31 
BarcodeGenerator(QWidget * parent,const char * name)32 BarcodeGenerator::BarcodeGenerator(QWidget* parent, const char* name)
33 	: QDialog(parent),
34 	  paintBarcodeTimer(nullptr)
35 {
36 	ui.setupUi(this);
37 	setObjectName(name);
38 	setModal(true);
39 
40 	ui.bcodeBox->layout()->setAlignment(Qt::AlignTop);
41 	ui.colorBox->layout()->setAlignment(Qt::AlignTop);
42 
43 	connect(&thread, SIGNAL(renderedImage(QString)),this, SLOT(updatePreview(QString)));
44 
45 	/*
46 	 *  We extract the barcode information from the BWIPP metadata which looks like this:
47 	 *
48 	 *  % --BEGIN ENCODER gs1-128--
49 	 *  % --REQUIRES preamble raiseerror renlinear code128--
50 	 *  % --DESC: GS1-128
51 	 *  % --EXAM: (01)95012345678903(3103)000123
52 	 *  % --EXOP: includetext
53 	 *  % --RNDR: renlinear
54 	 *
55 	 */
56 
57 	QFile f(ScPaths::instance().shareDir() + QString("/plugins/barcode.ps"));
58 	if(!f.open(QIODevice::ReadOnly))
59 	{
60 		qDebug()<<"Barcodegenerator unable to open "<<f.fileName();
61 		return;
62 	}
63 	QTextStream ts(&f);
64 	QString bwipp = ts.readAll();
65 	f.close();
66 
67 	QRegExp rx(
68 				"[\\r\\n]+% --BEGIN (RESOURCE|RENDERER|ENCODER) ([\\w-]+)--[\\r\\n]+"
69 				"(.*[\\r\\n]+)?"
70 				"(%%BeginResource.*[\\r\\n]+)"
71 				"% --END \\1 \\2--[\\r\\n]+");
72 	rx.setMinimal(true);
73 	int pos = 0;
74 	while ( (pos = rx.indexIn(bwipp, pos)) != -1 )
75 	{
76 		int len = rx.matchedLength();
77 		QString restype = rx.cap(1);
78 		QString resname = rx.cap(2);
79 		QString reshead = rx.cap(3);
80 		QString resbody = rx.cap(4);
81 
82 		resbodys[resname] = resbody;
83 
84 		if (restype=="ENCODER")
85 		{
86 			QRegExp rxhead(
87 						"% --REQUIRES (.*)--[\\r\\n]+"
88 						"% --DESC:(.*)[\\r\\n]+"
89 						"% --EXAM:(.*)[\\r\\n]+"
90 						"% --EXOP:(.*)[\\r\\n]+"
91 						"% --RNDR:(.*)[\\r\\n]+"
92 						);
93 			if (rxhead.indexIn(reshead) >= 0)
94 			{
95 				resreqs[resname] = rxhead.cap(1).trimmed();
96 				resdescs[resname] = rxhead.cap(2).trimmed();
97 				resexams[resname] = rxhead.cap(3).trimmed();
98 				resexops[resname] = rxhead.cap(4).trimmed();
99 				resrndrs[resname] = rxhead.cap(5).trimmed();
100 				encoderlist.append(resname);
101 			}
102 		}
103 		pos += len;
104 	}
105 
106 	foreach (const QString& enc, encoderlist)
107 		map[resdescs[enc]] = BarcodeType(enc, resexams[enc], resexops[enc]);
108 
109 	/*
110 	 *  Ultimately all of this static data about the capabilities of each barcode
111 	 *  encoder will be replaced by data read from the barcode.ps metadata, when
112 	 *  such data exists...
113 	 *
114 	 */
115 
116 	// Content for the version and ecc combos
117 	resvers["qrcode"] = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40";
118 	resecls["qrcode"] = "L,Q,M,H";
119 	resvers["gs1qrcode"] = resvers["qrcode"];
120 	resecls["gs1qrcode"] = resecls["qrcode"];
121 	resvers["hibcqrcode"] = resvers["qrcode"];
122 	resecls["hibcqrcode"] = resecls["qrcode"];
123 	resvers["microqrcode"] = "M1,M2,M3,M4";
124 	resecls["microqrcode"] = "L,Q,M,H";
125 	resvers["datamatrix"] = "10x10,12x12,14x14,16x16,18x18,20x20,22x22,24x24,26x26,32x32,36x36,40x40,44x44,48x48,52x52,64x64,72x72,80x80,88x88,96x96,104x104,120x120,132x132,144x144,8x18,8x32,12x26,12x36,16x36,16x48";
126 	resecls["datamatrix"] = "";
127 	resvers["gs1datamatrix"] = resvers["datamatrix"];
128 	resecls["gs1datamatrix"] = resvers["datamatrix"];
129 	resvers["hibcdatamatrix"] = resvers["datamatrix"];
130 	resecls["hibcdatamatrix"] = resecls["datamatrix"];
131 	resvers["azteccode"] = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32";
132 	resvlbl["azteccode"] = "Layers";
133 	resecls["azteccode"] = "5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95";
134 	resvers["azteccodecompact"] = "1,2,3,4";
135 	resvlbl["azteccodecompact"] = resvlbl["azteccode"];
136 	resecls["azteccodecompact"] = resecls["azteccode"];
137 	resvers["pdf417"] = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30";
138 	resvlbl["pdf417"] = "Columns";
139 	resecls["pdf417"] = "1,2,3,4,5";
140 	resvers["pdf417compact"] = resvers["pdf417"];
141 	resvlbl["pdf417compact"] = resvlbl["pdf417"];
142 	resecls["pdf417compact"] = resecls["pdf417"];
143 	resvers["hibcpdf417"] = resvers["pdf417"];
144 	resvlbl["hibcpdf417"] = resvlbl["pdf417"];
145 	resecls["hibcpdf417"] = resecls["pdf417"];
146 	resvers["micropdf417"] = "1x11,1x14,1x17,1x20,1x24,1x28,2x8,2x11,2x14,2x17,2x20,2x23,2x26,3x6,3x8,3x10,3x12,3x15,3x20,3x26,3x32,3x38,3x44,4x4,4x6,4x8,4x10,4x12,4x15,4x20,4x26,4x32,4x38,4x44";
147 	resecls["micropdf417"] = "";
148 	resvers["hibcmicropdf417"] = resvers["micropdf417"];
149 	resecls["hibcmicropdf417"] = resecls["micropdf417"];
150 	resvers["hanxin"] = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84";
151 	resecls["hanxin"] = "L1,L2,L3,L4";
152 	resecls["ultracode"] = "EC0,EC1,EC2,EC3,EC4,EC5";
153 
154 
155 	// Which options checkboxes are enabled for each encoder
156 	QStringList includetextAvail = encoderlist;
157 	foreach (const QString& enc, includetextAvail)
158 		resincludetextAvail[enc] = true;
159 
160 	QStringList guardwhitespaceAvail;
161 	guardwhitespaceAvail << "ean13" << "ean8" << "isbn" << "ismn" << "issn" << "ean13composite" << "ean8composite";
162 	foreach (const QString& enc, guardwhitespaceAvail)
163 		resguardwhitespaceAvail[enc] = true;
164 
165 	QStringList includecheckAvail;
166 	includecheckAvail << "bc412" << "channelcode" << "code11" << "code2of5" << "coop2of5" << "datalogic2of5"
167 					  << "iata2of5" << "industrial2of5" << "matrix2of5" << "code39" << "code39ext"
168 					  << "code93" << "code93ext" << "interleaved2of5" << "msi" << "rationalizedCodabar";
169 	foreach (const QString& enc, includecheckAvail)
170 		resincludecheckAvail[enc] = true;
171 
172 	QStringList includecheckintextAvail;
173 	includecheckintextAvail << "bc412" << "code11" << "code2of5" << "coop2of5" << "datalogic2of5" << "iata2of5"
174 							<< "industrial2of5" << "matrix2of5" << "code39" << "code39ext" << "interleaved2of5"
175 							<< "japanpost" << "msi" << "planet" << "plessey" << "postnet" << "rationalizedCodabar" << "royalmail";
176 	foreach (const QString& enc, includecheckintextAvail)
177 		resincludecheckintextAvail[enc] = true;
178 
179 	QStringList parseAvail;
180 	parseAvail << "azteccode" << "azteccodecompact" << "codablockf" << "hibccodablockf" << "code128" << "hibccode128" << "code16k" << "code39ext" << "code49"
181 			   << "code93ext" << "codeone" << "datamatrix" << "hibcdatamatrix" << "maxicode" << "micropdf417" << "hibcmicropdf417" << "pdf417" << "hibcpdf417"
182 			   << "pdf417compact" << "posicode" << "qrcode" << "hibcqrcode" << "microqrcode" << "telepen" << "hanxin" << "dotcode" << "ultracode";
183 	foreach (const QString& enc, parseAvail)
184 		resparseAvail[enc] = true;
185 
186 	QStringList parsefncAvail;
187 	parsefncAvail << "codablockf" << "code128" << "code16k" << "code49" << "code93" << "codeone"
188 				  << "datamatrix" << "posicode" << "qrcode" << "microqrcode" << "dotcode" << "ultracode";
189 	foreach (const QString& enc, parsefncAvail)
190 		resparsefncAvail[enc] = true;
191 
192 	// Building up the bcFamilyCombo grouping the formats for readablity
193 	ui.bcFamilyCombo->addItem(tr("Select a barcode family")); // to prevent 1st gs call
194 	ui.bcFamilyCombo->insertSeparator(999);
195 
196 	// Building up the bcCombo grouping the formats for readablity
197 	ui.bcCombo->addItem(tr("Select a barcode format")); // to prevent 1st gs call
198 	ui.bcCombo->insertSeparator(999);
199 
200 	QString familyName;
201 	QStringList bcNames;
202 	bcNames << "EAN-13" << "EAN-8" << "UPC-A" << "UPC-E" << "ISBN" << "ISMN" << "ISSN";
203 	familyName = tr("Point of Sale");
204 	familyList.append(familyName);
205 	familyItems.insert(familyName, bcNames);
206 
207 	bcNames.clear();
208 	bcNames << "GS1-14" << "GS1 Data Matrix" << "GS1 QR Code" << "GS1-128" << "ITF-14" << "SSCC-18";
209 	familyName = tr("Supply Chain");
210 	familyList.append(familyName);
211 	familyItems.insert(familyName, bcNames);
212 
213 	bcNames.clear();
214 	bcNames << "QR Code" << "Micro QR Code" << "Data Matrix" << "Aztec Code" << "Compact Aztec Code"
215 			<< "Aztec Runes" << "PDF417" << "Compact PDF417" << "MicroPDF417" << "Han Xin Code"
216 			<< "DotCode" << "Ultracode";
217 	familyName = tr("Two-dimensional symbols");
218 	familyList.append(familyName);
219 	familyItems.insert(familyName, bcNames);
220 
221 	bcNames.clear();
222 	bcNames << "Code 128" << "Code 39" << "Code 39 Extended" << "Code 93" << "Code 93 Extended"
223 			<< "Interleaved 2 of 5 (ITF)";
224 	familyName = tr("One-dimensional symbols");
225 	familyList.append(familyName);
226 	familyItems.insert(familyName, bcNames);
227 
228 	bcNames.clear();
229 	bcNames << "GS1 DataBar Omnidirectional" << "GS1 DataBar Stacked Omnidirectional"
230 			<< "GS1 DataBar Expanded" << "GS1 DataBar Expanded Stacked" << "GS1 DataBar Truncated"
231 			<< "GS1 DataBar Stacked" << "GS1 DataBar Limited" << "GS1 North American Coupon";
232 	familyName = tr("GS1 DataBar family");
233 	familyList.append(familyName);
234 	familyItems.insert(familyName, bcNames);
235 
236 	bcNames.clear();
237 	bcNames << "AusPost 4 State Customer Code" << "Deutsche Post Identcode" << "Deutsche Post Leitcode"
238 			<< "Japan Post 4 State Customer Code" << "Royal Dutch TPG Post KIX"
239 			<< "Royal Mail 4 State Customer Code" << "USPS Intelligent Mail" << "USPS PLANET" << "USPS POSTNET";
240 	familyName = tr("Postal symbols");
241 	familyList.append(familyName);
242 	familyItems.insert(familyName, bcNames);
243 
244 	bcNames.clear();
245 	bcNames << "Italian Pharmacode" << "Pharmaceutical Binary Code" << "Two-track Pharmacode"
246 			<< "Pharmazentralnummer (PZN)" << "HIBC Codablock F" << "HIBC Code 128" << "HIBC Code 39"
247 			<< "HIBC Data Matrix" << "HIBC MicroPDF417" << "HIBC PDF417" << "HIBC QR Code";
248 	familyName = tr("Pharmaceutical symbols");
249 	familyList.append(familyName);
250 	familyItems.insert(familyName, bcNames);
251 
252 	bcNames.clear();
253 	bcNames << "Code 11" << "Codabar" << "Code 25" << "COOP 2 of 5" << "Datalogic 2 of 5" << "IATA 2 of 5"
254 			<< "Industrial 2 of 5" << "Matrix 2 of 5" << "MSI Modified Plessey" << "Plessey UK"
255 			<< "PosiCode" << "Telepen" << "Telepen Numeric"<< "Code 16K" << "Codablock F" << "Code 49"
256 			<< "Code One";
257 	familyName = tr("Less-used symbols");
258 	familyList.append(familyName);
259 	familyItems.insert(familyName, bcNames);
260 
261 	bcNames.clear();
262 	bcNames << "EAN-13 Composite" << "EAN-8 Composite" << "UPC-A Composite" << "UPC-E Composite"
263 			<< "GS1 DataBar Omnidirectional Composite" << "GS1 DataBar Stacked Omnidirectional Composite"
264 			<< "GS1 DataBar Expanded Composite" << "GS1 DataBar Expanded Stacked Composite"
265 			<< "GS1 DataBar Truncated Composite" << "GS1 DataBar Stacked Composite"
266 			<< "GS1 DataBar Limited Composite" << "GS1-128 Composite";
267 	familyName = tr("GS1 Composite symbols");
268 	familyList.append(familyName);
269 	familyItems.insert(familyName, bcNames);
270 
271 	ui.bcFamilyCombo->addItems(familyList);
272 
273 	/*
274 	 *  End of the hard-coded data
275 	 *
276 	 */
277 
278 	guiColor = ui.codeEdit->palette().color(QPalette::Window);
279 
280 	ui.okButton->setText(CommonStrings::tr_OK);
281 	ui.cancelButton->setText(CommonStrings::tr_Cancel);
282 	ui.resetButton->setIcon(IconManager::instance().loadIcon("u_undo16.png"));
283 
284 	if (ScCore->primaryMainWindow()->doc->PageColors.contains("Black"))
285 	{
286 		lnColor = ScCore->primaryMainWindow()->doc->PageColors["Black"];
287 		txtColor = ScCore->primaryMainWindow()->doc->PageColors["Black"];
288 		ui.linesLabel->setToolTip("Black");
289 		ui.txtLabel->setToolTip("Black");
290 	}
291 	else
292 	{
293 		ui.linesLabel->setToolTip("n.a.");
294 		ui.txtLabel->setToolTip("n.a.");
295 	}
296 	if (ScCore->primaryMainWindow()->doc->PageColors.contains("White"))
297 	{
298 		bgColor = ScCore->primaryMainWindow()->doc->PageColors["White"];
299 		ui.bgLabel->setToolTip("White");
300 	}
301 	else
302 		ui.bgLabel->setToolTip("n.a.");
303 
304 	paintColorSample(ui.linesLabel, lnColor);
305 	paintColorSample(ui.txtLabel, txtColor);
306 	paintColorSample(ui.bgLabel, bgColor);
307 
308 	paintBarcodeTimer=new QTimer(this);
309 	paintBarcodeTimer->setSingleShot(true);
310 	connect(paintBarcodeTimer, SIGNAL(timeout()), this, SLOT(paintBarcode()));
311 
312 	connect(ui.bcFamilyCombo, SIGNAL(activated(QString)), this, SLOT(bcFamilyComboChanged()));
313 	connect(ui.bcCombo, SIGNAL(activated(QString)), this, SLOT(bcComboChanged()));
314 	connect(ui.bgColorButton, SIGNAL(clicked()), this, SLOT(bgColorButton_pressed()));
315 	connect(ui.lnColorButton, SIGNAL(clicked()), this, SLOT(lnColorButton_pressed()));
316 	connect(ui.txtColorButton, SIGNAL(clicked()), this, SLOT(txtColorButton_pressed()));
317 	connect(ui.okButton, SIGNAL(clicked()), this, SLOT(okButton_pressed()));
318 	connect(ui.cancelButton, SIGNAL(clicked()), this, SLOT(cancelButton_pressed()));
319 	connect(ui.codeEdit, SIGNAL(textChanged(QString)), this, SLOT(codeEdit_textChanged(QString)));
320 	connect(ui.resetButton, SIGNAL(clicked()), this, SLOT(resetButton_clicked()));
321 	bcComboChanged();
322 
323 }
324 
~BarcodeGenerator()325 BarcodeGenerator::~BarcodeGenerator()
326 {
327 	if (!paintBarcodeTimer)
328 		return;
329 	delete paintBarcodeTimer;
330 	paintBarcodeTimer = nullptr;
331 }
332 
updateOptions()333 void BarcodeGenerator::updateOptions()
334 {
335 	QString enc=map[ui.bcCombo->currentText()].command;
336 
337 	ui.formatLabel->setText(resvlbl.contains(enc) ? resvlbl[enc] + ":" : "Version:");
338 	ui.formatCombo->blockSignals(true);
339 	ui.formatCombo->clear();
340 	ui.formatCombo->addItem("Auto");
341 	if (resvers.contains(enc))
342 	{
343 		ui.formatCombo->insertSeparator(999);
344 		ui.formatCombo->addItems(resvers[enc].split(","));
345 		ui.formatLabel->setEnabled(true);
346 		ui.formatCombo->setEnabled(true);
347 	}
348 	else
349 	{
350 		ui.formatLabel->setEnabled(false);
351 		ui.formatCombo->setEnabled(false);
352 	}
353 	ui.formatCombo->blockSignals(false);
354 
355 	ui.eccCombo->blockSignals(true);
356 	ui.eccCombo->clear();
357 	ui.eccCombo->addItem("Auto");
358 	if (resecls.contains(enc))
359 	{
360 		ui.eccCombo->insertSeparator(999);
361 		ui.eccCombo->addItems(resecls[enc].split(","));
362 		ui.eccLabel->setEnabled(true);
363 		ui.eccCombo->setEnabled(true);
364 	}
365 	else
366 	{
367 		ui.eccLabel->setEnabled(false);
368 		ui.eccCombo->setEnabled(false);
369 	}
370 	ui.eccCombo->blockSignals(false);
371 
372 }
373 
374 
bcFamilyComboChanged()375 void BarcodeGenerator::bcFamilyComboChanged()
376 {
377 	ui.bcCombo->blockSignals(true);
378 	ui.bcCombo->clear();
379 	ui.bcCombo->addItem(tr("Select a barcode format")); // to prevent 1st gs call
380 	ui.bcCombo->insertSeparator(999);
381 	ui.bcCombo->addItems(familyItems[ui.bcFamilyCombo->currentText()]);
382 	ui.bcCombo->blockSignals(false);
383 	bcComboChanged();
384 }
385 
bcComboChanged(int i)386 void BarcodeGenerator::bcComboChanged(int i)
387 {
388 	bcComboChanged();
389 }
390 
bcComboChanged()391 void BarcodeGenerator::bcComboChanged()
392 {
393 	updateOptions();
394 
395 	if (ui.bcCombo->currentIndex() == 0)
396 	{
397 		ui.okButton->setEnabled(false);
398 		ui.sampleLabel->setText(tr("Select Type"));
399 		ui.codeEdit->clear();
400 		ui.codeEdit->setEnabled(false);
401 		ui.optionsEdit->clear();
402 		ui.optionsEdit->setEnabled(false);
403 		ui.includetextCheck->setEnabled(false);
404 		ui.guardwhitespaceCheck->setEnabled(false);
405 		ui.includecheckCheck->setEnabled(false);
406 		ui.includecheckintextCheck->setEnabled(false);
407 		ui.parseCheck->setEnabled(false);
408 		ui.parsefncCheck->setEnabled(false);
409 		ui.formatLabel->setEnabled(false);
410 		ui.formatCombo->setEnabled(false);
411 		ui.eccLabel->setEnabled(false);
412 		ui.eccCombo->setEnabled(false);
413 		ui.bgColorButton->setEnabled(false);
414 		ui.lnColorButton->setEnabled(false);
415 		ui.txtColorButton->setEnabled(false);
416 		return;
417 	}
418 
419 	ui.codeEdit->setEnabled(true);
420 	ui.optionsEdit->setEnabled(true);
421 	ui.bgColorButton->setEnabled(true);
422 	ui.lnColorButton->setEnabled(true);
423 	ui.txtColorButton->setEnabled(true);
424 	ui.okButton->setEnabled(true);
425 
426 	QString s = ui.bcCombo->currentText();
427 	ui.codeEdit->blockSignals(true);
428 	ui.codeEdit->setText(map[s].exampleContents);
429 	ui.codeEdit->blockSignals(false);
430 	ui.optionsEdit->blockSignals(true);
431 	ui.optionsEdit->setText(map[s].exampleOptions);
432 	ui.optionsEdit->blockSignals(false);
433 
434 	QString enc = map[s].command;
435 	ui.includetextCheck->setEnabled(resincludetextAvail[enc]);
436 	ui.guardwhitespaceCheck->setEnabled(resguardwhitespaceAvail[enc]);
437 	ui.includecheckCheck->setEnabled(resincludecheckAvail[enc]);
438 	ui.includecheckintextCheck->setEnabled(resincludetextAvail[enc] && resincludecheckintextAvail[enc]);
439 	ui.parseCheck->setEnabled(resparseAvail[enc]);
440 	ui.parsefncCheck->setEnabled(resparsefncAvail[enc]);
441 
442 	updateUIFromOptionsText();
443 
444 	enqueuePaintBarcode(0);
445 }
446 
enqueuePaintBarcode(int delay)447 void BarcodeGenerator::enqueuePaintBarcode(int delay)
448 {
449 	ui.okButton->setEnabled(false);
450 	//	paintBarcode();
451 	paintBarcodeTimer->start(delay);
452 }
453 
updateOptionsTextFromUI()454 void BarcodeGenerator::updateOptionsTextFromUI()
455 {
456 	QString opts = ui.optionsEdit->text();
457 
458 	if (ui.includetextCheck->isChecked())
459 	{
460 		if (!opts.contains(QRegExp("\\bincludetext\\b")))
461 			opts.append(" includetext");
462 	}
463 	else
464 	{
465 		opts.replace(QRegExp("\\bincludetext\\b")," ");
466 	}
467 
468 	if (ui.guardwhitespaceCheck->isChecked())
469 	{
470 		if (!opts.contains(QRegExp("\\bguardwhitespace\\b")))
471 			opts.append(" guardwhitespace");
472 	}
473 	else
474 	{
475 		opts.replace(QRegExp("\\bguardwhitespace\\b")," ");
476 	}
477 
478 	if (ui.includecheckCheck->isChecked())
479 	{
480 		if (!opts.contains(QRegExp("\\bincludecheck\\b")))
481 			opts.append(" includecheck");
482 	}
483 	else
484 	{
485 		opts.replace(QRegExp("\\bincludecheck\\b")," ");
486 	}
487 
488 	if (ui.includecheckintextCheck->isChecked())
489 	{
490 		if (!opts.contains(QRegExp("\\bincludecheckintext\\b")))
491 			opts.append(" includecheckintext");
492 	}
493 	else
494 	{
495 		opts.replace(QRegExp("\\bincludecheckintext\\b")," ");
496 	}
497 
498 	if (ui.parseCheck->isChecked())
499 	{
500 		if (!opts.contains(QRegExp("\\bparse\\b")))
501 			opts.append(" parse");
502 	}
503 	else
504 	{
505 		opts.replace(QRegExp("\\bparse\\b")," ");
506 	}
507 
508 	if (ui.parsefncCheck->isChecked())
509 	{
510 		if (!opts.contains(QRegExp("\\bparsefnc\\b")))
511 			opts.append(" parsefnc");
512 	}
513 	else
514 	{
515 		opts.replace(QRegExp("\\bparsefnc\\b")," ");
516 	}
517 
518 	QString enc = map[ui.bcCombo->currentText()].command;
519 	QString vlbl = resvlbl.contains(enc) ? resvlbl[enc].toLower() : "version";
520 
521 	if (ui.formatCombo->currentIndex() != 0)
522 	{
523 		QString t = ui.formatCombo->currentText();
524 		if (!opts.contains(QRegExp("\\b" + QRegExp::escape(vlbl) + "=.*\\b")))
525 			opts.append(" " + vlbl + "=" + t);
526 		else
527 			opts.replace(QRegExp("\\b" + QRegExp::escape(vlbl) + "=\\S*\\b"), vlbl + "=" + t);
528 	}
529 	else
530 	{
531 		opts.replace(QRegExp("\\b" + QRegExp::escape(vlbl) + "=\\S*\\b"), " ");
532 	}
533 
534 	if (ui.eccCombo->currentIndex() != 0)
535 	{
536 		QString t = ui.eccCombo->currentText();
537 		if (!opts.contains(QRegExp("\\beclevel=.*\\b")))
538 			opts.append(" eclevel=" + t);
539 		else
540 			opts.replace(QRegExp("\\beclevel=\\S*\\b"), "eclevel=" + t);
541 	}
542 	else
543 	{
544 		opts.replace(QRegExp("\\beclevel=\\S*\\b")," ");
545 	}
546 
547 	ui.optionsEdit->blockSignals(true);
548 	ui.optionsEdit->setText(opts.simplified());
549 	ui.optionsEdit->blockSignals(false);
550 
551 }
552 
updateUIFromOptionsText()553 void BarcodeGenerator::updateUIFromOptionsText()
554 {
555 	ui.includetextCheck->blockSignals(true);
556 	ui.includetextCheck->setChecked(ui.optionsEdit->text().contains(QRegExp("\\bincludetext\\b")));
557 	ui.includetextCheck->blockSignals(false);
558 
559 	ui.guardwhitespaceCheck->blockSignals(true);
560 	ui.guardwhitespaceCheck->setChecked(ui.optionsEdit->text().contains(QRegExp("\\bguardwhitespace\\b")));
561 	ui.guardwhitespaceCheck->blockSignals(false);
562 
563 	ui.includecheckCheck->blockSignals(true);
564 	ui.includecheckCheck->setChecked(ui.optionsEdit->text().contains(QRegExp("\\bincludecheck\\b")));
565 	ui.includecheckCheck->blockSignals(false);
566 
567 	ui.includecheckintextCheck->blockSignals(true);
568 	ui.includecheckintextCheck->setChecked(ui.optionsEdit->text().contains(QRegExp("\\bincludecheckintext\\b")));
569 	ui.includecheckintextCheck->blockSignals(false);
570 
571 	ui.parseCheck->blockSignals(true);
572 	ui.parseCheck->setChecked(ui.optionsEdit->text().contains(QRegExp("\\bparse\\b")));
573 	ui.parseCheck->blockSignals(false);
574 
575 	ui.parsefncCheck->blockSignals(true);
576 	ui.parsefncCheck->setChecked(ui.optionsEdit->text().contains(QRegExp("\\bparsefnc\\b")));
577 	ui.parsefncCheck->blockSignals(false);
578 
579 	QString enc = map[ui.bcCombo->currentText()].command;
580 	QString vlbl = resvlbl.contains(enc) ? resvlbl[enc].toLower() : "version";
581 
582 	QRegExp rxf("\\b" + QRegExp::escape(vlbl) + "=(\\S*)\\b");
583 	ui.formatCombo->blockSignals(true);
584 	if (ui.optionsEdit->text().contains(rxf))
585 	{
586 		int idx = ui.formatCombo->findText(rxf.cap(1));
587 		if (idx == -1)
588 			idx = 0;
589 		ui.formatCombo->setCurrentIndex(idx);
590 	}
591 	else
592 	{
593 		ui.formatCombo->setCurrentIndex(0);
594 	}
595 	ui.formatCombo->blockSignals(false);
596 
597 	QRegExp rxe("\\beclevel=(\\S*)\\b");
598 	ui.eccCombo->blockSignals(true);
599 	if (ui.optionsEdit->text().contains(rxe))
600 	{
601 		int idx=ui.eccCombo->findText(rxe.cap(1));
602 		if (idx == -1)
603 			idx = 0;
604 		ui.eccCombo->setCurrentIndex(idx);
605 	}
606 	else
607 	{
608 		ui.eccCombo->setCurrentIndex(0);
609 	}
610 	ui.eccCombo->blockSignals(false);
611 }
612 
updatePreview(const QString & errorMsg)613 void BarcodeGenerator::updatePreview(const QString& errorMsg)
614 {
615 	QString pngFile = QDir::toNativeSeparators(ScPaths::tempFileDir() + "bcode.png");
616 	if (errorMsg.isEmpty())
617 	{
618 		ui.sampleLabel->setPixmap(QPixmap(pngFile));
619 		ui.okButton->setEnabled(true);
620 	}
621 	else
622 	{
623 		ui.sampleLabel->setText("<qt>" + errorMsg + "</qt>");
624 	}
625 }
626 
on_includetextCheck_stateChanged(int)627 void BarcodeGenerator::on_includetextCheck_stateChanged(int)
628 {
629 	updateOptionsTextFromUI();
630 	enqueuePaintBarcode(0);
631 }
632 
on_guardwhitespaceCheck_stateChanged(int)633 void BarcodeGenerator::on_guardwhitespaceCheck_stateChanged(int)
634 {
635 	updateOptionsTextFromUI();
636 	enqueuePaintBarcode(0);
637 }
638 
on_includecheckCheck_stateChanged(int)639 void BarcodeGenerator::on_includecheckCheck_stateChanged(int)
640 {
641 	updateOptionsTextFromUI();
642 	enqueuePaintBarcode(0);
643 }
644 
on_includecheckintextCheck_stateChanged(int)645 void BarcodeGenerator::on_includecheckintextCheck_stateChanged(int)
646 {
647 	updateOptionsTextFromUI();
648 	enqueuePaintBarcode(0);
649 }
650 
on_parseCheck_stateChanged(int)651 void BarcodeGenerator::on_parseCheck_stateChanged(int)
652 {
653 	updateOptionsTextFromUI();
654 	enqueuePaintBarcode(0);
655 }
656 
on_parsefncCheck_stateChanged(int)657 void BarcodeGenerator::on_parsefncCheck_stateChanged(int)
658 {
659 	updateOptionsTextFromUI();
660 	enqueuePaintBarcode(0);
661 }
662 
on_formatCombo_currentIndexChanged(int)663 void BarcodeGenerator::on_formatCombo_currentIndexChanged(int)
664 {
665 	updateOptionsTextFromUI();
666 	enqueuePaintBarcode(0);
667 }
668 
on_eccCombo_currentIndexChanged(int)669 void BarcodeGenerator::on_eccCombo_currentIndexChanged(int)
670 {
671 	updateOptionsTextFromUI();
672 	enqueuePaintBarcode(0);
673 }
674 
paintColorSample(QLabel * l,const ScColor & c)675 void BarcodeGenerator::paintColorSample(QLabel *l, const ScColor & c)
676 {
677 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
678 	QPixmap currentPixmap = l->pixmap(Qt::ReturnByValue);
679 #else
680 	QPixmap currentPixmap = l->pixmap() ? *(l->pixmap()) : QPixmap();
681 #endif
682 
683 	double pixelRatio = l->devicePixelRatioF();
684 	QSize pixmapSize(currentPixmap.width(), currentPixmap.height());
685 	if (currentPixmap.isNull())
686 	{
687 		QRect rect = l->frameRect();
688 		pixmapSize = QSize(rect.width() * pixelRatio, rect.height() * pixelRatio);
689 	}
690 	QPixmap pm(pixmapSize.width(), pixmapSize.height());
691 	pm.fill(c.getRawRGBColor()); // brute force sc2qt color convert for preview
692 	l->setPixmap(pm);
693 }
694 
bgColorButton_pressed()695 void BarcodeGenerator::bgColorButton_pressed()
696 {
697 	ColorsAndFillsDialog d(this, &ScCore->primaryMainWindow()->doc->docGradients, ScCore->primaryMainWindow()->doc->PageColors, "", &ScCore->primaryMainWindow()->doc->docPatterns, ScCore->primaryMainWindow()->doc, ScCore->primaryMainWindow());
698 	if (!d.exec())
699 		return;
700 
701 	QString selectedColorName = d.selectedColorName();
702 	if (selectedColorName == CommonStrings::None)
703 		return;
704 
705 	bgColor = d.selectedColor();
706 	ui.bgLabel->setToolTip(d.selectedColorName());
707 	paintColorSample(ui.bgLabel, bgColor);
708 	enqueuePaintBarcode(0);
709 }
710 
lnColorButton_pressed()711 void BarcodeGenerator::lnColorButton_pressed()
712 {
713 	ColorsAndFillsDialog d(this, &ScCore->primaryMainWindow()->doc->docGradients, ScCore->primaryMainWindow()->doc->PageColors, "", &ScCore->primaryMainWindow()->doc->docPatterns, ScCore->primaryMainWindow()->doc, ScCore->primaryMainWindow());
714 	if (!d.exec())
715 		return;
716 
717 	QString selectedColorName = d.selectedColorName();
718 	if (selectedColorName == CommonStrings::None)
719 		return;
720 
721 	lnColor = d.selectedColor();
722 	ui.linesLabel->setToolTip(d.selectedColorName());
723 	paintColorSample(ui.linesLabel, lnColor);
724 	enqueuePaintBarcode(0);
725 }
726 
txtColorButton_pressed()727 void BarcodeGenerator::txtColorButton_pressed()
728 {
729 	ColorsAndFillsDialog d(this, &ScCore->primaryMainWindow()->doc->docGradients, ScCore->primaryMainWindow()->doc->PageColors, "", &ScCore->primaryMainWindow()->doc->docPatterns, ScCore->primaryMainWindow()->doc, ScCore->primaryMainWindow());
730 	if (!d.exec())
731 		return;
732 
733 	QString selectedColorName = d.selectedColorName();
734 	if (selectedColorName == CommonStrings::None)
735 		return;
736 
737 	txtColor = d.selectedColor();
738 	ui.txtLabel->setToolTip(d.selectedColorName());
739 	paintColorSample(ui.txtLabel, txtColor);
740 	enqueuePaintBarcode(0);
741 }
742 
okButton_pressed()743 void BarcodeGenerator::okButton_pressed()
744 {
745 	QString psFile = QDir::toNativeSeparators(ScPaths::tempFileDir() + "bcode.ps");
746 
747 	// no need to call paintBarcode(pngFile, 300); because
748 	// it's created by previous run...
749 	hide();
750 	const FileFormat * fmt = LoadSavePlugin::getFormatByExt("ps");
751 
752 	UndoTransaction tran;
753 	if (UndoManager::undoEnabled())
754 	{
755 		tran = UndoManager::instance()->beginTransaction(
756 				   ScCore->primaryMainWindow()->doc->currentPage()->getUName(),
757 				   Um::IImageFrame,
758 				   Um::ImportBarcode,
759 				   ui.bcCombo->currentText() + " (" + ui.codeEdit->text() + ")",
760 				   Um::IEPS);
761 	}
762 
763 	if (fmt)
764 	{
765 		fmt->loadFile(psFile, LoadSavePlugin::lfUseCurrentPage|LoadSavePlugin::lfInteractive|LoadSavePlugin::lfNoDialogs);
766 		if (tran)
767 			tran.commit();
768 	}
769 	accept();
770 }
771 
cancelButton_pressed()772 void BarcodeGenerator::cancelButton_pressed()
773 {
774 	reject();
775 }
776 
codeEdit_textChanged(const QString & s)777 void BarcodeGenerator::codeEdit_textChanged(const QString& s)
778 {
779 	enqueuePaintBarcode(0);
780 }
781 
on_optionsEdit_textChanged(const QString & s)782 void BarcodeGenerator::on_optionsEdit_textChanged(const QString &s )
783 {
784 	updateUIFromOptionsText();
785 	enqueuePaintBarcode(0);
786 }
787 
paintBarcode()788 void BarcodeGenerator::paintBarcode()
789 {
790 	QString coloropts("barcolor=%1 showbackground backgroundcolor=%2 textcolor=%3");
791 	coloropts = coloropts.arg(lnColor.name().replace('#', ""), bgColor.name().replace('#', ""), txtColor.name().replace('#', ""));
792 
793 	QString opts=ui.optionsEdit->text() + " " + coloropts;
794 
795 	// Assemble PS from encoder and requirement bodies
796 	QString psCommand = "%!PS-Adobe-2.0 EPSF-2.0\n";
797 	QString req;
798 	QString enc = map[ui.bcCombo->currentText()].command;
799 	foreach (req, resreqs[enc].split(" "))
800 		psCommand.append(resbodys[req]);
801 	psCommand.append(resbodys[enc]);
802 	psCommand.append(
803 				"errordict begin\n"
804 				"/handleerror {\n"
805 				"$error begin\n"
806 				"errorname dup length string cvs 0 6 getinterval (bwipp.) eq {\n"
807 				"(%stderr) (w) file\n"
808 				"dup (\nBWIPP ERROR: ) writestring\n"
809 				"dup errorname dup length string cvs writestring\n"
810 				"dup ( ) writestring\n"
811 				"dup errorinfo dup length string cvs writestring\n"
812 				"dup (\n) writestring\n"
813 				"dup flushfile end quit\n"
814 				"} if\n"
815 				"end //handleerror exec\n"
816 				"} bind def\n"
817 				"end\n"
818 				);
819 	QString comm("20 10 moveto <%1> <%2> /%3 /uk.co.terryburton.bwipp findresource exec\n");
820 	QString bcdata(ui.codeEdit->text().toLatin1().toHex());
821 	QString bcopts(opts.toLatin1().toHex());
822 	comm = comm.arg(bcdata, bcopts, map[ui.bcCombo->currentText()].command);
823 	psCommand.append(comm);
824 	psCommand.append("showpage\n");
825 
826 	thread.render(psCommand);
827 }
828 
829 
resetButton_clicked()830 void BarcodeGenerator::resetButton_clicked()
831 {
832 	bcComboChanged();
833 }
834