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 #include "checkDocument.h"
8 
9 #include <QComboBox>
10 #include <QEvent>
11 #include <QHBoxLayout>
12 #include <QHeaderView>
13 #include <QImage>
14 #include <QLabel>
15 #include <QPixmap>
16 #include <QPushButton>
17 #include <QSpacerItem>
18 #include <QToolTip>
19 #include <QTreeWidget>
20 #include <QTreeWidgetItem>
21 #include <QVBoxLayout>
22 
23 #include "commonstrings.h"
24 #include "documentchecker.h"
25 #include "pdfoptions.h"
26 #include "prefsmanager.h"
27 #include "scpage.h"
28 #include "scribusapp.h"
29 #include "scribuscore.h"
30 #include "scribusdoc.h"
31 #include "iconmanager.h"
32 #include "util.h"
33 
34 // readable constants for QTreeWidgetItem column ids
35 #define COLUMN_ITEM 0
36 #define COLUMN_PROBLEM 1
37 #define COLUMN_LAYER 2
38 // #define COLUMN_INFO 3
39 
CheckDocument(QWidget * parent,bool modal)40 CheckDocument::CheckDocument( QWidget* parent, bool modal )
41 	: ScrPaletteBase( parent, "checkDocument", modal )
42 {
43 	showPagesWithoutErrors = PrefsManager::instance().appPrefs.verifierPrefs.showPagesWithoutErrors;
44 	showNonPrintingLayerErrors = PrefsManager::instance().appPrefs.verifierPrefs.showNonPrintingLayerErrors;
45 
46 	iconSetChange();
47 
48 	checkDocumentLayout = new QVBoxLayout( this );
49 	checkDocumentLayout->setContentsMargins(9, 9, 9, 9);
50 	checkDocumentLayout->setSpacing(6);
51 
52 	layout1 = new QHBoxLayout;
53 	layout1->setContentsMargins(0, 0, 0, 0);
54 	layout1->setSpacing(6);
55 	textLabel1 = new QLabel( this );
56 	layout1->addWidget( textLabel1 );
57 	curCheckProfile = new QComboBox( this );
58 	layout1->addWidget( curCheckProfile );
59 	checkDocumentLayout->addLayout( layout1 );
60 
61 	reportDisplay = new QTreeWidget( this );
62 	reportDisplay->header()->setSectionsClickable(false );
63 	reportDisplay->header()->setSectionsMovable( false );
64 	reportDisplay->setSortingEnabled(false);
65 	reportDisplay->setAlternatingRowColors(true);
66 	checkDocumentLayout->addWidget( reportDisplay );
67 
68 	layout2 = new QHBoxLayout;
69 	layout2->setContentsMargins(0, 0, 0, 0);
70 	layout2->setSpacing(6);
71 	reScan = new QPushButton(this );
72 	layout2->addWidget( reScan );
73 	QSpacerItem* spacer = new QSpacerItem( 2, 2, QSizePolicy::Expanding, QSizePolicy::Minimum );
74 	layout2->addItem( spacer );
75 	ignoreErrors = new QPushButton(this );
76 	layout2->addWidget( ignoreErrors );
77 	checkDocumentLayout->addLayout( layout2 );
78 	setIgnoreEnabled(false);
79 	checkMode = checkNULL;
80 	languageChange();
81 	itemMap.clear();
82 	posMap.clear();
83 	pageMap.clear();
84 	masterPageMap.clear();
85 	masterPageItemMap.clear();
86 	resize( QSize(320, 260).expandedTo(minimumSizeHint()) );
87 
88 	connect(ScQApp, SIGNAL(iconSetChanged()), this, SLOT(iconSetChange()));
89 
90 	connect(ignoreErrors, SIGNAL(clicked()), this, SIGNAL(ignoreAllErrors()));
91 	connect(curCheckProfile, SIGNAL(activated(const QString&)), this, SLOT(newScan(const QString&)));
92 	connect(reScan, SIGNAL(clicked()), this, SLOT(doReScan()));
93 }
94 
changeEvent(QEvent * e)95 void CheckDocument::changeEvent(QEvent *e)
96 {
97 	if (e->type() == QEvent::LanguageChange)
98 	{
99 		languageChange();
100 	}
101 	else
102 		QWidget::changeEvent(e);
103 }
104 
iconSetChange()105 void CheckDocument::iconSetChange()
106 {
107 	graveError = IconManager::instance().loadPixmap("22/dialog-error.png");
108 	onlyWarning = IconManager::instance().loadPixmap("22/dialog-warning.png");
109 	noErrors = IconManager::instance().loadPixmap("ok.png");
110 }
111 
languageChange()112 void CheckDocument::languageChange()
113 {
114 	setWindowTitle( tr( "Preflight Verifier" ) );
115 	QStringList headerLabels;
116 	headerLabels << tr("Items") << tr("Problems")
117 				 << tr("Layer");// << tr("Information");
118 	reportDisplay->setHeaderLabels(headerLabels);
119 	reportDisplay->setColumnCount(headerLabels.count());
120 
121 	textLabel1->setText( tr("Current Profile:"));
122 	ignoreErrors->setText( tr("&Ignore Errors"));
123 	reScan->setText( tr("Check again"));
124 
125 	textLabel1->setToolTip( "<qt>"+ tr( "Preflight profile to base the report generation on. Options can be set in Document Setup or Preferences.") + "</qt>");
126 	ignoreErrors->setToolTip( "<qt>"+ tr( "Ignore found errors and continue to export or print. Be sure to understand the errors you are ignoring before continuing.") + "</qt>");
127 	reScan->setToolTip( "<qt>"+ tr( "Rerun the document scan to check corrections you may have made" ) + "</qt>");
128 
129 	warnMap.clear();
130 	warnMap.insert(PV_ANNOTATION,				qMakePair(tr("Object is a PDF Annotation or Field"),					tr("Indicates that editorial changes have been made to a PDF are still present or your PDF contains unprintable annotation items. They may cause issues in professional printing. Also helpful reminder if you are wanting to publish a final draft without editorial relics.")));
131 	warnMap.insert(PV_APPLIED_MASTER_DIFF_SIDE,	qMakePair(tr("Applied master page has different page destination (left, middle, right side)"),
132 																														tr("Have you applied the correct Master Page?")));
133 	warnMap.insert(PV_EMPTY_IMAGE_FRAME,		qMakePair(tr("Empty Image Frame"),										tr("If you have created an image frame, there is the presumption that you planned to put an image in it")));
134 	warnMap.insert(PV_EMPTY_TEXT_FRAME,			qMakePair(tr("Empty Text Frame"),										tr("If you have created a text frame, there is the presumption that you planned to put text in it")));
135 	warnMap.insert(PV_FONT_NOT_EMBEDDED,		qMakePair(tr("Imported document contains non-embedded fonts"),			tr("When some imported document uses non-embedded fonts, then their rendering will be wrong, unless by chance you have them installed on their system, but that cannot be guaranteed in case you want to share the resulting document")));
136 	warnMap.insert(PV_HIGH_DPI,					qMakePair(tr("Image resolution above %1 DPI,\ncurrently %2 x %3 DPI"),	tr("This is a user definable setting serving as a caution for high resolution images, which may lead to unnecessarily large files")));
137 	warnMap.insert(PV_IMAGE_FRAME_PART_FILLED,	qMakePair(tr("Image dimension is smaller than its frame"),				tr("The image does not fit the whole space you reserved for it. Maybe this is intended, or maybe this is caused by bad inner placement or scale. The result will either be a cropped image or white space around the image.")));
138 	warnMap.insert(PV_IS_GIF,					qMakePair(tr("Image is GIF"),											tr("This warning alerts you that you are using a bitmap based graphic format that is typically not used for high resolution images (.gif is one of those). This may result in poor viewing quality (for example: when commercially printed, viewed on a high-resolution screens, etc...). If your PDF will be printed commercially, there are some printing systems that will have difficulty printing these types of images.")));
139 	warnMap.insert(PV_LOW_DPI,					qMakePair(tr("Image resolution below %1 DPI,\ncurrently %2 x %3 DPI"),	tr("This is a user definable setting serving as a caution for low resolution images, which may lead to poor quality output")));
140 	warnMap.insert(PV_MISSING_GLYPH,			qMakePair(tr("Glyphs missing"),											tr("You have one or more characters which do not have a corresponding glyph in your chosen font")));
141 	warnMap.insert(PV_MISSING_IMAGE,			qMakePair(tr("Missing Image"),											tr("The assigned image file cannot be found")));
142 	warnMap.insert(PV_NON_ON_PAGE,				qMakePair(tr("Object is not on a Page"),								tr("An object is placed somewhere outside of the page borders, it will not be printed and might be missing somewhere")));
143 	warnMap.insert(PV_NOT_CMYK_SPOT,			qMakePair(tr("Object colorspace is not CMYK or spot"),					tr("PDF supports many different ways to represent the color of any object including RGB, CMYK and Spot (aka Separation) colors. Some of the PDF standards, such as PDF/X-1a, require the only CMYK and Spot colors be used.")));
144 	warnMap.insert(PV_RASTER_PDF,				qMakePair(tr("Object is a placed PDF"),									tr("The warning is verifying for you that there is a PDF loaded into an Image Frame, where it will be rasterized or converted to a bitmap. Its resolution may be less than ideal. See PDF Export to learn how to minimize this problem.")));
145 	warnMap.insert(PV_TEXT_OVERFLOW,			qMakePair(tr("Text overflow"),											tr("There is more text than can show in the frame as sized. Nonvisible excess characters like spaces and carriage returns may trigger this if nothing appears to be missing.")));
146 	warnMap.insert(PV_TRANSPARENCY,				qMakePair(tr("Object has transparency"),								tr("This warning indicates that your document contains images that have a transparent layer. This is really only an issue if using older printing profiles or PostScript. It is safe to ignore this when exporting to PDF version greater than 1.4.")));
147 	warnMap.insert(PV_WRONG_FONT,				qMakePair(tr("Annotation uses a non-TrueType font"),					tr("Annotations support only a standard set of fonts. Choose another one.")));
148 	warnMap.insert(PV_LAYER_TRANSPARENCY,		qMakePair(tr("Transparency used"),										tr("This layer uses transparency, only an issue if using older printing profiles. You may safely ignore this when using modern printing methods, or exporting to PDF version greater than 1.4.")));
149 	warnMap.insert(PV_LAYER_BLENDMODE,			qMakePair(tr("Blendmode used"),											tr("This layer uses blendmodes which relies on transparency, only an issue if using older printing profiles. You may safely ignore this when using modern printing methods, or exporting to PDF version greater than 1.4.")));
150 	warnMap.insert(PV_LAYER_PRINTVIS_MISMATCH,	qMakePair(tr("Print/Visible mismatch"),									tr("This layer uses transparency, only an issue if using older printing profiles. You may safely ignore this when using modern printing methods, or exporting to PDF version greater than 1.4.")));
151 }
152 
bestCheckerProfileForCheckMode(const QString & defaultProfile)153 QString CheckDocument::bestCheckerProfileForCheckMode(const QString& defaultProfile)
154 {
155 	QString bestProfile = bestCheckerProfileForCheckMode(this->checkMode, defaultProfile);
156 	return bestProfile;
157 }
158 
bestCheckerProfileForCheckMode(CheckMode mode,const QString & defaultProfile)159 QString CheckDocument::bestCheckerProfileForCheckMode(CheckMode mode, const QString& defaultProfile)
160 {
161 	QString bestProfile = defaultProfile;
162 
163 	if (mode == CheckDocument::checkPDF || mode == CheckDocument::checkOutputPreviewPDF)
164 	{
165 		PDFVersion pdfVersion = m_Doc->pdfOptions().Version;
166 		if (pdfVersion == PDFVersion::PDF_13)
167 			bestProfile = CommonStrings::PDF_1_3;
168 		else if (pdfVersion == PDFVersion::PDF_14)
169 			bestProfile = CommonStrings::PDF_1_4;
170 		else if (pdfVersion == PDFVersion::PDF_15)
171 			bestProfile = CommonStrings::PDF_1_5;
172 		else if (pdfVersion == PDFVersion::PDF_16)
173 			bestProfile = CommonStrings::PDF_1_6;
174 		else if (pdfVersion == PDFVersion::PDF_X1a)
175 			bestProfile = CommonStrings::PDF_X1a;
176 		else if (pdfVersion == PDFVersion::PDF_X3)
177 			bestProfile = CommonStrings::PDF_X3;
178 		else if (pdfVersion == PDFVersion::PDF_X4)
179 			bestProfile = CommonStrings::PDF_X4;
180 	}
181 	else if (mode == CheckDocument::checkEPS || mode == CheckDocument::checkOutputPreviewPS)
182 		bestProfile = CommonStrings::PostScript;
183 
184 	const auto& checkerProfiles = m_Doc->checkerProfiles();
185 	if (checkerProfiles.contains(bestProfile))
186 		return bestProfile;
187 	return defaultProfile;
188 }
189 
setDoc(ScribusDoc * doc)190 void CheckDocument::setDoc(ScribusDoc *doc)
191 {
192 	m_Doc = doc;
193 	clearErrorList();
194 	CheckerPrefsList::Iterator it;
195 	CheckerPrefsList::Iterator itend=doc->checkerProfiles().end();
196 	for (it = doc->checkerProfiles().begin(); it != itend ; ++it)
197 		curCheckProfile->addItem(it.key());
198 	setCurrentComboItem(curCheckProfile, doc->curCheckProfile());
199 }
200 
slotSelect(QTreeWidgetItem * ite)201 void CheckDocument::slotSelect(QTreeWidgetItem* ite)
202 {
203 	if (itemMap.contains(ite))
204 	{
205 		// #10537 Check item has not been destroyed before requesting its selection
206 		if (itemMap[ite].isNull())
207 			return;
208 		ScCore->primaryMainWindow()->closeActiveWindowMasterPageEditor();
209 		m_Doc->setActiveLayer(itemMap[ite]->m_layerID);
210 		ScCore->primaryMainWindow()->changeLayer(m_Doc->activeLayer());
211 		if (itemMap[ite]->isTextFrame())
212 			emit selectElement(itemMap[ite], true, posMap[ite]);
213 		else
214 			emit selectElementByItem(itemMap[ite], true);
215 		return;
216 	}
217 	if (pageMap.contains(ite))
218 	{
219 		// #10537 Get page index from pointer in case user has deleted a page
220 		// after preflight has been run
221 		int pageIndex = m_Doc->DocPages.indexOf(pageMap[ite]);
222 		if (pageIndex < 0)
223 			return;
224 		ScCore->primaryMainWindow()->closeActiveWindowMasterPageEditor();
225 		emit selectPage(pageIndex);
226 		return;
227 	}
228 	if (masterPageMap.contains(ite))
229 	{
230 		// #10537 Get page index from pointer in case user has deleted a page
231 		// after preflight has been run
232 		int pageIndex = m_Doc->MasterPages.indexOf(masterPageMap[ite]);
233 		if (pageIndex < 0)
234 			return;
235 		emit selectMasterPage(masterPageMap[ite]->pageName());
236 		return;
237 	}
238 	if (masterPageItemMap.contains(ite))
239 	{
240 		// #10537 Check item has not been destroyed before requesting its selection
241 		if (masterPageItemMap[ite].isNull())
242 			return;
243 		if (!m_Doc->masterPageMode())
244 			emit selectMasterPage(masterPageItemMap[ite]->OnMasterPage);
245 		m_Doc->setActiveLayer(masterPageItemMap[ite]->m_layerID);
246 		ScCore->primaryMainWindow()->changeLayer(m_Doc->activeLayer());
247 		if (masterPageItemMap[ite]->isTextFrame())
248 			emit selectElement(masterPageItemMap[ite], true, posMap[ite]);
249 		else
250 			emit selectElementByItem(masterPageItemMap[ite], true);
251 		return;
252 	}
253 }
254 
doReScan()255 void CheckDocument::doReScan()
256 {
257 	showPagesWithoutErrors=PrefsManager::instance().appPrefs.verifierPrefs.showPagesWithoutErrors;
258 	showNonPrintingLayerErrors=PrefsManager::instance().appPrefs.verifierPrefs.showNonPrintingLayerErrors;
259 	newScan(curCheckProfile->currentText());
260 }
261 
newScan(const QString & name)262 void CheckDocument::newScan(const QString& name)
263 {
264 	clearErrorList();
265 	if (m_Doc==nullptr)
266 		return;
267 	m_Doc->setCurCheckProfile(name);
268 	DocumentChecker::checkDocument(m_Doc);
269 	buildErrorList(m_Doc);
270 }
271 
clearErrorList()272 void CheckDocument::clearErrorList()
273 {
274 	disconnect(reportDisplay, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(slotSelect(QTreeWidgetItem*)));
275 	reportDisplay->clear();
276 	reportDisplay->setSortingEnabled(false);
277 	itemMap.clear();
278 	posMap.clear();
279 	pageMap.clear();
280 	masterPageMap.clear();
281 	masterPageItemMap.clear();
282 }
283 
buildItem(QTreeWidgetItem * item,PreflightError errorType,PageItem * pageItem)284 void CheckDocument::buildItem(QTreeWidgetItem * item,
285 							   PreflightError errorType,
286 							   PageItem * pageItem)
287 {
288 	Q_ASSERT_X(item != nullptr, "CheckDocument::buildItem",
289 				"No reference to QTreeWidgetItem item");
290 	Q_ASSERT_X(pageItem != nullptr, "CheckDocument::buildItem",
291 				"No reference to PageItem pageItem");
292 
293 	switch (errorType)
294 	{
295 		case MissingGlyph:
296 			item->setText(COLUMN_PROBLEM, warnMap[PV_MISSING_GLYPH].first);
297 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_MISSING_GLYPH].second);
298 			item->setIcon(COLUMN_ITEM, graveError);
299 			pageGraveError = true;
300 			itemError = true;
301 			break;
302 		case TextOverflow:
303 			item->setText(COLUMN_PROBLEM, warnMap[PV_TEXT_OVERFLOW].first);
304 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_TEXT_OVERFLOW].second);
305 			item->setIcon(COLUMN_ITEM, onlyWarning);
306 			break;
307 		case ObjectNotOnPage:
308 			item->setText(COLUMN_PROBLEM, warnMap[PV_NON_ON_PAGE].first);
309 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_NON_ON_PAGE].second);
310 			item->setIcon(COLUMN_ITEM, onlyWarning);
311 			break;
312 		case MissingImage:
313 			if (pageItem->externalFile().isEmpty())
314 			{
315 				item->setText(COLUMN_PROBLEM, warnMap[PV_EMPTY_IMAGE_FRAME].first);
316 				item->setToolTip(COLUMN_PROBLEM, warnMap[PV_EMPTY_IMAGE_FRAME].second);
317 				item->setIcon(COLUMN_ITEM, onlyWarning );
318 			}
319 			else
320 			{
321 				item->setText(COLUMN_PROBLEM, warnMap[PV_MISSING_IMAGE].first);
322 				item->setToolTip(COLUMN_PROBLEM, warnMap[PV_MISSING_IMAGE].second);
323 				item->setIcon(COLUMN_ITEM, graveError );
324 				pageGraveError = true;
325 			}
326 			break;
327 		case ImageDPITooLow:
328 		{
329 			int xres = qRound(72.0 / pageItem->imageXScale());
330 			int yres = qRound(72.0 / pageItem->imageYScale());
331 			item->setText(COLUMN_PROBLEM, warnMap[PV_LOW_DPI].first.arg(minResDPI).arg(xres).arg(yres));
332 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_LOW_DPI].second);
333 			item->setIcon(COLUMN_ITEM, onlyWarning );
334 			break;
335 		}
336 		case ImageDPITooHigh:
337 		{
338 			int xres = qRound(72.0 / pageItem->imageXScale());
339 			int yres = qRound(72.0 / pageItem->imageYScale());
340 			item->setText(COLUMN_PROBLEM, warnMap[PV_HIGH_DPI].first.arg(maxResDPI).arg(xres).arg(yres));
341 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_HIGH_DPI].second);
342 			item->setIcon(COLUMN_ITEM, onlyWarning );
343 			break;
344 		}
345 		case PartFilledImageFrame:
346 			item->setText(COLUMN_PROBLEM, warnMap[PV_IMAGE_FRAME_PART_FILLED].first);
347 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_IMAGE_FRAME_PART_FILLED].second);
348 			item->setIcon(COLUMN_ITEM, onlyWarning);
349 			break;
350 		case Transparency:
351 			item->setText(COLUMN_PROBLEM, warnMap[PV_TRANSPARENCY].first);
352 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_TRANSPARENCY].second);
353 			item->setIcon(COLUMN_ITEM, graveError );
354 			pageGraveError = true;
355 			itemError = true;
356 			break;
357 		case PDFAnnotField:
358 			item->setText(COLUMN_PROBLEM, warnMap[PV_ANNOTATION].second);
359 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_ANNOTATION].second);
360 			item->setIcon(COLUMN_ITEM, onlyWarning );
361 			break;
362 		case PlacedPDF:
363 			item->setText(COLUMN_PROBLEM, warnMap[PV_RASTER_PDF].first);
364 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_RASTER_PDF].second);
365 			item->setIcon(COLUMN_ITEM, onlyWarning );
366 			break;
367 		case ImageIsGIF:
368 			item->setText(COLUMN_PROBLEM, warnMap[PV_IS_GIF].first);
369 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_IS_GIF].second);
370 			item->setIcon(COLUMN_ITEM, onlyWarning);
371 			break;
372 		case WrongFontInAnnotation:
373 			item->setText(COLUMN_PROBLEM, warnMap[PV_WRONG_FONT].first);
374 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_WRONG_FONT].second);
375 			item->setIcon(COLUMN_ITEM, graveError );
376 			pageGraveError = true;
377 			itemError = true;
378 			break;
379 		case NotCMYKOrSpot:
380 			item->setText(COLUMN_PROBLEM, warnMap[PV_NOT_CMYK_SPOT].first);
381 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_NOT_CMYK_SPOT].second);
382 			item->setIcon(COLUMN_ITEM, onlyWarning);
383 			itemError = true;
384 			break;
385 		case FontNotEmbedded:
386 			item->setText(COLUMN_PROBLEM, warnMap[PV_FONT_NOT_EMBEDDED].first);
387 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_FONT_NOT_EMBEDDED].second);
388 			item->setIcon(COLUMN_ITEM, graveError);
389 			itemError = true;
390 			break;
391 		case EmptyTextFrame:
392 			item->setText(COLUMN_PROBLEM, warnMap[PV_EMPTY_TEXT_FRAME].first);
393 			item->setToolTip(COLUMN_PROBLEM, warnMap[PV_EMPTY_TEXT_FRAME].second);
394 			item->setIcon(COLUMN_ITEM, onlyWarning);
395 			itemError = true;
396 			break;
397 		default:
398 			break;
399 	};
400 	// additional informations
401 	const ScLayer* layer = m_Doc->Layers.layerByID(pageItem->m_layerID);
402 	if (layer)
403 	{
404 		item->setText(COLUMN_LAYER, layer->Name);
405 		item->setData(COLUMN_LAYER, Qt::DecorationRole, layer->markerColor);
406 	}
407 }
408 
buildErrorList(ScribusDoc * doc)409 void CheckDocument::buildErrorList(ScribusDoc *doc)
410 {
411 // 	bool resultError = false;
412 	m_Doc = doc;
413 	disconnect(curCheckProfile, SIGNAL(activated(const QString&)), this, SLOT(newScan(const QString&)));
414 	curCheckProfile->clear();
415 	clearErrorList();
416 
417 	if (m_Doc==nullptr)
418 		return;
419 
420 	minResDPI = qRound(doc->checkerProfiles()[doc->curCheckProfile()].minResolution);
421 	maxResDPI = qRound(doc->checkerProfiles()[doc->curCheckProfile()].maxResolution);
422 
423 	CheckerPrefsList::Iterator it;
424 	CheckerPrefsList::Iterator itend=doc->checkerProfiles().end();
425 	for (it = doc->checkerProfiles().begin(); it != itend ; ++it)
426 		curCheckProfile->addItem(it.key());
427 	setCurrentComboItem(curCheckProfile, doc->curCheckProfile());
428 	if (!doc->hasPreflightErrors()
429 	    //this flag is used by documentchecker as indicator for marks change after updating
430 		&& !doc->notesChanged())
431 	{
432 		QTreeWidgetItem * documentItem = new QTreeWidgetItem( reportDisplay );
433 		documentItem->setText(COLUMN_ITEM, tr( "Document" ) );
434 		documentItem->setIcon(COLUMN_ITEM, noErrors );
435 		documentItem->setText(COLUMN_PROBLEM, tr( "No Problems found" ) );
436 		ignoreErrors->setText( tr("OK"));
437 	}
438 	else
439 	{
440 		bool hasError = false;
441 		bool layoutGraveError = false;
442 		itemError = false;
443 
444 
445 		// MARKS ***********************************************
446 		if (doc->notesChanged())
447 		{
448 			QTreeWidgetItem * marksItem = new QTreeWidgetItem(reportDisplay);
449 			marksItem->setText(0, tr("After Marks update document was changed"));
450 			marksItem->setIcon(COLUMN_ITEM, onlyWarning );
451 			doc->setNotesChanged(false);
452 		}
453 
454 		// LAYERS **********************************************8
455 		QTreeWidgetItem * layerItem = new QTreeWidgetItem(reportDisplay);
456 		layerItem->setText(COLUMN_ITEM, tr("Layers"));
457 
458 		if (doc->docLayerErrors.count() != 0)
459 		{
460 			QMap<int, errorCodes>::Iterator docLayerErrorsIt;
461 			errorCodes::Iterator layerErrorsIt;
462 
463 			for (docLayerErrorsIt = doc->docLayerErrors.begin();
464 				 docLayerErrorsIt != doc->docLayerErrors.end();
465 				 ++docLayerErrorsIt)
466 			{
467 				QTreeWidgetItem * layer = new QTreeWidgetItem(layerItem);
468 				for (layerErrorsIt = docLayerErrorsIt.value().begin();
469 					 layerErrorsIt != docLayerErrorsIt.value().end(); ++layerErrorsIt)
470 				{
471 					QTreeWidgetItem * errorText = new QTreeWidgetItem( layer, 0 );
472 					switch (layerErrorsIt.key())
473 					{
474 						case Transparency:
475 							errorText->setText(COLUMN_ITEM, warnMap[PV_LAYER_TRANSPARENCY].first);
476 							errorText->setToolTip(COLUMN_ITEM, warnMap[PV_LAYER_TRANSPARENCY].second);
477 							errorText->setIcon(COLUMN_ITEM, graveError );
478 							layoutGraveError = true;
479 							break;
480 						case BlendMode:
481 							errorText->setText(COLUMN_ITEM, warnMap[PV_LAYER_BLENDMODE].first);
482 							errorText->setToolTip(COLUMN_ITEM, warnMap[PV_LAYER_BLENDMODE].second);
483 							errorText->setIcon(COLUMN_ITEM, graveError );
484 							layoutGraveError = true;
485 							break;
486 						case OffConflictLayers:
487 							errorText->setText(COLUMN_ITEM, warnMap[PV_LAYER_PRINTVIS_MISMATCH].first);
488 							errorText->setToolTip(COLUMN_ITEM, warnMap[PV_LAYER_PRINTVIS_MISMATCH].second);
489 							errorText->setIcon(COLUMN_ITEM, onlyWarning );
490 							break;
491 						default:
492 							break;
493 					}
494 				}
495 				layer->setText(COLUMN_ITEM,tr("Layer \"%1\"").arg(doc->layerName(docLayerErrorsIt.key())));
496 				if (layoutGraveError)
497 					layer->setIcon(COLUMN_ITEM, graveError );
498 				else
499 					layer->setIcon(COLUMN_ITEM, onlyWarning );
500 				layer->setText(COLUMN_PROBLEM, tr("Issues: %1").arg(doc->docLayerErrors[docLayerErrorsIt.key()].count()));
501 				layer->setExpanded(true);
502 			}
503 			layerItem->setExpanded(true);
504 		}
505 		// END of LAYERS
506 
507 		// Master Pages *****************************************************
508 		QTreeWidgetItem * masterPageRootItem = new QTreeWidgetItem(reportDisplay);
509 		masterPageRootItem->setText(COLUMN_ITEM, tr("Master Pages"));
510 		int mpErrorCount = 0;
511 
512 		for (int mPage = 0; mPage < doc->MasterPages.count(); ++mPage)
513 		{
514 			hasError = false;
515 			pageGraveError = false;
516 			QTreeWidgetItem * page=nullptr;
517 			if (showPagesWithoutErrors)
518 			{
519 				page = new QTreeWidgetItem( masterPageRootItem);
520 				masterPageMap.insert(page, doc->MasterPages.at(mPage));
521 			}
522 
523 			QMap<PageItem*, errorCodes>::Iterator masterItemErrorsIt;
524 			for (masterItemErrorsIt = doc->masterItemErrors.begin();
525 				 masterItemErrorsIt != doc->masterItemErrors.end();
526 				 ++masterItemErrorsIt)
527 			{
528 				if (((masterItemErrorsIt.key()->OwnPage == mPage)
529 					|| (masterItemErrorsIt.key()->OnMasterPage == doc->MasterPages.at(mPage)->pageName()))
530 					&&
531 					((showNonPrintingLayerErrors) ||
532 					(!showNonPrintingLayerErrors && doc->layerPrintable(masterItemErrorsIt.key()->m_layerID)))
533 					)
534 				{
535 					if (!showPagesWithoutErrors && page==nullptr)
536 					{
537 						page = new QTreeWidgetItem( masterPageRootItem);
538 						masterPageMap.insert(page, doc->MasterPages.at(mPage));
539 					}
540 					hasError = true;
541 					QTreeWidgetItem * object = new QTreeWidgetItem( page);
542 					masterPageItemMap.insert(object, masterItemErrorsIt.key());
543 					object->setText(COLUMN_ITEM, masterItemErrorsIt.key()->itemName());
544 					errorCodes::Iterator it3;
545 					if (masterItemErrorsIt.value().count() == 1)
546 					{
547 						it3 = masterItemErrorsIt.value().begin();
548 						buildItem(object, it3.key(), masterItemErrorsIt.key());
549 						posMap.insert(object, it3.value());
550 					}
551 					else
552 					{
553 						for (it3 = masterItemErrorsIt.value().begin(); it3 != masterItemErrorsIt.value().end(); ++it3)
554 						{
555 							QTreeWidgetItem * errorText = new QTreeWidgetItem( object, 0 );
556 							buildItem(errorText, it3.key(), masterItemErrorsIt.key());
557 							masterPageItemMap.insert(errorText, masterItemErrorsIt.key());
558 							posMap.insert(object, it3.value());
559 						}
560 						object->setExpanded( true );
561 					}
562 					if (itemError)
563 						object->setIcon(COLUMN_ITEM, graveError );
564 					else
565 						object->setIcon(COLUMN_ITEM, onlyWarning );
566 				}
567 			}
568 			if (hasError)
569 			{
570 				++mpErrorCount;
571 				if (pageGraveError)
572 					page->setIcon(COLUMN_ITEM, graveError );
573 				else
574 					page->setIcon(COLUMN_ITEM, onlyWarning );
575 				page->setExpanded( true );
576 			}
577 			else
578 			{
579 				if (showPagesWithoutErrors && page!=nullptr)
580 					page->setIcon(COLUMN_ITEM, noErrors );
581 			}
582 			if (page!=nullptr)
583 				page->setText(COLUMN_ITEM, doc->MasterPages.at(mPage)->pageName());
584 		}
585 		masterPageRootItem->setExpanded(true);
586 		masterPageRootItem->setText(COLUMN_PROBLEM, tr("Issues: %1").arg(mpErrorCount));
587 		// END of MASTER PAGES
588 
589 		// PAGES ********************************8
590 		for (int aPage = 0; aPage < doc->DocPages.count(); ++aPage)
591 		{
592 			int pageErrorCount=0;
593 			QString tmp;
594 			hasError = false;
595 			pageGraveError = false;
596 			QTreeWidgetItem * page=nullptr;
597 			if (showPagesWithoutErrors)
598 			{
599 				page = new QTreeWidgetItem( reportDisplay);
600 				pageMap.insert(page, doc->DocPages.at(aPage));
601 			}
602 
603 			QMap<int, errorCodes>::Iterator pageErrorsIt;
604 			for (pageErrorsIt = doc->pageErrors.begin();
605 				 pageErrorsIt != doc->pageErrors.end();
606 				 ++pageErrorsIt)
607 			{
608 				if (pageErrorsIt.key() == aPage)
609 				{
610 					if (page==nullptr)
611 					{
612 						page = new QTreeWidgetItem( reportDisplay);
613 						pageMap.insert(page, doc->DocPages.at(aPage));
614 					}
615 					QTreeWidgetItem * errorText = new QTreeWidgetItem(page);
616 					errorText->setText(COLUMN_PROBLEM, warnMap[PV_APPLIED_MASTER_DIFF_SIDE].first);
617 					errorText->setToolTip(COLUMN_PROBLEM, warnMap[PV_APPLIED_MASTER_DIFF_SIDE].second);
618 					errorText->setIcon(COLUMN_ITEM, onlyWarning );
619 					pageMap.insert(errorText, doc->DocPages.at(aPage));
620 					hasError=true;
621 					page->setExpanded( true );
622 					++pageErrorCount;
623 				}
624 			}
625 
626 			QMap<PageItem*, errorCodes>::Iterator docItemErrorsIt;
627 			for (docItemErrorsIt = doc->docItemErrors.begin();
628 				 docItemErrorsIt != doc->docItemErrors.end();
629 				 ++docItemErrorsIt)
630 			{
631 				if (docItemErrorsIt.key()->OwnPage == aPage &&
632 					((showNonPrintingLayerErrors) ||
633 					(!showNonPrintingLayerErrors && doc->layerPrintable(docItemErrorsIt.key()->m_layerID)))
634 					)
635 				{
636 					if (!showPagesWithoutErrors && page==nullptr)
637 					{
638 						page = new QTreeWidgetItem( reportDisplay);
639 						pageMap.insert(page, doc->DocPages.at(aPage));
640 					}
641 					hasError = true;
642 					itemError = false;
643 					QTreeWidgetItem * object = new QTreeWidgetItem(page);
644 					object->setText(COLUMN_ITEM, docItemErrorsIt.key()->itemName());
645 					itemMap.insert(object, docItemErrorsIt.key());
646 					errorCodes::Iterator it3;
647 					if (docItemErrorsIt.value().count() == 1)
648 					{
649 						it3 = docItemErrorsIt.value().begin();
650 						buildItem(object, it3.key(), docItemErrorsIt.key());
651 						posMap.insert(object, it3.value());
652 						++pageErrorCount;
653 					}
654 					else
655 					{
656 						for (it3 = docItemErrorsIt.value().begin(); it3 != docItemErrorsIt.value().end(); ++it3)
657 						{
658 							QTreeWidgetItem * errorText = new QTreeWidgetItem( object);
659 							buildItem(errorText, it3.key(), docItemErrorsIt.key());
660 							itemMap.insert(errorText, docItemErrorsIt.key());
661 							posMap.insert(object, it3.value());
662 							++pageErrorCount;
663 						}
664 						object->setExpanded( true );
665 					}
666 					if (itemError)
667 						object->setIcon(COLUMN_ITEM, graveError );
668 					else
669 						object->setIcon(COLUMN_ITEM, onlyWarning );
670 				}
671 			}
672 			if (hasError)
673 			{
674 				if (pageGraveError)
675 					page->setIcon(COLUMN_ITEM, graveError );
676 				else
677 					page->setIcon(COLUMN_ITEM, onlyWarning );
678 				page->setExpanded( true );
679 				page->setText(COLUMN_PROBLEM, tr( "Issues: %1" ).arg(pageErrorCount) );
680 			}
681 			else
682 			{
683 				if (showPagesWithoutErrors && page!=nullptr)
684 					page->setIcon( 0, noErrors );
685 			}
686 			if (page!=nullptr)
687 				page->setText(COLUMN_ITEM, tr("Page ")+tmp.setNum(aPage+1));
688 		}
689 		// END of PAGES
690 
691 		// FREE ITEMS **************************************************
692 		QMap<PageItem*, errorCodes>::Iterator freeItemsErrorsIt;
693 		bool hasfreeItems = false;
694 		for (freeItemsErrorsIt = doc->docItemErrors.begin(); freeItemsErrorsIt != doc->docItemErrors.end(); ++freeItemsErrorsIt)
695 		{
696 			if (doc->OnPage(freeItemsErrorsIt.key()) == -1)
697 			{
698 				hasfreeItems = true;
699 				break;
700 			}
701 		}
702 		if (hasfreeItems)
703 		{
704 			bool hasError = false;
705 			bool pageGraveError = false;
706 			QTreeWidgetItem * freeItem = new QTreeWidgetItem( reportDisplay);
707 			for (freeItemsErrorsIt = doc->docItemErrors.begin(); freeItemsErrorsIt != doc->docItemErrors.end(); ++freeItemsErrorsIt)
708 			{
709 				if (doc->OnPage(freeItemsErrorsIt.key()) == -1)
710 				{
711 					hasError = true;
712 					QTreeWidgetItem * object = new QTreeWidgetItem(freeItem);
713 					object->setText(0, freeItemsErrorsIt.key()->itemName());
714 					itemMap.insert(object, freeItemsErrorsIt.key());
715 					errorCodes::Iterator it3;
716 					if (freeItemsErrorsIt.value().count() == 1)
717 					{
718 						it3 = freeItemsErrorsIt.value().begin();
719 						buildItem(object, it3.key(), freeItemsErrorsIt.key());
720 						posMap.insert(object, it3.value());
721 					}
722 					else
723 					{
724 						for (it3 = freeItemsErrorsIt.value().begin(); it3 != freeItemsErrorsIt.value().end(); ++it3)
725 						{
726 							QTreeWidgetItem * errorText = new QTreeWidgetItem( object);
727 							buildItem(errorText, it3.key(), freeItemsErrorsIt.key());
728 							itemMap.insert(errorText, freeItemsErrorsIt.key());
729 							posMap.insert(object, it3.value());
730 						}
731 						object->setExpanded( true );
732 					}
733 					if (pageGraveError)
734 						object->setIcon(COLUMN_ITEM, graveError );
735 					else
736 						object->setIcon(COLUMN_ITEM, onlyWarning );
737 				}
738 			}
739 			if (hasError)
740 			{
741 				if (pageGraveError)
742 					freeItem->setIcon(COLUMN_ITEM, graveError );
743 				else
744 					freeItem->setIcon(COLUMN_ITEM, onlyWarning );
745 				freeItem->setExpanded( true );
746 			}
747 			else
748 				freeItem->setIcon(COLUMN_ITEM, noErrors );
749 			freeItem->setText(COLUMN_ITEM, tr("Free Objects"));
750 		}
751 		// END of FREE ITEMS
752 
753 		ignoreErrors->setText( tr("&Ignore Errors"));
754 	}
755 
756 	reportDisplay->resizeColumnToContents(COLUMN_ITEM);
757 	reportDisplay->resizeColumnToContents(COLUMN_PROBLEM);
758 	reportDisplay->resizeColumnToContents(COLUMN_LAYER);
759 	connect(curCheckProfile, SIGNAL(activated(const QString&)), this, SLOT(newScan(const QString&)));
760 	connect(reportDisplay, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(slotSelect(QTreeWidgetItem*)));
761 }
762 
setIgnoreEnabled(bool state)763 void CheckDocument::setIgnoreEnabled(bool state)
764 {
765 	noButton = !state;
766 	ignoreErrors->setVisible(state);
767 }
768 
isIgnoreEnabled()769 bool CheckDocument::isIgnoreEnabled()
770 {
771 	return !noButton;
772 }
773