• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.5 API Reference
  • KDE Home
  • Contact Us
 

KParts

  • kparts
partmanager.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE project
2  Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
3  (C) 1999 David Faure <faure@kde.org>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "partmanager.h"
22 #include <kparts/event.h>
23 #include <kparts/part.h>
24 #include <kglobal.h>
25 #include <kdebug.h>
26 
27 #include <QtGui/QApplication>
28 #include <QtGui/QScrollBar>
29 #include <kcomponentdata.h>
30 
31 //#define DEBUG_PARTMANAGER
32 
33 using namespace KParts;
34 
35 namespace KParts {
36 
37 class PartManagerPrivate
38 {
39 public:
40  PartManagerPrivate()
41  {
42  m_activeWidget = 0;
43  m_activePart = 0;
44  m_selectedPart = 0;
45  m_selectedWidget = 0;
46  m_bAllowNestedParts = false;
47  m_bIgnoreScrollBars = false;
48  m_activationButtonMask = Qt::LeftButton | Qt::MidButton | Qt::RightButton;
49  m_reason = PartManager::NoReason;
50  }
51  ~PartManagerPrivate()
52  {
53  }
54  void setReason( QEvent* ev ) {
55  switch( ev->type() ) {
56  case QEvent::MouseButtonPress:
57  case QEvent::MouseButtonDblClick: {
58  QMouseEvent* mev = static_cast<QMouseEvent *>( ev );
59  m_reason = mev->button() == Qt::LeftButton
60  ? PartManager::ReasonLeftClick
61  : ( mev->button() == Qt::MidButton
62  ? PartManager::ReasonMidClick
63  : PartManager::ReasonRightClick );
64  break;
65  }
66  case QEvent::FocusIn:
67  m_reason = static_cast<QFocusEvent *>( ev )->reason();
68  break;
69  default:
70  kWarning(1000) << "PartManagerPrivate::setReason got unexpected ev type " << ev->type();
71  break;
72  }
73  }
74 
75  Part * m_activePart;
76  QWidget *m_activeWidget;
77 
78  QList<Part *> m_parts;
79 
80  PartManager::SelectionPolicy m_policy;
81 
82  Part *m_selectedPart;
83  QWidget *m_selectedWidget;
84 
85  QList<const QWidget *> m_managedTopLevelWidgets;
86  short int m_activationButtonMask;
87  bool m_bIgnoreScrollBars;
88  bool m_bAllowNestedParts;
89  int m_reason;
90 };
91 
92 }
93 
94 PartManager::PartManager( QWidget * parent )
95  : QObject( parent ),d(new PartManagerPrivate)
96 {
97 
98  qApp->installEventFilter( this );
99 
100  d->m_policy = Direct;
101 
102  addManagedTopLevelWidget( parent );
103 }
104 
105 PartManager::PartManager( QWidget *topLevel, QObject *parent )
106  : QObject( parent ),d(new PartManagerPrivate)
107 {
108 
109  qApp->installEventFilter( this );
110 
111  d->m_policy = Direct;
112 
113  addManagedTopLevelWidget( topLevel );
114 }
115 
116 PartManager::~PartManager()
117 {
118  foreach( const QWidget* w, d->m_managedTopLevelWidgets )
119  {
120  disconnect( w, SIGNAL(destroyed()),
121  this, SLOT(slotManagedTopLevelWidgetDestroyed()) );
122  }
123 
124  foreach( Part* it, d->m_parts )
125  {
126  it->setManager( 0 );
127  }
128 
129  // core dumps ... setActivePart( 0 );
130  qApp->removeEventFilter( this );
131  delete d;
132 }
133 
134 void PartManager::setSelectionPolicy( SelectionPolicy policy )
135 {
136  d->m_policy = policy;
137 }
138 
139 PartManager::SelectionPolicy PartManager::selectionPolicy() const
140 {
141  return d->m_policy;
142 }
143 
144 void PartManager::setAllowNestedParts( bool allow )
145 {
146  d->m_bAllowNestedParts = allow;
147 }
148 
149 bool PartManager::allowNestedParts() const
150 {
151  return d->m_bAllowNestedParts;
152 }
153 
154 void PartManager::setIgnoreScrollBars( bool ignore )
155 {
156  d->m_bIgnoreScrollBars = ignore;
157 }
158 
159 bool PartManager::ignoreScrollBars() const
160 {
161  return d->m_bIgnoreScrollBars;
162 }
163 
164 void PartManager::setActivationButtonMask( short int buttonMask )
165 {
166  d->m_activationButtonMask = buttonMask;
167 }
168 
169 short int PartManager::activationButtonMask() const
170 {
171  return d->m_activationButtonMask;
172 }
173 
174 bool PartManager::eventFilter( QObject *obj, QEvent *ev )
175 {
176 
177  if ( ev->type() != QEvent::MouseButtonPress &&
178  ev->type() != QEvent::MouseButtonDblClick &&
179  ev->type() != QEvent::FocusIn )
180  return false;
181 
182  if ( !obj->isWidgetType() )
183  return false;
184 
185  QWidget *w = static_cast<QWidget *>( obj );
186 
187  if ( ( ( w->windowFlags().testFlag(Qt::Dialog) ) && w->isModal() ) ||
188  ( w->windowFlags().testFlag(Qt::Popup) ) || ( w->windowFlags().testFlag(Qt::Tool) ) )
189  return false;
190 
191  QMouseEvent* mev = 0;
192  if ( ev->type() == QEvent::MouseButtonPress || ev->type() == QEvent::MouseButtonDblClick )
193  {
194  mev = static_cast<QMouseEvent *>( ev );
195 #ifdef DEBUG_PARTMANAGER
196  kDebug(1000) << "PartManager::eventFilter button: " << mev->button() << " " << "d->m_activationButtonMask=" << d->m_activationButtonMask;
197 #endif
198  if ( ( mev->button() & d->m_activationButtonMask ) == 0 )
199  return false; // ignore this button
200  }
201 
202  Part * part;
203  while ( w )
204  {
205  QPoint pos;
206 
207  if ( !d->m_managedTopLevelWidgets.contains( w->topLevelWidget() ) )
208  return false;
209 
210  if ( d->m_bIgnoreScrollBars && ::qobject_cast<QScrollBar *>(w) )
211  return false;
212 
213  if ( mev ) // mouse press or mouse double-click event
214  {
215  pos = mev->globalPos();
216  part = findPartFromWidget( w, pos );
217  } else
218  part = findPartFromWidget( w );
219 
220 #ifdef DEBUG_PARTMANAGER
221  const char* evType = ( ev->type() == QEvent::MouseButtonPress ) ? "MouseButtonPress"
222  : ( ev->type() == QEvent::MouseButtonDblClick ) ? "MouseButtonDblClick"
223  : ( ev->type() == QEvent::FocusIn ) ? "FocusIn" : "OTHER! ERROR!";
224 #endif
225  if ( part ) // We found a part whose widget is w
226  {
227  if ( d->m_policy == PartManager::TriState )
228  {
229  if ( ev->type() == QEvent::MouseButtonDblClick )
230  {
231  if ( part == d->m_activePart && w == d->m_activeWidget )
232  return false;
233 
234 #ifdef DEBUG_PARTMANAGER
235  kDebug(1000) << "PartManager::eventFilter dblclick -> setActivePart" << part;
236 #endif
237  d->setReason( ev );
238  setActivePart( part, w );
239  d->m_reason = NoReason;
240  return true;
241  }
242 
243  if ( ( d->m_selectedWidget != w || d->m_selectedPart != part ) &&
244  ( d->m_activeWidget != w || d->m_activePart != part ) )
245  {
246  if ( part->isSelectable() )
247  setSelectedPart( part, w );
248  else {
249 #ifdef DEBUG_PARTMANAGER
250  kDebug(1000) << "Part " << part << " (non-selectable) made active because " << w->metaObject()->className() << " got event" << " " << evType;
251 #endif
252  d->setReason( ev );
253  setActivePart( part, w );
254  d->m_reason = NoReason;
255  }
256  return true;
257  }
258  else if ( d->m_selectedWidget == w && d->m_selectedPart == part )
259  {
260 #ifdef DEBUG_PARTMANAGER
261  kDebug(1000) << "Part " << part << " made active (from selected) because " << w->metaObject()->className() << " got event" << " " << evType;
262 #endif
263  d->setReason( ev );
264  setActivePart( part, w );
265  d->m_reason = NoReason;
266  return true;
267  }
268  else if ( d->m_activeWidget == w && d->m_activePart == part )
269  {
270  setSelectedPart( 0 );
271  return false;
272  }
273 
274  return false;
275  }
276  else if ( part != d->m_activePart )
277  {
278 #ifdef DEBUG_PARTMANAGER
279  kDebug(1000) << "Part " << part << " made active because " << w->metaObject()->className() << " got event" << " " << evType;
280 #endif
281  d->setReason( ev );
282  setActivePart( part, w );
283  d->m_reason = NoReason;
284  }
285 
286  return false;
287  }
288 
289  w = w->parentWidget();
290 
291  if ( w && ( ( ( w->windowFlags() & Qt::Dialog ) && w->isModal() ) ||
292  ( w->windowFlags() & Qt::Popup ) || ( w->windowFlags() & Qt::Tool ) ) )
293  {
294 #ifdef DEBUG_PARTMANAGER
295  kDebug(1000) << QString("No part made active although %1/%2 got event - loop aborted").arg(obj->objectName()).arg(obj->metaObject()->className());
296 #endif
297  return false;
298  }
299 
300  }
301 
302 #ifdef DEBUG_PARTMANAGER
303  kDebug(1000) << QString("No part made active although %1/%2 got event").arg(obj->objectName()).arg(obj->metaObject()->className());
304 #endif
305  return false;
306 }
307 
308 Part * PartManager::findPartFromWidget( QWidget * widget, const QPoint &pos )
309 {
310  for ( QList<Part *>::iterator it = d->m_parts.begin(), end = d->m_parts.end() ; it != end ; ++it )
311  {
312  Part *part = (*it)->hitTest( widget, pos );
313  if ( part && d->m_parts.contains( part ) )
314  return part;
315  }
316  return 0;
317 }
318 
319 Part * PartManager::findPartFromWidget( QWidget * widget )
320 {
321  for ( QList<Part *>::iterator it = d->m_parts.begin(), end = d->m_parts.end() ; it != end ; ++it )
322  {
323  if ( widget == (*it)->widget() )
324  return (*it);
325  }
326  return 0;
327 }
328 
329 void PartManager::addPart( Part *part, bool setActive )
330 {
331  Q_ASSERT( part );
332 
333  // don't add parts more than once :)
334  if ( d->m_parts.contains( part ) ) {
335 #ifdef DEBUG_PARTMANAGER
336  kWarning(1000) << part << " already added" << kBacktrace(5);
337 #endif
338  return;
339  }
340 
341  d->m_parts.append( part );
342 
343  part->setManager( this );
344 
345  if ( setActive ) {
346  setActivePart( part );
347 
348  if ( QWidget *w = part->widget() ) {
349  // Prevent focus problems
350  if ( w->focusPolicy() == Qt::NoFocus ) {
351  kWarning(1000) << "Part '" << part->objectName() << "' has a widget "
352  << w->objectName() << " with a focus policy of NoFocus. It should have at least a"
353  << "ClickFocus policy, for part activation to work well." << endl;
354  }
355  if ( part->widget() && part->widget()->focusPolicy() == Qt::TabFocus ) {
356  kWarning(1000) << "Part '" << part->objectName() << "' has a widget "
357  << w->objectName() << " with a focus policy of TabFocus. It should have at least a"
358  << "ClickFocus policy, for part activation to work well." << endl;
359  }
360  w->setFocus();
361  w->show();
362  }
363  }
364  emit partAdded( part );
365 }
366 
367 void PartManager::removePart( Part *part )
368 {
369  if (!d->m_parts.contains(part)) {
370  return;
371  }
372 
373  const int nb = d->m_parts.removeAll(part);
374  Q_ASSERT(nb == 1);
375  Q_UNUSED(nb); // no warning in release mode
376  part->setManager(0);
377 
378  emit partRemoved( part );
379 
380  if ( part == d->m_activePart )
381  setActivePart( 0 );
382  if ( part == d->m_selectedPart )
383  setSelectedPart( 0 );
384 }
385 
386 void PartManager::replacePart( Part * oldPart, Part * newPart, bool setActive )
387 {
388  //kDebug(1000) << "replacePart " << oldPart->name() << "-> " << newPart->name() << " setActive=" << setActive;
389  // This methods does exactly removePart + addPart but without calling setActivePart(0) in between
390  if ( !d->m_parts.contains( oldPart ) )
391  {
392  kFatal(1000) << QString("Can't remove part %1, not in KPartManager's list.").arg(oldPart->objectName());
393  return;
394  }
395 
396  d->m_parts.removeAll( oldPart );
397  oldPart->setManager(0);
398 
399  emit partRemoved( oldPart );
400 
401  addPart( newPart, setActive );
402 }
403 
404 void PartManager::setActivePart( Part *part, QWidget *widget )
405 {
406  if ( part && !d->m_parts.contains( part ) )
407  {
408  kWarning(1000) << "trying to activate a non-registered part!" << part->objectName();
409  return; // don't allow someone call setActivePart with a part we don't know about
410  }
411 
412  //check whether nested parts are disallowed and activate the top parent part then, by traversing the
413  //tree recursively (Simon)
414  if ( part && !d->m_bAllowNestedParts )
415  {
416  QObject *parentPart = part->parent(); // ### this relies on people using KParts::Factory!
417  KParts::Part *parPart = ::qobject_cast<KParts::Part *>( parentPart );
418  if ( parPart )
419  {
420  setActivePart( parPart, parPart->widget() );
421  return;
422  }
423  }
424 
425 #ifdef DEBUG_PARTMANAGER
426  kDebug(1000) << "PartManager::setActivePart d->m_activePart=" << d->m_activePart << "<->part=" << part
427  << " d->m_activeWidget=" << d->m_activeWidget << "<->widget=" << widget << endl;
428 #endif
429 
430  // don't activate twice
431  if ( d->m_activePart && part && d->m_activePart == part &&
432  (!widget || d->m_activeWidget == widget) )
433  return;
434 
435  KParts::Part *oldActivePart = d->m_activePart;
436  QWidget *oldActiveWidget = d->m_activeWidget;
437 
438  setSelectedPart( 0 );
439 
440  d->m_activePart = part;
441  d->m_activeWidget = widget;
442 
443  if ( oldActivePart )
444  {
445  KParts::Part *savedActivePart = part;
446  QWidget *savedActiveWidget = widget;
447 
448  PartActivateEvent ev( false, oldActivePart, oldActiveWidget );
449  QApplication::sendEvent( oldActivePart, &ev );
450  if ( oldActiveWidget )
451  {
452  disconnect( oldActiveWidget, SIGNAL(destroyed()),
453  this, SLOT(slotWidgetDestroyed()) );
454  QApplication::sendEvent( oldActiveWidget, &ev );
455  }
456 
457  d->m_activePart = savedActivePart;
458  d->m_activeWidget = savedActiveWidget;
459  }
460 
461  if ( d->m_activePart )
462  {
463  if ( !widget )
464  d->m_activeWidget = part->widget();
465 
466  PartActivateEvent ev( true, d->m_activePart, d->m_activeWidget );
467  QApplication::sendEvent( d->m_activePart, &ev );
468  if ( d->m_activeWidget )
469  {
470  connect( d->m_activeWidget, SIGNAL(destroyed()),
471  this, SLOT(slotWidgetDestroyed()) );
472  QApplication::sendEvent( d->m_activeWidget, &ev );
473  }
474  }
475  // Set the new active instance in KGlobal
476  setActiveComponent(d->m_activePart ? d->m_activePart->componentData() : KGlobal::mainComponent());
477 
478 #ifdef DEBUG_PARTMANAGER
479  kDebug(1000) << this << " emitting activePartChanged " << d->m_activePart;
480 #endif
481  emit activePartChanged( d->m_activePart );
482 }
483 
484 void PartManager::setActiveComponent(const KComponentData &instance)
485 {
486  // It's a separate method to allow redefining this behavior
487  KGlobal::setActiveComponent(instance);
488 }
489 
490 Part *PartManager::activePart() const
491 {
492  return d->m_activePart;
493 }
494 
495 QWidget *PartManager::activeWidget() const
496 {
497  return d->m_activeWidget;
498 }
499 
500 void PartManager::setSelectedPart( Part *part, QWidget *widget )
501 {
502  if ( part == d->m_selectedPart && widget == d->m_selectedWidget )
503  return;
504 
505  Part *oldPart = d->m_selectedPart;
506  QWidget *oldWidget = d->m_selectedWidget;
507 
508  d->m_selectedPart = part;
509  d->m_selectedWidget = widget;
510 
511  if ( part && !widget )
512  d->m_selectedWidget = part->widget();
513 
514  if ( oldPart )
515  {
516  PartSelectEvent ev( false, oldPart, oldWidget );
517  QApplication::sendEvent( oldPart, &ev );
518  QApplication::sendEvent( oldWidget, &ev );
519  }
520 
521  if ( d->m_selectedPart )
522  {
523  PartSelectEvent ev( true, d->m_selectedPart, d->m_selectedWidget );
524  QApplication::sendEvent( d->m_selectedPart, &ev );
525  QApplication::sendEvent( d->m_selectedWidget, &ev );
526  }
527 }
528 
529 Part *PartManager::selectedPart() const
530 {
531  return d->m_selectedPart;
532 }
533 
534 QWidget *PartManager::selectedWidget() const
535 {
536  return d->m_selectedWidget;
537 }
538 
539 void PartManager::slotObjectDestroyed()
540 {
541  kDebug(1000);
542  removePart( const_cast<Part *>( static_cast<const Part *>( sender() ) ) );
543 }
544 
545 void PartManager::slotWidgetDestroyed()
546 {
547  kDebug(1000);
548  if ( static_cast<const QWidget *>( sender() ) == d->m_activeWidget )
549  setActivePart( 0 ); //do not remove the part because if the part's widget dies, then the
550  //part will delete itself anyway, invoking removePart() in its destructor
551 }
552 
553 const QList<Part *> PartManager::parts() const
554 {
555  return d->m_parts;
556 }
557 
558 void PartManager::addManagedTopLevelWidget( const QWidget *topLevel )
559 {
560  if ( !topLevel->isTopLevel() )
561  return;
562 
563  if ( d->m_managedTopLevelWidgets.contains( topLevel ) )
564  return;
565 
566  d->m_managedTopLevelWidgets.append( topLevel );
567  connect( topLevel, SIGNAL(destroyed()),
568  this, SLOT(slotManagedTopLevelWidgetDestroyed()) );
569 }
570 
571 void PartManager::removeManagedTopLevelWidget( const QWidget *topLevel )
572 {
573  if ( !topLevel->isTopLevel() )
574  return;
575 
576  d->m_managedTopLevelWidgets.removeAll( topLevel );
577 }
578 
579 void PartManager::slotManagedTopLevelWidgetDestroyed()
580 {
581  const QWidget *widget = static_cast<const QWidget *>( sender() );
582  removeManagedTopLevelWidget( widget );
583 }
584 
585 int PartManager::reason() const
586 {
587  return d->m_reason;
588 }
589 
590 #include "partmanager.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Thu Feb 21 2013 11:12:38 by doxygen 1.8.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KParts

Skip menu "KParts"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.8.5 API Reference

Skip menu "kdelibs-4.8.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal