diff --git a/app/fileopscontextmanageritem.cpp b/app/fileopscontextmanageritem.cpp index 83ce7d9a..8cda2951 100644 --- a/app/fileopscontextmanageritem.cpp +++ b/app/fileopscontextmanageritem.cpp @@ -1,415 +1,415 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2007 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, Boston, MA 02110-1301, USA. */ // Self #include "fileopscontextmanageritem.h" // Qt #include #include #include #include #include #include #include // KDE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Local #include #include #include #include "fileoperations.h" #include "sidebar.h" namespace Gwenview { QList FileOpsContextManagerItem::urlList() const { QList urlList; KFileItemList list = contextManager()->selectedFileItemList(); if (list.count() > 0) { urlList = list.urlList(); } else { QUrl url = contextManager()->currentUrl(); Q_ASSERT(url.isValid()); urlList << url; } return urlList; } void FileOpsContextManagerItem::updateServiceList() { // This code is inspired from // kdebase/apps/lib/konq/konq_menuactions.cpp // Get list of all distinct mimetypes in selection QStringList mimeTypes; Q_FOREACH(const KFileItem & item, contextManager()->selectedFileItemList()) { const QString mimeType = item.mimetype(); if (!mimeTypes.contains(mimeType)) { mimeTypes << mimeType; } } // Query trader mServiceList = KFileItemActions::associatedApplications(mimeTypes, QString()); } QMimeData* FileOpsContextManagerItem::selectionMimeData() { QMimeData* mimeData = new QMimeData; KFileItemList list = contextManager()->selectedFileItemList(); mimeData->setUrls(list.urlList()); return mimeData; } QUrl FileOpsContextManagerItem::pasteTargetUrl() const { // If only one folder is selected, paste inside it, otherwise paste in // current KFileItemList list = contextManager()->selectedFileItemList(); if (list.count() == 1 && list.first().isDir()) { return list.first().url(); } else { return contextManager()->currentDirUrl(); } } static QAction* createSeparator(QObject* parent) { QAction* action = new QAction(parent); action->setSeparator(true); return action; } FileOpsContextManagerItem::FileOpsContextManagerItem(ContextManager* manager, QListView* thumbnailView, KActionCollection* actionCollection, KXMLGUIClient* client) : AbstractContextManagerItem(manager) { mThumbnailView = thumbnailView; mXMLGUIClient = client; mGroup = new SideBarGroup(i18n("File Operations")); setWidget(mGroup); EventWatcher::install(mGroup, QEvent::Show, this, SLOT(updateSideBarContent())); mInTrash = false; mNewFileMenu = new KNewFileMenu(Q_NULLPTR, QString(), this); connect(contextManager(), SIGNAL(selectionChanged()), SLOT(updateActions())); connect(contextManager(), SIGNAL(currentDirUrlChanged(QUrl)), SLOT(updateActions())); KActionCategory* file = new KActionCategory(i18nc("@title actions category", "File"), actionCollection); KActionCategory* edit = new KActionCategory(i18nc("@title actions category", "Edit"), actionCollection); mCutAction = edit->addAction(KStandardAction::Cut, this, SLOT(cut())); mCopyAction = edit->addAction(KStandardAction::Copy, this, SLOT(copy())); mPasteAction = edit->addAction(KStandardAction::Paste, this, SLOT(paste())); mCopyToAction = file->addAction("file_copy_to", this, SLOT(copyTo())); mCopyToAction->setText(i18nc("Verb", "Copy To...")); actionCollection->setDefaultShortcut(mCopyToAction, Qt::Key_F7); mMoveToAction = file->addAction("file_move_to", this, SLOT(moveTo())); mMoveToAction->setText(i18nc("Verb", "Move To...")); actionCollection->setDefaultShortcut(mMoveToAction, Qt::Key_F8); mLinkToAction = file->addAction("file_link_to", this, SLOT(linkTo())); mLinkToAction->setText(i18nc("Verb: create link to the file where user wants", "Link To...")); actionCollection->setDefaultShortcut(mLinkToAction, Qt::Key_F9); mRenameAction = file->addAction("file_rename", this, SLOT(rename())); mRenameAction->setText(i18nc("Verb", "Rename...")); mRenameAction->setIcon(QIcon::fromTheme("edit-rename")); actionCollection->setDefaultShortcut(mRenameAction, Qt::Key_F2); mTrashAction = file->addAction("file_trash", this, SLOT(trash())); mTrashAction->setText(i18nc("Verb", "Trash")); mTrashAction->setIcon(QIcon::fromTheme("user-trash")); actionCollection->setDefaultShortcut(mTrashAction, Qt::Key_Delete); mDelAction = file->addAction(KStandardAction::DeleteFile, this, SLOT(del())); mRestoreAction = file->addAction("file_restore", this, SLOT(restore())); mRestoreAction->setText(i18n("Restore")); mShowPropertiesAction = file->addAction("file_show_properties", this, SLOT(showProperties())); mShowPropertiesAction->setText(i18n("Properties")); mShowPropertiesAction->setIcon(QIcon::fromTheme("document-properties")); mCreateFolderAction = file->addAction("file_create_folder", this, SLOT(createFolder())); mCreateFolderAction->setText(i18n("Create Folder...")); mCreateFolderAction->setIcon(QIcon::fromTheme("folder-new")); mOpenWithAction = file->addAction("file_open_with"); mOpenWithAction->setText(i18n("Open With")); QMenu* menu = new QMenu; mOpenWithAction->setMenu(menu); connect(menu, &QMenu::aboutToShow, this, &FileOpsContextManagerItem::populateOpenMenu); connect(menu, &QMenu::triggered, this, &FileOpsContextManagerItem::openWith); mRegularFileActionList << mRenameAction << mTrashAction << mDelAction << createSeparator(this) << mCopyToAction << mMoveToAction << mLinkToAction << createSeparator(this) << mOpenWithAction << mShowPropertiesAction << createSeparator(this) << mCreateFolderAction ; mTrashFileActionList << mRestoreAction << mDelAction << createSeparator(this) << mShowPropertiesAction ; connect(QApplication::clipboard(), SIGNAL(dataChanged()), SLOT(updatePasteAction())); updatePasteAction(); // Delay action update because it must happen *after* main window has called // createGUI(), otherwise calling mXMLGUIClient->plugActionList() will // fail. QMetaObject::invokeMethod(this, "updateActions", Qt::QueuedConnection); } FileOpsContextManagerItem::~FileOpsContextManagerItem() { delete mOpenWithAction->menu(); } void FileOpsContextManagerItem::updateActions() { const int count = contextManager()->selectedFileItemList().count(); const bool selectionNotEmpty = count > 0; const bool urlIsValid = contextManager()->currentUrl().isValid(); const bool dirUrlIsValid = contextManager()->currentDirUrl().isValid(); mInTrash = contextManager()->currentDirUrl().scheme() == "trash"; mCutAction->setEnabled(selectionNotEmpty); mCopyAction->setEnabled(selectionNotEmpty); mCopyToAction->setEnabled(selectionNotEmpty); mMoveToAction->setEnabled(selectionNotEmpty); mLinkToAction->setEnabled(selectionNotEmpty); mTrashAction->setEnabled(selectionNotEmpty); mRestoreAction->setEnabled(selectionNotEmpty); mDelAction->setEnabled(selectionNotEmpty); mOpenWithAction->setEnabled(selectionNotEmpty); mRenameAction->setEnabled(count == 1); mCreateFolderAction->setEnabled(dirUrlIsValid); mShowPropertiesAction->setEnabled(dirUrlIsValid || urlIsValid); mXMLGUIClient->unplugActionList("file_action_list"); QList& list = mInTrash ? mTrashFileActionList : mRegularFileActionList; mXMLGUIClient->plugActionList("file_action_list", list); updateSideBarContent(); } void FileOpsContextManagerItem::updatePasteAction() { const QMimeData *mimeData = QApplication::clipboard()->mimeData(); bool enable; KFileItem destItem(pasteTargetUrl()); const QString text = KIO::pasteActionText(mimeData, &enable, destItem); mPasteAction->setEnabled(enable); mPasteAction->setText(text); } void FileOpsContextManagerItem::updateSideBarContent() { if (!mGroup->isVisible()) { return; } mGroup->clear(); QList& list = mInTrash ? mTrashFileActionList : mRegularFileActionList; Q_FOREACH(QAction * action, list) { if (action->isEnabled() && !action->isSeparator()) { mGroup->addAction(action); } } } void FileOpsContextManagerItem::showProperties() { KFileItemList list = contextManager()->selectedFileItemList(); if (list.count() > 0) { KPropertiesDialog::showDialog(list, mGroup); } else { QUrl url = contextManager()->currentDirUrl(); KPropertiesDialog::showDialog(url, mGroup); } } void FileOpsContextManagerItem::cut() { QMimeData* mimeData = selectionMimeData(); KIO::setClipboardDataCut(mimeData, true); QApplication::clipboard()->setMimeData(mimeData); } void FileOpsContextManagerItem::copy() { QMimeData* mimeData = selectionMimeData(); KIO::setClipboardDataCut(mimeData, false); QApplication::clipboard()->setMimeData(mimeData); } void FileOpsContextManagerItem::paste() { KIO::Job *job = KIO::paste(QApplication::clipboard()->mimeData(), pasteTargetUrl()); KJobWidgets::setWindow(job, mGroup); } void FileOpsContextManagerItem::trash() { FileOperations::trash(urlList(), mGroup); } void FileOpsContextManagerItem::del() { FileOperations::del(urlList(), mGroup); } void FileOpsContextManagerItem::restore() { KIO::RestoreJob *job = KIO::restoreFromTrash(urlList()); KJobWidgets::setWindow(job, mGroup); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } void FileOpsContextManagerItem::copyTo() { FileOperations::copyTo(urlList(), mGroup); } void FileOpsContextManagerItem::moveTo() { FileOperations::moveTo(urlList(), mGroup); } void FileOpsContextManagerItem::linkTo() { FileOperations::linkTo(urlList(), mGroup); } void FileOpsContextManagerItem::rename() { if (mThumbnailView->isVisible()) { QModelIndex index = mThumbnailView->currentIndex(); mThumbnailView->edit(index); } else { FileOperations::rename(urlList().first(), mGroup); } } void FileOpsContextManagerItem::createFolder() { QUrl url = contextManager()->currentDirUrl(); mNewFileMenu->setParentWidget(mGroup); mNewFileMenu->setPopupFiles(QList() << url); mNewFileMenu->createDirectory(); } void FileOpsContextManagerItem::populateOpenMenu() { QMenu* openMenu = mOpenWithAction->menu(); qDeleteAll(openMenu->actions()); updateServiceList(); int idx = 0; Q_FOREACH(const KService::Ptr & service, mServiceList) { QString text = service->name().replace('&', "&&"); QAction* action = openMenu->addAction(text); action->setIcon(QIcon::fromTheme(service->icon())); action->setData(idx); ++idx; } openMenu->addSeparator(); QAction* action = openMenu->addAction(i18n("Other Application...")); action->setData(-1); } void FileOpsContextManagerItem::openWith(QAction* action) { Q_ASSERT(action); KService::Ptr service; QList list = urlList(); bool ok; int idx = action->data().toInt(&ok); GV_RETURN_IF_FAIL(ok); if (idx == -1) { // Other Application... KOpenWithDialog dlg(list, mGroup); if (!dlg.exec()) { return; } service = dlg.service(); if (!service) { // User entered a custom command Q_ASSERT(!dlg.text().isEmpty()); KRun::run(dlg.text(), list, mGroup); return; } } else { service = mServiceList.at(idx); } Q_ASSERT(service); - KRun::run(*service, list, mGroup); + KRun::runService(*service, list, mGroup); } } // namespace diff --git a/app/kipiinterface.cpp b/app/kipiinterface.cpp index 7bbc3474..069d831b 100644 --- a/app/kipiinterface.cpp +++ b/app/kipiinterface.cpp @@ -1,510 +1,510 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2000-2008 Aurélien Gâteau Copyright 2008 Angelo Naselli 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. */ #include "kipiinterface.h" // Qt #include #include #include #include #include #include // KDE #include #include #include #include #include #include #include #include // KIPI #include #include #include #include #include //#include // local #include "mainwindow.h" #include "kipiimagecollectionselector.h" #include "kipiuploadwidget.h" #include #include #include #include #include #define KIPI_PLUGINS_URL QStringLiteral("appstream://photolayoutseditor.desktop") namespace Gwenview { #undef ENABLE_LOG #undef LOG //#define ENABLE_LOG #ifdef ENABLE_LOG #define LOG(x) qDebug() << x #else #define LOG(x) ; #endif class KIPIImageInfo : public KIPI::ImageInfoShared { static const QRegExp sExtensionRE; public: KIPIImageInfo(KIPI::Interface* interface, const QUrl &url) : KIPI::ImageInfoShared(interface, url) { - KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); + KFileItem item(url); mAttributes.insert("name", url.fileName()); mAttributes.insert("comment", comment()); mAttributes.insert("date", TimeUtils::dateTimeForFileItem(item)); mAttributes.insert("orientation", orientation()); mAttributes.insert("title", prettyFileName()); int size = item.size(); if (size > 0) { mAttributes.insert("filesize", size); } } QMap attributes() { return mAttributes; } void delAttributes(const QStringList& attributeNames) { Q_FOREACH(const QString& name, attributeNames) { mAttributes.remove(name); } } void clearAttributes() { mAttributes.clear(); } void addAttributes(const QVariantMap& attributes) { QVariantMap::ConstIterator it = attributes.constBegin(), end = attributes.constEnd(); for (; it != end; ++it) { mAttributes.insert(it.key(), it.value()); } } private: QString prettyFileName() const { QString txt = _url.fileName(); txt.replace('_', ' '); txt.remove(sExtensionRE); return txt; } QString comment() const { if (!_url.isLocalFile()) return QString(); JpegContent content; bool ok = content.load(_url.toLocalFile()); if (!ok) return QString(); return content.comment(); } int orientation() const { #if 0 //PORT QT5 KFileMetaInfo metaInfo(_url); if (!metaInfo.isValid()) { return 0; } const KFileMetaInfoItem& mii = metaInfo.item("http://freedesktop.org/standards/xesam/1.0/core#orientation"); bool ok = false; const Orientation orientation = (Orientation)mii.value().toInt(&ok); if (!ok) { return 0; } switch (orientation) { case NOT_AVAILABLE: case NORMAL: return 0; case ROT_90: return 90; case ROT_180: return 180; case ROT_270: return 270; case HFLIP: case VFLIP: case TRANSPOSE: case TRANSVERSE: qWarning() << "Can't represent an orientation value of" << orientation << "as an angle (" << _url << ')'; return 0; } #endif //qWarning() << "Don't know how to handle an orientation value of" << orientation << '(' << _url << ')'; return 0; } QVariantMap mAttributes; }; const QRegExp KIPIImageInfo::sExtensionRE("\\.[a-z0-9]+$", Qt::CaseInsensitive); struct MenuInfo { QString mName; QList mActions; MenuInfo() {} MenuInfo(const QString& name) : mName(name) {} }; typedef QMap MenuInfoMap; struct KIPIInterfacePrivate { KIPIInterface* q; MainWindow* mMainWindow; QMenu* mPluginMenu; KIPI::PluginLoader* mPluginLoader; KIPI::PluginLoader::PluginList mPluginQueue; MenuInfoMap mMenuInfoMap; QAction * mLoadingAction; QAction * mNoPluginAction; QAction * mInstallPluginAction; QFileSystemWatcher mPluginWatcher; QTimer mPluginLoadTimer; void setupPluginsMenu() { mPluginMenu = static_cast( mMainWindow->factory()->container("plugins", mMainWindow)); QObject::connect(mPluginMenu, &QMenu::aboutToShow, q, &KIPIInterface::loadPlugins); } QAction * createDummyPluginAction(const QString& text) { QAction * action = new QAction(q); action->setText(text); //PORT QT5 action->setShortcutConfigurable(false); action->setEnabled(false); return action; } }; KIPIInterface::KIPIInterface(MainWindow* mainWindow) : KIPI::Interface(mainWindow) , d(new KIPIInterfacePrivate) { d->q = this; d->mMainWindow = mainWindow; d->mPluginLoader = nullptr; d->mLoadingAction = d->createDummyPluginAction(i18n("Loading...")); d->mNoPluginAction = d->createDummyPluginAction(i18n("No Plugin Found")); d->mInstallPluginAction = d->createDummyPluginAction(i18nc("@item:inmenu", "Install Plugins")); connect(&d->mPluginLoadTimer, &QTimer::timeout, this, &KIPIInterface::loadPlugins); d->setupPluginsMenu(); QObject::connect(d->mMainWindow->contextManager(), SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged())); QObject::connect(d->mMainWindow->contextManager(), SIGNAL(currentDirUrlChanged(QUrl)), this, SLOT(slotDirectoryChanged())); #if 0 //TODO instead of delaying can we load them all at start-up to use actions somewhere else? // delay a bit, so that it's called after loadPlugins() QTimer::singleShot(0, this, SLOT(init())); #endif } KIPIInterface::~KIPIInterface() { delete d; } static bool actionLessThan(QAction* a1, QAction* a2) { QString a1Text = a1->text().replace('&', QString()); QString a2Text = a2->text().replace('&', QString()); return QString::compare(a1Text, a2Text, Qt::CaseInsensitive) < 0; } void KIPIInterface::loadPlugins() { // Already done if (d->mPluginLoader) { return; } d->mMenuInfoMap[KIPI::ImagesPlugin] = MenuInfo(i18nc("@title:menu", "Images")); d->mMenuInfoMap[KIPI::ToolsPlugin] = MenuInfo(i18nc("@title:menu", "Tools")); d->mMenuInfoMap[KIPI::ImportPlugin] = MenuInfo(i18nc("@title:menu", "Import")); d->mMenuInfoMap[KIPI::ExportPlugin] = MenuInfo(i18nc("@title:menu", "Export")); d->mMenuInfoMap[KIPI::BatchPlugin] = MenuInfo(i18nc("@title:menu", "Batch Processing")); d->mMenuInfoMap[KIPI::CollectionsPlugin] = MenuInfo(i18nc("@title:menu", "Collections")); d->mPluginLoader = new KIPI::PluginLoader(); d->mPluginLoader->setInterface(this); d->mPluginLoader->init(); d->mPluginQueue = d->mPluginLoader->pluginList(); d->mPluginMenu->addAction(d->mLoadingAction); loadOnePlugin(); } void KIPIInterface::loadOnePlugin() { while (!d->mPluginQueue.isEmpty()) { KIPI::PluginLoader::Info* pluginInfo = d->mPluginQueue.takeFirst(); if (!pluginInfo->shouldLoad()) { continue; } KIPI::Plugin* plugin = pluginInfo->plugin(); if (!plugin) { qWarning() << "Plugin from library" << pluginInfo->library() << "failed to load"; continue; } plugin->setup(d->mMainWindow); QList actions = plugin->actions(); Q_FOREACH(QAction * action, actions) { KIPI::Category category = plugin->category(action); if (!d->mMenuInfoMap.contains(category)) { qWarning() << "Unknown category '" << category; continue; } d->mMenuInfoMap[category].mActions << action; } // FIXME: Port //plugin->actionCollection()->readShortcutSettings(); // If we reach this point, we just loaded one plugin. Go back to the // event loop. We will come back to load the remaining plugins or create // the menu later QMetaObject::invokeMethod(this, "loadOnePlugin", Qt::QueuedConnection); return; } // If we reach this point, all plugins have been loaded. We can fill the // menu MenuInfoMap::Iterator it = d->mMenuInfoMap.begin(), end = d->mMenuInfoMap.end(); for (; it != end; ++it) { MenuInfo& info = it.value(); if (!info.mActions.isEmpty()) { QMenu* menu = d->mPluginMenu->addMenu(info.mName); qSort(info.mActions.begin(), info.mActions.end(), actionLessThan); Q_FOREACH(QAction * action, info.mActions) { menu->addAction(action); } } } d->mPluginMenu->removeAction(d->mLoadingAction); if (d->mPluginMenu->isEmpty()) { if (KIO::DesktopExecParser::hasSchemeHandler(QUrl(KIPI_PLUGINS_URL))) { d->mPluginMenu->addAction(d->mInstallPluginAction); d->mInstallPluginAction->setEnabled(true); QObject::connect(d->mInstallPluginAction, &QAction::triggered, this, [=](){QDesktopServices::openUrl(QUrl(KIPI_PLUGINS_URL));}); d->mPluginWatcher.addPaths(QCoreApplication::libraryPaths()); connect(&d->mPluginWatcher, &QFileSystemWatcher::directoryChanged, this, &KIPIInterface::packageFinished); } else { d->mPluginMenu->addAction(d->mNoPluginAction); } } loadingFinished(); } void KIPIInterface::packageFinished() { if (d->mPluginLoader) { delete d->mPluginLoader; d->mPluginLoader = nullptr; } d->mPluginMenu->removeAction(d->mInstallPluginAction); d->mPluginMenu->removeAction(d->mNoPluginAction); d->mPluginLoadTimer.start(1000); } QList KIPIInterface::pluginActions(KIPI::Category category) const { const_cast(this)->loadPlugins(); if (isLoadingFinished()) { QList list = d->mMenuInfoMap.value(category).mActions; if (list.isEmpty()) { list << d->mNoPluginAction; } return list; } else { return QList() << d->mLoadingAction; } } bool KIPIInterface::isLoadingFinished() const { if (!d->mPluginLoader) { // Not even started return false; } return d->mPluginQueue.isEmpty(); } void KIPIInterface::init() { slotDirectoryChanged(); slotSelectionChanged(); } KIPI::ImageCollection KIPIInterface::currentAlbum() { LOG(""); const ContextManager* contextManager = d->mMainWindow->contextManager(); const QUrl url = contextManager->currentDirUrl(); const SortedDirModel* model = contextManager->dirModel(); QList list; const int count = model->rowCount(); for (int row = 0; row < count; ++row) { const QModelIndex& index = model->index(row, 0); const KFileItem item = model->itemForIndex(index); if (MimeTypeUtils::fileItemKind(item) == MimeTypeUtils::KIND_RASTER_IMAGE) { list << item.targetUrl(); } } return KIPI::ImageCollection(new ImageCollection(url, url.fileName(), list)); } KIPI::ImageCollection KIPIInterface::currentSelection() { LOG(""); KFileItemList fileList = d->mMainWindow->contextManager()->selectedFileItemList(); QList list = fileList.urlList(); QUrl url = d->mMainWindow->contextManager()->currentUrl(); return KIPI::ImageCollection(new ImageCollection(url, url.fileName(), list)); } QList KIPIInterface::allAlbums() { LOG(""); QList list; list << currentAlbum() << currentSelection(); return list; } KIPI::ImageInfo KIPIInterface::info(const QUrl &url) { LOG(""); return KIPI::ImageInfo(new KIPIImageInfo(this, url)); } int KIPIInterface::features() const { return KIPI::HostAcceptNewImages; } /** * KDirLister will pick up the image if necessary, so no updating is needed * here, it is however necessary to discard caches if the plugin preserves timestamp */ bool KIPIInterface::addImage(const QUrl&, QString&) { //TODO setContext(const QUrl ¤tUrl, const KFileItemList& selection)? //Cache::instance()->invalidate( url ); return true; } void KIPIInterface::delImage(const QUrl&) { //TODO } void KIPIInterface::refreshImages(const QList&) { // TODO } KIPI::ImageCollectionSelector* KIPIInterface::imageCollectionSelector(QWidget *parent) { return new KIPIImageCollectionSelector(this, parent); } KIPI::UploadWidget* KIPIInterface::uploadWidget(QWidget *parent) { return (new KIPIUploadWidget(this, parent)); } void KIPIInterface::slotSelectionChanged() { emit selectionChanged(!d->mMainWindow->contextManager()->selectedFileItemList().isEmpty()); } void KIPIInterface::slotDirectoryChanged() { emit currentAlbumChanged(true); } #ifdef GWENVIEW_KIPI_WITH_CREATE_METHODS KIPI::FileReadWriteLock* KIPIInterface::createReadWriteLock(const QUrl& url) const { return NULL; } KIPI::MetadataProcessor* KIPIInterface::createMetadataProcessor() const { return NULL; } #ifdef GWENVIEW_KIPI_WITH_CREATE_RAW_PROCESSOR KIPI::RawProcessor* KIPIInterface::createRawProcessor() const { return NULL; } #endif #endif } //namespace diff --git a/app/mainwindow.h b/app/mainwindow.h index 023a74e2..967f9724 100644 --- a/app/mainwindow.h +++ b/app/mainwindow.h @@ -1,142 +1,142 @@ /* Gwenview: an image viewer Copyright 2007 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, Boston, MA 02110-1301, USA. */ #ifndef MAINWINDOW_H #define MAINWINDOW_H // Qt #include // KDE #include class QModelIndex; class QUrl; namespace Gwenview { class ViewMainPage; class ContextManager; class MainWindow : public KXmlGuiWindow { Q_OBJECT public: MainWindow(); ~MainWindow(); /** * Defines the url to display when the window is shown for the first time. */ void setInitialUrl(const QUrl&); void startSlideShow(); ViewMainPage* viewMainPage() const; ContextManager* contextManager() const; void setDistractionFreeMode(bool); public Q_SLOTS: void showStartMainPage(); /** * Go to url, without changing current mode */ void goToUrl(const QUrl&); Q_SIGNALS: void viewModeChanged(); public Q_SLOTS: virtual void setCaption(const QString&) Q_DECL_OVERRIDE; virtual void setCaption(const QString&, bool modified) Q_DECL_OVERRIDE; protected: virtual bool queryClose() Q_DECL_OVERRIDE; virtual QSize sizeHint() const Q_DECL_OVERRIDE; virtual void showEvent(QShowEvent*) Q_DECL_OVERRIDE; virtual void resizeEvent(QResizeEvent*) Q_DECL_OVERRIDE; virtual void saveProperties(KConfigGroup&) Q_DECL_OVERRIDE; virtual void readProperties(const KConfigGroup&) Q_DECL_OVERRIDE; - bool eventFilter(QObject *, QEvent *); + bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE; private Q_SLOTS: void setActiveViewModeAction(QAction* action); void openDirUrl(const QUrl&); void slotThumbnailViewIndexActivated(const QModelIndex&); void slotStartMainPageUrlSelected(const QUrl&); void goUp(); void toggleSideBar(bool visible); void updateToggleSideBarAction(); void slotModifiedDocumentListChanged(); void slotPartCompleted(); void slotDirModelNewItems(); void slotDirListerCompleted(); void slotSelectionChanged(); void slotCurrentDirUrlChanged(const QUrl &url); void goToPrevious(); void goToNext(); void goToFirst(); void goToLast(); void updatePreviousNextActions(); void leaveFullScreen(); void toggleFullScreen(bool); void toggleSlideShow(); void updateSlideShowAction(); void saveCurrent(); void saveCurrentAs(); void openFile(); void openUrl(const QUrl& url); void reload(); void showDocumentInFullScreen(const QUrl&); void showConfigDialog(); void loadConfig(); void print(); void preloadNextUrl(); void toggleMenuBar(); void toggleStatusBar(); void showFirstDocumentReached(); void showLastDocumentReached(); private: struct Private; MainWindow::Private* const d; void openSelectedDocuments(); void saveConfig(); }; } // namespace #endif /* MAINWINDOW_H */ diff --git a/importer/importdialog.cpp b/importer/importdialog.cpp index 5e9e847c..808be48e 100644 --- a/importer/importdialog.cpp +++ b/importer/importdialog.cpp @@ -1,267 +1,267 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2009 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 "importdialog.h" // Qt #include #include #include // KDE #include #include #include #include #include #include #include #include #include #include // Local #include "dialogpage.h" #include "importer.h" #include "importerconfig.h" #include "progresspage.h" #include "thumbnailpage.h" namespace Gwenview { class ImportDialogPrivate { public: ImportDialog* q; QStackedWidget* mCentralWidget; ThumbnailPage* mThumbnailPage; ProgressPage* mProgressPage; DialogPage* mDialogPage; Importer* mImporter; void deleteImportedUrls() { QList importedUrls = mImporter->importedUrlList(); QList skippedUrls = mImporter->skippedUrlList(); int importedCount = importedUrls.count(); int skippedCount = skippedUrls.count(); if (importedCount == 0 && skippedCount == 0) { return; } QStringList message; message << i18np( "One document has been imported.", "%1 documents have been imported.", importedCount); if (skippedCount > 0) { message << i18np( "One document has been skipped because it had already been imported.", "%1 documents have been skipped because they had already been imported.", skippedCount); } if (mImporter->renamedCount() > 0) { message[0].append("*"); message << "* " + i18np( "One of them has been renamed because another document with the same name had already been imported.", "%1 of them have been renamed because other documents with the same name had already been imported.", mImporter->renamedCount()) + ""; } message << QString(); if (skippedCount == 0) { message << i18np( "Delete the imported document from the device?", "Delete the %1 imported documents from the device?", importedCount); } else if (importedCount == 0) { message << i18np( "Delete the skipped document from the device?", "Delete the %1 skipped documents from the device?", skippedCount); } else { message << i18ncp( "Singular sentence is actually never used.", "Delete the imported or skipped document from the device?", "Delete the %1 imported and skipped documents from the device?", importedCount + skippedCount); } int answer = KMessageBox::questionYesNo(mCentralWidget, "" + message.join("
") + "
", i18nc("@title:window", "Import Finished"), KStandardGuiItem::del(), KGuiItem(i18n("Keep")) ); if (answer != KMessageBox::Yes) { return; } QList urls = importedUrls + skippedUrls; while (true) { KIO::Job* job = KIO::del(urls); if (job->exec()) { break; } // Deleting failed int answer = KMessageBox::warningYesNo(mCentralWidget, i18np("Failed to delete the document:\n%2", "Failed to delete documents:\n%2", urls.count(), job->errorString()), QString(), KGuiItem(i18n("Retry")), KGuiItem(i18n("Ignore")) ); if (answer != KMessageBox::Yes) { // Ignore break; } } } void startGwenview() { KService::Ptr service = KService::serviceByDesktopName("org.kde.gwenview"); if (!service) { qCritical() << "Could not find gwenview"; } else { - KRun::run(*service, {mThumbnailPage->destinationUrl()}, 0 /* window */); + KRun::runService(*service, {mThumbnailPage->destinationUrl()}, 0 /* window */); } } void showWhatNext() { mCentralWidget->setCurrentWidget(mDialogPage); mDialogPage->setText(i18n("What do you want to do now?")); mDialogPage->removeButtons(); int gwenview = mDialogPage->addButton(KGuiItem(i18n("View Imported Documents with Gwenview"), "gwenview")); int importMore = mDialogPage->addButton(KGuiItem(i18n("Import more Documents"))); mDialogPage->addButton(KGuiItem(i18n("Quit"), "dialog-cancel")); int answer = mDialogPage->exec(); if (answer == gwenview) { startGwenview(); qApp->quit(); } else if (answer == importMore) { mCentralWidget->setCurrentWidget(mThumbnailPage); } else { /* quit */ qApp->quit(); } } }; ImportDialog::ImportDialog() : d(new ImportDialogPrivate) { d->q = this; d->mImporter = new Importer(this); connect(d->mImporter, SIGNAL(error(QString)), SLOT(showImportError(QString))); d->mThumbnailPage = new ThumbnailPage; QUrl url = ImporterConfig::destinationUrl(); if (!url.isValid()) { url = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); int year = QDate::currentDate().year(); url.setPath(url.path() + '/' + QString::number(year)); } d->mThumbnailPage->setDestinationUrl(url); d->mProgressPage = new ProgressPage(d->mImporter); d->mDialogPage = new DialogPage; d->mCentralWidget = new QStackedWidget; setCentralWidget(d->mCentralWidget); d->mCentralWidget->addWidget(d->mThumbnailPage); d->mCentralWidget->addWidget(d->mProgressPage); d->mCentralWidget->addWidget(d->mDialogPage); connect(d->mThumbnailPage, SIGNAL(importRequested()), SLOT(startImport())); connect(d->mThumbnailPage, SIGNAL(rejected()), SLOT(close())); connect(d->mImporter, SIGNAL(importFinished()), SLOT(slotImportFinished())); d->mCentralWidget->setCurrentWidget(d->mThumbnailPage); setWindowIcon(QIcon::fromTheme("gwenview")); setAutoSaveSettings(); } ImportDialog::~ImportDialog() { delete d; } QSize ImportDialog::sizeHint() const { return QSize(700, 500); } void ImportDialog::setSourceUrl(const QUrl& url, const QString& deviceUdi) { QString name, iconName; if (deviceUdi.isEmpty()) { name = url.url(QUrl::PreferLocalFile); iconName = KProtocolInfo::icon(url.scheme()); if (iconName.isEmpty()) { iconName = "folder"; } } else { Solid::Device device(deviceUdi); name = device.vendor() + " " + device.product(); iconName = device.icon(); } d->mThumbnailPage->setSourceUrl(url, iconName, name); } void ImportDialog::startImport() { QUrl url = d->mThumbnailPage->destinationUrl(); ImporterConfig::setDestinationUrl(url); ImporterConfig::self()->save(); d->mCentralWidget->setCurrentWidget(d->mProgressPage); d->mImporter->setAutoRenameFormat( ImporterConfig::autoRename() ? ImporterConfig::autoRenameFormat() : QString()); d->mImporter->start(d->mThumbnailPage->urlList(), url); } void ImportDialog::slotImportFinished() { d->deleteImportedUrls(); d->showWhatNext(); } void ImportDialog::showImportError(const QString& message) { KMessageBox::sorry(this, message); d->mCentralWidget->setCurrentWidget(d->mThumbnailPage); } } // namespace diff --git a/importer/importer.cpp b/importer/importer.cpp index a7e1d4ea..fa64982b 100644 --- a/importer/importer.cpp +++ b/importer/importer.cpp @@ -1,242 +1,243 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2009 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 "importer.h" // Qt #include #include #include // KDE #include #include #include #include #include #include #include // stdc++ #include // Local #include #include #include #include namespace Gwenview { struct ImporterPrivate { Importer* q; QWidget* mAuthWindow; - std::auto_ptr mFileNameFormater; + std::unique_ptr mFileNameFormater; QUrl mTempImportDirUrl; /* @defgroup reset Should be reset in start() * @{ */ QList mUrlList; QList mImportedUrlList; QList mSkippedUrlList; int mRenamedCount; int mProgress; int mJobProgress; /* @} */ QUrl mCurrentUrl; void emitError(const QString& message) { QMetaObject::invokeMethod(q, "error", Q_ARG(QString, message)); } bool createImportDir(const QUrl& url) { Q_ASSERT(url.isLocalFile()); // FIXME: Support remote urls if (!QDir().mkpath(url.toLocalFile())) { emitError(i18n("Could not create destination folder.")); return false; } QString message; QString dir = FileUtils::createTempDir(url.toLocalFile(), ".gwenview_importer-", &message); mTempImportDirUrl = QUrl::fromLocalFile(dir); if (mTempImportDirUrl.isEmpty()) { emitError(i18n("Could not create temporary upload folder:\n%1", message)); return false; } return true; } void importNext() { if (mUrlList.empty()) { q->finalizeImport(); return; } mCurrentUrl = mUrlList.takeFirst(); QUrl dst = mTempImportDirUrl; dst.setPath(dst.path() + mCurrentUrl.fileName()); KIO::Job* job = KIO::copy(mCurrentUrl, dst, KIO::HideProgressInfo); KJobWidgets::setWindow(job, mAuthWindow); QObject::connect(job, SIGNAL(result(KJob*)), q, SLOT(slotCopyDone(KJob*))); QObject::connect(job, SIGNAL(percent(KJob*,ulong)), q, SLOT(slotPercent(KJob*,ulong))); } void renameImportedUrl(const QUrl& src) { QUrl dst = src.resolved(QUrl("..")); QString fileName; if (mFileNameFormater.get()) { - KFileItem item(KFileItem::Unknown, KFileItem::Unknown, src, true /* delayedMimeTypes */); + KFileItem item(src); + item.setDelayedMimeTypes(true); // Get the document time, but do not cache the result because the // 'src' url is temporary: if we import "foo/image.jpg" and // "bar/image.jpg", both images will be temporarily saved in the // 'src' url. QDateTime dateTime = TimeUtils::dateTimeForFileItem(item, TimeUtils::SkipCache); fileName = mFileNameFormater->format(src, dateTime); } else { fileName = src.fileName(); } dst.setPath(dst.path() + fileName); FileUtils::RenameResult result = FileUtils::rename(src, dst, mAuthWindow); switch (result) { case FileUtils::RenamedOK: mImportedUrlList << mCurrentUrl; break; case FileUtils::RenamedUnderNewName: mRenamedCount++; mImportedUrlList << mCurrentUrl; break; case FileUtils::Skipped: mSkippedUrlList << mCurrentUrl; break; case FileUtils::RenameFailed: qWarning() << "Rename failed for" << mCurrentUrl; } q->advance(); importNext(); } }; Importer::Importer(QWidget* parent) : QObject(parent) , d(new ImporterPrivate) { d->q = this; d->mAuthWindow = parent; } Importer::~Importer() { delete d; } void Importer::setAutoRenameFormat(const QString& format) { if (format.isEmpty()) { d->mFileNameFormater.reset(0); } else { d->mFileNameFormater.reset(new FileNameFormater(format)); } } void Importer::start(const QList& list, const QUrl& destination) { d->mUrlList = list; d->mImportedUrlList.clear(); d->mSkippedUrlList.clear(); d->mRenamedCount = 0; d->mProgress = 0; d->mJobProgress = 0; emitProgressChanged(); maximumChanged(d->mUrlList.count() * 100); if (!d->createImportDir(destination)) { qWarning() << "Could not create import dir"; return; } d->importNext(); } void Importer::slotCopyDone(KJob* _job) { KIO::CopyJob* job = static_cast(_job); QUrl url = job->destUrl(); if (job->error()) { qWarning() << "FIXME: What do we do with failed urls?"; advance(); d->importNext(); return; } d->renameImportedUrl(url); } void Importer::finalizeImport() { KIO::Job* job = KIO::del(d->mTempImportDirUrl, KIO::HideProgressInfo); KJobWidgets::setWindow(job, d->mAuthWindow); importFinished(); } void Importer::advance() { ++d->mProgress; d->mJobProgress = 0; emitProgressChanged(); } void Importer::slotPercent(KJob*, unsigned long percent) { d->mJobProgress = percent; emitProgressChanged(); } void Importer::emitProgressChanged() { progressChanged(d->mProgress * 100 + d->mJobProgress); } QList Importer::importedUrlList() const { return d->mImportedUrlList; } QList Importer::skippedUrlList() const { return d->mSkippedUrlList; } int Importer::renamedCount() const { return d->mRenamedCount; } } // namespace diff --git a/tests/auto/importertest.h b/tests/auto/importertest.h index 57ad6157..e7732f4c 100644 --- a/tests/auto/importertest.h +++ b/tests/auto/importertest.h @@ -1,53 +1,53 @@ /* Gwenview: an image viewer Copyright 2009 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, Boston, MA 02110-1301, USA. */ #ifndef IMPORTERTEST_H #define IMPORTERTEST_H // stdc++ #include // Qt #include // KDE #include #include class ImporterTest : public QObject { Q_OBJECT private Q_SLOTS: void init(); void testContentsAreIdentical(); void testSuccessfulImport(); void testAutoRenameFormat(); void testReadOnlyDestination(); void testFileNameFormater(); void testFileNameFormater_data(); void testSkippedUrlList(); void testRenamedCount(); private: - std::auto_ptr mTempDir; + std::unique_ptr mTempDir; QList mDocumentList; }; #endif /* IMPORTERTEST_H */ diff --git a/tests/auto/thumbnailprovidertest.cpp b/tests/auto/thumbnailprovidertest.cpp index b194fad3..363aeca6 100644 --- a/tests/auto/thumbnailprovidertest.cpp +++ b/tests/auto/thumbnailprovidertest.cpp @@ -1,280 +1,280 @@ /* Gwenview: an image viewer Copyright 2007 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, Boston, MA 02110-1301, USA. */ #include "thumbnailprovidertest.h" // Qt #include #include #include #include // KDE #include #include #include #include // Local #include "../lib/imageformats/imageformats.h" #include "../lib/thumbnailprovider/thumbnailprovider.h" #include "testutils.h" // libc #include #include using namespace Gwenview; QTEST_MAIN(ThumbnailProviderTest) SandBox::SandBox() : mPath(QDir::currentPath() + "/sandbox") {} void SandBox::initDir() { KIO::Job* job; QDir dir(mPath); if (dir.exists()) { QUrl sandBoxUrl("file://" + mPath); job = KIO::del(sandBoxUrl); QVERIFY2(job->exec(), "Couldn't delete sandbox"); } dir.mkpath("."); } void SandBox::fill() { initDir(); createTestImage("red.png", 300, 200, Qt::red); createTestImage("blue.png", 200, 300, Qt::blue); createTestImage("small.png", 50, 50, Qt::green); copyTestImage("orient6.jpg", 128, 256); copyTestImage("orient6-small.jpg", 32, 64); } void SandBox::copyTestImage(const QString& testFileName, int width, int height) { QUrl testPath = urlForTestFile(testFileName); QUrl testDest = QUrl("file://" + mPath + '/' + testFileName); KIO::Job* job = KIO::copy(testPath, testDest); QVERIFY2(job->exec(), "Couldn't copy test image"); mSizeHash.insert(testFileName, QSize(width, height)); } static QImage createColoredImage(int width, int height, const QColor& color) { QImage image(width, height, QImage::Format_RGB32); QPainter painter(&image); painter.fillRect(image.rect(), color); return image; } void SandBox::createTestImage(const QString& name, int width, int height, const QColor& color) { QImage image = createColoredImage(width, height, color); image.save(mPath + '/' + name, "png"); mSizeHash.insert(name, QSize(width, height)); } void ThumbnailProviderTest::initTestCase() { qRegisterMetaType("KFileItem"); Gwenview::ImageFormats::registerPlugins(); } void ThumbnailProviderTest::init() { ThumbnailProvider::setThumbnailBaseDir(mSandBox.mPath + "/thumbnails/"); mSandBox.fill(); } static void syncRun(ThumbnailProvider *provider) { QEventLoop loop; QObject::connect(provider, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); } void ThumbnailProviderTest::testLoadLocal() { QDir dir(mSandBox.mPath); // Create a list of items which will be thumbnailed KFileItemList list; Q_FOREACH(const QFileInfo & info, dir.entryInfoList(QDir::Files)) { QUrl url("file://" + info.absoluteFilePath()); - KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); + KFileItem item(url); list << item; } // Generate the thumbnails ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Normal); provider.appendItems(list); QSignalSpy spy(&provider, SIGNAL(thumbnailLoaded(KFileItem,QPixmap,QSize,qulonglong))); syncRun(&provider); while (!ThumbnailProvider::isThumbnailWriterEmpty()) { QTest::qWait(100); } // Check we generated the correct number of thumbnails QDir thumbnailDir = ThumbnailProvider::thumbnailBaseDir(ThumbnailGroup::Normal); // There should be one file less because small.png is a png and is too // small to have a thumbnail QStringList entryList = thumbnailDir.entryList(QStringList("*.png")); QCOMPARE(entryList.count(), mSandBox.mSizeHash.size() - 1); // Check thumbnail keys QHash > thumbnailHash; Q_FOREACH(const QString& name, entryList) { QImage thumb; QVERIFY(thumb.load(thumbnailDir.filePath(name))); QUrl url(thumb.text("Thumb::URI")); KFileItem item = list.findByUrl(url); QVERIFY(!item.isNull()); QSize originalSize = mSandBox.mSizeHash.value(item.url().fileName()); uint mtime = item.time(KFileItem::ModificationTime).toTime_t(); if (mtime == uint(-1)) { // This happens from time to time on build.kde.org, but I haven't // been able to reproduce it locally, so let's try to gather more // information. qWarning() << "mtime == -1 for url" << url << ". This should not happen!"; qWarning() << "errno:" << errno << "message:" << strerror(errno); qWarning() << "QFile::exists(" << url.toLocalFile() << "):" << QFile::exists(url.toLocalFile()); qWarning() << "Recalculating mtime" << item.time(KFileItem::ModificationTime).toTime_t(); QFAIL("Invalid time for test KFileItem"); } QCOMPARE(thumb.text("Thumb::Image::Width"), QString::number(originalSize.width())); QCOMPARE(thumb.text("Thumb::Image::Height"), QString::number(originalSize.height())); QCOMPARE(thumb.text("Thumb::Mimetype"), item.mimetype()); QCOMPARE(thumb.text("Thumb::Size"), QString::number(item.size())); QCOMPARE(thumb.text("Thumb::MTime"), QString::number(mtime)); } // Check what was in the thumbnailLoaded() signals QCOMPARE(spy.count(), mSandBox.mSizeHash.size()); QSignalSpy::ConstIterator it = spy.constBegin(), end = spy.constEnd(); for (; it != end; ++it) { const QVariantList args = *it; const KFileItem item = qvariant_cast(args.at(0)); const QSize size = args.at(2).toSize(); const QSize expectedSize = mSandBox.mSizeHash.value(item.url().fileName()); QCOMPARE(size, expectedSize); } } void ThumbnailProviderTest::testUseEmbeddedOrNot() { QImage expectedThumbnail; QPixmap thumbnailPix; SandBox sandBox; sandBox.initDir(); // This image is red (0xfe0000) and 256x128 but contains a white 128x64 thumbnail sandBox.copyTestImage("embedded-thumbnail.jpg", 256, 128); KFileItemList list; QUrl url("file://" + QDir(sandBox.mPath).absoluteFilePath("embedded-thumbnail.jpg")); - list << KFileItem(KFileItem::Unknown, KFileItem::Unknown, url); + list << KFileItem(url); // Loading a normal thumbnail should bring the white one { ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Normal); provider.appendItems(list); QSignalSpy spy(&provider, SIGNAL(thumbnailLoaded(KFileItem,QPixmap,QSize,qulonglong))); syncRun(&provider); QCOMPARE(spy.count(), 1); expectedThumbnail = createColoredImage(128, 64, Qt::white); thumbnailPix = qvariant_cast(spy.at(0).at(1)); QVERIFY(TestUtils::imageCompare(expectedThumbnail, thumbnailPix.toImage())); } // Loading a large thumbnail should bring the red one { ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Large); provider.appendItems(list); QSignalSpy spy(&provider, SIGNAL(thumbnailLoaded(KFileItem,QPixmap,QSize,qulonglong))); syncRun(&provider); QCOMPARE(spy.count(), 1); expectedThumbnail = createColoredImage(256, 128, QColor(254, 0, 0)); thumbnailPix = qvariant_cast(spy.at(0).at(1)); QVERIFY(TestUtils::imageCompare(expectedThumbnail, thumbnailPix.toImage())); } } void ThumbnailProviderTest::testLoadRemote() { QUrl url = setUpRemoteTestDir("test.png"); if (!url.isValid()) { QSKIP("Not running this test: failed to setup remote test dir."); } url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + "test.png"); KFileItemList list; - KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); + KFileItem item(url); list << item; ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Normal); provider.appendItems(list); syncRun(&provider); while (!ThumbnailProvider::isThumbnailWriterEmpty()) { QTest::qWait(100); } QDir thumbnailDir = ThumbnailProvider::thumbnailBaseDir(ThumbnailGroup::Normal); QStringList entryList = thumbnailDir.entryList(QStringList("*.png")); QCOMPARE(entryList.count(), 1); } void ThumbnailProviderTest::testRemoveItemsWhileGenerating() { QDir dir(mSandBox.mPath); // Create a list of items which will be thumbnailed KFileItemList list; Q_FOREACH(const QFileInfo & info, dir.entryInfoList(QDir::Files)) { QUrl url("file://" + info.absoluteFilePath()); - KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); + KFileItem item(url); list << item; } // Start generating thumbnails for items ThumbnailProvider provider; provider.setThumbnailGroup(ThumbnailGroup::Normal); provider.appendItems(list); QEventLoop loop; connect(&provider, SIGNAL(finished()), &loop, SLOT(quit())); // Remove items, it should not crash provider.removeItems(list); loop.exec(); } diff --git a/tests/auto/timeutilstest.cpp b/tests/auto/timeutilstest.cpp index 5b61cb0b..93d81d23 100644 --- a/tests/auto/timeutilstest.cpp +++ b/tests/auto/timeutilstest.cpp @@ -1,92 +1,92 @@ /* 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, Boston, MA 02110-1301, USA. */ #include "timeutilstest.h" // libc #include // KDE #include #include #include // Local #include "../lib/timeutils.h" #include "testutils.h" QTEST_MAIN(TimeUtilsTest) using namespace Gwenview; static void touchFile(const QString& path) { utime(QFile::encodeName(path).data(), 0); } #define NEW_ROW(fileName, dateTime) QTest::newRow(fileName) << fileName << dateTime void TimeUtilsTest::testBasic_data() { QTest::addColumn("fileName"); QTest::addColumn("expectedDateTime"); NEW_ROW("date/exif-datetimeoriginal.jpg", QDateTime::fromString("2003-03-10T17:45:21", Qt::ISODate)); NEW_ROW("date/exif-datetime-only.jpg", QDateTime::fromString("2003-03-25T02:02:21", Qt::ISODate)); QUrl url = urlForTestFile("test.png"); - KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); + KFileItem item(url); NEW_ROW("test.png", item.time(KFileItem::ModificationTime)); } void TimeUtilsTest::testBasic() { QFETCH(QString, fileName); QFETCH(QDateTime, expectedDateTime); QDateTime dateTime; QUrl url = urlForTestFile(fileName); - KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); + KFileItem item(url); dateTime = TimeUtils::dateTimeForFileItem(item); QCOMPARE(dateTime, expectedDateTime); dateTime = TimeUtils::dateTimeForFileItem(item, TimeUtils::SkipCache); QCOMPARE(dateTime, expectedDateTime); } void TimeUtilsTest::testCache() { QTemporaryFile tempFile; QVERIFY(tempFile.open()); QUrl url = QUrl::fromLocalFile(tempFile.fileName()); - KFileItem item1(KFileItem::Unknown, KFileItem::Unknown, url); + KFileItem item1(url); QDateTime dateTime1 = TimeUtils::dateTimeForFileItem(item1); QCOMPARE(dateTime1, item1.time(KFileItem::ModificationTime)); QTest::qWait(1200); touchFile(url.toLocalFile()); - KFileItem item2(KFileItem::Unknown, KFileItem::Unknown, url); + KFileItem item2(url); QDateTime dateTime2 = TimeUtils::dateTimeForFileItem(item2); QVERIFY(dateTime1 != dateTime2); QCOMPARE(dateTime2, item2.time(KFileItem::ModificationTime)); }