File indexing completed on 2024-04-28 05:45:05
0001 /* 0002 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef KFILEITEMMODELROLESUPDATER_H 0008 #define KFILEITEMMODELROLESUPDATER_H 0009 0010 #include "dolphin_export.h" 0011 #include "kitemviews/kitemmodelbase.h" 0012 0013 #include <list> 0014 0015 #include "config-dolphin.h" 0016 #include <KFileItem> 0017 0018 #include <QObject> 0019 #include <QSet> 0020 #include <QSize> 0021 #include <QStringList> 0022 0023 class KDirectoryContentsCounter; 0024 class KFileItemModel; 0025 class QPixmap; 0026 class QTimer; 0027 class KOverlayIconPlugin; 0028 0029 namespace KIO 0030 { 0031 class PreviewJob; 0032 } 0033 0034 #if HAVE_BALOO 0035 namespace Baloo 0036 { 0037 class FileMonitor; 0038 } 0039 #include <Baloo/IndexerConfig> 0040 #endif 0041 0042 /** 0043 * @brief Resolves expensive roles asynchronously and applies them to the KFileItemModel. 0044 * 0045 * KFileItemModel only resolves roles that are inexpensive like e.g. the file name or 0046 * the permissions. Creating previews or determining the MIME-type can be quite expensive 0047 * and KFileItemModelRolesUpdater takes care to update such roles asynchronously. 0048 * 0049 * To prevent a huge CPU and I/O load, these roles are not updated for all 0050 * items, but only for the visible items, some items around the visible area, 0051 * and the items on the first and last pages of the view. This is a compromise 0052 * that aims to minimize the risk that the user sees items with unknown icons 0053 * in the view when scrolling or pressing Home or End. 0054 * 0055 * Determining the roles is done in several phases: 0056 * 0057 * 1. If the sort role is "slow", it is determined for all items. If this 0058 * cannot be finished synchronously in 200 ms, the remaining items are 0059 * handled asynchronously by \a resolveNextSortRole(). 0060 * 0061 * 2. The function startUpdating(), which is called if either the sort role 0062 * has been successfully determined for all items, or items are inserted 0063 * in the view, or the visible items might have changed because items 0064 * were removed or moved, tries to determine the icons for all visible 0065 * items synchronously for 200 ms. Then: 0066 * 0067 * (a) If previews are disabled, icons and all other roles are determined 0068 * asynchronously for the interesting items. This is done by the 0069 * function \a resolveNextPendingRoles(). 0070 * 0071 * (b) If previews are enabled, a \a KIO::PreviewJob is started that loads 0072 * the previews for the interesting items. At the same time, the icons 0073 * for these items are determined asynchronously as fast as possible 0074 * by \a resolveNextPendingRoles(). This minimizes the risk that the 0075 * user sees "unknown" icons when scrolling before the previews have 0076 * arrived. 0077 * 0078 * 3. Finally, the entire process is repeated for any items that might have 0079 * changed in the mean time. 0080 */ 0081 class DOLPHIN_EXPORT KFileItemModelRolesUpdater : public QObject 0082 { 0083 Q_OBJECT 0084 0085 public: 0086 explicit KFileItemModelRolesUpdater(KFileItemModel *model, QObject *parent = nullptr); 0087 ~KFileItemModelRolesUpdater() override; 0088 0089 void setIconSize(const QSize &size); 0090 QSize iconSize() const; 0091 0092 void setDevicePixelRatio(qreal devicePixelRatio); 0093 qreal devicePixelRatio() const; 0094 0095 /** 0096 * Sets the range of items that are visible currently. The roles 0097 * of visible items are resolved first. 0098 */ 0099 void setVisibleIndexRange(int index, int count); 0100 0101 void setMaximumVisibleItems(int count); 0102 0103 /** 0104 * If \a show is set to true, the "iconPixmap" role will be filled with a preview 0105 * of the file. If \a show is false the MIME type icon will be used for the "iconPixmap" 0106 * role. 0107 */ 0108 void setPreviewsShown(bool show); 0109 bool previewsShown() const; 0110 0111 /** 0112 * If enabled a small preview gets upscaled to the icon size in case where 0113 * the icon size is larger than the preview. Per default enlarging is 0114 * enabled. 0115 */ 0116 void setEnlargeSmallPreviews(bool enlarge); 0117 bool enlargeSmallPreviews() const; 0118 0119 /** 0120 * If \a paused is set to true the asynchronous resolving of roles will be paused. 0121 * State changes during pauses like changing the icon size or the preview-shown 0122 * will be remembered and handled after unpausing. 0123 */ 0124 void setPaused(bool paused); 0125 bool isPaused() const; 0126 0127 /** 0128 * Sets the roles that should be resolved asynchronously. 0129 */ 0130 void setRoles(const QSet<QByteArray> &roles); 0131 QSet<QByteArray> roles() const; 0132 0133 /** 0134 * Sets the list of enabled thumbnail plugins that are used for previews. 0135 * Per default all plugins enabled in the KConfigGroup "PreviewSettings" 0136 * are used. 0137 * 0138 * For a list of available plugins, call KIO::PreviewJob::availableThumbnailerPlugins(). 0139 * 0140 * @see enabledPlugins 0141 */ 0142 void setEnabledPlugins(const QStringList &list); 0143 0144 /** 0145 * Returns the list of enabled thumbnail plugins. 0146 * @see setEnabledPlugins 0147 */ 0148 QStringList enabledPlugins() const; 0149 0150 /** 0151 * Sets the maximum file size of local files for which 0152 * previews will be generated (if enabled). A value of 0 0153 * indicates no file size limit. 0154 * Per default the value from KConfigGroup "PreviewSettings" 0155 * MaximumSize is used, 0 otherwise. 0156 * @param size 0157 */ 0158 void setLocalFileSizePreviewLimit(qlonglong size); 0159 qlonglong localFileSizePreviewLimit() const; 0160 0161 /** 0162 * If set to true, directories contents are scanned to determine their size 0163 * Default true 0164 */ 0165 void setScanDirectories(bool enabled); 0166 bool scanDirectories() const; 0167 0168 /** 0169 * Notifies the updater of a change in the hover state on an item. 0170 * 0171 * This will trigger asynchronous loading of the next few thumb sequence images 0172 * using a PreviewJob. 0173 * 0174 * @param item URL of the item that is hovered, or an empty URL if no item is hovered. 0175 * @param seqIdx The current hover sequence index. While an item is hovered, 0176 * this method will be called repeatedly with increasing values 0177 * for this parameter. 0178 */ 0179 void setHoverSequenceState(const QUrl &itemUrl, int seqIdx); 0180 0181 private Q_SLOTS: 0182 void slotItemsInserted(const KItemRangeList &itemRanges); 0183 void slotItemsRemoved(const KItemRangeList &itemRanges); 0184 void slotItemsMoved(KItemRange itemRange, const QList<int> &movedToIndexes); 0185 void slotItemsChanged(const KItemRangeList &itemRanges, const QSet<QByteArray> &roles); 0186 void slotSortRoleChanged(const QByteArray ¤t, const QByteArray &previous); 0187 0188 /** 0189 * Is invoked after a preview has been received successfully. 0190 * 0191 * Note that this is not called for hover sequence previews. 0192 * 0193 * @see startPreviewJob() 0194 */ 0195 void slotGotPreview(const KFileItem &item, const QPixmap &pixmap); 0196 0197 /** 0198 * Is invoked after generating a preview has failed. 0199 * 0200 * Note that this is not called for hover sequence previews. 0201 * 0202 * @see startPreviewJob() 0203 */ 0204 void slotPreviewFailed(const KFileItem &item); 0205 0206 /** 0207 * Is invoked when the preview job has been finished. Starts a new preview 0208 * job if there are any interesting items without previews left, or updates 0209 * the changed items otherwise. 0210 * 0211 * Note that this is not called for hover sequence previews. 0212 * 0213 * @see startPreviewJob() 0214 */ 0215 void slotPreviewJobFinished(); 0216 0217 /** 0218 * Is invoked after a hover sequence preview has been received successfully. 0219 */ 0220 void slotHoverSequenceGotPreview(const KFileItem &item, const QPixmap &pixmap); 0221 0222 /** 0223 * Is invoked after generating a hover sequence preview has failed. 0224 */ 0225 void slotHoverSequencePreviewFailed(const KFileItem &item); 0226 0227 /** 0228 * Is invoked when a hover sequence preview job is finished. May start another 0229 * job for the next sequence index right away by calling 0230 * \a loadNextHoverSequencePreview(). 0231 * 0232 * Note that a PreviewJob will only ever generate a single sequence image, due 0233 * to limitations of the PreviewJob API. 0234 */ 0235 void slotHoverSequencePreviewJobFinished(); 0236 0237 /** 0238 * Is invoked when one of the KOverlayIconPlugin emit the signal that an overlay has changed 0239 */ 0240 void slotOverlaysChanged(const QUrl &url, const QStringList &); 0241 0242 /** 0243 * Resolves the sort role of the next item in m_pendingSortRole, applies it 0244 * to the model, and invokes itself if there are any pending items left. If 0245 * that is not the case, \a startUpdating() is called. 0246 */ 0247 void resolveNextSortRole(); 0248 0249 /** 0250 * Resolves the icon name and (if previews are disabled) all other roles 0251 * for the next interesting item. If there are no pending items left, any 0252 * changed items are updated. 0253 */ 0254 void resolveNextPendingRoles(); 0255 0256 /** 0257 * Resolves items that have not been resolved yet after the change has been 0258 * notified by slotItemsChanged(). Is invoked if the m_changedItemsTimer 0259 * expires. 0260 */ 0261 void resolveRecentlyChangedItems(); 0262 0263 void applyChangedBalooRoles(const QString &file); 0264 void applyChangedBalooRolesForItem(const KFileItem &file); 0265 0266 void slotDirectoryContentsCountReceived(const QString &path, int count, long long size); 0267 0268 private: 0269 /** 0270 * Starts the updating of all roles. The visible items are handled first. 0271 */ 0272 void startUpdating(); 0273 0274 /** 0275 * Loads the icons for the visible items. After 200 ms, the function 0276 * stops determining mime types and only loads preliminary icons. 0277 * This is a compromise that prevents that 0278 * (a) the GUI is blocked for more than 200 ms, and 0279 * (b) "unknown" icons could be shown in the view. 0280 */ 0281 void updateVisibleIcons(); 0282 0283 /** 0284 * Creates previews for the items starting from the first item in 0285 * m_pendingPreviewItems. 0286 * @see slotGotPreview() 0287 * @see slotPreviewFailed() 0288 * @see slotPreviewJobFinished() 0289 */ 0290 void startPreviewJob(); 0291 0292 /** 0293 * Transforms a raw preview image, applying scale and frame. 0294 * 0295 * @param pixmap A raw preview image from a PreviewJob. 0296 * @return The scaled and decorated preview image. 0297 */ 0298 QPixmap transformPreviewPixmap(const QPixmap &pixmap); 0299 0300 /** 0301 * Starts a PreviewJob for loading the next hover sequence image. 0302 */ 0303 void loadNextHoverSequencePreview(); 0304 0305 /** 0306 * Aborts the currently running hover sequence PreviewJob (if any). 0307 */ 0308 void killHoverSequencePreviewJob(); 0309 0310 /** 0311 * Ensures that icons, previews, and other roles are determined for any 0312 * items that have been changed. 0313 */ 0314 void updateChangedItems(); 0315 0316 /** 0317 * Resolves the sort role of the item and applies it to the model. 0318 */ 0319 void applySortRole(int index); 0320 0321 void applySortProgressToModel(); 0322 0323 enum ResolveHint { ResolveFast, ResolveAll }; 0324 bool applyResolvedRoles(int index, ResolveHint hint); 0325 QHash<QByteArray, QVariant> rolesData(const KFileItem &item, int index); 0326 0327 /** 0328 * Must be invoked if a property has been changed that affects 0329 * the look of the preview. Takes care to update all previews. 0330 */ 0331 void updateAllPreviews(); 0332 0333 void killPreviewJob(); 0334 0335 QList<int> indexesToResolve() const; 0336 0337 void trimHoverSequenceLoadedItems(); 0338 0339 private: 0340 /** 0341 * enqueue directory size counting for KFileItem item at index 0342 */ 0343 void startDirectorySizeCounting(const KFileItem &item, int index); 0344 0345 enum State { Idle, Paused, ResolvingSortRole, ResolvingAllRoles, PreviewJobRunning }; 0346 0347 State m_state; 0348 0349 // Property changes during pausing must be remembered to be able 0350 // to react when unpausing again: 0351 bool m_previewChangedDuringPausing; 0352 bool m_iconSizeChangedDuringPausing; 0353 bool m_rolesChangedDuringPausing; 0354 0355 // Property for setPreviewsShown()/previewsShown(). 0356 bool m_previewShown; 0357 0358 // Property for setEnlargeSmallPreviews()/enlargeSmallPreviews() 0359 bool m_enlargeSmallPreviews; 0360 0361 // True if the role "iconPixmap" should be cleared when resolving the next 0362 // role with resolveRole(). Is necessary if the preview gets disabled 0363 // during the roles-updater has been paused by setPaused(). 0364 bool m_clearPreviews; 0365 0366 // Remembers which items have been handled already, to prevent that 0367 // previews and other expensive roles are determined again. 0368 QSet<KFileItem> m_finishedItems; 0369 0370 KFileItemModel *m_model; 0371 QSize m_iconSize; 0372 qreal m_devicePixelRatio; 0373 int m_firstVisibleIndex; 0374 int m_lastVisibleIndex; 0375 int m_maximumVisibleItems; 0376 QSet<QByteArray> m_roles; 0377 QSet<QByteArray> m_resolvableRoles; 0378 QStringList m_enabledPlugins; 0379 qulonglong m_localFileSizePreviewLimit; 0380 0381 // Items for which the sort role still has to be determined. 0382 QSet<KFileItem> m_pendingSortRoleItems; 0383 0384 // Indexes of items which still have to be handled by 0385 // resolveNextPendingRoles(). 0386 QList<int> m_pendingIndexes; 0387 0388 // Items which have been left over from the last call of startPreviewJob(). 0389 // A new preview job will be started from them once the first one finishes. 0390 KFileItemList m_pendingPreviewItems; 0391 0392 KIO::PreviewJob *m_previewJob; 0393 0394 // Info about the item that the user currently hovers, and the current sequence 0395 // index for thumb generation. 0396 KFileItem m_hoverSequenceItem; 0397 int m_hoverSequenceIndex; 0398 KIO::PreviewJob *m_hoverSequencePreviewJob; 0399 int m_hoverSequenceNumSuccessiveFailures; 0400 std::list<KFileItem> m_hoverSequenceLoadedItems; 0401 0402 // When downloading or copying large files, the slot slotItemsChanged() 0403 // will be called periodically within a quite short delay. To prevent 0404 // a high CPU-load by generating e.g. previews for each notification, the update 0405 // will be postponed until no file change has been done within a longer period 0406 // of time. 0407 QTimer *m_recentlyChangedItemsTimer; 0408 QSet<KFileItem> m_recentlyChangedItems; 0409 0410 // Items which have not been changed repeatedly recently. 0411 QSet<KFileItem> m_changedItems; 0412 0413 KDirectoryContentsCounter *m_directoryContentsCounter; 0414 0415 QList<KOverlayIconPlugin *> m_overlayIconsPlugin; 0416 0417 #if HAVE_BALOO 0418 Baloo::FileMonitor *m_balooFileMonitor; 0419 Baloo::IndexerConfig m_balooConfig; 0420 #endif 0421 }; 0422 0423 #endif