diff options
Diffstat (limited to 'tdeparts/partmanager.cpp')
-rw-r--r-- | tdeparts/partmanager.cpp | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/tdeparts/partmanager.cpp b/tdeparts/partmanager.cpp new file mode 100644 index 000000000..1af0f1ee3 --- /dev/null +++ b/tdeparts/partmanager.cpp @@ -0,0 +1,601 @@ +// -*- mode: c++; c-basic-offset: 2 -*- +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <hausmann@kde.org> + (C) 1999 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "partmanager.h" +#include <tdeparts/event.h> +#include <tdeparts/part.h> +#include <kglobal.h> +#include <kdebug.h> + +#include <tqapplication.h> + +//#define DEBUG_PARTMANAGER + +using namespace KParts; + +template class TQPtrList<Part>; + +namespace KParts { + +class PartManagerPrivate +{ +public: + PartManagerPrivate() + { + m_activeWidget = 0; + m_activePart = 0; + m_selectedPart = 0; + m_selectedWidget = 0; + m_bAllowNestedParts = false; + m_bIgnoreScrollBars = false; + m_activationButtonMask = Qt::LeftButton | Qt::MidButton | Qt::RightButton; + m_reason = PartManager::NoReason; + } + ~PartManagerPrivate() + { + } + void setReason( TQEvent* ev ) { + switch( ev->type() ) { + case TQEvent::MouseButtonPress: + case TQEvent::MouseButtonDblClick: { + TQMouseEvent* mev = TQT_TQMOUSEEVENT( ev ); + m_reason = mev->button() == Qt::LeftButton + ? PartManager::ReasonLeftClick + : ( mev->button() == Qt::MidButton + ? PartManager::ReasonMidClick + : PartManager::ReasonRightClick ); + break; + } + case TQEvent::FocusIn: + m_reason = TQT_TQFOCUSEVENT( ev )->reason(); + break; + default: + kdWarning(1000) << "PartManagerPrivate::setReason got unexpected ev type " << ev->type() << endl; + break; + } + } + + Part * m_activePart; + TQWidget *m_activeWidget; + + TQPtrList<Part> m_parts; + + PartManager::SelectionPolicy m_policy; + + Part *m_selectedPart; + TQWidget *m_selectedWidget; + + TQPtrList<TQWidget> m_managedTopLevelWidgets; + short int m_activationButtonMask; + bool m_bIgnoreScrollBars; + bool m_bAllowNestedParts; + int m_reason; +}; + +} + +PartManager::PartManager( TQWidget * parent, const char * name ) + : TQObject( parent, name ) +{ + d = new PartManagerPrivate; + + tqApp->installEventFilter( this ); + + d->m_policy = Direct; + + addManagedTopLevelWidget( parent ); +} + +PartManager::PartManager( TQWidget *topLevel, TQObject *parent, const char *name ) + : TQObject( parent, name ) +{ + d = new PartManagerPrivate; + + tqApp->installEventFilter( this ); + + d->m_policy = Direct; + + addManagedTopLevelWidget( topLevel ); +} + +PartManager::~PartManager() +{ + for ( TQPtrListIterator<TQWidget> it( d->m_managedTopLevelWidgets ); + it.current(); ++it ) + disconnect( it.current(), TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotManagedTopLevelWidgetDestroyed() ) ); + + for ( TQPtrListIterator<Part> it( d->m_parts ); it.current(); ++it ) + { + it.current()->setManager( 0 ); + } + + // core dumps ... setActivePart( 0L ); + tqApp->removeEventFilter( this ); + delete d; +} + +void PartManager::setSelectionPolicy( SelectionPolicy policy ) +{ + d->m_policy = policy; +} + +PartManager::SelectionPolicy PartManager::selectionPolicy() const +{ + return d->m_policy; +} + +void PartManager::setAllowNestedParts( bool allow ) +{ + d->m_bAllowNestedParts = allow; +} + +bool PartManager::allowNestedParts() const +{ + return d->m_bAllowNestedParts; +} + +void PartManager::setIgnoreScrollBars( bool ignore ) +{ + d->m_bIgnoreScrollBars = ignore; +} + +bool PartManager::ignoreScrollBars() const +{ + return d->m_bIgnoreScrollBars; +} + +void PartManager::setActivationButtonMask( short int buttonMask ) +{ + d->m_activationButtonMask = buttonMask; +} + +short int PartManager::activationButtonMask() const +{ + return d->m_activationButtonMask; +} + +bool PartManager::eventFilter( TQObject *obj, TQEvent *ev ) +{ + + if ( ev->type() != TQEvent::MouseButtonPress && + ev->type() != TQEvent::MouseButtonDblClick && + ev->type() != TQEvent::FocusIn ) + return false; + + if ( !obj->isWidgetType() ) + return false; + + TQWidget *w = TQT_TQWIDGET( obj ); + + if ( ( w->testWFlags( WType_Dialog ) && w->isModal() ) || + w->testWFlags( WType_Popup ) || w->testWFlags( WStyle_Tool ) ) + return false; + + TQMouseEvent* mev = 0L; + if ( ev->type() == TQEvent::MouseButtonPress || ev->type() == TQEvent::MouseButtonDblClick ) + { + mev = TQT_TQMOUSEEVENT( ev ); +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "PartManager::eventFilter button: " << mev->button() << " " << "d->m_activationButtonMask=" << d->m_activationButtonMask << endl; +#endif + if ( ( mev->button() & d->m_activationButtonMask ) == 0 ) + return false; // ignore this button + } + + Part * part; + while ( w ) + { + TQPoint pos; + + if ( !d->m_managedTopLevelWidgets.containsRef( w->topLevelWidget() ) ) + return false; + + if ( d->m_bIgnoreScrollBars && w->inherits( TQSCROLLBAR_OBJECT_NAME_STRING ) ) + return false; + + if ( mev ) // mouse press or mouse double-click event + { + pos = mev->globalPos(); + part = findPartFromWidget( w, pos ); + } else + part = findPartFromWidget( w ); + +#ifdef DEBUG_PARTMANAGER + TQCString evType = ( ev->type() == TQEvent::MouseButtonPress ) ? "MouseButtonPress" + : ( ev->type() == TQEvent::MouseButtonDblClick ) ? "MouseButtonDblClick" + : ( ev->type() == TQEvent::FocusIn ) ? "FocusIn" : "OTHER! ERROR!"; +#endif + if ( part ) // We found a part whose widget is w + { + if ( d->m_policy == PartManager::TriState ) + { + if ( ev->type() == TQEvent::MouseButtonDblClick ) + { + if ( part == d->m_activePart && w == d->m_activeWidget ) + return false; + +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "PartManager::eventFilter dblclick -> setActivePart" << part << endl; +#endif + d->setReason( ev ); + setActivePart( part, w ); + d->m_reason = NoReason; + return true; + } + + if ( ( d->m_selectedWidget != w || d->m_selectedPart != part ) && + ( d->m_activeWidget != w || d->m_activePart != part ) ) + { + if ( part->isSelectable() ) + setSelectedPart( part, w ); + else { +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "Part " << part << " (non-selectable) made active because " << w->className() << " got event" << " " << evType << endl; +#endif + d->setReason( ev ); + setActivePart( part, w ); + d->m_reason = NoReason; + } + return true; + } + else if ( d->m_selectedWidget == w && d->m_selectedPart == part ) + { +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "Part " << part << " made active (from selected) because " << w->className() << " got event" << " " << evType << endl; +#endif + d->setReason( ev ); + setActivePart( part, w ); + d->m_reason = NoReason; + return true; + } + else if ( d->m_activeWidget == w && d->m_activePart == part ) + { + setSelectedPart( 0L ); + return false; + } + + return false; + } + else if ( part != d->m_activePart ) + { +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "Part " << part << " made active because " << w->className() << " got event" << " " << evType << endl; +#endif + d->setReason( ev ); + setActivePart( part, w ); + d->m_reason = NoReason; + } + + return false; + } + + w = w->parentWidget(); + + if ( w && ( ( w->testWFlags( WType_Dialog ) && w->isModal() ) || + w->testWFlags( WType_Popup ) || w->testWFlags( WStyle_Tool ) ) ) + { +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << TQString("No part made active although %1/%2 got event - loop aborted").arg(obj->name()).arg(obj->className()) << endl; +#endif + return false; + } + + } + +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << TQString("No part made active although %1/%2 got event").arg(obj->name()).arg(obj->className()) << endl; +#endif + return false; +} + +Part * PartManager::findPartFromWidget( TQWidget * widget, const TQPoint &pos ) +{ + TQPtrListIterator<Part> it ( d->m_parts ); + for ( ; it.current() ; ++it ) + { + Part *part = it.current()->hitTest( widget, pos ); + if ( part && d->m_parts.findRef( part ) != -1 ) + return part; + } + return 0L; +} + +Part * PartManager::findPartFromWidget( TQWidget * widget ) +{ + TQPtrListIterator<Part> it ( d->m_parts ); + for ( ; it.current() ; ++it ) + { + if ( widget == it.current()->widget() ) + return it.current(); + } + return 0L; +} + +void PartManager::addPart( Part *part, bool setActive ) +{ + if ( d->m_parts.findRef( part ) != -1 ) // don't add parts more than once :) + { +#ifdef DEBUG_PARTMANAGER + kdWarning(1000) << k_funcinfo << part << " already added" << kdBacktrace(5) << endl; +#endif + return; + } + + d->m_parts.append( part ); + + part->setManager( this ); + + if ( setActive ) + { + setActivePart( part ); + if ( part->widget() ) + part->widget()->setFocus(); + } + + // Prevent focus problems + if ( part->widget() && part->widget()->focusPolicy() == TQ_NoFocus ) + { + 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; + } + if ( part->widget() && part->widget()->focusPolicy() == TQ_TabFocus ) + { + 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; + } + + if ( setActive && part->widget() ) + part->widget()->show(); + emit partAdded( part ); +} + +void PartManager::removePart( Part *part ) +{ + if ( d->m_parts.findRef( part ) == -1 ) + { + kdFatal(1000) << TQString(TQString("Can't remove part %1, not in KPartManager's list.").arg(part->name())) << endl; + return; + } + + //Warning. The part could be already deleted + //kdDebug(1000) << TQString("Part %1 removed").arg(part->name()) << endl; + int nb = d->m_parts.count(); + bool ok = d->m_parts.removeRef( part ); + Q_ASSERT( ok ); + Q_ASSERT( (int)d->m_parts.count() == nb-1 ); + part->setManager(0); + + emit partRemoved( part ); + + if ( part == d->m_activePart ) + setActivePart( 0 ); + if ( part == d->m_selectedPart ) + setSelectedPart( 0 ); +} + +void PartManager::replacePart( Part * oldPart, Part * newPart, bool setActive ) +{ + //kdDebug(1000) << "replacePart " << oldPart->name() << "-> " << newPart->name() << " setActive=" << setActive << endl; + // This methods does exactly removePart + addPart but without calling setActivePart(0) in between + if ( d->m_parts.findRef( oldPart ) == -1 ) + { + kdFatal(1000) << TQString(TQString("Can't remove part %1, not in KPartManager's list.").arg(oldPart->name())) << endl; + return; + } + + d->m_parts.removeRef( oldPart ); + oldPart->setManager(0); + + emit partRemoved( oldPart ); + + addPart( newPart, setActive ); +} + +void PartManager::setActivePart( Part *part, TQWidget *widget ) +{ + if ( part && d->m_parts.findRef( part ) == -1 ) + { + kdWarning( 1000 ) << "PartManager::setActivePart : trying to activate a non-registered part! " << part->name() << endl; + return; // don't allow someone call setActivePart with a part we don't know about + } + + //check whether nested parts are disallowed and activate the top parent part then, by traversing the + //tree recursively (Simon) + if ( part && !d->m_bAllowNestedParts ) + { + TQObject *parentPart = TQT_TQOBJECT(part->parent()); // ### this relies on people using KParts::Factory! + if ( parentPart && parentPart->inherits( "KParts::Part" ) ) + { + KParts::Part *parPart = static_cast<KParts::Part *>( parentPart ); + setActivePart( parPart, parPart->widget() ); + return; + } + } + +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "PartManager::setActivePart d->m_activePart=" << d->m_activePart << "<->part=" << part + << " d->m_activeWidget=" << d->m_activeWidget << "<->widget=" << widget << endl; +#endif + + // don't activate twice + if ( d->m_activePart && part && d->m_activePart == part && + (!widget || d->m_activeWidget == widget) ) + return; + + KParts::Part *oldActivePart = d->m_activePart; + TQWidget *oldActiveWidget = d->m_activeWidget; + + setSelectedPart( 0L ); + + d->m_activePart = part; + d->m_activeWidget = widget; + + if ( oldActivePart ) + { + KParts::Part *savedActivePart = part; + TQWidget *savedActiveWidget = widget; + + PartActivateEvent ev( false, oldActivePart, oldActiveWidget ); + TQApplication::sendEvent( oldActivePart, &ev ); + if ( oldActiveWidget ) + { + disconnect( oldActiveWidget, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotWidgetDestroyed() ) ); + TQApplication::sendEvent( oldActiveWidget, &ev ); + } + + d->m_activePart = savedActivePart; + d->m_activeWidget = savedActiveWidget; + } + + if ( d->m_activePart ) + { + if ( !widget ) + d->m_activeWidget = part->widget(); + + PartActivateEvent ev( true, d->m_activePart, d->m_activeWidget ); + TQApplication::sendEvent( d->m_activePart, &ev ); + if ( d->m_activeWidget ) + { + connect( d->m_activeWidget, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotWidgetDestroyed() ) ); + TQApplication::sendEvent( d->m_activeWidget, &ev ); + } + } + // Set the new active instance in TDEGlobal + setActiveInstance( d->m_activePart ? d->m_activePart->instance() : 0L ); + + kdDebug(1000) << this << " emitting activePartChanged " << d->m_activePart << endl; + emit activePartChanged( d->m_activePart ); +} + +void PartManager::setActiveInstance( TDEInstance * instance ) +{ + // It's a separate method to allow redefining this behavior + TDEGlobal::_activeInstance = instance; +} + +Part *PartManager::activePart() const +{ + return d->m_activePart; +} + +TQWidget *PartManager::activeWidget() const +{ + return d->m_activeWidget; +} + +void PartManager::setSelectedPart( Part *part, TQWidget *widget ) +{ + if ( part == d->m_selectedPart && widget == d->m_selectedWidget ) + return; + + Part *oldPart = d->m_selectedPart; + TQWidget *oldWidget = d->m_selectedWidget; + + d->m_selectedPart = part; + d->m_selectedWidget = widget; + + if ( part && !widget ) + d->m_selectedWidget = part->widget(); + + if ( oldPart ) + { + PartSelectEvent ev( false, oldPart, oldWidget ); + TQApplication::sendEvent( oldPart, &ev ); + TQApplication::sendEvent( oldWidget, &ev ); + } + + if ( d->m_selectedPart ) + { + PartSelectEvent ev( true, d->m_selectedPart, d->m_selectedWidget ); + TQApplication::sendEvent( d->m_selectedPart, &ev ); + TQApplication::sendEvent( d->m_selectedWidget, &ev ); + } +} + +Part *PartManager::selectedPart() const +{ + return d->m_selectedPart; +} + +TQWidget *PartManager::selectedWidget() const +{ + return d->m_selectedWidget; +} + +void PartManager::slotObjectDestroyed() +{ + kdDebug(1000) << "KPartManager::slotObjectDestroyed()" << endl; + removePart( const_cast<Part *>( static_cast<const Part *>( sender() ) ) ); +} + +void PartManager::slotWidgetDestroyed() +{ + kdDebug(1000) << "KPartsManager::slotWidgetDestroyed()" << endl; + if ( static_cast<const TQWidget *>( sender() ) == d->m_activeWidget ) + setActivePart( 0L ); //do not remove the part because if the part's widget dies, then the + //part will delete itself anyway, invoking removePart() in its destructor +} + +const TQPtrList<Part> *PartManager::parts() const +{ + return &d->m_parts; +} + +void PartManager::addManagedTopLevelWidget( const TQWidget *topLevel ) +{ + if ( !topLevel->isTopLevel() ) + return; + + if ( d->m_managedTopLevelWidgets.containsRef( topLevel ) ) + return; + + d->m_managedTopLevelWidgets.append( topLevel ); + connect( topLevel, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotManagedTopLevelWidgetDestroyed() ) ); +} + +void PartManager::removeManagedTopLevelWidget( const TQWidget *topLevel ) +{ + if ( !topLevel->isTopLevel() ) + return; + + if ( d->m_managedTopLevelWidgets.findRef( topLevel ) == -1 ) + return; + + d->m_managedTopLevelWidgets.remove(); +} + +void PartManager::slotManagedTopLevelWidgetDestroyed() +{ + const TQWidget *widget = static_cast<const TQWidget *>( sender() ); + removeManagedTopLevelWidget( widget ); +} + +int PartManager::reason() const +{ + return d->m_reason; +} + +void PartManager::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +#include "partmanager.moc" |