diff --git a/ThumbnailView/ThumbnailFacade.cpp b/ThumbnailView/ThumbnailFacade.cpp index 3381d0ed..9f1d8448 100644 --- a/ThumbnailView/ThumbnailFacade.cpp +++ b/ThumbnailView/ThumbnailFacade.cpp @@ -1,180 +1,192 @@ /* Copyright (C) 2003-2010 Jesper K. Pedersen 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ThumbnailFacade.h" #include "ImageManager/ThumbnailCache.h" #include #include "Settings/SettingsData.h" #include "ThumbnailToolTip.h" #include "ThumbnailModel.h" #include "CellGeometry.h" #include "ThumbnailWidget.h" #include "GridResizeSlider.h" ThumbnailView::ThumbnailFacade* ThumbnailView::ThumbnailFacade::s_instance = nullptr; ThumbnailView::ThumbnailFacade::ThumbnailFacade() :m_cellGeometry( nullptr ), m_model( nullptr ),m_widget( nullptr ), m_toolTip( nullptr ) { // To avoid one of the components references one of the other before it has been initialized, we first construct them all with null. m_cellGeometry = new CellGeometry(this); m_model = new ThumbnailModel(this); m_widget = new ThumbnailWidget(this); m_toolTip = new ThumbnailToolTip( m_widget ); connect(m_widget, &ThumbnailWidget::showImage, this, &ThumbnailFacade::showImage); connect(m_widget, &ThumbnailWidget::showSelection, this, &ThumbnailFacade::showSelection); connect(m_widget, &ThumbnailWidget::fileIdUnderCursorChanged, this, &ThumbnailFacade::fileIdUnderCursorChanged); connect(m_widget, &ThumbnailWidget::currentDateChanged, this, &ThumbnailFacade::currentDateChanged); connect(m_widget, &ThumbnailWidget::selectionCountChanged, this, &ThumbnailFacade::selectionChanged); connect(m_model, &ThumbnailModel::collapseAllStacksEnabled, this, &ThumbnailFacade::collapseAllStacksEnabled); connect(m_model, &ThumbnailModel::expandAllStacksEnabled, this, &ThumbnailFacade::expandAllStacksEnabled); s_instance = this; } QWidget* ThumbnailView::ThumbnailFacade::gui() { return m_widget; } void ThumbnailView::ThumbnailFacade::gotoDate( const DB::ImageDate& date, bool b) { m_widget->gotoDate( date, b ); } void ThumbnailView::ThumbnailFacade::setCurrentItem( const DB::FileName& fileName ) { widget()->setCurrentItem(fileName); } void ThumbnailView::ThumbnailFacade::reload( SelectionUpdateMethod method ) { m_widget->reload( method ); } DB::FileNameList ThumbnailView::ThumbnailFacade::selection( ThumbnailView::SelectionMode mode ) const { return m_widget->selection(mode); } DB::FileNameList ThumbnailView::ThumbnailFacade::imageList(Order order) const { return m_model->imageList(order); } DB::FileName ThumbnailView::ThumbnailFacade::mediaIdUnderCursor() const { return m_widget->mediaIdUnderCursor(); } DB::FileName ThumbnailView::ThumbnailFacade::currentItem() const { return m_model->imageAt(m_widget->currentIndex().row()); } void ThumbnailView::ThumbnailFacade::setImageList(const DB::FileNameList& list) { m_model->setImageList(list); } void ThumbnailView::ThumbnailFacade::setSortDirection( SortDirection direction ) { m_model->setSortDirection( direction ); } QSlider* ThumbnailView::ThumbnailFacade::createResizeSlider() { return new GridResizeSlider( this ); } void ThumbnailView::ThumbnailFacade::selectAll() { m_widget->selectAll(); } void ThumbnailView::ThumbnailFacade::clearSelection() { m_widget->clearSelection(); } void ThumbnailView::ThumbnailFacade::showToolTipsOnImages( bool on ) { m_toolTip->setActive( on ); } void ThumbnailView::ThumbnailFacade::toggleStackExpansion(const DB::FileName& fileName) { m_model->toggleStackExpansion(fileName); } void ThumbnailView::ThumbnailFacade::collapseAllStacks() { m_model->collapseAllStacks(); } void ThumbnailView::ThumbnailFacade::expandAllStacks() { m_model->expandAllStacks(); } void ThumbnailView::ThumbnailFacade::updateDisplayModel() { m_model->updateDisplayModel(); } void ThumbnailView::ThumbnailFacade::changeSingleSelection(const DB::FileName& fileName) { m_widget->changeSingleSelection(fileName); } ThumbnailView::ThumbnailModel* ThumbnailView::ThumbnailFacade::model() { Q_ASSERT( m_model ); return m_model; } ThumbnailView::CellGeometry* ThumbnailView::ThumbnailFacade::cellGeometry() { Q_ASSERT( m_cellGeometry ); return m_cellGeometry; } ThumbnailView::ThumbnailWidget* ThumbnailView::ThumbnailFacade::widget() { Q_ASSERT( m_widget ); return m_widget; } ThumbnailView::ThumbnailFacade* ThumbnailView::ThumbnailFacade::instance() { Q_ASSERT( s_instance ); return s_instance; } void ThumbnailView::ThumbnailFacade::slotRecreateThumbnail() { Q_FOREACH( const DB::FileName& fileName, widget()->selection( NoExpandCollapsedStacks )) { ImageManager::ThumbnailCache::instance()->removeThumbnail( fileName ); BackgroundJobs::HandleVideoThumbnailRequestJob::removeFullScaleFrame(fileName); m_model->updateCell(fileName); } } +void ThumbnailView::ThumbnailFacade::clearFilter() +{ + Q_ASSERT( m_model ); + m_model->clearFilter(); +} + +void ThumbnailView::ThumbnailFacade::setFilter(DB::ImageSearchInfo filter) +{ + Q_ASSERT( m_model ); + m_model->setFilter(filter); +} + // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/ThumbnailView/ThumbnailFacade.h b/ThumbnailView/ThumbnailFacade.h index 4d0f9a48..6777b194 100644 --- a/ThumbnailView/ThumbnailFacade.h +++ b/ThumbnailView/ThumbnailFacade.h @@ -1,92 +1,96 @@ /* Copyright (C) 2003-2010 Jesper K. Pedersen 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef THUMBNAILFACADE_H #define THUMBNAILFACADE_H #include "ThumbnailFactory.h" #include "ThumbnailWidget.h" #include +#include class QSlider; namespace ThumbnailView { class ThumbnailModel; class CellGeometry; class ThumbnailPainter; class ThumbnailToolTip; class ThumbnailFacade :public QObject, public ThumbnailFactory { Q_OBJECT public: static ThumbnailFacade* instance(); ThumbnailFacade(); QWidget* gui(); void setCurrentItem( const DB::FileName& fileName ); void reload( SelectionUpdateMethod method ); DB::FileNameList selection( ThumbnailView::SelectionMode mode = ExpandCollapsedStacks ) const; DB::FileNameList imageList(Order) const; DB::FileName mediaIdUnderCursor() const; DB::FileName currentItem() const; void setImageList(const DB::FileNameList& list); void setSortDirection( SortDirection ); /** * @brief createResizeSlider returns a QSlider that can be used to resize the thumbnail grid. * @return a (horizontal) QSlider */ QSlider* createResizeSlider(); public slots: void gotoDate( const DB::ImageDate& date, bool includeRanges ); void selectAll(); void clearSelection(); void showToolTipsOnImages( bool b ); void toggleStackExpansion(const DB::FileName& id); void collapseAllStacks(); void expandAllStacks(); void updateDisplayModel(); void changeSingleSelection(const DB::FileName& fileName); void slotRecreateThumbnail(); + void clearFilter(); + void setFilter(DB::ImageSearchInfo setFilter); + signals: void showImage( const DB::FileName& id ); void showSelection(); void fileIdUnderCursorChanged( const DB::FileName& id ); void currentDateChanged( const QDateTime& ); void selectionChanged(int numberOfItemsSelected ); void collapseAllStacksEnabled(bool enabled); void expandAllStacksEnabled(bool enabled); private: ThumbnailModel* model() override; CellGeometry* cellGeometry() override; ThumbnailWidget* widget() override; private: static ThumbnailFacade* s_instance; CellGeometry* m_cellGeometry; ThumbnailModel* m_model; ThumbnailWidget* m_widget; ThumbnailPainter* m_painter; ThumbnailToolTip* m_toolTip; }; } #endif /* THUMBNAILFACADE_H */ // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/ThumbnailView/ThumbnailModel.cpp b/ThumbnailView/ThumbnailModel.cpp index 4aff2dde..b8e4131c 100644 --- a/ThumbnailView/ThumbnailModel.cpp +++ b/ThumbnailView/ThumbnailModel.cpp @@ -1,465 +1,483 @@ /* Copyright (C) 2003-2019 The KPhotoAlbum Development Team 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ThumbnailModel.h" #include #include #include #include #include #include #include #include #include "CellGeometry.h" #include "ThumbnailRequest.h" #include "ThumbnailWidget.h" #include "SelectionMaintainer.h" ThumbnailView::ThumbnailModel::ThumbnailModel( ThumbnailFactory* factory) : ThumbnailComponent( factory ) , m_sortDirection( Settings::SettingsData::instance()->showNewestThumbnailFirst() ? NewestFirst : OldestFirst ) , m_firstVisibleRow(-1) , m_lastVisibleRow(-1) { connect( DB::ImageDB::instance(), SIGNAL(imagesDeleted(DB::FileNameList)), this, SLOT(imagesDeletedFromDB(DB::FileNameList)) ); m_ImagePlaceholder = QIcon::fromTheme( QLatin1String("image-x-generic") ).pixmap( cellGeometryInfo()->preferredIconSize() ); m_VideoPlaceholder = QIcon::fromTheme( QLatin1String("video-x-generic") ).pixmap( cellGeometryInfo()->preferredIconSize() ); + m_filter.setSearchMode(0); } static bool stackOrderComparator(const DB::FileName& a, const DB::FileName& b) { return a.info()->stackOrder() < b.info()->stackOrder(); } void ThumbnailView::ThumbnailModel::updateDisplayModel() { beginResetModel(); ImageManager::AsyncLoader::instance()->stop( model(), ImageManager::StopOnlyNonPriorityLoads ); // Note, this can be simplified, if we make the database backend already // return things in the right order. Then we only need one pass while now // we need to go through the list two times. /* Extract all stacks we have first. Different stackid's might be * intermingled in the result so we need to know this ahead before * creating the display list. */ typedef QList StackList; typedef QMap StackMap; StackMap stackContents; Q_FOREACH(const DB::FileName& fileName, m_imageList) { DB::ImageInfoPtr imageInfo = fileName.info(); if ( imageInfo && imageInfo->isStacked() ) { DB::StackID stackid = imageInfo->stackId(); stackContents[stackid].append(fileName); } } /* * All stacks need to be ordered in their stack order. We don't rely that * the images actually came in the order necessary. */ for (StackMap::iterator it = stackContents.begin(); it != stackContents.end(); ++it) { std::stable_sort(it->begin(), it->end(), stackOrderComparator); } /* Build the final list to be displayed. That is basically the sequence * we got from the original, but the stacks shown with all images together * in the right sequence or collapsed showing only the top image. */ m_displayList = DB::FileNameList(); QSet alreadyShownStacks; Q_FOREACH( const DB::FileName& fileName, m_imageList) { DB::ImageInfoPtr imageInfo = fileName.info(); + if (!m_filter.match(imageInfo)) + continue; if ( imageInfo && imageInfo->isStacked()) { DB::StackID stackid = imageInfo->stackId(); if (alreadyShownStacks.contains(stackid)) continue; StackMap::iterator found = stackContents.find(stackid); Q_ASSERT(found != stackContents.end()); const StackList& orderedStack = *found; if (m_expandedStacks.contains(stackid)) { Q_FOREACH( const DB::FileName& fileName, orderedStack) { m_displayList.append(fileName); } } else { m_displayList.append(orderedStack.at(0)); } alreadyShownStacks.insert(stackid); } else { m_displayList.append(fileName); } } if ( m_sortDirection != OldestFirst ) m_displayList = m_displayList.reversed(); updateIndexCache(); emit collapseAllStacksEnabled( m_expandedStacks.size() > 0); emit expandAllStacksEnabled( m_allStacks.size() != model()->m_expandedStacks.size() ); endResetModel(); } void ThumbnailView::ThumbnailModel::toggleStackExpansion(const DB::FileName& fileName) { DB::ImageInfoPtr imageInfo = fileName.info(); if (imageInfo) { DB::StackID stackid = imageInfo->stackId(); model()->beginResetModel(); if (m_expandedStacks.contains(stackid)) m_expandedStacks.remove(stackid); else m_expandedStacks.insert(stackid); updateDisplayModel(); model()->endResetModel(); } } void ThumbnailView::ThumbnailModel::collapseAllStacks() { m_expandedStacks.clear(); updateDisplayModel(); } void ThumbnailView::ThumbnailModel::expandAllStacks() { m_expandedStacks = m_allStacks; updateDisplayModel(); } void ThumbnailView::ThumbnailModel::setImageList(const DB::FileNameList& items) { m_imageList = items; m_allStacks.clear(); Q_FOREACH( const DB::FileName& fileName, items) { DB::ImageInfoPtr info = fileName.info(); if ( info && info->isStacked() ) m_allStacks << info->stackId(); } updateDisplayModel(); preloadThumbnails(); } // TODO(hzeller) figure out if this should return the m_imageList or m_displayList. DB::FileNameList ThumbnailView::ThumbnailModel::imageList(Order order) const { if ( order == SortedOrder && m_sortDirection == NewestFirst ) return m_displayList.reversed(); else return m_displayList; } void ThumbnailView::ThumbnailModel::imagesDeletedFromDB( const DB::FileNameList& list ) { SelectionMaintainer dummy(widget(),model()); Q_FOREACH( const DB::FileName& fileName, list ) { m_displayList.removeAll(fileName); m_imageList.removeAll(fileName); } updateDisplayModel(); } int ThumbnailView::ThumbnailModel::indexOf(const DB::FileName& fileName) { Q_ASSERT( !fileName.isNull() ); if ( !m_fileNameToIndex.contains(fileName) ) m_fileNameToIndex.insert(fileName, m_displayList.indexOf(fileName)); return m_fileNameToIndex[fileName]; } int ThumbnailView::ThumbnailModel::indexOf(const DB::FileName& fileName) const { Q_ASSERT( !fileName.isNull() ); if ( !m_fileNameToIndex.contains(fileName) ) return -1; return m_fileNameToIndex[fileName]; } void ThumbnailView::ThumbnailModel::updateIndexCache() { m_fileNameToIndex.clear(); int index = 0; Q_FOREACH( const DB::FileName& fileName, m_displayList) { m_fileNameToIndex[fileName] = index; ++index; } } DB::FileName ThumbnailView::ThumbnailModel::rightDropItem() const { return m_rightDrop; } void ThumbnailView::ThumbnailModel::setRightDropItem( const DB::FileName& item ) { m_rightDrop = item; } DB::FileName ThumbnailView::ThumbnailModel::leftDropItem() const { return m_leftDrop; } void ThumbnailView::ThumbnailModel::setLeftDropItem( const DB::FileName& item ) { m_leftDrop = item; } void ThumbnailView::ThumbnailModel::setSortDirection( SortDirection direction ) { if ( direction == m_sortDirection ) return; Settings::SettingsData::instance()->setShowNewestFirst( direction == NewestFirst ); m_displayList = m_displayList.reversed(); updateIndexCache(); m_sortDirection = direction; } bool ThumbnailView::ThumbnailModel::isItemInExpandedStack( const DB::StackID& id ) const { return m_expandedStacks.contains(id); } int ThumbnailView::ThumbnailModel::imageCount() const { return m_displayList.size(); } void ThumbnailView::ThumbnailModel::setOverrideImage(const DB::FileName& fileName, const QPixmap &pixmap) { if ( pixmap.isNull() ) m_overrideFileName = DB::FileName(); else { m_overrideFileName = fileName; m_overrideImage = pixmap; } emit dataChanged( fileNameToIndex(fileName), fileNameToIndex(fileName)); } DB::FileName ThumbnailView::ThumbnailModel::imageAt( int index ) const { Q_ASSERT( index >= 0 && index < imageCount() ); return m_displayList.at(index); } int ThumbnailView::ThumbnailModel::rowCount(const QModelIndex&) const { return imageCount(); } QVariant ThumbnailView::ThumbnailModel::data(const QModelIndex& index, int role ) const { if ( !index.isValid() || index.row() >= m_displayList.size()) return QVariant(); if ( role == Qt::DecorationRole ) { const DB::FileName fileName = m_displayList.at(index.row()); return pixmap( fileName ); } if ( role == Qt::DisplayRole ) return thumbnailText( index ); return QVariant(); } void ThumbnailView::ThumbnailModel::requestThumbnail( const DB::FileName& fileName, const ImageManager::Priority priority ) { DB::ImageInfoPtr imageInfo = fileName.info(); if ( !imageInfo ) return; // request the thumbnail in the size that is set in the settings, not in the current grid size: const QSize cellSize = cellGeometryInfo()->baseIconSize(); const int angle = imageInfo->angle(); const int row = indexOf(fileName); ThumbnailRequest* request = new ThumbnailRequest( row, fileName, cellSize, angle, this ); request->setPriority( priority ); ImageManager::AsyncLoader::instance()->load( request ); } void ThumbnailView::ThumbnailModel::pixmapLoaded(ImageManager::ImageRequest* request, const QImage& /*image*/) { const DB::FileName fileName = request->databaseFileName(); const QSize fullSize = request->fullSize(); // As a result of the image being loaded, we emit the dataChanged signal, which in turn asks the delegate to paint the cell // The delegate now fetches the newly loaded image from the cache. DB::ImageInfoPtr imageInfo = fileName.info(); // TODO(hzeller): figure out, why the size is set here. We do an implicit // write here to the database. if ( fullSize.isValid() && imageInfo ) { imageInfo->setSize( fullSize ); } emit dataChanged(fileNameToIndex(fileName), fileNameToIndex(fileName)); } QString ThumbnailView::ThumbnailModel::thumbnailText( const QModelIndex& index ) const { const DB::FileName fileName = imageAt( index.row() ); QString text; const QSize cellSize = cellGeometryInfo()->preferredIconSize(); const int thumbnailHeight = cellSize.height() - 2 * Settings::SettingsData::instance()->thumbnailSpace(); const int thumbnailWidth = cellSize.width(); // no subtracting here const int maxCharacters = thumbnailHeight / QFontMetrics( widget()->font() ).maxWidth() * 2; if ( Settings::SettingsData::instance()->displayLabels()) { QString line = fileName.info()->label(); if ( QFontMetrics( widget()->font() ).width( line ) > thumbnailWidth ) { line = line.left( maxCharacters ); line += QString::fromLatin1( " ..." ); } text += line + QString::fromLatin1("\n"); } if ( Settings::SettingsData::instance()->displayCategories()) { QStringList grps = fileName.info()->availableCategories(); for( QStringList::const_iterator it = grps.constBegin(); it != grps.constEnd(); ++it ) { QString category = *it; if ( category != i18n( "Folder" ) && category != i18n( "Media Type" ) ) { Utilities::StringSet items = fileName.info()->itemsOfCategory( category ); if (Settings::SettingsData::instance()->hasUntaggedCategoryFeatureConfigured() && ! Settings::SettingsData::instance()->untaggedImagesTagVisible()) { if (category == Settings::SettingsData::instance()->untaggedCategory()) { if (items.contains(Settings::SettingsData::instance()->untaggedTag())) { items.remove(Settings::SettingsData::instance()->untaggedTag()); } } } if (!items.empty()) { QString line; bool first = true; for( Utilities::StringSet::const_iterator it2 = items.begin(); it2 != items.end(); ++it2 ) { QString item = *it2; if ( first ) first = false; else line += QString::fromLatin1( ", " ); line += item; } if ( QFontMetrics( widget()->font() ).width( line ) > thumbnailWidth ) { line = line.left( maxCharacters ); line += QString::fromLatin1( " ..." ); } text += line + QString::fromLatin1( "\n" ); } } } } if(text.isEmpty()) text = QString::fromLatin1( "" ); return text.trimmed(); } void ThumbnailView::ThumbnailModel::updateCell( int row ) { updateCell( index( row, 0 ) ); } void ThumbnailView::ThumbnailModel::updateCell( const QModelIndex& index ) { emit dataChanged( index, index ); } void ThumbnailView::ThumbnailModel::updateCell( const DB::FileName& fileName ) { updateCell( indexOf(fileName) ); } QModelIndex ThumbnailView::ThumbnailModel::fileNameToIndex( const DB::FileName& fileName ) const { if ( fileName.isNull() ) return QModelIndex(); else return index( indexOf(fileName), 0 ); } QPixmap ThumbnailView::ThumbnailModel::pixmap( const DB::FileName& fileName ) const { if ( m_overrideFileName == fileName) return m_overrideImage; const DB::ImageInfoPtr imageInfo = fileName.info(); if (imageInfo == DB::ImageInfoPtr(nullptr) ) return QPixmap(); if ( ImageManager::ThumbnailCache::instance()->contains( fileName ) ) { // the cached thumbnail needs to be scaled to the actual thumbnail size: return ImageManager::ThumbnailCache::instance()->lookup( fileName ).scaled( cellGeometryInfo()->preferredIconSize(), Qt::KeepAspectRatio ); } const_cast(this)->requestThumbnail( fileName, ImageManager::ThumbnailVisible ); if ( imageInfo->isVideo() ) return m_VideoPlaceholder; else return m_ImagePlaceholder; } bool ThumbnailView::ThumbnailModel::thumbnailStillNeeded( int row ) const { return ( row >= m_firstVisibleRow && row <= m_lastVisibleRow ); } void ThumbnailView::ThumbnailModel::updateVisibleRowInfo() { m_firstVisibleRow = widget()->indexAt( QPoint(0,0) ).row(); const int columns = widget()->width() / cellGeometryInfo()->cellSize().width(); const int rows = widget()->height() / cellGeometryInfo()->cellSize().height(); m_lastVisibleRow = qMin(m_firstVisibleRow + columns*(rows+1), rowCount(QModelIndex())); // the cellGeometry has changed -> update placeholders m_ImagePlaceholder = QIcon::fromTheme( QLatin1String("image-x-generic") ).pixmap( cellGeometryInfo()->preferredIconSize() ); m_VideoPlaceholder = QIcon::fromTheme( QLatin1String("video-x-generic") ).pixmap( cellGeometryInfo()->preferredIconSize() ); } +void ThumbnailView::ThumbnailModel::clearFilter() +{ + if (!m_filter.isNull()) + { + m_filter = DB::ImageSearchInfo(); + emit filterChanged(); + } +} + +void ThumbnailView::ThumbnailModel::setFilter(DB::ImageSearchInfo filter) +{ + m_filter = filter; + emit filterChanged(); +} + void ThumbnailView::ThumbnailModel::preloadThumbnails() { // FIXME: it would make a lot of sense to merge preloadThumbnails() with pixmap() // and maybe also move the caching stuff into the ImageManager Q_FOREACH( const DB::FileName& fileName, m_displayList) { if ( fileName.isNull() ) continue; if ( ImageManager::ThumbnailCache::instance()->contains( fileName ) ) continue; const_cast(this)->requestThumbnail( fileName, ImageManager::ThumbnailInvisible ); } } // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/ThumbnailView/ThumbnailModel.h b/ThumbnailView/ThumbnailModel.h index ad14f7e3..b1408d03 100644 --- a/ThumbnailView/ThumbnailModel.h +++ b/ThumbnailView/ThumbnailModel.h @@ -1,158 +1,165 @@ /* Copyright (C) 2003-2010 Jesper K. Pedersen 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef THUMBNAILMODEL_H #define THUMBNAILMODEL_H #include #include #include #include +#include #include #include #include #include namespace ThumbnailView { class ThumbnailFactory; class ThumbnailModel :public QAbstractListModel, public ImageManager::ImageClientInterface, private ThumbnailComponent { Q_OBJECT public: explicit ThumbnailModel( ThumbnailFactory* factory ); // -------------------------------------------------- QAbstractListModel using QAbstractListModel::beginResetModel; using QAbstractListModel::endResetModel; int rowCount(const QModelIndex&) const override; QVariant data(const QModelIndex&, int) const override; QString thumbnailText( const QModelIndex& index ) const; void updateCell( int row ); void updateCell( const QModelIndex& index ); void updateCell( const DB::FileName& id ); // -------------------------------------------------- ImageClient API void pixmapLoaded(ImageManager::ImageRequest* request, const QImage& image) override; bool thumbnailStillNeeded( int row ) const; //-------------------------------------------------- Drag and Drop of items DB::FileName rightDropItem() const; void setRightDropItem( const DB::FileName& item ); DB::FileName leftDropItem() const; void setLeftDropItem( const DB::FileName& item ); //-------------------------------------------------- Stack void toggleStackExpansion(const DB::FileName& id); void collapseAllStacks(); void expandAllStacks(); bool isItemInExpandedStack( const DB::StackID& id ) const; //-------------------------------------------------- Position Information DB::FileName imageAt( int index ) const; int indexOf(const DB::FileName& fileName ) const; int indexOf( const DB::FileName& fileName ); QModelIndex fileNameToIndex( const DB::FileName& fileName ) const; //-------------------------------------------------- Images void setImageList(const DB::FileNameList& list); DB::FileNameList imageList(Order) const; int imageCount() const; void setOverrideImage( const DB::FileName& fileName, const QPixmap& pixmap ); //-------------------------------------------------- Misc. void updateDisplayModel(); void updateIndexCache(); void setSortDirection( SortDirection ); QPixmap pixmap( const DB::FileName& fileName ) const; public slots: void updateVisibleRowInfo(); + void clearFilter(); + void setFilter(DB::ImageSearchInfo filter); + signals: void collapseAllStacksEnabled(bool enabled); void expandAllStacksEnabled(bool enabled); void selectionChanged(int numberOfItemsSelected); + void filterChanged(); private: // Methods void requestThumbnail( const DB::FileName& mediaId, const ImageManager::Priority priority ); void preloadThumbnails(); private slots: void imagesDeletedFromDB( const DB::FileNameList& ); private: // Instance variables. /** * The list of images shown. The difference between m_imageList and * m_displayList is that m_imageList contains all the images given to us, * while m_displayList only includes those that currently should be * shown, ie. it exclude images from stacks that are collapsed and thus * not visible. */ DB::FileNameList m_displayList; /** The input list for images. See documentation for m_displayList */ DB::FileNameList m_imageList; /** * File which should have drop indication point drawn on its left side */ DB::FileName m_leftDrop; /** * File which should have drop indication point drawn on its right side */ DB::FileName m_rightDrop; SortDirection m_sortDirection; /** * All the stacks that should be shown expanded */ QSet m_expandedStacks; /** @short Store stack IDs for all images in current list * * Used by expandAllStacks. */ QSet m_allStacks; /** * A map mapping from Id to its index in m_displayList. */ QMap m_fileNameToIndex; int m_firstVisibleRow; int m_lastVisibleRow; DB::FileName m_overrideFileName; QPixmap m_overrideImage; // placeholder pixmaps to be displayed before thumbnails are loaded: QPixmap m_ImagePlaceholder; QPixmap m_VideoPlaceholder; + + DB::ImageSearchInfo m_filter; }; } #endif /* THUMBNAILMODEL_H */ // vi:expandtab:tabstop=4 shiftwidth=4: