bookmarks.cpp
上传用户:huahtool
上传日期:2015-12-10
资源大小:1089k
文件大小:32k
源码类别:

浏览器

开发平台:

Visual C++

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