diff --git a/CMakeLists.txt b/CMakeLists.txt index 38fd26bf3..5a39d6288 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,141 +1,141 @@ cmake_minimum_required(VERSION 3.0) # KDE Application Version, managed by release script set (KDE_APPLICATIONS_VERSION_MAJOR "18") set (KDE_APPLICATIONS_VERSION_MINOR "03") set (KDE_APPLICATIONS_VERSION_MICRO "70") set (KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}.${KDE_APPLICATIONS_VERSION_MICRO}") project(Dolphin VERSION ${KDE_APPLICATIONS_VERSION}) set(QT_MIN_VERSION "5.5.0") -set(KF5_MIN_VERSION "5.37.0") +set(KF5_MIN_VERSION "5.40.0") set(ECM_MIN_VERSION "1.6.0") # ECM setup find_package(ECM ${ECM_MIN_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) include(ECMSetupVersion) include(ECMGenerateHeaders) include(ECMPackageConfigHelpers) include(GenerateExportHeader) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) ecm_setup_version(${KDE_APPLICATIONS_VERSION} VARIABLE_PREFIX DOLPHIN VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/src/dolphin_version.h" ) ecm_setup_version("5.0.0" VARIABLE_PREFIX DOLPHINVCS VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/dolphinvcs_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/DolphinVcsConfigVersion.cmake" SOVERSION 5 ) ecm_setup_version("5.0.0" VARIABLE_PREFIX DOLPHINPRIVATE SOVERSION 5 ) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Concurrent Widgets Gui DBus ) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS DocTools Init KCMUtils NewStuff CoreAddons I18n DBusAddons Bookmarks Config KIO Parts Solid IconThemes Completion TextWidgets Notifications Crash ) find_package(KF5 ${KF5_MIN_VERSION} OPTIONAL_COMPONENTS Activities ) find_package(Phonon4Qt5 CONFIG REQUIRED) find_package(KF5Baloo 4.97) set_package_properties(KF5Baloo PROPERTIES DESCRIPTION "Baloo Core libraries" URL "http://www.kde.org" TYPE OPTIONAL PURPOSE "For adding desktop-wide search and tagging support to dolphin" ) find_package(KF5BalooWidgets 4.97) set_package_properties(KF5BalooWidgets PROPERTIES DESCRIPTION "Baloos Widgets" URL "http://www.kde.org" TYPE OPTIONAL ) find_package(KF5FileMetaData 5.19.0) set_package_properties(KF5FileMetaData PROPERTIES URL "https://projects.kde.org/kfilemetadata" TYPE OPTIONAL PURPOSE "For accessing file metadata labels" ) if (KF5Baloo_FOUND AND KF5BalooWidgets_FOUND AND KF5FileMetaData_FOUND) message(STATUS "Baloo packages are found") set(HAVE_BALOO TRUE) else() find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS KDELibs4Support # for KFileMetaDataWidget ) endif() add_definitions(-DQT_NO_URL_CAST_FROM_STRING) add_subdirectory(src) add_subdirectory(doc) # CMake files set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/DolphinVcs") ecm_configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/DolphinVcsConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/DolphinVcsConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/DolphinVcsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/DolphinVcsConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT DolphinVcsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE DolphinVcsTargets.cmake ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/dolphinvcs_version.h" DESTINATION "${KDE_INSTALL_INCLUDEDIR}/Dolphin" COMPONENT Devel ) configure_file(org.kde.dolphin.FileManager1.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.dolphin.FileManager1.service) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.dolphin.FileManager1.service DESTINATION ${DBUS_SERVICES_INSTALL_DIR}) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index 0d7f98311..8ea106a5e 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -1,1205 +1,1205 @@ /*************************************************************************** * Copyright (C) 2011 by Peter Penz * * * * 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 "kfileitemmodelrolesupdater.h" #include "kfileitemmodel.h" #include #include #include #include #include #include #include #include #include #include #include "private/kpixmapmodifier.h" #include "private/kdirectorycontentscounter.h" #include #include #include #include #include #include #ifdef HAVE_BALOO #include "private/kbaloorolesprovider.h" #include #include #endif // #define KFILEITEMMODELROLESUPDATER_DEBUG namespace { // Maximum time in ms that the KFileItemModelRolesUpdater // may perform a blocking operation const int MaxBlockTimeout = 200; // If the number of items is smaller than ResolveAllItemsLimit, // the roles of all items will be resolved. const int ResolveAllItemsLimit = 500; // Not only the visible area, but up to ReadAheadPages before and after // this area will be resolved. const int ReadAheadPages = 5; } KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QObject* parent) : QObject(parent), m_state(Idle), m_previewChangedDuringPausing(false), m_iconSizeChangedDuringPausing(false), m_rolesChangedDuringPausing(false), m_previewShown(false), m_enlargeSmallPreviews(true), m_clearPreviews(false), m_finishedItems(), m_model(model), m_iconSize(), m_firstVisibleIndex(0), m_lastVisibleIndex(-1), m_maximumVisibleItems(50), m_roles(), m_resolvableRoles(), m_enabledPlugins(), m_pendingSortRoleItems(), m_pendingIndexes(), m_pendingPreviewItems(), m_previewJob(), m_recentlyChangedItemsTimer(0), m_recentlyChangedItems(), m_changedItems(), m_directoryContentsCounter(0) #ifdef HAVE_BALOO , m_balooFileMonitor(0) #endif { Q_ASSERT(model); const KConfigGroup globalConfig(KSharedConfig::openConfig(), "PreviewSettings"); - m_enabledPlugins = globalConfig.readEntry("Plugins", QStringList() - << QStringLiteral("directorythumbnail") - << QStringLiteral("imagethumbnail") - << QStringLiteral("jpegthumbnail")); + m_enabledPlugins = globalConfig.readEntry("Plugins", QStringList()); + if (m_enabledPlugins.isEmpty()) { + m_enabledPlugins = KIO::PreviewJob::defaultPlugins(); + } connect(m_model, &KFileItemModel::itemsInserted, this, &KFileItemModelRolesUpdater::slotItemsInserted); connect(m_model, &KFileItemModel::itemsRemoved, this, &KFileItemModelRolesUpdater::slotItemsRemoved); connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); connect(m_model, &KFileItemModel::itemsMoved, this, &KFileItemModelRolesUpdater::slotItemsMoved); connect(m_model, &KFileItemModel::sortRoleChanged, this, &KFileItemModelRolesUpdater::slotSortRoleChanged); // Use a timer to prevent that each call of slotItemsChanged() results in a synchronous // resolving of the roles. Postpone the resolving until no update has been done for 1 second. m_recentlyChangedItemsTimer = new QTimer(this); m_recentlyChangedItemsTimer->setInterval(1000); m_recentlyChangedItemsTimer->setSingleShot(true); connect(m_recentlyChangedItemsTimer, &QTimer::timeout, this, &KFileItemModelRolesUpdater::resolveRecentlyChangedItems); m_resolvableRoles.insert("size"); m_resolvableRoles.insert("type"); m_resolvableRoles.insert("isExpandable"); #ifdef HAVE_BALOO m_resolvableRoles += KBalooRolesProvider::instance().roles(); #endif m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this); connect(m_directoryContentsCounter, &KDirectoryContentsCounter::result, this, &KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived); auto plugins = KPluginLoader::instantiatePlugins(QStringLiteral("kf5/overlayicon"), nullptr, qApp); foreach (QObject *it, plugins) { auto plugin = qobject_cast(it); if (plugin) { m_overlayIconsPlugin.append(plugin); connect(plugin, &KOverlayIconPlugin::overlaysChanged, this, &KFileItemModelRolesUpdater::slotOverlaysChanged); } else { // not our/valid plugin, so delete the created object it->deleteLater(); } } } KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater() { killPreviewJob(); } void KFileItemModelRolesUpdater::setIconSize(const QSize& size) { if (size != m_iconSize) { m_iconSize = size; if (m_state == Paused) { m_iconSizeChangedDuringPausing = true; } else if (m_previewShown) { // An icon size change requires the regenerating of // all previews m_finishedItems.clear(); startUpdating(); } } } QSize KFileItemModelRolesUpdater::iconSize() const { return m_iconSize; } void KFileItemModelRolesUpdater::setVisibleIndexRange(int index, int count) { if (index < 0) { index = 0; } if (count < 0) { count = 0; } if (index == m_firstVisibleIndex && count == m_lastVisibleIndex - m_firstVisibleIndex + 1) { // The range has not been changed return; } m_firstVisibleIndex = index; m_lastVisibleIndex = qMin(index + count - 1, m_model->count() - 1); startUpdating(); } void KFileItemModelRolesUpdater::setMaximumVisibleItems(int count) { m_maximumVisibleItems = count; } void KFileItemModelRolesUpdater::setPreviewsShown(bool show) { if (show == m_previewShown) { return; } m_previewShown = show; if (!show) { m_clearPreviews = true; } updateAllPreviews(); } bool KFileItemModelRolesUpdater::previewsShown() const { return m_previewShown; } void KFileItemModelRolesUpdater::setEnlargeSmallPreviews(bool enlarge) { if (enlarge != m_enlargeSmallPreviews) { m_enlargeSmallPreviews = enlarge; if (m_previewShown) { updateAllPreviews(); } } } bool KFileItemModelRolesUpdater::enlargeSmallPreviews() const { return m_enlargeSmallPreviews; } void KFileItemModelRolesUpdater::setEnabledPlugins(const QStringList& list) { if (m_enabledPlugins != list) { m_enabledPlugins = list; if (m_previewShown) { updateAllPreviews(); } } } void KFileItemModelRolesUpdater::setPaused(bool paused) { if (paused == (m_state == Paused)) { return; } if (paused) { m_state = Paused; killPreviewJob(); } else { const bool updatePreviews = (m_iconSizeChangedDuringPausing && m_previewShown) || m_previewChangedDuringPausing; const bool resolveAll = updatePreviews || m_rolesChangedDuringPausing; if (resolveAll) { m_finishedItems.clear(); } m_iconSizeChangedDuringPausing = false; m_previewChangedDuringPausing = false; m_rolesChangedDuringPausing = false; if (!m_pendingSortRoleItems.isEmpty()) { m_state = ResolvingSortRole; resolveNextSortRole(); } else { m_state = Idle; } startUpdating(); } } void KFileItemModelRolesUpdater::setRoles(const QSet& roles) { if (m_roles != roles) { m_roles = roles; #ifdef HAVE_BALOO // Check whether there is at least one role that must be resolved // with the help of Baloo. If this is the case, a (quite expensive) // resolving will be done in KFileItemModelRolesUpdater::rolesData() and // the role gets watched for changes. const KBalooRolesProvider& rolesProvider = KBalooRolesProvider::instance(); bool hasBalooRole = false; QSetIterator it(roles); while (it.hasNext()) { const QByteArray& role = it.next(); if (rolesProvider.roles().contains(role)) { hasBalooRole = true; break; } } if (hasBalooRole && m_balooConfig.fileIndexingEnabled() && !m_balooFileMonitor) { m_balooFileMonitor = new Baloo::FileMonitor(this); connect(m_balooFileMonitor, &Baloo::FileMonitor::fileMetaDataChanged, this, &KFileItemModelRolesUpdater::applyChangedBalooRoles); } else if (!hasBalooRole && m_balooFileMonitor) { delete m_balooFileMonitor; m_balooFileMonitor = 0; } #endif if (m_state == Paused) { m_rolesChangedDuringPausing = true; } else { startUpdating(); } } } QSet KFileItemModelRolesUpdater::roles() const { return m_roles; } bool KFileItemModelRolesUpdater::isPaused() const { return m_state == Paused; } QStringList KFileItemModelRolesUpdater::enabledPlugins() const { return m_enabledPlugins; } void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRanges) { QElapsedTimer timer; timer.start(); // Determine the sort role synchronously for as many items as possible. if (m_resolvableRoles.contains(m_model->sortRole())) { int insertedCount = 0; foreach (const KItemRange& range, itemRanges) { const int lastIndex = insertedCount + range.index + range.count - 1; for (int i = insertedCount + range.index; i <= lastIndex; ++i) { if (timer.elapsed() < MaxBlockTimeout) { applySortRole(i); } else { m_pendingSortRoleItems.insert(m_model->fileItem(i)); } } insertedCount += range.count; } applySortProgressToModel(); // If there are still items whose sort role is unknown, check if the // asynchronous determination of the sort role is already in progress, // and start it if that is not the case. if (!m_pendingSortRoleItems.isEmpty() && m_state != ResolvingSortRole) { killPreviewJob(); m_state = ResolvingSortRole; resolveNextSortRole(); } } startUpdating(); } void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRanges) { Q_UNUSED(itemRanges); const bool allItemsRemoved = (m_model->count() == 0); #ifdef HAVE_BALOO if (m_balooFileMonitor) { // Don't let the FileWatcher watch for removed items if (allItemsRemoved) { m_balooFileMonitor->clear(); } else { QStringList newFileList; foreach (const QString& file, m_balooFileMonitor->files()) { if (m_model->index(QUrl::fromLocalFile(file)) >= 0) { newFileList.append(file); } } m_balooFileMonitor->setFiles(newFileList); } } #endif if (allItemsRemoved) { m_state = Idle; m_finishedItems.clear(); m_pendingSortRoleItems.clear(); m_pendingIndexes.clear(); m_pendingPreviewItems.clear(); m_recentlyChangedItems.clear(); m_recentlyChangedItemsTimer->stop(); m_changedItems.clear(); killPreviewJob(); } else { // Only remove the items from m_finishedItems. They will be removed // from the other sets later on. QSet::iterator it = m_finishedItems.begin(); while (it != m_finishedItems.end()) { if (m_model->index(*it) < 0) { it = m_finishedItems.erase(it); } else { ++it; } } // The visible items might have changed. startUpdating(); } } void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, QList movedToIndexes) { Q_UNUSED(itemRange); Q_UNUSED(movedToIndexes); // The visible items might have changed. startUpdating(); } void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList& itemRanges, const QSet& roles) { Q_UNUSED(roles); // Find out if slotItemsChanged() has been done recently. If that is the // case, resolving the roles is postponed until a timer has exceeded // to prevent expensive repeated updates if files are updated frequently. const bool itemsChangedRecently = m_recentlyChangedItemsTimer->isActive(); QSet& targetSet = itemsChangedRecently ? m_recentlyChangedItems : m_changedItems; foreach (const KItemRange& itemRange, itemRanges) { int index = itemRange.index; for (int count = itemRange.count; count > 0; --count) { const KFileItem item = m_model->fileItem(index); targetSet.insert(item); ++index; } } m_recentlyChangedItemsTimer->start(); if (!itemsChangedRecently) { updateChangedItems(); } } void KFileItemModelRolesUpdater::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous) { Q_UNUSED(current); Q_UNUSED(previous); if (m_resolvableRoles.contains(current)) { m_pendingSortRoleItems.clear(); m_finishedItems.clear(); const int count = m_model->count(); QElapsedTimer timer; timer.start(); // Determine the sort role synchronously for as many items as possible. for (int index = 0; index < count; ++index) { if (timer.elapsed() < MaxBlockTimeout) { applySortRole(index); } else { m_pendingSortRoleItems.insert(m_model->fileItem(index)); } } applySortProgressToModel(); if (!m_pendingSortRoleItems.isEmpty()) { // Trigger the asynchronous determination of the sort role. killPreviewJob(); m_state = ResolvingSortRole; resolveNextSortRole(); } } else { m_state = Idle; m_pendingSortRoleItems.clear(); applySortProgressToModel(); } } void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPixmap& pixmap) { if (m_state != PreviewJobRunning) { return; } m_changedItems.remove(item); const int index = m_model->index(item); if (index < 0) { return; } QPixmap scaledPixmap = pixmap; const QString mimeType = item.mimetype(); const int slashIndex = mimeType.indexOf(QLatin1Char('/')); const bool isFontPreview = mimeType.right(slashIndex).contains(QLatin1String("font")); const bool isFolderPreview = item.isDir(); const bool isWindowsExePreview = mimeType == QLatin1String("application/x-ms-dos-executable") || mimeType == QLatin1String("application/x-msdownload"); if (!isFolderPreview && !isFontPreview && !isWindowsExePreview) { if (m_enlargeSmallPreviews) { KPixmapModifier::applyFrame(scaledPixmap, m_iconSize); } else { // Assure that small previews don't get enlarged. Instead they // should be shown centered within the frame. const QSize contentSize = KPixmapModifier::sizeInsideFrame(m_iconSize); const bool enlargingRequired = scaledPixmap.width() < contentSize.width() && scaledPixmap.height() < contentSize.height(); if (enlargingRequired) { QSize frameSize = scaledPixmap.size() / scaledPixmap.devicePixelRatio(); frameSize.scale(m_iconSize, Qt::KeepAspectRatio); QPixmap largeFrame(frameSize); largeFrame.fill(Qt::transparent); KPixmapModifier::applyFrame(largeFrame, frameSize); QPainter painter(&largeFrame); painter.drawPixmap((largeFrame.width() - scaledPixmap.width() / scaledPixmap.devicePixelRatio()) / 2, (largeFrame.height() - scaledPixmap.height() / scaledPixmap.devicePixelRatio()) / 2, scaledPixmap); scaledPixmap = largeFrame; } else { // The image must be shrinked as it is too large to fit into // the available icon size KPixmapModifier::applyFrame(scaledPixmap, m_iconSize); } } } else { KPixmapModifier::scale(scaledPixmap, m_iconSize); } QHash data = rolesData(item); const QStringList overlays = data["iconOverlays"].toStringList(); // Strangely KFileItem::overlays() returns empty string-values, so // we need to check first whether an overlay must be drawn at all. // It is more efficient to do it here, as KIconLoader::drawOverlays() // assumes that an overlay will be drawn and has some additional // setup time. foreach (const QString& overlay, overlays) { if (!overlay.isEmpty()) { // There is at least one overlay, draw all overlays above m_pixmap // and cancel the check KIconLoader::global()->drawOverlays(overlays, scaledPixmap, KIconLoader::Desktop); break; } } data.insert("iconPixmap", scaledPixmap); disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_finishedItems.insert(item); } void KFileItemModelRolesUpdater::slotPreviewFailed(const KFileItem& item) { if (m_state != PreviewJobRunning) { return; } m_changedItems.remove(item); const int index = m_model->index(item); if (index >= 0) { QHash data; data.insert("iconPixmap", QPixmap()); disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); applyResolvedRoles(index, ResolveAll); m_finishedItems.insert(item); } } void KFileItemModelRolesUpdater::slotPreviewJobFinished() { m_previewJob = 0; if (m_state != PreviewJobRunning) { return; } m_state = Idle; if (!m_pendingPreviewItems.isEmpty()) { startPreviewJob(); } else { if (!m_changedItems.isEmpty()) { updateChangedItems(); } } } void KFileItemModelRolesUpdater::resolveNextSortRole() { if (m_state != ResolvingSortRole) { return; } QSet::iterator it = m_pendingSortRoleItems.begin(); while (it != m_pendingSortRoleItems.end()) { const KFileItem item = *it; const int index = m_model->index(item); // Continue if the sort role has already been determined for the // item, and the item has not been changed recently. if (!m_changedItems.contains(item) && m_model->data(index).contains(m_model->sortRole())) { it = m_pendingSortRoleItems.erase(it); continue; } applySortRole(index); m_pendingSortRoleItems.erase(it); break; } if (!m_pendingSortRoleItems.isEmpty()) { applySortProgressToModel(); QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextSortRole); } else { m_state = Idle; // Prevent that we try to update the items twice. disconnect(m_model, &KFileItemModel::itemsMoved, this, &KFileItemModelRolesUpdater::slotItemsMoved); applySortProgressToModel(); connect(m_model, &KFileItemModel::itemsMoved, this, &KFileItemModelRolesUpdater::slotItemsMoved); startUpdating(); } } void KFileItemModelRolesUpdater::resolveNextPendingRoles() { if (m_state != ResolvingAllRoles) { return; } while (!m_pendingIndexes.isEmpty()) { const int index = m_pendingIndexes.takeFirst(); const KFileItem item = m_model->fileItem(index); if (m_finishedItems.contains(item)) { continue; } applyResolvedRoles(index, ResolveAll); m_finishedItems.insert(item); m_changedItems.remove(item); break; } if (!m_pendingIndexes.isEmpty()) { QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextPendingRoles); } else { m_state = Idle; if (m_clearPreviews) { // Only go through the list if there are items which might still have previews. if (m_finishedItems.count() != m_model->count()) { QHash data; data.insert("iconPixmap", QPixmap()); disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); for (int index = 0; index <= m_model->count(); ++index) { if (m_model->data(index).contains("iconPixmap")) { m_model->setData(index, data); } } connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); } m_clearPreviews = false; } if (!m_changedItems.isEmpty()) { updateChangedItems(); } } } void KFileItemModelRolesUpdater::resolveRecentlyChangedItems() { m_changedItems += m_recentlyChangedItems; m_recentlyChangedItems.clear(); updateChangedItems(); } void KFileItemModelRolesUpdater::applyChangedBalooRoles(const QString& file) { #ifdef HAVE_BALOO const KFileItem item = m_model->fileItem(QUrl::fromLocalFile(file)); if (item.isNull()) { // itemUrl is not in the model anymore, probably because // the corresponding file has been deleted in the meantime. return; } applyChangedBalooRolesForItem(item); #endif } void KFileItemModelRolesUpdater::applyChangedBalooRolesForItem(const KFileItem &item) { #ifdef HAVE_BALOO Baloo::File file(item.localPath()); file.load(); const KBalooRolesProvider& rolesProvider = KBalooRolesProvider::instance(); QHash data; foreach (const QByteArray& role, rolesProvider.roles()) { // Overwrite all the role values with an empty QVariant, because the roles // provider doesn't overwrite it when the property value list is empty. // See bug 322348 data.insert(role, QVariant()); } QHashIterator it(rolesProvider.roleValues(file, m_roles)); while (it.hasNext()) { it.next(); data.insert(it.key(), it.value()); } disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); const int index = m_model->index(item); m_model->setData(index, data); connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); #else #ifndef Q_CC_MSVC Q_UNUSED(item); #endif #endif } void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count) { const bool getSizeRole = m_roles.contains("size"); const bool getIsExpandableRole = m_roles.contains("isExpandable"); if (getSizeRole || getIsExpandableRole) { const int index = m_model->index(QUrl::fromLocalFile(path)); if (index >= 0) { QHash data; if (getSizeRole) { data.insert("size", count); } if (getIsExpandableRole) { data.insert("isExpandable", count > 0); } disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); } } } void KFileItemModelRolesUpdater::startUpdating() { if (m_state == Paused) { return; } if (m_finishedItems.count() == m_model->count()) { // All roles have been resolved already. m_state = Idle; return; } // Terminate all updates that are currently active. killPreviewJob(); m_pendingIndexes.clear(); QElapsedTimer timer; timer.start(); // Determine the icons for the visible items synchronously. updateVisibleIcons(); // A detailed update of the items in and near the visible area // only makes sense if sorting is finished. if (m_state == ResolvingSortRole) { return; } // Start the preview job or the asynchronous resolving of all roles. QList indexes = indexesToResolve(); if (m_previewShown) { m_pendingPreviewItems.clear(); m_pendingPreviewItems.reserve(indexes.count()); foreach (int index, indexes) { const KFileItem item = m_model->fileItem(index); if (!m_finishedItems.contains(item)) { m_pendingPreviewItems.append(item); } } startPreviewJob(); } else { m_pendingIndexes = indexes; // Trigger the asynchronous resolving of all roles. m_state = ResolvingAllRoles; QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextPendingRoles); } } void KFileItemModelRolesUpdater::updateVisibleIcons() { int lastVisibleIndex = m_lastVisibleIndex; if (lastVisibleIndex <= 0) { // Guess a reasonable value for the last visible index if the view // has not told us about the real value yet. lastVisibleIndex = qMin(m_firstVisibleIndex + m_maximumVisibleItems, m_model->count() - 1); if (lastVisibleIndex <= 0) { lastVisibleIndex = qMin(200, m_model->count() - 1); } } QElapsedTimer timer; timer.start(); // Try to determine the final icons for all visible items. int index; for (index = m_firstVisibleIndex; index <= lastVisibleIndex && timer.elapsed() < MaxBlockTimeout; ++index) { applyResolvedRoles(index, ResolveFast); } // KFileItemListView::initializeItemListWidget(KItemListWidget*) will load // preliminary icons (i.e., without mime type determination) for the // remaining items. } void KFileItemModelRolesUpdater::startPreviewJob() { m_state = PreviewJobRunning; if (m_pendingPreviewItems.isEmpty()) { QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::slotPreviewJobFinished); return; } // PreviewJob internally caches items always with the size of // 128 x 128 pixels or 256 x 256 pixels. A (slow) downscaling is done // by PreviewJob if a smaller size is requested. For images KFileItemModelRolesUpdater must // do a downscaling anyhow because of the frame, so in this case only the provided // cache sizes are requested. const QSize cacheSize = (m_iconSize.width() > 128) || (m_iconSize.height() > 128) ? QSize(256, 256) : QSize(128, 128); // KIO::filePreview() will request the MIME-type of all passed items, which (in the // worst case) might block the application for several seconds. To prevent such // a blocking, we only pass items with known mime type to the preview job. const int count = m_pendingPreviewItems.count(); KFileItemList itemSubSet; itemSubSet.reserve(count); if (m_pendingPreviewItems.first().isMimeTypeKnown()) { // Some mime types are known already, probably because they were // determined when loading the icons for the visible items. Start // a preview job for all items at the beginning of the list which // have a known mime type. do { itemSubSet.append(m_pendingPreviewItems.takeFirst()); } while (!m_pendingPreviewItems.isEmpty() && m_pendingPreviewItems.first().isMimeTypeKnown()); } else { // Determine mime types for MaxBlockTimeout ms, and start a preview // job for the corresponding items. QElapsedTimer timer; timer.start(); do { const KFileItem item = m_pendingPreviewItems.takeFirst(); item.determineMimeType(); itemSubSet.append(item); } while (!m_pendingPreviewItems.isEmpty() && timer.elapsed() < MaxBlockTimeout); } KIO::PreviewJob* job = new KIO::PreviewJob(itemSubSet, cacheSize, &m_enabledPlugins); job->setIgnoreMaximumSize(itemSubSet.first().isLocalFile()); if (job->uiDelegate()) { KJobWidgets::setWindow(job, qApp->activeWindow()); } connect(job, &KIO::PreviewJob::gotPreview, this, &KFileItemModelRolesUpdater::slotGotPreview); connect(job, &KIO::PreviewJob::failed, this, &KFileItemModelRolesUpdater::slotPreviewFailed); connect(job, &KIO::PreviewJob::finished, this, &KFileItemModelRolesUpdater::slotPreviewJobFinished); m_previewJob = job; } void KFileItemModelRolesUpdater::updateChangedItems() { if (m_state == Paused) { return; } if (m_changedItems.isEmpty()) { return; } m_finishedItems -= m_changedItems; if (m_resolvableRoles.contains(m_model->sortRole())) { m_pendingSortRoleItems += m_changedItems; if (m_state != ResolvingSortRole) { // Stop the preview job if necessary, and trigger the // asynchronous determination of the sort role. killPreviewJob(); m_state = ResolvingSortRole; QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextSortRole); } return; } QList visibleChangedIndexes; QList invisibleChangedIndexes; foreach (const KFileItem& item, m_changedItems) { const int index = m_model->index(item); if (index < 0) { m_changedItems.remove(item); continue; } if (index >= m_firstVisibleIndex && index <= m_lastVisibleIndex) { visibleChangedIndexes.append(index); } else { invisibleChangedIndexes.append(index); } } std::sort(visibleChangedIndexes.begin(), visibleChangedIndexes.end()); if (m_previewShown) { foreach (int index, visibleChangedIndexes) { m_pendingPreviewItems.append(m_model->fileItem(index)); } foreach (int index, invisibleChangedIndexes) { m_pendingPreviewItems.append(m_model->fileItem(index)); } if (!m_previewJob) { startPreviewJob(); } } else { const bool resolvingInProgress = !m_pendingIndexes.isEmpty(); m_pendingIndexes = visibleChangedIndexes + m_pendingIndexes + invisibleChangedIndexes; if (!resolvingInProgress) { // Trigger the asynchronous resolving of the changed roles. m_state = ResolvingAllRoles; QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextPendingRoles); } } } void KFileItemModelRolesUpdater::applySortRole(int index) { QHash data; const KFileItem item = m_model->fileItem(index); if (m_model->sortRole() == "type") { if (!item.isMimeTypeKnown()) { item.determineMimeType(); } data.insert("type", item.mimeComment()); } else if (m_model->sortRole() == "size" && item.isLocalFile() && item.isDir()) { const QString path = item.localPath(); data.insert("size", m_directoryContentsCounter->countDirectoryContentsSynchronously(path)); } else { // Probably the sort role is a baloo role - just determine all roles. data = rolesData(item); } disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); } void KFileItemModelRolesUpdater::applySortProgressToModel() { // Inform the model about the progress of the resolved items, // so that it can give an indication when the sorting has been finished. const int resolvedCount = m_model->count() - m_pendingSortRoleItems.count(); m_model->emitSortProgress(resolvedCount); } bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint) { const KFileItem item = m_model->fileItem(index); const bool resolveAll = (hint == ResolveAll); bool iconChanged = false; if (!item.isMimeTypeKnown() || !item.isFinalIconKnown()) { item.determineMimeType(); iconChanged = true; } else if (!m_model->data(index).contains("iconName")) { iconChanged = true; } if (iconChanged || resolveAll || m_clearPreviews) { if (index < 0) { return false; } QHash data; if (resolveAll) { data = rolesData(item); } data.insert("iconName", item.iconName()); if (m_clearPreviews) { data.insert("iconPixmap", QPixmap()); } disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); m_model->setData(index, data); connect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged); return true; } return false; } QHash KFileItemModelRolesUpdater::rolesData(const KFileItem& item) { QHash data; const bool getSizeRole = m_roles.contains("size"); const bool getIsExpandableRole = m_roles.contains("isExpandable"); if ((getSizeRole || getIsExpandableRole) && item.isDir()) { if (item.isLocalFile()) { // Tell m_directoryContentsCounter that we want to count the items // inside the directory. The result will be received in slotDirectoryContentsCountReceived. const QString path = item.localPath(); m_directoryContentsCounter->addDirectory(path); } else if (getSizeRole) { data.insert("size", -1); // -1 indicates an unknown number of items } } if (m_roles.contains("type")) { data.insert("type", item.mimeComment()); } QStringList overlays = item.overlays(); foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) { overlays.append(it->getOverlays(item.url())); } data.insert("iconOverlays", overlays); #ifdef HAVE_BALOO if (m_balooFileMonitor) { m_balooFileMonitor->addFile(item.localPath()); applyChangedBalooRolesForItem(item); } #endif return data; } void KFileItemModelRolesUpdater::slotOverlaysChanged(const QUrl& url, const QStringList &) { const KFileItem item = m_model->fileItem(url); if (item.isNull()) { return; } const int index = m_model->index(item); QHash data = m_model->data(index); QStringList overlays = item.overlays(); foreach (KOverlayIconPlugin *it, m_overlayIconsPlugin) { overlays.append(it->getOverlays(url)); } data.insert("iconOverlays", overlays); m_model->setData(index, data); } void KFileItemModelRolesUpdater::updateAllPreviews() { if (m_state == Paused) { m_previewChangedDuringPausing = true; } else { m_finishedItems.clear(); startUpdating(); } } void KFileItemModelRolesUpdater::killPreviewJob() { if (m_previewJob) { disconnect(m_previewJob, &KIO::PreviewJob::gotPreview, this, &KFileItemModelRolesUpdater::slotGotPreview); disconnect(m_previewJob, &KIO::PreviewJob::failed, this, &KFileItemModelRolesUpdater::slotPreviewFailed); disconnect(m_previewJob, &KIO::PreviewJob::finished, this, &KFileItemModelRolesUpdater::slotPreviewJobFinished); m_previewJob->kill(); m_previewJob = 0; m_pendingPreviewItems.clear(); } } QList KFileItemModelRolesUpdater::indexesToResolve() const { const int count = m_model->count(); QList result; result.reserve(ResolveAllItemsLimit); // Add visible items. for (int i = m_firstVisibleIndex; i <= m_lastVisibleIndex; ++i) { result.append(i); } // We need a reasonable upper limit for number of items to resolve after // and before the visible range. m_maximumVisibleItems can be quite large // when using Compace View. const int readAheadItems = qMin(ReadAheadPages * m_maximumVisibleItems, ResolveAllItemsLimit / 2); // Add items after the visible range. const int endExtendedVisibleRange = qMin(m_lastVisibleIndex + readAheadItems, count - 1); for (int i = m_lastVisibleIndex + 1; i <= endExtendedVisibleRange; ++i) { result.append(i); } // Add items before the visible range in reverse order. const int beginExtendedVisibleRange = qMax(0, m_firstVisibleIndex - readAheadItems); for (int i = m_firstVisibleIndex - 1; i >= beginExtendedVisibleRange; --i) { result.append(i); } // Add items on the last page. const int beginLastPage = qMax(qMin(endExtendedVisibleRange + 1, count - 1), count - m_maximumVisibleItems); for (int i = beginLastPage; i < count; ++i) { result.append(i); } // Add items on the first page. const int endFirstPage = qMin(qMax(beginExtendedVisibleRange - 1, 0), m_maximumVisibleItems); for (int i = 0; i <= endFirstPage; ++i) { result.append(i); } // Continue adding items until ResolveAllItemsLimit is reached. int remainingItems = ResolveAllItemsLimit - result.count(); for (int i = endExtendedVisibleRange + 1; i < beginLastPage && remainingItems > 0; ++i) { result.append(i); --remainingItems; } for (int i = beginExtendedVisibleRange - 1; i > endFirstPage && remainingItems > 0; --i) { result.append(i); --remainingItems; } return result; } diff --git a/src/settings/dolphin_directoryviewpropertysettings.kcfg b/src/settings/dolphin_directoryviewpropertysettings.kcfg index 9584fc8b3..6bcf3cd02 100644 --- a/src/settings/dolphin_directoryviewpropertysettings.kcfg +++ b/src/settings/dolphin_directoryviewpropertysettings.kcfg @@ -1,83 +1,83 @@ kfileitemdelegate.h When this option is enabled hidden files, such as those starting with a '.', will be shown in the file view. false This option defines the used version of the view properties. -1 This option controls the style of the view. Currently supported values include icons (0), details (1) and column (2) views. DolphinView::IconsView When this option is enabled, a preview of the file content is shown as an icon. - false + true When this option is enabled, the sorted items are categorized into groups. false This option defines which attribute (text, size, date, etc.) sorting is performed on. text Qt::AscendingOrder Qt::AscendingOrder Qt::DescendingOrder true The last time these properties were changed by the user. diff --git a/src/settings/general/previewssettingspage.cpp b/src/settings/general/previewssettingspage.cpp index 1a92cd16c..ed0d9bd77 100644 --- a/src/settings/general/previewssettingspage.cpp +++ b/src/settings/general/previewssettingspage.cpp @@ -1,186 +1,186 @@ /*************************************************************************** * Copyright (C) 2006 by Peter Penz * * * * 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 "previewssettingspage.h" #include "dolphin_generalsettings.h" #include "configurepreviewplugindialog.h" #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // default settings namespace { const int MaxRemotePreviewSize = 0; // 0 MB } PreviewsSettingsPage::PreviewsSettingsPage(QWidget* parent) : SettingsPageBase(parent), m_initialized(false), m_listView(0), m_enabledPreviewPlugins(), m_remoteFileSizeBox(0) { QVBoxLayout* topLayout = new QVBoxLayout(this); QLabel* showPreviewsLabel = new QLabel(i18nc("@title:group", "Show previews for:"), this); m_listView = new QListView(this); ServiceItemDelegate* delegate = new ServiceItemDelegate(m_listView, m_listView); connect(delegate, &ServiceItemDelegate::requestServiceConfiguration, this, &PreviewsSettingsPage::configureService); ServiceModel* serviceModel = new ServiceModel(this); QSortFilterProxyModel* proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(serviceModel); proxyModel->setSortRole(Qt::DisplayRole); m_listView->setModel(proxyModel); m_listView->setItemDelegate(delegate); m_listView->setVerticalScrollMode(QListView::ScrollPerPixel); QLabel* remoteFileSizeLabel = new QLabel(i18nc("@label", "Skip previews for remote files above:"), this); m_remoteFileSizeBox = new QSpinBox(this); m_remoteFileSizeBox->setSingleStep(1); m_remoteFileSizeBox->setSuffix(QStringLiteral(" MB")); m_remoteFileSizeBox->setRange(0, 9999999); /* MB */ QHBoxLayout* fileSizeBoxLayout = new QHBoxLayout(); fileSizeBoxLayout->addWidget(remoteFileSizeLabel, 0, Qt::AlignRight); fileSizeBoxLayout->addWidget(m_remoteFileSizeBox); topLayout->addWidget(showPreviewsLabel); topLayout->addWidget(m_listView); topLayout->addLayout(fileSizeBoxLayout); loadSettings(); connect(m_listView, &QListView::clicked, this, &PreviewsSettingsPage::changed); connect(m_remoteFileSizeBox, static_cast(&QSpinBox::valueChanged), this, &PreviewsSettingsPage::changed); } PreviewsSettingsPage::~PreviewsSettingsPage() { } void PreviewsSettingsPage::applySettings() { const QAbstractItemModel* model = m_listView->model(); const int rowCount = model->rowCount(); if (rowCount > 0) { m_enabledPreviewPlugins.clear(); for (int i = 0; i < rowCount; ++i) { const QModelIndex index = model->index(i, 0); const bool checked = model->data(index, Qt::CheckStateRole).toBool(); if (checked) { const QString enabledPlugin = model->data(index, Qt::UserRole).toString(); m_enabledPreviewPlugins.append(enabledPlugin); } } } KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings")); globalConfig.writeEntry("Plugins", m_enabledPreviewPlugins); const qulonglong maximumRemoteSize = static_cast(m_remoteFileSizeBox->value()) * 1024 * 1024; globalConfig.writeEntry("MaximumRemoteSize", maximumRemoteSize, KConfigBase::Normal | KConfigBase::Global); globalConfig.sync(); } void PreviewsSettingsPage::restoreDefaults() { m_remoteFileSizeBox->setValue(MaxRemotePreviewSize); } void PreviewsSettingsPage::showEvent(QShowEvent* event) { if (!event->spontaneous() && !m_initialized) { loadPreviewPlugins(); m_initialized = true; } SettingsPageBase::showEvent(event); } void PreviewsSettingsPage::configureService(const QModelIndex& index) { const QAbstractItemModel* model = index.model(); const QString pluginName = model->data(index).toString(); const QString desktopEntryName = model->data(index, ServiceModel::DesktopEntryNameRole).toString(); ConfigurePreviewPluginDialog* dialog = new ConfigurePreviewPluginDialog(pluginName, desktopEntryName, this); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); } void PreviewsSettingsPage::loadPreviewPlugins() { QAbstractItemModel* model = m_listView->model(); const KService::List plugins = KServiceTypeTrader::self()->query(QStringLiteral("ThumbCreator")); foreach (const KService::Ptr& service, plugins) { const bool configurable = service->property(QStringLiteral("Configurable"), QVariant::Bool).toBool(); const bool show = m_enabledPreviewPlugins.contains(service->desktopEntryName()); model->insertRow(0); const QModelIndex index = model->index(0, 0); model->setData(index, show, Qt::CheckStateRole); model->setData(index, configurable, ServiceModel::ConfigurableRole); model->setData(index, service->name(), Qt::DisplayRole); model->setData(index, service->desktopEntryName(), ServiceModel::DesktopEntryNameRole); } model->sort(Qt::DisplayRole); } void PreviewsSettingsPage::loadSettings() { - KConfigGroup globalConfig(KSharedConfig::openConfig(), "PreviewSettings"); - m_enabledPreviewPlugins = globalConfig.readEntry("Plugins", QStringList() - << QStringLiteral("directorythumbnail") - << QStringLiteral("imagethumbnail") - << QStringLiteral("jpegthumbnail")); - + const KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings")); + m_enabledPreviewPlugins = globalConfig.readEntry("Plugins", QStringList()); + if (m_enabledPreviewPlugins.isEmpty()) { + m_enabledPreviewPlugins = KIO::PreviewJob::defaultPlugins(); + } const qulonglong defaultRemotePreview = static_cast(MaxRemotePreviewSize) * 1024 * 1024; const qulonglong maxRemoteByteSize = globalConfig.readEntry("MaximumRemoteSize", defaultRemotePreview); const int maxRemoteMByteSize = maxRemoteByteSize / (1024 * 1024); m_remoteFileSizeBox->setValue(maxRemoteMByteSize); } diff --git a/src/views/dolphinitemlistview.cpp b/src/views/dolphinitemlistview.cpp index a3740cb26..d73889fd5 100644 --- a/src/views/dolphinitemlistview.cpp +++ b/src/views/dolphinitemlistview.cpp @@ -1,263 +1,264 @@ /*************************************************************************** * Copyright (C) 2011 by Peter Penz * * * * 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 "dolphinitemlistview.h" #include "dolphin_generalsettings.h" #include "dolphin_iconsmodesettings.h" #include "dolphin_detailsmodesettings.h" #include "dolphin_compactmodesettings.h" #include "dolphinfileitemlistwidget.h" #include #include #include #include +#include #include #include "zoomlevelinfo.h" DolphinItemListView::DolphinItemListView(QGraphicsWidget* parent) : KFileItemListView(parent), m_zoomLevel(0) { updateFont(); updateGridSize(); } DolphinItemListView::~DolphinItemListView() { writeSettings(); } void DolphinItemListView::setZoomLevel(int level) { if (level < ZoomLevelInfo::minimumLevel()) { level = ZoomLevelInfo::minimumLevel(); } else if (level > ZoomLevelInfo::maximumLevel()) { level = ZoomLevelInfo::maximumLevel(); } if (level == m_zoomLevel) { return; } m_zoomLevel = level; ViewModeSettings settings(viewMode()); if (previewsShown()) { const int previewSize = ZoomLevelInfo::iconSizeForZoomLevel(level); settings.setPreviewSize(previewSize); } else { const int iconSize = ZoomLevelInfo::iconSizeForZoomLevel(level); settings.setIconSize(iconSize); } updateGridSize(); } int DolphinItemListView::zoomLevel() const { return m_zoomLevel; } void DolphinItemListView::readSettings() { ViewModeSettings settings(viewMode()); settings.readConfig(); beginTransaction(); setEnabledSelectionToggles(GeneralSettings::showSelectionToggle()); setSupportsItemExpanding(itemLayoutSupportsItemExpanding(itemLayout())); updateFont(); updateGridSize(); const KConfigGroup globalConfig(KSharedConfig::openConfig(), "PreviewSettings"); - const QStringList plugins = globalConfig.readEntry("Plugins", QStringList() - << QStringLiteral("directorythumbnail") - << QStringLiteral("imagethumbnail") - << QStringLiteral("jpegthumbnail")); - setEnabledPlugins(plugins); + QStringList enabledPlugins = globalConfig.readEntry("Plugins", QStringList()); + if (enabledPlugins.isEmpty()) { + enabledPlugins = KIO::PreviewJob::defaultPlugins(); + } + setEnabledPlugins(enabledPlugins); endTransaction(); } void DolphinItemListView::writeSettings() { IconsModeSettings::self()->save(); CompactModeSettings::self()->save(); DetailsModeSettings::self()->save(); } KItemListWidgetCreatorBase* DolphinItemListView::defaultWidgetCreator() const { return new KItemListWidgetCreator(); } bool DolphinItemListView::itemLayoutSupportsItemExpanding(ItemLayout layout) const { return layout == DetailsLayout && DetailsModeSettings::expandableFolders(); } void DolphinItemListView::onItemLayoutChanged(ItemLayout current, ItemLayout previous) { setHeaderVisible(current == DetailsLayout); updateFont(); updateGridSize(); KFileItemListView::onItemLayoutChanged(current, previous); } void DolphinItemListView::onPreviewsShownChanged(bool shown) { Q_UNUSED(shown); updateGridSize(); } void DolphinItemListView::onVisibleRolesChanged(const QList& current, const QList& previous) { KFileItemListView::onVisibleRolesChanged(current, previous); updateGridSize(); } void DolphinItemListView::updateFont() { const ViewModeSettings settings(viewMode()); if (settings.useSystemFont()) { KItemListView::updateFont(); } else { QFont font(settings.fontFamily(), qRound(settings.fontSize())); font.setItalic(settings.italicFont()); font.setWeight(settings.fontWeight()); font.setPointSizeF(settings.fontSize()); KItemListStyleOption option = styleOption(); option.font = font; option.fontMetrics = QFontMetrics(font); setStyleOption(option); } } void DolphinItemListView::updateGridSize() { const ViewModeSettings settings(viewMode()); // Calculate the size of the icon const int iconSize = previewsShown() ? settings.previewSize() : settings.iconSize(); m_zoomLevel = ZoomLevelInfo::zoomLevelForIconSize(QSize(iconSize, iconSize)); KItemListStyleOption option = styleOption(); const int padding = 2; int horizontalMargin = 0; int verticalMargin = 0; // Calculate the item-width and item-height int itemWidth; int itemHeight; int maxTextLines = 0; int maxTextWidth = 0; switch (itemLayout()) { case KFileItemListView::IconsLayout: { const int minItemWidth = 48; itemWidth = minItemWidth + IconsModeSettings::textWidthIndex() * 64; if (previewsShown()) { // Optimize the width for previews with a 3:2 aspect ratio instead // of a 1:1 ratio to avoid wasting too much vertical space when // showing photos. const int minWidth = iconSize * 3 / 2; itemWidth = qMax(itemWidth, minWidth); } if (itemWidth < iconSize + padding * 2) { itemWidth = iconSize + padding * 2; } itemHeight = padding * 3 + iconSize + option.fontMetrics.lineSpacing(); horizontalMargin = 4; verticalMargin = 8; maxTextLines = IconsModeSettings::maximumTextLines(); break; } case KFileItemListView::CompactLayout: { itemWidth = padding * 4 + iconSize + option.fontMetrics.height() * 5; const int textLinesCount = visibleRoles().count(); itemHeight = padding * 2 + qMax(iconSize, textLinesCount * option.fontMetrics.lineSpacing()); if (CompactModeSettings::maximumTextWidthIndex() > 0) { // A restriction is given for the maximum width of the text (0 means // having no restriction) maxTextWidth = option.fontMetrics.height() * 10 * CompactModeSettings::maximumTextWidthIndex(); } horizontalMargin = 8; break; } case KFileItemListView::DetailsLayout: { itemWidth = -1; itemHeight = padding * 2 + qMax(iconSize, option.fontMetrics.lineSpacing()); break; } default: itemWidth = -1; itemHeight = -1; Q_ASSERT(false); break; } // Apply the calculated values option.padding = padding; option.horizontalMargin = horizontalMargin; option.verticalMargin = verticalMargin; option.iconSize = iconSize; option.maxTextLines = maxTextLines; option.maxTextWidth = maxTextWidth; beginTransaction(); setStyleOption(option); setItemSize(QSizeF(itemWidth, itemHeight)); endTransaction(); } ViewModeSettings::ViewMode DolphinItemListView::viewMode() const { ViewModeSettings::ViewMode mode; switch (itemLayout()) { case KFileItemListView::IconsLayout: mode = ViewModeSettings::IconsMode; break; case KFileItemListView::CompactLayout: mode = ViewModeSettings::CompactMode; break; case KFileItemListView::DetailsLayout: mode = ViewModeSettings::DetailsMode; break; default: mode = ViewModeSettings::IconsMode; Q_ASSERT(false); break; } return mode; }