diff --git a/app/gvcore.cpp b/app/gvcore.cpp index eedb1e3e..64ab72c2 100644 --- a/app/gvcore.cpp +++ b/app/gvcore.cpp @@ -1,489 +1,470 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "gvcore.h" #include "dialogguard.h" // Qt #include #include #include #include // KDE #include #include -#include -#include #include #include // Local #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Gwenview { struct GvCorePrivate { GvCore* q; MainWindow* mMainWindow; SortedDirModel* mDirModel; HistoryModel* mRecentFoldersModel; RecentFilesModel* mRecentFilesModel; QPalette mPalettes[4]; QString mFullScreenPaletteName; bool showSaveAsDialog(const QUrl &url, QUrl* outUrl, QByteArray* format) { DialogGuard dialog(mMainWindow); dialog->setAcceptMode(QFileDialog::AcceptSave); dialog->setWindowTitle(i18nc("@title:window", "Save Image")); dialog->selectUrl(url); QStringList supportedMimetypes; for (const QByteArray &mimeName : QImageWriter::supportedMimeTypes()) { supportedMimetypes.append(QString::fromLocal8Bit(mimeName)); } dialog->setMimeTypeFilters(supportedMimetypes); dialog->selectMimeTypeFilter(MimeTypeUtils::urlMimeType(url)); // Show dialog do { if (!dialog->exec()) { return false; } QList files = dialog->selectedUrls(); if (files.isEmpty()) { return false; } QString filename = files.first().fileName(); const QMimeType mimeType = QMimeDatabase().mimeTypeForFile(filename, QMimeDatabase::MatchExtension); if (mimeType.isValid()) { *format = mimeType.preferredSuffix().toLocal8Bit(); break; } KMessageBox::sorry( mMainWindow, i18nc("@info", "Gwenview cannot save images as %1.", QFileInfo(filename).suffix()) ); } while (true); *outUrl = dialog->selectedUrls().first(); return true; } void setupPalettes() { QPalette pal; int value = GwenviewConfig::viewBackgroundValue(); QColor fgColor = value > 128 ? Qt::black : Qt::white; // Normal KSharedConfigPtr config = KSharedConfig::openConfig(); mPalettes[GvCore::NormalPalette] = KColorScheme::createApplicationPalette(config); pal = mPalettes[GvCore::NormalPalette]; pal.setColor(QPalette::Base, QColor::fromHsv(0, 0, value)); pal.setColor(QPalette::Text, fgColor); mPalettes[GvCore::NormalViewPalette] = pal; // Fullscreen QString name = GwenviewConfig::fullScreenColorScheme(); if (name.isEmpty()) { // Default color scheme mFullScreenPaletteName = QStandardPaths::locate(QStandardPaths::AppDataLocation, "color-schemes/fullscreen.colors"); config = KSharedConfig::openConfig(mFullScreenPaletteName); } else if (name.contains('/')) { // Full path to a .colors file mFullScreenPaletteName = name; config = KSharedConfig::openConfig(mFullScreenPaletteName); } else { // Standard KDE color scheme mFullScreenPaletteName = QString("color-schemes/%1.colors").arg(name); config = KSharedConfig::openConfig(mFullScreenPaletteName, KConfig::FullConfig, QStandardPaths::AppDataLocation); } mPalettes[GvCore::FullScreenPalette] = KColorScheme::createApplicationPalette(config); // If we are using the default palette, adjust it to match the system color scheme if (name.isEmpty()) { adjustDefaultFullScreenPalette(); } // FullScreenView has textured background pal = mPalettes[GvCore::FullScreenPalette]; QString path = QStandardPaths::locate(QStandardPaths::AppDataLocation, "images/background.png"); QPixmap bgTexture(path); pal.setBrush(QPalette::Base, bgTexture); mPalettes[GvCore::FullScreenViewPalette] = pal; } void adjustDefaultFullScreenPalette() { // The Fullscreen palette by default does not use the system color scheme, and therefore uses an 'accent' color // of blue. So for every color group/role combination that uses the accent color, we use a muted version of the // Normal palette. We also use the normal HighlightedText color so it properly contrasts with Highlight. const QPalette normalPal = mPalettes[GvCore::NormalPalette]; QPalette fullscreenPal = mPalettes[GvCore::FullScreenPalette]; // Colors from the normal palette (source of the system theme's accent color) const QColor normalToolTipBase = normalPal.color(QPalette::Normal, QPalette::ToolTipBase); const QColor normalToolTipText = normalPal.color(QPalette::Normal, QPalette::ToolTipText); const QColor normalHighlight = normalPal.color(QPalette::Normal, QPalette::Highlight); const QColor normalHighlightedText = normalPal.color(QPalette::Normal, QPalette::HighlightedText); const QColor normalLink = normalPal.color(QPalette::Normal, QPalette::Link); const QColor normalActiveToolTipBase = normalPal.color(QPalette::Active, QPalette::ToolTipBase); const QColor normalActiveToolTipText = normalPal.color(QPalette::Active, QPalette::ToolTipText); const QColor normalActiveHighlight = normalPal.color(QPalette::Active, QPalette::Highlight); const QColor normalActiveHighlightedText = normalPal.color(QPalette::Active, QPalette::HighlightedText); const QColor normalActiveLink = normalPal.color(QPalette::Active, QPalette::Link); const QColor normalDisabledToolTipBase = normalPal.color(QPalette::Disabled, QPalette::ToolTipBase); const QColor normalDisabledToolTipText = normalPal.color(QPalette::Disabled, QPalette::ToolTipText); // Note: Disabled Highlight missing as they do not use the accent color const QColor normalDisabledLink = normalPal.color(QPalette::Disabled, QPalette::Link); const QColor normalInactiveToolTipBase = normalPal.color(QPalette::Inactive, QPalette::ToolTipBase); const QColor normalInactiveToolTipText = normalPal.color(QPalette::Inactive, QPalette::ToolTipText); const QColor normalInactiveHighlight = normalPal.color(QPalette::Inactive, QPalette::Highlight); const QColor normalInactiveHighlightedText = normalPal.color(QPalette::Inactive, QPalette::HighlightedText); const QColor normalInactiveLink = normalPal.color(QPalette::Inactive, QPalette::Link); // Colors of the fullscreen palette which we will be modifying QColor fullScreenToolTipBase = fullscreenPal.color(QPalette::Normal, QPalette::ToolTipBase); QColor fullScreenToolTipText = fullscreenPal.color(QPalette::Normal, QPalette::ToolTipText); QColor fullScreenHighlight = fullscreenPal.color(QPalette::Normal, QPalette::Highlight); QColor fullScreenLink = fullscreenPal.color(QPalette::Normal, QPalette::Link); QColor fullScreenActiveToolTipBase = fullscreenPal.color(QPalette::Active, QPalette::ToolTipBase); QColor fullScreenActiveToolTipText = fullscreenPal.color(QPalette::Active, QPalette::ToolTipText); QColor fullScreenActiveHighlight = fullscreenPal.color(QPalette::Active, QPalette::Highlight); QColor fullScreenActiveLink = fullscreenPal.color(QPalette::Active, QPalette::Link); QColor fullScreenDisabledToolTipBase = fullscreenPal.color(QPalette::Disabled, QPalette::ToolTipBase); QColor fullScreenDisabledToolTipText = fullscreenPal.color(QPalette::Disabled, QPalette::ToolTipText); QColor fullScreenDisabledLink = fullscreenPal.color(QPalette::Disabled, QPalette::Link); QColor fullScreenInactiveToolTipBase = fullscreenPal.color(QPalette::Inactive, QPalette::ToolTipBase); QColor fullScreenInactiveToolTipText = fullscreenPal.color(QPalette::Inactive, QPalette::ToolTipText); QColor fullScreenInactiveHighlight = fullscreenPal.color(QPalette::Inactive, QPalette::Highlight); QColor fullScreenInactiveLink = fullscreenPal.color(QPalette::Inactive, QPalette::Link); // Adjust the value of the normal color so it's not too dark/bright, and apply to the respective fullscreen color fullScreenToolTipBase .setHsv(normalToolTipBase.hue(), normalToolTipBase.saturation(), (127 + 2 * normalToolTipBase.value()) / 3); fullScreenToolTipText .setHsv(normalToolTipText.hue(), normalToolTipText.saturation(), (127 + 2 * normalToolTipText.value()) / 3); fullScreenHighlight .setHsv(normalHighlight.hue(), normalHighlight.saturation(), (127 + 2 * normalHighlight.value()) / 3); fullScreenLink .setHsv(normalLink.hue(), normalLink.saturation(), (127 + 2 * normalLink.value()) / 3); fullScreenActiveToolTipBase .setHsv(normalActiveToolTipBase.hue(), normalActiveToolTipBase.saturation(), (127 + 2 * normalActiveToolTipBase.value()) / 3); fullScreenActiveToolTipText .setHsv(normalActiveToolTipText.hue(), normalActiveToolTipText.saturation(), (127 + 2 * normalActiveToolTipText.value()) / 3); fullScreenActiveHighlight .setHsv(normalActiveHighlight.hue(), normalActiveHighlight.saturation(), (127 + 2 * normalActiveHighlight.value()) / 3); fullScreenActiveLink .setHsv(normalActiveLink.hue(), normalActiveLink.saturation(), (127 + 2 * normalActiveLink.value()) / 3); fullScreenDisabledToolTipBase.setHsv(normalDisabledToolTipBase.hue(), normalDisabledToolTipBase.saturation(), (127 + 2 * normalDisabledToolTipBase.value()) / 3); fullScreenDisabledToolTipText.setHsv(normalDisabledToolTipText.hue(), normalDisabledToolTipText.saturation(), (127 + 2 * normalDisabledToolTipText.value()) / 3); fullScreenDisabledLink .setHsv(normalDisabledLink.hue(), normalDisabledLink.saturation(), (127 + 2 * normalDisabledLink.value()) / 3); fullScreenInactiveToolTipBase.setHsv(normalInactiveToolTipBase.hue(), normalInactiveToolTipBase.saturation(), (127 + 2 * normalInactiveToolTipBase.value()) / 3); fullScreenInactiveToolTipText.setHsv(normalInactiveToolTipText.hue(), normalInactiveToolTipText.saturation(), (127 + 2 * normalInactiveToolTipText.value()) / 3); fullScreenInactiveHighlight .setHsv(normalInactiveHighlight.hue(), normalInactiveHighlight.saturation(), (127 + 2 * normalInactiveHighlight.value()) / 3); fullScreenInactiveLink .setHsv(normalInactiveLink.hue(), normalInactiveLink.saturation(), (127 + 2 * normalInactiveLink.value()) / 3); // Apply the modified colors to the fullscreen palette fullscreenPal.setColor(QPalette::Normal, QPalette::ToolTipBase, fullScreenToolTipBase); fullscreenPal.setColor(QPalette::Normal, QPalette::ToolTipText, fullScreenToolTipText); fullscreenPal.setColor(QPalette::Normal, QPalette::Highlight, fullScreenHighlight); fullscreenPal.setColor(QPalette::Normal, QPalette::Link, fullScreenLink); fullscreenPal.setColor(QPalette::Active, QPalette::ToolTipBase, fullScreenActiveToolTipBase); fullscreenPal.setColor(QPalette::Active, QPalette::ToolTipText, fullScreenActiveToolTipText); fullscreenPal.setColor(QPalette::Active, QPalette::Highlight, fullScreenActiveHighlight); fullscreenPal.setColor(QPalette::Active, QPalette::Link, fullScreenActiveLink); fullscreenPal.setColor(QPalette::Disabled, QPalette::ToolTipBase, fullScreenDisabledToolTipBase); fullscreenPal.setColor(QPalette::Disabled, QPalette::ToolTipText, fullScreenDisabledToolTipText); fullscreenPal.setColor(QPalette::Disabled, QPalette::Link, fullScreenDisabledLink); fullscreenPal.setColor(QPalette::Inactive, QPalette::ToolTipBase, fullScreenInactiveToolTipBase); fullscreenPal.setColor(QPalette::Inactive, QPalette::ToolTipText, fullScreenInactiveToolTipText); fullscreenPal.setColor(QPalette::Inactive, QPalette::Highlight, fullScreenInactiveHighlight); fullscreenPal.setColor(QPalette::Inactive, QPalette::Link, fullScreenInactiveLink); // Since we use an adjusted version of the normal highlight color, we need to use the normal version of the // text color so it contrasts fullscreenPal.setColor(QPalette::Normal, QPalette::HighlightedText, normalHighlightedText); fullscreenPal.setColor(QPalette::Active, QPalette::HighlightedText, normalActiveHighlightedText); fullscreenPal.setColor(QPalette::Inactive, QPalette::HighlightedText, normalInactiveHighlightedText); mPalettes[GvCore::FullScreenPalette] = fullscreenPal; } }; GvCore::GvCore(MainWindow* mainWindow, SortedDirModel* dirModel) : QObject(mainWindow) , d(new GvCorePrivate) { d->q = this; d->mMainWindow = mainWindow; d->mDirModel = dirModel; d->mRecentFoldersModel = 0; d->mRecentFilesModel = 0; d->setupPalettes(); connect(GwenviewConfig::self(), SIGNAL(configChanged()), SLOT(slotConfigChanged())); } GvCore::~GvCore() { delete d; } QAbstractItemModel* GvCore::recentFoldersModel() const { if (!d->mRecentFoldersModel) { d->mRecentFoldersModel = new HistoryModel(const_cast(this), QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/recentfolders/"); } return d->mRecentFoldersModel; } QAbstractItemModel* GvCore::recentFilesModel() const { if (!d->mRecentFilesModel) { d->mRecentFilesModel = new RecentFilesModel(const_cast(this)); } return d->mRecentFilesModel; } AbstractSemanticInfoBackEnd* GvCore::semanticInfoBackEnd() const { return d->mDirModel->semanticInfoBackEnd(); } SortedDirModel* GvCore::sortedDirModel() const { return d->mDirModel; } void GvCore::addUrlToRecentFolders(QUrl url) { if (!GwenviewConfig::historyEnabled()) { return; } if (!url.isValid()) { return; } // For "sftp://localhost", "/" is a different path than "" (bug #312060) if (!url.path().isEmpty() && !url.path().endsWith('/')) { url.setPath(url.path() + '/'); } recentFoldersModel(); d->mRecentFoldersModel->addUrl(url); } void GvCore::addUrlToRecentFiles(const QUrl &url) { if (!GwenviewConfig::historyEnabled()) { return; } recentFilesModel(); d->mRecentFilesModel->addUrl(url); } void GvCore::saveAll() { SaveAllHelper helper(d->mMainWindow); helper.save(); } void GvCore::save(const QUrl &url) { Document::Ptr doc = DocumentFactory::instance()->load(url); QByteArray format = doc->format(); const QByteArrayList availableTypes = QImageWriter::supportedImageFormats(); if (availableTypes.contains(format)) { DocumentJob* job = doc->save(url, format); connect(job, SIGNAL(result(KJob*)), SLOT(slotSaveResult(KJob*))); } else { // We don't know how to save in 'format', ask the user for a format we can // write to. KGuiItem saveUsingAnotherFormat = KStandardGuiItem::saveAs(); saveUsingAnotherFormat.setText(i18n("Save using another format")); int result = KMessageBox::warningContinueCancel( d->mMainWindow, i18n("Gwenview cannot save images in '%1' format.", QString(format)), QString() /* caption */, saveUsingAnotherFormat ); if (result == KMessageBox::Continue) { saveAs(url); } } } void GvCore::saveAs(const QUrl &url) { QByteArray format; QUrl saveAsUrl; if (!d->showSaveAsDialog(url, &saveAsUrl, &format)) { return; } - // Check for overwrite - KIO::StatJob *statJob = KIO::stat(saveAsUrl, KIO::StatJob::DestinationSide, 0); - KJobWidgets::setWindow(statJob, d->mMainWindow); - if (statJob->exec()) { - int answer = KMessageBox::warningContinueCancel( - d->mMainWindow, - xi18nc("@info", - "A file named %1 already exists.\n" - "Are you sure you want to overwrite it?", - saveAsUrl.fileName()), - QString(), - KStandardGuiItem::overwrite()); - if (answer == KMessageBox::Cancel) { - return; - } - } - // Start save Document::Ptr doc = DocumentFactory::instance()->load(url); KJob* job = doc->save(saveAsUrl, format.data()); if (!job) { const QString name = saveAsUrl.fileName().isEmpty() ? saveAsUrl.toDisplayString() : saveAsUrl.fileName(); const QString msg = xi18nc("@info", "Saving %1 failed:
%2", name, doc->errorString()); KMessageBox::sorry(QApplication::activeWindow(), msg); } else { connect(job, SIGNAL(result(KJob*)), SLOT(slotSaveResult(KJob*))); } } static void applyTransform(const QUrl &url, Orientation orientation) { TransformImageOperation* op = new TransformImageOperation(orientation); Document::Ptr doc = DocumentFactory::instance()->load(url); op->applyToDocument(doc); } void GvCore::slotSaveResult(KJob* _job) { SaveJob* job = static_cast(_job); QUrl oldUrl = job->oldUrl(); QUrl newUrl = job->newUrl(); if (job->error()) { QString name = newUrl.fileName().isEmpty() ? newUrl.toDisplayString() : newUrl.fileName(); QString msg = xi18nc("@info", "Saving %1 failed:
%2", name, kxi18n(qPrintable(job->errorString()))); int result = KMessageBox::warningContinueCancel( d->mMainWindow, msg, QString() /* caption */, KStandardGuiItem::saveAs()); if (result == KMessageBox::Continue) { saveAs(newUrl); } return; } if (oldUrl != newUrl) { d->mMainWindow->goToUrl(newUrl); ViewMainPage* page = d->mMainWindow->viewMainPage(); if (page->isVisible()) { HudMessageBubble* bubble = new HudMessageBubble(); bubble->setText(i18n("You are now viewing the new document.")); KGuiItem item = KStandardGuiItem::back(); item.setText(i18n("Go back to the original")); HudButton* button = bubble->addButton(item); BinderRef::bind(button, SIGNAL(clicked()), d->mMainWindow, &MainWindow::goToUrl, oldUrl); connect(button, SIGNAL(clicked()), bubble, SLOT(deleteLater())); page->showMessageWidget(bubble); } } } void GvCore::rotateLeft(const QUrl &url) { applyTransform(url, ROT_270); } void GvCore::rotateRight(const QUrl &url) { applyTransform(url, ROT_90); } void GvCore::setRating(const QUrl &url, int rating) { QModelIndex index = d->mDirModel->indexForUrl(url); if (!index.isValid()) { qWarning() << "invalid index!"; return; } d->mDirModel->setData(index, rating, SemanticInfoDirModel::RatingRole); } static void clearModel(QAbstractItemModel* model) { model->removeRows(0, model->rowCount()); } void GvCore::clearRecentFilesAndFolders() { clearModel(recentFilesModel()); clearModel(recentFoldersModel()); } void GvCore::slotConfigChanged() { if (!GwenviewConfig::historyEnabled()) { clearRecentFilesAndFolders(); } d->setupPalettes(); } QPalette GvCore::palette(GvCore::PaletteType type) const { return d->mPalettes[type]; } QString GvCore::fullScreenPaletteName() const { return d->mFullScreenPaletteName; } } // namespace