-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathdirmodel.h
402 lines (321 loc) · 13.7 KB
/
dirmodel.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
/*
License: GPL-2
An electronic filing cabinet: scan, print, stack, arrange
Copyright (C) 2009 Simon Glass, [email protected]
.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
X-Comment: On Debian GNU/Linux systems, the complete text of the GNU General
Public License can be found in the /usr/share/common-licenses/GPL file.
*/
#include <QDirModel>
#include <QSortFilterProxyModel>
class Operation;
class TreeItem;
struct err_info;
/**
* @brief An item in the list of top-level paper repositories
*
* This contains information about a paper repository, including the top-level
* directory containing it. A list of these is contained in Dirmodel, which
* handles all the repositories visible to paperman.
*/
class Diritem
{
public:
Diritem (QDirModel *model);
~Diritem ();
// void setRecent(QModelIndex index);
bool isRecent(void) { return _recent; }
// QPersistentModelIndex index (void) const { return _index; }
QModelIndex index (void) const;
QString dir (void) const { return _dir; }
// bool valid (void) { return _valid; }
/**
* @brief Sets the directory, returning true if ok
* @param dir directory to set, updated to canonical path
* @return true if valid, false if directory is invalid
*/
bool setDir(QString& dir);
//!< Read or create a cache
TreeItem *ensureCache(Operation *op);
//!< Build a cache
TreeItem *buildCache(Operation *op);
// Drop the cache and free memory
void dropCache();
const QModelIndex rootIndex() const { return _root; }
/**
* @brief Refresh the cache from the given path
* @param Root path to refresh. Set this to the parent of anything that has
* changed
* Return: true if OK, false on failure to write cache to file
*/
bool refreshCache(const QString path, Operation *op);
private:
// Get the filename for the dir cache
QString dirCacheFilename() const;
// Read any available cache of the directory tree
bool readCache();
private:
QString _dir; //!< the directory
QDirModel *_model; //!< the directory model
// QPersistentModelIndex _index; //!< the index of this directory in the model
bool _valid; //!< true if the directory is valid
bool _recent; //!< true if this item displays a 'recent' list
QModelIndex _index; //!< index of this item, if _recent
TreeItem *_dir_cache; //!< Cache of the directory tree, or 0
QModelIndex _root; //!< index in this item's top-level dir in QDirModel
};
/** this model is like a QDirModel, but adds the facility to create some
top level 'mounts'. At the top level, only these mounts are present, and
each points to a directory somewhere in the tree. Therefore once in the
tree somewhere it is only possible to rise up to the top level mount for
that position
For example we might have top level directories like this:
/pub/paper
finance
marketing
projects
/pub/starmpaper
So the root parent will indicate that there are two rows, and asking for
either of these will return one of our special indexes (corresponding to
a Diritem). Going below (for example) /pub/paper you will see whatever
is in that directory. In this case that is the three items finance,
marketing and projects. Asking for the parent of one of these three will
return our special Diritem parent for /pub/paper, not the normal
QDirModel node. Asking for the parent again (of /pub/paper) will return
QModelIndex()
*/
class Dirmodel : public QDirModel
{
Q_OBJECT
friend class TestDirmodel;
public:
Dirmodel (QObject * parent = 0);
~Dirmodel ();
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent) override;
/**
* @brief add a new repository directory to the list
* @param dir directory add (updated to canonical path)
* @param ignore_error add the dir even if it doesn't exist
* @return true on success, else false
*/
bool addDir(QString& dir, bool ignore_error = false);
/** Remove a repository directory from the list
\param index model index of directory to remove */
bool removeDirFromList (const QModelIndex &index);
/**
* @brief mkdir
* @param parent parent directory to create it in
* @param name name of directory to create
* @param op operation to track progress (nullptr if none)
* @return Index of the created dir, or QModelIndex() on error
*/
QModelIndex mkdir(const QModelIndex &parent, const QString &name,
Operation *op);
/** count the number of files in a directory, upto the given maximum. Then
return a string like '45 files', or 'no files' */
QString countFiles(const QModelIndex &parent, int max);
/**
* @brief Create a root index for a Diritem
* @param item_ind Index of the item in the underlying model
* @param row Row number of the Diritem (position in _item)
* @return index in Dirmodel
*/
QModelIndex createRootIndex(QModelIndex item_ind, int row) const;
QModelIndex index(const QString & path, int column = 0) const;
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
override;
QModelIndex parent(const QModelIndex &index) const override;
QModelIndex index(int row, int column, const QModelIndex &parent)
const override;
QVariant headerData(int section, Qt::Orientation orientation, int role)
const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
/** returns the string for the given role for the 'recent' node */
QString getRecent(int role) const;
/** finds the index which corresponds to the 'root' for this index. This
root index is in our _items list, and has a null parent
\param index index whose root is to be found
\returns the index of the root, or QModelIndex() if not found */
QModelIndex findRoot(const QModelIndex &index) const;
// Diritem * findItem(QModelIndex index) const;
/** move a directory from to inside the given destination directory */
struct err_info *moveDir (QString src, QString dst);
Qt::DropActions supportedDropActions () const override;
/** finds the given index in our list of indices, if present, and returns the sequence
number of it
\returns sequence number if found, else -1 */
int findIndex (const QModelIndex &index) const;
/** checks if the index given is one of our special root indices
These are the top level repositories which appear in the dir tree.
\returns true if this index is a root index */
int isRoot (const QModelIndex &index) const;
/** given a directory path within an item, this finds the model index for that
path
\param item item to check within
\param path path to find (relative to the item's root path)
\returns the model index if found, or empty index if not */
QModelIndex findPath (int i, Diritem *item, QString path) const;
QString filePath (const QModelIndex &index) const;
/** displays the filename of this index and all its parents up to the root */
void traceIndex (const QModelIndex &index) const;
QStringList mimeTypes() const override;
bool hasChildren(const QModelIndex &parent) const override;
/** add a new index to the recent list
\param index index to add */
void addToRecent (QModelIndex &index);
/** check that a dirname does not overlap any existing top-level dirnames.
This means that it must not contain or be contained by any of them
\param dirname Dir to check
\param user_dirname Dir name as supplied by user (not canonical)
\returns NULL if ok, else error */
err_info *checkOverlap (QString &dirname, QString &user_dirname);
/**
* @brief Ensure that a cache is available
* @param root_ind Indirect of the top-level item the cache is for
* @param op Operation to update
* @return cache pointer
*
* This reads a cache file in, if not already done. If there is no cache, one
* is created and a cache file is written.
*/
TreeItem *ensureCache(const QModelIndex& root_ind, Operation *op);
/**
* @brief Find folders in the current repo which match a text string
* @param text Text to match
* @param dirPath Full path of the directory to search
* @param root Index of a top-level repository to search
* @param missing Suggestions for directories to create
* @param op Operation to update
* @return list of matching paths
*
* This looks for 4-digit years and 3-character months to try to guess
* which folders to put at the top of the list
*/
QStringList findFolders(const QString& text, const QString& dirPath,
const QModelIndex& root, QStringList& missing,
Operation *op);
/**
* @brief Find files matching a substring
* @param text Text to search for
* @param dirPath Full path to search, without trailing /
* @param root Index of the repository
* @param op Operation to updates
* @return List of matches, as paths relative to the root directory
*/
QStringList findFiles(const QString& text, const QString& dirPath,
const QModelIndex& root, Operation *op);
//! Refresh the cache for a given repository
void refreshCache(const QModelIndex& root_ind, Operation *op);
/**
* @brief Refresh a part of the cache
* @param parent Parent index to refresh
* @param op Operation to report to user
*
* All children of ind are regenerated but ind itself remains the same
*/
void refreshCacheFrom(const QModelIndex& parent, Operation *op);
private:
/** counts the number of files in 'path', adds it to count and returns it.
Stops if count > max
\param path path to check
\param count initial file count
\param max maximum count (to stop at)
\return number of files found */
int count_files (QString path, int count, int max);
/**
* @brief Add folder-name matches to a list
* @param matches List to update
* @param baseLen String length of the base directory path
* @param dirPath Full directory patch to search
* @param parent Cache node for dirPath
* @param match Search string to use
*
* Any matches found are added to matches - this function is recursive
*/
void addMatches(QStringList& matches, const uint baseLen,
const QString &dirPath, const TreeItem *parent,
const QString &match);
/**
* @brief Add filename matches to a list
* @param matches List to update
* @param baseLen String length of the base directory path
* @param dirPath Full directory patch to search
* @param parent Cache node for dirPath
* @param match Search string to use
*
* Any matches found are added to matches as paths relative to dirPath
* This function is recursive
*/
void addFileMatches(QStringList& matches, uint baseLen,
const QString &dirPath, const TreeItem *parent,
const QString& text);
/**
* @brief Find the a directory path in a tree
* @param parent Root of tree
* @param path Path to search for
* @return Node representing the path
*
* Given a path like "a/b/c" and a tree, this finds the assocated node for
* the path. In this case it would expect a child "a" of parent, then a
* grandchild "b", then a great grandchild "c", returning that node
*/
const TreeItem *findDir(const TreeItem *parent, QString path);
// Drop the cache for a repository
void dropCache(const QModelIndex& root_ind);
// Build a new cache
void buildCache(const QModelIndex& root_ind, Operation *op);
// Diritem *lookupItem(QModelIndex ind, QModelIndex& item_ind) const;
/**
* @brief Find an item
* @param ind
* @return
*/
Diritem * findItem(QModelIndex ind) const;
/**
* @brief Get the top-level index for an item
* @param row Row number of the item
* @return index for the item
*/
QModelIndex itemRootIndex(int row) const;
signals:
void droppedOnFolder (const QMimeData *data, QString &path);
private:
QList<Diritem *> _item; //!< a list of items to display
QModelIndex _root; //!< the model index of the root node
QModelIndexList _recent; //!< list of recent directories
/**
* @brief Maps a Dirmodel index to its associated Diritem and QDirModel index
*
* This does not store the top-level index for each Diritem
*/
QMap<QModelIndex, QPair<Diritem *, QModelIndex>> *_map;
};
class Dirproxy : public QSortFilterProxyModel
{
public:
Dirproxy(QObject *parent = nullptr);
~Dirproxy();
void setActive(bool active);
protected:
virtual bool filterAcceptsRow(int source_row,
const QModelIndex &source_parent) const;
// true if the proxy is filtering, false if it is just a pass-through
bool _active;
};
void dirmodel_tests (void);