KParts
partmanager.cpp
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, 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 <QtGui/QApplication> 00028 #include <QtGui/QScrollBar> 00029 #include <kcomponentdata.h> 00030 00031 //#define DEBUG_PARTMANAGER 00032 00033 using namespace KParts; 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 m_reason = PartManager::NoReason; 00050 } 00051 ~PartManagerPrivate() 00052 { 00053 } 00054 void setReason( QEvent* ev ) { 00055 switch( ev->type() ) { 00056 case QEvent::MouseButtonPress: 00057 case QEvent::MouseButtonDblClick: { 00058 QMouseEvent* mev = static_cast<QMouseEvent *>( ev ); 00059 m_reason = mev->button() == Qt::LeftButton 00060 ? PartManager::ReasonLeftClick 00061 : ( mev->button() == Qt::MidButton 00062 ? PartManager::ReasonMidClick 00063 : PartManager::ReasonRightClick ); 00064 break; 00065 } 00066 case QEvent::FocusIn: 00067 m_reason = static_cast<QFocusEvent *>( ev )->reason(); 00068 break; 00069 default: 00070 kWarning(1000) << "PartManagerPrivate::setReason got unexpected ev type " << ev->type(); 00071 break; 00072 } 00073 } 00074 00075 Part * m_activePart; 00076 QWidget *m_activeWidget; 00077 00078 QList<Part *> m_parts; 00079 00080 PartManager::SelectionPolicy m_policy; 00081 00082 Part *m_selectedPart; 00083 QWidget *m_selectedWidget; 00084 00085 QList<const QWidget *> m_managedTopLevelWidgets; 00086 short int m_activationButtonMask; 00087 bool m_bIgnoreScrollBars; 00088 bool m_bAllowNestedParts; 00089 int m_reason; 00090 }; 00091 00092 } 00093 00094 PartManager::PartManager( QWidget * parent ) 00095 : QObject( parent ),d(new PartManagerPrivate) 00096 { 00097 00098 qApp->installEventFilter( this ); 00099 00100 d->m_policy = Direct; 00101 00102 addManagedTopLevelWidget( parent ); 00103 } 00104 00105 PartManager::PartManager( QWidget *topLevel, QObject *parent ) 00106 : QObject( parent ),d(new PartManagerPrivate) 00107 { 00108 00109 qApp->installEventFilter( this ); 00110 00111 d->m_policy = Direct; 00112 00113 addManagedTopLevelWidget( topLevel ); 00114 } 00115 00116 PartManager::~PartManager() 00117 { 00118 foreach( const QWidget* w, d->m_managedTopLevelWidgets ) 00119 { 00120 disconnect( w, SIGNAL( destroyed() ), 00121 this, SLOT( slotManagedTopLevelWidgetDestroyed() ) ); 00122 } 00123 00124 foreach( Part* it, d->m_parts ) 00125 { 00126 it->setManager( 0 ); 00127 } 00128 00129 // core dumps ... setActivePart( 0 ); 00130 qApp->removeEventFilter( this ); 00131 delete d; 00132 } 00133 00134 void PartManager::setSelectionPolicy( SelectionPolicy policy ) 00135 { 00136 d->m_policy = policy; 00137 } 00138 00139 PartManager::SelectionPolicy PartManager::selectionPolicy() const 00140 { 00141 return d->m_policy; 00142 } 00143 00144 void PartManager::setAllowNestedParts( bool allow ) 00145 { 00146 d->m_bAllowNestedParts = allow; 00147 } 00148 00149 bool PartManager::allowNestedParts() const 00150 { 00151 return d->m_bAllowNestedParts; 00152 } 00153 00154 void PartManager::setIgnoreScrollBars( bool ignore ) 00155 { 00156 d->m_bIgnoreScrollBars = ignore; 00157 } 00158 00159 bool PartManager::ignoreScrollBars() const 00160 { 00161 return d->m_bIgnoreScrollBars; 00162 } 00163 00164 void PartManager::setActivationButtonMask( short int buttonMask ) 00165 { 00166 d->m_activationButtonMask = buttonMask; 00167 } 00168 00169 short int PartManager::activationButtonMask() const 00170 { 00171 return d->m_activationButtonMask; 00172 } 00173 00174 bool PartManager::eventFilter( QObject *obj, QEvent *ev ) 00175 { 00176 00177 if ( ev->type() != QEvent::MouseButtonPress && 00178 ev->type() != QEvent::MouseButtonDblClick && 00179 ev->type() != QEvent::FocusIn ) 00180 return false; 00181 00182 if ( !obj->isWidgetType() ) 00183 return false; 00184 00185 QWidget *w = static_cast<QWidget *>( obj ); 00186 00187 if ( ( ( w->windowFlags().testFlag(Qt::Dialog) ) && w->isModal() ) || 00188 ( w->windowFlags().testFlag(Qt::Popup) ) || ( w->windowFlags().testFlag(Qt::Tool) ) ) 00189 return false; 00190 00191 QMouseEvent* mev = 0; 00192 if ( ev->type() == QEvent::MouseButtonPress || ev->type() == QEvent::MouseButtonDblClick ) 00193 { 00194 mev = static_cast<QMouseEvent *>( ev ); 00195 #ifdef DEBUG_PARTMANAGER 00196 kDebug(1000) << "PartManager::eventFilter button: " << mev->button() << " " << "d->m_activationButtonMask=" << d->m_activationButtonMask; 00197 #endif 00198 if ( ( mev->button() & d->m_activationButtonMask ) == 0 ) 00199 return false; // ignore this button 00200 } 00201 00202 Part * part; 00203 while ( w ) 00204 { 00205 QPoint pos; 00206 00207 if ( !d->m_managedTopLevelWidgets.contains( w->topLevelWidget() ) ) 00208 return false; 00209 00210 if ( d->m_bIgnoreScrollBars && ::qobject_cast<QScrollBar *>(w) ) 00211 return false; 00212 00213 if ( mev ) // mouse press or mouse double-click event 00214 { 00215 pos = mev->globalPos(); 00216 part = findPartFromWidget( w, pos ); 00217 } else 00218 part = findPartFromWidget( w ); 00219 00220 #ifdef DEBUG_PARTMANAGER 00221 const char* evType = ( ev->type() == QEvent::MouseButtonPress ) ? "MouseButtonPress" 00222 : ( ev->type() == QEvent::MouseButtonDblClick ) ? "MouseButtonDblClick" 00223 : ( ev->type() == QEvent::FocusIn ) ? "FocusIn" : "OTHER! ERROR!"; 00224 #endif 00225 if ( part ) // We found a part whose widget is w 00226 { 00227 if ( d->m_policy == PartManager::TriState ) 00228 { 00229 if ( ev->type() == QEvent::MouseButtonDblClick ) 00230 { 00231 if ( part == d->m_activePart && w == d->m_activeWidget ) 00232 return false; 00233 00234 #ifdef DEBUG_PARTMANAGER 00235 kDebug(1000) << "PartManager::eventFilter dblclick -> setActivePart" << part; 00236 #endif 00237 d->setReason( ev ); 00238 setActivePart( part, w ); 00239 d->m_reason = NoReason; 00240 return true; 00241 } 00242 00243 if ( ( d->m_selectedWidget != w || d->m_selectedPart != part ) && 00244 ( d->m_activeWidget != w || d->m_activePart != part ) ) 00245 { 00246 if ( part->isSelectable() ) 00247 setSelectedPart( part, w ); 00248 else { 00249 #ifdef DEBUG_PARTMANAGER 00250 kDebug(1000) << "Part " << part << " (non-selectable) made active because " << w->metaObject()->className() << " got event" << " " << evType; 00251 #endif 00252 d->setReason( ev ); 00253 setActivePart( part, w ); 00254 d->m_reason = NoReason; 00255 } 00256 return true; 00257 } 00258 else if ( d->m_selectedWidget == w && d->m_selectedPart == part ) 00259 { 00260 #ifdef DEBUG_PARTMANAGER 00261 kDebug(1000) << "Part " << part << " made active (from selected) because " << w->metaObject()->className() << " got event" << " " << evType; 00262 #endif 00263 d->setReason( ev ); 00264 setActivePart( part, w ); 00265 d->m_reason = NoReason; 00266 return true; 00267 } 00268 else if ( d->m_activeWidget == w && d->m_activePart == part ) 00269 { 00270 setSelectedPart( 0 ); 00271 return false; 00272 } 00273 00274 return false; 00275 } 00276 else if ( part != d->m_activePart ) 00277 { 00278 #ifdef DEBUG_PARTMANAGER 00279 kDebug(1000) << "Part " << part << " made active because " << w->metaObject()->className() << " got event" << " " << evType; 00280 #endif 00281 d->setReason( ev ); 00282 setActivePart( part, w ); 00283 d->m_reason = NoReason; 00284 } 00285 00286 return false; 00287 } 00288 00289 w = w->parentWidget(); 00290 00291 if ( w && ( ( ( w->windowFlags() & Qt::Dialog ) && w->isModal() ) || 00292 ( w->windowFlags() & Qt::Popup ) || ( w->windowFlags() & Qt::Tool ) ) ) 00293 { 00294 #ifdef DEBUG_PARTMANAGER 00295 kDebug(1000) << QString("No part made active although %1/%2 got event - loop aborted").arg(obj->objectName()).arg(obj->metaObject()->className()); 00296 #endif 00297 return false; 00298 } 00299 00300 } 00301 00302 #ifdef DEBUG_PARTMANAGER 00303 kDebug(1000) << QString("No part made active although %1/%2 got event").arg(obj->objectName()).arg(obj->metaObject()->className()); 00304 #endif 00305 return false; 00306 } 00307 00308 Part * PartManager::findPartFromWidget( QWidget * widget, const QPoint &pos ) 00309 { 00310 for ( QList<Part *>::iterator it = d->m_parts.begin(), end = d->m_parts.end() ; it != end ; ++it ) 00311 { 00312 Part *part = (*it)->hitTest( widget, pos ); 00313 if ( part && d->m_parts.contains( part ) ) 00314 return part; 00315 } 00316 return 0; 00317 } 00318 00319 Part * PartManager::findPartFromWidget( QWidget * widget ) 00320 { 00321 for ( QList<Part *>::iterator it = d->m_parts.begin(), end = d->m_parts.end() ; it != end ; ++it ) 00322 { 00323 if ( widget == (*it)->widget() ) 00324 return (*it); 00325 } 00326 return 0; 00327 } 00328 00329 void PartManager::addPart( Part *part, bool setActive ) 00330 { 00331 Q_ASSERT( part ); 00332 00333 // don't add parts more than once :) 00334 if ( d->m_parts.contains( part ) ) { 00335 #ifdef DEBUG_PARTMANAGER 00336 kWarning(1000) << part << " already added" << kBacktrace(5); 00337 #endif 00338 return; 00339 } 00340 00341 d->m_parts.append( part ); 00342 00343 part->setManager( this ); 00344 00345 if ( setActive ) { 00346 setActivePart( part ); 00347 00348 if ( QWidget *w = part->widget() ) { 00349 // Prevent focus problems 00350 if ( w->focusPolicy() == Qt::NoFocus ) { 00351 kWarning(1000) << "Part '" << part->objectName() << "' has a widget " 00352 << w->objectName() << " with a focus policy of NoFocus. It should have at least a" 00353 << "ClickFocus policy, for part activation to work well." << endl; 00354 } 00355 if ( part->widget() && part->widget()->focusPolicy() == Qt::TabFocus ) { 00356 kWarning(1000) << "Part '" << part->objectName() << "' has a widget " 00357 << w->objectName() << " with a focus policy of TabFocus. It should have at least a" 00358 << "ClickFocus policy, for part activation to work well." << endl; 00359 } 00360 w->setFocus(); 00361 w->show(); 00362 } 00363 } 00364 emit partAdded( part ); 00365 } 00366 00367 void PartManager::removePart( Part *part ) 00368 { 00369 if (!d->m_parts.contains(part)) { 00370 return; 00371 } 00372 00373 const int nb = d->m_parts.removeAll(part); 00374 Q_ASSERT(nb == 1); 00375 Q_UNUSED(nb); // no warning in release mode 00376 part->setManager(0); 00377 00378 emit partRemoved( part ); 00379 00380 if ( part == d->m_activePart ) 00381 setActivePart( 0 ); 00382 if ( part == d->m_selectedPart ) 00383 setSelectedPart( 0 ); 00384 } 00385 00386 void PartManager::replacePart( Part * oldPart, Part * newPart, bool setActive ) 00387 { 00388 //kDebug(1000) << "replacePart " << oldPart->name() << "-> " << newPart->name() << " setActive=" << setActive; 00389 // This methods does exactly removePart + addPart but without calling setActivePart(0) in between 00390 if ( !d->m_parts.contains( oldPart ) ) 00391 { 00392 kFatal(1000) << QString("Can't remove part %1, not in KPartManager's list.").arg(oldPart->objectName()); 00393 return; 00394 } 00395 00396 d->m_parts.removeAll( oldPart ); 00397 oldPart->setManager(0); 00398 00399 emit partRemoved( oldPart ); 00400 00401 addPart( newPart, setActive ); 00402 } 00403 00404 void PartManager::setActivePart( Part *part, QWidget *widget ) 00405 { 00406 if ( part && !d->m_parts.contains( part ) ) 00407 { 00408 kWarning(1000) << "trying to activate a non-registered part!" << part->objectName(); 00409 return; // don't allow someone call setActivePart with a part we don't know about 00410 } 00411 00412 //check whether nested parts are disallowed and activate the top parent part then, by traversing the 00413 //tree recursively (Simon) 00414 if ( part && !d->m_bAllowNestedParts ) 00415 { 00416 QObject *parentPart = part->parent(); // ### this relies on people using KParts::Factory! 00417 KParts::Part *parPart = ::qobject_cast<KParts::Part *>( parentPart ); 00418 if ( parPart ) 00419 { 00420 setActivePart( parPart, parPart->widget() ); 00421 return; 00422 } 00423 } 00424 00425 #ifdef DEBUG_PARTMANAGER 00426 kDebug(1000) << "PartManager::setActivePart d->m_activePart=" << d->m_activePart << "<->part=" << part 00427 << " d->m_activeWidget=" << d->m_activeWidget << "<->widget=" << widget << endl; 00428 #endif 00429 00430 // don't activate twice 00431 if ( d->m_activePart && part && d->m_activePart == part && 00432 (!widget || d->m_activeWidget == widget) ) 00433 return; 00434 00435 KParts::Part *oldActivePart = d->m_activePart; 00436 QWidget *oldActiveWidget = d->m_activeWidget; 00437 00438 setSelectedPart( 0 ); 00439 00440 d->m_activePart = part; 00441 d->m_activeWidget = widget; 00442 00443 if ( oldActivePart ) 00444 { 00445 KParts::Part *savedActivePart = part; 00446 QWidget *savedActiveWidget = widget; 00447 00448 PartActivateEvent ev( false, oldActivePart, oldActiveWidget ); 00449 QApplication::sendEvent( oldActivePart, &ev ); 00450 if ( oldActiveWidget ) 00451 { 00452 disconnect( oldActiveWidget, SIGNAL( destroyed() ), 00453 this, SLOT( slotWidgetDestroyed() ) ); 00454 QApplication::sendEvent( oldActiveWidget, &ev ); 00455 } 00456 00457 d->m_activePart = savedActivePart; 00458 d->m_activeWidget = savedActiveWidget; 00459 } 00460 00461 if ( d->m_activePart ) 00462 { 00463 if ( !widget ) 00464 d->m_activeWidget = part->widget(); 00465 00466 PartActivateEvent ev( true, d->m_activePart, d->m_activeWidget ); 00467 QApplication::sendEvent( d->m_activePart, &ev ); 00468 if ( d->m_activeWidget ) 00469 { 00470 connect( d->m_activeWidget, SIGNAL( destroyed() ), 00471 this, SLOT( slotWidgetDestroyed() ) ); 00472 QApplication::sendEvent( d->m_activeWidget, &ev ); 00473 } 00474 } 00475 // Set the new active instance in KGlobal 00476 setActiveComponent(d->m_activePart ? d->m_activePart->componentData() : KGlobal::mainComponent()); 00477 00478 #ifdef DEBUG_PARTMANAGER 00479 kDebug(1000) << this << " emitting activePartChanged " << d->m_activePart; 00480 #endif 00481 emit activePartChanged( d->m_activePart ); 00482 } 00483 00484 void PartManager::setActiveComponent(const KComponentData &instance) 00485 { 00486 // It's a separate method to allow redefining this behavior 00487 KGlobal::setActiveComponent(instance); 00488 } 00489 00490 Part *PartManager::activePart() const 00491 { 00492 return d->m_activePart; 00493 } 00494 00495 QWidget *PartManager::activeWidget() const 00496 { 00497 return d->m_activeWidget; 00498 } 00499 00500 void PartManager::setSelectedPart( Part *part, QWidget *widget ) 00501 { 00502 if ( part == d->m_selectedPart && widget == d->m_selectedWidget ) 00503 return; 00504 00505 Part *oldPart = d->m_selectedPart; 00506 QWidget *oldWidget = d->m_selectedWidget; 00507 00508 d->m_selectedPart = part; 00509 d->m_selectedWidget = widget; 00510 00511 if ( part && !widget ) 00512 d->m_selectedWidget = part->widget(); 00513 00514 if ( oldPart ) 00515 { 00516 PartSelectEvent ev( false, oldPart, oldWidget ); 00517 QApplication::sendEvent( oldPart, &ev ); 00518 QApplication::sendEvent( oldWidget, &ev ); 00519 } 00520 00521 if ( d->m_selectedPart ) 00522 { 00523 PartSelectEvent ev( true, d->m_selectedPart, d->m_selectedWidget ); 00524 QApplication::sendEvent( d->m_selectedPart, &ev ); 00525 QApplication::sendEvent( d->m_selectedWidget, &ev ); 00526 } 00527 } 00528 00529 Part *PartManager::selectedPart() const 00530 { 00531 return d->m_selectedPart; 00532 } 00533 00534 QWidget *PartManager::selectedWidget() const 00535 { 00536 return d->m_selectedWidget; 00537 } 00538 00539 void PartManager::slotObjectDestroyed() 00540 { 00541 kDebug(1000); 00542 removePart( const_cast<Part *>( static_cast<const Part *>( sender() ) ) ); 00543 } 00544 00545 void PartManager::slotWidgetDestroyed() 00546 { 00547 kDebug(1000); 00548 if ( static_cast<const QWidget *>( sender() ) == d->m_activeWidget ) 00549 setActivePart( 0 ); //do not remove the part because if the part's widget dies, then the 00550 //part will delete itself anyway, invoking removePart() in its destructor 00551 } 00552 00553 const QList<Part *> PartManager::parts() const 00554 { 00555 return d->m_parts; 00556 } 00557 00558 void PartManager::addManagedTopLevelWidget( const QWidget *topLevel ) 00559 { 00560 if ( !topLevel->isTopLevel() ) 00561 return; 00562 00563 if ( d->m_managedTopLevelWidgets.contains( topLevel ) ) 00564 return; 00565 00566 d->m_managedTopLevelWidgets.append( topLevel ); 00567 connect( topLevel, SIGNAL( destroyed() ), 00568 this, SLOT( slotManagedTopLevelWidgetDestroyed() ) ); 00569 } 00570 00571 void PartManager::removeManagedTopLevelWidget( const QWidget *topLevel ) 00572 { 00573 if ( !topLevel->isTopLevel() ) 00574 return; 00575 00576 d->m_managedTopLevelWidgets.removeAll( topLevel ); 00577 } 00578 00579 void PartManager::slotManagedTopLevelWidgetDestroyed() 00580 { 00581 const QWidget *widget = static_cast<const QWidget *>( sender() ); 00582 removeManagedTopLevelWidget( widget ); 00583 } 00584 00585 int PartManager::reason() const 00586 { 00587 return d->m_reason; 00588 } 00589 00590 #include "partmanager.moc"
KDE 4.6 API Reference