Changeset View
Changeset View
Standalone View
Standalone View
app/gvcore.cpp
Show All 19 Lines | |||||
20 | */ | 20 | */ | ||
21 | // Self | 21 | // Self | ||
22 | #include "gvcore.h" | 22 | #include "gvcore.h" | ||
23 | #include "dialogguard.h" | 23 | #include "dialogguard.h" | ||
24 | 24 | | |||
25 | // Qt | 25 | // Qt | ||
26 | #include <QApplication> | 26 | #include <QApplication> | ||
27 | #include <QUrl> | 27 | #include <QUrl> | ||
28 | #include <QHBoxLayout> | ||||
28 | #include <QImageWriter> | 29 | #include <QImageWriter> | ||
30 | #include <QLabel> | ||||
29 | #include <QMimeDatabase> | 31 | #include <QMimeDatabase> | ||
30 | #include <QDebug> | 32 | #include <QDebug> | ||
33 | #include <QSpacerItem> | ||||
34 | #include <QSpinBox> | ||||
31 | 35 | | |||
32 | // KDE | 36 | // KDE | ||
33 | #include <QFileDialog> | | |||
34 | #include <KColorScheme> | 37 | #include <KColorScheme> | ||
38 | #include <KFileCustomDialog> | ||||
39 | #include <KFileWidget> | ||||
35 | #include <KLocalizedString> | 40 | #include <KLocalizedString> | ||
36 | #include <KMessageBox> | 41 | #include <KMessageBox> | ||
37 | 42 | | |||
38 | // Local | 43 | // Local | ||
39 | #include <lib/binder.h> | 44 | #include <lib/binder.h> | ||
40 | #include <lib/document/documentfactory.h> | 45 | #include <lib/document/documentfactory.h> | ||
41 | #include <lib/document/documentjob.h> | 46 | #include <lib/document/documentjob.h> | ||
42 | #include <lib/document/savejob.h> | 47 | #include <lib/document/savejob.h> | ||
Show All 17 Lines | |||||
60 | { | 65 | { | ||
61 | GvCore* q; | 66 | GvCore* q; | ||
62 | MainWindow* mMainWindow; | 67 | MainWindow* mMainWindow; | ||
63 | SortedDirModel* mDirModel; | 68 | SortedDirModel* mDirModel; | ||
64 | HistoryModel* mRecentFoldersModel; | 69 | HistoryModel* mRecentFoldersModel; | ||
65 | RecentFilesModel* mRecentFilesModel; | 70 | RecentFilesModel* mRecentFilesModel; | ||
66 | QPalette mPalettes[4]; | 71 | QPalette mPalettes[4]; | ||
67 | QString mFullScreenPaletteName; | 72 | QString mFullScreenPaletteName; | ||
73 | const int configFileJPEGQualityValue = GwenviewConfig::jPEGQuality(); | ||||
68 | 74 | | |||
69 | bool showSaveAsDialog(const QUrl &url, QUrl* outUrl, QByteArray* format) | 75 | bool showSaveAsDialog(const QUrl &url, QUrl* outUrl, QByteArray* format) | ||
70 | { | 76 | { | ||
71 | DialogGuard<QFileDialog> dialog(mMainWindow); | 77 | // Build the JPEG quality chooser custom widget | ||
72 | dialog->setAcceptMode(QFileDialog::AcceptSave); | 78 | QWidget* JPEGQualityChooserWidget = new QWidget; | ||
79 | JPEGQualityChooserWidget->setVisible(false); // shown only for JPEGs | ||||
80 | | ||||
81 | QLabel* JPEGQualityChooserLabel = new QLabel; | ||||
82 | JPEGQualityChooserLabel->setText(i18n("JPEG quality:")); | ||||
83 | JPEGQualityChooserLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); | ||||
84 | | ||||
85 | QSpinBox* JPEGQualityChooserSpinBox = new QSpinBox; | ||||
86 | JPEGQualityChooserSpinBox->setMinimum(1); | ||||
87 | JPEGQualityChooserSpinBox->setMaximum(100); | ||||
88 | JPEGQualityChooserSpinBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); | ||||
89 | JPEGQualityChooserSpinBox->setSuffix(i18nc("Spinbox suffix; percentage 1 - 100", "%")); | ||||
90 | JPEGQualityChooserSpinBox->setValue(configFileJPEGQualityValue); | ||||
91 | | ||||
92 | // Temporarily change JPEG quality value | ||||
93 | QObject::connect(JPEGQualityChooserSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), | ||||
94 | JPEGQualityChooserSpinBox, [=](int value) { | ||||
95 | GwenviewConfig::setJPEGQuality(value); | ||||
96 | }); | ||||
97 | | ||||
98 | QSpacerItem* horizontalSpacer = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed); | ||||
99 | | ||||
100 | QHBoxLayout* JPEGQualityChooserLayout = new QHBoxLayout(JPEGQualityChooserWidget); | ||||
101 | JPEGQualityChooserLayout->setContentsMargins(0,0,0,0); | ||||
102 | JPEGQualityChooserLayout->addWidget(JPEGQualityChooserLabel); | ||||
103 | JPEGQualityChooserLayout->addWidget(JPEGQualityChooserSpinBox); | ||||
104 | JPEGQualityChooserLayout->addItem(horizontalSpacer); | ||||
105 | | ||||
106 | // Set up the dialog | ||||
107 | DialogGuard<KFileCustomDialog> dialog(mMainWindow); | ||||
108 | KFileWidget* fileWidget = dialog->fileWidget(); | ||||
109 | dialog->setCustomWidget(JPEGQualityChooserWidget); | ||||
110 | dialog->setOperationMode(KFileWidget::Saving); | ||||
73 | dialog->setWindowTitle(i18nc("@title:window", "Save Image")); | 111 | dialog->setWindowTitle(i18nc("@title:window", "Save Image")); | ||
74 | // Temporary workaround for selectUrl() not setting the | 112 | // Temporary workaround for selectUrl() not setting the | ||
75 | // initial directory to url (removed in D4193) | 113 | // initial directory to url (removed in D4193) | ||
76 | dialog->setDirectoryUrl(url.adjusted(QUrl::RemoveFilename)); | 114 | dialog->setUrl(url.adjusted(QUrl::RemoveFilename)); | ||
77 | dialog->selectUrl(url); | 115 | fileWidget->setSelectedUrl(url); | ||
78 | 116 | | |||
79 | QStringList supportedMimetypes; | 117 | QStringList supportedMimetypes; | ||
80 | for (const QByteArray &mimeName : QImageWriter::supportedMimeTypes()) { | 118 | for (const QByteArray &mimeName : QImageWriter::supportedMimeTypes()) { | ||
81 | supportedMimetypes.append(QString::fromLocal8Bit(mimeName)); | 119 | supportedMimetypes.append(QString::fromLocal8Bit(mimeName)); | ||
82 | } | 120 | } | ||
83 | 121 | | |||
84 | dialog->setMimeTypeFilters(supportedMimetypes); | 122 | fileWidget->setMimeFilter(supportedMimetypes, | ||
85 | dialog->selectMimeTypeFilter(MimeTypeUtils::urlMimeType(url)); | 123 | MimeTypeUtils::urlMimeType(url)); | ||
124 | | ||||
125 | // Only show the JPEG quality chooser when saving a JPEG image | ||||
126 | QObject::connect(fileWidget, &KFileWidget::filterChanged, | ||||
127 | JPEGQualityChooserWidget, [=](const QString &filter) { | ||||
128 | JPEGQualityChooserWidget->setVisible(filter.contains(QStringLiteral("jpeg"))); | ||||
129 | }); | ||||
86 | 130 | | |||
87 | // Show dialog | 131 | // Show dialog | ||
88 | do { | 132 | do { | ||
89 | if (!dialog->exec()) { | 133 | if (!dialog->exec()) { | ||
90 | return false; | 134 | return false; | ||
91 | } | 135 | } | ||
92 | 136 | | |||
93 | QList<QUrl> files = dialog->selectedUrls(); | 137 | QList<QUrl> files = fileWidget->selectedUrls(); | ||
94 | if (files.isEmpty()) { | 138 | if (files.isEmpty()) { | ||
95 | return false; | 139 | return false; | ||
96 | } | 140 | } | ||
97 | 141 | | |||
98 | QString filename = files.first().fileName(); | 142 | QString filename = files.first().fileName(); | ||
99 | 143 | | |||
100 | const QMimeType mimeType = QMimeDatabase().mimeTypeForFile(filename, QMimeDatabase::MatchExtension); | 144 | const QMimeType mimeType = QMimeDatabase().mimeTypeForFile(filename, QMimeDatabase::MatchExtension); | ||
101 | if (mimeType.isValid()) { | 145 | if (mimeType.isValid()) { | ||
102 | *format = mimeType.preferredSuffix().toLocal8Bit(); | 146 | *format = mimeType.preferredSuffix().toLocal8Bit(); | ||
103 | break; | 147 | break; | ||
104 | } | 148 | } | ||
105 | KMessageBox::sorry( | 149 | KMessageBox::sorry( | ||
106 | mMainWindow, | 150 | mMainWindow, | ||
107 | i18nc("@info", | 151 | i18nc("@info", | ||
108 | "Gwenview cannot save images as %1.", QFileInfo(filename).suffix()) | 152 | "Gwenview cannot save images as %1.", QFileInfo(filename).suffix()) | ||
109 | ); | 153 | ); | ||
110 | } while (true); | 154 | } while (true); | ||
111 | 155 | | |||
112 | *outUrl = dialog->selectedUrls().first(); | 156 | *outUrl = fileWidget->selectedUrls().first(); | ||
113 | return true; | 157 | return true; | ||
114 | } | 158 | } | ||
115 | 159 | | |||
116 | void setupPalettes() | 160 | void setupPalettes() | ||
117 | { | 161 | { | ||
118 | QPalette pal; | 162 | QPalette pal; | ||
119 | int value = GwenviewConfig::viewBackgroundValue(); | 163 | int value = GwenviewConfig::viewBackgroundValue(); | ||
120 | QColor fgColor = value > 128 ? Qt::black : Qt::white; | 164 | QColor fgColor = value > 128 ? Qt::black : Qt::white; | ||
▲ Show 20 Lines • Show All 235 Lines • ▼ Show 20 Line(s) | |||||
356 | void GvCore::saveAs(const QUrl &url) | 400 | void GvCore::saveAs(const QUrl &url) | ||
357 | { | 401 | { | ||
358 | QByteArray format; | 402 | QByteArray format; | ||
359 | QUrl saveAsUrl; | 403 | QUrl saveAsUrl; | ||
360 | if (!d->showSaveAsDialog(url, &saveAsUrl, &format)) { | 404 | if (!d->showSaveAsDialog(url, &saveAsUrl, &format)) { | ||
361 | return; | 405 | return; | ||
362 | } | 406 | } | ||
363 | 407 | | |||
408 | if (format == "jpg") { | ||||
409 | // Gwenview code assumes JPEG images have "jpeg" format, so if the | ||||
410 | // dialog returned the format "jpg", use "jpeg" instead | ||||
411 | // This does not affect the actual filename extension | ||||
412 | format = "jpeg"; | ||||
413 | } | ||||
414 | | ||||
364 | // Start save | 415 | // Start save | ||
365 | Document::Ptr doc = DocumentFactory::instance()->load(url); | 416 | Document::Ptr doc = DocumentFactory::instance()->load(url); | ||
366 | KJob* job = doc->save(saveAsUrl, format.data()); | 417 | KJob* job = doc->save(saveAsUrl, format); | ||
367 | if (!job) { | 418 | if (!job) { | ||
368 | const QString name = saveAsUrl.fileName().isEmpty() ? saveAsUrl.toDisplayString() : saveAsUrl.fileName(); | 419 | const QString name = saveAsUrl.fileName().isEmpty() ? saveAsUrl.toDisplayString() : saveAsUrl.fileName(); | ||
369 | const QString msg = xi18nc("@info", "<emphasis strong='true'>Saving <filename>%1</filename> failed:</emphasis><nl />%2", | 420 | const QString msg = xi18nc("@info", "<emphasis strong='true'>Saving <filename>%1</filename> failed:</emphasis><nl />%2", | ||
370 | name, doc->errorString()); | 421 | name, doc->errorString()); | ||
371 | KMessageBox::sorry(QApplication::activeWindow(), msg); | 422 | KMessageBox::sorry(QApplication::activeWindow(), msg); | ||
372 | } else { | 423 | } else { | ||
373 | connect(job, SIGNAL(result(KJob*)), SLOT(slotSaveResult(KJob*))); | 424 | connect(job, SIGNAL(result(KJob*)), SLOT(slotSaveResult(KJob*))); | ||
374 | } | 425 | } | ||
375 | } | 426 | } | ||
376 | 427 | | |||
377 | static void applyTransform(const QUrl &url, Orientation orientation) | 428 | static void applyTransform(const QUrl &url, Orientation orientation) | ||
378 | { | 429 | { | ||
379 | TransformImageOperation* op = new TransformImageOperation(orientation); | 430 | TransformImageOperation* op = new TransformImageOperation(orientation); | ||
380 | Document::Ptr doc = DocumentFactory::instance()->load(url); | 431 | Document::Ptr doc = DocumentFactory::instance()->load(url); | ||
381 | op->applyToDocument(doc); | 432 | op->applyToDocument(doc); | ||
382 | } | 433 | } | ||
383 | 434 | | |||
384 | void GvCore::slotSaveResult(KJob* _job) | 435 | void GvCore::slotSaveResult(KJob* _job) | ||
385 | { | 436 | { | ||
437 | // Regardless of job result, reset JPEG config value if it was changed by | ||||
438 | // the Save As dialog | ||||
439 | if (GwenviewConfig::jPEGQuality() != d->configFileJPEGQualityValue) { | ||||
440 | GwenviewConfig::setJPEGQuality(d->configFileJPEGQualityValue); | ||||
441 | } | ||||
442 | | ||||
386 | SaveJob* job = static_cast<SaveJob*>(_job); | 443 | SaveJob* job = static_cast<SaveJob*>(_job); | ||
387 | QUrl oldUrl = job->oldUrl(); | 444 | QUrl oldUrl = job->oldUrl(); | ||
388 | QUrl newUrl = job->newUrl(); | 445 | QUrl newUrl = job->newUrl(); | ||
389 | 446 | | |||
390 | if (job->error()) { | 447 | if (job->error()) { | ||
391 | QString name = newUrl.fileName().isEmpty() ? newUrl.toDisplayString() : newUrl.fileName(); | 448 | QString name = newUrl.fileName().isEmpty() ? newUrl.toDisplayString() : newUrl.fileName(); | ||
392 | const QString msg = xi18nc("@info", "<emphasis strong='true'>Saving <filename>%1</filename> failed:</emphasis><nl />%2", | 449 | const QString msg = xi18nc("@info", "<emphasis strong='true'>Saving <filename>%1</filename> failed:</emphasis><nl />%2", | ||
393 | name, kxi18n(qPrintable(job->errorString()))); | 450 | name, kxi18n(qPrintable(job->errorString()))); | ||
▲ Show 20 Lines • Show All 81 Lines • Show Last 20 Lines |