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