1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File: QtxWorkstack.cxx
24 // Author: Sergey TELKOV
26 #include "QtxWorkstack.h"
28 #include "QtxAction.h"
35 #include <QDataStream>
36 #include <QFocusEvent>
37 #include <QMouseEvent>
38 #include <QRubberBand>
39 #include <QApplication>
40 #include <QStyleOption>
41 #include <QInputDialog>
42 #include <QStackedWidget>
43 #include <QAbstractButton>
46 \class QtxWorkstackArea::WidgetEvent
48 \brief Internal class used to forward child widgets events to the workarea
51 class QtxWorkstackArea::WidgetEvent : public QEvent
54 WidgetEvent( Type t, QtxWorkstackChild* w = 0 ) : QEvent( t ), myChild( w ) {};
56 QtxWorkstackChild* child() const { return myChild; }
59 QtxWorkstackChild* myChild; // event receiver widget
63 \class QtxWorkstackArea::RestoreEvent
65 \brief Internal class used to forward restore info events to the workarea
68 class QtxWorkstackArea::RestoreEvent : public QtxWorkstackArea::WidgetEvent
71 RestoreEvent( Type t, int id, int f, QtxWorkstackChild* w )
72 : WidgetEvent( t, w ), myId( id ), myFlags( f ) {};
74 int id() const { return myId; }
75 int flags() const { return myFlags; }
83 \class QtxWorkstackDrag
85 \brief Workstack drag object
90 \param ws parent workstack
91 \param child child widget container
93 QtxWorkstackDrag::QtxWorkstackDrag( QtxWorkstack* ws, QtxWorkstackChild* child )
102 QApplication::instance()->installEventFilter( this );
108 QtxWorkstackDrag::~QtxWorkstackDrag()
110 QApplication::instance()->removeEventFilter( this );
116 \brief Custom event filter.
117 \param o event receiver widget
119 \return \c true if event should be filtered (stop further processing)
121 bool QtxWorkstackDrag::eventFilter( QObject*, QEvent* e )
125 case QEvent::MouseMove:
126 updateTarget( ((QMouseEvent*)e)->globalPos() );
128 case QEvent::MouseButtonRelease:
141 \brief Detect and set dropping target widget.
142 \param p current dragging position
144 void QtxWorkstackDrag::updateTarget( const QPoint& p )
147 QtxWorkstackArea* area = detectTarget( p, tab );
148 setTarget( area, tab );
152 \brief Detect dropping target.
153 \param p current dragging position
154 \param tab resulting target tab page index
155 \return target workarea or 0 if there is no correct drop target
157 QtxWorkstackArea* QtxWorkstackDrag::detectTarget( const QPoint& p, int& tab ) const
162 QtxWorkstackArea* area = myWS->areaAt( p );
164 tab = area->tabAt( p );
169 \brief Set dropping target.
170 \param area new target workarea
171 \param tab target workarea's tab page index
173 void QtxWorkstackDrag::setTarget( QtxWorkstackArea* area, const int tab )
175 if ( !area || ( myArea == area && tab == myTab ) )
191 \brief Called when drop operation is finished.
193 Inserts dropped widget to the target workarea.
195 void QtxWorkstackDrag::dropWidget()
198 myArea->insertChild( myChild, myTab );
202 \brief Draw floating rectangle.
204 void QtxWorkstackDrag::drawRect()
209 QRect r = myArea->floatRect();
212 r.setTop( r.top() + m + 2 );
213 r.setLeft( r.left() + m + 2 );
214 r.setRight( r.right() - m - 2 );
215 r.setBottom( r.bottom() - m - 2 );
219 myAreaRect->setGeometry( r );
220 myAreaRect->setVisible( r.isValid() );
223 QRect tr = myArea->floatTab( myTab );
225 tr.setTop( tr.top() + m );
226 tr.setLeft( tr.left() + m );
227 tr.setRight( tr.right() - m );
228 tr.setBottom( tr.bottom() - m );
232 myTabRect->setGeometry( tr );
233 myTabRect->setVisible( tr.isValid() );
238 \brief Delete rubber band on the end on the dragging operation.
240 void QtxWorkstackDrag::endDrawRect()
250 \brief Create rubber band to be drawn on the dragging operation.
252 void QtxWorkstackDrag::startDrawRect()
255 myTabRect = new QRubberBand( QRubberBand::Rectangle );
260 myAreaRect = new QRubberBand( QRubberBand::Rectangle );
268 \brief Workstack area close button.
271 class CloseButton : public QAbstractButton
274 CloseButton( QWidget* );
276 QSize sizeHint() const;
277 QSize minimumSizeHint() const;
279 void enterEvent( QEvent* );
280 void leaveEvent( QEvent* );
281 void paintEvent( QPaintEvent* );
287 \param parent parent widget
289 CloseButton::CloseButton( QWidget* parent )
290 : QAbstractButton( parent )
292 setFocusPolicy( Qt::NoFocus );
296 \brief Get appropriate size for the button.
300 QSize CloseButton::sizeHint() const
304 if( !icon().isNull() )
306 const QPixmap pm = icon().pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize ),
308 dim = qMax( pm.width(), pm.height() );
310 return QSize( dim + 4, dim + 4 );
314 \brief Get minimum appropriate size for the button.
316 \return minimum size value
318 QSize CloseButton::minimumSizeHint() const
324 \brief Process mouse enter event.
326 \param event mouse enter event
328 void CloseButton::enterEvent( QEvent *event )
332 QAbstractButton::enterEvent( event );
336 \brief Process mouse leave event.
338 \param event mouse leave event
340 void CloseButton::leaveEvent( QEvent *event )
344 QAbstractButton::leaveEvent( event );
348 \brief Process paint event.
350 \param event paint event
352 void CloseButton::paintEvent( QPaintEvent* )
359 opt.state |= QStyle::State_AutoRaise;
360 if ( isEnabled() && underMouse() && !isChecked() && !isDown() )
361 opt.state |= QStyle::State_Raised;
363 opt.state |= QStyle::State_On;
365 opt.state |= QStyle::State_Sunken;
366 style()->drawPrimitive( QStyle::PE_PanelButtonTool, &opt, &p, this );
368 int shiftHorizontal = opt.state & QStyle::State_Sunken ? style()->pixelMetric( QStyle::PM_ButtonShiftHorizontal, &opt, this ) : 0;
369 int shiftVertical = opt.state & QStyle::State_Sunken ? style()->pixelMetric( QStyle::PM_ButtonShiftVertical, &opt, this ) : 0;
371 r.adjust( 2, 2, -2, -2 );
372 r.translate( shiftHorizontal, shiftVertical );
374 QPixmap pm = icon().pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize ), isEnabled() ?
375 underMouse() ? QIcon::Active : QIcon::Normal
377 isDown() ? QIcon::On : QIcon::Off );
378 style()->drawItemPixmap( &p, r, Qt::AlignCenter, pm );
383 \class QtxWorkstackSplitter
385 \brief Workstack splitter.
390 \param parent parent widget
392 QtxWorkstackSplitter::QtxWorkstackSplitter( QWidget* parent )
393 : QSplitter( parent )
395 setChildrenCollapsible( false );
401 QtxWorkstackSplitter::~QtxWorkstackSplitter()
406 \brief Get parent workstack
407 \return workstack owning this workarea
409 QtxWorkstack* QtxWorkstackSplitter::workstack() const
411 QtxWorkstack* ws = 0;
412 QWidget* wid = parentWidget();
415 ws = ::qobject_cast<QtxWorkstack*>( wid );
416 wid = wid->parentWidget();
422 \brief Save the widget area configuration into data stream.
424 void QtxWorkstackSplitter::saveState( QDataStream& stream ) const
426 stream << QtxWorkstack::SplitMarker;
429 if ( orientation() == Qt::Horizontal )
430 flags |= QtxWorkstack::Horizontal;
435 QList<int> sz = sizes();
436 for ( QList<int>::const_iterator it = sz.begin(); it != sz.end(); ++it )
439 for ( int i = 0; i < count(); i++ )
441 QWidget* wid = widget( i );
442 QtxWorkstackSplitter* split = ::qobject_cast<QtxWorkstackSplitter*>( wid );
444 split->saveState( stream );
447 QtxWorkstackArea* area = ::qobject_cast<QtxWorkstackArea*>( wid );
449 area->saveState( stream );
455 \brief Restore the widget area configuration from data stream info.
456 \return \c true in successful case.
458 bool QtxWorkstackSplitter::restoreState( QDataStream& stream, QMap<QString, QtxWorkstackChild*>& map )
466 setOrientation( flags & QtxWorkstack::Horizontal ? Qt::Horizontal : Qt::Vertical );
469 for ( int s = 0; s < num; s++ )
477 for ( int i = 0; i < num && ok; i++ )
482 if ( stream.status() != QDataStream::Ok )
485 if ( marker == QtxWorkstack::SplitMarker )
487 QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this );
489 split->setVisible( true );
491 ok = split->restoreState( stream, map );
493 else if ( marker == QtxWorkstack::AreaMarker )
495 QtxWorkstack* ws = workstack();
496 QtxWorkstackArea* area = ws->createArea( this );
498 area->setVisible( true );
500 ok = area->restoreState( stream, map );
513 \class QtxWorkstackArea
515 \brief Workstack widget workarea.
520 \param parent parent widget
522 QtxWorkstackArea::QtxWorkstackArea( QWidget* parent )
525 setFrameStyle( QFrame::Panel | QFrame::Sunken );
527 QVBoxLayout* base = new QVBoxLayout( this );
528 base->setMargin( frameWidth() );
529 base->setSpacing( 0 );
531 QWidget* top = new QWidget( this );
532 base->addWidget( top );
534 QHBoxLayout* tl = new QHBoxLayout( top );
537 myBar = new QtxWorkstackTabBar( top );
538 tl->addWidget( myBar, 1 );
540 CloseButton* close = new CloseButton( top );
541 close->setIcon( style()->standardIcon( QStyle::SP_TitleBarCloseButton ) );
543 tl->addWidget( myClose );
545 myStack = new QStackedWidget( this );
547 base->addWidget( myStack, 1 );
549 connect( myClose, SIGNAL( clicked() ), this, SLOT( onClose() ) );
550 connect( myBar, SIGNAL( currentChanged( int ) ), this, SLOT( onCurrentChanged( int ) ) );
551 connect( myBar, SIGNAL( dragActiveTab() ), this, SLOT( onDragActiveTab() ) );
552 connect( myBar, SIGNAL( contextMenuRequested( QPoint ) ), this, SLOT( onContextMenuRequested( QPoint ) ) );
558 QApplication::instance()->installEventFilter( this );
564 QtxWorkstackArea::~QtxWorkstackArea()
566 QApplication::instance()->removeEventFilter( this );
570 \brief Check if workarea contains any widgets.
571 \return \c true if area is null (havn't any child widgets)
573 bool QtxWorkstackArea::isNull() const
575 return myList.isEmpty();
579 \brief Check if workarea contains visible widgets.
580 \return \c true if area is empty (all child widgets are removed or now shown)
582 bool QtxWorkstackArea::isEmpty() const
585 for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !res; ++it )
586 res = (*it)->visibility();
591 \brief Add widget to the workarea.
592 \param wid widget to be added
593 \param idx position in the area widget to be added to
594 \param f widget flags
595 \return child widget container object (or 0 if index is invalid)
597 QtxWorkstackChild* QtxWorkstackArea::insertWidget( QWidget* wid, const int idx, Qt::WindowFlags f )
602 QtxWorkstackChild* c = child( wid );
604 c = new QtxWorkstackChild( wid, myStack, f );
606 insertChild( c, idx );
611 void QtxWorkstackArea::insertChild( QtxWorkstackChild* child, const int idx )
616 QtxWorkstackArea* a = child->area();
617 if ( a && a != this )
618 a->removeChild( child, false );
620 int pos = myList.indexOf( child );
621 if ( pos != -1 && ( pos == idx || ( idx < 0 && pos == (int)myList.count() - 1 ) ) )
624 bool found = myList.contains( child );
626 myList.removeAll( child );
627 pos = idx < 0 ? myList.count() : idx;
628 myList.insert( qMin( pos, (int)myList.count() ), child );
633 for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !hasId; ++it )
634 hasId = (*it)->id() == child->id();
636 if ( hasId || child->id() < 0 )
637 child->setId( generateId() );
639 connect( child, SIGNAL( destroyed( QObject* ) ), this, SLOT( onChildDestroyed( QObject* ) ) );
640 connect( child, SIGNAL( shown( QtxWorkstackChild* ) ), this, SLOT( onChildShown( QtxWorkstackChild* ) ) );
641 connect( child, SIGNAL( hidden( QtxWorkstackChild* ) ), this, SLOT( onChildHidden( QtxWorkstackChild* ) ) );
642 connect( child, SIGNAL( activated( QtxWorkstackChild* ) ), this, SLOT( onChildActivated( QtxWorkstackChild* ) ) );
643 connect( child, SIGNAL( captionChanged( QtxWorkstackChild* ) ), this, SLOT( onChildCaptionChanged( QtxWorkstackChild* ) ) );
648 setWidgetActive( child->widget() );
649 child->widget()->setFocus();
653 \brief Create and show popup menu for the area.
654 \param p mouse pointer position at which popup menu should be shown
656 void QtxWorkstackArea::onContextMenuRequested( QPoint p )
658 const QtxWorkstackTabBar* bar = ::qobject_cast<const QtxWorkstackTabBar*>( sender() );
663 int idx = tabAt( p );
665 wid = widget( myBar->tabId( idx ) );
667 emit contextMenuRequested( wid, p );
671 \brief Remove widget from workarea.
672 \param wid widget to be removed
673 \param del if \c true the widget should be also deleted
675 void QtxWorkstackArea::removeWidget( QWidget* wid, const bool del )
677 removeChild( child( wid ), del );
681 \brief Remove child from workarea.
682 \param child child to be removed
683 \param del if \c true the widget should be also deleted
685 void QtxWorkstackArea::removeChild( QtxWorkstackChild* child, const bool del )
687 if ( !myList.contains( child ) )
690 myStack->removeWidget( child );
692 if ( myBar->indexOf( child->id() ) != -1 )
693 myBar->removeTab( myBar->indexOf( child->id() ) );
695 myList.removeAll( child );
699 else if ( child->widget() )
701 disconnect( child, SIGNAL( destroyed( QObject* ) ), this, SLOT( onChildDestroyed( QObject* ) ) );
702 disconnect( child, SIGNAL( shown( QtxWorkstackChild* ) ), this, SLOT( onChildShown( QtxWorkstackChild* ) ) );
703 disconnect( child, SIGNAL( hidden( QtxWorkstackChild* ) ), this, SLOT( onChildHidden( QtxWorkstackChild* ) ) );
704 disconnect( child, SIGNAL( activated( QtxWorkstackChild* ) ), this, SLOT( onChildActivated( QtxWorkstackChild* ) ) );
705 disconnect( child, SIGNAL( captionChanged( QtxWorkstackChild* ) ), this, SLOT( onChildCaptionChanged( QtxWorkstackChild* ) ) );
714 QList<QtxWorkstackChild*> QtxWorkstackArea::childList() const
720 \brief Get all visible child widgets.
721 \return list of visible child widgets
723 QWidgetList QtxWorkstackArea::widgetList() const
726 for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it )
728 QtxWorkstackChild* c = *it;
729 if ( c->visibility() )
730 lst.append( c->widget() );
736 \brief Get active child widget.
737 \return active widget
739 QWidget* QtxWorkstackArea::activeWidget() const
741 return widget( myBar->tabId( myBar->currentIndex() ) );
745 \brief Set active widget.
746 \param wid widget to be made active
748 void QtxWorkstackArea::setActiveWidget( QWidget* wid )
750 myBar->setCurrentIndex( myBar->indexOf( widgetId( wid ) ) );
754 \brief Check if area owns the specified widget.
755 \param wid widget to be checked
756 \return \c true if area contains widget
758 bool QtxWorkstackArea::contains( QWidget* wid ) const
764 \brief Check if workarea is active.
765 \return \c true if area is active
767 bool QtxWorkstackArea::isActive() const
769 QtxWorkstack* ws = workstack();
773 return ws->activeArea() == this;
777 \brief Update active tab bar state (active/inactive).
779 void QtxWorkstackArea::updateActiveState()
781 myBar->setActive( isActive() );
785 \brief Get parent workstack
786 \return workstack owning this workarea
788 QtxWorkstack* QtxWorkstackArea::workstack() const
790 QtxWorkstack* ws = 0;
791 QWidget* wid = parentWidget();
794 ws = ::qobject_cast<QtxWorkstack*>( wid );
795 wid = wid->parentWidget();
801 \brief Custom event filter.
803 Process events from child widgets.
805 \param o event receiver widget
807 \return \c true if event should be filtered (stop further processing)
809 bool QtxWorkstackArea::eventFilter( QObject* o, QEvent* e )
811 if ( o->isWidgetType() )
813 QWidget* wid = (QWidget*)o;
814 if ( e->type() == QEvent::FocusIn || e->type() == QEvent::MouseButtonPress )
817 while ( !ok && wid && wid != myClose )
820 wid = wid->parentWidget();
823 QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)( e->type() == QEvent::FocusIn ? ActivateWidget : FocusWidget ) ) );
830 \brief Save the own widgets configuration into data stream.
832 void QtxWorkstackArea::saveState( QDataStream& stream ) const
834 stream << QtxWorkstack::AreaMarker;
835 stream << myList.count();
836 stream << myBar->tabId( myBar->currentIndex() );
837 for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it )
839 QtxWorkstackChild* c = *it;
841 stream << QtxWorkstack::WidgetMarker;
843 stream << c->widget()->objectName();
847 if ( c->visibility() )
848 flags |= QtxWorkstack::Visible;
855 \brief Restore the widgets configuration from data stream info.
856 \return \c true in successful case.
858 bool QtxWorkstackArea::restoreState( QDataStream& stream, QMap<QString, QtxWorkstackChild*>& map )
866 QtxWorkstackChild* curChild = 0;
867 for ( int i = 0; i < num; i++ )
872 if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::WidgetMarker )
884 QtxWorkstackChild* c = map.contains( name ) ? map[name] : 0;
887 qWarning( "QtxWorkstack: Restored child widget \"%s\" not found.", (const char*)name.toLatin1() );
896 QApplication::postEvent( this, new RestoreEvent( (QEvent::Type)RestoreWidget, id, flags, c ) );
900 QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)MakeCurrent, curChild ) );
906 \brief Get rectangle to be drawn when highlighting drop area.
907 \return area drop rectangle
909 QRect QtxWorkstackArea::floatRect() const
911 QRect r = myStack->geometry();
912 return QRect( mapToGlobal( r.topLeft() ), mapToGlobal( r.bottomRight() ) );
916 \brief Get rectangle to be drawn when highlighting drop area on tab bar.
918 \return tab bar drop rectrangle
920 QRect QtxWorkstackArea::floatTab( const int idx ) const
922 QRect r = myBar->tabRect( idx );
923 return QRect( myBar->mapToGlobal( r.topLeft() ), r.size() );
927 \brief Get tab index by point.
929 \return tab covering point or -1 if there is no tab covering point
931 int QtxWorkstackArea::tabAt( const QPoint& pnt ) const
934 QPoint p = myBar->mapFromGlobal( pnt );
935 for ( int i = 0; i < myBar->count() && idx == -1; i++ )
937 QRect r = myBar->tabRect( i );
938 if ( r.isValid() && r.contains( p ) )
945 \brief Event handler for custom events.
946 \param e custom event
948 void QtxWorkstackArea::customEvent( QEvent* e )
950 WidgetEvent* we = (WidgetEvent*)e;
952 switch ( we->type() )
955 myBar->updateActiveState();
956 emit activated( activeWidget() );
959 if ( activeWidget() )
961 if ( !activeWidget()->focusWidget() )
962 activeWidget()->setFocus();
965 if ( activeWidget()->focusWidget()->hasFocus() )
967 QFocusEvent in( QEvent::FocusIn );
968 QApplication::sendEvent( this, &in );
972 activeWidget()->focusWidget()->setFocus();
973 myBar->updateActiveState();
979 if ( we->child()->widget() )
980 setActiveWidget( we->child()->widget() );
985 QtxWorkstackChild* c = we->child();
986 RestoreEvent* re = (RestoreEvent*)we;
988 c->widget()->setVisible( re->flags() & QtxWorkstack::Visible );
989 c->setId( re->id() );
999 \brief Customize focus in event handler.
1000 \param e focus in event
1002 void QtxWorkstackArea::focusInEvent( QFocusEvent* e )
1004 QFrame::focusInEvent( e );
1006 myBar->updateActiveState();
1008 emit activated( activeWidget() );
1012 \brief Customize mouse press event handler.
1013 \param e mouse press event
1015 void QtxWorkstackArea::mousePressEvent( QMouseEvent* e )
1017 QFrame::mousePressEvent( e );
1019 emit activated( activeWidget() );
1023 \brief Called when user presses "Close" button.
1025 void QtxWorkstackArea::onClose()
1027 QWidget* wid = activeWidget();
1033 \brief Called when user selects any tab page.
1034 \param idx tab page index (not used)
1036 void QtxWorkstackArea::onCurrentChanged( int /*idx*/ )
1040 emit activated( activeWidget() );
1044 \brief Called when user starts tab page dragging.
1046 void QtxWorkstackArea::onDragActiveTab()
1048 QtxWorkstackChild* c = child( activeWidget() );
1052 new QtxWorkstackDrag( workstack(), c );
1056 \brief Called when area's child widget container is destroyed.
1057 \param obj widget container being destroyed
1059 void QtxWorkstackArea::onChildDestroyed( QObject* obj )
1061 removeChild( (QtxWorkstackChild*)obj, false );
1065 \brief Called when child widget container is shown.
1066 \param c child widget container being shown
1068 void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c )
1074 \brief Called when child widget container is hidden.
1075 \param c child widget container being hidden
1077 void QtxWorkstackArea::onChildHidden( QtxWorkstackChild* c )
1083 \brief Called when child widget container is activated.
1084 \param c child widget container being activated
1086 void QtxWorkstackArea::onChildActivated( QtxWorkstackChild* c )
1088 setWidgetActive( c->widget() );
1092 \brief Called when child widget container's title is changed.
1093 \param c child widget container which title is changed
1095 void QtxWorkstackArea::onChildCaptionChanged( QtxWorkstackChild* c )
1097 updateTab( c->widget() );
1101 \brief Update current child widget container.
1103 Raises widget when active tab page is changed.
1105 void QtxWorkstackArea::updateCurrent()
1107 QWidget* cur = child( widget( myBar->tabId( myBar->currentIndex() ) ) );
1109 myStack->setCurrentWidget( cur );
1113 \brief Update tab bar.
1114 \param wid tab page widget
1116 void QtxWorkstackArea::updateTab( QWidget* wid )
1118 int idx = myBar->indexOf( widgetId( wid ) );
1122 myBar->setTabIcon( idx, wid->windowIcon() );
1123 myBar->setTabText( idx, wid->windowTitle() );
1127 \brief Get child widget by specified identifier.
1129 \return widget or 0, if identifier in invalid
1131 QWidget* QtxWorkstackArea::widget( const int id ) const
1133 QtxWorkstackChild* c = child( id );
1135 return c ? c->widget() : 0;
1139 \brief Get child widget identifier.
1141 \return widget ID or -1 if widget is not found
1143 int QtxWorkstackArea::widgetId( QWidget* wid ) const
1145 QtxWorkstackChild* c = child( wid );
1147 return c ? c->id() : -1;
1151 \brief Set active child widget.
1152 \param wid widget to be set active
1154 void QtxWorkstackArea::setWidgetActive( QWidget* wid )
1156 int id = widgetId( wid );
1160 myBar->setCurrentIndex( myBar->indexOf( id ) );
1164 \brief Update internal state.
1166 void QtxWorkstackArea::updateState()
1168 bool updBar = myBar->updatesEnabled();
1169 bool updStk = myStack->updatesEnabled();
1170 myBar->setUpdatesEnabled( false );
1171 myStack->setUpdatesEnabled( false );
1173 bool block = myBar->signalsBlocked();
1174 myBar->blockSignals( true );
1176 QWidget* prev = activeWidget();
1179 for ( ChildList::iterator it = myList.begin(); it != myList.end(); ++it )
1181 QtxWorkstackChild* cont = *it;
1182 QWidget* wid = cont->widget();;
1183 int id = cont->id();
1188 bool vis = cont->visibility();
1190 int cIdx = myBar->indexOf( id );
1191 if ( cIdx != -1 && ( !vis || myBar->indexOf( id ) != idx ) )
1192 myBar->removeTab( cIdx );
1194 if ( myBar->indexOf( id ) == -1 && vis )
1195 myBar->setTabId( myBar->insertTab( idx, wid->windowTitle() ), id );
1200 myStack->removeWidget( cont );
1201 else if ( myStack->indexOf( cont ) < 0 )
1202 myStack->addWidget( cont );
1208 int curId = widgetId( prev );
1209 if ( myBar->indexOf( curId ) < 0 )
1211 QtxWorkstackChild* c = 0;
1212 int pos = myList.indexOf( child( prev ) );
1213 for ( int i = pos - 1; i >= 0 && !c; i-- )
1215 if ( myList.at( i )->visibility() )
1219 for ( int j = pos + 1; j < (int)myList.count() && !c; j++ )
1221 if ( myList.at( j )->visibility() )
1229 myBar->setCurrentIndex( myBar->indexOf( curId ) );
1231 myBar->blockSignals( block );
1235 myBar->updateActiveState();
1237 myBar->setUpdatesEnabled( updBar );
1238 myStack->setUpdatesEnabled( updStk );
1244 QResizeEvent re( myBar->size(), myBar->size() );
1245 QApplication::sendEvent( myBar, &re );
1247 myBar->updateGeometry();
1252 emit deactivated( this );
1257 if ( prev != activeWidget() )
1258 emit activated( activeWidget() );
1263 \brief Generate unique widget identifier.
1264 \return first non shared widget ID
1266 int QtxWorkstackArea::generateId() const
1270 for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it )
1271 map.insert( (*it)->id(), 0 );
1274 while ( map.contains( id ) )
1281 \brief Get child widget container.
1282 \param wid child widget
1283 \return child widget container corresponding to the \a wid
1285 QtxWorkstackChild* QtxWorkstackArea::child( QWidget* wid ) const
1287 QtxWorkstackChild* res = 0;
1288 for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !res; ++it )
1290 if ( (*it)->widget() == wid )
1296 QtxWorkstackChild* QtxWorkstackArea::child( const int id ) const
1298 QtxWorkstackChild* c = 0;
1299 for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !c; ++it )
1301 if ( (*it)->id() == id )
1308 \fn void QtxWorkstackArea::activated( QWidget* w )
1309 \brief Emitted when child widget is activated.
1310 \param w child widget being activated
1314 \fn void QtxWorkstackArea::contextMenuRequested( QWidget* w, QPoint p )
1315 \brief Emitted when context popup menu is requested.
1316 \param w child widget popup menu requested for
1317 \param p point popup menu to be shown at
1321 \fn void QtxWorkstackArea::deactivated( QtxWorkstackArea* wa )
1322 \brief Emitted when workarea is deactivated.
1323 \param wa workarea being deactivated
1327 \class QtxWorkstackChild
1329 \brief Workarea child widget container.
1334 \param wid child widget
1335 \param parent parent widget
1336 \param f widget flags
1338 QtxWorkstackChild::QtxWorkstackChild( QWidget* wid, QWidget* parent, Qt::WindowFlags f )
1339 : QWidget( parent ),
1345 myWidget->setParent( this, f );
1346 myWidget->installEventFilter( this );
1347 if ( myWidget->focusProxy() )
1348 myWidget->focusProxy()->installEventFilter( this );
1349 myWidget->setVisible( myWidget->isVisibleTo( myWidget->parentWidget() ) );
1351 QVBoxLayout* base = new QVBoxLayout( this );
1352 base->setMargin( 0 );
1353 base->addWidget( myWidget );
1355 connect( myWidget, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
1362 QtxWorkstackChild::~QtxWorkstackChild()
1364 QApplication::instance()->removeEventFilter( this );
1369 disconnect( widget(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
1372 widget()->removeEventFilter( this );
1373 if ( widget()->focusProxy() )
1374 widget()->focusProxy()->removeEventFilter( this );
1376 widget()->setParent( 0 );
1380 \brief Get child widget.
1381 \return child widget
1383 QWidget* QtxWorkstackChild::widget() const
1389 \brief Returns the id.
1391 int QtxWorkstackChild::id() const
1399 void QtxWorkstackChild::setId( const int id )
1405 \brief Returns true if this child window should be visible.
1407 bool QtxWorkstackChild::visibility()
1409 return myWidget ? myWidget->isVisibleTo( this ) : false;
1412 QtxWorkstackArea* QtxWorkstackChild::area() const
1414 QtxWorkstackArea* a = 0;
1415 QWidget* w = parentWidget();
1418 a = ::qobject_cast<QtxWorkstackArea*>( w );
1419 w = w->parentWidget();
1426 \brief Custom event filter.
1428 Process events from child widgets.
1430 \param o event receiver widget
1432 \return \c true if event should be filtered (stop further processing)
1434 bool QtxWorkstackChild::eventFilter( QObject* o, QEvent* e )
1436 if ( o->isWidgetType() )
1438 if ( e->type() == QEvent::WindowTitleChange || e->type() == QEvent::WindowIconChange )
1439 emit captionChanged( this );
1441 if ( !e->spontaneous() && e->type() == QEvent::ShowToParent )
1444 if ( !e->spontaneous() && e->type() == QEvent::HideToParent )
1445 emit hidden( this );
1447 if ( e->type() == QEvent::FocusIn )
1448 emit activated( this );
1450 return QWidget::eventFilter( o, e );
1454 \brief Called when child widget is destroyed.
1455 \param obj child widget being destroyed
1457 void QtxWorkstackChild::onDestroyed( QObject* obj )
1463 \brief Customize child event handler.
1464 \param e child event
1466 void QtxWorkstackChild::childEvent( QChildEvent* e )
1468 if ( e->removed() && e->child() == widget() )
1473 QWidget::childEvent( e );
1477 \fn void QtxWorkstackChild::shown( QtxWorkstackChild* w )
1478 \brief Emitted when child widget is shown.
1479 \param w child widget container
1483 \fn void QtxWorkstackChild::hidden( QtxWorkstackChild* w )
1484 \brief Emitted when child widget is hidden.
1485 \param w child widget container
1489 \fn void QtxWorkstackChild::activated( QtxWorkstackChild* w )
1490 \brief Emitted when child widget is activated.
1491 \param w child widget container
1495 \fn void QtxWorkstackChild::captionChanged( QtxWorkstackChild* w )
1496 \brief Emitted when child widget's title is changed.
1497 \param w child widget container
1501 \class QtxWorkstackTabBar
1503 \brief Workstack tab bar widget
1508 \param parent parent widget
1510 QtxWorkstackTabBar::QtxWorkstackTabBar( QWidget* parent )
1511 : QTabBar( parent ),
1512 myId( -1 ),myActive(false)
1514 setDrawBase( true );
1515 setElideMode( Qt::ElideNone );
1517 connect( this, SIGNAL( currentChanged( int ) ), this, SLOT( onCurrentChanged( int ) ) );
1523 QtxWorkstackTabBar::~QtxWorkstackTabBar()
1528 \brief Get tab page identifier.
1529 \param index tab page index
1530 \return tab page ID or -1 if \a index is out of range
1532 int QtxWorkstackTabBar::tabId( const int index ) const
1534 QVariant v = tabData( index );
1535 if ( !v.canConvert( QVariant::Int ) )
1541 \brief Set tab page identifier.
1542 \param index tab page index
1543 \param id tab page ID
1545 void QtxWorkstackTabBar::setTabId( const int index, const int id )
1547 setTabData( index, id );
1551 \brief Get tab page index by specified identifier.
1552 \param id tab page ID
1553 \return tab page index or -1 if not found
1555 int QtxWorkstackTabBar::indexOf( const int id ) const
1558 for ( int i = 0; i < (int)count() && index < 0; i++ )
1560 if ( tabId( i ) == id )
1567 \brief Check if the tab bar is active.
1568 \return \c true if tab bar is active
1570 bool QtxWorkstackTabBar::isActive() const
1576 \brief Set tab bar active/inactive.
1577 \param on new active state
1579 void QtxWorkstackTabBar::setActive( const bool on )
1581 if ( myActive == on )
1585 updateActiveState();
1589 \brief Update tab bar according to the 'active' state.
1591 void QtxWorkstackTabBar::updateActiveState()
1593 QColor bc = palette().color( QPalette::Text );
1594 QColor ac = isActive() ? palette().color( QPalette::Highlight ) : bc;
1595 for ( int i = 0; i < (int)count(); i++ )
1596 setTabTextColor( i, currentIndex() == i ? ac : bc );
1600 \brief Called when current tab page is changed.
1601 \param idx tab page index (not used)
1603 void QtxWorkstackTabBar::onCurrentChanged( int /*index*/ )
1605 updateActiveState();
1609 \brief Customize mouse move event handler.
1610 \param e mouse event
1612 void QtxWorkstackTabBar::mouseMoveEvent( QMouseEvent* e )
1614 if ( myId != -1 && !tabRect( indexOf( myId ) ).contains( e->pos() ) )
1617 emit dragActiveTab();
1620 QTabBar::mouseMoveEvent( e );
1624 \brief Customize mouse press event handler.
1625 \param e mouse event
1627 void QtxWorkstackTabBar::mousePressEvent( QMouseEvent* e )
1629 QTabBar::mousePressEvent( e );
1631 if ( e->button() == Qt::LeftButton )
1632 myId = tabId( currentIndex() );
1636 \brief Customize mouse release event handler.
1637 \param e mouse event
1639 void QtxWorkstackTabBar::mouseReleaseEvent( QMouseEvent* e )
1641 QTabBar::mouseReleaseEvent( e );
1645 if ( e->button() == Qt::RightButton )
1646 emit contextMenuRequested( e->globalPos() );
1650 \brief Customize context menu event handler.
1651 \param e context menu event
1653 void QtxWorkstackTabBar::contextMenuEvent( QContextMenuEvent* e )
1655 if ( e->reason() != QContextMenuEvent::Mouse )
1656 emit contextMenuRequested( e->globalPos() );
1660 \brief Process widget change state events (style, palette, enable state changing, etc).
1661 \param e change event (not used)
1663 void QtxWorkstackTabBar::changeEvent( QEvent* /*e*/ )
1665 updateActiveState();
1669 void QtxWorkstackTabBar::paintLabel( QPainter* p, const QRect& br, QTab* t, bool has_focus ) const
1671 if ( currentTab() != t->identifier() )
1673 QFont fnt = p->font();
1674 fnt.setUnderline( false );
1677 QTabBar::paintLabel( p, br, t, has_focus );
1682 \fn void QtxWorkstackTabBar::dragActiveTab()
1683 \brief Emitted when dragging operation is started.
1687 \fn void QtxWorkstackTabBar::contextMenuRequested( QPoint p )
1688 \brief Emitted when context popup menu is requested.
1689 \param p point popup menu to be shown at
1694 \brief Workstack widget.
1696 Organizes the child widgets in the tabbed space.
1697 Allows splitting the working area to arrange the child widgets in
1698 arbitrary way. Any widgets can be moved to another working area with
1699 drag-n-drop operation.
1701 This widget can be used as workspace of the application main window,
1702 for example, as kind of implementation of multi-document interface.
1707 \param parent parent widget
1709 QtxWorkstack::QtxWorkstack( QWidget* parent )
1710 : QWidget( parent ),
1716 myActionsMap.insert( SplitVertical, new QtxAction( QString(), tr( "Split vertically" ), 0, this ) );
1717 myActionsMap.insert( SplitHorizontal, new QtxAction( QString(), tr( "Split horizontally" ), 0, this ) );
1718 myActionsMap.insert( Close, new QtxAction( QString(), tr( "Close" ), 0, this ) );
1719 myActionsMap.insert( Rename, new QtxAction( QString(), tr( "Rename" ), 0, this ) );
1721 connect( myActionsMap[SplitVertical], SIGNAL( triggered( bool ) ), this, SLOT( splitVertical() ) );
1722 connect( myActionsMap[SplitHorizontal], SIGNAL( triggered( bool ) ), this, SLOT( splitHorizontal() ) );
1723 connect( myActionsMap[Close], SIGNAL( triggered( bool ) ), this, SLOT( onCloseWindow() ) );
1724 connect( myActionsMap[Rename], SIGNAL( triggered( bool ) ), this, SLOT( onRename() ) );
1726 // Action shortcut will work when action added in any widget.
1727 for ( QMap<int, QAction*>::iterator it = myActionsMap.begin(); it != myActionsMap.end(); ++it )
1729 addAction( it.value() );
1730 it.value()->setShortcutContext( Qt::ApplicationShortcut );
1733 QVBoxLayout* base = new QVBoxLayout( this );
1734 base->setMargin( 0 );
1736 mySplit = new QtxWorkstackSplitter( this );
1737 base->addWidget( mySplit );
1743 QtxWorkstack::~QtxWorkstack()
1748 \brief Get list of all widgets in all areas or in specified area which given
1750 \param wid widget specifying area if it is equal to null when widgets of all
1752 \return list of widgets
1754 QWidgetList QtxWorkstack::windowList( QWidget* wid ) const
1756 QList<QtxWorkstackArea*> lst;
1759 areas( mySplit, lst, true );
1763 QtxWorkstackArea* area = wgArea( wid );
1768 QWidgetList widList;
1769 for ( QList<QtxWorkstackArea*>::iterator it = lst.begin(); it != lst.end(); ++it )
1771 QWidgetList wids = (*it)->widgetList();
1772 for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr )
1773 widList.append( *itr );
1780 \brief Get all child widgets in the active workarea.
1781 \return list of widgets in active workarea
1783 QWidgetList QtxWorkstack::splitWindowList() const
1785 return myArea ? myArea->widgetList() : QWidgetList();
1789 \brief Get active widget.
1790 \return active widget
1792 QWidget* QtxWorkstack::activeWindow() const
1798 \brief Split workstack.
1800 Splitting is possible only if there are two or more widgets in the workarea.
1801 This function splits current workarea to two new ones.
1803 \param o splitting orientation (Qt::Orientation)
1805 void QtxWorkstack::split( const int o )
1807 QtxWorkstackArea* area = myWorkArea;
1809 area = activeArea();
1813 if ( area->widgetList().count() < 2 )
1816 QWidget* curWid = area->activeWidget();
1820 QSplitter* s = splitter( area );
1821 QList<QtxWorkstackArea*> areaList;
1822 areas( s, areaList );
1824 QList<QSplitter*> splitList;
1825 splitters( s, splitList );
1828 if ( areaList.count() + splitList.count() < 2 || s->orientation() == o )
1832 trg = wrapSplitter( area );
1837 trg->setOrientation( (Qt::Orientation)o );
1839 QtxWorkstackArea* newArea = createArea( 0 );
1840 trg->insertWidget( trg->indexOf( area ) + 1, newArea );
1842 area->removeWidget( curWid );
1843 newArea->insertWidget( curWid );
1845 distributeSpace( trg );
1852 \brief Split workarea of the given widget on two parts.
1854 Splitting is possible only if there are two or more widgets in the workarea.
1855 This function splits current workarea to two new ones.
1857 \param wid widget belonging to the workstack
1858 \param o splitting orientation type (Qt::Orientation)
1859 \param type splitting type (QtxWorkstack::SplitType)
1861 void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType type )
1865 // find area of the given widget
1866 QtxWorkstackArea* area = NULL;
1867 QList<QtxWorkstackArea*> allAreas;
1868 areas(mySplit, allAreas, true);
1870 for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it )
1872 if ( (*it)->contains( wid ) )
1879 QWidget* curWid = area->activeWidget();
1883 QWidgetList wids = area->widgetList();
1884 if ( wids.count() < 2 )
1887 QSplitter* s = splitter( area );
1888 QList<QtxWorkstackArea*> areaList;
1889 areas( s, areaList );
1891 QList<QSplitter*> splitList;
1892 splitters(s, splitList);
1895 if (areaList.count() + splitList.count() < 2 || s->orientation() == o)
1898 if (!trg) trg = wrapSplitter(area);
1901 trg->setOrientation(o);
1903 QtxWorkstackArea* newArea = createArea(0);
1904 insertWidget(newArea, trg, area);
1909 for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr )
1911 QWidget* wid_i = *itr;
1914 area->removeWidget( wid_i );
1915 newArea->insertWidget( wid_i );
1916 wid_i->showMaximized();
1922 QWidgetList::iterator itr = wids.begin();
1923 for ( ; itr != wids.end() && *itr != wid; ++itr )
1926 for ( ; itr != wids.end(); ++itr )
1928 area->removeWidget( *itr );
1929 newArea->insertWidget( *itr );
1930 (*itr)->showMaximized();
1935 area->removeWidget( wid );
1936 newArea->insertWidget( wid );
1937 wid->showMaximized();
1941 distributeSpace( trg );
1948 \brief Move widget(s) from the source workarea into the target workarea
1949 or reorder widgets inside one workarea.
1951 Move \a wid2 in target workarea. Put it right after \a wid1.
1952 If \a all parameter is \c true, all widgets from source workarea
1953 will be moved including \a wid2 and source workarea will be deleted then.
1955 If \a wid1 and \a wid2 belongs to one workarea, widgets will be just reordered
1958 \param wid1 widget from target workarea
1959 \param wid2 widget from source workarea
1960 \param all if \c true, all widgets from source workarea will
1961 be moved into the target one, else only the \a wid2 will be moved
1963 void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all )
1965 if ( !wid1 || !wid2 )
1968 // find area of the widgets
1969 QtxWorkstackArea *area1 = 0, *area2 = 0;
1970 QList<QtxWorkstackArea*> allAreas;
1971 areas( mySplit, allAreas, true );
1972 for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !( area1 && area2 ); ++it )
1974 if ( (*it)->contains( wid1 ) )
1977 if ( (*it)->contains( wid2 ) )
1981 if ( !area1 || !area2 )
1984 QSplitter* s1 = splitter( area1 );
1986 QWidget* curWid = area1->activeWidget();
1990 if ( area1 == area2 )
1994 // Set wid1 at first position, wid2 at second
1995 area1->insertWidget( wid1 );
1996 area1->insertWidget( wid2, 1 );
1997 wid1->showMaximized();
1998 wid2->showMaximized();
2002 // Set wid2 right after wid1
2003 area1->removeWidget( wid2 );
2005 QWidgetList wids1 = area1->widgetList();
2006 for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind );
2007 area1->insertWidget( wid2, wid1_ind + 1 );
2008 wid2->showMaximized();
2014 QWidgetList wids1 = area1->widgetList();
2015 for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind );
2018 // Set wid2 right after wid1, other widgets from area2 right after wid2
2019 QWidgetList wids2 = area2->widgetList();
2020 QWidgetList::iterator itr2 = wids2.begin();
2021 for ( int ind = wid1_ind + 1; itr2 != wids2.end(); ++itr2, ++ind )
2023 area2->removeWidget( *itr2 );
2024 if ( *itr2 == wid2 )
2025 area1->insertWidget( *itr2, wid1_ind + 1 );
2027 area1->insertWidget( *itr2, ind );
2028 (*itr2)->showMaximized();
2033 // Set wid2 right after wid1
2034 area2->removeWidget( wid2 );
2035 area1->insertWidget( wid2, wid1_ind + 1 );
2036 wid2->showMaximized();
2040 distributeSpace( s1 );
2042 area1->setActiveWidget( curWid );
2051 \brief Calculate sizes of the splitter widget for the workarea.
2054 static void setSizes (QIntList& szList, const int item_ind,
2055 const int new_near, const int new_this, const int new_farr)
2057 // set size to all items before an item # <item_ind>
2059 QIntList::iterator its = szList.begin();
2060 for (; its != szList.end() && cur_pos < item_ind; ++its, ++cur_pos) {
2063 if (its == szList.end()) return;
2064 // set size to item # <item_ind>
2067 // set size to all items after an item # <item_ind>
2068 for (; its != szList.end(); ++its) {
2074 \brief Set position of the widget relatively to its parent splitter.
2076 Orientation of positioning will correspond to the splitter orientation.
2079 \param pos position relatively to the splitter; value in the range [0..1]
2081 void QtxWorkstack::SetRelativePositionInSplitter( QWidget* wid, const double position )
2083 if ( position < 0.0 || 1.0 < position)
2089 // find area of the given widget
2090 QtxWorkstackArea* area = NULL;
2091 QList<QtxWorkstackArea*> allAreas;
2092 areas( mySplit, allAreas, true );
2093 for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it )
2095 if ( (*it)->contains( wid ) )
2102 QSplitter* split = splitter( area );
2106 // find index of the area in its splitter
2108 bool isFound = false;
2109 const QObjectList& was = split->children();
2110 for ( QObjectList::const_iterator ito = was.begin(); ito != was.end() && !isFound; ++ito, ++item_ind )
2116 if ( !isFound || item_ind == 0 )
2119 QIntList szList = split->sizes();
2120 int splitter_size = ( split->orientation() == Qt::Horizontal ? split->width() : split->height());
2121 int nb = szList.count();
2123 int new_prev = int( splitter_size * position / item_ind );
2124 if (nb == item_ind) return;
2125 int new_next = int( splitter_size * ( 1.0 - position ) / ( nb - item_ind ) );
2126 setSizes( szList, item_ind, new_prev, new_next, new_next );
2127 split->setSizes( szList );
2131 \brief Set position of the widget relatively to the entire workstack.
2133 If \a o is \c Qt::Horizontal, the horizontal position of \a wid will be changed.
2134 If \a o is \c Qt::Vertical, the vertical position of \a wid will be changed.
2137 \param o orientation of positioning (\c Qt::Horizontal or \c Qt::Vertical)
2138 \param pos position relatively to the workstack; value in range [0..1]
2140 void QtxWorkstack::SetRelativePosition( QWidget* wid, const Qt::Orientation o,
2141 const double position )
2143 if ( position < 0.0 || 1.0 < position )
2149 int splitter_size = o == Qt::Horizontal ? mySplit->width() : mySplit->height();
2150 int need_pos = int( position * splitter_size );
2151 int splitter_pos = 0;
2153 if ( setPosition( wid, mySplit, o, need_pos, splitter_pos ) != 0 )
2155 // impossible to set required position
2160 \brief Set accelerator key-combination for the action with specified \a id.
2162 \param accel action accelerator
2164 void QtxWorkstack::setAccel( const int id, const int accel )
2166 if ( !myActionsMap.contains( id ) )
2169 myActionsMap[id]->setShortcut( accel );
2173 \brief Get the action's accelerator key-combination.
2175 \return action accelerator
2177 int QtxWorkstack::accel( const int id ) const
2180 if ( myActionsMap.contains( id ) )
2181 res = myActionsMap[id]->shortcut();
2186 \brief Get icon for the specified action.
2188 If \a id is invalid, null icon is returned.
2190 \param id menu action ID
2191 \return menu item icon
2193 QIcon QtxWorkstack::icon( const int id ) const
2196 if ( myActionsMap.contains( id ) )
2197 ico = myActionsMap[id]->icon();
2202 \brief Set menu item icon for the specified action.
2203 \param id menu action ID
2204 \param ico new menu item icon
2206 void QtxWorkstack::setIcon( const int id, const QIcon& icon )
2208 if ( !myActionsMap.contains( id ) )
2211 myActionsMap[id]->setIcon( icon );
2215 \brief Set actions to be visible in the context popup menu.
2217 Actions, which IDs are set in \a flags parameter, will be shown in the
2218 context popup menu. Other actions will not be shown.
2220 \param flags ORed together actions flags
2222 void QtxWorkstack::setMenuActions( const int flags )
2224 myActionsMap[SplitVertical]->setVisible( flags & SplitVertical );
2225 myActionsMap[SplitHorizontal]->setVisible( flags & SplitHorizontal );
2226 myActionsMap[Close]->setVisible( flags & Close );
2227 myActionsMap[Rename]->setVisible( flags & Rename );
2231 \brief Set actions to be visible in the context popup menu.
2233 Actions, which IDs are set in \a flags parameter, will be shown in the
2234 context popup menu. Other actions will not be shown.
2236 \param flags ORed together actions flags
2238 int QtxWorkstack::menuActions() const
2241 ret = ret | ( myActionsMap[SplitVertical]->isVisible() ? SplitVertical : 0 );
2242 ret = ret | ( myActionsMap[SplitHorizontal]->isVisible() ? SplitHorizontal : 0 );
2243 ret = ret | ( myActionsMap[Close]->isVisible() ? Close : 0 );
2244 ret = ret | ( myActionsMap[Rename]->isVisible() ? Rename : 0 );
2249 \brief Calculate sizes of the splitter widget for the workarea.
2252 static int positionSimple (QIntList& szList, const int nb, const int splitter_size,
2253 const int item_ind, const int item_rel_pos,
2254 const int need_pos, const int splitter_pos)
2256 if (item_ind == 0) { // cannot move in this splitter
2257 return (need_pos - splitter_pos);
2262 int new_this = szList[item_ind];
2265 bool isToCheck = false;
2267 if (need_pos < splitter_pos) {
2268 // Set size of all previous workareas to zero <--
2269 if (item_ind == nb - 1) {
2270 // item iz last in the splitter, it will occupy all the splitter
2271 new_this = splitter_size;
2273 // recompute size of next items in splitter
2274 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
2276 delta = need_pos - splitter_pos;
2278 } else if (need_pos > (splitter_pos + splitter_size)) {
2279 // Set size of all next workareas to zero -->
2280 // recompute size of previous items in splitter
2282 new_prev = (splitter_size - new_this) / item_ind;
2283 delta = need_pos - (splitter_pos + splitter_size - new_this);
2285 } else { // required position lays inside this splitter
2286 // Move workarea inside splitter into required position <->
2287 int new_item_rel_pos = need_pos - splitter_pos;
2288 new_prev = new_item_rel_pos / item_ind;
2289 if (need_pos < (splitter_pos + item_rel_pos)) {
2290 // Make previous workareas smaller, next - bigger
2291 // No problem to keep old size of the widget
2293 // Make previous workareas bigger, next - smaller
2294 if (new_this > splitter_size - new_item_rel_pos) {
2295 new_this = splitter_size - new_item_rel_pos;
2297 // jfa to do: in this case fixed size of next widgets could prevent right resizing
2300 if (item_ind == nb - 1) {
2301 new_this = splitter_size - new_item_rel_pos;
2303 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
2308 setSizes (szList, item_ind, new_prev, new_this, new_next);
2313 \brief Set position of the widget.
2315 Called from SetRelativePosition() public method.
2317 \param wid widget to be moved
2318 \param split currently processed splitter (goes from more common
2319 to more particular splitter in recursion calls)
2320 \param o orientation of positioning
2321 \param need_pos required position of the given widget in pixels
2322 (from top/left side of workstack area)
2323 \param splitter_pos position of the splitter \a split
2324 (from top/left side of workstack area)
2325 \return difference between a required and a distinguished position
2327 int QtxWorkstack::setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o,
2328 const int need_pos, const int splitter_pos )
2330 if ( !wid || !split )
2331 return need_pos - splitter_pos;
2333 // Find corresponding sub-splitter.
2334 // Find also index of appropriate item in current splitter.
2335 int cur_ind = 0, item_ind = 0;
2336 bool isBottom = false, isFound = false;
2337 QSplitter* sub_split = NULL;
2338 const QObjectList& objs = split->children();
2339 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end() && !isFound; ++it )
2341 QtxWorkstackArea* area = ::qobject_cast<QtxWorkstackArea*>( *it );
2344 if ( area->contains( wid ) )
2352 else if ( (*it)->inherits( "QSplitter" ) )
2354 QList<QtxWorkstackArea*> areaList;
2355 areas( (QSplitter*)(*it), areaList, true );
2356 for ( QList<QtxWorkstackArea*>::iterator ita = areaList.begin(); ita != areaList.end() && !isFound; ++ita )
2358 if ( (*ita)->contains( wid ) )
2362 sub_split = (QSplitter*)*it;
2370 return ( need_pos - splitter_pos );
2372 if ( split->orientation() == o )
2374 // Find coordinates of near and far sides of the appropriate item relatively current splitter
2375 int splitter_size = ( o == Qt::Horizontal ? split->width() : split->height() );
2376 QIntList szList = split->sizes();
2377 int nb = szList.count();
2378 int item_rel_pos = 0; // position of near side of item relatively this splitter
2379 for (int i = 0; i < item_ind; i++) {
2380 item_rel_pos += szList[i];
2382 int item_size = szList[item_ind]; // size of item
2383 int item_pos = splitter_pos + item_rel_pos;
2385 // Resize splitter items to complete the conditions
2387 // I. Bottom of splitters stack reached
2389 int delta = positionSimple(szList, nb, splitter_size, item_ind, item_rel_pos, need_pos, splitter_pos);
2390 split->setSizes(szList);
2391 // Recompute delta, as some windows can reject given size
2392 int new_item_rel_pos = 0;
2393 QIntList szList1 = split->sizes();
2394 for (int i = 0; i < item_ind; i++) {
2395 new_item_rel_pos += szList1[i];
2397 delta = need_pos - (splitter_pos + new_item_rel_pos);
2401 // II. Bottom of splitters stack is not yet reached
2403 if (item_ind == 0) { // cannot move in this splitter
2404 // Process in sub-splitter
2405 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
2409 int new_this = szList[item_ind];
2412 if (need_pos < splitter_pos) {
2413 // Set size of all previous workareas to zero <--
2414 if (item_ind == nb - 1) {
2415 new_this = splitter_size;
2417 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
2419 setSizes (szList, item_ind, new_prev, new_this, new_next);
2420 split->setSizes(szList);
2421 // Recompute splitter_pos, as some windows can reject given size
2422 int new_item_rel_pos = 0;
2423 QIntList szList1 = split->sizes();
2424 for (int i = 0; i < item_ind; i++) {
2425 new_item_rel_pos += szList1[i];
2427 // Process in sub-splitter
2428 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2429 } else if (need_pos > (splitter_pos + splitter_size)) {
2430 // Set size of all next workareas to zero -->
2431 new_prev = (splitter_size - new_this) / item_ind;
2432 setSizes (szList, item_ind, new_prev, new_this, new_next);
2433 split->setSizes(szList);
2434 // Recompute splitter_pos, as some windows can reject given size
2435 int new_item_rel_pos = 0;
2436 QIntList szList1 = split->sizes();
2437 for (int i = 0; i < item_ind; i++) {
2438 new_item_rel_pos += szList1[i];
2440 // Process in sub-splitter
2441 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2443 // Set appropriate size of all previous/next items <->
2444 int new_item_rel_pos = item_rel_pos;
2445 if (need_pos < item_pos || (item_pos + item_size) < need_pos) {
2446 // Move item inside splitter into required position <->
2447 int new_this = szList[item_ind];
2449 new_item_rel_pos = need_pos - splitter_pos;
2450 if ((item_pos + item_size) < need_pos) {
2451 //new_item_rel_pos = need_pos - (item_pos + item_size);
2452 new_item_rel_pos = item_rel_pos + (need_pos - (item_pos + item_size));
2454 int new_prev = new_item_rel_pos / item_ind;
2455 if (need_pos < (splitter_pos + item_rel_pos)) {
2456 // Make previous workareas smaller, next - bigger
2457 // No problem to keep old size of the widget
2459 // Make previous workareas bigger, next - smaller
2460 if (new_this > splitter_size - new_item_rel_pos) {
2461 new_this = splitter_size - new_item_rel_pos;
2464 if (item_ind == nb - 1) {
2465 new_this = splitter_size - new_item_rel_pos;
2467 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
2469 setSizes (szList, item_ind, new_prev, new_this, new_next);
2470 split->setSizes(szList);
2471 // Recompute new_item_rel_pos, as some windows can reject given size
2472 new_item_rel_pos = 0;
2473 QIntList szList1 = split->sizes();
2474 for (int i = 0; i < item_ind; i++) {
2475 new_item_rel_pos += szList1[i];
2480 // Process in sub-splitter
2481 int add_pos = setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2485 // this can be if corresponding workarea is first in sub-splitter
2486 // or sub-splitter has another orientation
2488 // Resize ones again to reach precize position <->
2489 int need_pos_1 = splitter_pos + new_item_rel_pos + add_pos;
2491 // Move workarea inside splitter into required position <->
2492 int delta_1 = positionSimple(szList, nb, splitter_size, item_ind,
2493 new_item_rel_pos, need_pos_1, splitter_pos);
2494 split->setSizes(szList);
2495 // Recompute new_item_rel_pos, as some windows can reject given size
2496 new_item_rel_pos = 0;
2497 QIntList szList1 = split->sizes();
2498 for (int i = 0; i < item_ind; i++) {
2499 new_item_rel_pos += szList1[i];
2501 delta_1 = need_pos_1 - (splitter_pos + new_item_rel_pos);
2506 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
2513 \brief Redistribute space among widgets equally.
2514 \param split splitter
2516 void QtxWorkstack::distributeSpace( QSplitter* split ) const
2521 QIntList szList = split->sizes();
2522 int size = ( split->orientation() == Qt::Horizontal ?
2523 split->width() : split->height() ) / szList.count();
2524 for ( QIntList::iterator it = szList.begin(); it != szList.end(); ++it )
2526 split->setSizes( szList );
2530 \brief Split widgets vertically.
2532 void QtxWorkstack::splitVertical()
2534 split( Qt::Horizontal );
2538 \brief Split widgets horizontally.
2540 void QtxWorkstack::splitHorizontal()
2542 split( Qt::Vertical );
2546 \brief Called when user activates "Rename" menu item.
2548 Changes widget title.
2550 void QtxWorkstack::onRename()
2556 QString newName = QInputDialog::getText( topLevelWidget(), tr( "Rename" ), tr( "Enter new name:" ),
2557 QLineEdit::Normal, myWorkWin->windowTitle(), &ok );
2558 if ( ok && !newName.isEmpty() )
2559 myWorkWin->setWindowTitle( newName );
2563 \brief Wrap area into the new splitter.
2565 \return new splitter
2567 QSplitter* QtxWorkstack::wrapSplitter( QtxWorkstackArea* area )
2572 QSplitter* pSplit = splitter( area );
2576 bool upd = pSplit->updatesEnabled();
2577 pSplit->setUpdatesEnabled( false );
2579 QIntList szList = pSplit->sizes();
2581 QSplitter* wrap = new QtxWorkstackSplitter( 0 );
2582 pSplit->insertWidget( pSplit->indexOf( area ) + 1, wrap );
2583 wrap->setVisible( true );
2584 wrap->addWidget( area );
2586 pSplit->setSizes( szList );
2588 pSplit->setUpdatesEnabled( upd );
2594 \brief Reparent and add widget.
2596 \param pWid parent widget
2597 \param after widget after which \a wid should be added
2599 void QtxWorkstack::insertWidget( QWidget* wid, QWidget* pWid, QWidget* after )
2601 if ( !wid || !pWid )
2604 QWidgetList moveList;
2605 const QObjectList& lst = pWid->children();
2607 for ( QObjectList::const_iterator it = lst.begin(); it != lst.end(); ++it )
2609 if ( found && ( (*it)->inherits( "QSplitter" ) ||
2610 (*it)->inherits( "QtxWorkstackArea" ) ) )
2611 moveList.append( (QWidget*)(*it) );
2616 QMap<QWidget*, bool> map;
2617 for ( QWidgetList::iterator it = moveList.begin(); it != moveList.end(); ++it )
2619 map.insert( *it, (*it)->isVisibleTo( (*it)->parentWidget() ) );
2620 (*it)->setParent( 0 );
2624 wid->setParent( pWid );
2626 for ( QWidgetList::iterator itr = moveList.begin(); itr != moveList.end(); ++itr )
2628 (*itr)->setParent( pWid );
2629 (*itr)->setShown( map.contains( *itr ) ? map[*itr] : false );
2634 \brief Close active window.
2636 void QtxWorkstack::onCloseWindow()
2640 else if( activeWindow() )
2641 activeWindow()->close();
2645 \brief Called when workarea is destroyed.
2647 Set input focus to the neighbour area.
2649 \param obj workarea being destroyed
2651 void QtxWorkstack::onDestroyed( QObject* obj )
2653 QtxWorkstackArea* area = (QtxWorkstackArea*)obj;
2655 if ( area == myArea )
2660 QtxWorkstackArea* cur = neighbourArea( area );
2665 QApplication::postEvent( this, new QEvent( QEvent::User ) );
2669 \brief Called on window activating.
2670 \param area workarea being activated (not used)
2672 void QtxWorkstack::onWindowActivated( QWidget* /*area*/ )
2674 const QObject* obj = sender();
2675 if ( !obj->inherits( "QtxWorkstackArea" ) )
2678 setActiveArea( (QtxWorkstackArea*)obj );
2682 \brief Called on window deactivating.
2683 \param area workarea being deactivated
2685 void QtxWorkstack::onDeactivated( QtxWorkstackArea* area )
2687 if ( myArea != area )
2690 QList<QtxWorkstackArea*> lst;
2691 areas( mySplit, lst, true );
2693 int idx = lst.indexOf( area );
2700 QtxWorkstackArea* newArea = neighbourArea( area );
2701 if ( newArea && newArea->activeWidget() )
2702 newArea->activeWidget()->setFocus();
2704 QApplication::postEvent( this, new QEvent( QEvent::User ) );
2708 \brief Create and show popup menu for workarea.
2710 \param p popup position
2712 void QtxWorkstack::onContextMenuRequested( QWidget* w, QPoint p )
2714 QtxWorkstackArea* anArea = ::qobject_cast<QtxWorkstackArea*>( (QObject*)sender() );
2716 anArea = activeArea();
2721 QWidgetList lst = anArea->widgetList();
2722 if ( lst.isEmpty() )
2726 myWorkArea = anArea;
2728 QMenu* pm = new QMenu();
2730 if ( lst.count() > 1 )
2732 if ( myActionsMap[SplitVertical]->isEnabled() )
2733 pm->addAction( myActionsMap[SplitVertical] );
2734 if ( myActionsMap[SplitHorizontal]->isEnabled() )
2735 pm->addAction( myActionsMap[SplitHorizontal] );
2741 if ( myActionsMap[Close]->isEnabled() )
2742 pm->addAction( myActionsMap[Close] );
2743 if ( myActionsMap[Rename]->isEnabled() )
2744 pm->addAction( myActionsMap[Rename] );
2747 Qtx::simplifySeparators( pm );
2749 if ( !pm->actions().isEmpty() )
2759 \brief Add child widget.
2761 \param f widget flags
2762 \return child widget container
2764 QWidget* QtxWorkstack::addWindow( QWidget* w, Qt::WindowFlags f )
2769 return targetArea()->insertWidget( w, -1, f );
2773 \brief Handle custom events.
2774 \param e custom event (not used)
2776 void QtxWorkstack::customEvent( QEvent* /*e*/ )
2782 \brief Get splitter corresponding to the workarea.
2784 \return splitter corresponding to the workarea
2786 QSplitter* QtxWorkstack::splitter( QtxWorkstackArea* area ) const
2791 QSplitter* split = 0;
2793 QWidget* wid = area->parentWidget();
2794 if ( wid && wid->inherits( "QSplitter" ) )
2795 split = (QSplitter*)wid;
2801 \brief Get list of child splitters.
2802 \param split parent splitter
2803 \param splitList list to be filled with child splitters
2804 \param rec if \c true, perform recursive search of children
2806 void QtxWorkstack::splitters( QSplitter* split, QList<QSplitter*>& splitList, const bool rec ) const
2811 const QObjectList& objs = split->children();
2812 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
2815 splitters( (QSplitter*)*it, splitList, rec );
2816 if ( (*it)->inherits( "QSplitter" ) )
2817 splitList.append( (QSplitter*)*it );
2822 \brief Get list of child workareas.
2823 \param split parent splitter
2824 \param areaList list to be filled with child workareas
2825 \param rec if \c true, perform recursive search of children
2827 void QtxWorkstack::areas( QSplitter* split, QList<QtxWorkstackArea*>& areaList, const bool rec ) const
2832 const QObjectList& objs = split->children();
2833 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
2835 if ( (*it)->inherits( "QtxWorkstackArea" ) )
2836 areaList.append( (QtxWorkstackArea*)*it );
2837 else if ( rec && (*it)->inherits( "QSplitter" ) )
2838 areas( (QSplitter*)*it, areaList, rec );
2843 \brief Get active workarea.
2844 \return active workarea
2846 QtxWorkstackArea* QtxWorkstack::activeArea() const
2852 \brief Get target area (for which the current operation should be done).
2854 Returns active workarea or current area (if there is no active workarea).
2855 If there are no workareas, create new workarea and return it.
2859 QtxWorkstackArea* QtxWorkstack::targetArea()
2861 QtxWorkstackArea* area = activeArea();
2863 area = currentArea();
2866 QList<QtxWorkstackArea*> lst;
2867 areas( mySplit, lst );
2868 if ( !lst.isEmpty() )
2873 area = createArea( mySplit );
2879 \brief Get current workarea.
2881 Current workarea is that one which has input focus.
2883 \return current area
2885 QtxWorkstackArea* QtxWorkstack::currentArea() const
2887 QtxWorkstackArea* area = 0;
2888 QWidget* wid = focusWidget();
2889 while ( wid && !area )
2891 if ( wid->inherits( "QtxWorkstackArea" ) )
2892 area = (QtxWorkstackArea*)wid;
2893 wid = wid->parentWidget();
2900 \brief Create new workarea.
2901 \param parent parent widget
2902 \return created workarea
2904 QtxWorkstackArea* QtxWorkstack::createArea( QWidget* parent ) const
2906 QtxWorkstackArea* area = new QtxWorkstackArea( parent );
2908 connect( area, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
2909 connect( area, SIGNAL( activated( QWidget* ) ), this, SLOT( onWindowActivated( QWidget* ) ) );
2910 connect( area, SIGNAL( contextMenuRequested( QWidget*, QPoint ) ),
2911 this, SLOT( onContextMenuRequested( QWidget*, QPoint ) ) );
2912 connect( area, SIGNAL( deactivated( QtxWorkstackArea* ) ), this, SLOT( onDeactivated( QtxWorkstackArea* ) ) );
2918 \brief Set active workarea.
2921 void QtxWorkstack::setActiveArea( QtxWorkstackArea* area )
2923 QWidget* oldCur = myWin;
2925 QtxWorkstackArea* oldArea = myArea;
2929 if ( myArea != oldArea )
2932 oldArea->updateActiveState();
2934 myArea->updateActiveState();
2938 myWin = myArea->activeWidget();
2940 if ( myWin && oldCur != myWin )
2941 emit windowActivated( myWin );
2945 \brief Get workarea which is nearest to \a area.
2946 \param area area for which neighbour is searched
2947 \return neighbour area (or 0 if not found)
2949 QtxWorkstackArea* QtxWorkstack::neighbourArea( QtxWorkstackArea* area ) const
2951 QList<QtxWorkstackArea*> lst;
2952 areas( mySplit, lst, true );
2953 int pos = lst.indexOf( area );
2957 QtxWorkstackArea* na = 0;
2958 for ( int i = pos - 1; i >= 0 && !na; i-- )
2960 if ( !lst.at( i )->isEmpty() )
2964 for ( int j = pos + 1; j < (int)lst.count() && !na; j++ )
2966 if ( !lst.at( j )->isEmpty() )
2973 \brief Get workarea covering point.
2977 QtxWorkstackArea* QtxWorkstack::areaAt( const QPoint& p ) const
2979 QtxWorkstackArea* area = 0;
2980 QList<QtxWorkstackArea*> lst;
2981 areas( mySplit, lst, true );
2982 for ( QList<QtxWorkstackArea*>::iterator it = lst.begin(); it != lst.end() && !area; ++it )
2984 QtxWorkstackArea* cur = *it;
2985 QRect r = cur->geometry();
2986 if ( cur->parentWidget() )
2987 r = QRect( cur->parentWidget()->mapToGlobal( r.topLeft() ), r.size() );
2988 if ( r.contains( p ) )
2995 \brief Update internal state.
2997 void QtxWorkstack::updateState()
2999 updateState( mySplit );
3003 \brief Update splitter state.
3004 \param split splitter to be updated
3006 void QtxWorkstack::updateState( QSplitter* split )
3008 QList<QSplitter*> recList;
3009 splitters( split, recList, false );
3010 for ( QList<QSplitter*>::iterator itr = recList.begin(); itr != recList.end(); ++itr )
3011 updateState( *itr );
3013 QList<QSplitter*> splitList;
3014 splitters( split, splitList, false );
3016 QList<QtxWorkstackArea*> areaList;
3017 areas( split, areaList, false );
3020 for ( QList<QtxWorkstackArea*>::iterator it = areaList.begin(); it != areaList.end(); ++it )
3022 if ( (*it)->isEmpty() )
3031 if ( split == mySplit )
3034 for ( QList<QSplitter*>::iterator iter = splitList.begin(); iter != splitList.end() && !vis; ++iter )
3035 vis = (*iter)->isVisibleTo( (*iter)->parentWidget() );
3037 if ( areaList.isEmpty() && splitList.isEmpty() )
3040 split->setVisible( vis );
3044 \brief Dump workstack configuration to the state description array.
3045 \param version number
3046 \return state byte array.
3048 QByteArray QtxWorkstack::saveState( int version ) const
3052 QDataStream stream( &data, QIODevice::WriteOnly );
3053 stream << QtxWorkstack::VersionMarker;
3055 saveState( stream );
3061 \brief Restore workstack configuration from the state description array.
3062 \param version number
3063 \return restore performing state
3065 bool QtxWorkstack::restoreState( const QByteArray& state, int version )
3067 if ( state.isEmpty() )
3070 QByteArray sd = state;
3071 QDataStream stream( &sd, QIODevice::ReadOnly );
3075 if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::VersionMarker || ver != version )
3078 return restoreState( stream );
3081 void QtxWorkstack::saveState( QDataStream& stream ) const
3083 mySplit->saveState( stream );
3086 bool QtxWorkstack::restoreState( QDataStream& stream )
3088 QMap<QString, QtxWorkstackChild*> map;
3089 QList<QtxWorkstackArea*> areaList;
3090 areas( mySplit, areaList, true );
3091 for ( QList<QtxWorkstackArea*>::const_iterator it = areaList.begin(); it != areaList.end(); ++it )
3093 QtxWorkstackArea* area = *it;
3094 QList<QtxWorkstackChild*> childList = area->childList();
3095 for ( QList<QtxWorkstackChild*>::iterator itr = childList.begin(); itr != childList.end(); ++itr )
3097 QtxWorkstackChild* c = *itr;
3101 map.insert( c->widget()->objectName(), c );
3103 qDebug( "QtxWorkstack::restoreState: found widget \"%s\"", (const char*)c->widget()->objectName().toLatin1() );
3109 if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::SplitMarker )
3112 QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this );
3114 layout()->addWidget( split );
3116 bool ok = split->restoreState( stream, map );
3121 mySplit->deleteLater();
3124 QList<QtxWorkstackArea*> aList;
3125 areas( mySplit, aList, true );
3127 QtxWorkstackArea* a = !aList.isEmpty() ? aList.first() : 0;
3128 for ( QMap<QString, QtxWorkstackChild*>::const_iterator it = map.begin(); it != map.end(); ++it )
3130 QtxWorkstackChild* c = it.value();
3132 c->widget()->setVisible( false );
3134 a->insertChild( c );
3136 c->setVisible( false );
3144 \brief Set resize mode of all splitters opaque or transparent.
3145 \param opaque opaque mode
3147 void QtxWorkstack::setOpaqueResize( bool opaque )
3149 QList<QSplitter*> splitList;
3150 splitters( mySplit, splitList, true );
3151 splitList << mySplit;
3152 foreach( QSplitter* split, splitList )
3153 split->setOpaqueResize( opaque );
3157 \brief Get resize mode of all splitters: opaque (\c true) or transparent (\c false).
3158 \return current opaque mode
3160 bool QtxWorkstack::opaqueResize() const
3162 return mySplit->opaqueResize();
3167 \fn void QtxWorkstack::windowActivated( QWidget* w )
3168 \brief Emitted when the workstack's child widget \w is activated.
3169 \param w widget being activated
3173 \brief Gets area containing given widget
3175 \return pointer to QtxWorkstackArea* object
3177 QtxWorkstackArea* QtxWorkstack::wgArea( QWidget* wid ) const
3179 QtxWorkstackArea* resArea = 0;
3181 QList<QtxWorkstackArea*> areaList;
3182 areas( mySplit, areaList, true );
3184 QList<QtxWorkstackArea*>::ConstIterator it;
3185 for ( it = areaList.begin(); it != areaList.end() && !resArea; ++it )
3187 if ( (*it)->contains( wid ) )
3195 \brief Moves the first widget to the same area which the second widget belongs to
3196 \param wid widget to be moved
3197 \param wid_to widget specified the destination area
3198 \param before specifies whether the first widget has to be moved before or after
3200 \return TRUE if operation is completed successfully, FALSE otherwise
3202 bool QtxWorkstack::move( QWidget* wid, QWidget* wid_to, const bool before )
3204 if ( wid && wid_to )
3206 QtxWorkstackArea* area_src = wgArea( wid );
3207 QtxWorkstackArea* area_to = wgArea( wid_to );
3208 if ( area_src && area_to )
3210 // find index of the second widget
3211 QWidgetList wgList = area_to->widgetList();
3212 QWidgetList::ConstIterator it;
3214 for ( it = wgList.begin(); it != wgList.begin(); ++it, idx++ )
3216 if ( *it == wid_to )
3220 if ( idx < wgList.count() ) // paranoidal check
3224 area_src->removeWidget( wid, true );
3225 area_to->insertWidget( wid, idx );
3234 \brief Group all windows in one area
3235 \return TRUE if operation is completed successfully, FALSE otherwise
3237 void QtxWorkstack::stack()
3239 QWidgetList wgList = windowList();
3240 if ( !wgList.count() )
3241 return; // nothing to do
3243 QtxWorkstackArea* area_to = 0;
3244 QWidgetList::ConstIterator it;
3245 for ( it = wgList.begin(); it != wgList.end(); ++it )
3247 QtxWorkstackArea* area_src = 0;
3250 area_to = wgArea( *it );
3254 area_src = wgArea( *it );
3256 if ( area_src != area_to )
3258 area_src->removeWidget( *it, true );
3259 area_to->insertWidget( *it, -1 );
3260 (*it)->showMaximized();
3265 QAction* QtxWorkstack::action( const int id ) const
3267 return myActionsMap.contains( id ) ? myActionsMap[id] : 0;