diff --git a/app/browsemainpage.cpp b/app/browsemainpage.cpp index 0d29647e..dfe02317 100644 --- a/app/browsemainpage.cpp +++ b/app/browsemainpage.cpp @@ -1,547 +1,561 @@ // 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 "browsemainpage.h" // Qt #include #include #include // KDE #include #include #include #include #include #include #include #include #include #include #include #include // Local #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE +#include "lib/semanticinfo/semanticinfodirmodel.h" +#endif namespace Gwenview { inline Sorting::Enum sortingFromSortAction(const QAction* action) { Q_ASSERT(action); return Sorting::Enum(action->data().toInt()); } struct BrowseMainPagePrivate : public Ui_BrowseMainPage { BrowseMainPage* q; GvCore* mGvCore; KFilePlacesModel* mFilePlacesModel; KUrlNavigator* mUrlNavigator; SortedDirModel* mDirModel; int mDocumentCountImages; int mDocumentCountVideos; KFileItemList* mSelectedMediaItems; KActionCollection* mActionCollection; FilterController* mFilterController; QActionGroup* mSortAction; KToggleAction* mSortDescendingAction; QActionGroup* mThumbnailDetailsActionGroup; PreviewItemDelegate* mDelegate; void setupWidgets() { setupUi(q); q->layout()->setMargin(0); // mThumbnailView mThumbnailView->setModel(mDirModel); mDelegate = new PreviewItemDelegate(mThumbnailView); mThumbnailView->setItemDelegate(mDelegate); mThumbnailView->setSelectionMode(QAbstractItemView::ExtendedSelection); // mUrlNavigator (use stupid layouting code because KUrlNavigator ctor // can't be used directly from Designer) mFilePlacesModel = new KFilePlacesModel(q); mUrlNavigator = new KUrlNavigator(mFilePlacesModel, QUrl(), mUrlNavigatorContainer); mUrlNavigatorContainer->setAutoFillBackground(true); mUrlNavigatorContainer->setBackgroundRole(QPalette::Mid); QVBoxLayout* layout = new QVBoxLayout(mUrlNavigatorContainer); layout->setMargin(0); layout->addWidget(mUrlNavigator); QObject::connect(mUrlNavigator, SIGNAL(urlsDropped(QUrl,QDropEvent*)), q, SLOT(slotUrlsDropped(QUrl,QDropEvent*))); // FullScreen Toolbar mFullScreenToolBar->setVisible(false); mFullScreenToolBar2->setVisible(false); mFullScreenToolBar->setAutoFillBackground(true); mFullScreenToolBar2->setAutoFillBackground(true); mFullScreenToolBar->setBackgroundRole(QPalette::Mid); mFullScreenToolBar2->setBackgroundRole(QPalette::Mid); // Thumbnail slider QObject::connect(mThumbnailSlider, SIGNAL(valueChanged(int)), mThumbnailView, SLOT(setThumbnailWidth(int))); QObject::connect(mThumbnailView, SIGNAL(thumbnailWidthChanged(int)), mThumbnailSlider, SLOT(setValue(int))); // Document count label QMargins labelMargins = mDocumentCountLabel->contentsMargins(); labelMargins.setLeft(15); labelMargins.setRight(15); mDocumentCountLabel->setContentsMargins(labelMargins); } QAction *thumbnailDetailAction(const QString &text, PreviewItemDelegate::ThumbnailDetail detail) { QAction *action = new QAction(q); action->setText(text); action->setCheckable(true); action->setChecked(GwenviewConfig::thumbnailDetails() & detail); action->setData(QVariant(detail)); mThumbnailDetailsActionGroup->addAction(action); QObject::connect(action, SIGNAL(triggered(bool)), q, SLOT(updateThumbnailDetails())); return action; } void setupActions(KActionCollection* actionCollection) { KActionCategory* view = new KActionCategory(i18nc("@title actions category - means actions changing smth in interface", "View"), actionCollection); QAction * action = view->addAction("edit_location", q, SLOT(editLocation())); action->setText(i18nc("@action:inmenu Navigation Bar", "Edit Location")); actionCollection->setDefaultShortcut(action, Qt::Key_F6); KActionMenu* sortActionMenu = view->add("sort_by"); sortActionMenu->setText(i18nc("@action:inmenu", "Sort By")); mSortAction = new QActionGroup(actionCollection); action = new QAction(i18nc("@addAction:inmenu", "Name"), mSortAction); action->setCheckable(true); action->setData(QVariant(Sorting::Name)); action = new QAction(i18nc("@addAction:inmenu", "Date"), mSortAction); action->setCheckable(true); action->setData(QVariant(Sorting::Date)); action = new QAction(i18nc("@addAction:inmenu", "Size"), mSortAction); action->setCheckable(true); action->setData(QVariant(Sorting::Size)); +#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE + action = new QAction(i18nc("@addAction:inmenu", "Rating"), mSortAction); + action->setCheckable(true); + action->setData(QVariant(Sorting::Rating)); +#endif QObject::connect(mSortAction, SIGNAL(triggered(QAction*)), q, SLOT(updateSortOrder())); mSortDescendingAction = view->add("sort_desc"); mSortDescendingAction->setText(i18nc("@action:inmenu Sort", "Descending")); QObject::connect(mSortDescendingAction, SIGNAL(toggled(bool)), q, SLOT(updateSortOrder())); for(auto action : mSortAction->actions()) { sortActionMenu->addAction(action); } sortActionMenu->addSeparator(); sortActionMenu->addAction(mSortDescendingAction); mThumbnailDetailsActionGroup = new QActionGroup(q); mThumbnailDetailsActionGroup->setExclusive(false); KActionMenu* thumbnailDetailsAction = view->add("thumbnail_details"); thumbnailDetailsAction->setText(i18nc("@action:inmenu", "Thumbnail Details")); thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "Filename"), PreviewItemDelegate::FileNameDetail)); thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "Date"), PreviewItemDelegate::DateDetail)); thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "Image Size"), PreviewItemDelegate::ImageSizeDetail)); thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "File Size"), PreviewItemDelegate::FileSizeDetail)); #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "Rating"), PreviewItemDelegate::RatingDetail)); #endif KActionCategory* file = new KActionCategory(i18nc("@title actions category", "File"), actionCollection); action = file->addAction("add_folder_to_places", q, SLOT(addFolderToPlaces())); action->setText(i18nc("@action:inmenu", "Add Folder to Places")); } void setupFilterController() { QMenu* menu = new QMenu(mAddFilterButton); mFilterController = new FilterController(mFilterFrame, mDirModel); Q_FOREACH(QAction * action, mFilterController->actionList()) { menu->addAction(action); } mAddFilterButton->setMenu(menu); } void setupFullScreenToolBar() { mFullScreenToolBar->setIconDimensions(KIconLoader::SizeMedium); mFullScreenToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); mFullScreenToolBar->addAction(mActionCollection->action("browse")); mFullScreenToolBar->addAction(mActionCollection->action("view")); mFullScreenToolBar2->setIconDimensions(KIconLoader::SizeMedium); mFullScreenToolBar2->setToolButtonStyle(Qt::ToolButtonIconOnly); mFullScreenToolBar2->addAction(mActionCollection->action("leave_fullscreen")); } void updateSelectedMediaItems(const QItemSelection& selected, const QItemSelection& deselected) { for (auto index : selected.indexes()) { KFileItem item = mDirModel->itemForIndex(index); if (!ArchiveUtils::fileItemIsDirOrArchive(item)) { mSelectedMediaItems->append(item); } } for (auto index : deselected.indexes()) { KFileItem item = mDirModel->itemForIndex(index); mSelectedMediaItems->removeOne(item); } } void updateDocumentCountLabel() { if (mSelectedMediaItems->count() > 1) { KIO::filesize_t totalSize = 0; for (auto item : *mSelectedMediaItems) { totalSize += item.size(); } const QString text = i18nc("@info:status %1 number of selected documents, %2 total number of documents, %3 total filesize of selected documents", "Selected %1 of %2 (%3)", mSelectedMediaItems->count(), mDocumentCountImages + mDocumentCountVideos, KFormat().formatByteSize(totalSize)); mDocumentCountLabel->setText(text); } else { const QString imageText = i18ncp("@info:status Image files", "%1 image", "%1 images", mDocumentCountImages); const QString videoText = i18ncp("@info:status Video files", "%1 video", "%1 videos", mDocumentCountVideos); QString labelText; if (mDocumentCountImages > 0 && mDocumentCountVideos == 0) { labelText = imageText; } else if (mDocumentCountImages == 0 && mDocumentCountVideos > 0) { labelText = videoText; } else { labelText = i18nc("@info:status images, videos", "%1, %2", imageText, videoText); } mDocumentCountLabel->setText(labelText); } } void documentCountsForIndexRange(const QModelIndex& parent, int start, int end, int& imageCountOut, int& videoCountOut) { imageCountOut = 0; videoCountOut = 0; for (int row = start; row <= end; ++row) { QModelIndex index = mDirModel->index(row, 0, parent); KFileItem item = mDirModel->itemForIndex(index); if (!ArchiveUtils::fileItemIsDirOrArchive(item)) { MimeTypeUtils::Kind kind = MimeTypeUtils::mimeTypeKind(item.mimetype()); if (kind == MimeTypeUtils::KIND_RASTER_IMAGE || kind == MimeTypeUtils::KIND_SVG_IMAGE) { imageCountOut++; } else if (kind == MimeTypeUtils::KIND_VIDEO) { videoCountOut++; } } } } void updateContextBarActions() { PreviewItemDelegate::ContextBarActions actions; switch (GwenviewConfig::thumbnailActions()) { case ThumbnailActions::None: actions = PreviewItemDelegate::NoAction; break; case ThumbnailActions::ShowSelectionButtonOnly: actions = PreviewItemDelegate::SelectionAction; break; case ThumbnailActions::AllButtons: default: actions = PreviewItemDelegate::SelectionAction | PreviewItemDelegate::RotateAction; if (!q->window()->isFullScreen()) { actions |= PreviewItemDelegate::FullScreenAction; } break; } mDelegate->setContextBarActions(actions); } void applyPalette(bool fullScreenmode) { q->setPalette(mGvCore->palette(fullScreenmode ? GvCore::FullScreenPalette : GvCore::NormalPalette)); mThumbnailView->setPalette(mGvCore->palette(fullScreenmode ? GvCore::FullScreenViewPalette : GvCore::NormalViewPalette)); } }; BrowseMainPage::BrowseMainPage(QWidget* parent, KActionCollection* actionCollection, GvCore* gvCore) : QWidget(parent) , d(new BrowseMainPagePrivate) { d->q = this; d->mGvCore = gvCore; d->mDirModel = gvCore->sortedDirModel(); d->mDocumentCountImages = 0; d->mDocumentCountVideos = 0; d->mSelectedMediaItems = new KFileItemList; d->mActionCollection = actionCollection; d->setupWidgets(); d->setupActions(actionCollection); d->setupFilterController(); loadConfig(); updateSortOrder(); updateThumbnailDetails(); // Set up connections for document count connect(d->mDirModel, &SortedDirModel::rowsInserted, this, &BrowseMainPage::slotDirModelRowsInserted); connect(d->mDirModel, &SortedDirModel::rowsAboutToBeRemoved, this, &BrowseMainPage::slotDirModelRowsAboutToBeRemoved); connect(d->mDirModel, &SortedDirModel::modelReset, this, &BrowseMainPage::slotDirModelReset); connect(thumbnailView(), &ThumbnailView::selectionChangedSignal, this, &BrowseMainPage::slotSelectionChanged); installEventFilter(this); } BrowseMainPage::~BrowseMainPage() { delete d; } void BrowseMainPage::loadConfig() { d->applyPalette(window()->isFullScreen()); d->mUrlNavigator->setUrlEditable(GwenviewConfig::urlNavigatorIsEditable()); d->mUrlNavigator->setShowFullPath(GwenviewConfig::urlNavigatorShowFullPath()); d->mThumbnailSlider->setValue(GwenviewConfig::thumbnailSize()); d->mThumbnailSlider->updateToolTip(); // If GwenviewConfig::thumbnailSize() returns the current value of // mThumbnailSlider, it won't emit valueChanged() and the thumbnail view // won't be updated. That's why we do it ourself. d->mThumbnailView->setThumbnailAspectRatio(GwenviewConfig::thumbnailAspectRatio()); d->mThumbnailView->setThumbnailWidth(GwenviewConfig::thumbnailSize()); Q_FOREACH(QAction * action, d->mSortAction->actions()) { if (sortingFromSortAction(action) == GwenviewConfig::sorting()) { action->setChecked(true); break; } } d->mSortDescendingAction->setChecked(GwenviewConfig::sortDescending()); d->updateContextBarActions(); } void BrowseMainPage::saveConfig() const { GwenviewConfig::setUrlNavigatorIsEditable(d->mUrlNavigator->isUrlEditable()); GwenviewConfig::setUrlNavigatorShowFullPath(d->mUrlNavigator->showFullPath()); GwenviewConfig::setThumbnailSize(d->mThumbnailSlider->value()); GwenviewConfig::setSorting(sortingFromSortAction(d->mSortAction->checkedAction())); GwenviewConfig::setSortDescending(d->mSortDescendingAction->isChecked()); GwenviewConfig::setThumbnailDetails(d->mDelegate->thumbnailDetails()); } bool BrowseMainPage::eventFilter(QObject* watched, QEvent* event) { if (window()->isFullScreen() && event->type() == QEvent::ShortcutOverride) { const QKeyEvent* keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Escape) { d->mActionCollection->action("leave_fullscreen")->trigger(); event->accept(); } } return QWidget::eventFilter(watched, event); } ThumbnailView* BrowseMainPage::thumbnailView() const { return d->mThumbnailView; } KUrlNavigator* BrowseMainPage::urlNavigator() const { return d->mUrlNavigator; } void BrowseMainPage::reload() { QModelIndexList list = d->mThumbnailView->selectionModel()->selectedIndexes(); Q_FOREACH(const QModelIndex & index, list) { d->mThumbnailView->reloadThumbnail(index); } d->mDirModel->reload(); } void BrowseMainPage::editLocation() { d->mUrlNavigator->setUrlEditable(true); d->mUrlNavigator->setFocus(); } void BrowseMainPage::addFolderToPlaces() { QUrl url = d->mUrlNavigator->locationUrl(); QString text = url.adjusted(QUrl::StripTrailingSlash).fileName(); if (text.isEmpty()) { text = url.toDisplayString(); } d->mFilePlacesModel->addPlace(text, url); } void BrowseMainPage::slotDirModelRowsInserted(const QModelIndex& parent, int start, int end) { int imageCount; int videoCount; d->documentCountsForIndexRange(parent, start, end, imageCount, videoCount); if (imageCount > 0 || videoCount > 0) { d->mDocumentCountImages += imageCount; d->mDocumentCountVideos += videoCount; d->updateDocumentCountLabel(); } } void BrowseMainPage::slotDirModelRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { int imageCount; int videoCount; d->documentCountsForIndexRange(parent, start, end, imageCount, videoCount); if (imageCount > 0 || videoCount > 0) { d->mDocumentCountImages -= imageCount; d->mDocumentCountVideos -= videoCount; d->updateDocumentCountLabel(); } } void BrowseMainPage::slotDirModelReset() { d->mDocumentCountImages = 0; d->mDocumentCountVideos = 0; d->mSelectedMediaItems->clear(); d->updateDocumentCountLabel(); } void BrowseMainPage::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { d->updateSelectedMediaItems(selected, deselected); d->updateDocumentCountLabel(); } void BrowseMainPage::updateSortOrder() { const QAction* action = d->mSortAction->checkedAction(); GV_RETURN_IF_FAIL(action); const Qt::SortOrder order = d->mSortDescendingAction->isChecked() ? Qt::DescendingOrder : Qt::AscendingOrder; KDirModel::ModelColumns column; int sortRole; // Map Sorting::Enum to model columns and sorting roles switch (sortingFromSortAction(action)) { case Sorting::Name: column = KDirModel::Name; sortRole = Qt::DisplayRole; break; case Sorting::Size: column = KDirModel::Size; sortRole = Qt::DisplayRole; break; case Sorting::Date: column = KDirModel::ModifiedTime; sortRole = Qt::DisplayRole; break; +#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE + case Sorting::Rating: + column = KDirModel::Name; + sortRole = SemanticInfoDirModel::RatingRole; + break; +#endif } d->mDirModel->setSortRole(sortRole); d->mDirModel->sort(column, order); } void BrowseMainPage::updateThumbnailDetails() { PreviewItemDelegate::ThumbnailDetails details = 0; Q_FOREACH(const QAction * action, d->mThumbnailDetailsActionGroup->actions()) { if (action->isChecked()) { details |= PreviewItemDelegate::ThumbnailDetail(action->data().toInt()); } } d->mDelegate->setThumbnailDetails(details); } void BrowseMainPage::setFullScreenMode(bool fullScreen) { d->applyPalette(fullScreen); d->mUrlNavigatorContainer->setContentsMargins( fullScreen ? 6 : 0, 0, 0, 0); d->updateContextBarActions(); d->mFullScreenToolBar->setVisible(fullScreen); d->mFullScreenToolBar2->setVisible(fullScreen); if (fullScreen && d->mFullScreenToolBar->actions().isEmpty()) { d->setupFullScreenToolBar(); } } void BrowseMainPage::setStatusBarVisible(bool visible) { d->mStatusBarContainer->setVisible(visible); } void BrowseMainPage::slotUrlsDropped(const QUrl &destUrl, QDropEvent* event) { const QList urlList = KUrlMimeData::urlsFromMimeData(event->mimeData()); if (urlList.isEmpty()) { return; } event->acceptProposedAction(); // We can't call FileOperations::showMenuForDroppedUrls() directly because // we need the slot to return so that the drop event is accepted. Otherwise // the drop cursor is still visible when the menu is shown. QMetaObject::invokeMethod(this, "showMenuForDroppedUrls", Qt::QueuedConnection, Q_ARG(QList, urlList), Q_ARG(QUrl, destUrl)); } void BrowseMainPage::showMenuForDroppedUrls(const QList& urlList, const QUrl &destUrl) { FileOperations::showMenuForDroppedUrls(d->mUrlNavigator, urlList, destUrl); } QToolButton* BrowseMainPage::toggleSideBarButton() const { return d->mToggleSideBarButton; } } // namespace diff --git a/lib/gwenviewconfig.kcfg b/lib/gwenviewconfig.kcfg index 7196bbbc..fbdddd85 100644 --- a/lib/gwenviewconfig.kcfg +++ b/lib/gwenviewconfig.kcfg @@ -1,340 +1,341 @@ lib/sorting.h lib/zoommode.h lib/thumbnailactions.h lib/mousewheelbehavior.h lib/documentview/documentview.h lib/documentview/rasterimageview.h lib/print/printoptionspage.h lib/renderingintent.h General.Name,General.ImageSize,Exif.Photo.ExposureTime,Exif.Photo.Flash true true false 100 true 0.5 The percentage of memory used by Gwenview before it warns the user and suggest saving changes. new A list of filename extensions Gwenview should not try to load. We exclude *.new as well because this is the extension used for temporary files by KSaveFile. false Horizontal 1 false false information ThumbnailActions::AllButtons General.Name,Exif.Image.DateTime true false AbstractImageView::AlphaBackgroundNone #ffffff MouseWheelBehavior::Scroll false true 350, 100 DocumentView::SoftwareAnimation ZoomMode::Autofit Defines what happens when going to image B after having zoomed in on an area of image A. If set to Autofit, image B is zoomed out to fit the screen. If set to KeepSame, all images share the same zoom and position: image B is set to the same zoom parameters as image A (and if these are changed, image A will then be displayed with the updated zoom and position). If set to Individual, all images remember their own zoom and position: image B is initially set to the same zoom parameters as image A, but will then remember its own zoom and position (if these are changed, image A will NOT be displayed with the updated zoom and position). RenderingIntent::Perceptual Defines how colors are rendered when your display uses an ICC color profile and an image has colors that do not fit within the profile's color gamut. "Perceptual" will scale the colors of the entire image so that they all fit within the display's capabilities. "Relative" will squash only the colors that cannot be displayed, and leave the other colors alone. 128 3./2. false + Sorting::Name false 1 true Qt::AlignHCenter | Qt::AlignVCenter PrintOptionsPage::ScaleToPage false 15.0 10.0 PrintOptionsPage::Centimeters true false true false false 5.0 24 false false -1 0 0 true true false diff --git a/lib/semanticinfo/sorteddirmodel.cpp b/lib/semanticinfo/sorteddirmodel.cpp index 881f9278..f9cdc54f 100644 --- a/lib/semanticinfo/sorteddirmodel.cpp +++ b/lib/semanticinfo/sorteddirmodel.cpp @@ -1,302 +1,313 @@ /* 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 "sorteddirmodel.h" #include // Qt #include #include #include // KDE #include // Local #include #include #ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE #include #else #include "abstractsemanticinfobackend.h" #include "semanticinfodirmodel.h" +#include #endif namespace Gwenview { AbstractSortedDirModelFilter::AbstractSortedDirModelFilter(SortedDirModel* model) : QObject(model) , mModel(model) { if (mModel) { mModel->addFilter(this); } } AbstractSortedDirModelFilter::~AbstractSortedDirModelFilter() { if (mModel) { mModel->removeFilter(this); } } struct SortedDirModelPrivate { #ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE KDirModel* mSourceModel; #else SemanticInfoDirModel* mSourceModel; #endif QStringList mBlackListedExtensions; QList mFilters; QTimer mDelayedApplyFiltersTimer; MimeTypeUtils::Kinds mKindFilter; }; SortedDirModel::SortedDirModel(QObject* parent) : KDirSortFilterProxyModel(parent) , d(new SortedDirModelPrivate) { #ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE d->mSourceModel = new KDirModel(this); #else d->mSourceModel = new SemanticInfoDirModel(this); #endif setSourceModel(d->mSourceModel); d->mDelayedApplyFiltersTimer.setInterval(0); d->mDelayedApplyFiltersTimer.setSingleShot(true); connect(&d->mDelayedApplyFiltersTimer, &QTimer::timeout, this, &SortedDirModel::doApplyFilters); } SortedDirModel::~SortedDirModel() { delete d; } MimeTypeUtils::Kinds SortedDirModel::kindFilter() const { return d->mKindFilter; } void SortedDirModel::setKindFilter(MimeTypeUtils::Kinds kindFilter) { if (d->mKindFilter == kindFilter) { return; } d->mKindFilter = kindFilter; applyFilters(); } void SortedDirModel::adjustKindFilter(MimeTypeUtils::Kinds kinds, bool set) { MimeTypeUtils::Kinds kindFilter = d->mKindFilter; if (set) { kindFilter |= kinds; } else { kindFilter &= ~kinds; } setKindFilter(kindFilter); } void SortedDirModel::addFilter(AbstractSortedDirModelFilter* filter) { d->mFilters << filter; applyFilters(); } void SortedDirModel::removeFilter(AbstractSortedDirModelFilter* filter) { d->mFilters.removeAll(filter); applyFilters(); } KDirLister* SortedDirModel::dirLister() const { return d->mSourceModel->dirLister(); } void SortedDirModel::reload() { #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE d->mSourceModel->clearSemanticInfoCache(); #endif dirLister()->updateDirectory(dirLister()->url()); } void SortedDirModel::setBlackListedExtensions(const QStringList& list) { d->mBlackListedExtensions = list; } KFileItem SortedDirModel::itemForIndex(const QModelIndex& index) const { if (!index.isValid()) { return KFileItem(); } QModelIndex sourceIndex = mapToSource(index); return d->mSourceModel->itemForIndex(sourceIndex); } QUrl SortedDirModel::urlForIndex(const QModelIndex& index) const { KFileItem item = itemForIndex(index); return item.isNull() ? QUrl() : item.url(); } KFileItem SortedDirModel::itemForSourceIndex(const QModelIndex& sourceIndex) const { if (!sourceIndex.isValid()) { return KFileItem(); } return d->mSourceModel->itemForIndex(sourceIndex); } QModelIndex SortedDirModel::indexForItem(const KFileItem& item) const { if (item.isNull()) { return QModelIndex(); } QModelIndex sourceIndex = d->mSourceModel->indexForItem(item); return mapFromSource(sourceIndex); } QModelIndex SortedDirModel::indexForUrl(const QUrl &url) const { if (!url.isValid()) { return QModelIndex(); } QModelIndex sourceIndex = d->mSourceModel->indexForUrl(url); return mapFromSource(sourceIndex); } bool SortedDirModel::filterAcceptsRow(int row, const QModelIndex& parent) const { QModelIndex index = d->mSourceModel->index(row, 0, parent); KFileItem fileItem = d->mSourceModel->itemForIndex(index); MimeTypeUtils::Kinds kind = MimeTypeUtils::fileItemKind(fileItem); if (d->mKindFilter != MimeTypeUtils::Kinds() && !(d->mKindFilter & kind)) { return false; } if (kind != MimeTypeUtils::KIND_DIR && kind != MimeTypeUtils::KIND_ARCHIVE) { int dotPos = fileItem.name().lastIndexOf('.'); if (dotPos >= 1) { QString extension = fileItem.name().mid(dotPos + 1).toLower(); if (d->mBlackListedExtensions.contains(extension)) { return false; } } #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE if (!d->mSourceModel->semanticInfoAvailableForIndex(index)) { Q_FOREACH(const AbstractSortedDirModelFilter * filter, d->mFilters) { // Make sure we have semanticinfo, otherwise retrieve it and // return false, we will be called again later when it is // there. if (filter->needsSemanticInfo()) { d->mSourceModel->retrieveSemanticInfoForIndex(index); return false; } } } #endif Q_FOREACH(const AbstractSortedDirModelFilter * filter, d->mFilters) { if (!filter->acceptsIndex(index)) { return false; } } } return KDirSortFilterProxyModel::filterAcceptsRow(row, parent); } AbstractSemanticInfoBackEnd* SortedDirModel::semanticInfoBackEnd() const { #ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE return 0; #else return d->mSourceModel->semanticInfoBackEnd(); #endif } #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE SemanticInfo SortedDirModel::semanticInfoForSourceIndex(const QModelIndex& sourceIndex) const { return d->mSourceModel->semanticInfoForIndex(sourceIndex); } #endif void SortedDirModel::applyFilters() { d->mDelayedApplyFiltersTimer.start(); } void SortedDirModel::doApplyFilters() { QSortFilterProxyModel::invalidateFilter(); } bool SortedDirModel::lessThan(const QModelIndex& left, const QModelIndex& right) const { const KFileItem leftItem = itemForSourceIndex(left); const KFileItem rightItem = itemForSourceIndex(right); const bool leftIsDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(leftItem); const bool rightIsDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(rightItem); if (leftIsDirOrArchive != rightIsDirOrArchive) { return sortOrder() == Qt::AscendingOrder ? leftIsDirOrArchive : rightIsDirOrArchive; } - if (sortColumn() != KDirModel::ModifiedTime) { - return KDirSortFilterProxyModel::lessThan(left, right); + if (sortColumn() == KDirModel::ModifiedTime) { + const QDateTime leftDate = TimeUtils::dateTimeForFileItem(leftItem); + const QDateTime rightDate = TimeUtils::dateTimeForFileItem(rightItem); + + return leftDate < rightDate; } +#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE + if (sortRole() == SemanticInfoDirModel::RatingRole) { + const int leftRating = d->mSourceModel->data(left, SemanticInfoDirModel::RatingRole).toInt(); + const int rightRating = d->mSourceModel->data(right, SemanticInfoDirModel::RatingRole).toInt(); - const QDateTime leftDate = TimeUtils::dateTimeForFileItem(leftItem); - const QDateTime rightDate = TimeUtils::dateTimeForFileItem(rightItem); + if (leftRating != rightRating) { + return leftRating < rightRating; + } + } +#endif - return leftDate < rightDate; + return KDirSortFilterProxyModel::lessThan(left, right); } bool SortedDirModel::hasDocuments() const { const int count = rowCount(); if (count == 0) { return false; } for (int row = 0; row < count; ++row) { const QModelIndex idx = index(row, 0); const KFileItem item = itemForIndex(idx); if (!ArchiveUtils::fileItemIsDirOrArchive(item)) { return true; } } return false; } void SortedDirModel::setDirLister(KDirLister* dirLister) { d->mSourceModel->setDirLister(dirLister); } } //namespace diff --git a/lib/sorting.h b/lib/sorting.h index 52906197..0ef9ce27 100644 --- a/lib/sorting.h +++ b/lib/sorting.h @@ -1,48 +1,51 @@ // 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. */ #ifndef SORTING_H #define SORTING_H // Qt // KDE // Local namespace Gwenview { namespace Sorting { /** * This enum represents the different sorting orders. */ enum Enum { Name, Size, - Date + Date, +#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE + Rating +#endif }; } // namespace Sorting } // namespace Gwenview #endif /* SORTING_H */