┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
path: root/src/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/views')
-rw-r--r--src/views/dolphinview.cpp89
-rw-r--r--src/views/dolphinview.h13
-rw-r--r--src/views/dolphinviewactionhandler.cpp13
-rw-r--r--src/views/versioncontrol/kversioncontrolplugin.cpp5
-rw-r--r--src/views/versioncontrol/kversioncontrolplugin.h7
-rw-r--r--src/views/versioncontrol/versioncontrolobserver.cpp99
-rw-r--r--src/views/versioncontrol/versioncontrolobserver.h7
7 files changed, 156 insertions, 77 deletions
diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp
index 32e962459..d03b75ddd 100644
--- a/src/views/dolphinview.cpp
+++ b/src/views/dolphinview.cpp
@@ -48,7 +48,9 @@
#include <QApplication>
#include <QClipboard>
#include <QDropEvent>
+#include <QGraphicsOpacityEffect>
#include <QGraphicsSceneDragDropEvent>
+#include <QLabel>
#include <QMenu>
#include <QMimeDatabase>
#include <QPixmapCache>
@@ -65,6 +67,7 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
m_assureVisibleCurrentIndex(false),
m_isFolderWritable(true),
m_dragging(false),
+ m_loading(false),
m_url(url),
m_viewPropertiesContext(),
m_mode(DolphinView::IconsView),
@@ -82,7 +85,8 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
m_clearSelectionBeforeSelectingNewItems(false),
m_markFirstNewlySelectedItemAsCurrent(false),
m_versionControlObserver(nullptr),
- m_twoClicksRenamingTimer(nullptr)
+ m_twoClicksRenamingTimer(nullptr),
+ m_placeholderLabel(nullptr)
{
m_topLayout = new QVBoxLayout(this);
m_topLayout->setSpacing(0);
@@ -120,6 +124,28 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
connect(m_container->horizontalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); });
connect(m_container->verticalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); });
+ // Show some placeholder text for empty folders
+ // This is made using a heavily-modified QLabel rather than a KTitleWidget
+ // because KTitleWidget can't be told to turn off mouse-selectable text
+ m_placeholderLabel = new QLabel(this);
+ QFont placeholderLabelFont;
+ // To match the size of a level 2 Heading/KTitleWidget
+ placeholderLabelFont.setPointSize(qRound(placeholderLabelFont.pointSize() * 1.3));
+ m_placeholderLabel->setFont(placeholderLabelFont);
+ m_placeholderLabel->setTextInteractionFlags(Qt::NoTextInteraction);
+ m_placeholderLabel->setWordWrap(true);
+ m_placeholderLabel->setAlignment(Qt::AlignCenter);
+ // Match opacity of QML placeholder label component
+ auto *effect = new QGraphicsOpacityEffect(m_placeholderLabel);
+ effect->setOpacity(0.5);
+ m_placeholderLabel->setGraphicsEffect(effect);
+ // Set initial text and visibility
+ updatePlaceholderLabel();
+
+ auto *centeringLayout = new QVBoxLayout(m_container);
+ centeringLayout->addWidget(m_placeholderLabel);
+ centeringLayout->setAlignment(m_placeholderLabel, Qt::AlignCenter);
+
controller->setSelectionBehavior(KItemListController::MultiSelection);
connect(controller, &KItemListController::itemActivated, this, &DolphinView::slotItemActivated);
connect(controller, &KItemListController::itemsActivated, this, &DolphinView::slotItemsActivated);
@@ -140,7 +166,7 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
connect(m_model, &KFileItemModel::directoryLoadingStarted, this, &DolphinView::slotDirectoryLoadingStarted);
connect(m_model, &KFileItemModel::directoryLoadingCompleted, this, &DolphinView::slotDirectoryLoadingCompleted);
- connect(m_model, &KFileItemModel::directoryLoadingCanceled, this, &DolphinView::directoryLoadingCanceled);
+ connect(m_model, &KFileItemModel::directoryLoadingCanceled, this, &DolphinView::slotDirectoryLoadingCanceled);
connect(m_model, &KFileItemModel::directoryLoadingProgress, this, &DolphinView::directoryLoadingProgress);
connect(m_model, &KFileItemModel::directorySortingProgress, this, &DolphinView::directorySortingProgress);
connect(m_model, &KFileItemModel::itemsChanged,
@@ -152,6 +178,9 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
connect(m_model, &KFileItemModel::directoryRedirection, this, &DolphinView::slotDirectoryRedirection);
connect(m_model, &KFileItemModel::urlIsFileError, this, &DolphinView::urlIsFileError);
+ connect(this, &DolphinView::itemCountChanged,
+ this, &DolphinView::updatePlaceholderLabel);
+
m_view->installEventFilter(this);
connect(m_view, &DolphinItemListView::sortOrderChanged,
this, &DolphinView::slotSortOrderChangedByHeader);
@@ -915,7 +944,7 @@ void DolphinView::slotItemsActivated(const KItemSet& indexes)
const QUrl& url = openItemAsFolderUrl(item);
if (!url.isEmpty()) { // Open folders in new tabs
- Q_EMIT tabRequested(url, DolphinTabWidget::AfterLastTab);
+ Q_EMIT tabRequested(url);
} else {
items.append(item);
}
@@ -933,9 +962,9 @@ void DolphinView::slotItemMiddleClicked(int index)
const KFileItem& item = m_model->fileItem(index);
const QUrl& url = openItemAsFolderUrl(item);
if (!url.isEmpty()) {
- Q_EMIT tabRequested(url, DolphinTabWidget::AfterCurrentTab);
+ Q_EMIT tabRequested(url);
} else if (isTabsForFilesEnabled()) {
- Q_EMIT tabRequested(item.url(), DolphinTabWidget::AfterCurrentTab);
+ Q_EMIT tabRequested(item.url());
}
}
@@ -1594,6 +1623,9 @@ void DolphinView::slotRenamingResult(KJob* job)
void DolphinView::slotDirectoryLoadingStarted()
{
+ m_loading = true;
+ updatePlaceholderLabel();
+
// Disable the writestate temporary until it can be determined in a fast way
// in DolphinView::slotDirectoryLoadingCompleted()
if (m_isFolderWritable) {
@@ -1606,15 +1638,30 @@ void DolphinView::slotDirectoryLoadingStarted()
void DolphinView::slotDirectoryLoadingCompleted()
{
+ m_loading = false;
+
// Update the view-state. This has to be done asynchronously
// because the view might not be in its final state yet.
QTimer::singleShot(0, this, &DolphinView::updateViewState);
+ // Update the placeholder label in case we found that the folder was empty
+ // after loading it
+
Q_EMIT directoryLoadingCompleted();
+ updatePlaceholderLabel();
updateWritableState();
}
+void DolphinView::slotDirectoryLoadingCanceled()
+{
+ m_loading = false;
+
+ updatePlaceholderLabel();
+
+ Q_EMIT directoryLoadingCanceled();
+}
+
void DolphinView::slotItemsChanged()
{
m_assureVisibleCurrentIndex = false;
@@ -1976,3 +2023,35 @@ void DolphinView::slotSwipeUp()
{
Q_EMIT goUpRequested();
}
+
+void DolphinView::updatePlaceholderLabel()
+{
+ if (m_loading || itemsCount() > 0) {
+ m_placeholderLabel->setVisible(false);
+ return;
+ }
+
+ if (!nameFilter().isEmpty()) {
+ m_placeholderLabel->setText(i18n("No items matching the filter"));
+ } else if (m_url.scheme() == QLatin1String("baloosearch") || m_url.scheme() == QLatin1String("filenamesearch")) {
+ m_placeholderLabel->setText(i18n("No items matching the search"));
+ } else if (m_url.scheme() == QLatin1String("trash")) {
+ m_placeholderLabel->setText(i18n("Trash is empty"));
+ } else if (m_url.scheme() == QLatin1String("tags")) {
+ m_placeholderLabel->setText(i18n("No tags"));
+ } else if (m_url.scheme() == QLatin1String("recentlyused")) {
+ m_placeholderLabel->setText(i18n("No recently used items"));
+ } else if (m_url.scheme() == QLatin1String("smb")) {
+ m_placeholderLabel->setText(i18n("No shared folders found"));
+ } else if (m_url.scheme() == QLatin1String("network")) {
+ m_placeholderLabel->setText(i18n("No relevant network resources found"));
+ } else if (m_url.scheme() == QLatin1String("mtp")) {
+ m_placeholderLabel->setText(i18n("No MTP-compatible devices found"));
+ } else if (m_url.scheme() == QLatin1String("bluetooth")) {
+ m_placeholderLabel->setText(i18n("No Bluetooth devices found"));
+ } else {
+ m_placeholderLabel->setText(i18n("Folder is empty"));
+ }
+
+ m_placeholderLabel->setVisible(true);
+}
diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h
index 1d0ebe0fe..d0285da85 100644
--- a/src/views/dolphinview.h
+++ b/src/views/dolphinview.h
@@ -32,6 +32,7 @@ class KItemSet;
class ToolTipManager;
class VersionControlObserver;
class ViewProperties;
+class QLabel;
class QGraphicsSceneDragDropEvent;
class QRegularExpression;
@@ -432,7 +433,7 @@ signals:
/**
* Is emitted if a new tab should be opened for the URL \a url.
*/
- void tabRequested(const QUrl& url, DolphinTabWidget::TabPlacement tabPlacement);
+ void tabRequested(const QUrl& url);
/**
* Is emitted if the view mode (IconsView, DetailsView,
@@ -689,6 +690,12 @@ private slots:
void slotDirectoryLoadingCompleted();
/**
+ * Invoked when the file item model indicates that the loading of a directory has
+ * been canceled.
+ */
+ void slotDirectoryLoadingCanceled();
+
+ /**
* Is invoked when items of KFileItemModel have been changed.
*/
void slotItemsChanged();
@@ -804,6 +811,8 @@ private:
void abortTwoClicksRenaming();
+ void updatePlaceholderLabel();
+
private:
void updatePalette();
@@ -813,6 +822,7 @@ private:
bool m_isFolderWritable;
bool m_dragging; // True if a dragging is done. Required to be able to decide whether a
// tooltip may be shown when hovering an item.
+ bool m_loading;
QUrl m_url;
QString m_viewPropertiesContext;
@@ -841,6 +851,7 @@ private:
QTimer* m_twoClicksRenamingTimer;
QUrl m_twoClicksRenamingItemUrl;
+ QLabel* m_placeholderLabel;
// For unit tests
friend class TestBase;
diff --git a/src/views/dolphinviewactionhandler.cpp b/src/views/dolphinviewactionhandler.cpp
index f3e3f95a3..14c1e96c2 100644
--- a/src/views/dolphinviewactionhandler.cpp
+++ b/src/views/dolphinviewactionhandler.cpp
@@ -11,6 +11,7 @@
#include "kitemviews/kfileitemmodel.h"
#include "settings/viewpropertiesdialog.h"
#include "views/zoomlevelinfo.h"
+#include "kconfig_version.h"
#ifdef HAVE_BALOO
#include <Baloo/IndexerConfig>
@@ -78,7 +79,7 @@ void DolphinViewActionHandler::createActions()
// KNewFileMenu takes care of the GUI stuff.
QAction* newDirAction = m_actionCollection->addAction(QStringLiteral("create_dir"));
newDirAction->setText(i18nc("@action", "Create Folder..."));
- m_actionCollection->setDefaultShortcut(newDirAction, Qt::Key_F10);
+ m_actionCollection->setDefaultShortcuts(newDirAction, KStandardShortcut::createFolder());
newDirAction->setIcon(QIcon::fromTheme(QStringLiteral("folder-new")));
newDirAction->setEnabled(false); // Will be enabled in slotWriteStateChanged(bool) if the current URL is writable
connect(newDirAction, &QAction::triggered, this, &DolphinViewActionHandler::createDirectoryTriggered);
@@ -139,7 +140,7 @@ void DolphinViewActionHandler::createActions()
"You can configure advanced options there like managing "
"read- and write-permissions."));
propertiesAction->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")));
- m_actionCollection->setDefaultShortcuts(propertiesAction, {Qt::ALT + Qt::Key_Return, Qt::ALT + Qt::Key_Enter});
+ m_actionCollection->setDefaultShortcuts(propertiesAction, {Qt::ALT | Qt::Key_Return, Qt::ALT | Qt::Key_Enter});
connect(propertiesAction, &QAction::triggered, this, &DolphinViewActionHandler::slotProperties);
QAction *copyPathAction = m_actionCollection->addAction( QStringLiteral("copy_location") );
@@ -197,7 +198,7 @@ void DolphinViewActionHandler::createActions()
zoomResetAction->setToolTip(i18n("Zoom To Default"));
zoomResetAction->setWhatsThis(i18nc("@info:whatsthis zoom reset", "This resets the icon size to default."));
zoomResetAction->setIcon(QIcon::fromTheme(QStringLiteral("zoom-original")));
- m_actionCollection->setDefaultShortcuts(zoomResetAction, {Qt::CTRL + Qt::Key_0});
+ m_actionCollection->setDefaultShortcuts(zoomResetAction, {Qt::CTRL | Qt::Key_0});
connect(zoomResetAction, &QAction::triggered, this, &DolphinViewActionHandler::zoomReset);
QAction* zoomOutAction = KStandardAction::zoomOut(this,
@@ -567,7 +568,7 @@ KToggleAction* DolphinViewActionHandler::iconsModeAction()
KToggleAction* iconsView = m_actionCollection->add<KToggleAction>(QStringLiteral("icons"));
iconsView->setText(i18nc("@action:inmenu View Mode", "Icons"));
iconsView->setToolTip(i18nc("@info", "Icons view mode"));
- m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL + Qt::Key_1);
+ m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL | Qt::Key_1);
iconsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons")));
iconsView->setData(QVariant::fromValue(DolphinView::IconsView));
return iconsView;
@@ -578,7 +579,7 @@ KToggleAction* DolphinViewActionHandler::compactModeAction()
KToggleAction* iconsView = m_actionCollection->add<KToggleAction>(QStringLiteral("compact"));
iconsView->setText(i18nc("@action:inmenu View Mode", "Compact"));
iconsView->setToolTip(i18nc("@info", "Compact view mode"));
- m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL + Qt::Key_2);
+ m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL | Qt::Key_2);
iconsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details"))); // TODO: discuss with Oxygen-team the wrong (?) name
iconsView->setData(QVariant::fromValue(DolphinView::CompactView));
return iconsView;
@@ -589,7 +590,7 @@ KToggleAction* DolphinViewActionHandler::detailsModeAction()
KToggleAction* detailsView = m_actionCollection->add<KToggleAction>(QStringLiteral("details"));
detailsView->setText(i18nc("@action:inmenu View Mode", "Details"));
detailsView->setToolTip(i18nc("@info", "Details view mode"));
- m_actionCollection->setDefaultShortcut(detailsView, Qt::CTRL + Qt::Key_3);
+ m_actionCollection->setDefaultShortcut(detailsView, Qt::CTRL | Qt::Key_3);
detailsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
detailsView->setData(QVariant::fromValue(DolphinView::DetailsView));
return detailsView;
diff --git a/src/views/versioncontrol/kversioncontrolplugin.cpp b/src/views/versioncontrol/kversioncontrolplugin.cpp
index 2e1a4468b..9cbf0eb5b 100644
--- a/src/views/versioncontrol/kversioncontrolplugin.cpp
+++ b/src/views/versioncontrol/kversioncontrolplugin.cpp
@@ -15,3 +15,8 @@ KVersionControlPlugin::KVersionControlPlugin(QObject* parent) :
KVersionControlPlugin::~KVersionControlPlugin()
{
}
+
+QString KVersionControlPlugin::localRepositoryRoot(const QString &/*directory*/) const
+{
+ return QString();
+}
diff --git a/src/views/versioncontrol/kversioncontrolplugin.h b/src/views/versioncontrol/kversioncontrolplugin.h
index 0de305d14..aeac5ad29 100644
--- a/src/views/versioncontrol/kversioncontrolplugin.h
+++ b/src/views/versioncontrol/kversioncontrolplugin.h
@@ -144,6 +144,12 @@ public:
virtual QString fileName() const = 0;
/**
+ * Returns the path of the local repository root for the versionned directory
+ * Returns an emtpy QString when directory is not part of a working copy
+ */
+ virtual QString localRepositoryRoot(const QString& directory) const;
+
+ /**
* Is invoked whenever the version control
* information will get retrieved for the directory
* \p directory. It is assured that the directory
@@ -177,6 +183,7 @@ public:
* @return List of actions that are available for the out of version control
* items \p items. It's opposed to the \p versionedActions. Common usage
* is for clone/checkout actions.
+ * @since 21.04
*/
virtual QList<QAction*> outOfVersionControlActions(const KFileItemList& items) const = 0;
diff --git a/src/views/versioncontrol/versioncontrolobserver.cpp b/src/views/versioncontrol/versioncontrolobserver.cpp
index c66c639c8..cf5be3c91 100644
--- a/src/views/versioncontrol/versioncontrolobserver.cpp
+++ b/src/views/versioncontrol/versioncontrolobserver.cpp
@@ -21,7 +21,6 @@
VersionControlObserver::VersionControlObserver(QObject* parent) :
QObject(parent),
m_pendingItemStatesUpdate(false),
- m_versionedDirectory(false),
m_silentUpdate(false),
m_view(nullptr),
m_model(nullptr),
@@ -113,8 +112,8 @@ QList<QAction*> VersionControlObserver::actions(const KFileItemList& items) cons
return m_plugin->versionControlActions(items);
} else {
QList<QAction*> actions;
- for (const auto &plugin : qAsConst(m_plugins)) {
- actions << plugin.first->outOfVersionControlActions(items);
+ for (const QPointer<KVersionControlPlugin> &plugin : qAsConst(m_plugins)) {
+ actions << plugin->outOfVersionControlActions(items);
}
return actions;
}
@@ -155,23 +154,23 @@ void VersionControlObserver::verifyDirectory()
return;
}
- m_plugin = searchPlugin(rootItem.url());
- if (m_plugin) {
- if (!m_versionedDirectory) {
- m_versionedDirectory = true;
+ if (m_plugin != nullptr) {
+ if (!rootItem.url().path().startsWith(m_localRepoRoot) || !QFile::exists(m_localRepoRoot + '/' + m_plugin->fileName())) {
+ m_plugin = nullptr;
- // The directory is versioned. Assume that the user will further browse through
- // versioned directories and decrease the verification timer.
- m_dirVerificationTimer->setInterval(100);
+ // The directory is not versioned. Reset the verification timer to a higher
+ // value, so that browsing through non-versioned directories is not slown down
+ // by an immediate verification.
+ m_dirVerificationTimer->setInterval(500);
+ } else {
+ // View was versionned but should not be anymore
+ updateItemStates();
}
+ } else if ((m_plugin = searchPlugin(rootItem.url()))) {
+ // The directory is versioned. Assume that the user will further browse through
+ // versioned directories and decrease the verification timer.
+ m_dirVerificationTimer->setInterval(100);
updateItemStates();
- } else if (m_versionedDirectory) {
- m_versionedDirectory = false;
-
- // The directory is not versioned. Reset the verification timer to a higher
- // value, so that browsing through non-versioned directories is not slown down
- // by an immediate verification.
- m_dirVerificationTimer->setInterval(500);
}
}
@@ -273,7 +272,7 @@ int VersionControlObserver::createItemStatesList(QMap<QString, QVector<ItemState
return index - firstIndex; // number of processed items
}
-KVersionControlPlugin* VersionControlObserver::searchPlugin(const QUrl& directory)
+void VersionControlObserver::initPlugins()
{
if (!m_pluginsInitialized) {
// No searching for plugins has been done yet. Query the KServiceTypeTrader for
@@ -294,65 +293,41 @@ KVersionControlPlugin* VersionControlObserver::searchPlugin(const QUrl& director
connect(plugin, &KVersionControlPlugin::operationCompletedMessage,
this, &VersionControlObserver::operationCompletedMessage);
- m_plugins.append( qMakePair(plugin, plugin->fileName()) );
+ m_plugins.append(plugin);
}
}
}
m_pluginsInitialized = true;
}
+}
- if (m_plugins.empty()) {
- // A searching for plugins has already been done, but no
- // plugins are installed
- return nullptr;
- }
+KVersionControlPlugin* VersionControlObserver::searchPlugin(const QUrl& directory)
+{
+ initPlugins();
- // We use the number of upUrl() calls to find the best matching plugin
- // for the given directory. The smaller value, the better it is (0 is best).
- KVersionControlPlugin* bestPlugin = nullptr;
- int bestScore = INT_MAX;
+ // Verify whether the current directory is under a version system
+ for (const QPointer<KVersionControlPlugin> &plugin : qAsConst(m_plugins)) {
+ if (!plugin) {
+ continue;
+ }
- // Verify whether the current directory contains revision information
- // like .svn, .git, ...
- for (const auto &it : qAsConst(m_plugins)) {
- const QString fileName = directory.path() + '/' + it.second;
+ // first naively check if we are at working copy root
+ const QString fileName = directory.path() + '/' + plugin->fileName();
if (QFile::exists(fileName)) {
- // The score of this plugin is 0 (best), so we can just return this plugin,
- // instead of going through the plugin scoring procedure, we can't find a better one ;)
- return it.first;
+ m_localRepoRoot = directory.path();
+ return plugin;
}
-
- // Version control systems like Git provide the version information
- // file only in the root directory. Check whether the version information file can
- // be found in one of the parent directories. For performance reasons this
- // step is only done, if the previous directory was marked as versioned by
- // m_versionedDirectory. Drawback: Until e. g. Git is recognized, the root directory
- // must be shown at least once.
- if (m_versionedDirectory) {
- QUrl dirUrl(directory);
- QUrl upUrl = KIO::upUrl(dirUrl);
- int upUrlCounter = 1;
- while ((upUrlCounter < bestScore) && (upUrl != dirUrl)) {
- const QString fileName = dirUrl.path() + '/' + it.second;
- if (QFile::exists(fileName)) {
- if (upUrlCounter < bestScore) {
- bestPlugin = it.first;
- bestScore = upUrlCounter;
- }
- break;
- }
- dirUrl = upUrl;
- upUrl = KIO::upUrl(dirUrl);
- ++upUrlCounter;
- }
+ const QString root = plugin->localRepositoryRoot(directory.path());
+ if (!root.isEmpty()) {
+ m_localRepoRoot = root;
+ return plugin;
}
}
-
- return bestPlugin;
+ return nullptr;
}
bool VersionControlObserver::isVersionControlled() const
{
- return m_versionedDirectory && m_plugin;
+ return m_plugin != nullptr;
}
diff --git a/src/views/versioncontrol/versioncontrolobserver.h b/src/views/versioncontrol/versioncontrolobserver.h
index 89c047148..5f425fe85 100644
--- a/src/views/versioncontrol/versioncontrolobserver.h
+++ b/src/views/versioncontrol/versioncontrolobserver.h
@@ -101,7 +101,6 @@ private slots:
private:
typedef QPair<KFileItem, KVersionControlPlugin::ItemVersion> ItemState;
- typedef QPair<KVersionControlPlugin*, QString> VCSPlugin;
void updateItemStates();
@@ -133,10 +132,12 @@ private:
bool isVersionControlled() const;
private:
+ void initPlugins();
+
bool m_pendingItemStatesUpdate;
- bool m_versionedDirectory;
bool m_silentUpdate; // if true, no messages will be send during the update
// of version states
+ QString m_localRepoRoot;
DolphinView* m_view;
KFileItemModel* m_model;
@@ -145,7 +146,7 @@ private:
bool m_pluginsInitialized;
KVersionControlPlugin* m_plugin;
- QList<VCSPlugin> m_plugins;
+ QList<QPointer<KVersionControlPlugin>> m_plugins;
UpdateItemStatesThread* m_updateItemStatesThread;
friend class UpdateItemStatesThread;