45
|
1 /****************************************************************************
|
|
2 **
|
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 ** Contact: Qt Software Information (qt-info@nokia.com)
|
|
5 **
|
|
6 ** This file is part of the demonstration applications of the Qt Toolkit.
|
|
7 **
|
|
8 ** $QT_BEGIN_LICENSE:LGPL$
|
|
9 ** Commercial Usage
|
|
10 ** Licensees holding valid Qt Commercial licenses may use this file in
|
|
11 ** accordance with the Qt Commercial License Agreement provided with the
|
|
12 ** Software or, alternatively, in accordance with the terms contained in
|
|
13 ** a written agreement between you and Nokia.
|
|
14 **
|
|
15 ** GNU Lesser General Public License Usage
|
|
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
17 ** General Public License version 2.1 as published by the Free Software
|
|
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
19 ** packaging of this file. Please review the following information to
|
|
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
22 **
|
|
23 ** In addition, as a special exception, Nokia gives you certain
|
|
24 ** additional rights. These rights are described in the Nokia Qt LGPL
|
|
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
|
26 ** package.
|
|
27 **
|
|
28 ** GNU General Public License Usage
|
|
29 ** Alternatively, this file may be used under the terms of the GNU
|
|
30 ** General Public License version 3.0 as published by the Free Software
|
|
31 ** Foundation and appearing in the file LICENSE.GPL included in the
|
|
32 ** packaging of this file. Please review the following information to
|
|
33 ** ensure the GNU General Public License version 3.0 requirements will be
|
|
34 ** met: http://www.gnu.org/copyleft/gpl.html.
|
|
35 **
|
|
36 ** If you are unsure which license is appropriate for your use, please
|
|
37 ** contact the sales department at qt-sales@nokia.com.
|
|
38 ** $QT_END_LICENSE$
|
|
39 **
|
|
40 ****************************************************************************/
|
|
41
|
72
|
42 module bookmarks;
|
45
|
43
|
|
44
|
72
|
45 import qt.core.QObject;
|
|
46 import qt.core.QAbstractItemModel;
|
|
47 import qt.core.QBuffer;
|
|
48 import qt.core.QFile;
|
|
49 import qt.core.QMimeData;
|
94
|
50 import qt.core.QPersistentModelIndex;
|
|
51 import qt.gui.QUndoStack;
|
|
52 import qt.gui.QUndoCommand;
|
72
|
53 import qt.gui.QDesktopServices;
|
|
54 import qt.gui.QDragEnterEvent;
|
|
55 import qt.gui.QFileDialog;
|
|
56 import qt.gui.QHeaderView;
|
|
57 import qt.gui.QIcon;
|
|
58 import qt.gui.QMessageBox;
|
|
59 import qt.gui.QToolButton;
|
113
|
60 import qt.gui.QTreeView;
|
100
|
61 import qt.xml.QXmlStreamReader;
|
|
62 import qt.webkit.QWebSettings;
|
72
|
63
|
100
|
64 import tango.text.convert.Format;
|
72
|
65
|
94
|
66 //import qt.core.QDebug;
|
72
|
67
|
45
|
68 import autosaver;
|
|
69 import browserapplication;
|
|
70 import history;
|
|
71 import xbel;
|
|
72
|
|
73
|
77
|
74 const string BOOKMARKBAR = "Bookmarks Bar";
|
|
75 const string BOOKMARKMENU = "Bookmarks Menu";
|
45
|
76
|
100
|
77 // workaround for QList implementation
|
|
78 int indexOf(T)(T[] items, T item)
|
|
79 {
|
|
80 for(auto i = 0; i < items.length; ++i)
|
|
81 {
|
|
82 if(items[i] == item)
|
|
83 return i;
|
|
84 }
|
|
85 return -1;
|
|
86 }
|
45
|
87
|
|
88 /*!
|
73
|
89 Bookmark manager, owner of the bookmarks, loads, saves and basic tasks
|
|
90 */
|
45
|
91 class BookmarksManager : public QObject
|
|
92 {
|
74
|
93 mixin Signal!("entryAdded", BookmarkNode /*item*/);
|
|
94 mixin Signal!("entryRemoved", BookmarkNode /*parent*/, int /*row*/, BookmarkNode /*item*/);
|
|
95 mixin Signal!("entryChanged", BookmarkNode /*item*/);
|
45
|
96
|
|
97 public:
|
73
|
98
|
|
99 this(QObject parent = null)
|
|
100 {
|
|
101 super(parent);
|
|
102 m_loaded = false;
|
|
103 m_saveTimer = new AutoSaver(this);
|
|
104 m_bookmarkRootNode = null;
|
|
105 m_bookmarkModel = null;
|
|
106 this.entryAdded.connect(&m_saveTimer.changeOccurred);
|
|
107 this.entryRemoved.connect(&m_saveTimer.changeOccurred);
|
|
108 this.entryChanged.connect(&m_saveTimer.changeOccurred);
|
|
109 }
|
45
|
110
|
73
|
111 ~this()
|
|
112 {
|
|
113 m_saveTimer.saveIfNeccessary();
|
|
114 }
|
45
|
115
|
73
|
116 void addBookmark(BookmarkNode parent, BookmarkNode node, int row = -1)
|
|
117 {
|
|
118 if (!m_loaded)
|
|
119 return;
|
|
120 assert(parent);
|
|
121 InsertBookmarksCommand command = new InsertBookmarksCommand(this, parent, node, row);
|
|
122 m_commands.push(command);
|
|
123 }
|
45
|
124
|
74
|
125 void removeBookmark(BookmarkNode node)
|
73
|
126 {
|
|
127 if (!m_loaded)
|
|
128 return;
|
|
129
|
|
130 assert(node);
|
|
131 BookmarkNode parent = node.parent();
|
100
|
132 int row = indexOf(parent.children(), node);
|
73
|
133 RemoveBookmarksCommand command = new RemoveBookmarksCommand(this, parent, row);
|
|
134 m_commands.push(command);
|
|
135 }
|
|
136
|
77
|
137 void setTitle(BookmarkNode node, string newTitle)
|
73
|
138 {
|
|
139 if (!m_loaded)
|
|
140 return;
|
|
141
|
|
142 assert(node);
|
|
143 ChangeBookmarkCommand command = new ChangeBookmarkCommand(this, node, newTitle, true);
|
|
144 m_commands.push(command);
|
|
145 }
|
45
|
146
|
77
|
147 void setUrl(BookmarkNode node, string newUrl)
|
73
|
148 {
|
|
149 if (!m_loaded)
|
|
150 return;
|
45
|
151
|
73
|
152 assert(node);
|
|
153 ChangeBookmarkCommand command = new ChangeBookmarkCommand(this, node, newUrl, false);
|
|
154 m_commands.push(command);
|
|
155 }
|
45
|
156
|
73
|
157 void changeExpanded()
|
|
158 {
|
|
159 m_saveTimer.changeOccurred();
|
|
160 }
|
45
|
161
|
74
|
162 BookmarkNode bookmarks()
|
73
|
163 {
|
|
164 if (!m_loaded)
|
|
165 load();
|
|
166 return m_bookmarkRootNode;
|
|
167 }
|
45
|
168
|
74
|
169 BookmarkNode menu()
|
73
|
170 {
|
|
171 if (!m_loaded)
|
|
172 load();
|
45
|
173
|
100
|
174 for (int i = m_bookmarkRootNode.children().length - 1; i >= 0; --i) {
|
77
|
175 BookmarkNode node = m_bookmarkRootNode.children()[i];
|
73
|
176 if (node.title == tr(BOOKMARKMENU))
|
|
177 return node;
|
|
178 }
|
|
179 assert(false);
|
100
|
180 return null;
|
73
|
181 }
|
45
|
182
|
74
|
183 BookmarkNode toolbar()
|
73
|
184 {
|
|
185 if (!m_loaded)
|
|
186 load();
|
45
|
187
|
100
|
188 for (int i = m_bookmarkRootNode.children().length - 1; i >= 0; --i) {
|
77
|
189 BookmarkNode node = m_bookmarkRootNode.children()[i];
|
73
|
190 if (node.title == tr(BOOKMARKBAR))
|
|
191 return node;
|
|
192 }
|
|
193 assert(false);
|
100
|
194 return null;
|
73
|
195 }
|
45
|
196
|
73
|
197 BookmarksModel bookmarksModel()
|
|
198 {
|
|
199 if (!m_bookmarkModel)
|
|
200 m_bookmarkModel = new BookmarksModel(this, this);
|
|
201 return m_bookmarkModel;
|
|
202 }
|
45
|
203
|
73
|
204 QUndoStack undoRedoStack() { return m_commands; };
|
45
|
205
|
73
|
206 public:
|
|
207
|
|
208 void importBookmarks()
|
|
209 {
|
100
|
210 string fileName = QFileDialog.getOpenFileName(null, tr("Open File"), null, tr("XBEL (*.xbel *.xml)"));
|
|
211 if (fileName.length == 0)
|
73
|
212 return;
|
45
|
213
|
100
|
214 auto reader = new XbelReader;
|
73
|
215 BookmarkNode importRootNode = reader.read(fileName);
|
|
216 if (reader.error() != QXmlStreamReader.NoError) {
|
100
|
217 QMessageBox.warning(null, "Loading Bookmark",
|
|
218 Format(tr("Error when loading bookmarks on line %1, column %2:\n"
|
|
219 "%3"), reader.lineNumber(), reader.columnNumber(), reader.errorString()));
|
73
|
220 }
|
45
|
221
|
100
|
222 importRootNode.setType(BookmarkNode.Type.Folder);
|
|
223 importRootNode.title = Format(tr("Imported %1"), QDate.currentDate().toString(Qt_DateFormat.SystemLocaleShortDate));
|
73
|
224 addBookmark(menu(), importRootNode);
|
|
225 }
|
45
|
226
|
73
|
227 void exportBookmarks()
|
|
228 {
|
100
|
229 string fileName = QFileDialog.getSaveFileName(null, tr("Save File"),
|
|
230 Format(tr("%1 Bookmarks.xbel"), QCoreApplication.applicationName()),
|
73
|
231 tr("XBEL (*.xbel *.xml)"));
|
100
|
232 if (fileName.length == 0)
|
73
|
233 return;
|
45
|
234
|
100
|
235 auto writer = new XbelWriter;
|
73
|
236 if (!writer.write(fileName, m_bookmarkRootNode))
|
100
|
237 QMessageBox.critical(null, tr("Export error"), tr("error saving bookmarks"));
|
73
|
238 }
|
45
|
239
|
73
|
240 private:
|
|
241
|
|
242 void save()
|
|
243 {
|
|
244 if (!m_loaded)
|
|
245 return;
|
45
|
246
|
100
|
247 auto writer = new XbelWriter;
|
77
|
248 string dir = QDesktopServices.storageLocation(QDesktopServices.DataLocation);
|
80
|
249 string bookmarkFile = dir ~ "/bookmarks.xbel";
|
73
|
250 if (!writer.write(bookmarkFile, m_bookmarkRootNode))
|
94
|
251 qWarning("BookmarkManager: error saving to" ~ bookmarkFile);
|
73
|
252 }
|
45
|
253
|
|
254 private:
|
73
|
255
|
|
256 void load()
|
|
257 {
|
|
258 if (m_loaded)
|
|
259 return;
|
|
260 m_loaded = true;
|
45
|
261
|
77
|
262 string dir = QDesktopServices.storageLocation(QDesktopServices.DataLocation);
|
80
|
263 string bookmarkFile = dir ~ "/bookmarks.xbel";
|
73
|
264 if (!QFile.exists(bookmarkFile))
|
80
|
265 bookmarkFile = ":defaultbookmarks.xbel";
|
45
|
266
|
73
|
267 XbelReader reader;
|
|
268 m_bookmarkRootNode = reader.read(bookmarkFile);
|
|
269 if (reader.error() != QXmlStreamReader.NoError) {
|
100
|
270 QMessageBox.warning(null, "Loading Bookmark",
|
|
271 Format(tr("Error when loading bookmarks on line %1, column %2:\n"
|
|
272 "%3"), reader.lineNumber(), reader.columnNumber(), reader.errorString()));
|
73
|
273 }
|
45
|
274
|
73
|
275 BookmarkNode toolbar = null;
|
|
276 BookmarkNode menu = null;
|
74
|
277 BookmarkNode[] others;
|
100
|
278 for (int i = m_bookmarkRootNode.children().length - 1; i >= 0; --i) {
|
77
|
279 BookmarkNode node = m_bookmarkRootNode.children()[i];
|
100
|
280 if (node.type() == BookmarkNode.Type.Folder) {
|
73
|
281 // Automatically convert
|
|
282 if (node.title == tr("Toolbar Bookmarks") && !toolbar) {
|
|
283 node.title = tr(BOOKMARKBAR);
|
|
284 }
|
|
285 if (node.title == tr(BOOKMARKBAR) && !toolbar) {
|
|
286 toolbar = node;
|
|
287 }
|
45
|
288
|
73
|
289 // Automatically convert
|
|
290 if (node.title == tr("Menu") && !menu) {
|
|
291 node.title = tr(BOOKMARKMENU);
|
|
292 }
|
|
293 if (node.title == tr(BOOKMARKMENU) && !menu) {
|
|
294 menu = node;
|
|
295 }
|
|
296 } else {
|
77
|
297 others ~= node;
|
73
|
298 }
|
|
299 m_bookmarkRootNode.remove(node);
|
|
300 }
|
100
|
301 assert(m_bookmarkRootNode.children().length == 0);
|
73
|
302 if (!toolbar) {
|
100
|
303 toolbar = new BookmarkNode(BookmarkNode.Type.Folder, m_bookmarkRootNode);
|
73
|
304 toolbar.title = tr(BOOKMARKBAR);
|
|
305 } else {
|
|
306 m_bookmarkRootNode.add(toolbar);
|
|
307 }
|
45
|
308
|
73
|
309 if (!menu) {
|
100
|
310 menu = new BookmarkNode(BookmarkNode.Type.Folder, m_bookmarkRootNode);
|
73
|
311 menu.title = tr(BOOKMARKMENU);
|
|
312 } else {
|
|
313 m_bookmarkRootNode.add(menu);
|
|
314 }
|
45
|
315
|
77
|
316 for (int i = 0; i < others.length; ++i)
|
|
317 menu.add(others[i]);
|
73
|
318 }
|
45
|
319
|
73
|
320 bool m_loaded;
|
|
321 AutoSaver m_saveTimer;
|
|
322 BookmarkNode m_bookmarkRootNode;
|
|
323 BookmarksModel m_bookmarkModel;
|
|
324 QUndoStack m_commands;
|
72
|
325 }
|
45
|
326
|
|
327 class RemoveBookmarksCommand : public QUndoCommand
|
|
328 {
|
73
|
329 public:
|
45
|
330
|
100
|
331 this(BookmarksManager m_bookmarkManager, BookmarkNode parent, int row)
|
73
|
332 {
|
100
|
333 super(tr("Remove Bookmark"));
|
73
|
334 m_row = row;
|
100
|
335 m_bookmarkManager = m_bookmarkManager;
|
|
336 m_node = (row < parent.children().length) ? parent.children()[row] : null;
|
73
|
337 m_parent = parent;
|
|
338 m_done = false;
|
|
339 }
|
45
|
340
|
73
|
341 ~this()
|
|
342 {
|
|
343 if (m_done && !m_node.parent()) {
|
|
344 delete m_node;
|
|
345 }
|
|
346 }
|
45
|
347
|
73
|
348 void undo()
|
|
349 {
|
|
350 m_parent.add(m_node, m_row);
|
100
|
351 m_bookmarkManager.entryAdded.emit(m_node);
|
73
|
352 m_done = false;
|
|
353 }
|
45
|
354
|
73
|
355 void redo()
|
|
356 {
|
|
357 m_parent.remove(m_node);
|
100
|
358 m_bookmarkManager.entryRemoved.emit(m_parent, m_row, m_node);
|
73
|
359 m_done = true;
|
|
360 }
|
45
|
361
|
|
362 protected:
|
73
|
363
|
|
364 int m_row;
|
100
|
365 BookmarksManager m_bookmarkManager;
|
73
|
366 BookmarkNode m_node;
|
|
367 BookmarkNode m_parent;
|
|
368 bool m_done;
|
|
369 }
|
45
|
370
|
|
371 class InsertBookmarksCommand : public RemoveBookmarksCommand
|
|
372 {
|
73
|
373 public:
|
100
|
374
|
|
375 this(BookmarksManager m_bookmarkManager, BookmarkNode parent, BookmarkNode node, int row)
|
73
|
376 {
|
100
|
377 super(m_bookmarkManager, parent, row);
|
45
|
378
|
100
|
379 setText(tr("Insert Bookmark"));
|
73
|
380 m_node = node;
|
|
381 }
|
45
|
382
|
73
|
383 void undo() { RemoveBookmarksCommand.redo(); }
|
|
384 void redo() { RemoveBookmarksCommand.undo(); }
|
45
|
385 }
|
|
386
|
|
387 class ChangeBookmarkCommand : public QUndoCommand
|
|
388 {
|
73
|
389 public:
|
45
|
390
|
100
|
391 this(BookmarksManager m_bookmarkManager, BookmarkNode node, string newValue, bool title)
|
73
|
392 {
|
|
393 super();
|
100
|
394 m_bookmarkManager = m_bookmarkManager;
|
73
|
395 m_title = title;
|
|
396 m_newValue = newValue;
|
|
397 m_node = node;
|
|
398 if (m_title) {
|
|
399 m_oldValue = m_node.title;
|
100
|
400 setText(tr("Name Change"));
|
73
|
401 } else {
|
|
402 m_oldValue = m_node.url;
|
100
|
403 setText(tr("Address Change"));
|
73
|
404 }
|
|
405 }
|
45
|
406
|
73
|
407 void undo()
|
|
408 {
|
|
409 if (m_title)
|
|
410 m_node.title = m_oldValue;
|
|
411 else
|
|
412 m_node.url = m_oldValue;
|
100
|
413 m_bookmarkManager.entryChanged.emit(m_node);
|
73
|
414 }
|
45
|
415
|
73
|
416 void redo()
|
|
417 {
|
|
418 if (m_title)
|
|
419 m_node.title = m_newValue;
|
|
420 else
|
|
421 m_node.url = m_newValue;
|
100
|
422 m_bookmarkManager.entryChanged.emit(m_node);
|
73
|
423 }
|
45
|
424
|
|
425 private:
|
73
|
426
|
100
|
427 BookmarksManager m_bookmarkManager;
|
73
|
428 bool m_title;
|
77
|
429 string m_oldValue;
|
|
430 string m_newValue;
|
73
|
431 BookmarkNode m_node;
|
45
|
432 }
|
|
433
|
|
434 /*!
|
73
|
435 BookmarksModel is a QAbstractItemModel wrapper around the BookmarkManager
|
|
436 */
|
72
|
437 import qt.gui.QIcon;
|
|
438
|
45
|
439 class BookmarksModel : public QAbstractItemModel
|
|
440 {
|
73
|
441 public:
|
45
|
442
|
73
|
443 void entryAdded(BookmarkNode item)
|
|
444 {
|
|
445 assert(item && item.parent());
|
100
|
446 int row = indexOf(item.parent().children(), item);
|
73
|
447 BookmarkNode parent = item.parent();
|
|
448 // item was already added so remove beore beginInsertRows is called
|
|
449 parent.remove(item);
|
|
450 beginInsertRows(index(parent), row, row);
|
|
451 parent.add(item, row);
|
|
452 endInsertRows();
|
|
453 }
|
45
|
454
|
74
|
455 void entryRemoved(BookmarkNode parent, int row, BookmarkNode item)
|
73
|
456 {
|
|
457 // item was already removed, re-add so beginRemoveRows works
|
|
458 parent.add(item, row);
|
|
459 beginRemoveRows(index(parent), row, row);
|
|
460 parent.remove(item);
|
|
461 endRemoveRows();
|
|
462 }
|
45
|
463
|
74
|
464 void entryChanged(BookmarkNode item)
|
73
|
465 {
|
|
466 QModelIndex idx = index(item);
|
74
|
467 dataChanged.emit(idx, idx);
|
73
|
468 }
|
|
469
|
45
|
470 public:
|
73
|
471
|
|
472 enum Roles {
|
|
473 TypeRole = Qt.UserRole + 1,
|
|
474 UrlRole = Qt.UserRole + 2,
|
|
475 UrlStringRole = Qt.UserRole + 3,
|
|
476 SeparatorRole = Qt.UserRole + 4
|
74
|
477 };
|
45
|
478
|
74
|
479 this(BookmarksManager bookmarkManager, QObject parent = null)
|
73
|
480 {
|
74
|
481 super(parent);
|
73
|
482 m_endMacro = false;
|
|
483 m_bookmarksManager = bookmarkManager;
|
|
484 bookmarkManager.entryAdded.connect(&this.entryAdded);
|
|
485 bookmarkManager.entryRemoved.connect(&this.entryRemoved);
|
|
486 bookmarkManager.entryChanged.connect(&this.entryChanged);
|
|
487 }
|
45
|
488
|
74
|
489 BookmarksManager bookmarksManager()
|
|
490 {
|
|
491 return m_bookmarksManager;
|
|
492 }
|
45
|
493
|
74
|
494 QVariant headerData(int section, Qt.Orientation orientation, int role = Qt.DisplayRole)
|
73
|
495 {
|
|
496 if (orientation == Qt.Horizontal && role == Qt.DisplayRole) {
|
|
497 switch (section) {
|
100
|
498 case 0: return new QVariant(tr("Title"));
|
|
499 case 1: return QVariant(tr("Address"));
|
73
|
500 }
|
|
501 }
|
|
502 return QAbstractItemModel.headerData(section, orientation, role);
|
|
503 }
|
45
|
504
|
73
|
505 QVariant data(QModelIndex index, int role = Qt.DisplayRole)
|
|
506 {
|
|
507 if (!index.isValid() || index.model() != this)
|
100
|
508 return new QVariant();
|
45
|
509
|
73
|
510 BookmarkNode bookmarkNode = node(index);
|
|
511 switch (role) {
|
100
|
512 case Qt_ItemDataRole.EditRole:
|
|
513 case Qt_ItemDataRole.DisplayRole:
|
|
514 if (bookmarkNode.type() == BookmarkNode.Type.Separator) {
|
73
|
515 switch (index.column()) {
|
100
|
516 case 0:
|
|
517 char[] tmp = new char[](50);
|
|
518 tmp[] = 0xB7;
|
|
519 return new QVariant(tmp);
|
94
|
520 case 1: return null;
|
73
|
521 }
|
|
522 }
|
45
|
523
|
73
|
524 switch (index.column()) {
|
100
|
525 case 0: return new QVariant(bookmarkNode.title);
|
|
526 case 1: return new QVariant(bookmarkNode.url);
|
73
|
527 }
|
|
528 break;
|
100
|
529 case BookmarksModel.Roles.UrlRole:
|
|
530 return new QVariant(new QUrl(bookmarkNode.url));
|
73
|
531 break;
|
100
|
532 case BookmarksModel.Roles.UrlStringRole:
|
|
533 return new QVariant(bookmarkNode.url);
|
73
|
534 break;
|
100
|
535 case BookmarksModel.Roles.TypeRole:
|
|
536 return new QVariant(cast(ulong) bookmarkNode.type());
|
73
|
537 break;
|
100
|
538 case BookmarksModel.Roles.SeparatorRole:
|
|
539 return new QVariant(bookmarkNode.type() == BookmarkNode.Type.Separator);
|
73
|
540 break;
|
100
|
541 case Qt_ItemDataRole.DecorationRole:
|
73
|
542 if (index.column() == 0) {
|
113
|
543 //TODO: is cast(void*) ok?
|
100
|
544 if (bookmarkNode.type() == BookmarkNode.Type.Folder)
|
113
|
545 return new QVariant(cast(void*) QApplication.style().standardIcon(QStyle.SP_DirIcon));
|
|
546 return new QVariant(cast(void*) BrowserApplication.instance().icon(new QUrl(bookmarkNode.url)));
|
73
|
547 }
|
|
548 }
|
45
|
549
|
100
|
550 return new QVariant();
|
73
|
551 }
|
|
552
|
|
553 int columnCount(QModelIndex parent = QModelIndex())
|
|
554 {
|
|
555 return (parent.column() > 0) ? 0 : 2;
|
|
556 }
|
|
557
|
|
558 int rowCount(QModelIndex parent = QModelIndex())
|
|
559 {
|
|
560 if (parent.column() > 0)
|
|
561 return 0;
|
45
|
562
|
73
|
563 if (!parent.isValid())
|
100
|
564 return m_bookmarksManager.bookmarks().children().length;
|
45
|
565
|
74
|
566 BookmarkNode item = cast(BookmarkNode) parent.internalPointer();
|
100
|
567 return item.children().length;
|
73
|
568 }
|
|
569
|
74
|
570 QModelIndex index(int row, int column, QModelIndex parent = QModelIndex())
|
73
|
571 {
|
|
572 if (row < 0 || column < 0 || row >= rowCount(parent) || column >= columnCount(parent))
|
|
573 return QModelIndex();
|
45
|
574
|
73
|
575 // get the parent node
|
|
576 BookmarkNode parentNode = node(parent);
|
100
|
577 return createIndex(row, column, cast(void*) parentNode.children()[row]);
|
73
|
578 }
|
45
|
579
|
74
|
580 QModelIndex parent(QModelIndex index = QModelIndex())
|
73
|
581 {
|
|
582 if (!index.isValid())
|
|
583 return QModelIndex();
|
45
|
584
|
73
|
585 BookmarkNode itemNode = node(index);
|
100
|
586 BookmarkNode parentNode = (itemNode ? itemNode.parent() : null);
|
73
|
587 if (!parentNode || parentNode == m_bookmarksManager.bookmarks())
|
|
588 return QModelIndex();
|
45
|
589
|
73
|
590 // get the parent's row
|
|
591 BookmarkNode grandParentNode = parentNode.parent();
|
|
592 int parentRow = grandParentNode.children().indexOf(parentNode);
|
|
593 assert(parentRow >= 0);
|
100
|
594 return createIndex(parentRow, 0, cast(void*) parentNode);
|
73
|
595 }
|
45
|
596
|
94
|
597 int flags(QModelIndex index)
|
73
|
598 {
|
|
599 if (!index.isValid())
|
|
600 return Qt.NoItemFlags;
|
|
601
|
94
|
602 int flags = Qt_ItemFlag.ItemIsSelectable | Qt_ItemFlag.ItemIsEnabled;
|
45
|
603
|
73
|
604 BookmarkNode bookmarkNode = node(index);
|
45
|
605
|
73
|
606 if (bookmarkNode != m_bookmarksManager.menu() && bookmarkNode != m_bookmarksManager.toolbar()) {
|
94
|
607 flags |= Qt_ItemFlag.ItemIsDragEnabled;
|
100
|
608 if (bookmarkNode.type() != BookmarkNode.Type.Separator)
|
94
|
609 flags |= Qt_ItemFlag.ItemIsEditable;
|
73
|
610 }
|
|
611 if (hasChildren(index))
|
94
|
612 flags |= Qt_ItemFlag.ItemIsDropEnabled;
|
73
|
613 return flags;
|
|
614 }
|
|
615
|
94
|
616 int supportedDropActions()
|
73
|
617 {
|
100
|
618 return Qt_DropAction.CopyAction | Qt_DropAction.MoveAction;
|
73
|
619 }
|
45
|
620
|
74
|
621 bool removeRows(int row, int count, QModelIndex parent = QModelIndex())
|
73
|
622 {
|
|
623 if (row < 0 || count <= 0 || row + count > rowCount(parent))
|
|
624 return false;
|
|
625
|
|
626 BookmarkNode bookmarkNode = node(parent);
|
|
627 for (int i = row + count - 1; i >= row; --i) {
|
77
|
628 BookmarkNode node = bookmarkNode.children()[i];
|
73
|
629 if (node == m_bookmarksManager.menu() || node == m_bookmarksManager.toolbar())
|
|
630 continue;
|
45
|
631
|
73
|
632 m_bookmarksManager.removeBookmark(node);
|
|
633 }
|
|
634 if (m_endMacro) {
|
|
635 m_bookmarksManager.undoRedoStack().endMacro();
|
|
636 m_endMacro = false;
|
|
637 }
|
|
638 return true;
|
|
639 }
|
|
640
|
94
|
641 bool setData(QModelIndex index, QVariant value, int role = Qt_ItemDataRole.EditRole)
|
73
|
642 {
|
94
|
643 if (!index.isValid() || (flags(index) & Qt_ItemFlag.ItemIsEditable) == 0)
|
73
|
644 return false;
|
45
|
645
|
73
|
646 BookmarkNode item = node(index);
|
45
|
647
|
73
|
648 switch (role) {
|
100
|
649 case Qt_ItemDataRole.EditRole:
|
|
650 case Qt_ItemDataRole.DisplayRole:
|
73
|
651 if (index.column() == 0) {
|
|
652 m_bookmarksManager.setTitle(item, value.toString());
|
|
653 break;
|
|
654 }
|
|
655 if (index.column() == 1) {
|
|
656 m_bookmarksManager.setUrl(item, value.toString());
|
|
657 break;
|
|
658 }
|
|
659 return false;
|
100
|
660 case BookmarksModel.Roles.UrlRole:
|
73
|
661 m_bookmarksManager.setUrl(item, value.toUrl().toString());
|
|
662 break;
|
100
|
663 case BookmarksModel.Roles.UrlStringRole:
|
73
|
664 m_bookmarksManager.setUrl(item, value.toString());
|
|
665 break;
|
|
666 default:
|
|
667 break;
|
|
668 return false;
|
|
669 }
|
|
670
|
|
671 return true;
|
|
672 }
|
45
|
673
|
94
|
674 QMimeData mimeData(QModelIndex[] indexes)
|
73
|
675 {
|
94
|
676 auto mimeData = new QMimeData();
|
|
677 auto data = new QByteArray;
|
|
678 auto stream = new QDataStream(data, QIODevice.WriteOnly);
|
74
|
679 foreach (QModelIndex index; indexes) {
|
73
|
680 if (index.column() != 0 || !index.isValid())
|
|
681 continue;
|
94
|
682 auto encodedData = new QByteArray;
|
|
683 auto buffer = new QBuffer(encodedData);
|
73
|
684 buffer.open(QBuffer.ReadWrite);
|
94
|
685 auto writer = new XbelWriter;
|
|
686 BookmarkNode parentNode = node(index);
|
|
687 writer.write(buffer, parentNode);
|
100
|
688 foreach(b; encodedData.data()[0..encodedData.size()])
|
|
689 stream.writeByte(cast(byte) b);
|
73
|
690 }
|
|
691 mimeData.setData(MIMETYPE, data);
|
|
692 return mimeData;
|
|
693 }
|
45
|
694
|
80
|
695 const string MIMETYPE = "application/bookmarks.xbel";
|
45
|
696
|
77
|
697 string[] mimeTypes()
|
73
|
698 {
|
77
|
699 return [ MIMETYPE ];
|
73
|
700 }
|
45
|
701
|
94
|
702 bool dropMimeData(QMimeData data, Qt_DropAction action, int row, int column, QModelIndex parent)
|
73
|
703 {
|
94
|
704 if (action == Qt_DropAction.IgnoreAction)
|
73
|
705 return true;
|
45
|
706
|
73
|
707 if (!data.hasFormat(MIMETYPE) || column > 0)
|
|
708 return false;
|
45
|
709
|
73
|
710 QByteArray ba = data.data(MIMETYPE);
|
94
|
711 QDataStream stream = new QDataStream(ba, QIODevice.ReadOnly);
|
73
|
712 if (stream.atEnd())
|
|
713 return false;
|
45
|
714
|
73
|
715 QUndoStack undoStack = m_bookmarksManager.undoRedoStack();
|
80
|
716 undoStack.beginMacro("Move Bookmarks");
|
45
|
717
|
73
|
718 while (!stream.atEnd()) {
|
94
|
719 auto encodedData = new QByteArray;
|
113
|
720 //stream >> encodedData; //TODO
|
100
|
721
|
94
|
722 auto buffer = new QBuffer(encodedData);
|
73
|
723 buffer.open(QBuffer.ReadOnly);
|
45
|
724
|
80
|
725 auto reader = new XbelReader;
|
94
|
726 BookmarkNode rootNode = reader.read(buffer);
|
74
|
727 BookmarkNode[] children = rootNode.children();
|
100
|
728 for (int i = 0; i < children.length; ++i) {
|
77
|
729 BookmarkNode bookmarkNode = children[i];
|
73
|
730 rootNode.remove(bookmarkNode);
|
|
731 row = qMax(0, row);
|
|
732 BookmarkNode parentNode = node(parent);
|
|
733 m_bookmarksManager.addBookmark(parentNode, bookmarkNode, row);
|
|
734 m_endMacro = true;
|
|
735 }
|
|
736 delete rootNode;
|
|
737 }
|
|
738 return true;
|
|
739 }
|
45
|
740
|
73
|
741 bool hasChildren(QModelIndex parent = QModelIndex())
|
|
742 {
|
|
743 if (!parent.isValid())
|
|
744 return true;
|
113
|
745 BookmarkNode parentNode = node(parent);
|
100
|
746 return (parentNode.type() == BookmarkNode.Type.Folder);
|
73
|
747 }
|
45
|
748
|
73
|
749 BookmarkNode node(QModelIndex index)
|
|
750 {
|
74
|
751 BookmarkNode itemNode = cast(BookmarkNode) index.internalPointer();
|
73
|
752 if (!itemNode)
|
|
753 return m_bookmarksManager.bookmarks();
|
|
754 return itemNode;
|
|
755 }
|
45
|
756
|
73
|
757 QModelIndex index(BookmarkNode node)
|
|
758 {
|
|
759 BookmarkNode parent = node.parent();
|
|
760 if (!parent)
|
|
761 return QModelIndex();
|
100
|
762 return createIndex(indexOf(parent.children(), node), 0, cast(void*) node);
|
73
|
763 }
|
45
|
764
|
|
765 private:
|
|
766
|
73
|
767 bool m_endMacro;
|
|
768 BookmarksManager m_bookmarksManager;
|
45
|
769 }
|
|
770
|
|
771 // Menu that is dynamically populated from the bookmarks
|
|
772 import modelmenu;
|
73
|
773
|
45
|
774 class BookmarksMenu : public ModelMenu
|
|
775 {
|
74
|
776 mixin Signal!("openUrl", QUrl /*url*/);
|
45
|
777
|
|
778 public:
|
73
|
779
|
74
|
780 this(QWidget parent = null)
|
73
|
781 {
|
|
782 super(parent);
|
100
|
783 m_bookmarksManager = null;
|
113
|
784 this.activated.connect(&this.activatedIndex);
|
73
|
785 setMaxRows(-1);
|
100
|
786 setHoverRole(BookmarksModel.Roles.UrlStringRole);
|
|
787 setSeparatorRole(BookmarksModel.Roles.SeparatorRole);
|
73
|
788 }
|
|
789
|
74
|
790 void setInitialActions(QAction[] actions)
|
73
|
791 {
|
|
792 m_initialActions = actions;
|
100
|
793 for (int i = 0; i < m_initialActions.length; ++i)
|
77
|
794 addAction(m_initialActions[i]);
|
73
|
795 }
|
|
796
|
45
|
797 protected:
|
73
|
798
|
45
|
799 bool prePopulated()
|
73
|
800 {
|
|
801 m_bookmarksManager = BrowserApplication.bookmarksManager();
|
|
802 setModel(m_bookmarksManager.bookmarksModel());
|
|
803 setRootIndex(m_bookmarksManager.bookmarksModel().index(1, 0));
|
|
804 // initial actions
|
100
|
805 for (int i = 0; i < m_initialActions.length; ++i)
|
77
|
806 addAction(m_initialActions[i]);
|
100
|
807 if (m_initialActions.length)
|
73
|
808 addSeparator();
|
|
809 createMenu(model().index(0, 0), 1, this);
|
|
810 return true;
|
|
811 }
|
45
|
812
|
|
813 private:
|
73
|
814
|
113
|
815 void activatedIndex(QModelIndex index)
|
73
|
816 {
|
100
|
817 openUrl.emit(index.data(BookmarksModel.Roles.UrlRole).toUrl());
|
73
|
818 }
|
|
819
|
|
820 private:
|
|
821
|
|
822 BookmarksManager m_bookmarksManager;
|
74
|
823 QAction[] m_initialActions;
|
45
|
824 }
|
|
825
|
|
826 /*
|
|
827 Proxy model that filters out the bookmarks so only the folders
|
|
828 are left behind. Used in the add bookmark dialog combobox.
|
|
829 */
|
72
|
830 import qt.gui.QSortFilterProxyModel;
|
|
831
|
45
|
832 class AddBookmarkProxyModel : public QSortFilterProxyModel
|
|
833 {
|
|
834 public:
|
73
|
835
|
|
836 this(QObject parent = null)
|
|
837 {
|
|
838 super(parent);
|
|
839 }
|
|
840
|
|
841 int columnCount(QModelIndex parent = QModelIndex())
|
|
842 {
|
|
843 return qMin(1, QSortFilterProxyModel.columnCount(parent));
|
|
844 }
|
|
845
|
|
846 protected:
|
|
847
|
|
848 bool filterAcceptsRow(int source_row, QModelIndex source_parent)
|
|
849 {
|
|
850 QModelIndex idx = sourceModel().index(source_row, 0, source_parent);
|
|
851 return sourceModel().hasChildren(idx);
|
|
852 }
|
45
|
853 }
|
|
854
|
|
855 /*!
|
73
|
856 Add bookmark dialog
|
|
857 */
|
72
|
858
|
45
|
859 import ui_addbookmarkdialog;
|
72
|
860
|
94
|
861 class AddBookmarkDialog : public QDialog //, public Ui_AddBookmarkDialog
|
45
|
862 {
|
113
|
863 mixin Ui_AddBookmarkDialog;
|
94
|
864
|
73
|
865 public:
|
45
|
866
|
77
|
867 this(string url, string title, QWidget parent = null, BookmarksManager bookmarkManager = null)
|
73
|
868 {
|
94
|
869 super(parent);
|
73
|
870 m_url = url;
|
|
871 m_bookmarksManager = bookmarkManager;
|
|
872
|
|
873 setWindowFlags(Qt.Sheet);
|
|
874 if (!m_bookmarksManager)
|
|
875 m_bookmarksManager = BrowserApplication.bookmarksManager();
|
113
|
876 setupUi(this);
|
|
877 auto view = new QTreeView(this);
|
73
|
878 m_proxyModel = new AddBookmarkProxyModel(this);
|
|
879 BookmarksModel model = m_bookmarksManager.bookmarksModel();
|
|
880 m_proxyModel.setSourceModel(model);
|
|
881 view.setModel(m_proxyModel);
|
|
882 view.expandAll();
|
|
883 view.header().setStretchLastSection(true);
|
|
884 view.header().hide();
|
|
885 view.setItemsExpandable(false);
|
|
886 view.setRootIsDecorated(false);
|
|
887 view.setIndentation(10);
|
|
888 location.setModel(m_proxyModel);
|
|
889 view.show();
|
|
890 location.setView(view);
|
|
891 BookmarkNode menu = m_bookmarksManager.menu();
|
|
892 QModelIndex idx = m_proxyModel.mapFromSource(model.index(menu));
|
|
893 view.setCurrentIndex(idx);
|
|
894 location.setCurrentIndex(idx.row());
|
|
895 name.setText(title);
|
|
896 }
|
72
|
897
|
|
898 private:
|
45
|
899
|
73
|
900 void accept()
|
|
901 {
|
|
902 QModelIndex index = location.view().currentIndex();
|
|
903 index = m_proxyModel.mapToSource(index);
|
|
904 if (!index.isValid())
|
|
905 index = m_bookmarksManager.bookmarksModel().index(0, 0);
|
|
906 BookmarkNode parent = m_bookmarksManager.bookmarksModel().node(index);
|
113
|
907 BookmarkNode bookmark = new BookmarkNode(BookmarkNode.Type.Bookmark);
|
73
|
908 bookmark.url = m_url;
|
|
909 bookmark.title = name.text();
|
|
910 m_bookmarksManager.addBookmark(parent, bookmark);
|
|
911 QDialog.accept();
|
|
912 }
|
45
|
913
|
|
914 private:
|
73
|
915
|
77
|
916 string m_url;
|
73
|
917 BookmarksManager m_bookmarksManager;
|
|
918 AddBookmarkProxyModel m_proxyModel;
|
45
|
919 }
|
|
920
|
150
|
921 import ui_bookmarksdialog;
|
45
|
922
|
|
923 //class TreeProxyModel;
|
94
|
924 class BookmarksDialog : public QDialog //, public Ui_BookmarksDialog
|
45
|
925 {
|
113
|
926 mixin Ui_BookmarksDialog;
|
94
|
927
|
74
|
928 mixin Signal!("openUrl", QUrl /*url*/);
|
45
|
929
|
|
930 public:
|
73
|
931
|
|
932 this(QWidget parent = null, BookmarksManager manager = null)
|
|
933 {
|
94
|
934 super(parent);
|
73
|
935 m_bookmarksManager = manager;
|
|
936 if (!m_bookmarksManager)
|
|
937 m_bookmarksManager = BrowserApplication.bookmarksManager();
|
113
|
938 setupUi(this);
|
45
|
939
|
73
|
940 tree.setUniformRowHeights(true);
|
|
941 tree.setSelectionBehavior(QAbstractItemView.SelectRows);
|
|
942 tree.setSelectionMode(QAbstractItemView.ContiguousSelection);
|
|
943 tree.setTextElideMode(Qt.ElideMiddle);
|
|
944 m_bookmarksModel = m_bookmarksManager.bookmarksModel();
|
|
945 m_proxyModel = new TreeProxyModel(this);
|
|
946 search.textChanged.connect(&m_proxyModel.setFilterFixedString);
|
|
947 removeButton.clicked.connect(&tree.removeOne);
|
|
948 m_proxyModel.setSourceModel(m_bookmarksModel);
|
|
949 tree.setModel(m_proxyModel);
|
|
950 tree.setDragDropMode(QAbstractItemView.InternalMove);
|
|
951 tree.setExpanded(m_proxyModel.index(0, 0), true);
|
|
952 tree.setAlternatingRowColors(true);
|
|
953 auto fm = new QFontMetrics(font());
|
113
|
954 int header = fm.width("m") * 40;
|
73
|
955 tree.header().resizeSection(0, header);
|
|
956 tree.header().setStretchLastSection(true);
|
|
957 tree.activated.connect(&this.open);
|
|
958 tree.setContextMenuPolicy(Qt.CustomContextMenu);
|
|
959 tree.customContextMenuRequested.connect(&this.customContextMenuRequested);
|
|
960 addFolderButton.clicked.connect(&this.newFolder);
|
|
961 expandNodes(m_bookmarksManager.bookmarks());
|
|
962 setAttribute(Qt.WA_DeleteOnClose);
|
|
963 }
|
|
964
|
|
965 ~this()
|
|
966 {
|
|
967 if (saveExpandedNodes(tree.rootIndex()))
|
|
968 m_bookmarksManager.changeExpanded();
|
|
969 }
|
45
|
970
|
|
971 private:
|
73
|
972
|
|
973 void customContextMenuRequested(QPoint pos)
|
|
974 {
|
77
|
975 auto menu = new QMenu;
|
73
|
976 QModelIndex index = tree.indexAt(pos);
|
|
977 index = index.sibling(index.row(), 0);
|
|
978 if (index.isValid() && !tree.model().hasChildren(index)) {
|
113
|
979 auto action = new QAction(tr("Open"), this);
|
|
980 action.triggered.connect(&this.open);
|
|
981 menu.addAction(action);
|
73
|
982 menu.addSeparator();
|
|
983 }
|
113
|
984 auto action = new QAction(tr("Delete"), this);
|
|
985 action.triggered.connect(&tree.removeOne);
|
|
986 menu.addAction(action);
|
73
|
987 menu.exec(QCursor.pos());
|
|
988 }
|
|
989
|
|
990 void open()
|
|
991 {
|
|
992 QModelIndex index = tree.currentIndex();
|
|
993 if (!index.parent().isValid())
|
|
994 return;
|
100
|
995 openUrl.emit(index.sibling(index.row(), 1).data(BookmarksModel.Roles.UrlRole).toUrl());
|
73
|
996 }
|
|
997
|
|
998 void newFolder()
|
|
999 {
|
|
1000 QModelIndex currentIndex = tree.currentIndex();
|
|
1001 QModelIndex idx = currentIndex;
|
|
1002 if (idx.isValid() && !idx.model().hasChildren(idx))
|
|
1003 idx = idx.parent();
|
|
1004 if (!idx.isValid())
|
|
1005 idx = tree.rootIndex();
|
|
1006 idx = m_proxyModel.mapToSource(idx);
|
|
1007 BookmarkNode parent = m_bookmarksManager.bookmarksModel().node(idx);
|
100
|
1008 BookmarkNode node = new BookmarkNode(BookmarkNode.Type.Folder);
|
73
|
1009 node.title = tr("New Folder");
|
|
1010 m_bookmarksManager.addBookmark(parent, node, currentIndex.row() + 1);
|
|
1011 }
|
45
|
1012
|
73
|
1013 private:
|
|
1014 void expandNodes(BookmarkNode node)
|
|
1015 {
|
113
|
1016 for (int i = 0; i < node.children().length; ++i) {
|
73
|
1017 BookmarkNode childNode = node.children()[i];
|
|
1018 if (childNode.expanded) {
|
|
1019 QModelIndex idx = m_bookmarksModel.index(childNode);
|
|
1020 idx = m_proxyModel.mapFromSource(idx);
|
|
1021 tree.setExpanded(idx, true);
|
|
1022 expandNodes(childNode);
|
|
1023 }
|
|
1024 }
|
|
1025 }
|
45
|
1026
|
73
|
1027 bool saveExpandedNodes(QModelIndex parent)
|
|
1028 {
|
|
1029 bool changed = false;
|
|
1030 for (int i = 0; i < m_proxyModel.rowCount(parent); ++i) {
|
|
1031 QModelIndex child = m_proxyModel.index(i, 0, parent);
|
|
1032 QModelIndex sourceIndex = m_proxyModel.mapToSource(child);
|
|
1033 BookmarkNode childNode = m_bookmarksModel.node(sourceIndex);
|
|
1034 bool wasExpanded = childNode.expanded;
|
|
1035 if (tree.isExpanded(child)) {
|
|
1036 childNode.expanded = true;
|
|
1037 changed |= saveExpandedNodes(child);
|
|
1038 } else {
|
|
1039 childNode.expanded = false;
|
|
1040 }
|
|
1041 changed |= (wasExpanded != childNode.expanded);
|
|
1042 }
|
|
1043 return changed;
|
|
1044 }
|
|
1045
|
|
1046 BookmarksManager m_bookmarksManager;
|
|
1047 BookmarksModel m_bookmarksModel;
|
|
1048 TreeProxyModel m_proxyModel;
|
72
|
1049 }
|
45
|
1050
|
74
|
1051
|
72
|
1052 import qt.gui.QToolBar;
|
|
1053
|
74
|
1054
|
45
|
1055 class BookmarksToolBar : public QToolBar
|
|
1056 {
|
113
|
1057 mixin Signal!("openUrl", QUrl /*url*/);
|
45
|
1058
|
|
1059 public:
|
|
1060
|
73
|
1061 this(BookmarksModel model, QWidget parent = null)
|
|
1062 {
|
|
1063 super(tr("Bookmark"), parent);
|
|
1064 m_bookmarksModel = model;
|
|
1065 this.actionTriggered.connect(&this.triggered);
|
|
1066 setRootIndex(model.index(0, 0));
|
|
1067 m_bookmarksModel.modelReset.connect(&this.build);
|
|
1068 m_bookmarksModel.rowsInserted.connect(&this.build);
|
|
1069 m_bookmarksModel.rowsRemoved.connect(&this.build);
|
|
1070 m_bookmarksModel.dataChanged.connect(&this.build);
|
|
1071 setAcceptDrops(true);
|
|
1072 }
|
45
|
1073
|
74
|
1074 void setRootIndex(QModelIndex index)
|
73
|
1075 {
|
|
1076 m_root = index;
|
|
1077 build();
|
|
1078 }
|
|
1079
|
|
1080 QModelIndex rootIndex()
|
|
1081 {
|
|
1082 return m_root;
|
|
1083 }
|
45
|
1084
|
|
1085 protected:
|
|
1086
|
73
|
1087 void dragEnterEvent(QDragEnterEvent event)
|
|
1088 {
|
77
|
1089 QMimeData mimeData = event.mimeData();
|
73
|
1090 if (mimeData.hasUrls())
|
|
1091 event.acceptProposedAction();
|
113
|
1092 super.dragEnterEvent(event);
|
73
|
1093 }
|
45
|
1094
|
73
|
1095 void dropEvent(QDropEvent event)
|
|
1096 {
|
77
|
1097 QMimeData mimeData = event.mimeData();
|
73
|
1098 if (mimeData.hasUrls() && mimeData.hasText()) {
|
74
|
1099 QUrl[] urls = mimeData.urls();
|
73
|
1100 QAction action = actionAt(event.pos());
|
77
|
1101 string dropText;
|
73
|
1102 if (action)
|
|
1103 dropText = action.text();
|
|
1104 int row = -1;
|
|
1105 QModelIndex parentIndex = m_root;
|
|
1106 for (int i = 0; i < m_bookmarksModel.rowCount(m_root); ++i) {
|
|
1107 QModelIndex idx = m_bookmarksModel.index(i, 0, m_root);
|
77
|
1108 string title = idx.data().toString();
|
73
|
1109 if (title == dropText) {
|
|
1110 row = i;
|
|
1111 if (m_bookmarksModel.hasChildren(idx)) {
|
|
1112 parentIndex = idx;
|
|
1113 row = -1;
|
|
1114 }
|
|
1115 break;
|
|
1116 }
|
|
1117 }
|
113
|
1118 BookmarkNode bookmark = new BookmarkNode(BookmarkNode.Type.Bookmark);
|
77
|
1119 bookmark.url = urls[0].toString();
|
73
|
1120 bookmark.title = mimeData.text();
|
45
|
1121
|
73
|
1122 BookmarkNode parent = m_bookmarksModel.node(parentIndex);
|
|
1123 BookmarksManager bookmarksManager = m_bookmarksModel.bookmarksManager();
|
|
1124 bookmarksManager.addBookmark(parent, bookmark, row);
|
|
1125 event.acceptProposedAction();
|
|
1126 }
|
100
|
1127 super.dropEvent(event);
|
73
|
1128 }
|
45
|
1129
|
|
1130 private:
|
73
|
1131
|
|
1132 void triggered(QAction action)
|
|
1133 {
|
|
1134 QVariant v = action.data();
|
142
|
1135 if (v.canConvert!(QUrl)) {
|
74
|
1136 openUrl.emit(v.toUrl());
|
73
|
1137 }
|
|
1138 }
|
|
1139
|
|
1140 void activated(QModelIndex index)
|
|
1141 {
|
100
|
1142 openUrl.emit(index.data(BookmarksModel.Roles.UrlRole).toUrl());
|
73
|
1143 }
|
|
1144
|
|
1145 void build()
|
|
1146 {
|
|
1147 clear();
|
|
1148 for (int i = 0; i < m_bookmarksModel.rowCount(m_root); ++i) {
|
|
1149 QModelIndex idx = m_bookmarksModel.index(i, 0, m_root);
|
|
1150 if (m_bookmarksModel.hasChildren(idx)) {
|
|
1151 QToolButton button = new QToolButton(this);
|
|
1152 button.setPopupMode(QToolButton.InstantPopup);
|
94
|
1153 button.setArrowType(Qt_ArrowType.DownArrow);
|
73
|
1154 button.setText(idx.data().toString());
|
|
1155 ModelMenu menu = new ModelMenu(this);
|
|
1156 menu.activated.connect(&this.activated);
|
|
1157 menu.setModel(m_bookmarksModel);
|
|
1158 menu.setRootIndex(idx);
|
|
1159 menu.addAction(new QAction(menu));
|
|
1160 button.setMenu(menu);
|
100
|
1161 button.setToolButtonStyle(Qt_ToolButtonStyle.ToolButtonTextOnly);
|
73
|
1162 QAction a = addWidget(button);
|
|
1163 a.setText(idx.data().toString());
|
|
1164 } else {
|
|
1165 QAction action = addAction(idx.data().toString());
|
100
|
1166 action.setData(idx.data(BookmarksModel.Roles.UrlRole));
|
73
|
1167 }
|
|
1168 }
|
|
1169 }
|
|
1170
|
|
1171 private:
|
|
1172
|
|
1173 BookmarksModel m_bookmarksModel;
|
113
|
1174 /*TODO: needed? QPersistentModelIndex*/ QModelIndex m_root;
|
45
|
1175 }
|