1 // Copyright (C) 2007-2014 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, or (at your option) any later version.
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( 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 Set active widget
1799 \param wid widget to activate
1801 void QtxWorkstack::setActiveWindow( QWidget* wid )
1804 activeArea()->setActiveWidget( wid );
1808 \brief Split workstack.
1810 Splitting is possible only if there are two or more widgets in the workarea.
1811 This function splits current workarea to two new ones.
1813 \param o splitting orientation (Qt::Orientation)
1815 void QtxWorkstack::split( const int o )
1817 QtxWorkstackArea* area = myWorkArea;
1819 area = activeArea();
1823 if ( area->widgetList().count() < 2 )
1826 QWidget* curWid = area->activeWidget();
1830 QSplitter* s = splitter( area );
1831 QList<QtxWorkstackArea*> areaList;
1832 areas( s, areaList );
1834 QList<QSplitter*> splitList;
1835 splitters( s, splitList );
1838 if ( areaList.count() + splitList.count() < 2 || s->orientation() == o )
1842 trg = wrapSplitter( area );
1847 trg->setOrientation( (Qt::Orientation)o );
1849 QtxWorkstackArea* newArea = createArea( 0 );
1850 trg->insertWidget( trg->indexOf( area ) + 1, newArea );
1852 area->removeWidget( curWid );
1853 newArea->insertWidget( curWid );
1855 distributeSpace( trg );
1862 \brief Split workarea of the given widget on two parts.
1864 Splitting is possible only if there are two or more widgets in the workarea.
1865 This function splits current workarea to two new ones.
1867 \param wid widget belonging to the workstack
1868 \param o splitting orientation type (Qt::Orientation)
1869 \param type splitting type (QtxWorkstack::SplitType)
1871 void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType type )
1875 // find area of the given widget
1876 QtxWorkstackArea* area = NULL;
1877 QList<QtxWorkstackArea*> allAreas;
1878 areas(mySplit, allAreas, true);
1880 for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it )
1882 if ( (*it)->contains( wid ) )
1889 QWidget* curWid = area->activeWidget();
1893 QWidgetList wids = area->widgetList();
1894 if ( wids.count() < 2 )
1897 QSplitter* s = splitter( area );
1898 QList<QtxWorkstackArea*> areaList;
1899 areas( s, areaList );
1901 QList<QSplitter*> splitList;
1902 splitters(s, splitList);
1905 if (areaList.count() + splitList.count() < 2 || s->orientation() == o)
1908 if (!trg) trg = wrapSplitter(area);
1911 trg->setOrientation(o);
1913 QtxWorkstackArea* newArea = createArea(0);
1914 insertWidget(newArea, trg, area);
1919 for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr )
1921 QWidget* wid_i = *itr;
1924 area->removeWidget( wid_i );
1925 newArea->insertWidget( wid_i );
1926 wid_i->showMaximized();
1932 QWidgetList::iterator itr = wids.begin();
1933 for ( ; itr != wids.end() && *itr != wid; ++itr )
1936 for ( ; itr != wids.end(); ++itr )
1938 area->removeWidget( *itr );
1939 newArea->insertWidget( *itr );
1940 (*itr)->showMaximized();
1945 area->removeWidget( wid );
1946 newArea->insertWidget( wid );
1947 wid->showMaximized();
1951 distributeSpace( trg );
1958 \brief Move widget(s) from the source workarea into the target workarea
1959 or reorder widgets inside one workarea.
1961 Move \a wid2 in target workarea. Put it right after \a wid1.
1962 If \a all parameter is \c true, all widgets from source workarea
1963 will be moved including \a wid2 and source workarea will be deleted then.
1965 If \a wid1 and \a wid2 belongs to one workarea, widgets will be just reordered
1968 \param wid1 widget from target workarea
1969 \param wid2 widget from source workarea
1970 \param all if \c true, all widgets from source workarea will
1971 be moved into the target one, else only the \a wid2 will be moved
1973 void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all )
1975 if ( !wid1 || !wid2 )
1978 // find area of the widgets
1979 QtxWorkstackArea *area1 = 0, *area2 = 0;
1980 QList<QtxWorkstackArea*> allAreas;
1981 areas( mySplit, allAreas, true );
1982 for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !( area1 && area2 ); ++it )
1984 if ( (*it)->contains( wid1 ) )
1987 if ( (*it)->contains( wid2 ) )
1991 if ( !area1 || !area2 )
1994 QSplitter* s1 = splitter( area1 );
1996 QWidget* curWid = area1->activeWidget();
2000 if ( area1 == area2 )
2004 // Set wid1 at first position, wid2 at second
2005 area1->insertWidget( wid1 );
2006 area1->insertWidget( wid2, 1 );
2007 wid1->showMaximized();
2008 wid2->showMaximized();
2012 // Set wid2 right after wid1
2013 area1->removeWidget( wid2 );
2015 QWidgetList wids1 = area1->widgetList();
2016 for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind );
2017 area1->insertWidget( wid2, wid1_ind + 1 );
2018 wid2->showMaximized();
2024 QWidgetList wids1 = area1->widgetList();
2025 for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind );
2028 // Set wid2 right after wid1, other widgets from area2 right after wid2
2029 QWidgetList wids2 = area2->widgetList();
2030 QWidgetList::iterator itr2 = wids2.begin();
2031 for ( int ind = wid1_ind + 1; itr2 != wids2.end(); ++itr2, ++ind )
2033 area2->removeWidget( *itr2 );
2034 if ( *itr2 == wid2 )
2035 area1->insertWidget( *itr2, wid1_ind + 1 );
2037 area1->insertWidget( *itr2, ind );
2038 (*itr2)->showMaximized();
2043 // Set wid2 right after wid1
2044 area2->removeWidget( wid2 );
2045 area1->insertWidget( wid2, wid1_ind + 1 );
2046 wid2->showMaximized();
2050 distributeSpace( s1 );
2052 area1->setActiveWidget( curWid );
2061 \brief Calculate sizes of the splitter widget for the workarea.
2064 static void setSizes (QIntList& szList, const int item_ind,
2065 const int new_near, const int new_this, const int new_farr)
2067 // set size to all items before an item # <item_ind>
2069 QIntList::iterator its = szList.begin();
2070 for (; its != szList.end() && cur_pos < item_ind; ++its, ++cur_pos) {
2073 if (its == szList.end()) return;
2074 // set size to item # <item_ind>
2077 // set size to all items after an item # <item_ind>
2078 for (; its != szList.end(); ++its) {
2084 \brief Set position of the widget relatively to its parent splitter.
2086 Orientation of positioning will correspond to the splitter orientation.
2089 \param pos position relatively to the splitter; value in the range [0..1]
2091 void QtxWorkstack::SetRelativePositionInSplitter( QWidget* wid, const double position )
2093 if ( position < 0.0 || 1.0 < position)
2099 // find area of the given widget
2100 QtxWorkstackArea* area = NULL;
2101 QList<QtxWorkstackArea*> allAreas;
2102 areas( mySplit, allAreas, true );
2103 for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it )
2105 if ( (*it)->contains( wid ) )
2112 QSplitter* split = splitter( area );
2116 // find index of the area in its splitter
2118 bool isFound = false;
2119 const QObjectList& was = split->children();
2120 for ( QObjectList::const_iterator ito = was.begin(); ito != was.end() && !isFound; ++ito, ++item_ind )
2126 if ( !isFound || item_ind == 0 )
2129 QIntList szList = split->sizes();
2130 int splitter_size = ( split->orientation() == Qt::Horizontal ? split->width() : split->height());
2131 int nb = szList.count();
2133 int new_prev = int( splitter_size * position / item_ind );
2134 if (nb == item_ind) return;
2135 int new_next = int( splitter_size * ( 1.0 - position ) / ( nb - item_ind ) );
2136 setSizes( szList, item_ind, new_prev, new_next, new_next );
2137 split->setSizes( szList );
2141 \brief Set position of the widget relatively to the entire workstack.
2143 If \a o is \c Qt::Horizontal, the horizontal position of \a wid will be changed.
2144 If \a o is \c Qt::Vertical, the vertical position of \a wid will be changed.
2147 \param o orientation of positioning (\c Qt::Horizontal or \c Qt::Vertical)
2148 \param pos position relatively to the workstack; value in range [0..1]
2150 void QtxWorkstack::SetRelativePosition( QWidget* wid, const Qt::Orientation o,
2151 const double position )
2153 if ( position < 0.0 || 1.0 < position )
2159 int splitter_size = o == Qt::Horizontal ? mySplit->width() : mySplit->height();
2160 int need_pos = int( position * splitter_size );
2161 int splitter_pos = 0;
2163 if ( setPosition( wid, mySplit, o, need_pos, splitter_pos ) != 0 )
2165 // impossible to set required position
2170 \brief Set accelerator key-combination for the action with specified \a id.
2172 \param accel action accelerator
2174 void QtxWorkstack::setAccel( const int id, const int accel )
2176 if ( !myActionsMap.contains( id ) )
2179 myActionsMap[id]->setShortcut( accel );
2183 \brief Get the action's accelerator key-combination.
2185 \return action accelerator
2187 int QtxWorkstack::accel( const int id ) const
2190 if ( myActionsMap.contains( id ) )
2191 res = myActionsMap[id]->shortcut();
2196 \brief Get icon for the specified action.
2198 If \a id is invalid, null icon is returned.
2200 \param id menu action ID
2201 \return menu item icon
2203 QIcon QtxWorkstack::icon( const int id ) const
2206 if ( myActionsMap.contains( id ) )
2207 ico = myActionsMap[id]->icon();
2212 \brief Set menu item icon for the specified action.
2213 \param id menu action ID
2214 \param ico new menu item icon
2216 void QtxWorkstack::setIcon( const int id, const QIcon& icon )
2218 if ( !myActionsMap.contains( id ) )
2221 myActionsMap[id]->setIcon( icon );
2225 \brief Set actions to be visible in the context popup menu.
2227 Actions, which IDs are set in \a flags parameter, will be shown in the
2228 context popup menu. Other actions will not be shown.
2230 \param flags ORed together actions flags
2232 void QtxWorkstack::setMenuActions( const int flags )
2234 myActionsMap[SplitVertical]->setVisible( flags & SplitVertical );
2235 myActionsMap[SplitHorizontal]->setVisible( flags & SplitHorizontal );
2236 myActionsMap[Close]->setVisible( flags & Close );
2237 myActionsMap[Rename]->setVisible( flags & Rename );
2241 \brief Set actions to be visible in the context popup menu.
2243 Actions, which IDs are set in \a flags parameter, will be shown in the
2244 context popup menu. Other actions will not be shown.
2246 \param flags ORed together actions flags
2248 int QtxWorkstack::menuActions() const
2251 ret = ret | ( myActionsMap[SplitVertical]->isVisible() ? SplitVertical : 0 );
2252 ret = ret | ( myActionsMap[SplitHorizontal]->isVisible() ? SplitHorizontal : 0 );
2253 ret = ret | ( myActionsMap[Close]->isVisible() ? Close : 0 );
2254 ret = ret | ( myActionsMap[Rename]->isVisible() ? Rename : 0 );
2259 \brief Calculate sizes of the splitter widget for the workarea.
2262 static int positionSimple (QIntList& szList, const int nb, const int splitter_size,
2263 const int item_ind, const int item_rel_pos,
2264 const int need_pos, const int splitter_pos)
2266 if (item_ind == 0) { // cannot move in this splitter
2267 return (need_pos - splitter_pos);
2272 int new_this = szList[item_ind];
2275 bool isToCheck = false;
2277 if (need_pos < splitter_pos) {
2278 // Set size of all previous workareas to zero <--
2279 if (item_ind == nb - 1) {
2280 // item iz last in the splitter, it will occupy all the splitter
2281 new_this = splitter_size;
2283 // recompute size of next items in splitter
2284 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
2286 delta = need_pos - splitter_pos;
2288 } else if (need_pos > (splitter_pos + splitter_size)) {
2289 // Set size of all next workareas to zero -->
2290 // recompute size of previous items in splitter
2292 new_prev = (splitter_size - new_this) / item_ind;
2293 delta = need_pos - (splitter_pos + splitter_size - new_this);
2295 } else { // required position lays inside this splitter
2296 // Move workarea inside splitter into required position <->
2297 int new_item_rel_pos = need_pos - splitter_pos;
2298 new_prev = new_item_rel_pos / item_ind;
2299 if (need_pos < (splitter_pos + item_rel_pos)) {
2300 // Make previous workareas smaller, next - bigger
2301 // No problem to keep old size of the widget
2303 // Make previous workareas bigger, next - smaller
2304 if (new_this > splitter_size - new_item_rel_pos) {
2305 new_this = splitter_size - new_item_rel_pos;
2307 // jfa to do: in this case fixed size of next widgets could prevent right resizing
2310 if (item_ind == nb - 1) {
2311 new_this = splitter_size - new_item_rel_pos;
2313 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
2318 setSizes (szList, item_ind, new_prev, new_this, new_next);
2323 \brief Set position of the widget.
2325 Called from SetRelativePosition() public method.
2327 \param wid widget to be moved
2328 \param split currently processed splitter (goes from more common
2329 to more particular splitter in recursion calls)
2330 \param o orientation of positioning
2331 \param need_pos required position of the given widget in pixels
2332 (from top/left side of workstack area)
2333 \param splitter_pos position of the splitter \a split
2334 (from top/left side of workstack area)
2335 \return difference between a required and a distinguished position
2337 int QtxWorkstack::setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o,
2338 const int need_pos, const int splitter_pos )
2340 if ( !wid || !split )
2341 return need_pos - splitter_pos;
2343 // Find corresponding sub-splitter.
2344 // Find also index of appropriate item in current splitter.
2345 int cur_ind = 0, item_ind = 0;
2346 bool isBottom = false, isFound = false;
2347 QSplitter* sub_split = NULL;
2348 const QObjectList& objs = split->children();
2349 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end() && !isFound; ++it )
2351 QtxWorkstackArea* area = ::qobject_cast<QtxWorkstackArea*>( *it );
2354 if ( area->contains( wid ) )
2362 else if ( (*it)->inherits( "QSplitter" ) )
2364 QList<QtxWorkstackArea*> areaList;
2365 areas( (QSplitter*)(*it), areaList, true );
2366 for ( QList<QtxWorkstackArea*>::iterator ita = areaList.begin(); ita != areaList.end() && !isFound; ++ita )
2368 if ( (*ita)->contains( wid ) )
2372 sub_split = (QSplitter*)*it;
2380 return ( need_pos - splitter_pos );
2382 if ( split->orientation() == o )
2384 // Find coordinates of near and far sides of the appropriate item relatively current splitter
2385 int splitter_size = ( o == Qt::Horizontal ? split->width() : split->height() );
2386 QIntList szList = split->sizes();
2387 int nb = szList.count();
2388 int item_rel_pos = 0; // position of near side of item relatively this splitter
2389 for (int i = 0; i < item_ind; i++) {
2390 item_rel_pos += szList[i];
2392 int item_size = szList[item_ind]; // size of item
2393 int item_pos = splitter_pos + item_rel_pos;
2395 // Resize splitter items to complete the conditions
2397 // I. Bottom of splitters stack reached
2399 int delta = positionSimple(szList, nb, splitter_size, item_ind, item_rel_pos, need_pos, splitter_pos);
2400 split->setSizes(szList);
2401 // Recompute delta, as some windows can reject given size
2402 int new_item_rel_pos = 0;
2403 QIntList szList1 = split->sizes();
2404 for (int i = 0; i < item_ind; i++) {
2405 new_item_rel_pos += szList1[i];
2407 delta = need_pos - (splitter_pos + new_item_rel_pos);
2411 // II. Bottom of splitters stack is not yet reached
2413 if (item_ind == 0) { // cannot move in this splitter
2414 // Process in sub-splitter
2415 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
2419 int new_this = szList[item_ind];
2422 if (need_pos < splitter_pos) {
2423 // Set size of all previous workareas to zero <--
2424 if (item_ind == nb - 1) {
2425 new_this = splitter_size;
2427 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
2429 setSizes (szList, item_ind, new_prev, new_this, new_next);
2430 split->setSizes(szList);
2431 // Recompute splitter_pos, as some windows can reject given size
2432 int new_item_rel_pos = 0;
2433 QIntList szList1 = split->sizes();
2434 for (int i = 0; i < item_ind; i++) {
2435 new_item_rel_pos += szList1[i];
2437 // Process in sub-splitter
2438 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2439 } else if (need_pos > (splitter_pos + splitter_size)) {
2440 // Set size of all next workareas to zero -->
2441 new_prev = (splitter_size - new_this) / item_ind;
2442 setSizes (szList, item_ind, new_prev, new_this, new_next);
2443 split->setSizes(szList);
2444 // Recompute splitter_pos, as some windows can reject given size
2445 int new_item_rel_pos = 0;
2446 QIntList szList1 = split->sizes();
2447 for (int i = 0; i < item_ind; i++) {
2448 new_item_rel_pos += szList1[i];
2450 // Process in sub-splitter
2451 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2453 // Set appropriate size of all previous/next items <->
2454 int new_item_rel_pos = item_rel_pos;
2455 if (need_pos < item_pos || (item_pos + item_size) < need_pos) {
2456 // Move item inside splitter into required position <->
2457 int new_this = szList[item_ind];
2459 new_item_rel_pos = need_pos - splitter_pos;
2460 if ((item_pos + item_size) < need_pos) {
2461 //new_item_rel_pos = need_pos - (item_pos + item_size);
2462 new_item_rel_pos = item_rel_pos + (need_pos - (item_pos + item_size));
2464 int new_prev = new_item_rel_pos / item_ind;
2465 if (need_pos < (splitter_pos + item_rel_pos)) {
2466 // Make previous workareas smaller, next - bigger
2467 // No problem to keep old size of the widget
2469 // Make previous workareas bigger, next - smaller
2470 if (new_this > splitter_size - new_item_rel_pos) {
2471 new_this = splitter_size - new_item_rel_pos;
2474 if (item_ind == nb - 1) {
2475 new_this = splitter_size - new_item_rel_pos;
2477 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
2479 setSizes (szList, item_ind, new_prev, new_this, new_next);
2480 split->setSizes(szList);
2481 // Recompute new_item_rel_pos, as some windows can reject given size
2482 new_item_rel_pos = 0;
2483 QIntList szList1 = split->sizes();
2484 for (int i = 0; i < item_ind; i++) {
2485 new_item_rel_pos += szList1[i];
2490 // Process in sub-splitter
2491 int add_pos = setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2495 // this can be if corresponding workarea is first in sub-splitter
2496 // or sub-splitter has another orientation
2498 // Resize ones again to reach precize position <->
2499 int need_pos_1 = splitter_pos + new_item_rel_pos + add_pos;
2501 // Move workarea inside splitter into required position <->
2502 int delta_1 = positionSimple(szList, nb, splitter_size, item_ind,
2503 new_item_rel_pos, need_pos_1, splitter_pos);
2504 split->setSizes(szList);
2505 // Recompute new_item_rel_pos, as some windows can reject given size
2506 new_item_rel_pos = 0;
2507 QIntList szList1 = split->sizes();
2508 for (int i = 0; i < item_ind; i++) {
2509 new_item_rel_pos += szList1[i];
2511 delta_1 = need_pos_1 - (splitter_pos + new_item_rel_pos);
2516 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
2523 \brief Redistribute space among widgets equally.
2524 \param split splitter
2526 void QtxWorkstack::distributeSpace( QSplitter* split ) const
2531 QIntList szList = split->sizes();
2532 int size = ( split->orientation() == Qt::Horizontal ?
2533 split->width() : split->height() ) / szList.count();
2534 for ( QIntList::iterator it = szList.begin(); it != szList.end(); ++it )
2536 split->setSizes( szList );
2540 \brief Split widgets vertically.
2542 void QtxWorkstack::splitVertical()
2544 split( Qt::Horizontal );
2548 \brief Split widgets horizontally.
2550 void QtxWorkstack::splitHorizontal()
2552 split( Qt::Vertical );
2556 \brief Called when user activates "Rename" menu item.
2558 Changes widget title.
2560 void QtxWorkstack::onRename()
2566 QString newName = QInputDialog::getText( topLevelWidget(), tr( "Rename" ), tr( "Enter new name:" ),
2567 QLineEdit::Normal, myWorkWin->windowTitle(), &ok );
2568 if ( ok && !newName.isEmpty() )
2569 myWorkWin->setWindowTitle( newName );
2573 \brief Wrap area into the new splitter.
2575 \return new splitter
2577 QSplitter* QtxWorkstack::wrapSplitter( QtxWorkstackArea* area )
2582 QSplitter* pSplit = splitter( area );
2586 bool upd = pSplit->updatesEnabled();
2587 pSplit->setUpdatesEnabled( false );
2589 QIntList szList = pSplit->sizes();
2591 QSplitter* wrap = new QtxWorkstackSplitter( 0 );
2592 pSplit->insertWidget( pSplit->indexOf( area ) + 1, wrap );
2593 wrap->setVisible( true );
2594 wrap->addWidget( area );
2596 pSplit->setSizes( szList );
2598 pSplit->setUpdatesEnabled( upd );
2604 \brief Reparent and add widget.
2606 \param pWid parent widget
2607 \param after widget after which \a wid should be added
2609 void QtxWorkstack::insertWidget( QWidget* wid, QWidget* pWid, QWidget* after )
2611 if ( !wid || !pWid )
2614 QWidgetList moveList;
2615 const QObjectList& lst = pWid->children();
2617 for ( QObjectList::const_iterator it = lst.begin(); it != lst.end(); ++it )
2619 if ( found && ( (*it)->inherits( "QSplitter" ) ||
2620 (*it)->inherits( "QtxWorkstackArea" ) ) )
2621 moveList.append( (QWidget*)(*it) );
2626 QMap<QWidget*, bool> map;
2627 for ( QWidgetList::iterator it = moveList.begin(); it != moveList.end(); ++it )
2629 map.insert( *it, (*it)->isVisibleTo( (*it)->parentWidget() ) );
2630 (*it)->setParent( 0 );
2634 wid->setParent( pWid );
2636 for ( QWidgetList::iterator itr = moveList.begin(); itr != moveList.end(); ++itr )
2638 (*itr)->setParent( pWid );
2639 (*itr)->setShown( map.contains( *itr ) ? map[*itr] : false );
2644 \brief Close active window.
2646 void QtxWorkstack::onCloseWindow()
2650 else if( activeWindow() )
2651 activeWindow()->close();
2655 \brief Called when workarea is destroyed.
2657 Set input focus to the neighbour area.
2659 \param obj workarea being destroyed
2661 void QtxWorkstack::onDestroyed( QObject* obj )
2663 QtxWorkstackArea* area = (QtxWorkstackArea*)obj;
2665 if ( area == myArea )
2670 QtxWorkstackArea* cur = neighbourArea( area );
2675 QApplication::postEvent( this, new QEvent( QEvent::User ) );
2679 \brief Called on window activating.
2680 \param area workarea being activated (not used)
2682 void QtxWorkstack::onWindowActivated( QWidget* /*area*/ )
2684 const QObject* obj = sender();
2685 if ( !obj->inherits( "QtxWorkstackArea" ) )
2688 setActiveArea( (QtxWorkstackArea*)obj );
2692 \brief Called on window deactivating.
2693 \param area workarea being deactivated
2695 void QtxWorkstack::onDeactivated( QtxWorkstackArea* area )
2697 if ( myArea != area )
2700 QList<QtxWorkstackArea*> lst;
2701 areas( mySplit, lst, true );
2703 int idx = lst.indexOf( area );
2710 QtxWorkstackArea* newArea = neighbourArea( area );
2711 if ( newArea && newArea->activeWidget() )
2712 newArea->activeWidget()->setFocus();
2714 QApplication::postEvent( this, new QEvent( QEvent::User ) );
2718 \brief Create and show popup menu for workarea.
2720 \param p popup position
2722 void QtxWorkstack::onContextMenuRequested( QWidget* w, QPoint p )
2724 QtxWorkstackArea* anArea = ::qobject_cast<QtxWorkstackArea*>( (QObject*)sender() );
2726 anArea = activeArea();
2731 QWidgetList lst = anArea->widgetList();
2732 if ( lst.isEmpty() )
2736 myWorkArea = anArea;
2738 QMenu* pm = new QMenu();
2740 if ( lst.count() > 1 )
2742 if ( !myActionsMap[SplitVertical]->isEnabled() )
2743 myActionsMap[SplitVertical]->setEnabled(true);
2744 pm->addAction( myActionsMap[SplitVertical] );
2745 if ( !myActionsMap[SplitHorizontal]->isEnabled() )
2746 myActionsMap[SplitHorizontal]->setEnabled(true);
2747 pm->addAction( myActionsMap[SplitHorizontal] );
2753 if ( myActionsMap[Close]->isEnabled() )
2754 pm->addAction( myActionsMap[Close] );
2755 if ( myActionsMap[Rename]->isEnabled() )
2756 pm->addAction( myActionsMap[Rename] );
2759 Qtx::simplifySeparators( pm );
2761 if ( !pm->actions().isEmpty() )
2771 \brief Add child widget.
2773 \param f widget flags
2774 \return child widget container
2776 QWidget* QtxWorkstack::addWindow( QWidget* w, Qt::WindowFlags f )
2781 return targetArea()->insertWidget( w, -1, f );
2785 \brief Handle custom events.
2786 \param e custom event (not used)
2788 void QtxWorkstack::customEvent( QEvent* /*e*/ )
2794 \brief Get splitter corresponding to the workarea.
2796 \return splitter corresponding to the workarea
2798 QSplitter* QtxWorkstack::splitter( QtxWorkstackArea* area ) const
2803 QSplitter* split = 0;
2805 QWidget* wid = area->parentWidget();
2806 if ( wid && wid->inherits( "QSplitter" ) )
2807 split = (QSplitter*)wid;
2813 \brief Get list of child splitters.
2814 \param split parent splitter
2815 \param splitList list to be filled with child splitters
2816 \param rec if \c true, perform recursive search of children
2818 void QtxWorkstack::splitters( QSplitter* split, QList<QSplitter*>& splitList, const bool rec ) const
2823 const QObjectList& objs = split->children();
2824 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
2827 splitters( (QSplitter*)*it, splitList, rec );
2828 if ( (*it)->inherits( "QSplitter" ) )
2829 splitList.append( (QSplitter*)*it );
2834 \brief Get list of child workareas.
2835 \param split parent splitter
2836 \param areaList list to be filled with child workareas
2837 \param rec if \c true, perform recursive search of children
2839 void QtxWorkstack::areas( QSplitter* split, QList<QtxWorkstackArea*>& areaList, const bool rec ) const
2844 const QObjectList& objs = split->children();
2845 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
2847 if ( (*it)->inherits( "QtxWorkstackArea" ) )
2848 areaList.append( (QtxWorkstackArea*)*it );
2849 else if ( rec && (*it)->inherits( "QSplitter" ) )
2850 areas( (QSplitter*)*it, areaList, rec );
2855 \brief Get active workarea.
2856 \return active workarea
2858 QtxWorkstackArea* QtxWorkstack::activeArea() const
2864 \brief Get target area (for which the current operation should be done).
2866 Returns active workarea or current area (if there is no active workarea).
2867 If there are no workareas, create new workarea and return it.
2871 QtxWorkstackArea* QtxWorkstack::targetArea()
2873 QtxWorkstackArea* area = activeArea();
2875 area = currentArea();
2878 QList<QtxWorkstackArea*> lst;
2879 areas( mySplit, lst );
2880 if ( !lst.isEmpty() )
2885 area = createArea( mySplit );
2891 \brief Get current workarea.
2893 Current workarea is that one which has input focus.
2895 \return current area
2897 QtxWorkstackArea* QtxWorkstack::currentArea() const
2899 QtxWorkstackArea* area = 0;
2900 QWidget* wid = focusWidget();
2901 while ( wid && !area )
2903 if ( wid->inherits( "QtxWorkstackArea" ) )
2904 area = (QtxWorkstackArea*)wid;
2905 wid = wid->parentWidget();
2912 \brief Create new workarea.
2913 \param parent parent widget
2914 \return created workarea
2916 QtxWorkstackArea* QtxWorkstack::createArea( QWidget* parent ) const
2918 QtxWorkstackArea* area = new QtxWorkstackArea( parent );
2920 connect( area, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
2921 connect( area, SIGNAL( activated( QWidget* ) ), this, SLOT( onWindowActivated( QWidget* ) ) );
2922 connect( area, SIGNAL( contextMenuRequested( QWidget*, QPoint ) ),
2923 this, SLOT( onContextMenuRequested( QWidget*, QPoint ) ) );
2924 connect( area, SIGNAL( deactivated( QtxWorkstackArea* ) ), this, SLOT( onDeactivated( QtxWorkstackArea* ) ) );
2930 \brief Set active workarea.
2933 void QtxWorkstack::setActiveArea( QtxWorkstackArea* area )
2935 QWidget* oldCur = myWin;
2937 QtxWorkstackArea* oldArea = myArea;
2941 if ( myArea != oldArea )
2944 oldArea->updateActiveState();
2946 myArea->updateActiveState();
2950 myWin = myArea->activeWidget();
2952 if ( myWin && oldCur != myWin )
2953 emit windowActivated( myWin );
2957 \brief Get workarea which is nearest to \a area.
2958 \param area area for which neighbour is searched
2959 \return neighbour area (or 0 if not found)
2961 QtxWorkstackArea* QtxWorkstack::neighbourArea( QtxWorkstackArea* area ) const
2963 QList<QtxWorkstackArea*> lst;
2964 areas( mySplit, lst, true );
2965 int pos = lst.indexOf( area );
2969 QtxWorkstackArea* na = 0;
2970 for ( int i = pos - 1; i >= 0 && !na; i-- )
2972 if ( !lst.at( i )->isEmpty() )
2976 for ( int j = pos + 1; j < (int)lst.count() && !na; j++ )
2978 if ( !lst.at( j )->isEmpty() )
2985 \brief Get workarea covering point.
2989 QtxWorkstackArea* QtxWorkstack::areaAt( const QPoint& p ) const
2991 QtxWorkstackArea* area = 0;
2992 QList<QtxWorkstackArea*> lst;
2993 areas( mySplit, lst, true );
2994 for ( QList<QtxWorkstackArea*>::iterator it = lst.begin(); it != lst.end() && !area; ++it )
2996 QtxWorkstackArea* cur = *it;
2997 QRect r = cur->geometry();
2998 if ( cur->parentWidget() )
2999 r = QRect( cur->parentWidget()->mapToGlobal( r.topLeft() ), r.size() );
3000 if ( r.contains( p ) )
3007 \brief Update internal state.
3009 void QtxWorkstack::updateState()
3011 updateState( mySplit );
3015 \brief Update splitter state.
3016 \param split splitter to be updated
3018 void QtxWorkstack::updateState( QSplitter* split )
3020 QList<QSplitter*> recList;
3021 splitters( split, recList, false );
3022 for ( QList<QSplitter*>::iterator itr = recList.begin(); itr != recList.end(); ++itr )
3023 updateState( *itr );
3025 QList<QSplitter*> splitList;
3026 splitters( split, splitList, false );
3028 QList<QtxWorkstackArea*> areaList;
3029 areas( split, areaList, false );
3032 for ( QList<QtxWorkstackArea*>::iterator it = areaList.begin(); it != areaList.end(); ++it )
3034 if ( (*it)->isEmpty() )
3043 if ( split == mySplit )
3046 for ( QList<QSplitter*>::iterator iter = splitList.begin(); iter != splitList.end() && !vis; ++iter )
3047 vis = (*iter)->isVisibleTo( (*iter)->parentWidget() );
3049 if ( areaList.isEmpty() && splitList.isEmpty() )
3052 split->setVisible( vis );
3056 \brief Dump workstack configuration to the state description array.
3057 \param version number
3058 \return state byte array.
3060 QByteArray QtxWorkstack::saveState( int version ) const
3064 QDataStream stream( &data, QIODevice::WriteOnly );
3065 stream << QtxWorkstack::VersionMarker;
3067 saveState( stream );
3073 \brief Restore workstack configuration from the state description array.
3074 \param version number
3075 \return restore performing state
3077 bool QtxWorkstack::restoreState( const QByteArray& state, int version )
3079 if ( state.isEmpty() )
3082 QByteArray sd = state;
3083 QDataStream stream( &sd, QIODevice::ReadOnly );
3087 if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::VersionMarker || ver != version )
3090 return restoreState( stream );
3093 void QtxWorkstack::saveState( QDataStream& stream ) const
3095 mySplit->saveState( stream );
3098 bool QtxWorkstack::restoreState( QDataStream& stream )
3100 QMap<QString, QtxWorkstackChild*> map;
3101 QList<QtxWorkstackArea*> areaList;
3102 areas( mySplit, areaList, true );
3103 for ( QList<QtxWorkstackArea*>::const_iterator it = areaList.begin(); it != areaList.end(); ++it )
3105 QtxWorkstackArea* area = *it;
3106 QList<QtxWorkstackChild*> childList = area->childList();
3107 for ( QList<QtxWorkstackChild*>::iterator itr = childList.begin(); itr != childList.end(); ++itr )
3109 QtxWorkstackChild* c = *itr;
3113 map.insert( c->widget()->objectName(), c );
3115 qDebug( "QtxWorkstack::restoreState: found widget \"%s\"", (const char*)c->widget()->objectName().toLatin1() );
3121 if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::SplitMarker )
3124 QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this );
3126 layout()->addWidget( split );
3128 bool ok = split->restoreState( stream, map );
3133 mySplit->deleteLater();
3136 QList<QtxWorkstackArea*> aList;
3137 areas( mySplit, aList, true );
3139 QtxWorkstackArea* a = !aList.isEmpty() ? aList.first() : 0;
3140 for ( QMap<QString, QtxWorkstackChild*>::const_iterator it = map.begin(); it != map.end(); ++it )
3142 QtxWorkstackChild* c = it.value();
3144 c->widget()->setVisible( false );
3146 a->insertChild( c );
3148 c->setVisible( false );
3156 \brief Set resize mode of all splitters opaque or transparent.
3157 \param opaque opaque mode
3159 void QtxWorkstack::setOpaqueResize( bool opaque )
3161 QList<QSplitter*> splitList;
3162 splitters( mySplit, splitList, true );
3163 splitList << mySplit;
3164 foreach( QSplitter* split, splitList )
3165 split->setOpaqueResize( opaque );
3169 \brief Get resize mode of all splitters: opaque (\c true) or transparent (\c false).
3170 \return current opaque mode
3172 bool QtxWorkstack::opaqueResize() const
3174 return mySplit->opaqueResize();
3179 \fn void QtxWorkstack::windowActivated( QWidget* w )
3180 \brief Emitted when the workstack's child widget \w is activated.
3181 \param w widget being activated
3185 \brief Gets area containing given widget
3187 \return pointer to QtxWorkstackArea* object
3189 QtxWorkstackArea* QtxWorkstack::wgArea( QWidget* wid ) const
3191 QtxWorkstackArea* resArea = 0;
3193 QList<QtxWorkstackArea*> areaList;
3194 areas( mySplit, areaList, true );
3196 QList<QtxWorkstackArea*>::ConstIterator it;
3197 for ( it = areaList.begin(); it != areaList.end() && !resArea; ++it )
3199 if ( (*it)->contains( wid ) )
3207 \brief Moves the first widget to the same area which the second widget belongs to
3208 \param wid widget to be moved
3209 \param wid_to widget specified the destination area
3210 \param before specifies whether the first widget has to be moved before or after
3212 \return TRUE if operation is completed successfully, FALSE otherwise
3214 bool QtxWorkstack::move( QWidget* wid, QWidget* wid_to, const bool before )
3216 if ( wid && wid_to )
3218 QtxWorkstackArea* area_src = wgArea( wid );
3219 QtxWorkstackArea* area_to = wgArea( wid_to );
3220 if ( area_src && area_to )
3222 // find index of the second widget
3223 QWidgetList wgList = area_to->widgetList();
3224 QWidgetList::ConstIterator it;
3226 for ( it = wgList.begin(); it != wgList.begin(); ++it, idx++ )
3228 if ( *it == wid_to )
3232 if ( idx < wgList.count() ) // paranoidal check
3236 area_src->removeWidget( wid, true );
3237 area_to->insertWidget( wid, idx );
3238 wid->showMaximized();
3247 \brief Group all windows in one area
3248 \return TRUE if operation is completed successfully, FALSE otherwise
3250 void QtxWorkstack::stack()
3252 QWidgetList wgList = windowList();
3253 if ( !wgList.count() )
3254 return; // nothing to do
3256 QtxWorkstackArea* area_to = 0;
3257 QWidgetList::ConstIterator it;
3258 for ( it = wgList.begin(); it != wgList.end(); ++it )
3260 QtxWorkstackArea* area_src = 0;
3263 area_to = wgArea( *it );
3267 area_src = wgArea( *it );
3269 if ( area_src != area_to )
3271 area_src->removeWidget( *it, true );
3272 area_to->insertWidget( *it, -1 );
3273 (*it)->showMaximized();
3278 QAction* QtxWorkstack::action( const int id ) const
3280 return myActionsMap.contains( id ) ? myActionsMap[id] : 0;