kio Library API Documentation

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 <kaction.h>
00029 #include <kbookmarkmenu.h>
00030 #include <kdebug.h>
00031 
00032 #include <ktoolbar.h>
00033 #include <ktoolbarbutton.h>
00034 
00035 #include <kconfig.h>
00036 #include <kpopupmenu.h>
00037 
00038 #include "kbookmarkdrag.h"
00039 #include "kbookmarkmenu_p.h"
00040 #include "kbookmarkdombuilder.h"
00041 
00042 #include "dptrtemplate.h"
00043 
00044 #include <qapplication.h>
00045 
00046 class KBookmarkBarPrivate : public dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate> 
00047 {
00048 public:
00049     QPtrList<KAction> m_actions;
00050     bool m_readOnly;
00051     KBookmarkManager* m_filteredMgr;
00052     KToolBar* m_sepToolBar;
00053     int m_sepIndex;
00054     bool m_atFirst;
00055     QString m_dropAddress;
00056     QString m_highlightedAddress;
00057 public:
00058     KBookmarkBarPrivate() {
00059         m_readOnly = false;
00060         m_filteredMgr = 0;
00061         m_sepToolBar = 0;
00062         m_sepIndex = -1;
00063         m_atFirst = false;
00064     }
00065 };
00066 template<> QPtrDict<KBookmarkBarPrivate>* dPtrTemplate<KBookmarkBar, KBookmarkBarPrivate>::d_ptr = 0;
00067 
00068 KBookmarkBarPrivate* KBookmarkBar::dptr() const 
00069 {
00070     return KBookmarkBarPrivate::d( this );
00071 }
00072 
00073 // usage of KXBELBookmarkImporterImpl is just plain evil, but it reduces code dup. so...
00074 class ToolbarFilter : public KXBELBookmarkImporterImpl 
00075 {
00076 public:
00077     ToolbarFilter() : m_visible(false) { ; }
00078     void filter( const KBookmarkGroup &grp ) { traverse(grp); }
00079 private:
00080     virtual void visit( const KBookmark & );
00081     virtual void visitEnter( const KBookmarkGroup & );
00082     virtual void visitLeave( const KBookmarkGroup & );
00083 private:
00084     bool m_visible;
00085     KBookmarkGroup m_visibleStart;
00086 };
00087 
00088 KBookmarkBar::KBookmarkBar( KBookmarkManager* mgr,
00089                             KBookmarkOwner *_owner, KToolBar *_toolBar,
00090                             KActionCollection *coll,
00091                             QObject *parent, const char *name )
00092     : QObject( parent, name ), m_pOwner(_owner), m_toolBar(_toolBar),
00093       m_actionCollection( coll ), m_pManager(mgr)
00094 {
00095     m_lstSubMenus.setAutoDelete( true );
00096 
00097     m_toolBar->setAcceptDrops( true );
00098     m_toolBar->installEventFilter( this ); // for drops
00099 
00100     dptr()->m_actions.setAutoDelete( true );
00101 
00102     connect( mgr, SIGNAL( changed(const QString &, const QString &) ),
00103              SLOT( slotBookmarksChanged(const QString &) ) );
00104 
00105     KBookmarkGroup toolbar = getToolbar();
00106     fillBookmarkBar( toolbar );
00107 }
00108 
00109 QString KBookmarkBar::parentAddress() 
00110 {
00111     return dptr()->m_filteredMgr ? QString::null : m_pManager->toolbar().address();
00112 }
00113 
00114 #define CURRENT_TOOLBAR() ( \
00115     dptr()->m_filteredMgr ? dptr()->m_filteredMgr->root()  \
00116                           : m_pManager->toolbar() )
00117 
00118 #define CURRENT_MANAGER() ( \
00119     dptr()->m_filteredMgr ? dptr()->m_filteredMgr  \
00120                           : m_pManager )
00121 
00122 KBookmarkGroup KBookmarkBar::getToolbar() 
00123 {
00124     if ( KBookmarkSettings::self()->m_filteredtoolbar )
00125     {
00126         if ( !dptr()->m_filteredMgr ) {
00127             dptr()->m_filteredMgr = KBookmarkManager::createTempManager();
00128         } else {
00129             KBookmarkGroup bkRoot = dptr()->m_filteredMgr->root();
00130             QValueList<KBookmark> bks;
00131             for (KBookmark bm = bkRoot.first(); !bm.isNull(); bm = bkRoot.next(bm)) 
00132                 bks << bm;
00133             for ( QValueListConstIterator<KBookmark> it = bks.begin(); it != bks.end(); ++it ) 
00134                 bkRoot.deleteBookmark( (*it) );
00135         }
00136         ToolbarFilter filter;
00137         KBookmarkDomBuilder builder( dptr()->m_filteredMgr->root(), 
00138                                      dptr()->m_filteredMgr );
00139         builder.connectImporter( &filter );
00140         filter.filter( m_pManager->root() );
00141     }
00142 
00143     return CURRENT_TOOLBAR();
00144 }
00145 
00146 KBookmarkBar::~KBookmarkBar()
00147 {
00148     clear();
00149     KBookmarkBarPrivate::delete_d(this);
00150 }
00151 
00152 void KBookmarkBar::clear()
00153 {
00154     QPtrListIterator<KAction> it( dptr()->m_actions );
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                 // create a normal URL item, with ID as a name
00202                 KAction *action = new KBookmarkAction( text, bm.icon(), 0,
00203                                                        this, SLOT(slotBookmarkSelected()),
00204                                                        m_actionCollection, 0 );
00205 
00206                 action->setProperty( "url", bm.url().url() );
00207                 action->setProperty( "address", bm.address() );
00208 
00209                 // ummm.... this doesn't appear do anything...
00210                 action->setToolTip( bm.url().prettyURL() );
00211 
00212                 action->plug(m_toolBar);
00213 
00214                 dptr()->m_actions.append( action );
00215             }
00216         }
00217         else
00218         {
00219             KActionMenu *action = new KBookmarkActionMenu( text, bm.icon(),
00220                                                            m_actionCollection,
00221                                                            "bookmarkbar-actionmenu");
00222             action->setProperty( "address", bm.address() );
00223             action->setProperty( "readOnly", dptr()->m_readOnly );
00224             action->setDelayed( false );
00225 
00226             // this flag doesn't have any UI yet
00227             KGlobal::config()->setGroup( "Settings" );
00228             bool addEntriesBookmarkBar = KGlobal::config()->readBoolEntry("AddEntriesBookmarkBar",true);
00229 
00230             KBookmarkMenu *menu = new KBookmarkMenu(CURRENT_MANAGER(), m_pOwner, action->popupMenu(),
00231                                                     m_actionCollection, false, addEntriesBookmarkBar,
00232                                                     bm.address());
00233             connect(menu, SIGNAL( aboutToShowContextMenu(const KBookmark &, QPopupMenu * ) ), 
00234                     this, SIGNAL( aboutToShowContextMenu(const KBookmark &, QPopupMenu * ) ));
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()
00255 {
00256     if (!m_pOwner) return; // this view doesn't handle bookmarks...
00257     m_pOwner->openBookmarkURL( sender()->property("url").toString() );
00258 }
00259 
00260 static const int const_sepId = -9999; // FIXME this is ugly, 
00261                                       // surely there is another 
00262                                       // way of doing this...
00263 
00264 static void removeTempSep(KBookmarkBarPrivate* p)
00265 {
00266     if (p->m_sepToolBar) {
00267         p->m_sepToolBar->removeItem(const_sepId);
00268         p->m_sepToolBar = 0; // needed?
00269     }
00270 }
00271 
00272 static KAction* findPluggedAction(QPtrList<KAction> actions, KToolBar *tb, int id)
00273 {
00274     QPtrListIterator<KAction> it( actions );
00275     for (; (*it); ++it )
00276         if ((*it)->isPlugged(tb, id))
00277             return (*it);
00278     return 0;
00279 }
00280 
00291 static QString handleToolbarDragMoveEvent(
00292     KBookmarkBarPrivate *p, KToolBar *tb, QPoint pos, QPtrList<KAction> actions, 
00293     bool &atFirst, KBookmarkManager *mgr
00294 ) {
00295     Q_UNUSED( mgr );
00296     Q_ASSERT( actions.isEmpty() || (tb == dynamic_cast<KToolBar*>(actions.first()->container(0))) );
00297     p->m_sepToolBar = tb;
00298     p->m_sepToolBar->removeItemDelayed(const_sepId);
00299 
00300     int index;
00301     KToolBarButton* b;
00302 
00303     b = dynamic_cast<KToolBarButton*>(tb->childAt(pos)); 
00304     KAction *a = 0;
00305     QString address;
00306     atFirst = false;
00307 
00308     if (b)
00309     {
00310         index = tb->itemIndex(b->id());
00311         QRect r = b->geometry();
00312         if (index == 0)
00313             atFirst = true;
00314         else if (pos.x() < ((r.left() + r.right())/2))
00315         {
00316             // if in first half of button then 
00317             // we jump to previous index
00318             index--;
00319             b = tb->getButton(tb->idAt(index));
00320         }
00321     }
00322     else if (actions.isEmpty())
00323     {
00324         atFirst = true;
00325         index = 0;
00326         // we skip the action related stuff
00327         // and do what it should have...
00328         // FIXME - here we want to get the 
00329         // parent address of the bookmark 
00330         // bar itself and return that + "/0"
00331         p->m_sepIndex = 0;
00332         goto skipact; 
00333     }
00334     else // (!b)
00335     {
00336         index = actions.count() - 1;
00337         b = tb->getButton(tb->idAt(index));
00338         // if !b and not past last button, we didn't find button
00339         if (pos.x() <= b->geometry().left())
00340             goto skipact; // TODO - rename
00341     }
00342 
00343     a = findPluggedAction(actions, tb, b->id());
00344     Q_ASSERT(a);
00345     address = a->property("address").toString();
00346     p->m_sepIndex = index + (atFirst ? 0 : 1);
00347 
00348 #if 0
00349     { // ugly workaround to fix the goto scoping problems...
00350         KBookmark bk = mgr->findByAddress( address );
00351         if (bk.isGroup()) // TODO - fix this ****!!!, manhatten distance should be used!!!
00352         {
00353             kdDebug() << "kbookmarkbar:: popping up " << bk.text() << endl; 
00354             KBookmarkActionMenu *menu = dynamic_cast<KBookmarkActionMenu*>(a);
00355             Q_ASSERT(menu);
00356             menu->popup(tb->mapToGlobal(b->geometry().center()));
00357         } 
00358     }
00359 #endif
00360 
00361 skipact:
00362     tb->insertLineSeparator(p->m_sepIndex, const_sepId);
00363     return address;
00364 }
00365 
00366 // TODO - document!!!!
00367 static KAction* handleToolbarMouseButton(QPoint pos, QPtrList<KAction> actions, 
00368                                          KBookmarkManager * /*mgr*/, QPoint & pt)
00369 {
00370     KAction *act = actions.first();
00371     if (!act) {
00372         return 0;
00373     }
00374 
00375     KToolBar *tb = dynamic_cast<KToolBar*>(act->container(0));
00376     Q_ASSERT(tb);
00377 
00378     KToolBarButton *b;
00379     b = dynamic_cast<KToolBarButton*>(tb->childAt(pos)); 
00380     if (!b)
00381         return 0;
00382 
00383     KAction *a = 0;
00384     a = findPluggedAction(actions, tb, b->id());
00385     Q_ASSERT(a);
00386     pt = tb->mapToGlobal(pos);
00387 
00388     return a;
00389 }
00390 
00391 // TODO    *** drop improvements ***
00392 // open submenus on drop interactions
00393 
00394 // TODO    *** generic rmb improvements ***
00395 // don't *ever* show the rmb on press, always relase, possible???
00396 
00397 class KBookmarkBarRMBAssoc : public dPtrTemplate<KBookmarkBar, RMB> { };
00398 template<> QPtrDict<RMB>* dPtrTemplate<KBookmarkBar, RMB>::d_ptr = 0;
00399 
00400 static RMB* rmbSelf(KBookmarkBar *m) { return KBookmarkBarRMBAssoc::d(m); }
00401 
00402 void RMB::begin_rmb_action(KBookmarkBar *self)
00403 {
00404     RMB *s = rmbSelf(self);
00405     s->recv = self;
00406     s->m_parentAddress = self->parentAddress();
00407     s->s_highlightedAddress = self->dptr()->m_highlightedAddress; // rename in RMB
00408     s->m_pManager = self->m_pManager;
00409     s->m_pOwner = self->m_pOwner;
00410     s->m_parentMenu = 0;
00411 }
00412 
00413 void KBookmarkBar::slotRMBActionEditAt( int val )
00414 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionEditAt( val ); }
00415 
00416 void KBookmarkBar::slotRMBActionProperties( int val )
00417 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionProperties( val ); }
00418 
00419 void KBookmarkBar::slotRMBActionInsert( int val )
00420 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionInsert( val ); }
00421 
00422 void KBookmarkBar::slotRMBActionRemove( int val )
00423 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionRemove( val ); }
00424 
00425 void KBookmarkBar::slotRMBActionCopyLocation( int val )
00426 { RMB::begin_rmb_action(this); rmbSelf(this)->slotRMBActionCopyLocation( val ); }
00427 
00428 bool KBookmarkBar::eventFilter( QObject *o, QEvent *e )
00429 {
00430     if (dptr()->m_readOnly || dptr()->m_filteredMgr) // note, we assume m_pManager in various places, 
00431                                                      // this shouldn't really be the case
00432         return false; // todo: make this limit the actions
00433 
00434     if ( (e->type() == QEvent::MouseButtonRelease) || (e->type() == QEvent::MouseButtonPress) ) // FIXME, which one?
00435     {
00436         QMouseEvent *mev = (QMouseEvent*)e;
00437 
00438         QPoint pt;
00439         KAction *_a; 
00440 
00441         // FIXME, see how this holds up on an empty toolbar
00442         _a = handleToolbarMouseButton( mev->pos(), dptr()->m_actions, m_pManager, pt );
00443         if (_a && mev->button() == Qt::RightButton)
00444         {
00445             dptr()->m_highlightedAddress = _a->property("address").toString();
00446             KBookmark bookmark = m_pManager->findByAddress( dptr()->m_highlightedAddress );
00447             RMB::begin_rmb_action(this); 
00448             KPopupMenu *pm = new KPopupMenu;
00449             rmbSelf(this)->fillContextMenu( pm, dptr()->m_highlightedAddress, 0 );
00450             emit aboutToShowContextMenu( rmbSelf(this)->atAddress( dptr()->m_highlightedAddress ), pm );
00451             rmbSelf(this)->fillContextMenu2( pm, dptr()->m_highlightedAddress, 0 );
00452             pm->popup( pt );
00453             mev->accept();
00454         }
00455 
00456         return !!_a; // ignore the event if we didn't find the button
00457     }
00458     else if ( e->type() == QEvent::DragLeave )
00459     {
00460         removeTempSep(dptr());
00461         dptr()->m_dropAddress = QString::null;
00462     }
00463     else if ( e->type() == QEvent::Drop )
00464     {
00465         removeTempSep(dptr());
00466         QDropEvent *dev = (QDropEvent*)e;
00467         if ( !KBookmarkDrag::canDecode( dev ) )
00468             return false;
00469         QValueList<KBookmark> list = KBookmarkDrag::decode( dev );
00470         if (list.count() > 1)
00471             kdWarning(7043) << "Sorry, currently you can only drop one address "
00472                 "onto the bookmark bar!" << endl;
00473         KBookmark toInsert = list.first();
00474         KBookmark bookmark = m_pManager->findByAddress( dptr()->m_dropAddress );
00475         Q_ASSERT(!bookmark.isNull());
00476         kdDebug(7043) << "inserting " 
00477             << QString(dptr()->m_atFirst ? "before" : "after")
00478             << " dptr()->m_dropAddress == " << dptr()->m_dropAddress << endl;
00479         KBookmarkGroup parentBookmark = bookmark.parentGroup();
00480         Q_ASSERT(!parentBookmark.isNull());
00481         KBookmark newBookmark = parentBookmark.addBookmark( 
00482                 m_pManager, toInsert.fullText(),
00483                 toInsert.url() );
00484         parentBookmark.moveItem( newBookmark, dptr()->m_atFirst ? KBookmark() : bookmark );
00485         m_pManager->emitChanged( parentBookmark );
00486         return true;
00487     }
00488     else if ( e->type() == QEvent::DragMove )
00489     {
00490         QDragMoveEvent *dme = (QDragMoveEvent*)e;
00491         if (!KBookmarkDrag::canDecode( dme ))
00492             return false;
00493         bool _atFirst;
00494         QString dropAddress; 
00495         KToolBar *tb = (KToolBar*)o;
00496         dropAddress = handleToolbarDragMoveEvent(dptr(), tb, dme->pos(), dptr()->m_actions, _atFirst, m_pManager);
00497         if (!dropAddress.isNull())
00498         {
00499             dptr()->m_dropAddress = dropAddress;
00500             dptr()->m_atFirst = _atFirst;
00501             dme->accept();
00502         }
00503     }
00504     return false;
00505 }
00506 
00507 static bool showInToolbar( const KBookmark &bk ) {
00508     return (bk.internalElement().attributes().namedItem("showintoolbar").toAttr().value() == "yes"); 
00509 }
00510 
00511 void ToolbarFilter::visit( const KBookmark &bk ) {
00512     //kdDebug() << "visit(" << bk.text() << ")" << endl;
00513     if ( m_visible || showInToolbar(bk) )
00514         KXBELBookmarkImporterImpl::visit(bk);
00515 }
00516 
00517 void ToolbarFilter::visitEnter( const KBookmarkGroup &grp ) {
00518     //kdDebug() << "visitEnter(" << grp.text() << ")" << endl;
00519     if ( !m_visible && showInToolbar(grp) )
00520     {
00521         m_visibleStart = grp;
00522         m_visible = true;
00523     }
00524     if ( m_visible )
00525         KXBELBookmarkImporterImpl::visitEnter(grp);
00526 }
00527 
00528 void ToolbarFilter::visitLeave( const KBookmarkGroup &grp ) {
00529     //kdDebug() << "visitLeave()" << endl;
00530     if ( m_visible )
00531         KXBELBookmarkImporterImpl::visitLeave(grp);
00532     if ( m_visible && grp.address() == m_visibleStart.address() )
00533         m_visible = false;
00534 }
00535 
00536 #include "kbookmarkbar.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.2.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Mar 4 22:44:21 2004 by doxygen 1.3.6-20040222 written by Dimitri van Heesch, © 1997-2003