xref: /OK3568_Linux_fs/app/forlinx/flapp/src/plugins/allwinner/browser/bookmarks.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the demonstration applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33 
34 #include "bookmarks.h"
35 
36 #include "autosaver.h"
37 #include "browserapplication.h"
38 #include "history.h"
39 #include "xbel.h"
40 
41 #include <QtCore/QBuffer>
42 #include <QtCore/QFile>
43 #include <QtCore/QMimeData>
44 
45 #include <QtGui/QDesktopServices>
46 #include <QtGui/QDragEnterEvent>
47 #include <QtGui/QIcon>
48 #include <QtWidgets/QFileDialog>
49 #include <QtWidgets/QHeaderView>
50 #include <QtWidgets/QMessageBox>
51 #include <QtWidgets/QToolButton>
52 
53 #include <QWebSettings>
54 
55 #include <QtCore/QDebug>
56 
57 #define BOOKMARKBAR "Bookmarks Bar"
58 #define BOOKMARKMENU "Bookmarks Menu"
59 
BookmarksManager(QObject * parent)60 BookmarksManager::BookmarksManager(QObject *parent)
61     : QObject(parent)
62     , m_loaded(false)
63     , m_saveTimer(new AutoSaver(this))
64     , m_bookmarkRootNode(0)
65     , m_bookmarkModel(0)
66 {
67     connect(this, SIGNAL(entryAdded(BookmarkNode*)),
68             m_saveTimer, SLOT(changeOccurred()));
69     connect(this, SIGNAL(entryRemoved(BookmarkNode*,int,BookmarkNode*)),
70             m_saveTimer, SLOT(changeOccurred()));
71     connect(this, SIGNAL(entryChanged(BookmarkNode*)),
72             m_saveTimer, SLOT(changeOccurred()));
73 }
74 
~BookmarksManager()75 BookmarksManager::~BookmarksManager()
76 {
77     m_saveTimer->saveIfNeccessary();
78 }
79 
changeExpanded()80 void BookmarksManager::changeExpanded()
81 {
82     m_saveTimer->changeOccurred();
83 }
84 
load()85 void BookmarksManager::load()
86 {
87     if (m_loaded)
88         return;
89     m_loaded = true;
90 
91     QString dir = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
92     QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel");
93     if (!QFile::exists(bookmarkFile))
94         bookmarkFile = QLatin1String(":defaultbookmarks.xbel");
95 
96     XbelReader reader;
97     m_bookmarkRootNode = reader.read(bookmarkFile);
98     if (reader.error() != QXmlStreamReader::NoError) {
99         QMessageBox::warning(0, QLatin1String("Loading Bookmark"),
100             tr("Error when loading bookmarks on line %1, column %2:\n"
101                "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
102     }
103 
104     BookmarkNode *toolbar = 0;
105     BookmarkNode *menu = 0;
106     QList<BookmarkNode*> others;
107     for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
108         BookmarkNode *node = m_bookmarkRootNode->children().at(i);
109         if (node->type() == BookmarkNode::Folder) {
110             // Automatically convert
111             if (node->title == tr("Toolbar Bookmarks") && !toolbar) {
112                 node->title = tr(BOOKMARKBAR);
113             }
114             if (node->title == tr(BOOKMARKBAR) && !toolbar) {
115                 toolbar = node;
116             }
117 
118             // Automatically convert
119             if (node->title == tr("Menu") && !menu) {
120                 node->title = tr(BOOKMARKMENU);
121             }
122             if (node->title == tr(BOOKMARKMENU) && !menu) {
123                 menu = node;
124             }
125         } else {
126             others.append(node);
127         }
128         m_bookmarkRootNode->remove(node);
129     }
130     Q_ASSERT(m_bookmarkRootNode->children().count() == 0);
131     if (!toolbar) {
132         toolbar = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
133         toolbar->title = tr(BOOKMARKBAR);
134     } else {
135         m_bookmarkRootNode->add(toolbar);
136     }
137 
138     if (!menu) {
139         menu = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
140         menu->title = tr(BOOKMARKMENU);
141     } else {
142         m_bookmarkRootNode->add(menu);
143     }
144 
145     for (int i = 0; i < others.count(); ++i)
146         menu->add(others.at(i));
147 }
148 
save() const149 void BookmarksManager::save() const
150 {
151     if (!m_loaded)
152         return;
153 
154     XbelWriter writer;
155     QString dir = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
156     QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel");
157     if (!writer.write(bookmarkFile, m_bookmarkRootNode))
158         qWarning() << "BookmarkManager: error saving to" << bookmarkFile;
159 }
160 
addBookmark(BookmarkNode * parent,BookmarkNode * node,int row)161 void BookmarksManager::addBookmark(BookmarkNode *parent, BookmarkNode *node, int row)
162 {
163     if (!m_loaded)
164         return;
165     Q_ASSERT(parent);
166     InsertBookmarksCommand *command = new InsertBookmarksCommand(this, parent, node, row);
167     m_commands.push(command);
168 }
169 
removeBookmark(BookmarkNode * node)170 void BookmarksManager::removeBookmark(BookmarkNode *node)
171 {
172     if (!m_loaded)
173         return;
174 
175     Q_ASSERT(node);
176     BookmarkNode *parent = node->parent();
177     int row = parent->children().indexOf(node);
178     RemoveBookmarksCommand *command = new RemoveBookmarksCommand(this, parent, row);
179     m_commands.push(command);
180 }
181 
setTitle(BookmarkNode * node,const QString & newTitle)182 void BookmarksManager::setTitle(BookmarkNode *node, const QString &newTitle)
183 {
184     if (!m_loaded)
185         return;
186 
187     Q_ASSERT(node);
188     ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newTitle, true);
189     m_commands.push(command);
190 }
191 
setUrl(BookmarkNode * node,const QString & newUrl)192 void BookmarksManager::setUrl(BookmarkNode *node, const QString &newUrl)
193 {
194     if (!m_loaded)
195         return;
196 
197     Q_ASSERT(node);
198     ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newUrl, false);
199     m_commands.push(command);
200 }
201 
bookmarks()202 BookmarkNode *BookmarksManager::bookmarks()
203 {
204     if (!m_loaded)
205         load();
206     return m_bookmarkRootNode;
207 }
208 
menu()209 BookmarkNode *BookmarksManager::menu()
210 {
211     if (!m_loaded)
212         load();
213 
214     for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
215         BookmarkNode *node = m_bookmarkRootNode->children().at(i);
216         if (node->title == tr(BOOKMARKMENU))
217             return node;
218     }
219     Q_ASSERT(false);
220     return 0;
221 }
222 
toolbar()223 BookmarkNode *BookmarksManager::toolbar()
224 {
225     if (!m_loaded)
226         load();
227 
228     for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
229         BookmarkNode *node = m_bookmarkRootNode->children().at(i);
230         if (node->title == tr(BOOKMARKBAR))
231             return node;
232     }
233     Q_ASSERT(false);
234     return 0;
235 }
236 
bookmarksModel()237 BookmarksModel *BookmarksManager::bookmarksModel()
238 {
239     if (!m_bookmarkModel)
240         m_bookmarkModel = new BookmarksModel(this, this);
241     return m_bookmarkModel;
242 }
243 
importBookmarks()244 void BookmarksManager::importBookmarks()
245 {
246     QString fileName = QFileDialog::getOpenFileName(0, tr("Open File"),
247                                                      QString(),
248                                                      tr("XBEL (*.xbel *.xml)"));
249     if (fileName.isEmpty())
250         return;
251 
252     XbelReader reader;
253     BookmarkNode *importRootNode = reader.read(fileName);
254     if (reader.error() != QXmlStreamReader::NoError) {
255         QMessageBox::warning(0, QLatin1String("Loading Bookmark"),
256             tr("Error when loading bookmarks on line %1, column %2:\n"
257                "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
258     }
259 
260     importRootNode->setType(BookmarkNode::Folder);
261     importRootNode->title = (tr("Imported %1").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate)));
262     addBookmark(menu(), importRootNode);
263 }
264 
exportBookmarks()265 void BookmarksManager::exportBookmarks()
266 {
267     QString fileName = QFileDialog::getSaveFileName(0, tr("Save File"),
268                                 tr("%1 Bookmarks.xbel").arg(QCoreApplication::applicationName()),
269                                 tr("XBEL (*.xbel *.xml)"));
270     if (fileName.isEmpty())
271         return;
272 
273     XbelWriter writer;
274     if (!writer.write(fileName, m_bookmarkRootNode))
275         QMessageBox::critical(0, tr("Export error"), tr("error saving bookmarks"));
276 }
277 
RemoveBookmarksCommand(BookmarksManager * m_bookmarkManagaer,BookmarkNode * parent,int row)278 RemoveBookmarksCommand::RemoveBookmarksCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *parent, int row)
279     : QUndoCommand(BookmarksManager::tr("Remove Bookmark"))
280     , m_row(row)
281     , m_bookmarkManagaer(m_bookmarkManagaer)
282     , m_node(parent->children().value(row))
283     , m_parent(parent)
284     , m_done(false)
285 {
286 }
287 
~RemoveBookmarksCommand()288 RemoveBookmarksCommand::~RemoveBookmarksCommand()
289 {
290     if (m_done && !m_node->parent()) {
291         delete m_node;
292     }
293 }
294 
undo()295 void RemoveBookmarksCommand::undo()
296 {
297     m_parent->add(m_node, m_row);
298     emit m_bookmarkManagaer->entryAdded(m_node);
299     m_done = false;
300 }
301 
redo()302 void RemoveBookmarksCommand::redo()
303 {
304     m_parent->remove(m_node);
305     emit m_bookmarkManagaer->entryRemoved(m_parent, m_row, m_node);
306     m_done = true;
307 }
308 
InsertBookmarksCommand(BookmarksManager * m_bookmarkManagaer,BookmarkNode * parent,BookmarkNode * node,int row)309 InsertBookmarksCommand::InsertBookmarksCommand(BookmarksManager *m_bookmarkManagaer,
310                 BookmarkNode *parent, BookmarkNode *node, int row)
311     : RemoveBookmarksCommand(m_bookmarkManagaer, parent, row)
312 {
313     setText(BookmarksManager::tr("Insert Bookmark"));
314     m_node = node;
315 }
316 
ChangeBookmarkCommand(BookmarksManager * m_bookmarkManagaer,BookmarkNode * node,const QString & newValue,bool title)317 ChangeBookmarkCommand::ChangeBookmarkCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *node,
318                         const QString &newValue, bool title)
319     : QUndoCommand()
320     , m_bookmarkManagaer(m_bookmarkManagaer)
321     , m_title(title)
322     , m_newValue(newValue)
323     , m_node(node)
324 {
325     if (m_title) {
326         m_oldValue = m_node->title;
327         setText(BookmarksManager::tr("Name Change"));
328     } else {
329         m_oldValue = m_node->url;
330         setText(BookmarksManager::tr("Address Change"));
331     }
332 }
333 
undo()334 void ChangeBookmarkCommand::undo()
335 {
336     if (m_title)
337         m_node->title = m_oldValue;
338     else
339         m_node->url = m_oldValue;
340     emit m_bookmarkManagaer->entryChanged(m_node);
341 }
342 
redo()343 void ChangeBookmarkCommand::redo()
344 {
345     if (m_title)
346         m_node->title = m_newValue;
347     else
348         m_node->url = m_newValue;
349     emit m_bookmarkManagaer->entryChanged(m_node);
350 }
351 
BookmarksModel(BookmarksManager * bookmarkManager,QObject * parent)352 BookmarksModel::BookmarksModel(BookmarksManager *bookmarkManager, QObject *parent)
353     : QAbstractItemModel(parent)
354     , m_endMacro(false)
355     , m_bookmarksManager(bookmarkManager)
356 {
357     connect(bookmarkManager, SIGNAL(entryAdded(BookmarkNode*)),
358             this, SLOT(entryAdded(BookmarkNode*)));
359     connect(bookmarkManager, SIGNAL(entryRemoved(BookmarkNode*,int,BookmarkNode*)),
360             this, SLOT(entryRemoved(BookmarkNode*,int,BookmarkNode*)));
361     connect(bookmarkManager, SIGNAL(entryChanged(BookmarkNode*)),
362             this, SLOT(entryChanged(BookmarkNode*)));
363 }
364 
index(BookmarkNode * node) const365 QModelIndex BookmarksModel::index(BookmarkNode *node) const
366 {
367     BookmarkNode *parent = node->parent();
368     if (!parent)
369         return QModelIndex();
370     return createIndex(parent->children().indexOf(node), 0, node);
371 }
372 
entryAdded(BookmarkNode * item)373 void BookmarksModel::entryAdded(BookmarkNode *item)
374 {
375     Q_ASSERT(item && item->parent());
376     int row = item->parent()->children().indexOf(item);
377     BookmarkNode *parent = item->parent();
378     // item was already added so remove beore beginInsertRows is called
379     parent->remove(item);
380     beginInsertRows(index(parent), row, row);
381     parent->add(item, row);
382     endInsertRows();
383 }
384 
entryRemoved(BookmarkNode * parent,int row,BookmarkNode * item)385 void BookmarksModel::entryRemoved(BookmarkNode *parent, int row, BookmarkNode *item)
386 {
387     // item was already removed, re-add so beginRemoveRows works
388     parent->add(item, row);
389     beginRemoveRows(index(parent), row, row);
390     parent->remove(item);
391     endRemoveRows();
392 }
393 
entryChanged(BookmarkNode * item)394 void BookmarksModel::entryChanged(BookmarkNode *item)
395 {
396     QModelIndex idx = index(item);
397     emit dataChanged(idx, idx);
398 }
399 
removeRows(int row,int count,const QModelIndex & parent)400 bool BookmarksModel::removeRows(int row, int count, const QModelIndex &parent)
401 {
402     if (row < 0 || count <= 0 || row + count > rowCount(parent))
403         return false;
404 
405     BookmarkNode *bookmarkNode = node(parent);
406     for (int i = row + count - 1; i >= row; --i) {
407         BookmarkNode *node = bookmarkNode->children().at(i);
408         if (node == m_bookmarksManager->menu()
409             || node == m_bookmarksManager->toolbar())
410             continue;
411 
412         m_bookmarksManager->removeBookmark(node);
413     }
414     if (m_endMacro) {
415         m_bookmarksManager->undoRedoStack()->endMacro();
416         m_endMacro = false;
417     }
418     return true;
419 }
420 
headerData(int section,Qt::Orientation orientation,int role) const421 QVariant BookmarksModel::headerData(int section, Qt::Orientation orientation, int role) const
422 {
423     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
424         switch (section) {
425             case 0: return tr("Title");
426             case 1: return tr("Address");
427         }
428     }
429     return QAbstractItemModel::headerData(section, orientation, role);
430 }
431 
data(const QModelIndex & index,int role) const432 QVariant BookmarksModel::data(const QModelIndex &index, int role) const
433 {
434     if (!index.isValid() || index.model() != this)
435         return QVariant();
436 
437     const BookmarkNode *bookmarkNode = node(index);
438     switch (role) {
439     case Qt::EditRole:
440     case Qt::DisplayRole:
441         if (bookmarkNode->type() == BookmarkNode::Separator) {
442             switch (index.column()) {
443             case 0: return QString(50, 0xB7);
444             case 1: return QString();
445             }
446         }
447 
448         switch (index.column()) {
449         case 0: return bookmarkNode->title;
450         case 1: return bookmarkNode->url;
451         }
452         break;
453     case BookmarksModel::UrlRole:
454         return QUrl(bookmarkNode->url);
455         break;
456     case BookmarksModel::UrlStringRole:
457         return bookmarkNode->url;
458         break;
459     case BookmarksModel::TypeRole:
460         return bookmarkNode->type();
461         break;
462     case BookmarksModel::SeparatorRole:
463         return (bookmarkNode->type() == BookmarkNode::Separator);
464         break;
465     case Qt::DecorationRole:
466         if (index.column() == 0) {
467             if (bookmarkNode->type() == BookmarkNode::Folder)
468                 return QApplication::style()->standardIcon(QStyle::SP_DirIcon);
469             return BrowserApplication::instance()->icon(bookmarkNode->url);
470         }
471     }
472 
473     return QVariant();
474 }
475 
columnCount(const QModelIndex & parent) const476 int BookmarksModel::columnCount(const QModelIndex &parent) const
477 {
478     return (parent.column() > 0) ? 0 : 2;
479 }
480 
rowCount(const QModelIndex & parent) const481 int BookmarksModel::rowCount(const QModelIndex &parent) const
482 {
483     if (parent.column() > 0)
484         return 0;
485 
486     if (!parent.isValid())
487         return m_bookmarksManager->bookmarks()->children().count();
488 
489     const BookmarkNode *item = static_cast<BookmarkNode*>(parent.internalPointer());
490     return item->children().count();
491 }
492 
index(int row,int column,const QModelIndex & parent) const493 QModelIndex BookmarksModel::index(int row, int column, const QModelIndex &parent) const
494 {
495     if (row < 0 || column < 0 || row >= rowCount(parent) || column >= columnCount(parent))
496         return QModelIndex();
497 
498     // get the parent node
499     BookmarkNode *parentNode = node(parent);
500     return createIndex(row, column, parentNode->children().at(row));
501 }
502 
parent(const QModelIndex & index) const503 QModelIndex BookmarksModel::parent(const QModelIndex &index) const
504 {
505     if (!index.isValid())
506         return QModelIndex();
507 
508     BookmarkNode *itemNode = node(index);
509     BookmarkNode *parentNode = (itemNode ? itemNode->parent() : 0);
510     if (!parentNode || parentNode == m_bookmarksManager->bookmarks())
511         return QModelIndex();
512 
513     // get the parent's row
514     BookmarkNode *grandParentNode = parentNode->parent();
515     int parentRow = grandParentNode->children().indexOf(parentNode);
516     Q_ASSERT(parentRow >= 0);
517     return createIndex(parentRow, 0, parentNode);
518 }
519 
hasChildren(const QModelIndex & parent) const520 bool BookmarksModel::hasChildren(const QModelIndex &parent) const
521 {
522     if (!parent.isValid())
523         return true;
524     const BookmarkNode *parentNode = node(parent);
525     return (parentNode->type() == BookmarkNode::Folder);
526 }
527 
flags(const QModelIndex & index) const528 Qt::ItemFlags BookmarksModel::flags(const QModelIndex &index) const
529 {
530     if (!index.isValid())
531         return Qt::NoItemFlags;
532 
533     Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
534 
535     BookmarkNode *bookmarkNode = node(index);
536 
537     if (bookmarkNode != m_bookmarksManager->menu()
538         && bookmarkNode != m_bookmarksManager->toolbar()) {
539         flags |= Qt::ItemIsDragEnabled;
540         if (bookmarkNode->type() != BookmarkNode::Separator)
541             flags |= Qt::ItemIsEditable;
542     }
543     if (hasChildren(index))
544         flags |= Qt::ItemIsDropEnabled;
545     return flags;
546 }
547 
supportedDropActions() const548 Qt::DropActions BookmarksModel::supportedDropActions () const
549 {
550     return Qt::CopyAction | Qt::MoveAction;
551 }
552 
553 #define MIMETYPE QLatin1String("application/bookmarks.xbel")
554 
mimeTypes() const555 QStringList BookmarksModel::mimeTypes() const
556 {
557     QStringList types;
558     types << MIMETYPE;
559     return types;
560 }
561 
mimeData(const QModelIndexList & indexes) const562 QMimeData *BookmarksModel::mimeData(const QModelIndexList &indexes) const
563 {
564     QMimeData *mimeData = new QMimeData();
565     QByteArray data;
566     QDataStream stream(&data, QIODevice::WriteOnly);
567     foreach (QModelIndex index, indexes) {
568         if (index.column() != 0 || !index.isValid())
569             continue;
570         QByteArray encodedData;
571         QBuffer buffer(&encodedData);
572         buffer.open(QBuffer::ReadWrite);
573         XbelWriter writer;
574         const BookmarkNode *parentNode = node(index);
575         writer.write(&buffer, parentNode);
576         stream << encodedData;
577     }
578     mimeData->setData(MIMETYPE, data);
579     return mimeData;
580 }
581 
dropMimeData(const QMimeData * data,Qt::DropAction action,int row,int column,const QModelIndex & parent)582 bool BookmarksModel::dropMimeData(const QMimeData *data,
583      Qt::DropAction action, int row, int column, const QModelIndex &parent)
584 {
585     if (action == Qt::IgnoreAction)
586         return true;
587 
588     if (!data->hasFormat(MIMETYPE)
589         || column > 0)
590         return false;
591 
592     QByteArray ba = data->data(MIMETYPE);
593     QDataStream stream(&ba, QIODevice::ReadOnly);
594     if (stream.atEnd())
595         return false;
596 
597     QUndoStack *undoStack = m_bookmarksManager->undoRedoStack();
598     undoStack->beginMacro(QLatin1String("Move Bookmarks"));
599 
600     while (!stream.atEnd()) {
601         QByteArray encodedData;
602         stream >> encodedData;
603         QBuffer buffer(&encodedData);
604         buffer.open(QBuffer::ReadOnly);
605 
606         XbelReader reader;
607         BookmarkNode *rootNode = reader.read(&buffer);
608         QList<BookmarkNode*> children = rootNode->children();
609         for (int i = 0; i < children.count(); ++i) {
610             BookmarkNode *bookmarkNode = children.at(i);
611             rootNode->remove(bookmarkNode);
612             row = qMax(0, row);
613             BookmarkNode *parentNode = node(parent);
614             m_bookmarksManager->addBookmark(parentNode, bookmarkNode, row);
615             m_endMacro = true;
616         }
617         delete rootNode;
618     }
619     return true;
620 }
621 
setData(const QModelIndex & index,const QVariant & value,int role)622 bool BookmarksModel::setData(const QModelIndex &index, const QVariant &value, int role)
623 {
624     if (!index.isValid() || (flags(index) & Qt::ItemIsEditable) == 0)
625         return false;
626 
627     BookmarkNode *item = node(index);
628 
629     switch (role) {
630     case Qt::EditRole:
631     case Qt::DisplayRole:
632         if (index.column() == 0) {
633             m_bookmarksManager->setTitle(item, value.toString());
634             break;
635         }
636         if (index.column() == 1) {
637             m_bookmarksManager->setUrl(item, value.toString());
638             break;
639         }
640         return false;
641     case BookmarksModel::UrlRole:
642         m_bookmarksManager->setUrl(item, value.toUrl().toString());
643         break;
644     case BookmarksModel::UrlStringRole:
645         m_bookmarksManager->setUrl(item, value.toString());
646         break;
647     default:
648         break;
649         return false;
650     }
651 
652     return true;
653 }
654 
node(const QModelIndex & index) const655 BookmarkNode *BookmarksModel::node(const QModelIndex &index) const
656 {
657     BookmarkNode *itemNode = static_cast<BookmarkNode*>(index.internalPointer());
658     if (!itemNode)
659         return m_bookmarksManager->bookmarks();
660     return itemNode;
661 }
662 
663 
AddBookmarkProxyModel(QObject * parent)664 AddBookmarkProxyModel::AddBookmarkProxyModel(QObject *parent)
665     : QSortFilterProxyModel(parent)
666 {
667 }
668 
columnCount(const QModelIndex & parent) const669 int AddBookmarkProxyModel::columnCount(const QModelIndex &parent) const
670 {
671     return qMin(1, QSortFilterProxyModel::columnCount(parent));
672 }
673 
filterAcceptsRow(int source_row,const QModelIndex & source_parent) const674 bool AddBookmarkProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
675 {
676     QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
677     return sourceModel()->hasChildren(idx);
678 }
679 
AddBookmarkDialog(const QString & url,const QString & title,QWidget * parent,BookmarksManager * bookmarkManager)680 AddBookmarkDialog::AddBookmarkDialog(const QString &url, const QString &title, QWidget *parent, BookmarksManager *bookmarkManager)
681     : QDialog(parent)
682     , m_url(url)
683     , m_bookmarksManager(bookmarkManager)
684 {
685     setWindowFlags(Qt::Sheet);
686     if (!m_bookmarksManager)
687         m_bookmarksManager = BrowserApplication::bookmarksManager();
688     setupUi(this);
689     QTreeView *view = new QTreeView(this);
690     m_proxyModel = new AddBookmarkProxyModel(this);
691     BookmarksModel *model = m_bookmarksManager->bookmarksModel();
692     m_proxyModel->setSourceModel(model);
693     view->setModel(m_proxyModel);
694     view->expandAll();
695     view->header()->setStretchLastSection(true);
696     view->header()->hide();
697     view->setItemsExpandable(false);
698     view->setRootIsDecorated(false);
699     view->setIndentation(10);
700     location->setModel(m_proxyModel);
701     view->show();
702     location->setView(view);
703     BookmarkNode *menu = m_bookmarksManager->menu();
704     QModelIndex idx = m_proxyModel->mapFromSource(model->index(menu));
705     view->setCurrentIndex(idx);
706     location->setCurrentIndex(idx.row());
707     name->setText(title);
708 }
709 
accept()710 void AddBookmarkDialog::accept()
711 {
712     QModelIndex index = location->view()->currentIndex();
713     index = m_proxyModel->mapToSource(index);
714     if (!index.isValid())
715         index = m_bookmarksManager->bookmarksModel()->index(0, 0);
716     BookmarkNode *parent = m_bookmarksManager->bookmarksModel()->node(index);
717     BookmarkNode *bookmark = new BookmarkNode(BookmarkNode::Bookmark);
718     bookmark->url = m_url;
719     bookmark->title = name->text();
720     m_bookmarksManager->addBookmark(parent, bookmark);
721     QDialog::accept();
722 }
723 
BookmarksMenu(QWidget * parent)724 BookmarksMenu::BookmarksMenu(QWidget *parent)
725     : ModelMenu(parent)
726     , m_bookmarksManager(0)
727 {
728     connect(this, SIGNAL(activated(QModelIndex)),
729             this, SLOT(activated(QModelIndex)));
730     setMaxRows(-1);
731     setHoverRole(BookmarksModel::UrlStringRole);
732     setSeparatorRole(BookmarksModel::SeparatorRole);
733 }
734 
activated(const QModelIndex & index)735 void BookmarksMenu::activated(const QModelIndex &index)
736 {
737     emit openUrl(index.data(BookmarksModel::UrlRole).toUrl());
738 }
739 
prePopulated()740 bool BookmarksMenu::prePopulated()
741 {
742     m_bookmarksManager = BrowserApplication::bookmarksManager();
743     setModel(m_bookmarksManager->bookmarksModel());
744     setRootIndex(m_bookmarksManager->bookmarksModel()->index(1, 0));
745     // initial actions
746     for (int i = 0; i < m_initialActions.count(); ++i)
747         addAction(m_initialActions.at(i));
748     if (!m_initialActions.isEmpty())
749         addSeparator();
750     createMenu(model()->index(0, 0), 1, this);
751     return true;
752 }
753 
setInitialActions(QList<QAction * > actions)754 void BookmarksMenu::setInitialActions(QList<QAction*> actions)
755 {
756     m_initialActions = actions;
757     for (int i = 0; i < m_initialActions.count(); ++i)
758         addAction(m_initialActions.at(i));
759 }
760 
BookmarksDialog(QWidget * parent,BookmarksManager * manager)761 BookmarksDialog::BookmarksDialog(QWidget *parent, BookmarksManager *manager)
762     : QDialog(parent)
763 {
764     m_bookmarksManager = manager;
765     if (!m_bookmarksManager)
766         m_bookmarksManager = BrowserApplication::bookmarksManager();
767     setupUi(this);
768 
769     tree->setUniformRowHeights(true);
770     tree->setSelectionBehavior(QAbstractItemView::SelectRows);
771     tree->setSelectionMode(QAbstractItemView::ContiguousSelection);
772     tree->setTextElideMode(Qt::ElideMiddle);
773     m_bookmarksModel = m_bookmarksManager->bookmarksModel();
774     m_proxyModel = new TreeProxyModel(this);
775     connect(search, SIGNAL(textChanged(QString)),
776             m_proxyModel, SLOT(setFilterFixedString(QString)));
777     connect(removeButton, SIGNAL(clicked()), tree, SLOT(removeOne()));
778     m_proxyModel->setSourceModel(m_bookmarksModel);
779     tree->setModel(m_proxyModel);
780     tree->setDragDropMode(QAbstractItemView::InternalMove);
781     tree->setExpanded(m_proxyModel->index(0, 0), true);
782     tree->setAlternatingRowColors(true);
783     QFontMetrics fm(font());
784     int header = fm.width(QLatin1Char('m')) * 40;
785     tree->header()->resizeSection(0, header);
786     tree->header()->setStretchLastSection(true);
787     connect(tree, SIGNAL(activated(QModelIndex)),
788             this, SLOT(open()));
789     tree->setContextMenuPolicy(Qt::CustomContextMenu);
790     connect(tree, SIGNAL(customContextMenuRequested(QPoint)),
791             this, SLOT(customContextMenuRequested(QPoint)));
792     connect(addFolderButton, SIGNAL(clicked()),
793             this, SLOT(newFolder()));
794     expandNodes(m_bookmarksManager->bookmarks());
795     setAttribute(Qt::WA_DeleteOnClose);
796 }
797 
~BookmarksDialog()798 BookmarksDialog::~BookmarksDialog()
799 {
800     if (saveExpandedNodes(tree->rootIndex()))
801         m_bookmarksManager->changeExpanded();
802 }
803 
saveExpandedNodes(const QModelIndex & parent)804 bool BookmarksDialog::saveExpandedNodes(const QModelIndex &parent)
805 {
806     bool changed = false;
807     for (int i = 0; i < m_proxyModel->rowCount(parent); ++i) {
808         QModelIndex child = m_proxyModel->index(i, 0, parent);
809         QModelIndex sourceIndex = m_proxyModel->mapToSource(child);
810         BookmarkNode *childNode = m_bookmarksModel->node(sourceIndex);
811         bool wasExpanded = childNode->expanded;
812         if (tree->isExpanded(child)) {
813             childNode->expanded = true;
814             changed |= saveExpandedNodes(child);
815         } else {
816             childNode->expanded = false;
817         }
818         changed |= (wasExpanded != childNode->expanded);
819     }
820     return changed;
821 }
822 
expandNodes(BookmarkNode * node)823 void BookmarksDialog::expandNodes(BookmarkNode *node)
824 {
825     for (int i = 0; i < node->children().count(); ++i) {
826         BookmarkNode *childNode = node->children()[i];
827         if (childNode->expanded) {
828             QModelIndex idx = m_bookmarksModel->index(childNode);
829             idx = m_proxyModel->mapFromSource(idx);
830             tree->setExpanded(idx, true);
831             expandNodes(childNode);
832         }
833     }
834 }
835 
customContextMenuRequested(const QPoint & pos)836 void BookmarksDialog::customContextMenuRequested(const QPoint &pos)
837 {
838     QMenu menu;
839     QModelIndex index = tree->indexAt(pos);
840     index = index.sibling(index.row(), 0);
841     if (index.isValid() && !tree->model()->hasChildren(index)) {
842         menu.addAction(tr("Open"), this, SLOT(open()));
843         menu.addSeparator();
844     }
845     menu.addAction(tr("Delete"), tree, SLOT(removeOne()));
846     menu.exec(QCursor::pos());
847 }
848 
open()849 void BookmarksDialog::open()
850 {
851     QModelIndex index = tree->currentIndex();
852     if (!index.parent().isValid())
853         return;
854     emit openUrl(index.sibling(index.row(), 1).data(BookmarksModel::UrlRole).toUrl());
855 }
856 
newFolder()857 void BookmarksDialog::newFolder()
858 {
859     QModelIndex currentIndex = tree->currentIndex();
860     QModelIndex idx = currentIndex;
861     if (idx.isValid() && !idx.model()->hasChildren(idx))
862         idx = idx.parent();
863     if (!idx.isValid())
864         idx = tree->rootIndex();
865     idx = m_proxyModel->mapToSource(idx);
866     BookmarkNode *parent = m_bookmarksManager->bookmarksModel()->node(idx);
867     BookmarkNode *node = new BookmarkNode(BookmarkNode::Folder);
868     node->title = tr("New Folder");
869     m_bookmarksManager->addBookmark(parent, node, currentIndex.row() + 1);
870 }
871 
BookmarksToolBar(BookmarksModel * model,QWidget * parent)872 BookmarksToolBar::BookmarksToolBar(BookmarksModel *model, QWidget *parent)
873     : QToolBar(tr("Bookmark"), parent)
874     , m_bookmarksModel(model)
875 {
876     connect(this, SIGNAL(actionTriggered(QAction*)), this, SLOT(triggered(QAction*)));
877     setRootIndex(model->index(0, 0));
878     connect(m_bookmarksModel, SIGNAL(modelReset()), this, SLOT(build()));
879     connect(m_bookmarksModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(build()));
880     connect(m_bookmarksModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(build()));
881     connect(m_bookmarksModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(build()));
882     setAcceptDrops(true);
883 }
884 
dragEnterEvent(QDragEnterEvent * event)885 void BookmarksToolBar::dragEnterEvent(QDragEnterEvent *event)
886 {
887     const QMimeData *mimeData = event->mimeData();
888     if (mimeData->hasUrls())
889         event->acceptProposedAction();
890     QToolBar::dragEnterEvent(event);
891 }
892 
dropEvent(QDropEvent * event)893 void BookmarksToolBar::dropEvent(QDropEvent *event)
894 {
895     const QMimeData *mimeData = event->mimeData();
896     if (mimeData->hasUrls() && mimeData->hasText()) {
897         QList<QUrl> urls = mimeData->urls();
898         QAction *action = actionAt(event->pos());
899         QString dropText;
900         if (action)
901             dropText = action->text();
902         int row = -1;
903         QModelIndex parentIndex = m_root;
904         for (int i = 0; i < m_bookmarksModel->rowCount(m_root); ++i) {
905             QModelIndex idx = m_bookmarksModel->index(i, 0, m_root);
906             QString title = idx.data().toString();
907             if (title == dropText) {
908                 row = i;
909                 if (m_bookmarksModel->hasChildren(idx)) {
910                     parentIndex = idx;
911                     row = -1;
912                 }
913                 break;
914             }
915         }
916         BookmarkNode *bookmark = new BookmarkNode(BookmarkNode::Bookmark);
917         bookmark->url = urls.at(0).toString();
918         bookmark->title = mimeData->text();
919 
920         BookmarkNode *parent = m_bookmarksModel->node(parentIndex);
921         BookmarksManager *bookmarksManager = m_bookmarksModel->bookmarksManager();
922         bookmarksManager->addBookmark(parent, bookmark, row);
923         event->acceptProposedAction();
924     }
925     QToolBar::dropEvent(event);
926 }
927 
928 
setRootIndex(const QModelIndex & index)929 void BookmarksToolBar::setRootIndex(const QModelIndex &index)
930 {
931     m_root = index;
932     build();
933 }
934 
rootIndex() const935 QModelIndex BookmarksToolBar::rootIndex() const
936 {
937     return m_root;
938 }
939 
build()940 void BookmarksToolBar::build()
941 {
942     clear();
943     for (int i = 0; i < m_bookmarksModel->rowCount(m_root); ++i) {
944         QModelIndex idx = m_bookmarksModel->index(i, 0, m_root);
945         if (m_bookmarksModel->hasChildren(idx)) {
946             QToolButton *button = new QToolButton(this);
947             button->setPopupMode(QToolButton::InstantPopup);
948             button->setArrowType(Qt::DownArrow);
949             button->setText(idx.data().toString());
950             ModelMenu *menu = new ModelMenu(this);
951             connect(menu, SIGNAL(activated(QModelIndex)),
952                     this, SLOT(activated(QModelIndex)));
953             menu->setModel(m_bookmarksModel);
954             menu->setRootIndex(idx);
955             menu->addAction(new QAction(menu));
956             button->setMenu(menu);
957             button->setToolButtonStyle(Qt::ToolButtonTextOnly);
958             QAction *a = addWidget(button);
959             a->setText(idx.data().toString());
960         } else {
961             QAction *action = addAction(idx.data().toString());
962             action->setData(idx.data(BookmarksModel::UrlRole));
963         }
964     }
965 }
966 
triggered(QAction * action)967 void BookmarksToolBar::triggered(QAction *action)
968 {
969     QVariant v = action->data();
970     if (v.canConvert<QUrl>()) {
971         emit openUrl(v.toUrl());
972     }
973 }
974 
activated(const QModelIndex & index)975 void BookmarksToolBar::activated(const QModelIndex &index)
976 {
977     emit openUrl(index.data(BookmarksModel::UrlRole).toUrl());
978 }
979 
980