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 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15 #include "scconfig.h"
16 #include "pdfexportdialog.h"
17
18
19 #include <QByteArray>
20 #include <QCheckBox>
21 #include <QFileDialog>
22 #include <QGridLayout>
23 #include <QGroupBox>
24 #include <QHBoxLayout>
25 #include <QLineEdit>
26 #include <QListWidget>
27 #include <QMessageBox>
28 #include <QPushButton>
29 #include <QRadioButton>
30 #include <QSpacerItem>
31 #include <QToolButton>
32 #include <QToolTip>
33 #include <QVBoxLayout>
34
35 #include "commonstrings.h"
36 #include "iconmanager.h"
37 #include "pdfoptions.h"
38 #include "prefsfile.h"
39 #include "prefsmanager.h"
40 #include "scpaths.h"
41 #include "scribusdoc.h"
42 #include "scribusview.h"
43 #include "ui/customfdialog.h"
44 #include "ui/scmessagebox.h"
45 #include "ui/scrspinbox.h"
46 #include "units.h"
47 #include "util.h"
48
49
PDFExportDialog(QWidget * parent,const QString & docFileName,const QMap<QString,int> & DocFonts,ScribusView * currView,PDFOptions & pdfOptions,const ProfilesL & PDFXProfiles,const SCFonts & AllFonts,const ProfilesL & printerProfiles)50 PDFExportDialog::PDFExportDialog( QWidget* parent, const QString & docFileName,
51 const QMap<QString, int > & DocFonts,
52 ScribusView *currView, PDFOptions & pdfOptions,
53 const ProfilesL & PDFXProfiles, const SCFonts &AllFonts,
54 const ProfilesL & printerProfiles)
55 : QDialog( parent ),
56 m_doc(currView->m_doc),
57 m_opts(pdfOptions),
58 m_unitRatio(currView->m_doc->unitRatio()),
59 m_printerProfiles(printerProfiles)
60 {
61 setModal(true);
62 setWindowTitle( tr( "Save as PDF" ) );
63 setWindowIcon(IconManager::instance().loadIcon("AppIcon.png"));
64 PDFExportLayout = new QVBoxLayout( this );
65 PDFExportLayout->setSpacing(6);
66 PDFExportLayout->setContentsMargins(9, 9, 9, 9);
67 Name = new QGroupBox( this );
68 Name->setTitle( tr( "O&utput to File:" ) );
69 NameLayout = new QGridLayout( Name );
70 NameLayout->setSpacing(6);
71 NameLayout->setContentsMargins(9, 9, 9, 9);
72 NameLayout->setAlignment( Qt::AlignTop );
73 fileNameLineEdit = new QLineEdit( Name );
74 fileNameLineEdit->setMinimumSize( QSize( 268, 22 ) );
75 if (!m_opts.fileName.isEmpty())
76 fileNameLineEdit->setText( QDir::toNativeSeparators(m_opts.fileName) );
77 else
78 {
79 QFileInfo fi(docFileName);
80 QString completeBaseName = fi.completeBaseName();
81 if (completeBaseName.endsWith(".sla", Qt::CaseInsensitive))
82 if (completeBaseName.length() > 4) completeBaseName.chop(4);
83 if (completeBaseName.endsWith(".gz", Qt::CaseInsensitive))
84 if (completeBaseName.length() > 3) completeBaseName.chop(3);
85 if (fi.exists())
86 {
87 QString fileName(fi.path() + "/" + completeBaseName + ".pdf");
88 fileNameLineEdit->setText( QDir::toNativeSeparators(fileName) );
89 }
90 else
91 {
92 PrefsContext* dirs = PrefsManager::instance().prefsFile->getContext("dirs");
93 QString pdfdir = dirs->get("pdf", fi.path());
94 if (pdfdir.right(1) != "/")
95 pdfdir += "/";
96 QString fileName(pdfdir + completeBaseName + ".pdf");
97 fileNameLineEdit->setText( QDir::toNativeSeparators(fileName) );
98 }
99 }
100 NameLayout->addWidget( fileNameLineEdit, 0, 0 );
101 changeButton = new QPushButton( Name );
102 changeButton->setText( tr( "Cha&nge..." ) );
103 changeButton->setMinimumSize( QSize( 88, 24 ) );
104 NameLayout->addWidget( changeButton, 0, 1 );
105 multiFile = new QCheckBox( tr( "Output one file for eac&h page" ), Name );
106 multiFile->setChecked(m_opts.doMultiFile);
107 NameLayout->addWidget( multiFile, 1, 0 );
108 openAfterExportCheckBox = new QCheckBox( tr( "Open PDF after Export" ), Name );
109 openAfterExportCheckBox->setChecked(m_opts.openAfterExport);
110 NameLayout->addWidget( openAfterExportCheckBox, 2, 0 );
111 PDFExportLayout->addWidget( Name );
112
113 Options = new TabPDFOptions( this, pdfOptions, AllFonts, PDFXProfiles, DocFonts, currView->m_doc );
114 PDFExportLayout->addWidget( Options );
115 Layout7 = new QHBoxLayout;
116 Layout7->setSpacing(6);
117 Layout7->setContentsMargins(0, 0, 0, 0);
118 QSpacerItem* spacer_2 = new QSpacerItem( 2, 2, QSizePolicy::Expanding, QSizePolicy::Minimum );
119 Layout7->addItem( spacer_2 );
120 okButton = new QPushButton( tr( "&Save" ), this );
121 okButton->setAutoDefault( true );
122 okButton->setDefault( true );
123 Layout7->addWidget( okButton );
124 cancelButton = new QPushButton( CommonStrings::tr_Cancel, this );
125 Layout7->addWidget( cancelButton );
126 PDFExportLayout->addLayout( Layout7 );
127 if ((m_opts.Version == PDFVersion::PDF_X3) && (Options->InfoString->text().isEmpty()))
128 okButton->setEnabled(false);
129 resize(sizeHint());
130 // setMaximumSize( sizeHint() );
131 //tooltips
132 multiFile->setToolTip( "<qt>" + tr( "This enables exporting one individually named PDF file for each page in the document. Page numbers are added automatically. This is most useful for imposing PDF for commercial printing.") + "</qt>" );
133 openAfterExportCheckBox->setToolTip( "<qt>" + tr( "Open the exported PDF with the PDF viewer as set in External Tools preferences, when not exporting to a multi-file export destination") + "</qt>" );
134 okButton->setToolTip( "<qt>" + tr( "The save button will be disabled if you are trying to export PDF/X and the info string is missing from the PDF/X tab") + "</qt>" );
135 // signals and slots connections
136 connect( changeButton, SIGNAL( clicked() ), this, SLOT( ChangeFile() ) );
137 connect( okButton, SIGNAL( clicked() ), this, SLOT( DoExport() ) );
138 connect( cancelButton, SIGNAL( clicked() ), this, SLOT( reject() ) );
139 connect( fileNameLineEdit, SIGNAL( editingFinished() ), this, SLOT( fileNameChanged() ) );
140 connect( Options, SIGNAL(noInfo()), this, SLOT(disableSave()));
141 connect( Options, SIGNAL(hasInfo()), this, SLOT(enableSave()));
142 }
143
enableSave()144 void PDFExportDialog::enableSave()
145 {
146 okButton->setEnabled(true);
147 }
148
disableSave()149 void PDFExportDialog::disableSave()
150 {
151 okButton->setEnabled(false);
152 }
153
DoExport()154 void PDFExportDialog::DoExport()
155 {
156 // Check the page ranges
157 bool hasInvalidPageRange = false;
158 QString pageString(this->getPagesString());
159 std::vector<int> pageNumbers;
160
161 parsePagesString(pageString, &pageNumbers, m_doc->DocPages.count());
162 for (size_t i = 0; i < pageNumbers.size(); ++i)
163 {
164 int pageNumber = pageNumbers[i];
165 if (pageNumber < 1 || pageNumber > m_doc->DocPages.count())
166 {
167 hasInvalidPageRange = true;
168 break;
169 }
170 }
171
172 if ((pageNumbers.empty()) || hasInvalidPageRange)
173 {
174 ScMessageBox::warning(this, CommonStrings::trWarning, tr("The range of pages to export is invalid.\nPlease check it and try again."));
175 return;
176 }
177
178 // Checking if the path exists
179 bool createPath = false;
180 QString fn = QDir::fromNativeSeparators(fileNameLineEdit->text());
181 QFileInfo fi(fn);
182 QString dirPath = QDir::toNativeSeparators(fi.absolutePath());
183 if (!QFile::exists(fi.absolutePath()))
184 {
185 if (ScMessageBox::question(this, tr( "Save as PDF" ),
186 tr("%1 does not exists and will be created, continue?").arg(dirPath),
187 QMessageBox::Ok | QMessageBox::Cancel,
188 QMessageBox::NoButton, // GUI default
189 QMessageBox::Ok) // batch default
190 == QMessageBox::Cancel)
191 {
192 return;
193 }
194 createPath = true;
195 }
196
197 // NOTE: Qt4 contains QDir::mkpath()
198 QDir d(fn);
199 if (createPath)
200 {
201 if (!d.mkpath(fi.absolutePath()))
202 {
203 ScMessageBox::warning(this,
204 CommonStrings::trWarning,
205 tr("Cannot create directory: \n%1").arg(dirPath));
206 return;
207 }
208 }
209
210 bool doIt = false;
211 if (multiFile->isChecked())
212 doIt = true;
213 else
214 doIt = overwrite(this, fn);
215 if (!doIt) return;
216
217 int pageIndex = (Options->Pages->currentRow() >= 0) ? Options->Pages->currentRow() : 0;
218 m_presEffects = Options->EffVal;
219 m_presEffects[pageIndex].pageViewDuration = Options->PageTime->value();
220 m_presEffects[pageIndex].pageEffectDuration = Options->EffectTime->value();
221 m_presEffects[pageIndex].effectType = Options->EffectType->currentIndex();
222 m_presEffects[pageIndex].Dm = Options->EDirection->currentIndex();
223 m_presEffects[pageIndex].M = Options->EDirection_2->currentIndex();
224 m_presEffects[pageIndex].Di = Options->EDirection_2_2->currentIndex();
225 m_opts.LPISettings[Options->SelLPIcolor].Frequency = Options->LPIfreq->value();
226 m_opts.LPISettings[Options->SelLPIcolor].Angle = Options->LPIangle->value();
227 m_opts.LPISettings[Options->SelLPIcolor].SpotFunc = Options->LPIfunc->currentIndex();
228 accept();
229 }
230
ChangeFile()231 void PDFExportDialog::ChangeFile()
232 {
233 PrefsContext* dirs = PrefsManager::instance().prefsFile->getContext("dirs");
234 QString wdir = dirs->get("pdf", ScPaths::userDocumentDir());
235
236 QString wfile = QDir::fromNativeSeparators(fileNameLineEdit->text());
237 if (!wfile.isEmpty())
238 {
239 QFileInfo fInfo(wfile);
240 QString absPath = fInfo.absolutePath(); // Yes, we mean the file directory here
241 if (QDir(absPath).exists())
242 wdir = wfile;
243 }
244
245 QString d = QFileDialog::getSaveFileName(this, tr("Save As"), wdir, tr("PDF Files (*.pdf);;All Files (*)"), nullptr, QFileDialog::DontConfirmOverwrite);
246 if (d.length() > 0)
247 {
248 QString fn(QDir::fromNativeSeparators(d));
249 dirs->set("pdf", fn.left(fn.lastIndexOf("/")));
250 fileNameLineEdit->setText(QDir::toNativeSeparators(d));
251 }
252 }
253
fileNameChanged()254 void PDFExportDialog::fileNameChanged()
255 {
256 QString fileName = checkFileExtension(fileNameLineEdit->text(),"pdf");
257 fileNameLineEdit->setText( QDir::toNativeSeparators(fileName) );
258 }
259
updateDocOptions()260 void PDFExportDialog::updateDocOptions()
261 {
262 m_opts.fileName = QDir::fromNativeSeparators(fileNameLineEdit->text());
263 m_opts.doMultiFile = multiFile->isChecked();
264 m_opts.openAfterExport = openAfterExportCheckBox->isChecked();
265 m_opts.Thumbnails = Options->CheckBox1->isChecked();
266 m_opts.Compress = Options->Compression->isChecked();
267 m_opts.CompressMethod = (PDFOptions::PDFCompression) Options->CMethod->currentIndex();
268 m_opts.Quality = Options->CQuality->currentIndex();
269 m_opts.Resolution = Options->Resolution->value();
270 m_opts.FontEmbedding = Options->fontEmbeddingMode();
271 m_opts.EmbedList = Options->fontsToEmbed();
272 m_opts.SubsetList = Options->fontsToSubset();
273 m_opts.OutlineList = Options->fontsToOutline();
274 m_opts.RecalcPic = Options->DSColor->isChecked();
275 m_opts.PicRes = Options->ValC->value();
276 m_opts.embedPDF = Options->EmbedPDF->isChecked();
277 m_opts.Bookmarks = Options->CheckBM->isChecked();
278 m_opts.Binding = Options->ComboBind->currentIndex();
279 m_opts.MirrorH = Options->MirrorH->isChecked();
280 m_opts.MirrorV = Options->MirrorV->isChecked();
281 m_opts.doClip = Options->ClipMarg->isChecked();
282 m_opts.RotateDeg = Options->RotateDeg->currentIndex() * 90;
283 m_opts.pageRangeSelection = Options->AllPages->isChecked() ? 0 : 1;
284 m_opts.pageRangeString = Options->PageNr->text();
285 m_opts.PresentMode = Options->CheckBox10->isChecked();
286 if (m_opts.PresentMode)
287 {
288 for (int pg = 0; pg < m_doc->Pages->count(); ++pg)
289 {
290 m_doc->Pages->at(pg)->PresentVals = m_presEffects[pg];
291 }
292 }
293 m_opts.Articles = Options->Article->isChecked();
294 m_opts.Encrypt = Options->Encry->isChecked();
295 m_opts.UseLPI = Options->UseLPI->isChecked();
296 m_opts.useLayers = Options->useLayers->isChecked();
297 m_opts.UseSpotColors = !Options->useSpot->isChecked();
298 m_opts.displayBookmarks = Options->useBookmarks->isChecked();
299 m_opts.displayFullscreen = Options->useFullScreen->isChecked();
300 m_opts.displayLayers = Options->useLayers2->isChecked();
301 m_opts.displayThumbs = Options->useThumbnails->isChecked();
302 m_opts.hideMenuBar = Options->hideMenuBar->isChecked();
303 m_opts.hideToolBar = Options->hideToolBar->isChecked();
304 m_opts.fitWindow = Options->fitWindow->isChecked();
305 m_opts.useDocBleeds = Options->docBleeds->isChecked();
306 if (!Options->docBleeds->isChecked())
307 {
308 m_opts.bleeds.setTop(Options->BleedTop->value() / m_unitRatio);
309 m_opts.bleeds.setLeft(Options->BleedLeft->value() / m_unitRatio);
310 m_opts.bleeds.setRight(Options->BleedRight->value() / m_unitRatio);
311 m_opts.bleeds.setBottom(Options->BleedBottom->value()/ m_unitRatio);
312 }
313 m_opts.markLength = Options->markLength->value() / m_unitRatio;
314 m_opts.markOffset = Options->markOffset->value() / m_unitRatio;
315 m_opts.cropMarks = Options->cropMarks->isChecked();
316 m_opts.bleedMarks = Options->bleedMarks->isChecked();
317 m_opts.registrationMarks = Options->registrationMarks->isChecked();
318 m_opts.colorMarks = Options->colorMarks->isChecked();
319 m_opts.docInfoMarks = Options->docInfoMarks->isChecked();
320 int pgl = PDFOptions::SinglePage;
321 if (Options->singlePage->isChecked())
322 pgl = PDFOptions::SinglePage;
323 else if (Options->continuousPages->isChecked())
324 pgl = PDFOptions::OneColumn;
325 else if (Options->facingPagesLeft->isChecked())
326 pgl = PDFOptions::TwoColumnLeft;
327 else if (Options->facingPagesRight->isChecked())
328 pgl = PDFOptions::TwoColumnRight;
329 m_opts.PageLayout = pgl;
330 if (Options->actionCombo->currentIndex() != 0)
331 m_opts.openAction = Options->actionCombo->currentText();
332 else
333 m_opts.openAction = "";
334 if (Options->Encry->isChecked())
335 {
336 int Perm = -64;
337 if (Options->PDFVersionCombo->version() == PDFVersion::PDF_14)
338 Perm &= ~0x00240000;
339 if (Options->PrintSec->isChecked())
340 Perm += 4;
341 if (Options->ModifySec->isChecked())
342 Perm += 8;
343 if (Options->CopySec->isChecked())
344 Perm += 16;
345 if (Options->AddSec->isChecked())
346 Perm += 32;
347 m_opts.Permissions = Perm;
348 m_opts.PassOwner = Options->PassOwner->text();
349 m_opts.PassUser = Options->PassUser->text();
350 }
351 m_opts.Version = Options->PDFVersionCombo->version();
352 if (Options->OutCombo->currentIndex() == 0)
353 {
354 m_opts.UseRGB = true;
355 m_opts.isGrayscale = false;
356 m_opts.UseProfiles = false;
357 m_opts.UseProfiles2 = false;
358 }
359 else
360 {
361 if (Options->OutCombo->currentIndex() == 2)
362 {
363 m_opts.isGrayscale = true;
364 m_opts.UseRGB = false;
365 m_opts.UseProfiles = false;
366 m_opts.UseProfiles2 = false;
367 }
368 else
369 {
370 m_opts.isGrayscale = false;
371 m_opts.UseRGB = false;
372 if (m_doc->HasCMS)
373 {
374 m_opts.UseProfiles = Options->EmbedProfs->isChecked();
375 m_opts.UseProfiles2 = Options->EmbedProfs2->isChecked();
376 if (m_opts.Version != PDFVersion::PDF_X1a)
377 {
378 m_opts.Intent = Options->IntendS->currentIndex();
379 m_opts.Intent2 = Options->IntendI->currentIndex();
380 m_opts.EmbeddedI = Options->NoEmbedded->isChecked();
381 m_opts.SolidProf = Options->SolidPr->currentText();
382 m_opts.ImageProf = Options->ImageP->currentText();
383 }
384 m_opts.PrintProf = Options->PrintProfC->currentText();
385 if ((m_opts.Version == PDFVersion::PDF_X3) || (m_opts.Version == PDFVersion::PDF_X1a) || (m_opts.Version == PDFVersion::PDF_X4))
386 {
387 m_opts.Info = Options->InfoString->text();
388 m_opts.Encrypt = false;
389 m_opts.MirrorH = false;
390 m_opts.MirrorV = false;
391 //#8306 : PDF/X-3 export ignores rotation setting
392 //m_opts.RotateDeg = 0;
393 m_opts.PresentMode = false;
394 }
395 }
396 else
397 {
398 m_opts.UseProfiles = false;
399 m_opts.UseProfiles2 = false;
400 }
401 }
402 }
403 }
404
getPagesString()405 QString PDFExportDialog::getPagesString()
406 {
407 if (Options->AllPages->isChecked())
408 return "*";
409 return Options->PageNr->text();
410 }
411