Windows doesn't #define STD{IN,OUT,ERR}_FILENO
[qt-netbsd.git] / demos / browser / bookmarks.cpp
blobedafb76b9583260270d9afcdbdfbbffe4b4b461c
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the demonstration applications of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "bookmarks.h"
44 #include "autosaver.h"
45 #include "browserapplication.h"
46 #include "history.h"
47 #include "xbel.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)
69 : QObject(parent)
70 , m_loaded(false)
71 , m_saveTimer(new AutoSaver(this))
72 , m_bookmarkRootNode(0)
73 , m_bookmarkModel(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()
95 if (m_loaded)
96 return;
97 m_loaded = true;
99 QString dir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
100 QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel");
101 if (!QFile::exists(bookmarkFile))
102 bookmarkFile = QLatin1String(":defaultbookmarks.xbel");
104 XbelReader reader;
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) {
123 toolbar = node;
126 // Automatically convert
127 if (node->title == tr("Menu") && !menu) {
128 node->title = tr(BOOKMARKMENU);
130 if (node->title == tr(BOOKMARKMENU) && !menu) {
131 menu = node;
133 } else {
134 others.append(node);
136 m_bookmarkRootNode->remove(node);
138 Q_ASSERT(m_bookmarkRootNode->children().count() == 0);
139 if (!toolbar) {
140 toolbar = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
141 toolbar->title = tr(BOOKMARKBAR);
142 } else {
143 m_bookmarkRootNode->add(toolbar);
146 if (!menu) {
147 menu = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
148 menu->title = tr(BOOKMARKMENU);
149 } else {
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
159 if (!m_loaded)
160 return;
162 XbelWriter writer;
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)
171 if (!m_loaded)
172 return;
173 Q_ASSERT(parent);
174 InsertBookmarksCommand *command = new InsertBookmarksCommand(this, parent, node, row);
175 m_commands.push(command);
178 void BookmarksManager::removeBookmark(BookmarkNode *node)
180 if (!m_loaded)
181 return;
183 Q_ASSERT(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)
192 if (!m_loaded)
193 return;
195 Q_ASSERT(node);
196 ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newTitle, true);
197 m_commands.push(command);
200 void BookmarksManager::setUrl(BookmarkNode *node, const QString &newUrl)
202 if (!m_loaded)
203 return;
205 Q_ASSERT(node);
206 ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newUrl, false);
207 m_commands.push(command);
210 BookmarkNode *BookmarksManager::bookmarks()
212 if (!m_loaded)
213 load();
214 return m_bookmarkRootNode;
217 BookmarkNode *BookmarksManager::menu()
219 if (!m_loaded)
220 load();
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))
225 return node;
227 Q_ASSERT(false);
228 return 0;
231 BookmarkNode *BookmarksManager::toolbar()
233 if (!m_loaded)
234 load();
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))
239 return node;
241 Q_ASSERT(false);
242 return 0;
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"),
255 QString(),
256 tr("XBEL (*.xbel *.xml)"));
257 if (fileName.isEmpty())
258 return;
260 XbelReader reader;
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())
279 return;
281 XbelWriter writer;
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"))
288 , m_row(row)
289 , m_bookmarkManagaer(m_bookmarkManagaer)
290 , m_node(parent->children().value(row))
291 , m_parent(parent)
292 , m_done(false)
296 RemoveBookmarksCommand::~RemoveBookmarksCommand()
298 if (m_done && !m_node->parent()) {
299 delete m_node;
303 void RemoveBookmarksCommand::undo()
305 m_parent->add(m_node, m_row);
306 emit m_bookmarkManagaer->entryAdded(m_node);
307 m_done = false;
310 void RemoveBookmarksCommand::redo()
312 m_parent->remove(m_node);
313 emit m_bookmarkManagaer->entryRemoved(m_parent, m_row, m_node);
314 m_done = true;
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"));
322 m_node = node;
325 ChangeBookmarkCommand::ChangeBookmarkCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *node,
326 const QString &newValue, bool title)
327 : QUndoCommand()
328 , m_bookmarkManagaer(m_bookmarkManagaer)
329 , m_title(title)
330 , m_newValue(newValue)
331 , m_node(node)
333 if (m_title) {
334 m_oldValue = m_node->title;
335 setText(BookmarksManager::tr("Name Change"));
336 } else {
337 m_oldValue = m_node->url;
338 setText(BookmarksManager::tr("Address Change"));
342 void ChangeBookmarkCommand::undo()
344 if (m_title)
345 m_node->title = m_oldValue;
346 else
347 m_node->url = m_oldValue;
348 emit m_bookmarkManagaer->entryChanged(m_node);
351 void ChangeBookmarkCommand::redo()
353 if (m_title)
354 m_node->title = m_newValue;
355 else
356 m_node->url = m_newValue;
357 emit m_bookmarkManagaer->entryChanged(m_node);
360 BookmarksModel::BookmarksModel(BookmarksManager *bookmarkManager, QObject *parent)
361 : QAbstractItemModel(parent)
362 , m_endMacro(false)
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();
376 if (!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);
390 endInsertRows();
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);
399 endRemoveRows();
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))
411 return false;
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())
418 continue;
420 m_bookmarksManager->removeBookmark(node);
422 if (m_endMacro) {
423 m_bookmarksManager->undoRedoStack()->endMacro();
424 m_endMacro = false;
426 return true;
429 QVariant BookmarksModel::headerData(int section, Qt::Orientation orientation, int role) const
431 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
432 switch (section) {
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)
443 return QVariant();
445 const BookmarkNode *bookmarkNode = node(index);
446 switch (role) {
447 case Qt::EditRole:
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;
460 break;
461 case BookmarksModel::UrlRole:
462 return QUrl(bookmarkNode->url);
463 break;
464 case BookmarksModel::UrlStringRole:
465 return bookmarkNode->url;
466 break;
467 case BookmarksModel::TypeRole:
468 return bookmarkNode->type();
469 break;
470 case BookmarksModel::SeparatorRole:
471 return (bookmarkNode->type() == BookmarkNode::Separator);
472 break;
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);
481 return QVariant();
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)
492 return 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())
531 return true;
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;
553 return flags;
556 Qt::DropActions BookmarksModel::supportedDropActions () const
558 return Qt::CopyAction | Qt::MoveAction;
561 #define MIMETYPE QLatin1String("application/bookmarks.xbel")
563 QStringList BookmarksModel::mimeTypes() const
565 QStringList types;
566 types << MIMETYPE;
567 return types;
570 QMimeData *BookmarksModel::mimeData(const QModelIndexList &indexes) const
572 QMimeData *mimeData = new QMimeData();
573 QByteArray data;
574 QDataStream stream(&data, QIODevice::WriteOnly);
575 foreach (QModelIndex index, indexes) {
576 if (index.column() != 0 || !index.isValid())
577 continue;
578 QByteArray encodedData;
579 QBuffer buffer(&encodedData);
580 buffer.open(QBuffer::ReadWrite);
581 XbelWriter writer;
582 const BookmarkNode *parentNode = node(index);
583 writer.write(&buffer, parentNode);
584 stream << encodedData;
586 mimeData->setData(MIMETYPE, data);
587 return mimeData;
590 bool BookmarksModel::dropMimeData(const QMimeData *data,
591 Qt::DropAction action, int row, int column, const QModelIndex &parent)
593 if (action == Qt::IgnoreAction)
594 return true;
596 if (!data->hasFormat(MIMETYPE)
597 || column > 0)
598 return false;
600 QByteArray ba = data->data(MIMETYPE);
601 QDataStream stream(&ba, QIODevice::ReadOnly);
602 if (stream.atEnd())
603 return false;
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);
614 XbelReader reader;
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);
620 row = qMax(0, row);
621 BookmarkNode *parentNode = node(parent);
622 m_bookmarksManager->addBookmark(parentNode, bookmarkNode, row);
623 m_endMacro = true;
625 delete rootNode;
627 return true;
630 bool BookmarksModel::setData(const QModelIndex &index, const QVariant &value, int role)
632 if (!index.isValid() || (flags(index) & Qt::ItemIsEditable) == 0)
633 return false;
635 BookmarkNode *item = node(index);
637 switch (role) {
638 case Qt::EditRole:
639 case Qt::DisplayRole:
640 if (index.column() == 0) {
641 m_bookmarksManager->setTitle(item, value.toString());
642 break;
644 if (index.column() == 1) {
645 m_bookmarksManager->setUrl(item, value.toString());
646 break;
648 return false;
649 case BookmarksModel::UrlRole:
650 m_bookmarksManager->setUrl(item, value.toUrl().toString());
651 break;
652 case BookmarksModel::UrlStringRole:
653 m_bookmarksManager->setUrl(item, value.toString());
654 break;
655 default:
656 break;
657 return false;
660 return true;
663 BookmarkNode *BookmarksModel::node(const QModelIndex &index) const
665 BookmarkNode *itemNode = static_cast<BookmarkNode*>(index.internalPointer());
666 if (!itemNode)
667 return m_bookmarksManager->bookmarks();
668 return itemNode;
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)
689 : QDialog(parent)
690 , m_url(url)
691 , m_bookmarksManager(bookmarkManager)
693 setWindowFlags(Qt::Sheet);
694 if (!m_bookmarksManager)
695 m_bookmarksManager = BrowserApplication::bookmarksManager();
696 setupUi(this);
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);
702 view->expandAll();
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);
709 view->show();
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);
729 QDialog::accept();
732 BookmarksMenu::BookmarksMenu(QWidget *parent)
733 : ModelMenu(parent)
734 , m_bookmarksManager(0)
736 connect(this, SIGNAL(activated(const QModelIndex &)),
737 this, SLOT(activated(const QModelIndex &)));
738 setMaxRows(-1);
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));
753 // initial actions
754 for (int i = 0; i < m_initialActions.count(); ++i)
755 addAction(m_initialActions.at(i));
756 if (!m_initialActions.isEmpty())
757 addSeparator();
758 createMenu(model()->index(0, 0), 1, this);
759 return true;
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)
770 : QDialog(parent)
772 m_bookmarksManager = manager;
773 if (!m_bookmarksManager)
774 m_bookmarksManager = BrowserApplication::bookmarksManager();
775 setupUi(this);
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&)),
796 this, SLOT(open()));
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);
823 } else {
824 childNode->expanded = false;
826 changed |= (wasExpanded != childNode->expanded);
828 return changed;
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)
846 QMenu menu;
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()));
851 menu.addSeparator();
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())
861 return;
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))
870 idx = idx.parent();
871 if (!idx.isValid())
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());
907 QString dropText;
908 if (action)
909 dropText = action->text();
910 int row = -1;
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) {
916 row = i;
917 if (m_bookmarksModel->hasChildren(idx)) {
918 parentIndex = idx;
919 row = -1;
921 break;
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)
939 m_root = index;
940 build();
943 QModelIndex BookmarksToolBar::rootIndex() const
945 return m_root;
948 void BookmarksToolBar::build()
950 clear();
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());
968 } else {
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());