1/*
2 * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
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 3 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,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#include "bookmarkmodel.h"
18#include "../systemconsts.h"
19
20#include <QFile>
21#include <QFileInfo>
22#include <QJsonArray>
23#include <QJsonDocument>
24#include <QJsonObject>
25#include <QJsonParseError>
26#include <QSet>
27#include "../utils.h"
28
29BookmarkModel::BookmarkModel(QObject* parent):QAbstractTableModel(parent)
30{
31
32}
33
34QSet<int> BookmarkModel::bookmarksInFile(const QString &filename)
35{
36 QSet<int> lines;
37 foreach (const PBookmark& bookmark, mBookmarks) {
38 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0) {
39 lines.insert(bookmark->line);
40 }
41 }
42 return lines;
43}
44
45void BookmarkModel::addBookmark(const QString &filename, int line, const QString &description)
46{
47 Q_ASSERT(!isBookmarkExists(filename,line));
48 PBookmark bookmark = std::make_shared<Bookmark>();
49 bookmark->filename = filename;
50 bookmark->line = line;
51 bookmark->description = description;
52 beginInsertRows(QModelIndex(),mBookmarks.count(),mBookmarks.count());
53 mBookmarks.append(bookmark);
54 endInsertRows();
55}
56
57PBookmark BookmarkModel::bookmark(int i)
58{
59 return mBookmarks[i];
60}
61
62PBookmark BookmarkModel::bookmark(const QString &filename, int line)
63{
64 for (int i=0;i<mBookmarks.count();i++) {
65 PBookmark bookmark = mBookmarks[i];
66 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0
67 && bookmark->line == line) {
68 return bookmark;
69 }
70 }
71 return PBookmark();
72}
73
74bool BookmarkModel::removeBookmark(const QString &filename, int line)
75{
76 for (int i=0;i<mBookmarks.count();i++) {
77 PBookmark bookmark = mBookmarks[i];
78 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0
79 && bookmark->line == line) {
80 removeBookmarkAt(i);
81 return true;
82 }
83 }
84 return false;
85}
86
87void BookmarkModel::removeBookmarks(const QString &filename)
88{
89 for (int i=mBookmarks.count()-1;i>=0;i--) {
90 PBookmark bookmark = mBookmarks[i];
91 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0) {
92 removeBookmarkAt(i);
93 }
94 }
95}
96
97void BookmarkModel::clear()
98{
99 beginResetModel();
100 mBookmarks.clear();
101 endResetModel();
102}
103
104bool BookmarkModel::updateDescription(const QString &filename, int line, const QString &description)
105{
106 for (int i=0;i<mBookmarks.count();i++) {
107 PBookmark bookmark = mBookmarks[i];
108 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0
109 && bookmark->line == line) {
110 bookmark->description = description;
111 emit dataChanged(createIndex(i,0),createIndex(i,2));
112 return true;
113 }
114 }
115 return false;
116}
117
118void BookmarkModel::save(const QString &filename)
119{
120 QFile file(filename);
121 if (file.open(QFile::WriteOnly | QFile::Truncate)) {
122 QJsonArray array;
123 foreach (const PBookmark& bookmark, mBookmarks) {
124 QJsonObject obj;
125 obj["filename"]=bookmark->filename;
126 obj["line"]=bookmark->line;
127 obj["description"]=bookmark->description;
128 array.append(obj);
129 }
130 QJsonDocument doc;
131 doc.setArray(array);
132 if (file.write(doc.toJson())<0) {
133 throw FileError(tr("Save file '%1' failed.")
134 .arg(filename));
135 }
136 } else {
137 throw FileError(tr("Can't open file '%1' for write.")
138 .arg(filename));
139 }
140}
141
142void BookmarkModel::load(const QString& filename)
143{
144 clear();
145 QFile file(filename);
146 if (!file.exists())
147 return;
148 if (file.open(QFile::ReadOnly)) {
149 QByteArray content = file.readAll();
150 QJsonParseError error;
151 QJsonDocument doc(QJsonDocument::fromJson(content,&error));
152 if (error.error != QJsonParseError::NoError) {
153 throw FileError(tr("Error in json file '%1':%2 : %3")
154 .arg(filename)
155 .arg(error.offset)
156 .arg(error.errorString()));
157 }
158 QJsonArray array = doc.array();
159 for (int i=0;i<array.count();i++) {
160 QJsonValue value = array[i];
161 QJsonObject obj=value.toObject();
162 addBookmark( QFileInfo(obj["filename"].toString()).absoluteFilePath(),
163 obj["line"].toInt(),
164 obj["description"].toString());
165
166 }
167 } else {
168 throw FileError(tr("Can't open file '%1' for read.")
169 .arg(filename));
170 }
171}
172
173void BookmarkModel::onFileDeleteLines(const QString &filename, int startLine, int count)
174{
175 for (int i = mBookmarks.count()-1;i>=0;i--){
176 PBookmark bookmark = mBookmarks[i];
177 if (bookmark->filename == filename
178 && bookmark->line>=startLine) {
179 if (bookmark->line >= startLine+count) {
180 bookmark->line -= count;
181 emit dataChanged(createIndex(i,0),createIndex(i,2));
182 } else {
183 removeBookmarkAt(i);
184 }
185 }
186 }
187}
188
189void BookmarkModel::onFileInsertLines(const QString &filename, int startLine, int count)
190{
191 for (int i = mBookmarks.count()-1;i>=0;i--){
192 PBookmark bookmark = mBookmarks[i];
193 if (bookmark->filename == filename
194 && bookmark->line>=startLine) {
195 bookmark->line+=count;
196 emit dataChanged(createIndex(i,0),createIndex(i,2));
197 }
198 }
199}
200
201void BookmarkModel::removeBookmarkAt(int i)
202{
203 beginRemoveRows(QModelIndex(), i,i);
204 mBookmarks.removeAt(i);
205 endRemoveRows();
206}
207
208bool BookmarkModel::isBookmarkExists(const QString &filename, int line)
209{
210 foreach (const PBookmark& bookmark, mBookmarks) {
211 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0
212 && bookmark->line == line) {
213 return true;
214 }
215 }
216 return false;
217}
218
219int BookmarkModel::rowCount(const QModelIndex &) const
220{
221 return mBookmarks.count();
222}
223
224QVariant BookmarkModel::data(const QModelIndex &index, int role) const
225{
226 if (!index.isValid())
227 return QVariant();
228 int row = index.row();
229 PBookmark bookmark = mBookmarks[row];
230 if (role == Qt::DisplayRole) {
231 switch(index.column()) {
232 case 0:
233 return bookmark->description;
234 case 1:
235 return bookmark->line;
236 case 2:
237 return bookmark->filename;
238 }
239 }
240 return QVariant();
241}
242
243int BookmarkModel::columnCount(const QModelIndex &) const
244{
245 return 3;
246}
247
248QVariant BookmarkModel::headerData(int section, Qt::Orientation orientation, int role) const
249{
250 if (orientation == Qt::Horizontal) {
251 if (role == Qt::DisplayRole) {
252 switch(section) {
253 case 0:
254 return tr("Description");
255 case 1:
256 return tr("Line");
257 case 2:
258 return tr("Filename");
259 }
260 }
261 }
262 return QVariant();
263}
264
265