/* ============================================================ * * This file is a part of the rekonq project * * Copyright (C) 2008-2012 by Andrea Diamantini * Copyright (C) 2010 by Yoann Laissus * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * ============================================================ */ // Self Includes #include "bookmarkstoolbar.h" #include "bookmarkstoolbar.moc" // Local Includes #include "iconmanager.h" #include "bookmarkscontextmenu.h" #include "mainwindow.h" #include "application.h" #include "bookmarkmanager.h" #include "bookmarkowner.h" #include "webtab.h" // Qt Includes #include #include BookmarkMenu::BookmarkMenu(KBookmarkManager *manager, KBookmarkOwner *owner, KMenu *menu, KActionCollection* actionCollection) : KBookmarkMenu(manager, owner, menu, actionCollection) { } BookmarkMenu::BookmarkMenu(KBookmarkManager *manager, KBookmarkOwner *owner, KMenu *parentMenu, const QString &parentAddress) : KBookmarkMenu(manager, owner, parentMenu, parentAddress) { } BookmarkMenu::~BookmarkMenu() { kDebug() << "Deleting BookmarkMenu.. See http://svn.reviewboard.kde.org/r/5606/ about."; } KMenu * BookmarkMenu::contextMenu(QAction *act) { KBookmarkActionInterface* action = dynamic_cast(act); if (!action) return 0; return new BookmarksContextMenu(action->bookmark(), manager(), static_cast(owner())); } QAction * BookmarkMenu::actionForBookmark(const KBookmark &bookmark) { if (bookmark.isGroup()) { KBookmarkActionMenu *actionMenu = new KBookmarkActionMenu(bookmark, this); BookmarkMenu *menu = new BookmarkMenu(manager(), owner(), actionMenu->menu(), bookmark.address()); // An hack to get rid of bug 219274 connect(actionMenu, SIGNAL(hovered()), menu, SLOT(slotAboutToShow())); return actionMenu; } else if (bookmark.isSeparator()) { return KBookmarkMenu::actionForBookmark(bookmark); } else { KBookmarkAction *action = new KBookmarkAction(bookmark, owner(), this); action->setIcon(rApp->iconManager()->iconForUrl(KUrl(bookmark.url()))); connect(action, SIGNAL(hovered()), this, SLOT(actionHovered())); return action; } } void BookmarkMenu::refill() { clear(); fillBookmarks(); if (parentMenu()->actions().count() > 0) parentMenu()->addSeparator(); if (isRoot()) { addAddBookmarksList(); addEditBookmarks(); } else { addOpenFolderInTabs(); addAddBookmarksList(); } } void BookmarkMenu::addOpenFolderInTabs() { KBookmarkGroup group = manager()->findByAddress(parentAddress()).toGroup(); if (!group.first().isNull()) { KBookmark bookmark = group.first(); while (bookmark.isGroup() || bookmark.isSeparator()) { bookmark = group.next(bookmark); } if (!bookmark.isNull()) { parentMenu()->addAction(rApp->bookmarkManager()->owner()->createAction(group, BookmarkOwner::OPEN_FOLDER)); } } } void BookmarkMenu::actionHovered() { KBookmarkActionInterface* action = dynamic_cast(sender()); if (action) rApp->mainWindow()->notifyMessage(action->bookmark().url().url()); } // ------------------------------------------------------------------------------------------------------ BookmarkToolBar::BookmarkToolBar(KToolBar *toolBar, QObject *parent) : QObject(parent) , m_toolBar(toolBar) , m_currentMenu(0) , m_dragAction(0) , m_dropAction(0) , m_checkedAction(0) , m_filled(false) { toolBar->setContextMenuPolicy(Qt::CustomContextMenu); connect(toolBar, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenu(QPoint))); connect(rApp->bookmarkManager()->manager(), SIGNAL(changed(QString, QString)), this, SLOT(hideMenu())); toolBar->setAcceptDrops(true); toolBar->installEventFilter(this); toolBar->setShortcutEnabled(false); if (toolBar->isVisible()) { rApp->bookmarkManager()->fillBookmarkBar(this); m_filled = true; } } KToolBar* BookmarkToolBar::toolBar() { return m_toolBar; } void BookmarkToolBar::contextMenu(const QPoint &point) { KBookmarkActionInterface *action = dynamic_cast(toolBar()->actionAt(point)); KBookmark bookmark = rApp->bookmarkManager()->manager()->toolbar(); bool nullAction = true; if (action) { bookmark = action->bookmark(); nullAction = false; } BookmarksContextMenu menu(bookmark, rApp->bookmarkManager()->manager(), rApp->bookmarkManager()->owner(), nullAction); menu.exec(toolBar()->mapToGlobal(point)); } void BookmarkToolBar::menuDisplayed() { qApp->installEventFilter(this); m_currentMenu = qobject_cast(sender()); } void BookmarkToolBar::menuHidden() { qApp->removeEventFilter(this); m_currentMenu = 0; } void BookmarkToolBar::hideMenu() { if (m_currentMenu) m_currentMenu->hide(); } bool BookmarkToolBar::eventFilter(QObject *watched, QEvent *event) { if (m_currentMenu && m_currentMenu->isVisible() && !m_currentMenu->rect().contains(m_currentMenu->mapFromGlobal(QCursor::pos()))) { // To switch root folders as in a menubar KBookmarkActionMenu* act = dynamic_cast(toolBar()->actionAt(toolBar()->mapFromGlobal(QCursor::pos()))); if (event->type() == QEvent::MouseMove && act && act->menu() != m_currentMenu) { m_currentMenu->hide(); QPoint pos = toolBar()->mapToGlobal(toolBar()->widgetForAction(act)->pos()); act->menu()->popup(QPoint(pos.x(), pos.y() + toolBar()->widgetForAction(act)->height())); } else if (event->type() == QEvent::MouseButtonPress && act) { m_currentMenu->hide(); } return QObject::eventFilter(watched, event); } switch (event->type()) { case QEvent::Show: { if (!m_filled) { rApp->bookmarkManager()->fillBookmarkBar(this); m_filled = true; } } break; case QEvent::ActionRemoved: { QActionEvent *actionEvent = static_cast(event); if (actionEvent && actionEvent->action() != m_dropAction) { QWidget *widget = toolBar()->widgetForAction(actionEvent->action()); if (widget) { widget->removeEventFilter(this); } } } break; case QEvent::ParentChange: { QActionEvent *actionEvent = static_cast(event); if (actionEvent && actionEvent->action() != m_dropAction) { QWidget *widget = toolBar()->widgetForAction(actionEvent->action()); if (widget) { widget->removeEventFilter(this); } } } break; case QEvent::DragEnter: { QDragEnterEvent *dragEvent = static_cast(event); if (dragEvent->mimeData()->hasFormat("application/rekonq-bookmark") || dragEvent->mimeData()->hasFormat("text/uri-list") || dragEvent->mimeData()->hasFormat("text/plain")) { QFrame* dropIndicatorWidget = new QFrame(toolBar()); dropIndicatorWidget->setFrameShape(QFrame::VLine); m_dropAction = toolBar()->insertWidget(toolBar()->actionAt(dragEvent->pos()), dropIndicatorWidget); dragEvent->accept(); } } break; case QEvent::DragLeave: { QDragLeaveEvent *dragEvent = static_cast(event); if (m_checkedAction) { m_checkedAction->setCheckable(false); m_checkedAction->setChecked(false); } delete m_dropAction; m_dropAction = 0; dragEvent->accept(); } break; case QEvent::DragMove: { QDragMoveEvent *dragEvent = static_cast(event); if (dragEvent->mimeData()->hasFormat("application/rekonq-bookmark") || dragEvent->mimeData()->hasFormat("text/uri-list") || dragEvent->mimeData()->hasFormat("text/plain")) { QAction *overAction = toolBar()->actionAt(dragEvent->pos()); KBookmarkActionInterface *overActionBK = dynamic_cast(overAction); QWidget *widgetAction = toolBar()->widgetForAction(overAction); if (overAction != m_dropAction && overActionBK && widgetAction && m_dropAction) { toolBar()->removeAction(m_dropAction); if (m_checkedAction) { m_checkedAction->setCheckable(false); m_checkedAction->setChecked(false); } if (!overActionBK->bookmark().isGroup()) { if ((dragEvent->pos().x() - widgetAction->pos().x()) > (widgetAction->width() / 2)) { if (toolBar()->actions().count() > toolBar()->actions().indexOf(overAction) + 1) { toolBar()->insertAction(toolBar()->actions().at(toolBar()->actions().indexOf(overAction) + 1), m_dropAction); } else { toolBar()->addAction(m_dropAction); } } else { toolBar()->insertAction(overAction, m_dropAction); } } else { if ((dragEvent->pos().x() - widgetAction->pos().x()) >= (widgetAction->width() * 0.75)) { if (toolBar()->actions().count() > toolBar()->actions().indexOf(overAction) + 1) { toolBar()->insertAction(toolBar()->actions().at(toolBar()->actions().indexOf(overAction) + 1), m_dropAction); } else { toolBar()->addAction(m_dropAction); } } else if ((dragEvent->pos().x() - widgetAction->pos().x()) <= (widgetAction->width() * 0.25)) { toolBar()->insertAction(overAction, m_dropAction); } else { overAction->setCheckable(true); overAction->setChecked(true); m_checkedAction = overAction; } } dragEvent->accept(); } } } break; case QEvent::Drop: { QDropEvent *dropEvent = static_cast(event); KBookmark bookmark; KBookmarkGroup root = rApp->bookmarkManager()->manager()->toolbar(); if (m_checkedAction) { m_checkedAction->setCheckable(false); m_checkedAction->setChecked(false); } if (dropEvent->mimeData()->hasFormat("application/rekonq-bookmark")) { QByteArray addresses = dropEvent->mimeData()->data("application/rekonq-bookmark"); bookmark = rApp->bookmarkManager()->findByAddress(QString::fromLatin1(addresses.data())); if (bookmark.isNull()) return false; } else if (dropEvent->mimeData()->hasFormat("text/uri-list")) { // DROP is URL QString url = dropEvent->mimeData()->urls().at(0).toString(); QString title = url.contains(rApp->mainWindow()->currentTab()->url().url()) ? rApp->mainWindow()->currentTab()->view()->title() : url; bookmark = root.addBookmark(title, url); } else if (dropEvent->mimeData()->hasFormat("text/plain")) { // DROP is TEXT QString url = dropEvent->mimeData()->text(); KUrl u(url); if (u.isValid()) { QString title = url.contains(rApp->mainWindow()->currentTab()->url().url()) ? rApp->mainWindow()->currentTab()->view()->title() : url; bookmark = root.addBookmark(title, url); } } else { return false; } QAction *destAction = toolBar()->actionAt(dropEvent->pos()); if (destAction && destAction == m_dropAction) { if (toolBar()->actions().indexOf(m_dropAction) > 0) { destAction = toolBar()->actions().at(toolBar()->actions().indexOf(m_dropAction) - 1); } else { destAction = toolBar()->actions().at(1); } } if (destAction) { KBookmarkActionInterface *destBookmarkAction = dynamic_cast(destAction); QWidget *widgetAction = toolBar()->widgetForAction(destAction); if (destBookmarkAction && !destBookmarkAction->bookmark().isNull() && widgetAction && bookmark.address() != destBookmarkAction->bookmark().address()) { KBookmark destBookmark = destBookmarkAction->bookmark(); if (!destBookmark.isGroup()) { if ((dropEvent->pos().x() - widgetAction->pos().x()) >= (widgetAction->width() / 2)) { root.moveBookmark(bookmark, destBookmark); } else { root.moveBookmark(bookmark, destBookmark.parentGroup().previous(destBookmark)); } } else { if ((dropEvent->pos().x() - widgetAction->pos().x()) >= (widgetAction->width() * 0.75)) { root.moveBookmark(bookmark, destBookmark); } else if ((dropEvent->pos().x() - widgetAction->pos().x()) <= (widgetAction->width() * 0.25)) { root.moveBookmark(bookmark, destBookmark.parentGroup().previous(destBookmark)); } else { destBookmark.toGroup().addBookmark(bookmark); } } rApp->bookmarkManager()->emitChanged(); } } else { root.deleteBookmark(bookmark); bookmark = root.addBookmark(bookmark); if (dropEvent->pos().x() < toolBar()->widgetForAction(toolBar()->actions().first())->pos().x()) { root.moveBookmark(bookmark, KBookmark()); } rApp->bookmarkManager()->emitChanged(); } dropEvent->accept(); } break; default: break; } QMouseEvent *mouseEvent = static_cast(event); // These events need to be handled only for Bookmark actions and not the bar if (watched != toolBar() && mouseEvent) { switch (event->type()) { case QEvent::MouseButtonPress: // drag handling { QPoint pos = toolBar()->mapFromGlobal(QCursor::pos()); KBookmarkActionInterface *action = dynamic_cast(toolBar()->actionAt(pos)); if (action && mouseEvent->button() != Qt::MidButton) { m_dragAction = toolBar()->actionAt(pos); m_startDragPos = pos; // The menu is displayed only when the mouse button is released if (action->bookmark().isGroup()) return true; } } break; case QEvent::MouseMove: { int distance = (toolBar()->mapFromGlobal(QCursor::pos()) - m_startDragPos).manhattanLength(); if (!m_currentMenu && distance >= QApplication::startDragDistance()) { startDrag(); } } break; case QEvent::MouseButtonRelease: { QPoint destPos = toolBar()->mapFromGlobal(QCursor::pos()); int distance = (destPos - m_startDragPos).manhattanLength(); KBookmarkActionInterface *action = dynamic_cast(toolBar()->actionAt(destPos)); if (action && action->bookmark().isGroup()) { if (mouseEvent->button() == Qt::MidButton) { rApp->bookmarkManager()->owner()->openBookmarkFolder(action->bookmark()); } else if (distance < QApplication::startDragDistance()) { KBookmarkActionMenu *menu = dynamic_cast(toolBar()->actionAt(m_startDragPos)); QPoint actionPos = toolBar()->mapToGlobal(toolBar()->widgetForAction(menu)->pos()); menu->menu()->popup(QPoint(actionPos.x(), actionPos.y() + toolBar()->widgetForAction(menu)->height())); } } } break; default: break; } } return QObject::eventFilter(watched, event); } void BookmarkToolBar::actionHovered() { KBookmarkActionInterface* action = dynamic_cast(sender()); if (action) rApp->mainWindow()->notifyMessage(action->bookmark().url().url()); } void BookmarkToolBar::startDrag() { KBookmarkActionInterface *action = dynamic_cast(m_dragAction); if (action) { QMimeData *mimeData = new QMimeData; KBookmark bookmark = action->bookmark(); QByteArray address = bookmark.address().toLatin1(); mimeData->setData("application/rekonq-bookmark", address); bookmark.populateMimeData(mimeData); QDrag *drag = new QDrag(toolBar()); drag->setMimeData(mimeData); if (bookmark.isGroup()) { drag->setPixmap(KIcon(bookmark.icon()).pixmap(24, 24)); } else { drag->setPixmap(rApp->iconManager()->iconForUrl(action->bookmark().url()).pixmap(24, 24)); } drag->start(Qt::MoveAction); connect(drag, SIGNAL(destroyed()), this, SLOT(dragDestroyed())); } } void BookmarkToolBar::dragDestroyed() { // A workaround to get rid of the checked state of the dragged action if (m_dragAction) { m_dragAction->setVisible(false); m_dragAction->setVisible(true); m_dragAction = 0; } delete m_dropAction; m_dropAction = 0; }