# kio Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kbookmarkbar.cc

    00001 //  -*- c-basic-offset:4; indent-tabs-mode:nil -*-
    00002 // vim: set ts=4 sts=4 sw=4 et:
    00003 /* This file is part of the KDE project
    00004    Copyright (C) 1999 Kurt Granroth <granroth@kde.org>
    00005    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
    00006
    00007    This library is free software; you can redistribute it and/or
    00008    modify it under the terms of the GNU Library General Public
    00009    License as published by the Free Software Foundation; either
    00010    version 2 of the License, or (at your option) any later version.
    00011
    00012    This library is distributed in the hope that it will be useful,
    00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015    Library General Public License for more details.
    00016
    00017    You should have received a copy of the GNU Library General Public License
    00018    along with this library; see the file COPYING.LIB.  If not, write to
    00019    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00020    Boston, MA 02111-1307, USA.
    00021 */
    00022 #include <qregexp.h>
    00023 #include <qfile.h>
    00024
    00025 #include <kbookmarkbar.h>
    00026 #include <kbookmarkdrag.h>
    00027
    00028 #include <kbookmarkmenu.h>
    00029 #include <kdebug.h>
    00030
    00031 #include <ktoolbar.h>
    00032 #include <ktoolbarbutton.h>
    00033
    00034 #include <kconfig.h>
    00035 #include <kpopupmenu.h>
    00036
    00037 #include "kbookmarkdrag.h"
    00038 #include "kbookmarkmenu_p.h"
    00039 #include "kbookmarkdombuilder.h"
    00040
    00041 #include "dptrtemplate.h"
    00042
    00043 #include <qapplication.h>
    00044
    00045 class KBookmarkBarPrivate : public dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate>
    00046 {
    00047 public:
    00048     QPtrList<KAction> m_actions;
    00049     bool m_readOnly;
    00050     KBookmarkManager* m_filteredMgr;
    00051     KToolBar* m_sepToolBar;
    00052     int m_sepIndex;
    00053     bool m_atFirst;
    00054     QString m_dropAddress;
    00055     QString m_highlightedAddress;
    00056 public:
    00057     KBookmarkBarPrivate() {
    00058         m_readOnly = false;
    00059         m_filteredMgr = 0;
    00060         m_sepToolBar = 0;
    00061         m_sepIndex = -1;
    00062         m_atFirst = false;
    00063     }
    00064 };
    00065 template<> QPtrDict<KBookmarkBarPrivate>* dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate>::d_ptr = 0;
    00066
    00067 KBookmarkBarPrivate* KBookmarkBar::dptr() const
    00068 {
    00069     return KBookmarkBarPrivate::d( this );
    00070 }
    00071
    00072 // usage of KXBELBookmarkImporterImpl is just plain evil, but it reduces code dup. so...
    00073 class ToolbarFilter : public KXBELBookmarkImporterImpl
    00074 {
    00075 public:
    00076     ToolbarFilter() : m_visible(false) { ; }
    00077     void filter( const KBookmarkGroup &grp ) { traverse(grp); }
    00078 private:
    00079     virtual void visit( const KBookmark & );
    00080     virtual void visitEnter( const KBookmarkGroup & );
    00081     virtual void visitLeave( const KBookmarkGroup & );
    00082 private:
    00083     bool m_visible;
    00084     KBookmarkGroup m_visibleStart;
    00085 };
    00086
    00087 KBookmarkBar::KBookmarkBar( KBookmarkManager* mgr,
    00088                             KBookmarkOwner *_owner, KToolBar *_toolBar,
    00089                             KActionCollection *coll,
    00090                             QObject *parent, const char *name )
    00091     : QObject( parent, name ), m_pOwner(_owner), m_toolBar(_toolBar),
    00092       m_actionCollection( coll ), m_pManager(mgr)
    00093 {
    00094     m_lstSubMenus.setAutoDelete( true );
    00095
    00096     m_toolBar->setAcceptDrops( true );
    00097     m_toolBar->installEventFilter( this ); // for drops
    00098
    00099     dptr()->m_actions.setAutoDelete( true );
    00100
    00101     connect( mgr, SIGNAL( changed(const QString &, const QString &) ),
    00102              SLOT( slotBookmarksChanged(const QString &) ) );
    00103
    00104     KBookmarkGroup toolbar = getToolbar();
    00105     fillBookmarkBar( toolbar );
    00106 }
    00107
    00108 QString KBookmarkBar::parentAddress()
    00109 {
    00110     return dptr()->m_filteredMgr ? QString::null : m_pManager->toolbar().address();
    00111 }
    00112
    00113 #define CURRENT_TOOLBAR() ( \
    00114     dptr()->m_filteredMgr ? dptr()->m_filteredMgr->root()  \
    00115                           : m_pManager->toolbar() )
    00116
    00117 #define CURRENT_MANAGER() ( \
    00118     dptr()->m_filteredMgr ? dptr()->m_filteredMgr  \
    00119                           : m_pManager )
    00120
    00121 KBookmarkGroup KBookmarkBar::getToolbar()
    00122 {
    00123     if ( KBookmarkSettings::self()->m_filteredtoolbar )
    00124     {
    00125         if ( !dptr()->m_filteredMgr ) {
    00126             dptr()->m_filteredMgr = KBookmarkManager::createTempManager();
    00127         } else {
    00128             KBookmarkGroup bkRoot = dptr()->m_filteredMgr->root();
    00129             QValueList<KBookmark> bks;
    00130             for (KBookmark bm = bkRoot.first(); !bm.isNull(); bm = bkRoot.next(bm))
    00131                 bks << bm;
    00132             for ( QValueListConstIterator<KBookmark> it = bks.begin(); it != bks.end(); ++it )
    00133                 bkRoot.deleteBookmark( (*it) );
    00134         }
    00135         ToolbarFilter filter;
    00136         KBookmarkDomBuilder builder( dptr()->m_filteredMgr->root(),
    00137                                      dptr()->m_filteredMgr );
    00138         builder.connectImporter( &filter );
    00139         filter.filter( m_pManager->root() );
    00140     }
    00141
    00142     return CURRENT_TOOLBAR();
    00143 }
    00144
    00145 KBookmarkBar::~KBookmarkBar()
    00146 {
    00147     //clear();
    00148     KBookmarkBarPrivate::delete_d(this);
    00149 }
    00150
    00151 void KBookmarkBar::clear()
    00152 {
    00153     QPtrListIterator<KAction> it( dptr()->m_actions );
    00154     m_toolBar->clear();
    00155     for (; it.current(); ++it ) {
    00156         (*it)->unplugAll();
    00157     }
    00158     dptr()->m_actions.clear();
    00159     m_lstSubMenus.clear();
    00160 }
    00161
    00162 void KBookmarkBar::slotBookmarksChanged( const QString & group )
    00163 {
    00164     KBookmarkGroup tb = getToolbar(); // heavy for non cached toolbar version
    00165     kdDebug(7043) << "slotBookmarksChanged( " << group << " )" << endl;
    00166
    00167     if ( tb.isNull() )
    00168         return;
    00169
    00170     if ( tb.address() == group || KBookmarkSettings::self()->m_filteredtoolbar )
    00171     {
    00172         clear();
    00173         fillBookmarkBar( tb );
    00174     }
    00175     else
    00176     {
    00177         // Iterate recursively into child menus
    00178         QPtrListIterator<KBookmarkMenu> it( m_lstSubMenus );
    00179         for (; it.current(); ++it )
    00180         {
    00181             it.current()->slotBookmarksChanged( group );
    00182         }
    00183     }
    00184 }
    00185
    00186 void KBookmarkBar::fillBookmarkBar(KBookmarkGroup & parent)
    00187 {
    00188     if (parent.isNull())
    00189         return;
    00190
    00191     for (KBookmark bm = parent.first(); !bm.isNull(); bm = parent.next(bm))
    00192     {
    00193         QString text = bm.text();
    00194         text.replace( '&', "&&" );
    00195         if (!bm.isGroup())
    00196         {
    00197             if ( bm.isSeparator() )
    00198                 m_toolBar->insertLineSeparator();
    00199             else
    00200             {
    00201                 KAction *action = new KBookmarkAction( text, bm.icon(), 0, m_actionCollection, 0 );
    00202                 connect(action, SIGNAL( activated ( KAction::ActivationReason, Qt::ButtonState )),
    00203                         this, SLOT( slotBookmarkSelected( KAction::ActivationReason, Qt::ButtonState ) ));
    00204
    00205                 action->setProperty( "url", bm.url().url() );
    00206                 action->setProperty( "address", bm.address() );
    00207
    00208                 action->setToolTip( bm.url().prettyURL() );
    00209
    00210                 action->plug(m_toolBar);
    00211
    00212                 dptr()->m_actions.append( action );
    00213             }
    00214         }
    00215         else
    00216         {
    00217             KActionMenu *action = new KBookmarkActionMenu( text, bm.icon(),
    00218                                                            m_actionCollection,
    00219                                                            "bookmarkbar-actionmenu");
    00220             action->setProperty( "address", bm.address() );
    00221             action->setProperty( "readOnly", dptr()->m_readOnly );
    00222             action->setDelayed( false );
    00223
    00224             // this flag doesn't have any UI yet
    00225             KGlobal::config()->setGroup( "Settings" );
    00226             bool addEntriesBookmarkBar = KGlobal::config()->readBoolEntry("AddEntriesBookmarkBar",true);
    00227
    00228             KBookmarkMenu *menu = new KBookmarkMenu(CURRENT_MANAGER(), m_pOwner, action->popupMenu(),
    00229                                                     m_actionCollection, false, addEntriesBookmarkBar,
    00230                                                     bm.address());
    00231             connect(menu, SIGNAL( aboutToShowContextMenu(const KBookmark &, QPopupMenu * ) ),
    00232                     this, SIGNAL( aboutToShowContextMenu(const KBookmark &, QPopupMenu * ) ));
    00233             connect(menu, SIGNAL( openBookmark( const QString &, Qt::ButtonState) ),
    00234                     this, SIGNAL( openBookmark( const QString &, Qt::ButtonState) ));
    00235             menu->fillBookmarkMenu();
    00236             action->plug(m_toolBar);
    00237             m_lstSubMenus.append( menu );
    00238
    00239             dptr()->m_actions.append( action );
    00240         }
    00241     }
    00242 }
    00243
    00244 void KBookmarkBar::setReadOnly(bool readOnly)
    00245 {
    00246     dptr()->m_readOnly = readOnly;
    00247 }
    00248
    00249 bool KBookmarkBar::isReadOnly() const
    00250 {
    00251     return dptr()->m_readOnly;
    00252 }
    00253
    00254 void KBookmarkBar::slotBookmarkSelected( KAction::ActivationReason /*reason*/, Qt::ButtonState state )
    00255 {
    00256     if (!m_pOwner) return; // this view doesn't handle bookmarks...
    00257
    00258     const KAction* action = dynamic_cast<const KAction *>(sender());
    00259     if(action)
    00260     {
    00261         const QString & url = sender()->property("url").toString();
    00262         m_pOwner->openBookmarkURL(url);
    00263         emit openBookmark( url, state );
    00264     }
    00265 }
    00266
    00267 void KBookmarkBar::slotBookmarkSelected()
    00268 {
    00269     slotBookmarkSelected(KAction::ToolBarActivation, Qt::NoButton);
    00270 }
    00271
    00272 static const int const_sepId = -9999; // FIXME this is ugly,
    00273                                       // surely there is another
    00274                                       // way of doing this...
    00275
    00276 static void removeTempSep(KBookmarkBarPrivate* p)
    00277 {
    00278     if (p->m_sepToolBar) {
    00279         p->m_sepToolBar->removeItem(const_sepId);
    00280         p->m_sepToolBar = 0; // needed?
    00281     }
    00282 }
    00283
    00284 static KAction* findPluggedAction(QPtrList<KAction> actions, KToolBar *tb, int id)
    00285 {
    00286     QPtrListIterator<KAction> it( actions );
    00287     for (; (*it); ++it )
    00288         if ((*it)->isPlugged(tb, id))
    00289             return (*it);
    00290     return 0;
    00291 }
    00292
    00303 static QString handleToolbarDragMoveEvent(
    00304     KBookmarkBarPrivate *p, KToolBar *tb, QPoint pos, QPtrList<KAction> actions,
    00305     bool &atFirst, KBookmarkManager *mgr
    00306 ) {
    00307     Q_UNUSED( mgr );
    00308     Q_ASSERT( actions.isEmpty() || (tb == dynamic_cast<KToolBar*>(actions.first()->container(0))) );
    00309     p->m_sepToolBar = tb;
    00310     p->m_sepToolBar->removeItemDelayed(const_sepId);
    00311
    00312     int index;
    00313     KToolBarButton* b;
    00314
    00315     b = dynamic_cast<KToolBarButton*>(tb->childAt(pos));
    00316     KAction *a = 0;
    00317     QString address;
    00318     atFirst = false;
    00319
    00320     if (b)
    00321     {
    00322         index = tb->itemIndex(b->id());
    00323         QRect r = b->geometry();
    00324         if (pos.x() < ((r.left() + r.right())/2))
    00325         {
    00326             // if in first half of button then
    00327             // we jump to previous index
    00328             if ( index == 0 )
    00329                 atFirst = true;
    00330             else {
    00331                 index--;
    00332                 b = tb->getButton(tb->idAt(index));
    00333             }
    00334         }
    00335     }
    00336     else if (actions.isEmpty())
    00337     {
    00338         atFirst = true;
    00339         index = 0;
    00340         // we skip the action related stuff
    00341         // and do what it should have...
    00342         // FIXME - here we want to get the
    00343         // parent address of the bookmark
    00344         // bar itself and return that + "/0"
    00345         p->m_sepIndex = 0;
    00346         goto skipact;
    00347     }
    00348     else // (!b)
    00349     {
    00350         index = actions.count() - 1;
    00351         b = tb->getButton(tb->idAt(index));
    00352         // if !b and not past last button, we didn't find button
    00353         if (pos.x() <= b->geometry().left())
    00354             goto skipact; // TODO - rename
    00355     }
    00356
    00357     if ( !b )
    00358         return QString::null; // TODO Make it works for that case
    00359
    00360     a = findPluggedAction(actions, tb, b->id());
    00361     Q_ASSERT(a);
    00362     address = a->property("address").toString();
    00363     p->m_sepIndex = index + (atFirst ? 0 : 1);
    00364
    00365 #if 0
    00366     { // ugly workaround to fix the goto scoping problems...
    00367         KBookmark bk = mgr->findByAddress( address );
    00368         if (bk.isGroup()) // TODO - fix this ****!!!, manhatten distance should be used!!!
    00369         {
    00370             kdDebug() << "kbookmarkbar:: popping up " << bk.text() << endl;
    00371             KBookmarkActionMenu *menu = dynamic_cast<KBookmarkActionMenu*>(a);
    00372             Q_ASSERT(menu);
    00373             menu->popup(tb->mapToGlobal(b->geometry().center()));
    00374         }
    00375     }
    00376 #endif
    00377
    00378 skipact:
    00379     tb->insertLineSeparator(p->m_sepIndex, const_sepId);
    00380     return address;
    00381 }
    00382
    00383 // TODO - document!!!!
    00384 static KAction* handleToolbarMouseButton(QPoint pos, QPtrList<KAction> actions,
    00385                                          KBookmarkManager * /*mgr*/, QPoint & pt)
    00386 {
    00387     KAction *act = actions.first();
    00388     if (!act) {
    00389         return 0;
    00390     }
    00391
    00392     KToolBar *tb = dynamic_cast<KToolBar*>(act->container(0));
    00393     Q_ASSERT(tb);
    00394
    00395     KToolBarButton *b;
    00396     b = dynamic_cast<KToolBarButton*>(tb->childAt(pos));
    00397     if (!b)
    00398         return 0;
    00399
    00400     KAction *a = 0;
    00401     a = findPluggedAction(actions, tb, b->id());
    00402     Q_ASSERT(a);
    00403     pt = tb->mapToGlobal(pos);
    00404
    00405     return a;
    00406 }
    00407
    00408 // TODO    *** drop improvements ***
    00409 // open submenus on drop interactions
    00410
    00411 // TODO    *** generic rmb improvements ***
    00412 // don't *ever* show the rmb on press, always relase, possible???
    00413
    00414 class KBookmarkBarRMBAssoc : public dPtrTemplate<KBookmarkBar, RMB> { };
    00415 template<> QPtrDict<RMB>* dPtrTemplate<KBookmarkBar, RMB>::d_ptr = 0;
    00416
    00417 static RMB* rmbSelf(KBookmarkBar *m) { return KBookmarkBarRMBAssoc::d(m); }
    00418
    00419 void RMB::begin_rmb_action(KBookmarkBar *self)
    00420 {
    00421     RMB *s = rmbSelf(self);
    00422     s->recv = self;
    00423     s->m_parentAddress = self->parentAddress();
    00424     s->s_highlightedAddress = self->dptr()->m_highlightedAddress; // rename in RMB
    00425     s->m_pManager = self->m_pManager;
    00426     s->m_pOwner = self->m_pOwner;
    00427     s->m_parentMenu = 0;
    00428 }
    00429
    00430 void KBookmarkBar::slotRMBActionEditAt( int val )
    00431 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionEditAt( val ); }
    00432
    00433 void KBookmarkBar::slotRMBActionProperties( int val )
    00434 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionProperties( val ); }
    00435
    00436 void KBookmarkBar::slotRMBActionInsert( int val )
    00437 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionInsert( val ); }
    00438
    00439 void KBookmarkBar::slotRMBActionRemove( int val )
    00440 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionRemove( val ); }
    00441
    00442 void KBookmarkBar::slotRMBActionCopyLocation( int val )
    00443 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionCopyLocation( val ); }
    00444
    00445 bool KBookmarkBar::eventFilter( QObject *o, QEvent *e )
    00446 {
    00447     if (dptr()->m_readOnly || dptr()->m_filteredMgr) // note, we assume m_pManager in various places,
    00448                                                      // this shouldn't really be the case
    00449         return false; // todo: make this limit the actions
    00450
    00451     if ( (e->type() == QEvent::MouseButtonRelease) || (e->type() == QEvent::MouseButtonPress) ) // FIXME, which one?
    00452     {
    00453         QMouseEvent *mev = (QMouseEvent*)e;
    00454
    00455         QPoint pt;
    00456         KAction *_a;
    00457
    00458         // FIXME, see how this holds up on an empty toolbar
    00459         _a = handleToolbarMouseButton( mev->pos(), dptr()->m_actions, m_pManager, pt );
    00460         if (_a && mev->button() == Qt::RightButton)
    00461         {
    00462             dptr()->m_highlightedAddress = _a->property("address").toString();
    00463             KBookmark bookmark = m_pManager->findByAddress( dptr()->m_highlightedAddress );
    00464             RMB::begin_rmb_action(this);
    00465             KPopupMenu *pm = new KPopupMenu;
    00466             rmbSelf(this)->fillContextMenu( pm, dptr()->m_highlightedAddress, 0 );
    00467             emit aboutToShowContextMenu( rmbSelf(this)->atAddress( dptr()->m_highlightedAddress ), pm );
    00468             rmbSelf(this)->fillContextMenu2( pm, dptr()->m_highlightedAddress, 0 );
    00469             pm->popup( pt );
    00470             mev->accept();
    00471         }
    00472
    00473         return !!_a; // ignore the event if we didn't find the button
    00474     }
    00475     else if ( e->type() == QEvent::DragLeave )
    00476     {
    00477         removeTempSep(dptr());
    00478         dptr()->m_dropAddress = QString::null;
    00479     }
    00480     else if ( e->type() == QEvent::Drop )
    00481     {
    00482         removeTempSep(dptr());
    00483         QDropEvent *dev = (QDropEvent*)e;
    00484         if ( !KBookmarkDrag::canDecode( dev ) )
    00485             return false;
    00486         QValueList<KBookmark> list = KBookmarkDrag::decode( dev );
    00487         if (list.count() > 1)
    00488             kdWarning(7043) << "Sorry, currently you can only drop one address "
    00489                 "onto the bookmark bar!" << endl;
    00490         KBookmark toInsert = list.first();
    00491         KBookmark bookmark = m_pManager->findByAddress( dptr()->m_dropAddress );
    00492         Q_ASSERT(!bookmark.isNull());
    00493         kdDebug(7043) << "inserting "
    00494             << QString(dptr()->m_atFirst ? "before" : "after")
    00495             << " dptr()->m_dropAddress == " << dptr()->m_dropAddress << endl;
    00496         KBookmarkGroup parentBookmark = bookmark.parentGroup();
    00497         Q_ASSERT(!parentBookmark.isNull());
    00498         KBookmark newBookmark = parentBookmark.addBookmark(
    00499                 m_pManager, toInsert.fullText(),
    00500                 toInsert.url() );
    00501         parentBookmark.moveItem( newBookmark, dptr()->m_atFirst ? KBookmark() : bookmark );
    00502         m_pManager->emitChanged( parentBookmark );
    00503         return true;
    00504     }
    00505     else if ( e->type() == QEvent::DragMove )
    00506     {
    00507         QDragMoveEvent *dme = (QDragMoveEvent*)e;
    00508         if (!KBookmarkDrag::canDecode( dme ))
    00509             return false;
    00510         bool _atFirst;
    00511         QString dropAddress;
    00512         KToolBar *tb = (KToolBar*)o;
    00513         dropAddress = handleToolbarDragMoveEvent(dptr(), tb, dme->pos(), dptr()->m_actions, _atFirst, m_pManager);
    00514         if (!dropAddress.isNull())
    00515         {
    00516             dptr()->m_dropAddress = dropAddress;
    00517             dptr()->m_atFirst = _atFirst;
    00518             dme->accept();
    00519         }
    00520     }
    00521     return false;
    00522 }
    00523
    00524 static bool showInToolbar( const KBookmark &bk ) {
    00525     return (bk.internalElement().attributes().namedItem("showintoolbar").toAttr().value() == "yes");
    00526 }
    00527
    00528 void ToolbarFilter::visit( const KBookmark &bk ) {
    00529     //kdDebug() << "visit(" << bk.text() << ")" << endl;
    00530     if ( m_visible || showInToolbar(bk) )
    00531         KXBELBookmarkImporterImpl::visit(bk);
    00532 }
    00533
    00534 void ToolbarFilter::visitEnter( const KBookmarkGroup &grp ) {
    00535     //kdDebug() << "visitEnter(" << grp.text() << ")" << endl;
    00536     if ( !m_visible && showInToolbar(grp) )
    00537     {
    00538         m_visibleStart = grp;
    00539         m_visible = true;
    00540     }
    00541     if ( m_visible )
    00542         KXBELBookmarkImporterImpl::visitEnter(grp);
    00543 }
    00544
    00545 void ToolbarFilter::visitLeave( const KBookmarkGroup &grp ) {
    00546     //kdDebug() << "visitLeave()" << endl;
    00547     if ( m_visible )
    00548         KXBELBookmarkImporterImpl::visitLeave(grp);
    00549     if ( m_visible && grp.address() == m_visibleStart.address() )
    00550         m_visible = false;
    00551 }
    00552
    00553 #include "kbookmarkbar.moc"

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:55 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003