1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Qt Software Information (qt-info@nokia.com)
6 ** This file is part of the demonstration applications of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at qt-sales@nokia.com.
40 ****************************************************************************/
42 #include "bookmarks.h"
44 #include "autosaver.h"
45 #include "browserapplication.h"
49 #include <QtCore/QBuffer>
50 #include <QtCore/QFile>
51 #include <QtCore/QMimeData>
53 #include <QtGui/QDesktopServices>
54 #include <QtGui/QDragEnterEvent>
55 #include <QtGui/QFileDialog>
56 #include <QtGui/QHeaderView>
57 #include <QtGui/QIcon>
58 #include <QtGui/QMessageBox>
59 #include <QtGui/QToolButton>
61 #include <QtWebKit/QWebSettings>
63 #include <QtCore/QDebug>
65 #define BOOKMARKBAR "Bookmarks Bar"
66 #define BOOKMARKMENU "Bookmarks Menu"
68 BookmarksManager::BookmarksManager(QObject
*parent
)
71 , m_saveTimer(new AutoSaver(this))
72 , m_bookmarkRootNode(0)
75 connect(this, SIGNAL(entryAdded(BookmarkNode
*)),
76 m_saveTimer
, SLOT(changeOccurred()));
77 connect(this, SIGNAL(entryRemoved(BookmarkNode
*, int, BookmarkNode
*)),
78 m_saveTimer
, SLOT(changeOccurred()));
79 connect(this, SIGNAL(entryChanged(BookmarkNode
*)),
80 m_saveTimer
, SLOT(changeOccurred()));
83 BookmarksManager::~BookmarksManager()
85 m_saveTimer
->saveIfNeccessary();
88 void BookmarksManager::changeExpanded()
90 m_saveTimer
->changeOccurred();
93 void BookmarksManager::load()
99 QString dir
= QDesktopServices::storageLocation(QDesktopServices::DataLocation
);
100 QString bookmarkFile
= dir
+ QLatin1String("/bookmarks.xbel");
101 if (!QFile::exists(bookmarkFile
))
102 bookmarkFile
= QLatin1String(":defaultbookmarks.xbel");
105 m_bookmarkRootNode
= reader
.read(bookmarkFile
);
106 if (reader
.error() != QXmlStreamReader::NoError
) {
107 QMessageBox::warning(0, QLatin1String("Loading Bookmark"),
108 tr("Error when loading bookmarks on line %1, column %2:\n"
109 "%3").arg(reader
.lineNumber()).arg(reader
.columnNumber()).arg(reader
.errorString()));
112 BookmarkNode
*toolbar
= 0;
113 BookmarkNode
*menu
= 0;
114 QList
<BookmarkNode
*> others
;
115 for (int i
= m_bookmarkRootNode
->children().count() - 1; i
>= 0; --i
) {
116 BookmarkNode
*node
= m_bookmarkRootNode
->children().at(i
);
117 if (node
->type() == BookmarkNode::Folder
) {
118 // Automatically convert
119 if (node
->title
== tr("Toolbar Bookmarks") && !toolbar
) {
120 node
->title
= tr(BOOKMARKBAR
);
122 if (node
->title
== tr(BOOKMARKBAR
) && !toolbar
) {
126 // Automatically convert
127 if (node
->title
== tr("Menu") && !menu
) {
128 node
->title
= tr(BOOKMARKMENU
);
130 if (node
->title
== tr(BOOKMARKMENU
) && !menu
) {
136 m_bookmarkRootNode
->remove(node
);
138 Q_ASSERT(m_bookmarkRootNode
->children().count() == 0);
140 toolbar
= new BookmarkNode(BookmarkNode::Folder
, m_bookmarkRootNode
);
141 toolbar
->title
= tr(BOOKMARKBAR
);
143 m_bookmarkRootNode
->add(toolbar
);
147 menu
= new BookmarkNode(BookmarkNode::Folder
, m_bookmarkRootNode
);
148 menu
->title
= tr(BOOKMARKMENU
);
150 m_bookmarkRootNode
->add(menu
);
153 for (int i
= 0; i
< others
.count(); ++i
)
154 menu
->add(others
.at(i
));
157 void BookmarksManager::save() const
163 QString dir
= QDesktopServices::storageLocation(QDesktopServices::DataLocation
);
164 QString bookmarkFile
= dir
+ QLatin1String("/bookmarks.xbel");
165 if (!writer
.write(bookmarkFile
, m_bookmarkRootNode
))
166 qWarning() << "BookmarkManager: error saving to" << bookmarkFile
;
169 void BookmarksManager::addBookmark(BookmarkNode
*parent
, BookmarkNode
*node
, int row
)
174 InsertBookmarksCommand
*command
= new InsertBookmarksCommand(this, parent
, node
, row
);
175 m_commands
.push(command
);
178 void BookmarksManager::removeBookmark(BookmarkNode
*node
)
184 BookmarkNode
*parent
= node
->parent();
185 int row
= parent
->children().indexOf(node
);
186 RemoveBookmarksCommand
*command
= new RemoveBookmarksCommand(this, parent
, row
);
187 m_commands
.push(command
);
190 void BookmarksManager::setTitle(BookmarkNode
*node
, const QString
&newTitle
)
196 ChangeBookmarkCommand
*command
= new ChangeBookmarkCommand(this, node
, newTitle
, true);
197 m_commands
.push(command
);
200 void BookmarksManager::setUrl(BookmarkNode
*node
, const QString
&newUrl
)
206 ChangeBookmarkCommand
*command
= new ChangeBookmarkCommand(this, node
, newUrl
, false);
207 m_commands
.push(command
);
210 BookmarkNode
*BookmarksManager::bookmarks()
214 return m_bookmarkRootNode
;
217 BookmarkNode
*BookmarksManager::menu()
222 for (int i
= m_bookmarkRootNode
->children().count() - 1; i
>= 0; --i
) {
223 BookmarkNode
*node
= m_bookmarkRootNode
->children().at(i
);
224 if (node
->title
== tr(BOOKMARKMENU
))
231 BookmarkNode
*BookmarksManager::toolbar()
236 for (int i
= m_bookmarkRootNode
->children().count() - 1; i
>= 0; --i
) {
237 BookmarkNode
*node
= m_bookmarkRootNode
->children().at(i
);
238 if (node
->title
== tr(BOOKMARKBAR
))
245 BookmarksModel
*BookmarksManager::bookmarksModel()
247 if (!m_bookmarkModel
)
248 m_bookmarkModel
= new BookmarksModel(this, this);
249 return m_bookmarkModel
;
252 void BookmarksManager::importBookmarks()
254 QString fileName
= QFileDialog::getOpenFileName(0, tr("Open File"),
256 tr("XBEL (*.xbel *.xml)"));
257 if (fileName
.isEmpty())
261 BookmarkNode
*importRootNode
= reader
.read(fileName
);
262 if (reader
.error() != QXmlStreamReader::NoError
) {
263 QMessageBox::warning(0, QLatin1String("Loading Bookmark"),
264 tr("Error when loading bookmarks on line %1, column %2:\n"
265 "%3").arg(reader
.lineNumber()).arg(reader
.columnNumber()).arg(reader
.errorString()));
268 importRootNode
->setType(BookmarkNode::Folder
);
269 importRootNode
->title
= (tr("Imported %1").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate
)));
270 addBookmark(menu(), importRootNode
);
273 void BookmarksManager::exportBookmarks()
275 QString fileName
= QFileDialog::getSaveFileName(0, tr("Save File"),
276 tr("%1 Bookmarks.xbel").arg(QCoreApplication::applicationName()),
277 tr("XBEL (*.xbel *.xml)"));
278 if (fileName
.isEmpty())
282 if (!writer
.write(fileName
, m_bookmarkRootNode
))
283 QMessageBox::critical(0, tr("Export error"), tr("error saving bookmarks"));
286 RemoveBookmarksCommand::RemoveBookmarksCommand(BookmarksManager
*m_bookmarkManagaer
, BookmarkNode
*parent
, int row
)
287 : QUndoCommand(BookmarksManager::tr("Remove Bookmark"))
289 , m_bookmarkManagaer(m_bookmarkManagaer
)
290 , m_node(parent
->children().value(row
))
296 RemoveBookmarksCommand::~RemoveBookmarksCommand()
298 if (m_done
&& !m_node
->parent()) {
303 void RemoveBookmarksCommand::undo()
305 m_parent
->add(m_node
, m_row
);
306 emit m_bookmarkManagaer
->entryAdded(m_node
);
310 void RemoveBookmarksCommand::redo()
312 m_parent
->remove(m_node
);
313 emit m_bookmarkManagaer
->entryRemoved(m_parent
, m_row
, m_node
);
317 InsertBookmarksCommand::InsertBookmarksCommand(BookmarksManager
*m_bookmarkManagaer
,
318 BookmarkNode
*parent
, BookmarkNode
*node
, int row
)
319 : RemoveBookmarksCommand(m_bookmarkManagaer
, parent
, row
)
321 setText(BookmarksManager::tr("Insert Bookmark"));
325 ChangeBookmarkCommand::ChangeBookmarkCommand(BookmarksManager
*m_bookmarkManagaer
, BookmarkNode
*node
,
326 const QString
&newValue
, bool title
)
328 , m_bookmarkManagaer(m_bookmarkManagaer
)
330 , m_newValue(newValue
)
334 m_oldValue
= m_node
->title
;
335 setText(BookmarksManager::tr("Name Change"));
337 m_oldValue
= m_node
->url
;
338 setText(BookmarksManager::tr("Address Change"));
342 void ChangeBookmarkCommand::undo()
345 m_node
->title
= m_oldValue
;
347 m_node
->url
= m_oldValue
;
348 emit m_bookmarkManagaer
->entryChanged(m_node
);
351 void ChangeBookmarkCommand::redo()
354 m_node
->title
= m_newValue
;
356 m_node
->url
= m_newValue
;
357 emit m_bookmarkManagaer
->entryChanged(m_node
);
360 BookmarksModel::BookmarksModel(BookmarksManager
*bookmarkManager
, QObject
*parent
)
361 : QAbstractItemModel(parent
)
363 , m_bookmarksManager(bookmarkManager
)
365 connect(bookmarkManager
, SIGNAL(entryAdded(BookmarkNode
*)),
366 this, SLOT(entryAdded(BookmarkNode
*)));
367 connect(bookmarkManager
, SIGNAL(entryRemoved(BookmarkNode
*, int, BookmarkNode
*)),
368 this, SLOT(entryRemoved(BookmarkNode
*, int, BookmarkNode
*)));
369 connect(bookmarkManager
, SIGNAL(entryChanged(BookmarkNode
*)),
370 this, SLOT(entryChanged(BookmarkNode
*)));
373 QModelIndex
BookmarksModel::index(BookmarkNode
*node
) const
375 BookmarkNode
*parent
= node
->parent();
377 return QModelIndex();
378 return createIndex(parent
->children().indexOf(node
), 0, node
);
381 void BookmarksModel::entryAdded(BookmarkNode
*item
)
383 Q_ASSERT(item
&& item
->parent());
384 int row
= item
->parent()->children().indexOf(item
);
385 BookmarkNode
*parent
= item
->parent();
386 // item was already added so remove beore beginInsertRows is called
387 parent
->remove(item
);
388 beginInsertRows(index(parent
), row
, row
);
389 parent
->add(item
, row
);
393 void BookmarksModel::entryRemoved(BookmarkNode
*parent
, int row
, BookmarkNode
*item
)
395 // item was already removed, re-add so beginRemoveRows works
396 parent
->add(item
, row
);
397 beginRemoveRows(index(parent
), row
, row
);
398 parent
->remove(item
);
402 void BookmarksModel::entryChanged(BookmarkNode
*item
)
404 QModelIndex idx
= index(item
);
405 emit
dataChanged(idx
, idx
);
408 bool BookmarksModel::removeRows(int row
, int count
, const QModelIndex
&parent
)
410 if (row
< 0 || count
<= 0 || row
+ count
> rowCount(parent
))
413 BookmarkNode
*bookmarkNode
= node(parent
);
414 for (int i
= row
+ count
- 1; i
>= row
; --i
) {
415 BookmarkNode
*node
= bookmarkNode
->children().at(i
);
416 if (node
== m_bookmarksManager
->menu()
417 || node
== m_bookmarksManager
->toolbar())
420 m_bookmarksManager
->removeBookmark(node
);
423 m_bookmarksManager
->undoRedoStack()->endMacro();
429 QVariant
BookmarksModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
431 if (orientation
== Qt::Horizontal
&& role
== Qt::DisplayRole
) {
433 case 0: return tr("Title");
434 case 1: return tr("Address");
437 return QAbstractItemModel::headerData(section
, orientation
, role
);
440 QVariant
BookmarksModel::data(const QModelIndex
&index
, int role
) const
442 if (!index
.isValid() || index
.model() != this)
445 const BookmarkNode
*bookmarkNode
= node(index
);
448 case Qt::DisplayRole
:
449 if (bookmarkNode
->type() == BookmarkNode::Separator
) {
450 switch (index
.column()) {
451 case 0: return QString(50, 0xB7);
452 case 1: return QString();
456 switch (index
.column()) {
457 case 0: return bookmarkNode
->title
;
458 case 1: return bookmarkNode
->url
;
461 case BookmarksModel::UrlRole
:
462 return QUrl(bookmarkNode
->url
);
464 case BookmarksModel::UrlStringRole
:
465 return bookmarkNode
->url
;
467 case BookmarksModel::TypeRole
:
468 return bookmarkNode
->type();
470 case BookmarksModel::SeparatorRole
:
471 return (bookmarkNode
->type() == BookmarkNode::Separator
);
473 case Qt::DecorationRole
:
474 if (index
.column() == 0) {
475 if (bookmarkNode
->type() == BookmarkNode::Folder
)
476 return QApplication::style()->standardIcon(QStyle::SP_DirIcon
);
477 return BrowserApplication::instance()->icon(bookmarkNode
->url
);
484 int BookmarksModel::columnCount(const QModelIndex
&parent
) const
486 return (parent
.column() > 0) ? 0 : 2;
489 int BookmarksModel::rowCount(const QModelIndex
&parent
) const
491 if (parent
.column() > 0)
494 if (!parent
.isValid())
495 return m_bookmarksManager
->bookmarks()->children().count();
497 const BookmarkNode
*item
= static_cast<BookmarkNode
*>(parent
.internalPointer());
498 return item
->children().count();
501 QModelIndex
BookmarksModel::index(int row
, int column
, const QModelIndex
&parent
) const
503 if (row
< 0 || column
< 0 || row
>= rowCount(parent
) || column
>= columnCount(parent
))
504 return QModelIndex();
506 // get the parent node
507 BookmarkNode
*parentNode
= node(parent
);
508 return createIndex(row
, column
, parentNode
->children().at(row
));
511 QModelIndex
BookmarksModel::parent(const QModelIndex
&index
) const
513 if (!index
.isValid())
514 return QModelIndex();
516 BookmarkNode
*itemNode
= node(index
);
517 BookmarkNode
*parentNode
= (itemNode
? itemNode
->parent() : 0);
518 if (!parentNode
|| parentNode
== m_bookmarksManager
->bookmarks())
519 return QModelIndex();
521 // get the parent's row
522 BookmarkNode
*grandParentNode
= parentNode
->parent();
523 int parentRow
= grandParentNode
->children().indexOf(parentNode
);
524 Q_ASSERT(parentRow
>= 0);
525 return createIndex(parentRow
, 0, parentNode
);
528 bool BookmarksModel::hasChildren(const QModelIndex
&parent
) const
530 if (!parent
.isValid())
532 const BookmarkNode
*parentNode
= node(parent
);
533 return (parentNode
->type() == BookmarkNode::Folder
);
536 Qt::ItemFlags
BookmarksModel::flags(const QModelIndex
&index
) const
538 if (!index
.isValid())
539 return Qt::NoItemFlags
;
541 Qt::ItemFlags flags
= Qt::ItemIsSelectable
| Qt::ItemIsEnabled
;
543 BookmarkNode
*bookmarkNode
= node(index
);
545 if (bookmarkNode
!= m_bookmarksManager
->menu()
546 && bookmarkNode
!= m_bookmarksManager
->toolbar()) {
547 flags
|= Qt::ItemIsDragEnabled
;
548 if (bookmarkNode
->type() != BookmarkNode::Separator
)
549 flags
|= Qt::ItemIsEditable
;
551 if (hasChildren(index
))
552 flags
|= Qt::ItemIsDropEnabled
;
556 Qt::DropActions
BookmarksModel::supportedDropActions () const
558 return Qt::CopyAction
| Qt::MoveAction
;
561 #define MIMETYPE QLatin1String("application/bookmarks.xbel")
563 QStringList
BookmarksModel::mimeTypes() const
570 QMimeData
*BookmarksModel::mimeData(const QModelIndexList
&indexes
) const
572 QMimeData
*mimeData
= new QMimeData();
574 QDataStream
stream(&data
, QIODevice::WriteOnly
);
575 foreach (QModelIndex index
, indexes
) {
576 if (index
.column() != 0 || !index
.isValid())
578 QByteArray encodedData
;
579 QBuffer
buffer(&encodedData
);
580 buffer
.open(QBuffer::ReadWrite
);
582 const BookmarkNode
*parentNode
= node(index
);
583 writer
.write(&buffer
, parentNode
);
584 stream
<< encodedData
;
586 mimeData
->setData(MIMETYPE
, data
);
590 bool BookmarksModel::dropMimeData(const QMimeData
*data
,
591 Qt::DropAction action
, int row
, int column
, const QModelIndex
&parent
)
593 if (action
== Qt::IgnoreAction
)
596 if (!data
->hasFormat(MIMETYPE
)
600 QByteArray ba
= data
->data(MIMETYPE
);
601 QDataStream
stream(&ba
, QIODevice::ReadOnly
);
605 QUndoStack
*undoStack
= m_bookmarksManager
->undoRedoStack();
606 undoStack
->beginMacro(QLatin1String("Move Bookmarks"));
608 while (!stream
.atEnd()) {
609 QByteArray encodedData
;
610 stream
>> encodedData
;
611 QBuffer
buffer(&encodedData
);
612 buffer
.open(QBuffer::ReadOnly
);
615 BookmarkNode
*rootNode
= reader
.read(&buffer
);
616 QList
<BookmarkNode
*> children
= rootNode
->children();
617 for (int i
= 0; i
< children
.count(); ++i
) {
618 BookmarkNode
*bookmarkNode
= children
.at(i
);
619 rootNode
->remove(bookmarkNode
);
621 BookmarkNode
*parentNode
= node(parent
);
622 m_bookmarksManager
->addBookmark(parentNode
, bookmarkNode
, row
);
630 bool BookmarksModel::setData(const QModelIndex
&index
, const QVariant
&value
, int role
)
632 if (!index
.isValid() || (flags(index
) & Qt::ItemIsEditable
) == 0)
635 BookmarkNode
*item
= node(index
);
639 case Qt::DisplayRole
:
640 if (index
.column() == 0) {
641 m_bookmarksManager
->setTitle(item
, value
.toString());
644 if (index
.column() == 1) {
645 m_bookmarksManager
->setUrl(item
, value
.toString());
649 case BookmarksModel::UrlRole
:
650 m_bookmarksManager
->setUrl(item
, value
.toUrl().toString());
652 case BookmarksModel::UrlStringRole
:
653 m_bookmarksManager
->setUrl(item
, value
.toString());
663 BookmarkNode
*BookmarksModel::node(const QModelIndex
&index
) const
665 BookmarkNode
*itemNode
= static_cast<BookmarkNode
*>(index
.internalPointer());
667 return m_bookmarksManager
->bookmarks();
672 AddBookmarkProxyModel::AddBookmarkProxyModel(QObject
*parent
)
673 : QSortFilterProxyModel(parent
)
677 int AddBookmarkProxyModel::columnCount(const QModelIndex
&parent
) const
679 return qMin(1, QSortFilterProxyModel::columnCount(parent
));
682 bool AddBookmarkProxyModel::filterAcceptsRow(int source_row
, const QModelIndex
&source_parent
) const
684 QModelIndex idx
= sourceModel()->index(source_row
, 0, source_parent
);
685 return sourceModel()->hasChildren(idx
);
688 AddBookmarkDialog::AddBookmarkDialog(const QString
&url
, const QString
&title
, QWidget
*parent
, BookmarksManager
*bookmarkManager
)
691 , m_bookmarksManager(bookmarkManager
)
693 setWindowFlags(Qt::Sheet
);
694 if (!m_bookmarksManager
)
695 m_bookmarksManager
= BrowserApplication::bookmarksManager();
697 QTreeView
*view
= new QTreeView(this);
698 m_proxyModel
= new AddBookmarkProxyModel(this);
699 BookmarksModel
*model
= m_bookmarksManager
->bookmarksModel();
700 m_proxyModel
->setSourceModel(model
);
701 view
->setModel(m_proxyModel
);
703 view
->header()->setStretchLastSection(true);
704 view
->header()->hide();
705 view
->setItemsExpandable(false);
706 view
->setRootIsDecorated(false);
707 view
->setIndentation(10);
708 location
->setModel(m_proxyModel
);
710 location
->setView(view
);
711 BookmarkNode
*menu
= m_bookmarksManager
->menu();
712 QModelIndex idx
= m_proxyModel
->mapFromSource(model
->index(menu
));
713 view
->setCurrentIndex(idx
);
714 location
->setCurrentIndex(idx
.row());
715 name
->setText(title
);
718 void AddBookmarkDialog::accept()
720 QModelIndex index
= location
->view()->currentIndex();
721 index
= m_proxyModel
->mapToSource(index
);
722 if (!index
.isValid())
723 index
= m_bookmarksManager
->bookmarksModel()->index(0, 0);
724 BookmarkNode
*parent
= m_bookmarksManager
->bookmarksModel()->node(index
);
725 BookmarkNode
*bookmark
= new BookmarkNode(BookmarkNode::Bookmark
);
726 bookmark
->url
= m_url
;
727 bookmark
->title
= name
->text();
728 m_bookmarksManager
->addBookmark(parent
, bookmark
);
732 BookmarksMenu::BookmarksMenu(QWidget
*parent
)
734 , m_bookmarksManager(0)
736 connect(this, SIGNAL(activated(const QModelIndex
&)),
737 this, SLOT(activated(const QModelIndex
&)));
739 setHoverRole(BookmarksModel::UrlStringRole
);
740 setSeparatorRole(BookmarksModel::SeparatorRole
);
743 void BookmarksMenu::activated(const QModelIndex
&index
)
745 emit
openUrl(index
.data(BookmarksModel::UrlRole
).toUrl());
748 bool BookmarksMenu::prePopulated()
750 m_bookmarksManager
= BrowserApplication::bookmarksManager();
751 setModel(m_bookmarksManager
->bookmarksModel());
752 setRootIndex(m_bookmarksManager
->bookmarksModel()->index(1, 0));
754 for (int i
= 0; i
< m_initialActions
.count(); ++i
)
755 addAction(m_initialActions
.at(i
));
756 if (!m_initialActions
.isEmpty())
758 createMenu(model()->index(0, 0), 1, this);
762 void BookmarksMenu::setInitialActions(QList
<QAction
*> actions
)
764 m_initialActions
= actions
;
765 for (int i
= 0; i
< m_initialActions
.count(); ++i
)
766 addAction(m_initialActions
.at(i
));
769 BookmarksDialog::BookmarksDialog(QWidget
*parent
, BookmarksManager
*manager
)
772 m_bookmarksManager
= manager
;
773 if (!m_bookmarksManager
)
774 m_bookmarksManager
= BrowserApplication::bookmarksManager();
777 tree
->setUniformRowHeights(true);
778 tree
->setSelectionBehavior(QAbstractItemView::SelectRows
);
779 tree
->setSelectionMode(QAbstractItemView::ContiguousSelection
);
780 tree
->setTextElideMode(Qt::ElideMiddle
);
781 m_bookmarksModel
= m_bookmarksManager
->bookmarksModel();
782 m_proxyModel
= new TreeProxyModel(this);
783 connect(search
, SIGNAL(textChanged(QString
)),
784 m_proxyModel
, SLOT(setFilterFixedString(QString
)));
785 connect(removeButton
, SIGNAL(clicked()), tree
, SLOT(removeOne()));
786 m_proxyModel
->setSourceModel(m_bookmarksModel
);
787 tree
->setModel(m_proxyModel
);
788 tree
->setDragDropMode(QAbstractItemView::InternalMove
);
789 tree
->setExpanded(m_proxyModel
->index(0, 0), true);
790 tree
->setAlternatingRowColors(true);
791 QFontMetrics
fm(font());
792 int header
= fm
.width(QLatin1Char('m')) * 40;
793 tree
->header()->resizeSection(0, header
);
794 tree
->header()->setStretchLastSection(true);
795 connect(tree
, SIGNAL(activated(const QModelIndex
&)),
797 tree
->setContextMenuPolicy(Qt::CustomContextMenu
);
798 connect(tree
, SIGNAL(customContextMenuRequested(const QPoint
&)),
799 this, SLOT(customContextMenuRequested(const QPoint
&)));
800 connect(addFolderButton
, SIGNAL(clicked()),
801 this, SLOT(newFolder()));
802 expandNodes(m_bookmarksManager
->bookmarks());
803 setAttribute(Qt::WA_DeleteOnClose
);
806 BookmarksDialog::~BookmarksDialog()
808 if (saveExpandedNodes(tree
->rootIndex()))
809 m_bookmarksManager
->changeExpanded();
812 bool BookmarksDialog::saveExpandedNodes(const QModelIndex
&parent
)
814 bool changed
= false;
815 for (int i
= 0; i
< m_proxyModel
->rowCount(parent
); ++i
) {
816 QModelIndex child
= m_proxyModel
->index(i
, 0, parent
);
817 QModelIndex sourceIndex
= m_proxyModel
->mapToSource(child
);
818 BookmarkNode
*childNode
= m_bookmarksModel
->node(sourceIndex
);
819 bool wasExpanded
= childNode
->expanded
;
820 if (tree
->isExpanded(child
)) {
821 childNode
->expanded
= true;
822 changed
|= saveExpandedNodes(child
);
824 childNode
->expanded
= false;
826 changed
|= (wasExpanded
!= childNode
->expanded
);
831 void BookmarksDialog::expandNodes(BookmarkNode
*node
)
833 for (int i
= 0; i
< node
->children().count(); ++i
) {
834 BookmarkNode
*childNode
= node
->children()[i
];
835 if (childNode
->expanded
) {
836 QModelIndex idx
= m_bookmarksModel
->index(childNode
);
837 idx
= m_proxyModel
->mapFromSource(idx
);
838 tree
->setExpanded(idx
, true);
839 expandNodes(childNode
);
844 void BookmarksDialog::customContextMenuRequested(const QPoint
&pos
)
847 QModelIndex index
= tree
->indexAt(pos
);
848 index
= index
.sibling(index
.row(), 0);
849 if (index
.isValid() && !tree
->model()->hasChildren(index
)) {
850 menu
.addAction(tr("Open"), this, SLOT(open()));
853 menu
.addAction(tr("Delete"), tree
, SLOT(removeOne()));
854 menu
.exec(QCursor::pos());
857 void BookmarksDialog::open()
859 QModelIndex index
= tree
->currentIndex();
860 if (!index
.parent().isValid())
862 emit
openUrl(index
.sibling(index
.row(), 1).data(BookmarksModel::UrlRole
).toUrl());
865 void BookmarksDialog::newFolder()
867 QModelIndex currentIndex
= tree
->currentIndex();
868 QModelIndex idx
= currentIndex
;
869 if (idx
.isValid() && !idx
.model()->hasChildren(idx
))
872 idx
= tree
->rootIndex();
873 idx
= m_proxyModel
->mapToSource(idx
);
874 BookmarkNode
*parent
= m_bookmarksManager
->bookmarksModel()->node(idx
);
875 BookmarkNode
*node
= new BookmarkNode(BookmarkNode::Folder
);
876 node
->title
= tr("New Folder");
877 m_bookmarksManager
->addBookmark(parent
, node
, currentIndex
.row() + 1);
880 BookmarksToolBar::BookmarksToolBar(BookmarksModel
*model
, QWidget
*parent
)
881 : QToolBar(tr("Bookmark"), parent
)
882 , m_bookmarksModel(model
)
884 connect(this, SIGNAL(actionTriggered(QAction
*)), this, SLOT(triggered(QAction
*)));
885 setRootIndex(model
->index(0, 0));
886 connect(m_bookmarksModel
, SIGNAL(modelReset()), this, SLOT(build()));
887 connect(m_bookmarksModel
, SIGNAL(rowsInserted(const QModelIndex
&, int, int)), this, SLOT(build()));
888 connect(m_bookmarksModel
, SIGNAL(rowsRemoved(const QModelIndex
&, int, int)), this, SLOT(build()));
889 connect(m_bookmarksModel
, SIGNAL(dataChanged(const QModelIndex
&, const QModelIndex
&)), this, SLOT(build()));
890 setAcceptDrops(true);
893 void BookmarksToolBar::dragEnterEvent(QDragEnterEvent
*event
)
895 const QMimeData
*mimeData
= event
->mimeData();
896 if (mimeData
->hasUrls())
897 event
->acceptProposedAction();
898 QToolBar::dragEnterEvent(event
);
901 void BookmarksToolBar::dropEvent(QDropEvent
*event
)
903 const QMimeData
*mimeData
= event
->mimeData();
904 if (mimeData
->hasUrls() && mimeData
->hasText()) {
905 QList
<QUrl
> urls
= mimeData
->urls();
906 QAction
*action
= actionAt(event
->pos());
909 dropText
= action
->text();
911 QModelIndex parentIndex
= m_root
;
912 for (int i
= 0; i
< m_bookmarksModel
->rowCount(m_root
); ++i
) {
913 QModelIndex idx
= m_bookmarksModel
->index(i
, 0, m_root
);
914 QString title
= idx
.data().toString();
915 if (title
== dropText
) {
917 if (m_bookmarksModel
->hasChildren(idx
)) {
924 BookmarkNode
*bookmark
= new BookmarkNode(BookmarkNode::Bookmark
);
925 bookmark
->url
= urls
.at(0).toString();
926 bookmark
->title
= mimeData
->text();
928 BookmarkNode
*parent
= m_bookmarksModel
->node(parentIndex
);
929 BookmarksManager
*bookmarksManager
= m_bookmarksModel
->bookmarksManager();
930 bookmarksManager
->addBookmark(parent
, bookmark
, row
);
931 event
->acceptProposedAction();
933 QToolBar::dropEvent(event
);
937 void BookmarksToolBar::setRootIndex(const QModelIndex
&index
)
943 QModelIndex
BookmarksToolBar::rootIndex() const
948 void BookmarksToolBar::build()
951 for (int i
= 0; i
< m_bookmarksModel
->rowCount(m_root
); ++i
) {
952 QModelIndex idx
= m_bookmarksModel
->index(i
, 0, m_root
);
953 if (m_bookmarksModel
->hasChildren(idx
)) {
954 QToolButton
*button
= new QToolButton(this);
955 button
->setPopupMode(QToolButton::InstantPopup
);
956 button
->setArrowType(Qt::DownArrow
);
957 button
->setText(idx
.data().toString());
958 ModelMenu
*menu
= new ModelMenu(this);
959 connect(menu
, SIGNAL(activated(const QModelIndex
&)),
960 this, SLOT(activated(const QModelIndex
&)));
961 menu
->setModel(m_bookmarksModel
);
962 menu
->setRootIndex(idx
);
963 menu
->addAction(new QAction(menu
));
964 button
->setMenu(menu
);
965 button
->setToolButtonStyle(Qt::ToolButtonTextOnly
);
966 QAction
*a
= addWidget(button
);
967 a
->setText(idx
.data().toString());
969 QAction
*action
= addAction(idx
.data().toString());
970 action
->setData(idx
.data(BookmarksModel::UrlRole
));
975 void BookmarksToolBar::triggered(QAction
*action
)
977 QVariant v
= action
->data();
978 if (v
.canConvert
<QUrl
>()) {
979 emit
openUrl(v
.toUrl());
983 void BookmarksToolBar::activated(const QModelIndex
&index
)
985 emit
openUrl(index
.data(BookmarksModel::UrlRole
).toUrl());