X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/84010807786c352aaeb2320caf27e5f9048d8dec..d6e10a5942442f8423385ff1301c9163b334e4ed:/src/kitemviews/kfileitemmodel.h diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index 654c7dbeb..d48f600df 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,15 @@ class QTimer; * * Also the recursive expansion of sub-directories is supported by * KFileItemModel::setExpanded(). + * + * TODO: In the longterm instead of passing a KDirLister just an URL should + * be passed and a KDirLister used internally. This solves the following issues: + * - The user of the API does not need to decide whether he listens to KDirLister + * or KFileItemModel. + * - It resolves minor conceptual differences between KDirLister and KFileItemModel. + * E.g. there is no way for KFileItemModel to check whether a completed() signal + * will be emitted after newItems() will be send by KDirLister or not (in the case + * of setShowingDotFiles() no completed() signal will get emitted). */ class LIBDOLPHINPRIVATE_EXPORT KFileItemModel : public KItemModelBase { @@ -52,23 +62,39 @@ public: virtual int count() const; virtual QHash data(int index) const; - virtual bool setData(int index, const QHash &values); + virtual bool setData(int index, const QHash& values); /** - * @return True - * @reimp + * Sets a separate sorting with folders first (true) or a mixed sorting of files and folders (false). */ - virtual bool supportsGrouping() const; + void setSortFoldersFirst(bool foldersFirst); + bool sortFoldersFirst() const; + + void setShowHiddenFiles(bool show); + bool showHiddenFiles() const; /** - * @return True - * @reimp + * If set to true, only folders are shown as items of the model. Files + * are ignored. */ - virtual bool supportsSorting() const; + void setShowFoldersOnly(bool enabled); + bool showFoldersOnly() const; /** @reimp */ virtual QMimeData* createMimeData(const QSet& indexes) const; + /** @reimp */ + virtual int indexForKeyboardSearch(const QString& text, int startFromIndex = 0) const; + + /** @reimp */ + virtual bool supportsDropping(int index) const; + + /** @reimp */ + virtual QString roleDescription(const QByteArray& typeForRole) const; + + /** @reimp */ + virtual QList > groups() const; + /** * @return The file-item for the index \a index. If the index is in a valid * range it is assured that the file-item is not null. The runtime @@ -76,6 +102,13 @@ public: */ KFileItem fileItem(int index) const; + /** + * @return The file-item for the url \a url. If no file-item with the given + * URL is found KFileItem::isNull() will be true for the returned + * file-item. The runtime complexity of this call is O(1). + */ + KFileItem fileItem(const KUrl& url) const; + /** * @return The index for the file-item \a item. -1 is returned if no file-item * is found or if the file-item is null. The runtime @@ -83,6 +116,17 @@ public: */ int index(const KFileItem& item) const; + /** + * @return The index for the URL \a url. -1 is returned if no file-item + * is found. The runtime complexity of this call is O(1). + */ + int index(const KUrl& url) const; + + /** + * @return Root item of all items. + */ + KFileItem rootItem() const; + /** * Clears all items of the model. */ @@ -92,55 +136,160 @@ public: void setRoles(const QSet& roles); QSet roles() const; - bool setExpanded(int index, bool expanded); - bool isExpanded(int index) const; - bool isExpandable(int index) const; + virtual bool setExpanded(int index, bool expanded); + virtual bool isExpanded(int index) const; + virtual bool isExpandable(int index) const; + virtual int expandedParentsCount(int index) const; + + QSet expandedUrls() const; + + /** + * Marks the URLs in \a urls as subfolders which were expanded previously. + * They are re-expanded one by one each time the KDirLister's completed() signal is received. + * Note that a manual triggering of the KDirLister is required. + */ + void restoreExpandedUrls(const QSet& urls); + + /** + * Expands all parent-items of \a url. + */ + void expandParentItems(const KUrl& url); + + void setNameFilter(const QString& nameFilter); + QString nameFilter() const; + + struct RoleInfo + { QByteArray role; + QString translation; + QString group; + }; + + static QList rolesInformation(); + +signals: + /** + * Is emitted after the loading of a directory has been completed or new + * items have been inserted to an already loaded directory. Usually + * one or more itemsInserted() signals are emitted before loadingCompleted() + * (the only exception is loading an empty directory, where only a + * loadingCompleted() signal gets emitted). + */ + void loadingCompleted(); protected: - virtual void onGroupRoleChanged(const QByteArray& current, const QByteArray& previous); + virtual void onGroupedSortingChanged(bool current); virtual void onSortRoleChanged(const QByteArray& current, const QByteArray& previous); + virtual void onSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); private slots: + /** + * Resorts all items dependent on the set sortRole(), sortOrder() + * and foldersFirst() settings. + */ + void resortAllItems(); + void slotCompleted(); void slotCanceled(); void slotNewItems(const KFileItemList& items); void slotItemsDeleted(const KFileItemList& items); + void slotRefreshItems(const QList >& items); void slotClear(); void slotClear(const KUrl& url); + void slotNaturalSortingChanged(); - void dispatchPendingItems(); + void dispatchPendingItemsToInsert(); private: + enum RoleType { + // User visible roles: + NoRole, NameRole, SizeRole, DateRole, PermissionsRole, OwnerRole, + GroupRole, TypeRole, DestinationRole, PathRole, + // User visible roles available with Nepomuk: + CommentRole, TagsRole, RatingRole, ImageSizeRole, OrientationRole, + WordCountRole, LineCountRole, ArtistRole, AlbumRole, DurationRole, TrackRole, + CopiedFromRole, + // Non-visible roles: + IsDirRole, IsExpandedRole, IsExpandableRole, ExpandedParentsCountRole, + // Mandatory last entry: + RolesCount + }; + + struct ItemData + { + KFileItem item; + QHash values; + ItemData* parent; + }; + void insertItems(const KFileItemList& items); void removeItems(const KFileItemList& items); - void removeExpandedItems(); + /** + * Helper method for insertItems() and removeItems(): Creates + * a list of ItemData elements based on the given items. + * Note that the ItemData instances are created dynamically and + * must be deleted by the caller. + */ + QList createItemDataList(const KFileItemList& items) const; - enum Role { - NoRole, - NameRole, - SizeRole, - DateRole, - PermissionsRole, - OwnerRole, - GroupRole, - TypeRole, - DestinationRole, - PathRole, - IsDirRole, - IsExpandedRole, - ExpansionLevelRole, - RolesCount // Mandatory last entry - }; + void removeExpandedItems(); + /** + * Resets all values from m_requestRole to false. + */ void resetRoles(); - Role roleIndex(const QByteArray& role) const; + /** + * @return Role-type for the given role. + * Runtime complexity is O(1). + */ + RoleType typeForRole(const QByteArray& role) const; + + /** + * @return Role-byte-array for the given role-type. + * Runtime complexity is O(1). + */ + QByteArray roleForType(RoleType roleType) const; QHash retrieveData(const KFileItem& item) const; - bool lessThan(const KFileItem& a, const KFileItem& b) const; - void sort(const KFileItemList::iterator& start, const KFileItemList::iterator& end); + /** + * @return True if the item-data \a a should be ordered before the item-data + * \b. The item-data may have different parent-items. + */ + bool lessThan(const ItemData* a, const ItemData* b) const; + + /** + * Helper method for lessThan() and expandedParentsCountCompare(): Compares + * the passed item-data using m_sortRole as criteria. Both items must + * have the same parent item, otherwise the comparison will be wrong. + */ + int sortRoleCompare(const ItemData* a, const ItemData* b) const; + + /** + * Sorts the items by using lessThan() as comparison criteria. + * The merge sort algorithm is used to assure a worst-case + * of O(n * log(n)) and to keep the number of comparisons low. + */ + void sort(QList::iterator begin, QList::iterator end); + + /** Helper method for sort(). */ + void merge(QList::iterator begin, + QList::iterator pivot, + QList::iterator end); + + /** Helper method for sort(). */ + QList::iterator lowerBound(QList::iterator begin, + QList::iterator end, + const ItemData* value); + + /** Helper method for sort(). */ + QList::iterator upperBound(QList::iterator begin, + QList::iterator end, + const ItemData* value); + /** Helper method for sort(). */ + void reverse(QList::iterator begin, QList::iterator end); + int stringCompare(const QString& a, const QString& b) const; /** @@ -149,10 +298,10 @@ private: * is not sufficient, it is also important to check the hierarchy for having * a correct order like shown in a tree. */ - int expansionLevelsCompare(const KFileItem& a, const KFileItem& b) const; + int expandedParentsCountCompare(const ItemData* a, const ItemData* b) const; /** - * Helper method for expansionLevelCompare(). + * Helper method for expandedParentsCountCompare(). */ QString subPath(const KFileItem& item, const QString& itemPath, @@ -161,35 +310,104 @@ private: bool useMaximumUpdateInterval() const; + QList > nameRoleGroups() const; + QList > sizeRoleGroups() const; + QList > dateRoleGroups() const; + QList > permissionRoleGroups() const; + QList > ratingRoleGroups() const; + QList > genericStringRoleGroups(const QByteArray& typeForRole) const; + + /** + * Helper method for all xxxRoleGroups() methods to check whether the + * item with the given index is a child-item. A child-item is defined + * as item having an expansion-level > 0. All xxxRoleGroups() methods + * should skip the grouping if the item is a child-item (although + * KItemListView would be capable to show sub-groups in groups this + * results in visual clutter for most usecases). + */ + bool isChildItem(int index) const; + + /** + * @return Recursive list of child items that have \a item as upper most parent. + */ + KFileItemList childItems(const KFileItem& item) const; + + /** + * Maps the QByteArray-roles to RoleTypes and provides translation- and + * group-contexts. + */ + struct RoleInfoMap + { + const char* const role; + const RoleType roleType; + const char* const roleTranslationContext; + const char* const roleTranslation; + const char* const groupTranslationContext; + const char* const groupTranslation; + }; + + /** + * @return Map of user visible roles that are accessible by KFileItemModel::rolesInformation(). + */ + static const RoleInfoMap* rolesInfoMap(int& count); + private: QWeakPointer m_dirLister; bool m_naturalSorting; bool m_sortFoldersFirst; - Role m_groupRole; - Role m_sortRole; + RoleType m_sortRole; + QSet m_roles; Qt::CaseSensitivity m_caseSensitivity; - KFileItemList m_sortedItems; // Allows O(1) access for KFileItemModel::fileItem(int index) - QHash m_items; // Allows O(1) access for KFileItemModel::index(const KFileItem& item) - QList > m_data; + QList m_itemData; + QHash m_items; // Allows O(1) access for KFileItemModel::index(const KFileItem& item) + + KFileItemModelFilter m_filter; + QSet m_filteredItems; // Items that got hidden by KFileItemModel::setNameFilter() bool m_requestRole[RolesCount]; QTimer* m_minimumUpdateIntervalTimer; QTimer* m_maximumUpdateIntervalTimer; + QTimer* m_resortAllItemsTimer; KFileItemList m_pendingItemsToInsert; - KFileItemList m_pendingItemsToDelete; + bool m_pendingEmitLoadingCompleted; + + // Cache for KFileItemModel::groups() + mutable QList > m_groups; // Stores the smallest expansion level of the root-URL. Is required to calculate - // the "expansionLevel" role in an efficient way. A value < 0 indicates that - // it has not been initialized yet. - mutable int m_rootExpansionLevel; + // the "expandedParentsCount" role in an efficient way. A value < 0 indicates a + // special meaning: + enum ExpandedParentsCountRootTypes + { + // m_expandedParentsCountRoot is uninitialized and must be determined by checking + // the root URL from the KDirLister. + UninitializedExpandedParentsCountRoot = -1, + // All items should be forced to get an expanded parents count of 0 even if they + // represent child items. This is useful for slaves that provide no parent items + // for child items like e.g. the search IO slaves. + ForceExpandedParentsCountRoot = -2 + }; + mutable int m_expandedParentsCountRoot; + + // Stores the URLs of the expanded folders. + QSet m_expandedUrls; + + // URLs that must be expanded. The expanding is initially triggered in setExpanded() + // and done step after step in slotCompleted(). + QSet m_urlsToExpand; friend class KFileItemModelTest; // For unit testing }; +inline bool KFileItemModel::isChildItem(int index) const +{ + return m_requestRole[ExpandedParentsCountRole] && m_itemData.at(index)->values.value("expandedParentsCount").toInt() > 0; +} + #endif