]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/private/kdirectorycontentscounter.cpp
2c33edd4114079427b18d72c46a7ae6a6b378e85
[dolphin.git] / src / kitemviews / private / kdirectorycontentscounter.cpp
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
20
21 #include "kdirectorycontentscounter.h"
22
23 #include <kitemviews/kfileitemmodel.h>
24
25 #include <KDirWatch>
26 #include <QThread>
27
28 KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel* model, QObject* parent) :
29 QObject(parent),
30 m_model(model),
31 m_queue(),
32 m_worker(nullptr),
33 m_workerIsBusy(false),
34 m_dirWatcher(nullptr),
35 m_watchedDirs()
36 {
37 connect(m_model, &KFileItemModel::itemsRemoved,
38 this, &KDirectoryContentsCounter::slotItemsRemoved);
39
40 if (!m_workerThread) {
41 m_workerThread = new QThread();
42 m_workerThread->start();
43 }
44
45 m_worker = new KDirectoryContentsCounterWorker();
46 m_worker->moveToThread(m_workerThread);
47 ++m_workersCount;
48
49 connect(this, &KDirectoryContentsCounter::requestDirectoryContentsCount,
50 m_worker, &KDirectoryContentsCounterWorker::countDirectoryContents);
51 connect(m_worker, &KDirectoryContentsCounterWorker::result,
52 this, &KDirectoryContentsCounter::slotResult);
53
54 m_dirWatcher = new KDirWatch(this);
55 connect(m_dirWatcher, &KDirWatch::dirty, this, &KDirectoryContentsCounter::slotDirWatchDirty);
56 }
57
58 KDirectoryContentsCounter::~KDirectoryContentsCounter()
59 {
60 --m_workersCount;
61
62 if (m_workersCount > 0) {
63 // The worker thread will continue running. It could even be running
64 // a method of m_worker at the moment, so we delete it using
65 // deleteLater() to prevent a crash.
66 m_worker->deleteLater();
67 } else {
68 // There are no remaining workers -> stop the worker thread.
69 m_workerThread->quit();
70 m_workerThread->wait();
71 delete m_workerThread;
72 m_workerThread = nullptr;
73
74 // The worker thread has finished running now, so it's safe to delete
75 // m_worker. deleteLater() would not work at all because the event loop
76 // which would deliver the event to m_worker is not running any more.
77 delete m_worker;
78 }
79 }
80
81 void KDirectoryContentsCounter::addDirectory(const QString& path)
82 {
83 startWorker(path);
84 }
85
86 int KDirectoryContentsCounter::countDirectoryContentsSynchronously(const QString& path)
87 {
88 if (!m_dirWatcher->contains(path)) {
89 m_dirWatcher->addDir(path);
90 m_watchedDirs.insert(path);
91 }
92
93 KDirectoryContentsCounterWorker::Options options;
94
95 if (m_model->showHiddenFiles()) {
96 options |= KDirectoryContentsCounterWorker::CountHiddenFiles;
97 }
98
99 if (m_model->showDirectoriesOnly()) {
100 options |= KDirectoryContentsCounterWorker::CountDirectoriesOnly;
101 }
102
103 return KDirectoryContentsCounterWorker::subItemsCount(path, options);
104 }
105
106 void KDirectoryContentsCounter::slotResult(const QString& path, int count)
107 {
108 m_workerIsBusy = false;
109
110 if (!m_dirWatcher->contains(path)) {
111 m_dirWatcher->addDir(path);
112 m_watchedDirs.insert(path);
113 }
114
115 if (!m_queue.isEmpty()) {
116 startWorker(m_queue.dequeue());
117 }
118
119 emit result(path, count);
120 }
121
122 void KDirectoryContentsCounter::slotDirWatchDirty(const QString& path)
123 {
124 const int index = m_model->index(QUrl::fromLocalFile(path));
125 if (index >= 0) {
126 if (!m_model->fileItem(index).isDir()) {
127 // If INotify is used, KDirWatch issues the dirty() signal
128 // also for changed files inside the directory, even if we
129 // don't enable this behavior explicitly (see bug 309740).
130 return;
131 }
132
133 startWorker(path);
134 }
135 }
136
137 void KDirectoryContentsCounter::slotItemsRemoved()
138 {
139 const bool allItemsRemoved = (m_model->count() == 0);
140
141 if (!m_watchedDirs.isEmpty()) {
142 // Don't let KDirWatch watch for removed items
143 if (allItemsRemoved) {
144 foreach (const QString& path, m_watchedDirs) {
145 m_dirWatcher->removeDir(path);
146 }
147 m_watchedDirs.clear();
148 m_queue.clear();
149 } else {
150 QMutableSetIterator<QString> it(m_watchedDirs);
151 while (it.hasNext()) {
152 const QString& path = it.next();
153 if (m_model->index(QUrl::fromLocalFile(path)) < 0) {
154 m_dirWatcher->removeDir(path);
155 it.remove();
156 }
157 }
158 }
159 }
160 }
161
162 void KDirectoryContentsCounter::startWorker(const QString& path)
163 {
164 if (m_workerIsBusy) {
165 m_queue.enqueue(path);
166 } else {
167 KDirectoryContentsCounterWorker::Options options;
168
169 if (m_model->showHiddenFiles()) {
170 options |= KDirectoryContentsCounterWorker::CountHiddenFiles;
171 }
172
173 if (m_model->showDirectoriesOnly()) {
174 options |= KDirectoryContentsCounterWorker::CountDirectoriesOnly;
175 }
176
177 emit requestDirectoryContentsCount(path, options);
178 m_workerIsBusy = true;
179 }
180 }
181
182 QThread* KDirectoryContentsCounter::m_workerThread = nullptr;
183 int KDirectoryContentsCounter::m_workersCount = 0;