bookmarks.cpp Example File
webenginewidgets/demobrowser/bookmarks.cpp
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "bookmarks.h"
#include "autosaver.h"
#include "browserapplication.h"
#include "history.h"
#include "xbel.h"
#include <QtCore/QBuffer>
#include <QtCore/QFile>
#include <QtCore/QMimeData>
#include <QtGui/QDesktopServices>
#include <QtGui/QDragEnterEvent>
#include <QtGui/QIcon>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QToolButton>
#include <QtCore/QDebug>
#define BOOKMARKBAR "Bookmarks Bar"
#define BOOKMARKMENU "Bookmarks Menu"
BookmarksManager:: BookmarksManager(QObject * parent)
: QObject (parent)
, m_loaded(false )
, m_saveTimer(new AutoSaver(this ))
, m_bookmarkRootNode(0 )
, m_bookmarkModel(0 )
{
connect(this , SIGNAL(entryAdded(BookmarkNode* )),
m_saveTimer, SLOT(changeOccurred()));
connect(this , SIGNAL(entryRemoved(BookmarkNode* , int , BookmarkNode* )),
m_saveTimer, SLOT(changeOccurred()));
connect(this , SIGNAL(entryChanged(BookmarkNode* )),
m_saveTimer, SLOT(changeOccurred()));
}
BookmarksManager:: ~ BookmarksManager()
{
m_saveTimer- > saveIfNeccessary();
}
void BookmarksManager:: changeExpanded()
{
m_saveTimer- > changeOccurred();
}
void BookmarksManager:: load()
{
if (m_loaded)
return ;
m_loaded = true ;
QString dir = QStandardPaths :: writableLocation(QStandardPaths :: DataLocation);
QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel" );
if (! QFile :: exists(bookmarkFile))
bookmarkFile = QLatin1String(":defaultbookmarks.xbel" );
XbelReader reader;
m_bookmarkRootNode = reader. read(bookmarkFile);
if (reader. error() ! = QXmlStreamReader :: NoError) {
QMessageBox :: warning(0 , QLatin1String("Loading Bookmark" ),
tr("Error when loading bookmarks on line %1, column %2:\n"
"%3" ). arg(reader. lineNumber()). arg(reader. columnNumber()). arg(reader. errorString()));
}
BookmarkNode * toolbar = 0 ;
BookmarkNode * menu = 0 ;
QList < BookmarkNode* > others;
for (int i = m_bookmarkRootNode- > children(). count() - 1 ; i > = 0 ; - - i) {
BookmarkNode * node = m_bookmarkRootNode- > children(). at(i);
if (node- > type() = = BookmarkNode:: Folder) {
// Automatically convert
if (node- > title = = tr("Toolbar Bookmarks" ) & & ! toolbar) {
node- > title = tr(BOOKMARKBAR);
}
if (node- > title = = tr(BOOKMARKBAR) & & ! toolbar) {
toolbar = node;
}
// Automatically convert
if (node- > title = = tr("Menu" ) & & ! menu) {
node- > title = tr(BOOKMARKMENU);
}
if (node- > title = = tr(BOOKMARKMENU) & & ! menu) {
menu = node;
}
} else {
others. append(node);
}
m_bookmarkRootNode- > remove(node);
}
Q_ASSERT(m_bookmarkRootNode- > children(). count() = = 0 );
if (! toolbar) {
toolbar = new BookmarkNode(BookmarkNode:: Folder, m_bookmarkRootNode);
toolbar- > title = tr(BOOKMARKBAR);
} else {
m_bookmarkRootNode- > add(toolbar);
}
if (! menu) {
menu = new BookmarkNode(BookmarkNode:: Folder, m_bookmarkRootNode);
menu- > title = tr(BOOKMARKMENU);
} else {
m_bookmarkRootNode- > add(menu);
}
for (int i = 0 ; i < others. count(); + + i)
menu- > add(others. at(i));
}
void BookmarksManager:: save() const
{
if (! m_loaded)
return ;
XbelWriter writer;
QString dir = QStandardPaths :: writableLocation(QStandardPaths :: DataLocation);
QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel" );
if (! writer. write(bookmarkFile, m_bookmarkRootNode))
qWarning () < < "BookmarkManager: error saving to" < < bookmarkFile;
}
void BookmarksManager:: addBookmark(BookmarkNode * parent, BookmarkNode * node, int row)
{
if (! m_loaded)
return ;
Q_ASSERT(parent);
InsertBookmarksCommand * command = new InsertBookmarksCommand(this , parent, node, row);
m_commands. push(command);
}
void BookmarksManager:: removeBookmark(BookmarkNode * node)
{
if (! m_loaded)
return ;
Q_ASSERT(node);
BookmarkNode * parent = node- > parent();
int row = parent- > children(). indexOf(node);
RemoveBookmarksCommand * command = new RemoveBookmarksCommand(this , parent, row);
m_commands. push(command);
}
void BookmarksManager:: setTitle(BookmarkNode * node, const QString & newTitle)
{
if (! m_loaded)
return ;
Q_ASSERT(node);
ChangeBookmarkCommand * command = new ChangeBookmarkCommand(this , node, newTitle, true );
m_commands. push(command);
}
void BookmarksManager:: setUrl(BookmarkNode * node, const QString & newUrl)
{
if (! m_loaded)
return ;
Q_ASSERT(node);
ChangeBookmarkCommand * command = new ChangeBookmarkCommand(this , node, newUrl, false );
m_commands. push(command);
}
BookmarkNode * BookmarksManager:: bookmarks()
{
if (! m_loaded)
load();
return m_bookmarkRootNode;
}
BookmarkNode * BookmarksManager:: menu()
{
if (! m_loaded)
load();
for (int i = m_bookmarkRootNode- > children(). count() - 1 ; i > = 0 ; - - i) {
BookmarkNode * node = m_bookmarkRootNode- > children(). at(i);
if (node- > title = = tr(BOOKMARKMENU))
return node;
}
Q_ASSERT(false );
return 0 ;
}
BookmarkNode * BookmarksManager:: toolbar()
{
if (! m_loaded)
load();
for (int i = m_bookmarkRootNode- > children(). count() - 1 ; i > = 0 ; - - i) {
BookmarkNode * node = m_bookmarkRootNode- > children(). at(i);
if (node- > title = = tr(BOOKMARKBAR))
return node;
}
Q_ASSERT(false );
return 0 ;
}
BookmarksModel * BookmarksManager:: bookmarksModel()
{
if (! m_bookmarkModel)
m_bookmarkModel = new BookmarksModel(this , this );
return m_bookmarkModel;
}
void BookmarksManager:: importBookmarks()
{
QString fileName = QFileDialog :: getOpenFileName(0 , tr("Open File" ),
QString (),
tr("XBEL (*.xbel *.xml)" ));
if (fileName. isEmpty())
return ;
XbelReader reader;
BookmarkNode * importRootNode = reader. read(fileName);
if (reader. error() ! = QXmlStreamReader :: NoError) {
QMessageBox :: warning(0 , QLatin1String("Loading Bookmark" ),
tr("Error when loading bookmarks on line %1, column %2:\n"
"%3" ). arg(reader. lineNumber()). arg(reader. columnNumber()). arg(reader. errorString()));
}
importRootNode- > setType(BookmarkNode:: Folder);
importRootNode- > title = (tr("Imported %1" ). arg(QDate :: currentDate(). toString(Qt :: SystemLocaleShortDate)));
addBookmark(menu(), importRootNode);
}
void BookmarksManager:: exportBookmarks()
{
QString fileName = QFileDialog :: getSaveFileName(0 , tr("Save File" ),
tr("%1 Bookmarks.xbel" ). arg(QCoreApplication :: applicationName()),
tr("XBEL (*.xbel *.xml)" ));
if (fileName. isEmpty())
return ;
XbelWriter writer;
if (! writer. write(fileName, m_bookmarkRootNode))
QMessageBox :: critical(0 , tr("Export error" ), tr("error saving bookmarks" ));
}
RemoveBookmarksCommand:: RemoveBookmarksCommand(BookmarksManager * m_bookmarkManagaer, BookmarkNode * parent, int row)
: QUndoCommand (BookmarksManager:: tr("Remove Bookmark" ))
, m_row(row)
, m_bookmarkManagaer(m_bookmarkManagaer)
, m_node(parent- > children(). value(row))
, m_parent(parent)
, m_done(false )
{
}
RemoveBookmarksCommand:: ~ RemoveBookmarksCommand()
{
if (m_done & & ! m_node- > parent()) {
delete m_node;
}
}
void RemoveBookmarksCommand:: undo()
{
m_parent- > add(m_node, m_row);
emit m_bookmarkManagaer- > entryAdded(m_node);
m_done = false ;
}
void RemoveBookmarksCommand:: redo()
{
m_parent- > remove(m_node);
emit m_bookmarkManagaer- > entryRemoved(m_parent, m_row, m_node);
m_done = true ;
}
InsertBookmarksCommand:: InsertBookmarksCommand(BookmarksManager * m_bookmarkManagaer,
BookmarkNode * parent, BookmarkNode * node, int row)
: RemoveBookmarksCommand(m_bookmarkManagaer, parent, row)
{
setText(BookmarksManager:: tr("Insert Bookmark" ));
m_node = node;
}
ChangeBookmarkCommand:: ChangeBookmarkCommand(BookmarksManager * m_bookmarkManagaer, BookmarkNode * node,
const QString & newValue, bool title)
: QUndoCommand ()
, m_bookmarkManagaer(m_bookmarkManagaer)
, m_title(title)
, m_newValue(newValue)
, m_node(node)
{
if (m_title) {
m_oldValue = m_node- > title;
setText(BookmarksManager:: tr("Name Change" ));
} else {
m_oldValue = m_node- > url;
setText(BookmarksManager:: tr("Address Change" ));
}
}
void ChangeBookmarkCommand:: undo()
{
if (m_title)
m_node- > title = m_oldValue;
else
m_node- > url = m_oldValue;
emit m_bookmarkManagaer- > entryChanged(m_node);
}
void ChangeBookmarkCommand:: redo()
{
if (m_title)
m_node- > title = m_newValue;
else
m_node- > url = m_newValue;
emit m_bookmarkManagaer- > entryChanged(m_node);
}
BookmarksModel:: BookmarksModel(BookmarksManager * bookmarkManager, QObject * parent)
: QAbstractItemModel (parent)
, m_endMacro(false )
, m_bookmarksManager(bookmarkManager)
{
connect(bookmarkManager, SIGNAL(entryAdded(BookmarkNode* )),
this , SLOT(entryAdded(BookmarkNode* )));
connect(bookmarkManager, SIGNAL(entryRemoved(BookmarkNode* , int , BookmarkNode* )),
this , SLOT(entryRemoved(BookmarkNode* , int , BookmarkNode* )));
connect(bookmarkManager, SIGNAL(entryChanged(BookmarkNode* )),
this , SLOT(entryChanged(BookmarkNode* )));
}
QModelIndex BookmarksModel:: index(BookmarkNode * node) const
{
BookmarkNode * parent = node- > parent();
if (! parent)
return QModelIndex ();
return createIndex(parent- > children(). indexOf(node), 0 , node);
}
void BookmarksModel:: entryAdded(BookmarkNode * item)
{
Q_ASSERT(item & & item- > parent());
int row = item- > parent()- > children(). indexOf(item);
BookmarkNode * parent = item- > parent();
// item was already added so remove beore beginInsertRows is called
parent- > remove(item);
beginInsertRows(index(parent), row, row);
parent- > add(item, row);
endInsertRows();
}
void BookmarksModel:: entryRemoved(BookmarkNode * parent, int row, BookmarkNode * item)
{
// item was already removed, re-add so beginRemoveRows works
parent- > add(item, row);
beginRemoveRows(index(parent), row, row);
parent- > remove(item);
endRemoveRows();
}
void BookmarksModel:: entryChanged(BookmarkNode * item)
{
QModelIndex idx = index(item);
emit dataChanged(idx, idx);
}
bool BookmarksModel:: removeRows(int row, int count, const QModelIndex & parent)
{
if (row < 0 | | count < = 0 | | row + count > rowCount(parent))
return false ;
BookmarkNode * bookmarkNode = node(parent);
for (int i = row + count - 1 ; i > = row; - - i) {
BookmarkNode * node = bookmarkNode- > children(). at(i);
if (node = = m_bookmarksManager- > menu()
| | node = = m_bookmarksManager- > toolbar())
continue ;
m_bookmarksManager- > removeBookmark(node);
}
if (m_endMacro) {
m_bookmarksManager- > undoRedoStack()- > endMacro();
m_endMacro = false ;
}
return true ;
}
QVariant BookmarksModel:: headerData(int section, Qt :: Orientation orientation, int role) const
{
if (orientation = = Qt :: Horizontal & & role = = Qt :: DisplayRole) {
switch (section) {
case 0 : return tr("Title" );
case 1 : return tr("Address" );
}
}
return QAbstractItemModel :: headerData(section, orientation, role);
}
QVariant BookmarksModel:: data(const QModelIndex & index, int role) const
{
if (! index. isValid() | | index. model() ! = this )
return QVariant ();
const BookmarkNode * bookmarkNode = node(index);
switch (role) {
case Qt :: EditRole:
case Qt :: DisplayRole:
if (bookmarkNode- > type() = = BookmarkNode:: Separator) {
switch (index. column()) {
case 0 : return QString (50 , 0xB7 );
case 1 : return QString ();
}
}
switch (index. column()) {
case 0 : return bookmarkNode- > title;
case 1 : return bookmarkNode- > url;
}
break ;
case BookmarksModel:: UrlRole:
return QUrl (bookmarkNode- > url);
break ;
case BookmarksModel:: UrlStringRole:
return bookmarkNode- > url;
break ;
case BookmarksModel:: TypeRole:
return bookmarkNode- > type();
break ;
case BookmarksModel:: SeparatorRole:
return (bookmarkNode- > type() = = BookmarkNode:: Separator);
break ;
case Qt :: DecorationRole:
if (index. column() = = 0 ) {
if (bookmarkNode- > type() = = BookmarkNode:: Folder)
return QApplication :: style()- > standardIcon(QStyle :: SP_DirIcon);
return BrowserApplication:: instance()- > icon(bookmarkNode- > url);
}
}
return QVariant ();
}
int BookmarksModel:: columnCount(const QModelIndex & parent) const
{
return (parent. column() > 0 ) ? 0 : 2 ;
}
int BookmarksModel:: rowCount(const QModelIndex & parent) const
{
if (parent. column() > 0 )
return 0 ;
if (! parent. isValid())
return m_bookmarksManager- > bookmarks()- > children(). count();
const BookmarkNode * item = static_cast < BookmarkNode* > (parent. internalPointer());
return item- > children(). count();
}
QModelIndex BookmarksModel:: index(int row, int column, const QModelIndex & parent) const
{
if (row < 0 | | column < 0 | | row > = rowCount(parent) | | column > = columnCount(parent))
return QModelIndex ();
// get the parent node
BookmarkNode * parentNode = node(parent);
return createIndex(row, column, parentNode- > children(). at(row));
}
QModelIndex BookmarksModel:: parent(const QModelIndex & index) const
{
if (! index. isValid())
return QModelIndex ();
BookmarkNode * itemNode = node(index);
BookmarkNode * parentNode = (itemNode ? itemNode- > parent() : 0 );
if (! parentNode | | parentNode = = m_bookmarksManager- > bookmarks())
return QModelIndex ();
// get the parent's row
BookmarkNode * grandParentNode = parentNode- > parent();
int parentRow = grandParentNode- > children(). indexOf(parentNode);
Q_ASSERT(parentRow > = 0 );
return createIndex(parentRow, 0 , parentNode);
}
bool BookmarksModel:: hasChildren(const QModelIndex & parent) const
{
if (! parent. isValid())
return true ;
const BookmarkNode * parentNode = node(parent);
return (parentNode- > type() = = BookmarkNode:: Folder);
}
Qt :: ItemFlags BookmarksModel:: flags(const QModelIndex & index) const
{
if (! index. isValid())
return Qt :: NoItemFlags;
Qt :: ItemFlags flags = Qt :: ItemIsSelectable | Qt :: ItemIsEnabled;
BookmarkNode * bookmarkNode = node(index);
if (bookmarkNode ! = m_bookmarksManager- > menu()
& & bookmarkNode ! = m_bookmarksManager- > toolbar()) {
flags | = Qt :: ItemIsDragEnabled;
if (bookmarkNode- > type() ! = BookmarkNode:: Separator)
flags | = Qt :: ItemIsEditable;
}
if (hasChildren(index))
flags | = Qt :: ItemIsDropEnabled;
return flags;
}
Qt :: DropActions BookmarksModel:: supportedDropActions () const
{
return Qt :: CopyAction | Qt :: MoveAction;
}
#define MIMETYPE QLatin1String("application/bookmarks.xbel")
QStringList BookmarksModel:: mimeTypes() const
{
QStringList types;
types < < MIMETYPE;
return types;
}
QMimeData * BookmarksModel:: mimeData(const QModelIndexList & indexes) const
{
QMimeData * mimeData = new QMimeData ();
QByteArray data;
QDataStream stream(& data, QIODevice :: WriteOnly);
foreach (QModelIndex index, indexes) {
if (index. column() ! = 0 | | ! index. isValid())
continue ;
QByteArray encodedData;
QBuffer buffer(& encodedData);
buffer. open(QBuffer :: ReadWrite);
XbelWriter writer;
const BookmarkNode * parentNode = node(index);
writer. write(& buffer, parentNode);
stream < < encodedData;
}
mimeData- > setData(MIMETYPE, data);
return mimeData;
}
bool BookmarksModel:: dropMimeData(const QMimeData * data,
Qt :: DropAction action, int row, int column, const QModelIndex & parent)
{
if (action = = Qt :: IgnoreAction)
return true ;
if (! data- > hasFormat(MIMETYPE)
| | column > 0 )
return false ;
QByteArray ba = data- > data(MIMETYPE);
QDataStream stream(& ba, QIODevice :: ReadOnly);
if (stream. atEnd())
return false ;
QUndoStack * undoStack = m_bookmarksManager- > undoRedoStack();
undoStack- > beginMacro(QLatin1String("Move Bookmarks" ));
while (! stream. atEnd()) {
QByteArray encodedData;
stream > > encodedData;
QBuffer buffer(& encodedData);
buffer. open(QBuffer :: ReadOnly);
XbelReader reader;
BookmarkNode * rootNode = reader. read(& buffer);
QList < BookmarkNode* > children = rootNode- > children();
for (int i = 0 ; i < children. count(); + + i) {
BookmarkNode * bookmarkNode = children. at(i);
rootNode- > remove(bookmarkNode);
row = qMax (0 , row);
BookmarkNode * parentNode = node(parent);
m_bookmarksManager- > addBookmark(parentNode, bookmarkNode, row);
m_endMacro = true ;
}
delete rootNode;
}
return true ;
}
bool BookmarksModel:: setData(const QModelIndex & index, const QVariant & value, int role)
{
if (! index. isValid() | | (flags(index) & Qt :: ItemIsEditable) = = 0 )
return false ;
BookmarkNode * item = node(index);
switch (role) {
case Qt :: EditRole:
case Qt :: DisplayRole:
if (index. column() = = 0 ) {
m_bookmarksManager- > setTitle(item, value. toString());
break ;
}
if (index. column() = = 1 ) {
m_bookmarksManager- > setUrl(item, value. toString());
break ;
}
return false ;
case BookmarksModel:: UrlRole:
m_bookmarksManager- > setUrl(item, value. toUrl(). toString());
break ;
case BookmarksModel:: UrlStringRole:
m_bookmarksManager- > setUrl(item, value. toString());
break ;
default :
break ;
return false ;
}
return true ;
}
BookmarkNode * BookmarksModel:: node(const QModelIndex & index) const
{
BookmarkNode * itemNode = static_cast < BookmarkNode* > (index. internalPointer());
if (! itemNode)
return m_bookmarksManager- > bookmarks();
return itemNode;
}
AddBookmarkProxyModel:: AddBookmarkProxyModel(QObject * parent)
: QSortFilterProxyModel (parent)
{
}
int AddBookmarkProxyModel:: columnCount(const QModelIndex & parent) const
{
return qMin (1 , QSortFilterProxyModel :: columnCount(parent));
}
bool AddBookmarkProxyModel:: filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
{
QModelIndex idx = sourceModel()- > index(source_row, 0 , source_parent);
return sourceModel()- > hasChildren(idx);
}
AddBookmarkDialog:: AddBookmarkDialog(const QString & url, const QString & title, QWidget * parent, BookmarksManager * bookmarkManager)
: QDialog (parent)
, m_url(url)
, m_bookmarksManager(bookmarkManager)
{
setWindowFlags(Qt :: Sheet);
if (! m_bookmarksManager)
m_bookmarksManager = BrowserApplication:: bookmarksManager();
setupUi(this );
QTreeView * view = new QTreeView (this );
m_proxyModel = new AddBookmarkProxyModel(this );
BookmarksModel * model = m_bookmarksManager- > bookmarksModel();
m_proxyModel- > setSourceModel(model);
view- > setModel(m_proxyModel);
view- > expandAll();
view- > header()- > setStretchLastSection(true );
view- > header()- > hide();
view- > setItemsExpandable(false );
view- > setRootIsDecorated(false );
view- > setIndentation(10 );
location- > setModel(m_proxyModel);
view- > show();
location- > setView(view);
BookmarkNode * menu = m_bookmarksManager- > menu();
QModelIndex idx = m_proxyModel- > mapFromSource(model- > index(menu));
view- > setCurrentIndex(idx);
location- > setCurrentIndex(idx. row());
name- > setText(title);
}
void AddBookmarkDialog:: accept()
{
QModelIndex index = location- > view()- > currentIndex();
index = m_proxyModel- > mapToSource(index);
if (! index. isValid())
index = m_bookmarksManager- > bookmarksModel()- > index(0 , 0 );
BookmarkNode * parent = m_bookmarksManager- > bookmarksModel()- > node(index);
BookmarkNode * bookmark = new BookmarkNode(BookmarkNode:: Bookmark);
bookmark- > url = m_url;
bookmark- > title = name- > text();
m_bookmarksManager- > addBookmark(parent, bookmark);
QDialog :: accept();
}
BookmarksMenu:: BookmarksMenu(QWidget * parent)
: ModelMenu(parent)
, m_bookmarksManager(0 )
{
connect(this , SIGNAL(activated(QModelIndex )),
this , SLOT(activated(QModelIndex )));
setMaxRows(- 1 );
setHoverRole(BookmarksModel:: UrlStringRole);
setSeparatorRole(BookmarksModel:: SeparatorRole);
}
void BookmarksMenu:: activated(const QModelIndex & index)
{
emit openUrl(index. data(BookmarksModel:: UrlRole). toUrl());
}
bool BookmarksMenu:: prePopulated()
{
m_bookmarksManager = BrowserApplication:: bookmarksManager();
setModel(m_bookmarksManager- > bookmarksModel());
setRootIndex(m_bookmarksManager- > bookmarksModel()- > index(1 , 0 ));
// initial actions
for (int i = 0 ; i < m_initialActions. count(); + + i)
addAction(m_initialActions. at(i));
if (! m_initialActions. isEmpty())
addSeparator();
createMenu(model()- > index(0 , 0 ), 1 , this );
return true ;
}
void BookmarksMenu:: setInitialActions(QList < QAction * > actions)
{
m_initialActions = actions;
for (int i = 0 ; i < m_initialActions. count(); + + i)
addAction(m_initialActions. at(i));
}
BookmarksDialog:: BookmarksDialog(QWidget * parent, BookmarksManager * manager)
: QDialog (parent)
{
m_bookmarksManager = manager;
if (! m_bookmarksManager)
m_bookmarksManager = BrowserApplication:: bookmarksManager();
setupUi(this );
tree- > setUniformRowHeights(true );
tree- > setSelectionBehavior(QAbstractItemView :: SelectRows);
tree- > setSelectionMode(QAbstractItemView :: ContiguousSelection);
tree- > setTextElideMode(Qt :: ElideMiddle);
m_bookmarksModel = m_bookmarksManager- > bookmarksModel();
m_proxyModel = new TreeProxyModel(this );
connect(search, SIGNAL(textChanged(QString )),
m_proxyModel, SLOT(setFilterFixedString(QString )));
connect(removeButton, SIGNAL(clicked()), tree, SLOT(removeOne()));
m_proxyModel- > setSourceModel(m_bookmarksModel);
tree- > setModel(m_proxyModel);
tree- > setDragDropMode(QAbstractItemView :: InternalMove);
tree- > setExpanded(m_proxyModel- > index(0 , 0 ), true );
tree- > setAlternatingRowColors(true );
QFontMetrics fm(font());
int header = fm. width(QLatin1Char('m' )) * 40 ;
tree- > header()- > resizeSection(0 , header);
tree- > header()- > setStretchLastSection(true );
connect(tree, SIGNAL(activated(QModelIndex )),
this , SLOT(open()));
tree- > setContextMenuPolicy(Qt :: CustomContextMenu);
connect(tree, SIGNAL(customContextMenuRequested(QPoint )),
this , SLOT(customContextMenuRequested(QPoint )));
connect(addFolderButton, SIGNAL(clicked()),
this , SLOT(newFolder()));
expandNodes(m_bookmarksManager- > bookmarks());
setAttribute(Qt :: WA_DeleteOnClose);
}
BookmarksDialog:: ~ BookmarksDialog()
{
if (saveExpandedNodes(tree- > rootIndex()))
m_bookmarksManager- > changeExpanded();
}
bool BookmarksDialog:: saveExpandedNodes(const QModelIndex & parent)
{
bool changed = false ;
for (int i = 0 ; i < m_proxyModel- > rowCount(parent); + + i) {
QModelIndex child = m_proxyModel- > index(i, 0 , parent);
QModelIndex sourceIndex = m_proxyModel- > mapToSource(child);
BookmarkNode * childNode = m_bookmarksModel- > node(sourceIndex);
bool wasExpanded = childNode- > expanded;
if (tree- > isExpanded(child)) {
childNode- > expanded = true ;
changed | = saveExpandedNodes(child);
} else {
childNode- > expanded = false ;
}
changed | = (wasExpanded ! = childNode- > expanded);
}
return changed;
}
void BookmarksDialog:: expandNodes(BookmarkNode * node)
{
for (int i = 0 ; i < node- > children(). count(); + + i) {
BookmarkNode * childNode = node- > children()[ i] ;
if (childNode- > expanded) {
QModelIndex idx = m_bookmarksModel- > index(childNode);
idx = m_proxyModel- > mapFromSource(idx);
tree- > setExpanded(idx, true );
expandNodes(childNode);
}
}
}
void BookmarksDialog:: customContextMenuRequested(const QPoint & pos)
{
QMenu menu;
QModelIndex index = tree- > indexAt(pos);
index = index. sibling(index. row(), 0 );
if (index. isValid() & & ! tree- > model()- > hasChildren(index)) {
menu. addAction(tr("Open" ), this , SLOT(open()));
menu. addSeparator();
}
menu. addAction(tr("Delete" ), tree, SLOT(removeOne()));
menu. exec(QCursor :: pos());
}
void BookmarksDialog:: open()
{
QModelIndex index = tree- > currentIndex();
if (! index. parent(). isValid())
return ;
emit openUrl(index. sibling(index. row(), 1 ). data(BookmarksModel:: UrlRole). toUrl());
}
void BookmarksDialog:: newFolder()
{
QModelIndex currentIndex = tree- > currentIndex();
QModelIndex idx = currentIndex;
if (idx. isValid() & & ! idx. model()- > hasChildren(idx))
idx = idx. parent();
if (! idx. isValid())
idx = tree- > rootIndex();
idx = m_proxyModel- > mapToSource(idx);
BookmarkNode * parent = m_bookmarksManager- > bookmarksModel()- > node(idx);
BookmarkNode * node = new BookmarkNode(BookmarkNode:: Folder);
node- > title = tr("New Folder" );
m_bookmarksManager- > addBookmark(parent, node, currentIndex. row() + 1 );
}
BookmarksToolBar:: BookmarksToolBar(BookmarksModel * model, QWidget * parent)
: QToolBar (tr("Bookmark" ), parent)
, m_bookmarksModel(model)
{
connect(this , SIGNAL(actionTriggered(QAction * )), this , SLOT(triggered(QAction * )));
setRootIndex(model- > index(0 , 0 ));
connect(m_bookmarksModel, SIGNAL(modelReset()), this , SLOT(build()));
connect(m_bookmarksModel, SIGNAL(rowsInserted(QModelIndex , int , int )), this , SLOT(build()));
connect(m_bookmarksModel, SIGNAL(rowsRemoved(QModelIndex , int , int )), this , SLOT(build()));
connect(m_bookmarksModel, SIGNAL(dataChanged(QModelIndex , QModelIndex )), this , SLOT(build()));
setAcceptDrops(true );
}
void BookmarksToolBar:: dragEnterEvent(QDragEnterEvent * event)
{
const QMimeData * mimeData = event- > mimeData();
if (mimeData- > hasUrls())
event- > acceptProposedAction();
QToolBar :: dragEnterEvent(event);
}
void BookmarksToolBar:: dropEvent(QDropEvent * event)
{
const QMimeData * mimeData = event- > mimeData();
if (mimeData- > hasUrls() & & mimeData- > hasText()) {
QList < QUrl > urls = mimeData- > urls();
QAction * action = actionAt(event- > pos());
QString dropText;
if (action)
dropText = action- > text();
int row = - 1 ;
QModelIndex parentIndex = m_root;
for (int i = 0 ; i < m_bookmarksModel- > rowCount(m_root); + + i) {
QModelIndex idx = m_bookmarksModel- > index(i, 0 , m_root);
QString title = idx. data(). toString();
if (title = = dropText) {
row = i;
if (m_bookmarksModel- > hasChildren(idx)) {
parentIndex = idx;
row = - 1 ;
}
break ;
}
}
BookmarkNode * bookmark = new BookmarkNode(BookmarkNode:: Bookmark);
bookmark- > url = urls. at(0 ). toString();
bookmark- > title = mimeData- > text();
BookmarkNode * parent = m_bookmarksModel- > node(parentIndex);
BookmarksManager * bookmarksManager = m_bookmarksModel- > bookmarksManager();
bookmarksManager- > addBookmark(parent, bookmark, row);
event- > acceptProposedAction();
}
QToolBar :: dropEvent(event);
}
void BookmarksToolBar:: setRootIndex(const QModelIndex & index)
{
m_root = index;
build();
}
QModelIndex BookmarksToolBar:: rootIndex() const
{
return m_root;
}
void BookmarksToolBar:: build()
{
clear();
for (int i = 0 ; i < m_bookmarksModel- > rowCount(m_root); + + i) {
QModelIndex idx = m_bookmarksModel- > index(i, 0 , m_root);
if (m_bookmarksModel- > hasChildren(idx)) {
QToolButton * button = new QToolButton (this );
button- > setPopupMode(QToolButton :: InstantPopup);
button- > setArrowType(Qt :: DownArrow);
button- > setText(idx. data(). toString());
ModelMenu * menu = new ModelMenu(this );
connect(menu, SIGNAL(activated(QModelIndex )),
this , SLOT(activated(QModelIndex )));
menu- > setModel(m_bookmarksModel);
menu- > setRootIndex(idx);
menu- > addAction(new QAction (menu));
button- > setMenu(menu);
button- > setToolButtonStyle(Qt :: ToolButtonTextOnly);
QAction * a = addWidget(button);
a- > setText(idx. data(). toString());
} else {
QAction * action = addAction(idx. data(). toString());
action- > setData(idx. data(BookmarksModel:: UrlRole));
}
}
}
void BookmarksToolBar:: triggered(QAction * action)
{
QVariant v = action- > data();
if (v. canConvert< QUrl > ()) {
emit openUrl(v. toUrl());
}
}
void BookmarksToolBar:: activated(const QModelIndex & index)
{
emit openUrl(index. data(BookmarksModel:: UrlRole). toUrl());
}