diff --git a/Browser/AbstractCategoryModel.cpp b/Browser/AbstractCategoryModel.cpp index 909fcc3f..b6d52acb 100644 --- a/Browser/AbstractCategoryModel.cpp +++ b/Browser/AbstractCategoryModel.cpp @@ -1,152 +1,163 @@ -/* Copyright (C) 2003-2010 Jesper K. Pedersen +/* 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 "AbstractCategoryModel.h" #include "BrowserWidget.h" #include #include #include #include #include #include "enums.h" Browser::AbstractCategoryModel::AbstractCategoryModel( const DB::CategoryPtr& category, const DB::ImageSearchInfo& info ) : m_category( category ), m_info( info ) { m_images = DB::ImageDB::instance()->classify( info, m_category->name(), DB::Image ); m_videos = DB::ImageDB::instance()->classify( info, m_category->name(), DB::Video ); } bool Browser::AbstractCategoryModel::hasNoneEntry() const { int imageCount = m_images[DB::ImageDB::NONE()].count; int videoCount = m_videos[DB::ImageDB::NONE()].count; return (imageCount + videoCount != 0); } QString Browser::AbstractCategoryModel::text( const QString& name ) const { if ( name == DB::ImageDB::NONE() ) { if ( m_info.categoryMatchText(m_category->name()).length() == 0 ) return i18nc("As in No persons, no locations etc.", "None" ); else return i18nc("As in no other persons, or no other locations. ", "No other" ); } else { if (m_category->type() == DB::Category::FolderCategory) { QRegExp rx( QString::fromLatin1( "(.*/)(.*)$") ); QString value = name; value.replace( rx, QString::fromLatin1("\\2") ); return value; } else { return name; } } } QPixmap Browser::AbstractCategoryModel::icon( const QString& name ) const { const int size = m_category->thumbnailSize(); if ( BrowserWidget::isResizing() ) { QPixmap res( size, size * Settings::SettingsData::instance()->getThumbnailAspectRatio() ); res.fill( Qt::white ); return res; } if ( m_category->viewType() == DB::Category::TreeView || m_category->viewType() == DB::Category::IconView ) { if (DB::ImageDB::instance()->memberMap().isGroup(m_category->name(), name)) { return QIcon::fromTheme(QString::fromUtf8("folder-image")).pixmap(22); } else { return m_category->icon(); } } else { // The category images are screenshot from the size of the viewer (Which might very well be considered a bug) // This is the reason for asking for the thumbnail height being 3/4 of its width. return m_category->categoryImage( m_category->name(), name, size, size * Settings::SettingsData::instance()->getThumbnailAspectRatio() ); } } QVariant Browser::AbstractCategoryModel::data( const QModelIndex & index, int role) const { if ( !index.isValid() ) return QVariant(); const QString name = indexToName( index ); const int column = index.column(); if ( role == Qt::DisplayRole ) { switch( column ) { case 0: return text(name); case 1: return i18ncp("@item:intable number of images with a specific tag.","1 image", "%1 images", m_images[name].count); case 2: return i18ncp("@item:intable number of videos with a specific tag.","1 video", "%1 videos", m_videos[name].count); case 3: { DB::ImageDate range = m_images[name].range; range.extendTo(m_videos[name].range); - return range.toString(false); + return DB::ImageDate(range.start()).toString(false); + } + case 4: { + DB::ImageDate range = m_images[name].range; + range.extendTo(m_videos[name].range); + return DB::ImageDate(range.end()).toString(false); } } } else if ( role == Qt::DecorationRole && column == 0) { return icon( name ); } else if ( role == Qt::ToolTipRole ) return text(name); else if ( role == ItemNameRole ) return name; else if ( role == ValueRole ) { switch ( column ) { case 0: return name; // Notice we sort by **None** rather than None, which makes it show up at the top for less than searches. case 1: return m_images[name].count; case 2: return m_videos[name].count; case 3: { DB::ImageDate range = m_images[name].range; range.extendTo(m_videos[name].range); return range.start().toSecsSinceEpoch(); } + case 4: { + DB::ImageDate range = m_images[name].range; + range.extendTo(m_videos[name].range); + return range.end().toSecsSinceEpoch(); + } } } return QVariant(); } Qt::ItemFlags Browser::AbstractCategoryModel::flags( const QModelIndex& index ) const { return index.isValid() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::ItemFlags(); } QVariant Browser::AbstractCategoryModel::headerData( int section, Qt::Orientation orientation, int role) const { if ( orientation == Qt::Vertical || role != Qt::DisplayRole ) return QVariant(); switch ( section ) { case 0: return m_category->name(); case 1: return i18n("Images"); case 2: return i18n("Videos"); - case 3: return i18n("Date range"); + case 3: return i18n("Start Date"); + case 4: return i18n("End Date"); } return QVariant(); } // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/Browser/TreeCategoryModel.cpp b/Browser/TreeCategoryModel.cpp index efb62cfa..e9bb356f 100644 --- a/Browser/TreeCategoryModel.cpp +++ b/Browser/TreeCategoryModel.cpp @@ -1,252 +1,252 @@ -/* Copyright (C) 2003-2015 Jesper K. Pedersen +/* 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. */ // Qt includes #include // Local includes #include "TreeCategoryModel.h" #include "DB/ImageDB.h" #include "DB/CategoryItem.h" #include "DB/Category.h" #include "MainWindow/DirtyIndicator.h" struct Browser::TreeCategoryModel::Data { Data(const QString& name) : name(name), parent(nullptr) { } ~Data() { qDeleteAll(children); } void addChild(Data* child) { child->parent = this; children.append(child); } QString name; QList children; Data* parent; }; Browser::TreeCategoryModel::TreeCategoryModel(const DB::CategoryPtr& category, const DB::ImageSearchInfo& info) : AbstractCategoryModel(category, info) { m_data = new Data(QString()); createData(m_category->itemsCategories().data(), 0); if (hasNoneEntry()) { Data* data = new Data(DB::ImageDB::NONE()); data->parent = m_data; m_data->children.prepend(data); } m_memberMap = DB::ImageDB::instance()->memberMap(); } int Browser::TreeCategoryModel::rowCount(const QModelIndex& index) const { return indexToData(index)->children.count(); } int Browser::TreeCategoryModel::columnCount(const QModelIndex&) const { - return 4; + return 5; } QModelIndex Browser::TreeCategoryModel::index(int row, int column, const QModelIndex& parent) const { const Data* data = indexToData(parent); QList children = data->children; int size = children.count(); if ( row >= size || row < 0 || column >= columnCount(parent) || column < 0) { // Invalid index return QModelIndex(); } else { return createIndex(row, column, children[row]); } } QModelIndex Browser::TreeCategoryModel::parent(const QModelIndex& index) const { Data* me = indexToData(index); if (me == m_data) { return QModelIndex(); } Data* parent = me->parent; if (parent == m_data) { return QModelIndex(); } Data* grandParent = parent->parent; return createIndex(grandParent->children.indexOf(parent), 0, parent); } Browser::TreeCategoryModel::~TreeCategoryModel() { delete m_data; } bool Browser::TreeCategoryModel::createData(DB::CategoryItem* parentCategoryItem, Data* parent) { const QString name = parentCategoryItem->mp_name; const int imageCount = m_images.contains(name) ? m_images[name].count : 0; const int videoCount = m_videos.contains(name) ? m_videos[name].count : 0; Data* myData = new Data(name); bool anyItems = imageCount != 0 || videoCount != 0; for(QList::ConstIterator subCategoryIt = parentCategoryItem->mp_subcategories.constBegin(); subCategoryIt != parentCategoryItem->mp_subcategories.constEnd(); ++subCategoryIt) { anyItems = createData(*subCategoryIt, myData) || anyItems; } if (parent) { if (anyItems) { parent->addChild(myData); } else { delete myData; } } else { m_data = myData; } return anyItems; } Browser::TreeCategoryModel::Data* Browser::TreeCategoryModel::indexToData(const QModelIndex& index) const { if (! index.isValid()) { return m_data; } else { return static_cast(index.internalPointer()); } } QString Browser::TreeCategoryModel::indexToName(const QModelIndex& index) const { const Browser::TreeCategoryModel::Data* data = indexToData(index); return data->name; } Qt::DropActions Browser::TreeCategoryModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::ItemFlags Browser::TreeCategoryModel::flags(const QModelIndex& index) const { Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); if ( m_category->isSpecialCategory() || indexToName(index) == QString::fromUtf8("**NONE**")) { return defaultFlags; } if (indexToData(index)->parent != nullptr) { return defaultFlags | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } else if (index.column() == -1) { return defaultFlags | Qt::ItemIsDropEnabled; } else { return defaultFlags | Qt::ItemIsDragEnabled; } } QStringList Browser::TreeCategoryModel::mimeTypes() const { return QStringList() << QString::fromUtf8("x-kphotoalbum/x-browser-tag-drag"); } QMimeData* Browser::TreeCategoryModel::mimeData(const QModelIndexList& indexes) const { QMimeData* mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); // only use the first index, even if more than one are selected: stream << indexToName(indexes[0]); if (! indexes[0].parent().isValid()) { stream << QString(); } else { stream << indexToName(indexes[0].parent()); } mimeData->setData(QString::fromUtf8("x-kphotoalbum/x-browser-tag-drag"), encodedData); return mimeData; } Browser::TreeCategoryModel::tagData Browser::TreeCategoryModel::getDroppedTagData(QByteArray& encodedData) { QDataStream stream(&encodedData, QIODevice::ReadOnly); Browser::TreeCategoryModel::tagData droppedTagData; stream >> droppedTagData.tagName; stream >> droppedTagData.tagGroup; return droppedTagData; } bool Browser::TreeCategoryModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int, int, const QModelIndex& parent) { if (action == Qt::IgnoreAction) { return true; } const QString thisCategory = indexToName(parent); QByteArray encodedData = data->data(QString::fromUtf8("x-kphotoalbum/x-browser-tag-drag")); Browser::TreeCategoryModel::tagData droppedTagData = getDroppedTagData(encodedData); // the difference between a CopyAction and a MoveAction is that with the MoveAction, // we have to remove the tag from its current group first if (action == Qt::MoveAction) { // Remove the tag from its group and remove the group if it's empty now m_memberMap.removeMemberFromGroup(m_category->name(), droppedTagData.tagGroup, droppedTagData.tagName); if (m_memberMap.members(m_category->name(), droppedTagData.tagGroup, true) == QStringList()) { m_memberMap.deleteGroup(m_category->name(), droppedTagData.tagGroup); } } if (parent.isValid()) { // Check if the tag is dropped onto a copy of itself const DB::CategoryItemPtr categoryInfo = m_category->itemsCategories(); if (thisCategory == droppedTagData.tagName || categoryInfo->isDescendentOf(thisCategory, droppedTagData.tagName) ) { return true; } // Add the tag to a group, create it if we don't have it yet if (! m_memberMap.groups(m_category->name()).contains(thisCategory)) { m_memberMap.addGroup(m_category->name(), thisCategory); DB::ImageDB::instance()->memberMap() = m_memberMap; } m_memberMap.addMemberToGroup(m_category->name(), thisCategory, droppedTagData.tagName); } DB::ImageDB::instance()->memberMap() = m_memberMap; MainWindow::DirtyIndicator::markDirty(); emit(dataChanged()); return true; } // vi:expandtab:tabstop=4 shiftwidth=4: