diff --git a/libs/ui/KisImportExportManager.cpp b/libs/ui/KisImportExportManager.cpp index fff1ff2ac8..3c66c8c4c5 100644 --- a/libs/ui/KisImportExportManager.cpp +++ b/libs/ui/KisImportExportManager.cpp @@ -1,495 +1,522 @@ /* * Copyright (C) 2016 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisImportExportManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_config.h" #include "KisImportExportFilter.h" #include "KisDocument.h" #include #include #include "kis_painter.h" #include "kis_guides_config.h" #include "kis_grid_config.h" #include "kis_popup_button.h" #include // static cache for import and export mimetypes QStringList KisImportExportManager::m_importMimeTypes; QStringList KisImportExportManager::m_exportMimeTypes; class Q_DECL_HIDDEN KisImportExportManager::Private { public: bool batchMode {false}; QPointer progressUpdater {0}; }; KisImportExportManager::KisImportExportManager(KisDocument* document) : m_document(document) , d(new Private) { } KisImportExportManager::~KisImportExportManager() { delete d; } KisImportExportFilter::ConversionStatus KisImportExportManager::importDocument(const QString& location, const QString& mimeType) { return convert(Import, location, location, mimeType, false, 0); } KisImportExportFilter::ConversionStatus KisImportExportManager::exportDocument(const QString& location, const QString& realLocation, QByteArray& mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration) { return convert(Export, location, realLocation, mimeType, showWarnings, exportConfiguration); } // The static method to figure out to which parts of the // graph this mimetype has a connection to. QStringList KisImportExportManager::mimeFilter(Direction direction) { // Find the right mimetype by the extension QSet mimeTypes; // mimeTypes << KisDocument::nativeFormatMimeType() << "application/x-krita-paintoppreset" << "image/openraster"; if (direction == KisImportExportManager::Import) { if (m_importMimeTypes.isEmpty()) { KoJsonTrader trader; QListlist = trader.query("Krita/FileFilter", ""); Q_FOREACH(QPluginLoader *loader, list) { QJsonObject json = loader->metaData().value("MetaData").toObject(); Q_FOREACH(const QString &mimetype, json.value("X-KDE-Import").toString().split(",", QString::SkipEmptyParts)) { //qDebug() << "Adding import mimetype" << mimetype << KisMimeDatabase::descriptionForMimeType(mimetype) << "from plugin" << loader; mimeTypes << mimetype; } } qDeleteAll(list); m_importMimeTypes = mimeTypes.toList(); } return m_importMimeTypes; } else if (direction == KisImportExportManager::Export) { if (m_exportMimeTypes.isEmpty()) { KoJsonTrader trader; QListlist = trader.query("Krita/FileFilter", ""); Q_FOREACH(QPluginLoader *loader, list) { QJsonObject json = loader->metaData().value("MetaData").toObject(); Q_FOREACH(const QString &mimetype, json.value("X-KDE-Export").toString().split(",", QString::SkipEmptyParts)) { //qDebug() << "Adding export mimetype" << mimetype << KisMimeDatabase::descriptionForMimeType(mimetype) << "from plugin" << loader; mimeTypes << mimetype; } } qDeleteAll(list); m_exportMimeTypes = mimeTypes.toList(); } return m_exportMimeTypes; } return QStringList(); } KisImportExportFilter *KisImportExportManager::filterForMimeType(const QString &mimetype, KisImportExportManager::Direction direction) { int weight = -1; KisImportExportFilter *filter = 0; QListlist = KoJsonTrader::instance()->query("Krita/FileFilter", ""); Q_FOREACH(QPluginLoader *loader, list) { QJsonObject json = loader->metaData().value("MetaData").toObject(); QString directionKey = direction == Export ? "X-KDE-Export" : "X-KDE-Import"; if (json.value(directionKey).toString().split(",", QString::SkipEmptyParts).contains(mimetype)) { KLibFactory *factory = qobject_cast(loader->instance()); if (!factory) { warnUI << loader->errorString(); continue; } QObject* obj = factory->create(0); if (!obj || !obj->inherits("KisImportExportFilter")) { delete obj; continue; } KisImportExportFilter *f = qobject_cast(obj); if (!f) { delete obj; continue; } int w = json.value("X-KDE-Weight").toInt(); if (w > weight) { delete filter; filter = f; f->setObjectName(loader->fileName()); weight = w; } } } qDeleteAll(list); if (filter) { filter->setMimeType(mimetype); } return filter; } void KisImportExportManager::setBatchMode(const bool batch) { d->batchMode = batch; } bool KisImportExportManager::batchMode(void) const { return d->batchMode; } void KisImportExportManager::setProgresUpdater(KoProgressUpdater *updater) { d->progressUpdater = updater; } QString KisImportExportManager::askForAudioFileName(const QString &defaultDir, QWidget *parent) { KoFileDialog dialog(parent, KoFileDialog::ImportFiles, "ImportAudio"); if (!defaultDir.isEmpty()) { dialog.setDefaultDir(defaultDir); } QStringList mimeTypes; mimeTypes << "audio/mpeg"; mimeTypes << "audio/ogg"; mimeTypes << "audio/vorbis"; mimeTypes << "audio/vnd.wave"; mimeTypes << "audio/flac"; dialog.setMimeTypeFilters(mimeTypes); dialog.setCaption(i18nc("@titile:window", "Open Audio")); return dialog.filename(); } KisImportExportFilter::ConversionStatus KisImportExportManager::convert(KisImportExportManager::Direction direction, const QString &location, const QString& realLocation, const QString &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration) { // export configuration is supported for export only KIS_SAFE_ASSERT_RECOVER_NOOP(direction == Export || !bool(exportConfiguration)); QString typeName = mimeType; if (typeName.isEmpty()) { typeName = KisMimeDatabase::mimeTypeForFile(location); } QSharedPointer filter(filterForMimeType(typeName, direction)); if (!filter) { return KisImportExportFilter::FilterCreationError; } filter->setFilename(location); filter->setRealFilename(realLocation); filter->setBatchMode(batchMode()); filter->setMimeType(typeName); if (d->progressUpdater) { filter->setUpdater(d->progressUpdater->startSubtask()); } QByteArray from, to; if (direction == Export) { from = m_document->nativeFormatMimeType(); - to = mimeType.toLatin1(); + to = typeName.toLatin1(); } else { - from = mimeType.toLatin1(); + from = typeName.toLatin1(); to = m_document->nativeFormatMimeType(); } - if (!exportConfiguration) { - exportConfiguration = filter->lastSavedConfiguration(from, to); + KIS_ASSERT_RECOVER_RETURN_VALUE( + direction == Import || direction == Export, + KisImportExportFilter::BadConversionGraph); + + + + KisImportExportFilter::ConversionStatus status = KisImportExportFilter::OK; + if (direction == Import) { + if (!batchMode()) { + QApplication::setOverrideCursor(Qt::WaitCursor); + } + status = doImport(location, filter); + if (!batchMode()) { + QApplication::restoreOverrideCursor(); + } + } else /* if (direction == Export) */ { + if (!exportConfiguration) { + exportConfiguration = filter->lastSavedConfiguration(from, to); + } + if (exportConfiguration) { - // Fill with some meta information about the image - KisImageWSP image = m_document->image(); - KisPaintDeviceSP dev = image->projection(); - const KoColorSpace* cs = dev->colorSpace(); - const bool isThereAlpha = - KisPainter::checkDeviceHasTransparency(image->projection()); - - exportConfiguration->setProperty(KisImportExportFilter::ImageContainsTransparencyTag, isThereAlpha); - exportConfiguration->setProperty(KisImportExportFilter::ColorModelIDTag, cs->colorModelId().id()); - exportConfiguration->setProperty(KisImportExportFilter::ColorDepthIDTag, cs->colorDepthId().id()); - - const bool sRGB = - (cs->profile()->name().contains(QLatin1String("srgb"), Qt::CaseInsensitive) && - !cs->profile()->name().contains(QLatin1String("g10"))); - exportConfiguration->setProperty(KisImportExportFilter::sRGBTag, sRGB); + fillStaticExportConfigurationProperties(exportConfiguration); } + bool alsoAsKra = false; + if (!askUserAboutExportConfiguration(filter, exportConfiguration, + from, to, + batchMode(), showWarnings, + &alsoAsKra)) { + + return KisImportExportFilter::UserCancelled; + } + + if (!batchMode()) { + QApplication::setOverrideCursor(Qt::WaitCursor); + } + + status = doExport(location, filter, exportConfiguration); + + if (alsoAsKra && status == KisImportExportFilter::OK) { + QString kraLocation = location + ".kra"; + QByteArray mime = m_document->nativeFormatMimeType(); + QSharedPointer filter( + filterForMimeType(QString::fromLatin1(mime), Export)); + + KIS_SAFE_ASSERT_RECOVER_NOOP(filter); + + if (filter) { + filter->setFilename(kraLocation); + + KisPropertiesConfigurationSP kraExportConfiguration = + filter->lastSavedConfiguration(mime, mime); + + status = doExport(kraLocation, filter, kraExportConfiguration); + } else { + status = KisImportExportFilter::FilterCreationError; + } + } + + if (!batchMode()) { + QApplication::restoreOverrideCursor(); + } } + if (exportConfiguration) { + KisConfig().setExportConfiguration(typeName, exportConfiguration); + } + + return status; +} + +void KisImportExportManager::fillStaticExportConfigurationProperties(KisPropertiesConfigurationSP exportConfiguration) +{ + // Fill with some meta information about the image + KisImageSP image = m_document->image(); + KisPaintDeviceSP dev = image->projection(); + const KoColorSpace* cs = dev->colorSpace(); + const bool isThereAlpha = + KisPainter::checkDeviceHasTransparency(image->projection()); + + exportConfiguration->setProperty(KisImportExportFilter::ImageContainsTransparencyTag, isThereAlpha); + exportConfiguration->setProperty(KisImportExportFilter::ColorModelIDTag, cs->colorModelId().id()); + exportConfiguration->setProperty(KisImportExportFilter::ColorDepthIDTag, cs->colorDepthId().id()); + + const bool sRGB = + (cs->profile()->name().contains(QLatin1String("srgb"), Qt::CaseInsensitive) && + !cs->profile()->name().contains(QLatin1String("g10"))); + exportConfiguration->setProperty(KisImportExportFilter::sRGBTag, sRGB); +} + +bool +KisImportExportManager::askUserAboutExportConfiguration( + QSharedPointer filter, + KisPropertiesConfigurationSP exportConfiguration, + const QByteArray &from, + const QByteArray &to, + const bool batchMode, const bool showWarnings, + bool *alsoAsKra) +{ + const QString mimeUserDescription = KisMimeDatabase::descriptionForMimeType(to); + QStringList warnings; QStringList errors; - if (direction == Export) { + { KisPreExportChecker checker; checker.check(m_document->image(), filter->exportChecks()); warnings = checker.warnings(); errors = checker.errors(); } KisConfigWidget *wdg = filter->createConfigurationWidget(0, from, to); - bool alsoAsKra = false; - // Extra checks that cannot be done by the checker, because the checker only has access to the image. - if (!m_document->assistants().isEmpty() && typeName != m_document->nativeFormatMimeType()) { + if (!m_document->assistants().isEmpty() && to != m_document->nativeFormatMimeType()) { warnings.append(i18nc("image conversion warning", "The image contains assistants. The assistants will not be saved.")); } - if (m_document->guidesConfig().hasGuides() && typeName != m_document->nativeFormatMimeType()) { + if (m_document->guidesConfig().hasGuides() && to != m_document->nativeFormatMimeType()) { warnings.append(i18nc("image conversion warning", "The image contains guides. The guides will not be saved.")); } - if (!m_document->gridConfig().isDefault() && typeName != m_document->nativeFormatMimeType()) { + if (!m_document->gridConfig().isDefault() && to != m_document->nativeFormatMimeType()) { warnings.append(i18nc("image conversion warning", "The image contains a custom grid configuration. The configuration will not be saved.")); } - if (!batchMode() && !errors.isEmpty()) { + if (!batchMode && !errors.isEmpty()) { QString error = "

" - + i18n("Error: cannot save this image as a %1.", KisMimeDatabase::descriptionForMimeType(typeName)) + + i18n("Error: cannot save this image as a %1.", mimeUserDescription) + " Reasons:

" + "

    "; Q_FOREACH(const QString &w, errors) { error += "\n
  • " + w + "
  • "; } error += "
"; QMessageBox::critical(KisPart::instance()->currentMainwindow(), i18nc("@title:window", "Krita: Export Error"), error); - return KisImportExportFilter::UserCancelled; + return false; } - if (!batchMode() && (wdg || !warnings.isEmpty())) { + if (!batchMode && (wdg || !warnings.isEmpty())) { KoDialog dlg; dlg.setButtons(KoDialog::Ok | KoDialog::Cancel); - dlg.setWindowTitle(KisMimeDatabase::descriptionForMimeType(mimeType)); + dlg.setWindowTitle(mimeUserDescription); QWidget *page = new QWidget(&dlg); QVBoxLayout *layout = new QVBoxLayout(page); - if (!warnings.isEmpty()) { - - if (showWarnings) { - - QHBoxLayout *hLayout = new QHBoxLayout(); - - QLabel *labelWarning = new QLabel(); - labelWarning->setPixmap(KisIconUtils::loadIcon("dialog-warning").pixmap(32, 32)); - hLayout->addWidget(labelWarning); - - KisPopupButton *bn = new KisPopupButton(0); + if (showWarnings && !warnings.isEmpty()) { + QHBoxLayout *hLayout = new QHBoxLayout(); - bn->setText(i18nc("Keep the extra space at the end of the sentence, please", "Warning: saving as %1 will lose information from your image. ", KisMimeDatabase::descriptionForMimeType(mimeType))); + QLabel *labelWarning = new QLabel(); + labelWarning->setPixmap(KisIconUtils::loadIcon("dialog-warning").pixmap(32, 32)); + hLayout->addWidget(labelWarning); + KisPopupButton *bn = new KisPopupButton(0); - hLayout->addWidget(bn); + bn->setText(i18nc("Keep the extra space at the end of the sentence, please", "Warning: saving as %1 will lose information from your image. ", mimeUserDescription)); - layout->addLayout(hLayout); + hLayout->addWidget(bn); - QTextBrowser *browser = new QTextBrowser(); - browser->setMinimumWidth(bn->width()); - bn->setPopupWidget(browser); + layout->addLayout(hLayout); - QString warning = "

" - + i18n("You will lose information when saving this image as a %1.", KisMimeDatabase::descriptionForMimeType(typeName)); + QTextBrowser *browser = new QTextBrowser(); + browser->setMinimumWidth(bn->width()); + bn->setPopupWidget(browser); - if (warnings.size() == 1) { - warning += " Reason:

"; - } - else { - warning += " Reasons:

"; - } - warning += "

    "; + QString warning = "

    " + + i18n("You will lose information when saving this image as a %1.", mimeUserDescription); - Q_FOREACH(const QString &w, warnings) { - warning += "\n

  • " + w + "
  • "; - } + if (warnings.size() == 1) { + warning += " Reason:

    "; + } + else { + warning += " Reasons:

    "; + } + warning += "

      "; - warning += "
    "; - browser->setHtml(warning); + Q_FOREACH(const QString &w, warnings) { + warning += "\n
  • " + w + "
  • "; } + + warning += "
"; + browser->setHtml(warning); } if (wdg) { QGroupBox *box = new QGroupBox(i18n("Options")); QVBoxLayout *boxLayout = new QVBoxLayout(box); wdg->setConfiguration(exportConfiguration); boxLayout->addWidget(wdg); layout->addWidget(box); } - QCheckBox *chkAlsoAsKra = 0; if (showWarnings && !warnings.isEmpty()) { chkAlsoAsKra = new QCheckBox(i18n("Also save your image as a Krita file.")); chkAlsoAsKra->setChecked(KisConfig().readEntry("AlsoSaveAsKra", false)); layout->addWidget(chkAlsoAsKra); } dlg.setMainWidget(page); dlg.resize(dlg.minimumSize()); if (showWarnings || wdg) { if (!dlg.exec()) { - return KisImportExportFilter::UserCancelled; + return false; } } + *alsoAsKra = false; if (chkAlsoAsKra) { KisConfig().writeEntry("AlsoSaveAsKra", chkAlsoAsKra->isChecked()); - alsoAsKra = chkAlsoAsKra->isChecked(); + *alsoAsKra = chkAlsoAsKra->isChecked(); } if (wdg) { exportConfiguration = wdg->configuration(); } - } - KIS_ASSERT_RECOVER_RETURN_VALUE( - direction == Import || direction == Export, - KisImportExportFilter::BadConversionGraph); - - if (!batchMode()) { - QApplication::setOverrideCursor(Qt::WaitCursor); - } - - KisImportExportFilter::ConversionStatus status = KisImportExportFilter::OK; - if (direction == Import) { - status = doImport(location, filter); - } else /* if (direction == Export) */ { - status = doExport(location, filter, exportConfiguration); - - if (alsoAsKra && status == KisImportExportFilter::OK) { - QString kraLocation = location + ".kra"; - QByteArray mime = m_document->nativeFormatMimeType(); - QSharedPointer filter( - filterForMimeType(QString::fromLatin1(mime), Export)); - - KIS_SAFE_ASSERT_RECOVER_NOOP(filter); - - if (filter) { - filter->setFilename(kraLocation); - - KisPropertiesConfigurationSP kraExportConfiguration = - filter->lastSavedConfiguration(mime, mime); - - status = doExport(kraLocation, filter, kraExportConfiguration); - } else { - status = KisImportExportFilter::FilterCreationError; - } - } - } - - if (exportConfiguration) { - KisConfig().setExportConfiguration(typeName, exportConfiguration); - } - - if (!batchMode()) { - QApplication::restoreOverrideCursor(); - } - - return status; - + return true; } KisImportExportFilter::ConversionStatus KisImportExportManager::doImport(const QString &location, QSharedPointer filter) { QFile file(location); if (!file.exists()) { return KisImportExportFilter::FileNotFound; } if (filter->supportsIO() && !file.open(QFile::ReadOnly)) { return KisImportExportFilter::FileNotFound; } KisImportExportFilter::ConversionStatus status = filter->convert(m_document, &file, KisPropertiesConfigurationSP()); if (file.isOpen()) { file.close(); } return status; } KisImportExportFilter::ConversionStatus KisImportExportManager::doExport(const QString &location, QSharedPointer filter, KisPropertiesConfigurationSP exportConfiguration) { QSaveFile file(location); file.setDirectWriteFallback(true); if (filter->supportsIO() && !file.open(QFile::WriteOnly)) { file.cancelWriting(); return KisImportExportFilter::CreationError; } KisImportExportFilter::ConversionStatus status = filter->convert(m_document, &file, exportConfiguration); if (status != KisImportExportFilter::OK) { file.cancelWriting(); } else { file.commit(); } return status; } #include diff --git a/libs/ui/KisImportExportManager.h b/libs/ui/KisImportExportManager.h index c9f53d9eb5..769da25458 100644 --- a/libs/ui/KisImportExportManager.h +++ b/libs/ui/KisImportExportManager.h @@ -1,149 +1,153 @@ /* * Copyright (C) 2016 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_IMPORT_EXPORT_MANAGER_H #define KIS_IMPORT_EXPORT_MANAGER_H #include #include #include #include #include "KisImportExportFilter.h" #include "kritaui_export.h" class KisDocument; class KoProgressUpdater; /** * @brief The class managing all the filters. * * This class manages all filters for a %Calligra application. Normally * you will not have to use it, since KisMainWindow takes care of loading * and saving documents. * * @ref KisFilter * * @author Kalle Dalheimer * @author Torben Weis * @author Werner Trobin */ class KRITAUI_EXPORT KisImportExportManager : public QObject { Q_OBJECT public: /** * This enum is used to distinguish the import/export cases */ enum Direction { Import = 1, Export = 2 }; /** * Create a filter manager for a document */ explicit KisImportExportManager(KisDocument *document); public: virtual ~KisImportExportManager(); /** * Imports the specified document and returns the resultant filename * (most likely some file in /tmp). * @p path can be either a URL or a filename. * @p documentMimeType gives importDocument a hint about what type * the document may be. It can be left empty. * * @return status signals the success/error of the conversion. * If the QString which is returned isEmpty() and the status is OK, * then we imported the file directly into the document. */ KisImportExportFilter::ConversionStatus importDocument(const QString &location, const QString &mimeType); /** * @brief Exports the given file/document to the specified URL/mimetype. * * If @p mimeType is empty, then the closest matching Calligra part is searched * and when the method returns @p mimeType contains this mimetype. * Oh, well, export is a C++ keyword ;) */ KisImportExportFilter::ConversionStatus exportDocument(const QString &location, const QString& realLocation, QByteArray &mimeType, bool showWarnings = true, KisPropertiesConfigurationSP exportConfiguration = 0); ///@name Static API //@{ /** * Suitable for passing to KoFileDialog::setMimeTypeFilters. The default mime * gets set by the "users" of this method, as we do not have enough * information here. * Optionally, @p extraNativeMimeTypes are added after the native mimetype. */ static QStringList mimeFilter(Direction direction); /** * @brief filterForMimeType loads the relevant import/export plugin and returns it. The caller * is responsible for deleting it! * @param mimetype the mimetype we want to import/export. If there's more than one plugin, the one * with the highest weight as defined in the json description will be taken * @param direction import or export * @return a pointer to the filter plugin or 0 if none could be found */ static KisImportExportFilter *filterForMimeType(const QString &mimetype, Direction direction); /** * Set the filter manager is batch mode (no dialog shown) * instead of the interactive mode (dialog shown) */ void setBatchMode(const bool batch); /** * Get if the filter manager is batch mode (true) * or in interactive mode (true) */ bool batchMode(void) const; void setProgresUpdater(KoProgressUpdater *updater); static QString askForAudioFileName(const QString &defaultDir, QWidget *parent); private Q_SLOTS: private: KisImportExportFilter::ConversionStatus convert(Direction direction, const QString &location, const QString& realLocation, const QString &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration); + + void fillStaticExportConfigurationProperties(KisPropertiesConfigurationSP exportConfiguration); + bool askUserAboutExportConfiguration(QSharedPointer filter, KisPropertiesConfigurationSP exportConfiguration, const QByteArray &from, const QByteArray &to, bool batchMode, const bool showWarnings, bool *alsoAsKra); + KisImportExportFilter::ConversionStatus doImport(const QString &location, QSharedPointer filter); KisImportExportFilter::ConversionStatus doExport(const QString &location, QSharedPointer filter, KisPropertiesConfigurationSP exportConfiguration); // Private API KisImportExportManager(const KisImportExportManager& rhs); KisImportExportManager &operator=(const KisImportExportManager& rhs); KisDocument *m_document; /// A static cache for the availability checks of filters static QStringList m_importMimeTypes; static QStringList m_exportMimeTypes; class Private; Private * const d; }; #endif // __KO_FILTER_MANAGER_H__