1/*
2 * Copyright (C) by Klaas Freitag <freitag@kde.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15#ifndef FOLDERSTATUSMODEL_H
16#define FOLDERSTATUSMODEL_H
17
18#include <accountfwd.h>
19#include <QAbstractItemModel>
20#include <QLoggingCategory>
21#include <QVector>
22#include <QElapsedTimer>
23#include <QPointer>
24
25class QNetworkReply;
26namespace OCC {
27
28Q_DECLARE_LOGGING_CATEGORY(lcFolderStatus)
29
30class Folder;
31class ProgressInfo;
32class LsColJob;
33
34/**
35 * @brief The FolderStatusModel class
36 * @ingroup gui
37 */
38class FolderStatusModel : public QAbstractItemModel
39{
40 Q_OBJECT
41public:
42 FolderStatusModel(QObject *parent = 0);
43 ~FolderStatusModel();
44 void setAccountState(const AccountState *accountState);
45
46 Qt::ItemFlags flags(const QModelIndex &) const Q_DECL_OVERRIDE;
47 QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
48 bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE;
49 int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
50 int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
51 QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
52 QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE;
53 bool canFetchMore(const QModelIndex &parent) const Q_DECL_OVERRIDE;
54 void fetchMore(const QModelIndex &parent) Q_DECL_OVERRIDE;
55 bool hasChildren(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
56
57 struct SubFolderInfo
58 {
59 SubFolderInfo()
60 : _folder(0)
61 , _size(0)
62 , _isExternal(false)
63 , _fetched(false)
64 , _hasError(false)
65 , _fetchingLabel(false)
66 , _isUndecided(false)
67 , _checked(Qt::Checked)
68 {
69 }
70 Folder *_folder;
71 QString _name;
72 QString _path;
73 QVector<int> _pathIdx;
74 QVector<SubFolderInfo> _subs;
75 qint64 _size;
76 bool _isExternal;
77
78 bool _fetched; // If we did the LSCOL for this folder already
79 QPointer<LsColJob> _fetchingJob; // Currently running LsColJob
80 bool _hasError; // If the last fetching job ended in an error
81 QString _lastErrorString;
82 bool _fetchingLabel; // Whether a 'fetching in progress' label is shown.
83
84 // undecided folders are the big folders that the user has not accepted yet
85 bool _isUndecided;
86
87 Qt::CheckState _checked;
88
89 // Whether this has a FetchLabel subrow
90 bool hasLabel() const;
91
92 // Reset all subfolders and fetch status
93 void resetSubs(FolderStatusModel *model, QModelIndex index);
94
95 struct Progress
96 {
97 Progress()
98 : _warningCount(0)
99 , _overallPercent(0)
100 {
101 }
102 bool isNull() const
103 {
104 return _progressString.isEmpty() && _warningCount == 0 && _overallSyncString.isEmpty();
105 }
106 QString _progressString;
107 QString _overallSyncString;
108 int _warningCount;
109 int _overallPercent;
110 };
111 Progress _progress;
112 };
113
114 QVector<SubFolderInfo> _folders;
115
116 enum ItemType { RootFolder,
117 SubFolder,
118 AddButton,
119 FetchLabel };
120 ItemType classify(const QModelIndex &index) const;
121 SubFolderInfo *infoForIndex(const QModelIndex &index) const;
122
123 // If the selective sync check boxes were changed
124 bool isDirty() { return _dirty; }
125
126 /**
127 * return a QModelIndex for the given path within the given folder.
128 * Note: this method returns an invalid index if the path was not fetched from the server before
129 */
130 QModelIndex indexForPath(Folder *f, const QString &path) const;
131
132public slots:
133 void slotUpdateFolderState(Folder *);
134 void slotApplySelectiveSync();
135 void resetFolders();
136 void slotSyncAllPendingBigFolders();
137 void slotSyncNoPendingBigFolders();
138 void slotSetProgress(const ProgressInfo &progress);
139
140private slots:
141 void slotUpdateDirectories(const QStringList &);
142 void slotGatherPermissions(const QString &name, const QMap<QString, QString> &properties);
143 void slotLscolFinishedWithError(QNetworkReply *r);
144 void slotFolderSyncStateChange(Folder *f);
145 void slotFolderScheduleQueueChanged();
146 void slotNewBigFolder();
147
148 /**
149 * "In progress" labels for fetching data from the server are only
150 * added after some time to avoid popping.
151 */
152 void slotShowFetchProgress();
153
154private:
155 QStringList createBlackList(OCC::FolderStatusModel::SubFolderInfo *root,
156 const QStringList &oldBlackList) const;
157 const AccountState *_accountState;
158 bool _dirty; // If the selective sync checkboxes were changed
159
160 /**
161 * Keeps track of items that are fetching data from the server.
162 *
163 * See slotShowPendingFetchProgress()
164 */
165 QMap<QPersistentModelIndex, QElapsedTimer> _fetchingItems;
166
167signals:
168 void dirtyChanged();
169
170 // Tell the view that this item should be expanded because it has an undecided item
171 void suggestExpand(const QModelIndex &);
172
173 friend struct SubFolderInfo;
174};
175
176} // namespace OCC
177
178#endif // FOLDERSTATUSMODEL_H
179