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 <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"
KDE Logo
This file is part of the documentation for kio Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 23:09:06 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003