summaryrefslogtreecommitdiffstats
path: root/kio/bookmarks/kbookmarkbar.cc
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch)
tree5ac38a06f3dde268dc7927dc155896926aaf7012 /kio/bookmarks/kbookmarkbar.cc
downloadtdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz
tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kio/bookmarks/kbookmarkbar.cc')
-rw-r--r--kio/bookmarks/kbookmarkbar.cc554
1 files changed, 554 insertions, 0 deletions
diff --git a/kio/bookmarks/kbookmarkbar.cc b/kio/bookmarks/kbookmarkbar.cc
new file mode 100644
index 000000000..d71069014
--- /dev/null
+++ b/kio/bookmarks/kbookmarkbar.cc
@@ -0,0 +1,554 @@
+// -*- c-basic-offset:4; indent-tabs-mode:nil -*-
+// vim: set ts=4 sts=4 sw=4 et:
+/* This file is part of the KDE project
+ Copyright (C) 1999 Kurt Granroth <granroth@kde.org>
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include <qregexp.h>
+#include <qfile.h>
+
+#include <kbookmarkbar.h>
+#include <kbookmarkdrag.h>
+
+#include <kbookmarkmenu.h>
+#include <kdebug.h>
+
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+
+#include <kconfig.h>
+#include <kpopupmenu.h>
+
+#include "kbookmarkdrag.h"
+#include "kbookmarkmenu_p.h"
+#include "kbookmarkdombuilder.h"
+
+#include "dptrtemplate.h"
+
+#include <qapplication.h>
+
+class KBookmarkBarPrivate : public dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate>
+{
+public:
+ QPtrList<KAction> m_actions;
+ bool m_readOnly;
+ KBookmarkManager* m_filteredMgr;
+ KToolBar* m_sepToolBar;
+ int m_sepIndex;
+ bool m_atFirst;
+ QString m_dropAddress;
+ QString m_highlightedAddress;
+public:
+ KBookmarkBarPrivate() {
+ m_readOnly = false;
+ m_filteredMgr = 0;
+ m_sepToolBar = 0;
+ m_sepIndex = -1;
+ m_atFirst = false;
+ }
+};
+template<> QPtrDict<KBookmarkBarPrivate>* dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate>::d_ptr = 0;
+
+KBookmarkBarPrivate* KBookmarkBar::dptr() const
+{
+ return KBookmarkBarPrivate::d( this );
+}
+
+// usage of KXBELBookmarkImporterImpl is just plain evil, but it reduces code dup. so...
+class ToolbarFilter : public KXBELBookmarkImporterImpl
+{
+public:
+ ToolbarFilter() : m_visible(false) { ; }
+ void filter( const KBookmarkGroup &grp ) { traverse(grp); }
+private:
+ virtual void visit( const KBookmark & );
+ virtual void visitEnter( const KBookmarkGroup & );
+ virtual void visitLeave( const KBookmarkGroup & );
+private:
+ bool m_visible;
+ KBookmarkGroup m_visibleStart;
+};
+
+KBookmarkBar::KBookmarkBar( KBookmarkManager* mgr,
+ KBookmarkOwner *_owner, KToolBar *_toolBar,
+ KActionCollection *coll,
+ QObject *parent, const char *name )
+ : QObject( parent, name ), m_pOwner(_owner), m_toolBar(_toolBar),
+ m_actionCollection( coll ), m_pManager(mgr)
+{
+ m_lstSubMenus.setAutoDelete( true );
+
+ m_toolBar->setAcceptDrops( true );
+ m_toolBar->installEventFilter( this ); // for drops
+
+ dptr()->m_actions.setAutoDelete( true );
+
+ connect( mgr, SIGNAL( changed(const QString &, const QString &) ),
+ SLOT( slotBookmarksChanged(const QString &) ) );
+
+ KBookmarkGroup toolbar = getToolbar();
+ fillBookmarkBar( toolbar );
+}
+
+QString KBookmarkBar::parentAddress()
+{
+ return dptr()->m_filteredMgr ? QString::null : m_pManager->toolbar().address();
+}
+
+#define CURRENT_TOOLBAR() ( \
+ dptr()->m_filteredMgr ? dptr()->m_filteredMgr->root() \
+ : m_pManager->toolbar() )
+
+#define CURRENT_MANAGER() ( \
+ dptr()->m_filteredMgr ? dptr()->m_filteredMgr \
+ : m_pManager )
+
+KBookmarkGroup KBookmarkBar::getToolbar()
+{
+ if ( KBookmarkSettings::self()->m_filteredtoolbar )
+ {
+ if ( !dptr()->m_filteredMgr ) {
+ dptr()->m_filteredMgr = KBookmarkManager::createTempManager();
+ } else {
+ KBookmarkGroup bkRoot = dptr()->m_filteredMgr->root();
+ QValueList<KBookmark> bks;
+ for (KBookmark bm = bkRoot.first(); !bm.isNull(); bm = bkRoot.next(bm))
+ bks << bm;
+ for ( QValueListConstIterator<KBookmark> it = bks.begin(); it != bks.end(); ++it )
+ bkRoot.deleteBookmark( (*it) );
+ }
+ ToolbarFilter filter;
+ KBookmarkDomBuilder builder( dptr()->m_filteredMgr->root(),
+ dptr()->m_filteredMgr );
+ builder.connectImporter( &filter );
+ filter.filter( m_pManager->root() );
+ }
+
+ return CURRENT_TOOLBAR();
+}
+
+KBookmarkBar::~KBookmarkBar()
+{
+ //clear();
+ KBookmarkBarPrivate::delete_d(this);
+}
+
+void KBookmarkBar::clear()
+{
+ QPtrListIterator<KAction> it( dptr()->m_actions );
+ m_toolBar->clear();
+ for (; it.current(); ++it ) {
+ (*it)->unplugAll();
+ }
+ dptr()->m_actions.clear();
+ m_lstSubMenus.clear();
+}
+
+void KBookmarkBar::slotBookmarksChanged( const QString & group )
+{
+ KBookmarkGroup tb = getToolbar(); // heavy for non cached toolbar version
+ kdDebug(7043) << "slotBookmarksChanged( " << group << " )" << endl;
+
+ if ( tb.isNull() )
+ return;
+
+ if ( KBookmark::commonParent(group, tb.address()) == group // Is group a parent of tb.address?
+ || KBookmarkSettings::self()->m_filteredtoolbar )
+ {
+ clear();
+ fillBookmarkBar( tb );
+ }
+ else
+ {
+ // Iterate recursively into child menus
+ QPtrListIterator<KBookmarkMenu> it( m_lstSubMenus );
+ for (; it.current(); ++it )
+ {
+ it.current()->slotBookmarksChanged( group );
+ }
+ }
+}
+
+void KBookmarkBar::fillBookmarkBar(KBookmarkGroup & parent)
+{
+ if (parent.isNull())
+ return;
+
+ for (KBookmark bm = parent.first(); !bm.isNull(); bm = parent.next(bm))
+ {
+ QString text = bm.text();
+ text.replace( '&', "&&" );
+ if (!bm.isGroup())
+ {
+ if ( bm.isSeparator() )
+ m_toolBar->insertLineSeparator();
+ else
+ {
+ KAction *action = new KBookmarkAction( text, bm.icon(), 0, m_actionCollection, 0 );
+ connect(action, SIGNAL( activated ( KAction::ActivationReason, Qt::ButtonState )),
+ this, SLOT( slotBookmarkSelected( KAction::ActivationReason, Qt::ButtonState ) ));
+
+ action->setProperty( "url", bm.url().url() );
+ action->setProperty( "address", bm.address() );
+
+ action->setToolTip( bm.url().pathOrURL() );
+
+ action->plug(m_toolBar);
+
+ dptr()->m_actions.append( action );
+ }
+ }
+ else
+ {
+ KActionMenu *action = new KBookmarkActionMenu( text, bm.icon(),
+ m_actionCollection,
+ "bookmarkbar-actionmenu");
+ action->setProperty( "address", bm.address() );
+ action->setProperty( "readOnly", dptr()->m_readOnly );
+ action->setDelayed( false );
+
+ // this flag doesn't have any UI yet
+ KGlobal::config()->setGroup( "Settings" );
+ bool addEntriesBookmarkBar = KGlobal::config()->readBoolEntry("AddEntriesBookmarkBar",true);
+
+ KBookmarkMenu *menu = new KBookmarkMenu(CURRENT_MANAGER(), m_pOwner, action->popupMenu(),
+ m_actionCollection, false, addEntriesBookmarkBar,
+ bm.address());
+ connect(menu, SIGNAL( aboutToShowContextMenu(const KBookmark &, QPopupMenu * ) ),
+ this, SIGNAL( aboutToShowContextMenu(const KBookmark &, QPopupMenu * ) ));
+ connect(menu, SIGNAL( openBookmark( const QString &, Qt::ButtonState) ),
+ this, SIGNAL( openBookmark( const QString &, Qt::ButtonState) ));
+ menu->fillBookmarkMenu();
+ action->plug(m_toolBar);
+ m_lstSubMenus.append( menu );
+
+ dptr()->m_actions.append( action );
+ }
+ }
+}
+
+void KBookmarkBar::setReadOnly(bool readOnly)
+{
+ dptr()->m_readOnly = readOnly;
+}
+
+bool KBookmarkBar::isReadOnly() const
+{
+ return dptr()->m_readOnly;
+}
+
+void KBookmarkBar::slotBookmarkSelected( KAction::ActivationReason /*reason*/, Qt::ButtonState state )
+{
+ if (!m_pOwner) return; // this view doesn't handle bookmarks...
+
+ const KAction* action = dynamic_cast<const KAction *>(sender());
+ if(action)
+ {
+ const QString & url = sender()->property("url").toString();
+ m_pOwner->openBookmarkURL(url);
+ emit openBookmark( url, state );
+ }
+}
+
+void KBookmarkBar::slotBookmarkSelected()
+{
+ slotBookmarkSelected(KAction::ToolBarActivation, Qt::NoButton);
+}
+
+static const int const_sepId = -9999; // FIXME this is ugly,
+ // surely there is another
+ // way of doing this...
+
+static void removeTempSep(KBookmarkBarPrivate* p)
+{
+ if (p->m_sepToolBar) {
+ p->m_sepToolBar->removeItem(const_sepId);
+ p->m_sepToolBar = 0; // needed?
+ }
+}
+
+static KAction* findPluggedAction(QPtrList<KAction> actions, KToolBar *tb, int id)
+{
+ QPtrListIterator<KAction> it( actions );
+ for (; (*it); ++it )
+ if ((*it)->isPlugged(tb, id))
+ return (*it);
+ return 0;
+}
+
+/**
+ * Handle a QDragMoveEvent event on a toolbar drop
+ * @return the address of the bookmark to be dropped after/before
+ * else a QString::null if event should be ignored
+ * @param pos the current QDragMoveEvent position
+ * @param the toolbar
+ * @param actions the list of actions plugged into the bar
+ * @param atFirst bool reference, when true the position before the
+ * returned action was dropped on
+ */
+static QString handleToolbarDragMoveEvent(
+ KBookmarkBarPrivate *p, KToolBar *tb, QPoint pos, QPtrList<KAction> actions,
+ bool &atFirst, KBookmarkManager *mgr
+) {
+ Q_UNUSED( mgr );
+ Q_ASSERT( actions.isEmpty() || (tb == dynamic_cast<KToolBar*>(actions.first()->container(0))) );
+ p->m_sepToolBar = tb;
+ p->m_sepToolBar->removeItemDelayed(const_sepId);
+
+ int index = 0;
+ KToolBarButton* b;
+
+ b = dynamic_cast<KToolBarButton*>(tb->childAt(pos));
+ KAction *a = 0;
+ QString address;
+ atFirst = false;
+
+ if (b)
+ {
+ index = tb->itemIndex(b->id());
+ QRect r = b->geometry();
+ if (pos.x() < ((r.left() + r.right())/2))
+ {
+ // if in first half of button then
+ // we jump to previous index
+ if ( index == 0 )
+ atFirst = true;
+ else {
+ index--;
+ b = tb->getButton(tb->idAt(index));
+ }
+ }
+ }
+ else if (actions.isEmpty())
+ {
+ atFirst = true;
+ index = 0;
+ // we skip the action related stuff
+ // and do what it should have...
+ // FIXME - here we want to get the
+ // parent address of the bookmark
+ // bar itself and return that + "/0"
+ p->m_sepIndex = 0;
+ goto skipact;
+ }
+ else // (!b)
+ {
+ index = actions.count() - 1;
+ b = tb->getButton(tb->idAt(index));
+ // if !b and not past last button, we didn't find button
+ if (pos.x() <= b->geometry().left())
+ goto skipact; // TODO - rename
+ }
+
+ if ( !b )
+ return QString::null; // TODO Make it works for that case
+
+ a = findPluggedAction(actions, tb, b->id());
+ Q_ASSERT(a);
+ address = a->property("address").toString();
+ p->m_sepIndex = index + (atFirst ? 0 : 1);
+
+#if 0
+ { // ugly workaround to fix the goto scoping problems...
+ KBookmark bk = mgr->findByAddress( address );
+ if (bk.isGroup()) // TODO - fix this ****!!!, manhatten distance should be used!!!
+ {
+ kdDebug() << "kbookmarkbar:: popping up " << bk.text() << endl;
+ KBookmarkActionMenu *menu = dynamic_cast<KBookmarkActionMenu*>(a);
+ Q_ASSERT(menu);
+ menu->popup(tb->mapToGlobal(b->geometry().center()));
+ }
+ }
+#endif
+
+skipact:
+ tb->insertLineSeparator(p->m_sepIndex, const_sepId);
+ return address;
+}
+
+// TODO - document!!!!
+static KAction* handleToolbarMouseButton(QPoint pos, QPtrList<KAction> actions,
+ KBookmarkManager * /*mgr*/, QPoint & pt)
+{
+ KAction *act = actions.first();
+ if (!act) {
+ return 0;
+ }
+
+ KToolBar *tb = dynamic_cast<KToolBar*>(act->container(0));
+ Q_ASSERT(tb);
+
+ KToolBarButton *b;
+ b = dynamic_cast<KToolBarButton*>(tb->childAt(pos));
+ if (!b)
+ return 0;
+
+ KAction *a = 0;
+ a = findPluggedAction(actions, tb, b->id());
+ Q_ASSERT(a);
+ pt = tb->mapToGlobal(pos);
+
+ return a;
+}
+
+// TODO *** drop improvements ***
+// open submenus on drop interactions
+
+// TODO *** generic rmb improvements ***
+// don't *ever* show the rmb on press, always relase, possible???
+
+class KBookmarkBarRMBAssoc : public dPtrTemplate<KBookmarkBar, RMB> { };
+template<> QPtrDict<RMB>* dPtrTemplate<KBookmarkBar, RMB>::d_ptr = 0;
+
+static RMB* rmbSelf(KBookmarkBar *m) { return KBookmarkBarRMBAssoc::d(m); }
+
+void RMB::begin_rmb_action(KBookmarkBar *self)
+{
+ RMB *s = rmbSelf(self);
+ s->recv = self;
+ s->m_parentAddress = self->parentAddress();
+ s->s_highlightedAddress = self->dptr()->m_highlightedAddress; // rename in RMB
+ s->m_pManager = self->m_pManager;
+ s->m_pOwner = self->m_pOwner;
+ s->m_parentMenu = 0;
+}
+
+void KBookmarkBar::slotRMBActionEditAt( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionEditAt( val ); }
+
+void KBookmarkBar::slotRMBActionProperties( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionProperties( val ); }
+
+void KBookmarkBar::slotRMBActionInsert( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionInsert( val ); }
+
+void KBookmarkBar::slotRMBActionRemove( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionRemove( val ); }
+
+void KBookmarkBar::slotRMBActionCopyLocation( int val )
+{ RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionCopyLocation( val ); }
+
+bool KBookmarkBar::eventFilter( QObject *o, QEvent *e )
+{
+ if (dptr()->m_readOnly || dptr()->m_filteredMgr) // note, we assume m_pManager in various places,
+ // this shouldn't really be the case
+ return false; // todo: make this limit the actions
+
+ if ( (e->type() == QEvent::MouseButtonRelease) || (e->type() == QEvent::MouseButtonPress) ) // FIXME, which one?
+ {
+ QMouseEvent *mev = (QMouseEvent*)e;
+
+ QPoint pt;
+ KAction *_a;
+
+ // FIXME, see how this holds up on an empty toolbar
+ _a = handleToolbarMouseButton( mev->pos(), dptr()->m_actions, m_pManager, pt );
+ if (_a && mev->button() == Qt::RightButton)
+ {
+ dptr()->m_highlightedAddress = _a->property("address").toString();
+ KBookmark bookmark = m_pManager->findByAddress( dptr()->m_highlightedAddress );
+ RMB::begin_rmb_action(this);
+ KPopupMenu *pm = new KPopupMenu;
+ rmbSelf(this)->fillContextMenu( pm, dptr()->m_highlightedAddress, 0 );
+ emit aboutToShowContextMenu( rmbSelf(this)->atAddress( dptr()->m_highlightedAddress ), pm );
+ rmbSelf(this)->fillContextMenu2( pm, dptr()->m_highlightedAddress, 0 );
+ pm->popup( pt );
+ mev->accept();
+ }
+
+ return !!_a; // ignore the event if we didn't find the button
+ }
+ else if ( e->type() == QEvent::DragLeave )
+ {
+ removeTempSep(dptr());
+ dptr()->m_dropAddress = QString::null;
+ }
+ else if ( e->type() == QEvent::Drop )
+ {
+ removeTempSep(dptr());
+ QDropEvent *dev = (QDropEvent*)e;
+ if ( !KBookmarkDrag::canDecode( dev ) )
+ return false;
+ QValueList<KBookmark> list = KBookmarkDrag::decode( dev );
+ if (list.count() > 1)
+ kdWarning(7043) << "Sorry, currently you can only drop one address "
+ "onto the bookmark bar!" << endl;
+ KBookmark toInsert = list.first();
+ KBookmark bookmark = m_pManager->findByAddress( dptr()->m_dropAddress );
+ Q_ASSERT(!bookmark.isNull());
+ kdDebug(7043) << "inserting "
+ << QString(dptr()->m_atFirst ? "before" : "after")
+ << " dptr()->m_dropAddress == " << dptr()->m_dropAddress << endl;
+ KBookmarkGroup parentBookmark = bookmark.parentGroup();
+ Q_ASSERT(!parentBookmark.isNull());
+ KBookmark newBookmark = parentBookmark.addBookmark(
+ m_pManager, toInsert.fullText(),
+ toInsert.url() );
+ parentBookmark.moveItem( newBookmark, dptr()->m_atFirst ? KBookmark() : bookmark );
+ m_pManager->emitChanged( parentBookmark );
+ return true;
+ }
+ else if ( e->type() == QEvent::DragMove )
+ {
+ QDragMoveEvent *dme = (QDragMoveEvent*)e;
+ if (!KBookmarkDrag::canDecode( dme ))
+ return false;
+ bool _atFirst;
+ QString dropAddress;
+ KToolBar *tb = (KToolBar*)o;
+ dropAddress = handleToolbarDragMoveEvent(dptr(), tb, dme->pos(), dptr()->m_actions, _atFirst, m_pManager);
+ if (!dropAddress.isNull())
+ {
+ dptr()->m_dropAddress = dropAddress;
+ dptr()->m_atFirst = _atFirst;
+ dme->accept();
+ }
+ }
+ return false;
+}
+
+static bool showInToolbar( const KBookmark &bk ) {
+ return (bk.internalElement().attributes().namedItem("showintoolbar").toAttr().value() == "yes");
+}
+
+void ToolbarFilter::visit( const KBookmark &bk ) {
+ //kdDebug() << "visit(" << bk.text() << ")" << endl;
+ if ( m_visible || showInToolbar(bk) )
+ KXBELBookmarkImporterImpl::visit(bk);
+}
+
+void ToolbarFilter::visitEnter( const KBookmarkGroup &grp ) {
+ //kdDebug() << "visitEnter(" << grp.text() << ")" << endl;
+ if ( !m_visible && showInToolbar(grp) )
+ {
+ m_visibleStart = grp;
+ m_visible = true;
+ }
+ if ( m_visible )
+ KXBELBookmarkImporterImpl::visitEnter(grp);
+}
+
+void ToolbarFilter::visitLeave( const KBookmarkGroup &grp ) {
+ //kdDebug() << "visitLeave()" << endl;
+ if ( m_visible )
+ KXBELBookmarkImporterImpl::visitLeave(grp);
+ if ( m_visible && grp.address() == m_visibleStart.address() )
+ m_visible = false;
+}
+
+#include "kbookmarkbar.moc"