1 // Copyright (C) 2007-2015 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 myTop = new QWidget( this );
532 base->addWidget( myTop );
534 QHBoxLayout* tl = new QHBoxLayout( myTop );
537 myBar = new QtxWorkstackTabBar( myTop );
538 tl->addWidget( myBar, 1 );
540 CloseButton* close = new CloseButton( myTop );
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 Show/Hide tab bar.
908 void QtxWorkstackArea::showTabBar( bool visible)
910 myTop->setVisible(visible);
911 myBar->setVisible(visible);
916 \brief Get rectangle to be drawn when highlighting drop area.
917 \return area drop rectangle
919 QRect QtxWorkstackArea::floatRect() const
921 QRect r = myStack->geometry();
922 return QRect( mapToGlobal( r.topLeft() ), mapToGlobal( r.bottomRight() ) );
926 \brief Get rectangle to be drawn when highlighting drop area on tab bar.
928 \return tab bar drop rectrangle
930 QRect QtxWorkstackArea::floatTab( const int idx ) const
932 QRect r = myBar->tabRect( idx );
933 return QRect( myBar->mapToGlobal( r.topLeft() ), r.size() );
937 \brief Get tab index by point.
939 \return tab covering point or -1 if there is no tab covering point
941 int QtxWorkstackArea::tabAt( const QPoint& pnt ) const
944 QPoint p = myBar->mapFromGlobal( pnt );
945 for ( int i = 0; i < myBar->count() && idx == -1; i++ )
947 QRect r = myBar->tabRect( i );
948 if ( r.isValid() && r.contains( p ) )
955 \brief Event handler for custom events.
956 \param e custom event
958 void QtxWorkstackArea::customEvent( QEvent* e )
960 WidgetEvent* we = (WidgetEvent*)e;
962 switch ( we->type() )
965 myBar->updateActiveState();
966 // IMN 27/03/2015: This workaround caused by the bug INT PAL 0052623: OCC view blinking when
967 // using polyline sketcher which is reproduced on Unix systems with qt-4.8.4.
968 myStack->setUpdatesEnabled( false );
970 myStack->setUpdatesEnabled( true );
971 emit activated( activeWidget() );
974 if ( activeWidget() )
976 if ( !activeWidget()->focusWidget() )
977 activeWidget()->setFocus();
980 if ( activeWidget()->focusWidget()->hasFocus() )
982 QFocusEvent in( QEvent::FocusIn );
983 QApplication::sendEvent( this, &in );
987 activeWidget()->focusWidget()->setFocus();
988 myBar->updateActiveState();
994 if ( we->child()->widget() )
995 setActiveWidget( we->child()->widget() );
1000 QtxWorkstackChild* c = we->child();
1001 RestoreEvent* re = (RestoreEvent*)we;
1003 c->widget()->setVisible( re->flags() & QtxWorkstack::Visible );
1004 c->setId( re->id() );
1014 \brief Customize focus in event handler.
1015 \param e focus in event
1017 void QtxWorkstackArea::focusInEvent( QFocusEvent* e )
1019 QFrame::focusInEvent( e );
1021 myBar->updateActiveState();
1023 emit activated( activeWidget() );
1027 \brief Customize mouse press event handler.
1028 \param e mouse press event
1030 void QtxWorkstackArea::mousePressEvent( QMouseEvent* e )
1032 QFrame::mousePressEvent( e );
1034 emit activated( activeWidget() );
1038 \brief Called when user presses "Close" button.
1040 void QtxWorkstackArea::onClose()
1042 QWidget* wid = activeWidget();
1048 \brief Called when user selects any tab page.
1049 \param idx tab page index (not used)
1051 void QtxWorkstackArea::onCurrentChanged( int /*idx*/ )
1055 emit activated( activeWidget() );
1059 \brief Called when user starts tab page dragging.
1061 void QtxWorkstackArea::onDragActiveTab()
1063 QtxWorkstackChild* c = child( activeWidget() );
1067 new QtxWorkstackDrag( workstack(), c );
1071 \brief Called when area's child widget container is destroyed.
1072 \param obj widget container being destroyed
1074 void QtxWorkstackArea::onChildDestroyed( QObject* obj )
1076 removeChild( (QtxWorkstackChild*)obj, false );
1080 \brief Called when child widget container is shown.
1081 \param c child widget container being shown
1083 void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c )
1089 \brief Called when child widget container is hidden.
1090 \param c child widget container being hidden
1092 void QtxWorkstackArea::onChildHidden( QtxWorkstackChild* c )
1098 \brief Called when child widget container is activated.
1099 \param c child widget container being activated
1101 void QtxWorkstackArea::onChildActivated( QtxWorkstackChild* c )
1103 setWidgetActive( c->widget() );
1107 \brief Called when child widget container's title is changed.
1108 \param c child widget container which title is changed
1110 void QtxWorkstackArea::onChildCaptionChanged( QtxWorkstackChild* c )
1112 updateTab( c->widget() );
1116 \brief Update current child widget container.
1118 Raises widget when active tab page is changed.
1120 void QtxWorkstackArea::updateCurrent()
1122 QWidget* cur = child( myBar->tabId( myBar->currentIndex() ) );
1124 myStack->setCurrentWidget( cur );
1128 \brief Update tab bar.
1129 \param wid tab page widget
1131 void QtxWorkstackArea::updateTab( QWidget* wid )
1133 int idx = myBar->indexOf( widgetId( wid ) );
1137 myBar->setTabIcon( idx, wid->windowIcon() );
1138 myBar->setTabText( idx, wid->windowTitle() );
1142 \brief Get child widget by specified identifier.
1144 \return widget or 0, if identifier in invalid
1146 QWidget* QtxWorkstackArea::widget( const int id ) const
1148 QtxWorkstackChild* c = child( id );
1150 return c ? c->widget() : 0;
1154 \brief Get child widget identifier.
1156 \return widget ID or -1 if widget is not found
1158 int QtxWorkstackArea::widgetId( QWidget* wid ) const
1160 QtxWorkstackChild* c = child( wid );
1162 return c ? c->id() : -1;
1166 \brief Set active child widget.
1167 \param wid widget to be set active
1169 void QtxWorkstackArea::setWidgetActive( QWidget* wid )
1171 int id = widgetId( wid );
1175 myBar->setCurrentIndex( myBar->indexOf( id ) );
1179 \brief Update internal state.
1181 void QtxWorkstackArea::updateState()
1183 bool updBar = myBar->updatesEnabled();
1184 bool updStk = myStack->updatesEnabled();
1185 myBar->setUpdatesEnabled( false );
1186 myStack->setUpdatesEnabled( false );
1188 bool block = myBar->signalsBlocked();
1189 myBar->blockSignals( true );
1191 QWidget* prev = activeWidget();
1194 for ( ChildList::iterator it = myList.begin(); it != myList.end(); ++it )
1196 QtxWorkstackChild* cont = *it;
1197 QWidget* wid = cont->widget();;
1198 int id = cont->id();
1203 bool vis = cont->visibility();
1205 int cIdx = myBar->indexOf( id );
1206 if ( cIdx != -1 && ( !vis || myBar->indexOf( id ) != idx ) )
1207 myBar->removeTab( cIdx );
1209 if ( myBar->indexOf( id ) == -1 && vis )
1210 myBar->setTabId( myBar->insertTab( idx, wid->windowTitle() ), id );
1215 myStack->removeWidget( cont );
1216 else if ( myStack->indexOf( cont ) < 0 )
1217 myStack->addWidget( cont );
1223 int curId = widgetId( prev );
1224 if ( myBar->indexOf( curId ) < 0 )
1226 QtxWorkstackChild* c = 0;
1227 int pos = myList.indexOf( child( prev ) );
1228 for ( int i = pos - 1; i >= 0 && !c; i-- )
1230 if ( myList.at( i )->visibility() )
1234 for ( int j = pos + 1; j < (int)myList.count() && !c; j++ )
1236 if ( myList.at( j )->visibility() )
1244 myBar->setCurrentIndex( myBar->indexOf( curId ) );
1246 myBar->blockSignals( block );
1250 myBar->updateActiveState();
1252 myBar->setUpdatesEnabled( updBar );
1253 myStack->setUpdatesEnabled( updStk );
1259 QResizeEvent re( myBar->size(), myBar->size() );
1260 QApplication::sendEvent( myBar, &re );
1262 myBar->updateGeometry();
1267 emit deactivated( this );
1272 if ( prev != activeWidget() )
1273 emit activated( activeWidget() );
1278 \brief Generate unique widget identifier.
1279 \return first non shared widget ID
1281 int QtxWorkstackArea::generateId() const
1285 for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it )
1286 map.insert( (*it)->id(), 0 );
1289 while ( map.contains( id ) )
1296 \brief Get child widget container.
1297 \param wid child widget
1298 \return child widget container corresponding to the \a wid
1300 QtxWorkstackChild* QtxWorkstackArea::child( QWidget* wid ) const
1302 QtxWorkstackChild* res = 0;
1303 for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !res; ++it )
1305 if ( (*it)->widget() == wid )
1311 QtxWorkstackChild* QtxWorkstackArea::child( const int id ) const
1313 QtxWorkstackChild* c = 0;
1314 for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !c; ++it )
1316 if ( (*it)->id() == id )
1323 \fn void QtxWorkstackArea::activated( QWidget* w )
1324 \brief Emitted when child widget is activated.
1325 \param w child widget being activated
1329 \fn void QtxWorkstackArea::contextMenuRequested( QWidget* w, QPoint p )
1330 \brief Emitted when context popup menu is requested.
1331 \param w child widget popup menu requested for
1332 \param p point popup menu to be shown at
1336 \fn void QtxWorkstackArea::deactivated( QtxWorkstackArea* wa )
1337 \brief Emitted when workarea is deactivated.
1338 \param wa workarea being deactivated
1342 \class QtxWorkstackChild
1344 \brief Workarea child widget container.
1349 \param wid child widget
1350 \param parent parent widget
1351 \param f widget flags
1353 QtxWorkstackChild::QtxWorkstackChild( QWidget* wid, QWidget* parent, Qt::WindowFlags f )
1354 : QWidget( parent ),
1360 myWidget->setParent( this, f );
1361 myWidget->installEventFilter( this );
1362 if ( myWidget->focusProxy() )
1363 myWidget->focusProxy()->installEventFilter( this );
1364 myWidget->setVisible( myWidget->isVisibleTo( myWidget->parentWidget() ) );
1366 QVBoxLayout* base = new QVBoxLayout( this );
1367 base->setMargin( 0 );
1368 base->addWidget( myWidget );
1370 connect( myWidget, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
1377 QtxWorkstackChild::~QtxWorkstackChild()
1379 QApplication::instance()->removeEventFilter( this );
1384 disconnect( widget(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
1387 widget()->removeEventFilter( this );
1388 if ( widget()->focusProxy() )
1389 widget()->focusProxy()->removeEventFilter( this );
1391 widget()->setParent( 0 );
1395 \brief Get child widget.
1396 \return child widget
1398 QWidget* QtxWorkstackChild::widget() const
1404 \brief Returns the id.
1406 int QtxWorkstackChild::id() const
1414 void QtxWorkstackChild::setId( const int id )
1420 \brief Returns true if this child window should be visible.
1422 bool QtxWorkstackChild::visibility()
1424 return myWidget ? myWidget->isVisibleTo( this ) : false;
1427 QtxWorkstackArea* QtxWorkstackChild::area() const
1429 QtxWorkstackArea* a = 0;
1430 QWidget* w = parentWidget();
1433 a = ::qobject_cast<QtxWorkstackArea*>( w );
1434 w = w->parentWidget();
1441 \brief Custom event filter.
1443 Process events from child widgets.
1445 \param o event receiver widget
1447 \return \c true if event should be filtered (stop further processing)
1449 bool QtxWorkstackChild::eventFilter( QObject* o, QEvent* e )
1451 if ( o->isWidgetType() )
1453 if ( e->type() == QEvent::WindowTitleChange || e->type() == QEvent::WindowIconChange )
1454 emit captionChanged( this );
1456 if ( !e->spontaneous() && e->type() == QEvent::ShowToParent )
1459 if ( !e->spontaneous() && e->type() == QEvent::HideToParent )
1460 emit hidden( this );
1462 if ( e->type() == QEvent::FocusIn )
1463 emit activated( this );
1465 return QWidget::eventFilter( o, e );
1469 \brief Called when child widget is destroyed.
1470 \param obj child widget being destroyed
1472 void QtxWorkstackChild::onDestroyed( QObject* obj )
1478 \brief Customize child event handler.
1479 \param e child event
1481 void QtxWorkstackChild::childEvent( QChildEvent* e )
1483 if ( e->removed() && e->child() == widget() )
1488 QWidget::childEvent( e );
1492 \fn void QtxWorkstackChild::shown( QtxWorkstackChild* w )
1493 \brief Emitted when child widget is shown.
1494 \param w child widget container
1498 \fn void QtxWorkstackChild::hidden( QtxWorkstackChild* w )
1499 \brief Emitted when child widget is hidden.
1500 \param w child widget container
1504 \fn void QtxWorkstackChild::activated( QtxWorkstackChild* w )
1505 \brief Emitted when child widget is activated.
1506 \param w child widget container
1510 \fn void QtxWorkstackChild::captionChanged( QtxWorkstackChild* w )
1511 \brief Emitted when child widget's title is changed.
1512 \param w child widget container
1516 \class QtxWorkstackTabBar
1518 \brief Workstack tab bar widget
1523 \param parent parent widget
1525 QtxWorkstackTabBar::QtxWorkstackTabBar( QWidget* parent )
1526 : QTabBar( parent ),
1527 myId( -1 ),myActive(false)
1529 setDrawBase( true );
1530 setElideMode( Qt::ElideNone );
1532 connect( this, SIGNAL( currentChanged( int ) ), this, SLOT( onCurrentChanged( int ) ) );
1538 QtxWorkstackTabBar::~QtxWorkstackTabBar()
1543 \brief Get tab page identifier.
1544 \param index tab page index
1545 \return tab page ID or -1 if \a index is out of range
1547 int QtxWorkstackTabBar::tabId( const int index ) const
1549 QVariant v = tabData( index );
1550 if ( !v.canConvert( QVariant::Int ) )
1556 \brief Set tab page identifier.
1557 \param index tab page index
1558 \param id tab page ID
1560 void QtxWorkstackTabBar::setTabId( const int index, const int id )
1562 setTabData( index, id );
1566 \brief Get tab page index by specified identifier.
1567 \param id tab page ID
1568 \return tab page index or -1 if not found
1570 int QtxWorkstackTabBar::indexOf( const int id ) const
1573 for ( int i = 0; i < (int)count() && index < 0; i++ )
1575 if ( tabId( i ) == id )
1582 \brief Check if the tab bar is active.
1583 \return \c true if tab bar is active
1585 bool QtxWorkstackTabBar::isActive() const
1591 \brief Set tab bar active/inactive.
1592 \param on new active state
1594 void QtxWorkstackTabBar::setActive( const bool on )
1596 if ( myActive == on )
1600 updateActiveState();
1604 \brief Update tab bar according to the 'active' state.
1606 void QtxWorkstackTabBar::updateActiveState()
1608 QColor bc = palette().color( QPalette::Text );
1609 QColor ac = isActive() ? palette().color( QPalette::Highlight ) : bc;
1610 for ( int i = 0; i < (int)count(); i++ )
1611 setTabTextColor( i, currentIndex() == i ? ac : bc );
1615 \brief Called when current tab page is changed.
1616 \param idx tab page index (not used)
1618 void QtxWorkstackTabBar::onCurrentChanged( int /*index*/ )
1620 updateActiveState();
1624 \brief Customize mouse move event handler.
1625 \param e mouse event
1627 void QtxWorkstackTabBar::mouseMoveEvent( QMouseEvent* e )
1629 if ( myId != -1 && !tabRect( indexOf( myId ) ).contains( e->pos() ) )
1632 emit dragActiveTab();
1635 QTabBar::mouseMoveEvent( e );
1639 \brief Customize mouse press event handler.
1640 \param e mouse event
1642 void QtxWorkstackTabBar::mousePressEvent( QMouseEvent* e )
1644 QTabBar::mousePressEvent( e );
1646 if ( e->button() == Qt::LeftButton )
1647 myId = tabId( currentIndex() );
1651 \brief Customize mouse release event handler.
1652 \param e mouse event
1654 void QtxWorkstackTabBar::mouseReleaseEvent( QMouseEvent* e )
1656 QTabBar::mouseReleaseEvent( e );
1660 if ( e->button() == Qt::RightButton )
1661 emit contextMenuRequested( e->globalPos() );
1665 \brief Customize context menu event handler.
1666 \param e context menu event
1668 void QtxWorkstackTabBar::contextMenuEvent( QContextMenuEvent* e )
1670 if ( e->reason() != QContextMenuEvent::Mouse )
1671 emit contextMenuRequested( e->globalPos() );
1675 \brief Process widget change state events (style, palette, enable state changing, etc).
1676 \param e change event (not used)
1678 void QtxWorkstackTabBar::changeEvent( QEvent* /*e*/ )
1680 updateActiveState();
1684 void QtxWorkstackTabBar::paintLabel( QPainter* p, const QRect& br, QTab* t, bool has_focus ) const
1686 if ( currentTab() != t->identifier() )
1688 QFont fnt = p->font();
1689 fnt.setUnderline( false );
1692 QTabBar::paintLabel( p, br, t, has_focus );
1697 \fn void QtxWorkstackTabBar::dragActiveTab()
1698 \brief Emitted when dragging operation is started.
1702 \fn void QtxWorkstackTabBar::contextMenuRequested( QPoint p )
1703 \brief Emitted when context popup menu is requested.
1704 \param p point popup menu to be shown at
1709 \brief Workstack widget.
1711 Organizes the child widgets in the tabbed space.
1712 Allows splitting the working area to arrange the child widgets in
1713 arbitrary way. Any widgets can be moved to another working area with
1714 drag-n-drop operation.
1716 This widget can be used as workspace of the application main window,
1717 for example, as kind of implementation of multi-document interface.
1722 \param parent parent widget
1724 QtxWorkstack::QtxWorkstack( QWidget* parent )
1725 : QWidget( parent ),
1731 myActionsMap.insert( SplitVertical, new QtxAction( QString(), tr( "Split vertically" ), 0, this ) );
1732 myActionsMap.insert( SplitHorizontal, new QtxAction( QString(), tr( "Split horizontally" ), 0, this ) );
1733 myActionsMap.insert( Close, new QtxAction( QString(), tr( "Close" ), 0, this ) );
1734 myActionsMap.insert( Rename, new QtxAction( QString(), tr( "Rename" ), 0, this ) );
1736 connect( myActionsMap[SplitVertical], SIGNAL( triggered( bool ) ), this, SLOT( splitVertical() ) );
1737 connect( myActionsMap[SplitHorizontal], SIGNAL( triggered( bool ) ), this, SLOT( splitHorizontal() ) );
1738 connect( myActionsMap[Close], SIGNAL( triggered( bool ) ), this, SLOT( onCloseWindow() ) );
1739 connect( myActionsMap[Rename], SIGNAL( triggered( bool ) ), this, SLOT( onRename() ) );
1741 // Action shortcut will work when action added in any widget.
1742 for ( QMap<int, QAction*>::iterator it = myActionsMap.begin(); it != myActionsMap.end(); ++it )
1744 addAction( it.value() );
1745 it.value()->setShortcutContext( Qt::ApplicationShortcut );
1748 QVBoxLayout* base = new QVBoxLayout( this );
1749 base->setMargin( 0 );
1751 mySplit = new QtxWorkstackSplitter( this );
1752 base->addWidget( mySplit );
1758 QtxWorkstack::~QtxWorkstack()
1763 \brief Get list of all widgets in all areas or in specified area which given
1765 \param wid widget specifying area if it is equal to null when widgets of all
1767 \return list of widgets
1769 QWidgetList QtxWorkstack::windowList( QWidget* wid ) const
1771 QList<QtxWorkstackArea*> lst;
1774 areas( mySplit, lst, true );
1778 QtxWorkstackArea* area = wgArea( wid );
1783 QWidgetList widList;
1784 for ( QList<QtxWorkstackArea*>::iterator it = lst.begin(); it != lst.end(); ++it )
1786 QWidgetList wids = (*it)->widgetList();
1787 for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr )
1788 widList.append( *itr );
1795 \brief Get all child widgets in the active workarea.
1796 \return list of widgets in active workarea
1798 QWidgetList QtxWorkstack::splitWindowList() const
1800 return myArea ? myArea->widgetList() : QWidgetList();
1804 \brief Get active widget.
1805 \return active widget
1807 QWidget* QtxWorkstack::activeWindow() const
1813 \brief Set active widget
1814 \param wid widget to activate
1816 void QtxWorkstack::setActiveWindow( QWidget* wid )
1819 activeArea()->setActiveWidget( wid );
1823 \brief Split workstack.
1825 Splitting is possible only if there are two or more widgets in the workarea.
1826 This function splits current workarea to two new ones.
1828 \param o splitting orientation (Qt::Orientation)
1830 void QtxWorkstack::split( const int o )
1832 QtxWorkstackArea* area = myWorkArea;
1834 area = activeArea();
1838 if ( area->widgetList().count() < 2 )
1841 QWidget* curWid = area->activeWidget();
1845 QSplitter* s = splitter( area );
1846 QList<QtxWorkstackArea*> areaList;
1847 areas( s, areaList );
1849 QList<QSplitter*> splitList;
1850 splitters( s, splitList );
1853 if ( areaList.count() + splitList.count() < 2 || s->orientation() == o )
1857 trg = wrapSplitter( area );
1862 trg->setOrientation( (Qt::Orientation)o );
1864 QtxWorkstackArea* newArea = createArea( 0 );
1865 trg->insertWidget( trg->indexOf( area ) + 1, newArea );
1867 area->removeWidget( curWid );
1868 newArea->insertWidget( curWid );
1870 distributeSpace( trg );
1877 \brief Split workarea of the given widget on two parts.
1879 Splitting is possible only if there are two or more widgets in the workarea.
1880 This function splits current workarea to two new ones.
1882 \param wid widget belonging to the workstack
1883 \param o splitting orientation type (Qt::Orientation)
1884 \param type splitting type (QtxWorkstack::SplitType)
1886 void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType type )
1890 // find area of the given widget
1891 QtxWorkstackArea* area = NULL;
1892 QList<QtxWorkstackArea*> allAreas;
1893 areas(mySplit, allAreas, true);
1895 for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it )
1897 if ( (*it)->contains( wid ) )
1904 QWidget* curWid = area->activeWidget();
1908 QWidgetList wids = area->widgetList();
1909 if ( wids.count() < 2 )
1912 QSplitter* s = splitter( area );
1913 QList<QtxWorkstackArea*> areaList;
1914 areas( s, areaList );
1916 QList<QSplitter*> splitList;
1917 splitters(s, splitList);
1920 if (areaList.count() + splitList.count() < 2 || s->orientation() == o)
1923 if (!trg) trg = wrapSplitter(area);
1926 trg->setOrientation(o);
1928 QtxWorkstackArea* newArea = createArea(0);
1929 insertWidget(newArea, trg, area);
1934 for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr )
1936 QWidget* wid_i = *itr;
1939 area->removeWidget( wid_i );
1940 newArea->insertWidget( wid_i );
1941 wid_i->showMaximized();
1947 QWidgetList::iterator itr = wids.begin();
1948 for ( ; itr != wids.end() && *itr != wid; ++itr )
1951 for ( ; itr != wids.end(); ++itr )
1953 area->removeWidget( *itr );
1954 newArea->insertWidget( *itr );
1955 (*itr)->showMaximized();
1960 area->removeWidget( wid );
1961 newArea->insertWidget( wid );
1962 wid->showMaximized();
1966 distributeSpace( trg );
1973 \brief Move widget(s) from the source workarea into the target workarea
1974 or reorder widgets inside one workarea.
1976 Move \a wid2 in target workarea. Put it right after \a wid1.
1977 If \a all parameter is \c true, all widgets from source workarea
1978 will be moved including \a wid2 and source workarea will be deleted then.
1980 If \a wid1 and \a wid2 belongs to one workarea, widgets will be just reordered
1983 \param wid1 widget from target workarea
1984 \param wid2 widget from source workarea
1985 \param all if \c true, all widgets from source workarea will
1986 be moved into the target one, else only the \a wid2 will be moved
1988 void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all )
1990 if ( !wid1 || !wid2 )
1993 // find area of the widgets
1994 QtxWorkstackArea *area1 = 0, *area2 = 0;
1995 QList<QtxWorkstackArea*> allAreas;
1996 areas( mySplit, allAreas, true );
1997 for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !( area1 && area2 ); ++it )
1999 if ( (*it)->contains( wid1 ) )
2002 if ( (*it)->contains( wid2 ) )
2006 if ( !area1 || !area2 )
2009 QSplitter* s1 = splitter( area1 );
2011 QWidget* curWid = area1->activeWidget();
2015 if ( area1 == area2 )
2019 // Set wid1 at first position, wid2 at second
2020 area1->insertWidget( wid1 );
2021 area1->insertWidget( wid2, 1 );
2022 wid1->showMaximized();
2023 wid2->showMaximized();
2027 // Set wid2 right after wid1
2028 area1->removeWidget( wid2 );
2030 QWidgetList wids1 = area1->widgetList();
2031 for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind );
2032 area1->insertWidget( wid2, wid1_ind + 1 );
2033 wid2->showMaximized();
2039 QWidgetList wids1 = area1->widgetList();
2040 for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind );
2043 // Set wid2 right after wid1, other widgets from area2 right after wid2
2044 QWidgetList wids2 = area2->widgetList();
2045 QWidgetList::iterator itr2 = wids2.begin();
2046 for ( int ind = wid1_ind + 1; itr2 != wids2.end(); ++itr2, ++ind )
2048 area2->removeWidget( *itr2 );
2049 if ( *itr2 == wid2 )
2050 area1->insertWidget( *itr2, wid1_ind + 1 );
2052 area1->insertWidget( *itr2, ind );
2053 (*itr2)->showMaximized();
2058 // Set wid2 right after wid1
2059 area2->removeWidget( wid2 );
2060 area1->insertWidget( wid2, wid1_ind + 1 );
2061 wid2->showMaximized();
2065 distributeSpace( s1 );
2067 area1->setActiveWidget( curWid );
2076 \brief Calculate sizes of the splitter widget for the workarea.
2079 static void setSizes (QIntList& szList, const int item_ind,
2080 const int new_near, const int new_this, const int new_farr)
2082 // set size to all items before an item # <item_ind>
2084 QIntList::iterator its = szList.begin();
2085 for (; its != szList.end() && cur_pos < item_ind; ++its, ++cur_pos) {
2088 if (its == szList.end()) return;
2089 // set size to item # <item_ind>
2092 // set size to all items after an item # <item_ind>
2093 for (; its != szList.end(); ++its) {
2099 \brief Set position of the widget relatively to its parent splitter.
2101 Orientation of positioning will correspond to the splitter orientation.
2104 \param pos position relatively to the splitter; value in the range [0..1]
2106 void QtxWorkstack::SetRelativePositionInSplitter( QWidget* wid, const double position )
2108 if ( position < 0.0 || 1.0 < position)
2114 // find area of the given widget
2115 QtxWorkstackArea* area = NULL;
2116 QList<QtxWorkstackArea*> allAreas;
2117 areas( mySplit, allAreas, true );
2118 for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it )
2120 if ( (*it)->contains( wid ) )
2127 QSplitter* split = splitter( area );
2131 // find index of the area in its splitter
2133 bool isFound = false;
2134 const QObjectList& was = split->children();
2135 for ( QObjectList::const_iterator ito = was.begin(); ito != was.end() && !isFound; ++ito, ++item_ind )
2141 if ( !isFound || item_ind == 0 )
2144 QIntList szList = split->sizes();
2145 int splitter_size = ( split->orientation() == Qt::Horizontal ? split->width() : split->height());
2146 int nb = szList.count();
2148 int new_prev = int( splitter_size * position / item_ind );
2149 if (nb == item_ind) return;
2150 int new_next = int( splitter_size * ( 1.0 - position ) / ( nb - item_ind ) );
2151 setSizes( szList, item_ind, new_prev, new_next, new_next );
2152 split->setSizes( szList );
2156 \brief Set position of the widget relatively to the entire workstack.
2158 If \a o is \c Qt::Horizontal, the horizontal position of \a wid will be changed.
2159 If \a o is \c Qt::Vertical, the vertical position of \a wid will be changed.
2162 \param o orientation of positioning (\c Qt::Horizontal or \c Qt::Vertical)
2163 \param pos position relatively to the workstack; value in range [0..1]
2165 void QtxWorkstack::SetRelativePosition( QWidget* wid, const Qt::Orientation o,
2166 const double position )
2168 if ( position < 0.0 || 1.0 < position )
2174 int splitter_size = o == Qt::Horizontal ? mySplit->width() : mySplit->height();
2175 int need_pos = int( position * splitter_size );
2176 int splitter_pos = 0;
2178 if ( setPosition( wid, mySplit, o, need_pos, splitter_pos ) != 0 )
2180 // impossible to set required position
2185 \brief Set accelerator key-combination for the action with specified \a id.
2187 \param accel action accelerator
2189 void QtxWorkstack::setAccel( const int id, const int accel )
2191 if ( !myActionsMap.contains( id ) )
2194 myActionsMap[id]->setShortcut( accel );
2198 \brief Get the action's accelerator key-combination.
2200 \return action accelerator
2202 int QtxWorkstack::accel( const int id ) const
2205 if ( myActionsMap.contains( id ) )
2206 res = myActionsMap[id]->shortcut();
2211 \brief Get icon for the specified action.
2213 If \a id is invalid, null icon is returned.
2215 \param id menu action ID
2216 \return menu item icon
2218 QIcon QtxWorkstack::icon( const int id ) const
2221 if ( myActionsMap.contains( id ) )
2222 ico = myActionsMap[id]->icon();
2227 \brief Set menu item icon for the specified action.
2228 \param id menu action ID
2229 \param ico new menu item icon
2231 void QtxWorkstack::setIcon( const int id, const QIcon& icon )
2233 if ( !myActionsMap.contains( id ) )
2236 myActionsMap[id]->setIcon( icon );
2240 \brief Set actions to be visible in the context popup menu.
2242 Actions, which IDs are set in \a flags parameter, will be shown in the
2243 context popup menu. Other actions will not be shown.
2245 \param flags ORed together actions flags
2247 void QtxWorkstack::setMenuActions( const int flags )
2249 myActionsMap[SplitVertical]->setVisible( flags & SplitVertical );
2250 myActionsMap[SplitHorizontal]->setVisible( flags & SplitHorizontal );
2251 myActionsMap[Close]->setVisible( flags & Close );
2252 myActionsMap[Rename]->setVisible( flags & Rename );
2256 \brief Set actions to be visible in the context popup menu.
2258 Actions, which IDs are set in \a flags parameter, will be shown in the
2259 context popup menu. Other actions will not be shown.
2261 \param flags ORed together actions flags
2263 int QtxWorkstack::menuActions() const
2266 ret = ret | ( myActionsMap[SplitVertical]->isVisible() ? SplitVertical : 0 );
2267 ret = ret | ( myActionsMap[SplitHorizontal]->isVisible() ? SplitHorizontal : 0 );
2268 ret = ret | ( myActionsMap[Close]->isVisible() ? Close : 0 );
2269 ret = ret | ( myActionsMap[Rename]->isVisible() ? Rename : 0 );
2274 \brief Calculate sizes of the splitter widget for the workarea.
2277 static int positionSimple (QIntList& szList, const int nb, const int splitter_size,
2278 const int item_ind, const int item_rel_pos,
2279 const int need_pos, const int splitter_pos)
2281 if (item_ind == 0) { // cannot move in this splitter
2282 return (need_pos - splitter_pos);
2287 int new_this = szList[item_ind];
2290 bool isToCheck = false;
2292 if (need_pos < splitter_pos) {
2293 // Set size of all previous workareas to zero <--
2294 if (item_ind == nb - 1) {
2295 // item iz last in the splitter, it will occupy all the splitter
2296 new_this = splitter_size;
2298 // recompute size of next items in splitter
2299 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
2301 delta = need_pos - splitter_pos;
2303 } else if (need_pos > (splitter_pos + splitter_size)) {
2304 // Set size of all next workareas to zero -->
2305 // recompute size of previous items in splitter
2307 new_prev = (splitter_size - new_this) / item_ind;
2308 delta = need_pos - (splitter_pos + splitter_size - new_this);
2310 } else { // required position lays inside this splitter
2311 // Move workarea inside splitter into required position <->
2312 int new_item_rel_pos = need_pos - splitter_pos;
2313 new_prev = new_item_rel_pos / item_ind;
2314 if (need_pos < (splitter_pos + item_rel_pos)) {
2315 // Make previous workareas smaller, next - bigger
2316 // No problem to keep old size of the widget
2318 // Make previous workareas bigger, next - smaller
2319 if (new_this > splitter_size - new_item_rel_pos) {
2320 new_this = splitter_size - new_item_rel_pos;
2322 // jfa to do: in this case fixed size of next widgets could prevent right resizing
2325 if (item_ind == nb - 1) {
2326 new_this = splitter_size - new_item_rel_pos;
2328 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
2333 setSizes (szList, item_ind, new_prev, new_this, new_next);
2338 \brief Set position of the widget.
2340 Called from SetRelativePosition() public method.
2342 \param wid widget to be moved
2343 \param split currently processed splitter (goes from more common
2344 to more particular splitter in recursion calls)
2345 \param o orientation of positioning
2346 \param need_pos required position of the given widget in pixels
2347 (from top/left side of workstack area)
2348 \param splitter_pos position of the splitter \a split
2349 (from top/left side of workstack area)
2350 \return difference between a required and a distinguished position
2352 int QtxWorkstack::setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o,
2353 const int need_pos, const int splitter_pos )
2355 if ( !wid || !split )
2356 return need_pos - splitter_pos;
2358 // Find corresponding sub-splitter.
2359 // Find also index of appropriate item in current splitter.
2360 int cur_ind = 0, item_ind = 0;
2361 bool isBottom = false, isFound = false;
2362 QSplitter* sub_split = NULL;
2363 const QObjectList& objs = split->children();
2364 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end() && !isFound; ++it )
2366 QtxWorkstackArea* area = ::qobject_cast<QtxWorkstackArea*>( *it );
2369 if ( area->contains( wid ) )
2377 else if ( (*it)->inherits( "QSplitter" ) )
2379 QList<QtxWorkstackArea*> areaList;
2380 areas( (QSplitter*)(*it), areaList, true );
2381 for ( QList<QtxWorkstackArea*>::iterator ita = areaList.begin(); ita != areaList.end() && !isFound; ++ita )
2383 if ( (*ita)->contains( wid ) )
2387 sub_split = (QSplitter*)*it;
2395 return ( need_pos - splitter_pos );
2397 if ( split->orientation() == o )
2399 // Find coordinates of near and far sides of the appropriate item relatively current splitter
2400 int splitter_size = ( o == Qt::Horizontal ? split->width() : split->height() );
2401 QIntList szList = split->sizes();
2402 int nb = szList.count();
2403 int item_rel_pos = 0; // position of near side of item relatively this splitter
2404 for (int i = 0; i < item_ind; i++) {
2405 item_rel_pos += szList[i];
2407 int item_size = szList[item_ind]; // size of item
2408 int item_pos = splitter_pos + item_rel_pos;
2410 // Resize splitter items to complete the conditions
2412 // I. Bottom of splitters stack reached
2414 int delta = positionSimple(szList, nb, splitter_size, item_ind, item_rel_pos, need_pos, splitter_pos);
2415 split->setSizes(szList);
2416 // Recompute delta, as some windows can reject given size
2417 int new_item_rel_pos = 0;
2418 QIntList szList1 = split->sizes();
2419 for (int i = 0; i < item_ind; i++) {
2420 new_item_rel_pos += szList1[i];
2422 delta = need_pos - (splitter_pos + new_item_rel_pos);
2426 // II. Bottom of splitters stack is not yet reached
2428 if (item_ind == 0) { // cannot move in this splitter
2429 // Process in sub-splitter
2430 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
2434 int new_this = szList[item_ind];
2437 if (need_pos < splitter_pos) {
2438 // Set size of all previous workareas to zero <--
2439 if (item_ind == nb - 1) {
2440 new_this = splitter_size;
2442 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
2444 setSizes (szList, item_ind, new_prev, new_this, new_next);
2445 split->setSizes(szList);
2446 // Recompute splitter_pos, as some windows can reject given size
2447 int new_item_rel_pos = 0;
2448 QIntList szList1 = split->sizes();
2449 for (int i = 0; i < item_ind; i++) {
2450 new_item_rel_pos += szList1[i];
2452 // Process in sub-splitter
2453 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2454 } else if (need_pos > (splitter_pos + splitter_size)) {
2455 // Set size of all next workareas to zero -->
2456 new_prev = (splitter_size - new_this) / item_ind;
2457 setSizes (szList, item_ind, new_prev, new_this, new_next);
2458 split->setSizes(szList);
2459 // Recompute splitter_pos, as some windows can reject given size
2460 int new_item_rel_pos = 0;
2461 QIntList szList1 = split->sizes();
2462 for (int i = 0; i < item_ind; i++) {
2463 new_item_rel_pos += szList1[i];
2465 // Process in sub-splitter
2466 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2468 // Set appropriate size of all previous/next items <->
2469 int new_item_rel_pos = item_rel_pos;
2470 if (need_pos < item_pos || (item_pos + item_size) < need_pos) {
2471 // Move item inside splitter into required position <->
2472 int new_this = szList[item_ind];
2474 new_item_rel_pos = need_pos - splitter_pos;
2475 if ((item_pos + item_size) < need_pos) {
2476 //new_item_rel_pos = need_pos - (item_pos + item_size);
2477 new_item_rel_pos = item_rel_pos + (need_pos - (item_pos + item_size));
2479 int new_prev = new_item_rel_pos / item_ind;
2480 if (need_pos < (splitter_pos + item_rel_pos)) {
2481 // Make previous workareas smaller, next - bigger
2482 // No problem to keep old size of the widget
2484 // Make previous workareas bigger, next - smaller
2485 if (new_this > splitter_size - new_item_rel_pos) {
2486 new_this = splitter_size - new_item_rel_pos;
2489 if (item_ind == nb - 1) {
2490 new_this = splitter_size - new_item_rel_pos;
2492 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
2494 setSizes (szList, item_ind, new_prev, new_this, new_next);
2495 split->setSizes(szList);
2496 // Recompute new_item_rel_pos, as some windows can reject given size
2497 new_item_rel_pos = 0;
2498 QIntList szList1 = split->sizes();
2499 for (int i = 0; i < item_ind; i++) {
2500 new_item_rel_pos += szList1[i];
2505 // Process in sub-splitter
2506 int add_pos = setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2510 // this can be if corresponding workarea is first in sub-splitter
2511 // or sub-splitter has another orientation
2513 // Resize ones again to reach precize position <->
2514 int need_pos_1 = splitter_pos + new_item_rel_pos + add_pos;
2516 // Move workarea inside splitter into required position <->
2517 int delta_1 = positionSimple(szList, nb, splitter_size, item_ind,
2518 new_item_rel_pos, need_pos_1, splitter_pos);
2519 split->setSizes(szList);
2520 // Recompute new_item_rel_pos, as some windows can reject given size
2521 new_item_rel_pos = 0;
2522 QIntList szList1 = split->sizes();
2523 for (int i = 0; i < item_ind; i++) {
2524 new_item_rel_pos += szList1[i];
2526 delta_1 = need_pos_1 - (splitter_pos + new_item_rel_pos);
2531 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
2538 \brief Redistribute space among widgets equally.
2539 \param split splitter
2541 void QtxWorkstack::distributeSpace( QSplitter* split ) const
2546 QIntList szList = split->sizes();
2547 int size = ( split->orientation() == Qt::Horizontal ?
2548 split->width() : split->height() ) / szList.count();
2549 for ( QIntList::iterator it = szList.begin(); it != szList.end(); ++it )
2551 split->setSizes( szList );
2555 \brief Split widgets vertically.
2557 void QtxWorkstack::splitVertical()
2559 split( Qt::Horizontal );
2563 \brief Split widgets horizontally.
2565 void QtxWorkstack::splitHorizontal()
2567 split( Qt::Vertical );
2571 \brief Called when user activates "Rename" menu item.
2573 Changes widget title.
2575 void QtxWorkstack::onRename()
2581 QString newName = QInputDialog::getText( topLevelWidget(), tr( "Rename" ), tr( "Enter new name:" ),
2582 QLineEdit::Normal, myWorkWin->windowTitle(), &ok );
2583 if ( ok && !newName.isEmpty() )
2584 myWorkWin->setWindowTitle( newName );
2588 \brief Wrap area into the new splitter.
2590 \return new splitter
2592 QSplitter* QtxWorkstack::wrapSplitter( QtxWorkstackArea* area )
2597 QSplitter* pSplit = splitter( area );
2601 bool upd = pSplit->updatesEnabled();
2602 pSplit->setUpdatesEnabled( false );
2604 QIntList szList = pSplit->sizes();
2606 QSplitter* wrap = new QtxWorkstackSplitter( 0 );
2607 pSplit->insertWidget( pSplit->indexOf( area ) + 1, wrap );
2608 wrap->setVisible( true );
2609 wrap->addWidget( area );
2611 pSplit->setSizes( szList );
2613 pSplit->setUpdatesEnabled( upd );
2619 \brief Reparent and add widget.
2621 \param pWid parent widget
2622 \param after widget after which \a wid should be added
2624 void QtxWorkstack::insertWidget( QWidget* wid, QWidget* pWid, QWidget* after )
2626 if ( !wid || !pWid )
2629 QWidgetList moveList;
2630 const QObjectList& lst = pWid->children();
2632 for ( QObjectList::const_iterator it = lst.begin(); it != lst.end(); ++it )
2634 if ( found && ( (*it)->inherits( "QSplitter" ) ||
2635 (*it)->inherits( "QtxWorkstackArea" ) ) )
2636 moveList.append( (QWidget*)(*it) );
2641 QMap<QWidget*, bool> map;
2642 for ( QWidgetList::iterator it = moveList.begin(); it != moveList.end(); ++it )
2644 map.insert( *it, (*it)->isVisibleTo( (*it)->parentWidget() ) );
2645 (*it)->setParent( 0 );
2649 wid->setParent( pWid );
2651 for ( QWidgetList::iterator itr = moveList.begin(); itr != moveList.end(); ++itr )
2653 (*itr)->setParent( pWid );
2654 (*itr)->setShown( map.contains( *itr ) ? map[*itr] : false );
2659 \brief Close active window.
2661 void QtxWorkstack::onCloseWindow()
2665 else if( activeWindow() )
2666 activeWindow()->close();
2670 \brief Called when workarea is destroyed.
2672 Set input focus to the neighbour area.
2674 \param obj workarea being destroyed
2676 void QtxWorkstack::onDestroyed( QObject* obj )
2678 QtxWorkstackArea* area = (QtxWorkstackArea*)obj;
2680 if ( area == myArea )
2685 QtxWorkstackArea* cur = neighbourArea( area );
2690 QApplication::postEvent( this, new QEvent( QEvent::User ) );
2694 \brief Called on window activating.
2695 \param area workarea being activated (not used)
2697 void QtxWorkstack::onWindowActivated( QWidget* /*area*/ )
2699 const QObject* obj = sender();
2700 if ( !obj->inherits( "QtxWorkstackArea" ) )
2703 setActiveArea( (QtxWorkstackArea*)obj );
2707 \brief Called on window deactivating.
2708 \param area workarea being deactivated
2710 void QtxWorkstack::onDeactivated( QtxWorkstackArea* area )
2712 if ( myArea != area )
2715 QList<QtxWorkstackArea*> lst;
2716 areas( mySplit, lst, true );
2718 int idx = lst.indexOf( area );
2725 QtxWorkstackArea* newArea = neighbourArea( area );
2726 if ( newArea && newArea->activeWidget() )
2727 newArea->activeWidget()->setFocus();
2729 QApplication::postEvent( this, new QEvent( QEvent::User ) );
2733 \brief Create and show popup menu for workarea.
2735 \param p popup position
2737 void QtxWorkstack::onContextMenuRequested( QWidget* w, QPoint p )
2739 QtxWorkstackArea* anArea = ::qobject_cast<QtxWorkstackArea*>( (QObject*)sender() );
2741 anArea = activeArea();
2746 QWidgetList lst = anArea->widgetList();
2747 if ( lst.isEmpty() )
2751 myWorkArea = anArea;
2753 QMenu* pm = new QMenu();
2755 if ( lst.count() > 1 )
2757 if ( !myActionsMap[SplitVertical]->isEnabled() )
2758 myActionsMap[SplitVertical]->setEnabled(true);
2759 pm->addAction( myActionsMap[SplitVertical] );
2760 if ( !myActionsMap[SplitHorizontal]->isEnabled() )
2761 myActionsMap[SplitHorizontal]->setEnabled(true);
2762 pm->addAction( myActionsMap[SplitHorizontal] );
2768 if ( myActionsMap[Close]->isEnabled() )
2769 pm->addAction( myActionsMap[Close] );
2770 if ( myActionsMap[Rename]->isEnabled() )
2771 pm->addAction( myActionsMap[Rename] );
2774 Qtx::simplifySeparators( pm );
2776 if ( !pm->actions().isEmpty() )
2786 \brief Add child widget.
2788 \param f widget flags
2789 \return child widget container
2791 QWidget* QtxWorkstack::addWindow( QWidget* w, Qt::WindowFlags f )
2796 return targetArea()->insertWidget( w, -1, f );
2800 \brief Handle custom events.
2801 \param e custom event (not used)
2803 void QtxWorkstack::customEvent( QEvent* /*e*/ )
2809 \brief Get splitter corresponding to the workarea.
2811 \return splitter corresponding to the workarea
2813 QSplitter* QtxWorkstack::splitter( QtxWorkstackArea* area ) const
2818 QSplitter* split = 0;
2820 QWidget* wid = area->parentWidget();
2821 if ( wid && wid->inherits( "QSplitter" ) )
2822 split = (QSplitter*)wid;
2828 \brief Get list of child splitters.
2829 \param split parent splitter
2830 \param splitList list to be filled with child splitters
2831 \param rec if \c true, perform recursive search of children
2833 void QtxWorkstack::splitters( QSplitter* split, QList<QSplitter*>& splitList, const bool rec ) const
2838 const QObjectList& objs = split->children();
2839 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
2842 splitters( (QSplitter*)*it, splitList, rec );
2843 if ( (*it)->inherits( "QSplitter" ) )
2844 splitList.append( (QSplitter*)*it );
2849 \brief Get list of child workareas.
2850 \param split parent splitter
2851 \param areaList list to be filled with child workareas
2852 \param rec if \c true, perform recursive search of children
2854 void QtxWorkstack::areas( QSplitter* split, QList<QtxWorkstackArea*>& areaList, const bool rec ) const
2859 const QObjectList& objs = split->children();
2860 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
2862 if ( (*it)->inherits( "QtxWorkstackArea" ) )
2863 areaList.append( (QtxWorkstackArea*)*it );
2864 else if ( rec && (*it)->inherits( "QSplitter" ) )
2865 areas( (QSplitter*)*it, areaList, rec );
2870 \brief Get active workarea.
2871 \return active workarea
2873 QtxWorkstackArea* QtxWorkstack::activeArea() const
2879 \brief Get target area (for which the current operation should be done).
2881 Returns active workarea or current area (if there is no active workarea).
2882 If there are no workareas, create new workarea and return it.
2886 QtxWorkstackArea* QtxWorkstack::targetArea()
2888 QtxWorkstackArea* area = activeArea();
2890 area = currentArea();
2893 QList<QtxWorkstackArea*> lst;
2894 areas( mySplit, lst );
2895 if ( !lst.isEmpty() )
2900 area = createArea( mySplit );
2906 \brief Get current workarea.
2908 Current workarea is that one which has input focus.
2910 \return current area
2912 QtxWorkstackArea* QtxWorkstack::currentArea() const
2914 QtxWorkstackArea* area = 0;
2915 QWidget* wid = focusWidget();
2916 while ( wid && !area )
2918 if ( wid->inherits( "QtxWorkstackArea" ) )
2919 area = (QtxWorkstackArea*)wid;
2920 wid = wid->parentWidget();
2927 \brief Create new workarea.
2928 \param parent parent widget
2929 \return created workarea
2931 QtxWorkstackArea* QtxWorkstack::createArea( QWidget* parent ) const
2933 QtxWorkstackArea* area = new QtxWorkstackArea( parent );
2935 connect( area, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
2936 connect( area, SIGNAL( activated( QWidget* ) ), this, SLOT( onWindowActivated( QWidget* ) ) );
2937 connect( area, SIGNAL( contextMenuRequested( QWidget*, QPoint ) ),
2938 this, SLOT( onContextMenuRequested( QWidget*, QPoint ) ) );
2939 connect( area, SIGNAL( deactivated( QtxWorkstackArea* ) ), this, SLOT( onDeactivated( QtxWorkstackArea* ) ) );
2945 \brief Set active workarea.
2948 void QtxWorkstack::setActiveArea( QtxWorkstackArea* area )
2950 QWidget* oldCur = myWin;
2952 QtxWorkstackArea* oldArea = myArea;
2956 if ( myArea != oldArea )
2959 oldArea->updateActiveState();
2961 myArea->updateActiveState();
2965 myWin = myArea->activeWidget();
2967 if ( myWin && oldCur != myWin )
2968 emit windowActivated( myWin );
2972 \brief Get workarea which is nearest to \a area.
2973 \param area area for which neighbour is searched
2974 \return neighbour area (or 0 if not found)
2976 QtxWorkstackArea* QtxWorkstack::neighbourArea( QtxWorkstackArea* area ) const
2978 QList<QtxWorkstackArea*> lst;
2979 areas( mySplit, lst, true );
2980 int pos = lst.indexOf( area );
2984 QtxWorkstackArea* na = 0;
2985 for ( int i = pos - 1; i >= 0 && !na; i-- )
2987 if ( !lst.at( i )->isEmpty() )
2991 for ( int j = pos + 1; j < (int)lst.count() && !na; j++ )
2993 if ( !lst.at( j )->isEmpty() )
3000 \brief Get workarea covering point.
3004 QtxWorkstackArea* QtxWorkstack::areaAt( const QPoint& p ) const
3006 QtxWorkstackArea* area = 0;
3007 QList<QtxWorkstackArea*> lst;
3008 areas( mySplit, lst, true );
3009 for ( QList<QtxWorkstackArea*>::iterator it = lst.begin(); it != lst.end() && !area; ++it )
3011 QtxWorkstackArea* cur = *it;
3012 QRect r = cur->geometry();
3013 if ( cur->parentWidget() )
3014 r = QRect( cur->parentWidget()->mapToGlobal( r.topLeft() ), r.size() );
3015 if ( r.contains( p ) )
3022 \brief Update internal state.
3024 void QtxWorkstack::updateState()
3026 updateState( mySplit );
3030 \brief Update splitter state.
3031 \param split splitter to be updated
3033 void QtxWorkstack::updateState( QSplitter* split )
3035 QList<QSplitter*> recList;
3036 splitters( split, recList, false );
3037 for ( QList<QSplitter*>::iterator itr = recList.begin(); itr != recList.end(); ++itr )
3038 updateState( *itr );
3040 QList<QSplitter*> splitList;
3041 splitters( split, splitList, false );
3043 QList<QtxWorkstackArea*> areaList;
3044 areas( split, areaList, false );
3047 for ( QList<QtxWorkstackArea*>::iterator it = areaList.begin(); it != areaList.end(); ++it )
3049 if ( (*it)->isEmpty() )
3058 if ( split == mySplit )
3061 for ( QList<QSplitter*>::iterator iter = splitList.begin(); iter != splitList.end() && !vis; ++iter )
3062 vis = (*iter)->isVisibleTo( (*iter)->parentWidget() );
3064 if ( areaList.isEmpty() && splitList.isEmpty() )
3067 split->setVisible( vis );
3071 \brief Dump workstack configuration to the state description array.
3072 \param version number
3073 \return state byte array.
3075 QByteArray QtxWorkstack::saveState( int version ) const
3079 QDataStream stream( &data, QIODevice::WriteOnly );
3080 stream << QtxWorkstack::VersionMarker;
3082 saveState( stream );
3088 \brief Restore workstack configuration from the state description array.
3089 \param version number
3090 \return restore performing state
3092 bool QtxWorkstack::restoreState( const QByteArray& state, int version )
3094 if ( state.isEmpty() )
3097 QByteArray sd = state;
3098 QDataStream stream( &sd, QIODevice::ReadOnly );
3102 if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::VersionMarker || ver != version )
3105 return restoreState( stream );
3108 void QtxWorkstack::saveState( QDataStream& stream ) const
3110 mySplit->saveState( stream );
3113 bool QtxWorkstack::restoreState( QDataStream& stream )
3115 QMap<QString, QtxWorkstackChild*> map;
3116 QList<QtxWorkstackArea*> areaList;
3117 areas( mySplit, areaList, true );
3118 for ( QList<QtxWorkstackArea*>::const_iterator it = areaList.begin(); it != areaList.end(); ++it )
3120 QtxWorkstackArea* area = *it;
3121 QList<QtxWorkstackChild*> childList = area->childList();
3122 for ( QList<QtxWorkstackChild*>::iterator itr = childList.begin(); itr != childList.end(); ++itr )
3124 QtxWorkstackChild* c = *itr;
3128 map.insert( c->widget()->objectName(), c );
3130 qDebug( "QtxWorkstack::restoreState: found widget \"%s\"", (const char*)c->widget()->objectName().toLatin1() );
3136 if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::SplitMarker )
3139 QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this );
3141 layout()->addWidget( split );
3143 bool ok = split->restoreState( stream, map );
3148 mySplit->deleteLater();
3151 QList<QtxWorkstackArea*> aList;
3152 areas( mySplit, aList, true );
3154 QtxWorkstackArea* a = !aList.isEmpty() ? aList.first() : 0;
3155 for ( QMap<QString, QtxWorkstackChild*>::const_iterator it = map.begin(); it != map.end(); ++it )
3157 QtxWorkstackChild* c = it.value();
3159 c->widget()->setVisible( false );
3161 a->insertChild( c );
3163 c->setVisible( false );
3171 \brief Set resize mode of all splitters opaque or transparent.
3172 \param opaque opaque mode
3174 void QtxWorkstack::setOpaqueResize( bool opaque )
3176 QList<QSplitter*> splitList;
3177 splitters( mySplit, splitList, true );
3178 splitList << mySplit;
3179 foreach( QSplitter* split, splitList )
3180 split->setOpaqueResize( opaque );
3184 \brief Get resize mode of all splitters: opaque (\c true) or transparent (\c false).
3185 \return current opaque mode
3187 bool QtxWorkstack::opaqueResize() const
3189 return mySplit->opaqueResize();
3193 \brief Show/Hide active tab bar.
3195 void QtxWorkstack::showActiveTabBar( bool visible )
3197 QList<QtxWorkstackArea*> areaList;
3198 areas( mySplit, areaList, true );
3199 QList<QtxWorkstackArea*>::ConstIterator it;
3200 for ( it = areaList.begin(); it != areaList.end(); ++it )
3202 (*it)->showTabBar( visible );
3204 QList<QSplitter*> recList;
3205 splitters( mySplit, recList, true );
3206 for ( QList<QSplitter*>::iterator itr = recList.begin(); itr != recList.end(); ++itr )
3207 (*itr)->setVisible(visible);
3211 \fn void QtxWorkstack::windowActivated( QWidget* w )
3212 \brief Emitted when the workstack's child widget \w is activated.
3213 \param w widget being activated
3217 \brief Gets area containing given widget
3219 \return pointer to QtxWorkstackArea* object
3221 QtxWorkstackArea* QtxWorkstack::wgArea( QWidget* wid ) const
3223 QtxWorkstackArea* resArea = 0;
3225 QList<QtxWorkstackArea*> areaList;
3226 areas( mySplit, areaList, true );
3228 QList<QtxWorkstackArea*>::ConstIterator it;
3229 for ( it = areaList.begin(); it != areaList.end() && !resArea; ++it )
3231 if ( (*it)->contains( wid ) )
3239 \brief Moves the first widget to the same area which the second widget belongs to
3240 \param wid widget to be moved
3241 \param wid_to widget specified the destination area
3242 \param before specifies whether the first widget has to be moved before or after
3244 \return TRUE if operation is completed successfully, FALSE otherwise
3246 bool QtxWorkstack::move( QWidget* wid, QWidget* wid_to, const bool before )
3248 if ( wid && wid_to )
3250 QtxWorkstackArea* area_src = wgArea( wid );
3251 QtxWorkstackArea* area_to = wgArea( wid_to );
3252 if ( area_src && area_to )
3254 // find index of the second widget
3255 QWidgetList wgList = area_to->widgetList();
3256 QWidgetList::ConstIterator it;
3258 for ( it = wgList.begin(); it != wgList.begin(); ++it, idx++ )
3260 if ( *it == wid_to )
3264 if ( idx < wgList.count() ) // paranoidal check
3268 area_src->removeWidget( wid, true );
3269 area_to->insertWidget( wid, idx );
3270 wid->showMaximized();
3279 \brief Group all windows in one area
3280 \return TRUE if operation is completed successfully, FALSE otherwise
3282 void QtxWorkstack::stack()
3284 QWidgetList wgList = windowList();
3285 if ( !wgList.count() )
3286 return; // nothing to do
3288 QtxWorkstackArea* area_to = 0;
3289 QWidgetList::ConstIterator it;
3290 for ( it = wgList.begin(); it != wgList.end(); ++it )
3292 QtxWorkstackArea* area_src = 0;
3295 area_to = wgArea( *it );
3299 area_src = wgArea( *it );
3301 if ( area_src != area_to )
3303 area_src->removeWidget( *it, true );
3304 area_to->insertWidget( *it, -1 );
3305 (*it)->showMaximized();
3310 QAction* QtxWorkstack::action( const int id ) const
3312 return myActionsMap.contains( id ) ? myActionsMap[id] : 0;