kparts Library API Documentation

partmanager.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
00003              (C) 1999 David Faure <faure@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #include "partmanager.h"
00022 #include <kparts/event.h>
00023 #include <kparts/part.h>
00024 #include <kglobal.h>
00025 #include <kdebug.h>
00026 
00027 #include <qapplication.h>
00028 
00029 //#define DEBUG_PARTMANAGER
00030 
00031 using namespace KParts;
00032 
00033 template class QPtrList<Part>;
00034 
00035 namespace KParts {
00036 
00037 class PartManagerPrivate
00038 {
00039 public:
00040   PartManagerPrivate()
00041   {
00042     m_activeWidget = 0;
00043     m_activePart = 0;
00044     m_selectedPart = 0;
00045     m_selectedWidget = 0;
00046     m_bAllowNestedParts = false;
00047     m_bIgnoreScrollBars = false;
00048     m_activationButtonMask = Qt::LeftButton | Qt::MidButton | Qt::RightButton;
00049   }
00050   ~PartManagerPrivate()
00051   {
00052   }
00053 
00054   Part * m_activePart;
00055   QWidget *m_activeWidget;
00056 
00057   QPtrList<Part> m_parts;
00058 
00059   PartManager::SelectionPolicy m_policy;
00060 
00061   Part *m_selectedPart;
00062   QWidget *m_selectedWidget;
00063 
00064   QPtrList<QWidget> m_managedTopLevelWidgets;
00065   short int m_activationButtonMask;
00066   bool m_bIgnoreScrollBars;
00067   bool m_bAllowNestedParts;
00068 };
00069 
00070 }
00071 
00072 PartManager::PartManager( QWidget * parent, const char * name )
00073  : QObject( parent, name )
00074 {
00075   d = new PartManagerPrivate;
00076 
00077   qApp->installEventFilter( this );
00078 
00079   d->m_policy = Direct;
00080 
00081   addManagedTopLevelWidget( parent );
00082 }
00083 
00084 PartManager::PartManager( QWidget *topLevel, QObject *parent, const char *name )
00085  : QObject( parent, name )
00086 {
00087   d = new PartManagerPrivate;
00088 
00089   qApp->installEventFilter( this );
00090 
00091   d->m_policy = Direct;
00092 
00093   addManagedTopLevelWidget( topLevel );
00094 }
00095 
00096 PartManager::~PartManager()
00097 {
00098   for ( QPtrListIterator<QWidget> it( d->m_managedTopLevelWidgets );
00099         it.current(); ++it )
00100     disconnect( it.current(), SIGNAL( destroyed() ),
00101                 this, SLOT( slotManagedTopLevelWidgetDestroyed() ) );
00102 
00103   for ( QPtrListIterator<Part> it( d->m_parts ); it.current(); ++it )
00104       it.current()->setManager( 0 );
00105 
00106   // core dumps ... setActivePart( 0L );
00107   qApp->removeEventFilter( this );
00108   delete d;
00109 }
00110 
00111 void PartManager::setSelectionPolicy( SelectionPolicy policy )
00112 {
00113   d->m_policy = policy;
00114 }
00115 
00116 PartManager::SelectionPolicy PartManager::selectionPolicy() const
00117 {
00118   return d->m_policy;
00119 }
00120 
00121 void PartManager::setAllowNestedParts( bool allow )
00122 {
00123   d->m_bAllowNestedParts = allow;
00124 }
00125 
00126 bool PartManager::allowNestedParts() const
00127 {
00128   return d->m_bAllowNestedParts;
00129 }
00130 
00131 void PartManager::setIgnoreScrollBars( bool ignore )
00132 {
00133   d->m_bIgnoreScrollBars = ignore;
00134 }
00135 
00136 bool PartManager::ignoreScrollBars() const
00137 {
00138   return d->m_bIgnoreScrollBars;
00139 }
00140 
00141 void PartManager::setActivationButtonMask( short int buttonMask )
00142 {
00143     d->m_activationButtonMask = buttonMask;
00144 }
00145 
00146 short int PartManager::activationButtonMask() const
00147 {
00148     return d->m_activationButtonMask;
00149 }
00150 
00151 bool PartManager::eventFilter( QObject *obj, QEvent *ev )
00152 {
00153 
00154   if ( ev->type() != QEvent::MouseButtonPress &&
00155        ev->type() != QEvent::MouseButtonDblClick &&
00156        ev->type() != QEvent::FocusIn )
00157     return false;
00158 
00159   if ( !obj->isWidgetType() )
00160     return false;
00161 
00162   QWidget *w = static_cast<QWidget *>( obj );
00163 
00164   if ( ( w->testWFlags( WType_Dialog ) && w->isModal() ) ||
00165        w->testWFlags( WType_Popup ) || w->testWFlags( WStyle_Tool ) )
00166     return false;
00167 
00168   QMouseEvent* mev = 0L;
00169   if ( ev->type() == QEvent::MouseButtonPress || ev->type() == QEvent::MouseButtonDblClick )
00170   {
00171       mev = static_cast<QMouseEvent *>( ev );
00172 #ifdef DEBUG_PARTMANAGER
00173       kdDebug() << "PartManager::eventFilter button: " << mev->button() << " " << "d->m_activationButtonMask=" << d->m_activationButtonMask << endl;
00174 #endif
00175       if ( ( mev->button() & d->m_activationButtonMask ) == 0 )
00176         return false; // ignore this button
00177   }
00178 
00179   Part * part;
00180   while ( w )
00181   {
00182     QPoint pos;
00183 
00184     if ( !d->m_managedTopLevelWidgets.containsRef( w->topLevelWidget() ) )
00185       return false;
00186 
00187     if ( d->m_bIgnoreScrollBars && w->inherits( "QScrollBar" ) )
00188       return false;
00189 
00190     if ( mev ) // mouse press or mouse double-click event
00191     {
00192       pos = mev->globalPos();
00193       part = findPartFromWidget( w, pos );
00194     } else
00195       part = findPartFromWidget( w );
00196 
00197 #ifdef DEBUG_PARTMANAGER
00198     QCString evType = ( ev->type() == QEvent::MouseButtonPress ) ? "MouseButtonPress"
00199                       : ( ev->type() == QEvent::MouseButtonDblClick ) ? "MouseButtonDblClick"
00200                       : ( ev->type() == QEvent::FocusIn ) ? "FocusIn" : "OTHER! ERROR!";
00201 #endif
00202     if ( part ) // We found a part whose widget is w
00203     {
00204       if ( d->m_policy == PartManager::TriState )
00205       {
00206         if ( ev->type() == QEvent::MouseButtonDblClick )
00207         {
00208           if ( part == d->m_activePart && w == d->m_activeWidget )
00209             return false;
00210 
00211 #ifdef DEBUG_PARTMANAGER
00212           kdDebug(1000) << "PartManager::eventFilter dblclick -> setActivePart" << part << endl;
00213 #endif
00214           setActivePart( part, w );
00215           return true;
00216         }
00217 
00218         if ( ( d->m_selectedWidget != w || d->m_selectedPart != part ) &&
00219              ( d->m_activeWidget != w || d->m_activePart != part ) )
00220         {
00221           if ( part->isSelectable() )
00222             setSelectedPart( part, w );
00223           else {
00224 #ifdef DEBUG_PARTMANAGER
00225               kdDebug(1000) << "Part " << part << " (non-selectable) made active because " << w->className() << " got event" << " " << evType << endl;
00226 #endif
00227               setActivePart( part, w );
00228           }
00229           return true;
00230         }
00231         else if ( d->m_selectedWidget == w && d->m_selectedPart == part )
00232         {
00233 #ifdef DEBUG_PARTMANAGER
00234           kdDebug(1000) << "Part " << part << " made active (from selected) because " << w->className() << " got event" << " " << evType << endl;
00235 #endif
00236           setActivePart( part, w );
00237           return true;
00238         }
00239         else if ( d->m_activeWidget == w && d->m_activePart == part )
00240         {
00241           setSelectedPart( 0L );
00242           return false;
00243         }
00244 
00245         return false;
00246       }
00247       else if ( part != d->m_activePart )
00248       {
00249 #ifdef DEBUG_PARTMANAGER
00250         kdDebug(1000) << "Part " << part << " made active because " << w->className() << " got event" << " " << evType << endl;
00251 #endif
00252         setActivePart( part, w );
00253       }
00254 
00255       return false;
00256     }
00257 
00258     w = w->parentWidget();
00259 
00260     if ( w && ( ( w->testWFlags( WType_Dialog ) && w->isModal() ) ||
00261                 w->testWFlags( WType_Popup ) || w->testWFlags( WStyle_Tool ) ) )
00262     {
00263 #ifdef DEBUG_PARTMANAGER
00264       kdDebug(1000) << QString("No part made active although %1/%2 got event - loop aborted").arg(obj->name()).arg(obj->className()) << endl;
00265 #endif
00266       return false;
00267     }
00268 
00269   }
00270 
00271 #ifdef DEBUG_PARTMANAGER
00272   kdDebug(1000) << QString("No part made active although %1/%2 got event").arg(obj->name()).arg(obj->className()) << endl;
00273 #endif
00274   return false;
00275 }
00276 
00277 Part * PartManager::findPartFromWidget( QWidget * widget, const QPoint &pos )
00278 {
00279   QPtrListIterator<Part> it ( d->m_parts );
00280   for ( ; it.current() ; ++it )
00281   {
00282     Part *part = it.current()->hitTest( widget, pos );
00283     if ( part && d->m_parts.findRef( part ) != -1 )
00284       return part;
00285   }
00286   return 0L;
00287 }
00288 
00289 Part * PartManager::findPartFromWidget( QWidget * widget )
00290 {
00291   QPtrListIterator<Part> it ( d->m_parts );
00292   for ( ; it.current() ; ++it )
00293   {
00294     if ( widget == it.current()->widget() )
00295       return it.current();
00296   }
00297   return 0L;
00298 }
00299 
00300 void PartManager::addPart( Part *part, bool setActive )
00301 {
00302     if ( d->m_parts.findRef( part ) != -1 ) // don't add parts more than once :)
00303       return;
00304 
00305   d->m_parts.append( part );
00306 
00307   part->setManager( this );
00308 
00309   if ( setActive )
00310   {
00311     setActivePart( part );
00312     if ( part->widget() )
00313       part->widget()->setFocus();
00314   }
00315 
00316   // Prevent focus problems
00317   if ( part->widget() && part->widget()->focusPolicy() == QWidget::NoFocus )
00318   {
00319     kdWarning(1000) << "Part '" << part->name() << "' has a widget " << part->widget()->name() << " with a focus policy of NoFocus. It should have at least a ClickFocus policy, for part activation to work well." << endl;
00320   }
00321   if ( part->widget() && part->widget()->focusPolicy() == QWidget::TabFocus )
00322   {
00323     kdWarning(1000) << "Part '" << part->name() << "' has a widget " << part->widget()->name() << " with a focus policy of TabFocus. It should have at least a ClickFocus policy, for part activation to work well." << endl;
00324   }
00325 
00326   if ( part->widget() )
00327     part->widget()->show();
00328   emit partAdded( part );
00329 }
00330 
00331 void PartManager::removePart( Part *part )
00332 {
00333   if ( d->m_parts.findRef( part ) == -1 )
00334   {
00335     kdFatal(1000) << QString("Can't remove part %1, not in KPartManager's list.").arg(part->name()) << endl;
00336     return;
00337   }
00338 
00339   //Warning. The part could be already deleted
00340   //kdDebug(1000) << QString("Part %1 removed").arg(part->name()) << endl;
00341   d->m_parts.removeRef( part );
00342   part->setManager(0);
00343 
00344   emit partRemoved( part );
00345 
00346   if ( part == d->m_activePart )
00347     setActivePart( 0 );
00348   if ( part == d->m_selectedPart )
00349     setSelectedPart( 0 );
00350 }
00351 
00352 void PartManager::replacePart( Part * oldPart, Part * newPart, bool setActive )
00353 {
00354   //kdDebug(1000) << "replacePart " << oldPart->name() << "-> " << newPart->name() << " setActive=" << setActive << endl;
00355   // This methods does exactly removePart + addPart but without calling setActivePart(0) in between
00356   if ( d->m_parts.findRef( oldPart ) == -1 )
00357   {
00358     kdFatal(1000) << QString("Can't remove part %1, not in KPartManager's list.").arg(oldPart->name()) << endl;
00359     return;
00360   }
00361 
00362   d->m_parts.removeRef( oldPart );
00363   oldPart->setManager(0);
00364 
00365   emit partRemoved( oldPart );
00366 
00367   addPart( newPart, setActive );
00368 }
00369 
00370 void PartManager::setActivePart( Part *part, QWidget *widget )
00371 {
00372   if ( part && d->m_parts.findRef( part ) == -1 )
00373   {
00374       kdWarning( 1000 ) << "PartManager::setActivePart : trying to activate a non-registered part! " << part->name() << endl;
00375       return; // don't allow someone call setActivePart with a part we don't know about
00376   }
00377 
00378   //check whether nested parts are disallowed and activate the top parent part then, by traversing the
00379   //tree recursively (Simon)
00380   if ( part && !d->m_bAllowNestedParts )
00381   {
00382     QObject *parentPart = part->parent(); // ### this relies on people using KParts::Factory!
00383     if ( parentPart && parentPart->inherits( "KParts::Part" ) )
00384     {
00385       KParts::Part *parPart = static_cast<KParts::Part *>( parentPart );
00386       setActivePart( parPart, parPart->widget() );
00387       return;
00388     }
00389   }
00390 
00391   //kdDebug() << "PartManager::setActivePart d->m_activePart=" << d->m_activePart << "<->part=" << part
00392   //          << " d->m_activeWidget=" << d->m_activeWidget << "<->widget=" << widget << endl;
00393 
00394   // don't activate twice
00395   if ( d->m_activePart && part && d->m_activePart == part &&
00396        (!widget || d->m_activeWidget == widget) )
00397     return;
00398 
00399   KParts::Part *oldActivePart = d->m_activePart;
00400   QWidget *oldActiveWidget = d->m_activeWidget;
00401 
00402   setSelectedPart( 0L );
00403 
00404   d->m_activePart = part;
00405   d->m_activeWidget = widget;
00406 
00407   if ( oldActivePart )
00408   {
00409     KParts::Part *savedActivePart = part;
00410     QWidget *savedActiveWidget = widget;
00411 
00412     PartActivateEvent ev( false, oldActivePart, oldActiveWidget );
00413     QApplication::sendEvent( oldActivePart, &ev );
00414     if ( oldActiveWidget )
00415     {
00416       disconnect( oldActiveWidget, SIGNAL( destroyed() ),
00417                   this, SLOT( slotWidgetDestroyed() ) );
00418       QApplication::sendEvent( oldActiveWidget, &ev );
00419     }
00420 
00421     d->m_activePart = savedActivePart;
00422     d->m_activeWidget = savedActiveWidget;
00423   }
00424 
00425   if ( d->m_activePart )
00426   {
00427     if ( !widget )
00428       d->m_activeWidget = part->widget();
00429 
00430     PartActivateEvent ev( true, d->m_activePart, d->m_activeWidget );
00431     QApplication::sendEvent( d->m_activePart, &ev );
00432     if ( d->m_activeWidget )
00433     {
00434       connect( d->m_activeWidget, SIGNAL( destroyed() ),
00435                this, SLOT( slotWidgetDestroyed() ) );
00436       QApplication::sendEvent( d->m_activeWidget, &ev );
00437     }
00438   }
00439   // Set the new active instance in KGlobal
00440   setActiveInstance( d->m_activePart ? d->m_activePart->instance() : 0L );
00441 
00442   kdDebug(1000) << this << " emitting activePartChanged " << d->m_activePart << endl;
00443   emit activePartChanged( d->m_activePart );
00444 }
00445 
00446 void PartManager::setActiveInstance( KInstance * instance )
00447 {
00448   // It's a separate method to allow redefining this behavior
00449   KGlobal::_activeInstance = instance;
00450 }
00451 
00452 Part *PartManager::activePart() const
00453 {
00454   return d->m_activePart;
00455 }
00456 
00457 QWidget *PartManager::activeWidget() const
00458 {
00459   return  d->m_activeWidget;
00460 }
00461 
00462 void PartManager::setSelectedPart( Part *part, QWidget *widget )
00463 {
00464   if ( part == d->m_selectedPart && widget == d->m_selectedWidget )
00465     return;
00466 
00467   Part *oldPart = d->m_selectedPart;
00468   QWidget *oldWidget = d->m_selectedWidget;
00469 
00470   d->m_selectedPart = part;
00471   d->m_selectedWidget = widget;
00472 
00473   if ( part && !widget )
00474     d->m_selectedWidget = part->widget();
00475 
00476   if ( oldPart )
00477   {
00478     PartSelectEvent ev( false, oldPart, oldWidget );
00479     QApplication::sendEvent( oldPart, &ev );
00480     QApplication::sendEvent( oldWidget, &ev );
00481   }
00482 
00483   if ( d->m_selectedPart )
00484   {
00485     PartSelectEvent ev( true, d->m_selectedPart, d->m_selectedWidget );
00486     QApplication::sendEvent( d->m_selectedPart, &ev );
00487     QApplication::sendEvent( d->m_selectedWidget, &ev );
00488   }
00489 }
00490 
00491 Part *PartManager::selectedPart() const
00492 {
00493   return d->m_selectedPart;
00494 }
00495 
00496 QWidget *PartManager::selectedWidget() const
00497 {
00498   return d->m_selectedWidget;
00499 }
00500 
00501 void PartManager::slotObjectDestroyed()
00502 {
00503   kdDebug(1000) << "KPartManager::slotObjectDestroyed()" << endl;
00504   removePart( const_cast<Part *>( static_cast<const Part *>( sender() ) ) );
00505 }
00506 
00507 void PartManager::slotWidgetDestroyed()
00508 {
00509   kdDebug(1000) << "KPartsManager::slotWidgetDestroyed()" << endl;
00510   if ( static_cast<const QWidget *>( sender() ) == d->m_activeWidget )
00511     setActivePart( 0L ); //do not remove the part because if the part's widget dies, then the
00512                          //part will delete itself anyway, invoking removePart() in its destructor
00513 }
00514 
00515 const QPtrList<Part> *PartManager::parts() const
00516 {
00517   return &d->m_parts;
00518 }
00519 
00520 void PartManager::addManagedTopLevelWidget( const QWidget *topLevel )
00521 {
00522   if ( !topLevel->isTopLevel() )
00523     return;
00524 
00525   if ( d->m_managedTopLevelWidgets.containsRef( topLevel ) )
00526     return;
00527 
00528   d->m_managedTopLevelWidgets.append( topLevel );
00529   connect( topLevel, SIGNAL( destroyed() ),
00530            this, SLOT( slotManagedTopLevelWidgetDestroyed() ) );
00531 }
00532 
00533 void PartManager::removeManagedTopLevelWidget( const QWidget *topLevel )
00534 {
00535   if ( !topLevel->isTopLevel() )
00536     return;
00537 
00538   if ( d->m_managedTopLevelWidgets.findRef( topLevel ) == -1 )
00539     return;
00540 
00541   d->m_managedTopLevelWidgets.remove();
00542 }
00543 
00544 void PartManager::slotManagedTopLevelWidgetDestroyed()
00545 {
00546   const QWidget *widget = static_cast<const QWidget *>( sender() );
00547   removeManagedTopLevelWidget( widget );
00548 }
00549 
00550 void PartManager::virtual_hook( int, void* )
00551 { /*BASE::virtual_hook( id, data );*/ }
00552 
00553 #include "partmanager.moc"
KDE Logo
This file is part of the documentation for kparts Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Apr 21 18:44:09 2004 by doxygen 1.3.6-20040222 written by Dimitri van Heesch, © 1997-2003