1 // Copyright (C) 2007-2023 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.toUtf8() );
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 ( (int)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()[0];
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 if (need_pos < splitter_pos) {
2291 // Set size of all previous workareas to zero <--
2292 if (item_ind == nb - 1) {
2293 // item iz last in the splitter, it will occupy all the splitter
2294 new_this = splitter_size;
2296 // recompute size of next items in splitter
2297 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
2299 delta = need_pos - splitter_pos;
2301 } else if (need_pos > (splitter_pos + splitter_size)) {
2302 // Set size of all next workareas to zero -->
2303 // recompute size of previous items in splitter
2305 new_prev = (splitter_size - new_this) / item_ind;
2306 delta = need_pos - (splitter_pos + splitter_size - new_this);
2308 } else { // required position lays inside this splitter
2309 // Move workarea inside splitter into required position <->
2310 int new_item_rel_pos = need_pos - splitter_pos;
2311 new_prev = new_item_rel_pos / item_ind;
2312 if (need_pos < (splitter_pos + item_rel_pos)) {
2313 // Make previous workareas smaller, next - bigger
2314 // No problem to keep old size of the widget
2316 // Make previous workareas bigger, next - smaller
2317 if (new_this > splitter_size - new_item_rel_pos) {
2318 new_this = splitter_size - new_item_rel_pos;
2320 // jfa to do: in this case fixed size of next widgets could prevent right resizing
2322 if (item_ind == nb - 1) {
2323 new_this = splitter_size - new_item_rel_pos;
2325 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
2330 setSizes (szList, item_ind, new_prev, new_this, new_next);
2335 \brief Set position of the widget.
2337 Called from SetRelativePosition() public method.
2339 \param wid widget to be moved
2340 \param split currently processed splitter (goes from more common
2341 to more particular splitter in recursion calls)
2342 \param o orientation of positioning
2343 \param need_pos required position of the given widget in pixels
2344 (from top/left side of workstack area)
2345 \param splitter_pos position of the splitter \a split
2346 (from top/left side of workstack area)
2347 \return difference between a required and a distinguished position
2349 int QtxWorkstack::setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o,
2350 const int need_pos, const int splitter_pos )
2352 if ( !wid || !split )
2353 return need_pos - splitter_pos;
2355 // Find corresponding sub-splitter.
2356 // Find also index of appropriate item in current splitter.
2357 int cur_ind = 0, item_ind = 0;
2358 bool isBottom = false, isFound = false;
2359 QSplitter* sub_split = NULL;
2360 const QObjectList& objs = split->children();
2361 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end() && !isFound; ++it )
2363 QtxWorkstackArea* area = ::qobject_cast<QtxWorkstackArea*>( *it );
2366 if ( area->contains( wid ) )
2374 else if ( (*it)->inherits( "QSplitter" ) )
2376 QList<QtxWorkstackArea*> areaList;
2377 areas( (QSplitter*)(*it), areaList, true );
2378 for ( QList<QtxWorkstackArea*>::iterator ita = areaList.begin(); ita != areaList.end() && !isFound; ++ita )
2380 if ( (*ita)->contains( wid ) )
2384 sub_split = (QSplitter*)*it;
2392 return ( need_pos - splitter_pos );
2394 if ( split->orientation() == o )
2396 // Find coordinates of near and far sides of the appropriate item relatively current splitter
2397 int splitter_size = ( o == Qt::Horizontal ? split->width() : split->height() );
2398 QIntList szList = split->sizes();
2399 int nb = szList.count();
2400 int item_rel_pos = 0; // position of near side of item relatively this splitter
2401 for (int i = 0; i < item_ind; i++) {
2402 item_rel_pos += szList[i];
2404 int item_size = szList[item_ind]; // size of item
2405 int item_pos = splitter_pos + item_rel_pos;
2407 // Resize splitter items to complete the conditions
2409 // I. Bottom of splitters stack reached
2411 int delta = positionSimple(szList, nb, splitter_size, item_ind, item_rel_pos, need_pos, splitter_pos);
2412 split->setSizes(szList);
2413 // Recompute delta, as some windows can reject given size
2414 int new_item_rel_pos = 0;
2415 QIntList szList1 = split->sizes();
2416 for (int i = 0; i < item_ind; i++) {
2417 new_item_rel_pos += szList1[i];
2419 delta = need_pos - (splitter_pos + new_item_rel_pos);
2423 // II. Bottom of splitters stack is not yet reached
2425 if (item_ind == 0) { // cannot move in this splitter
2426 // Process in sub-splitter
2427 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
2431 int new_this = szList[item_ind];
2434 if (need_pos < splitter_pos) {
2435 // Set size of all previous workareas to zero <--
2436 if (item_ind == nb - 1) {
2437 new_this = splitter_size;
2439 new_next = (splitter_size - new_this) / (nb - item_ind - 1);
2441 setSizes (szList, item_ind, new_prev, new_this, new_next);
2442 split->setSizes(szList);
2443 // Recompute splitter_pos, as some windows can reject given size
2444 int new_item_rel_pos = 0;
2445 QIntList szList1 = split->sizes();
2446 for (int i = 0; i < item_ind; i++) {
2447 new_item_rel_pos += szList1[i];
2449 // Process in sub-splitter
2450 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2451 } else if (need_pos > (splitter_pos + splitter_size)) {
2452 // Set size of all next workareas to zero -->
2453 new_prev = (splitter_size - new_this) / item_ind;
2454 setSizes (szList, item_ind, new_prev, new_this, new_next);
2455 split->setSizes(szList);
2456 // Recompute splitter_pos, as some windows can reject given size
2457 int new_item_rel_pos = 0;
2458 QIntList szList1 = split->sizes();
2459 for (int i = 0; i < item_ind; i++) {
2460 new_item_rel_pos += szList1[i];
2462 // Process in sub-splitter
2463 return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2465 // Set appropriate size of all previous/next items <->
2466 int new_item_rel_pos = item_rel_pos;
2467 if (need_pos < item_pos || (item_pos + item_size) < need_pos) {
2468 // Move item inside splitter into required position <->
2469 int new_this = szList[item_ind];
2471 new_item_rel_pos = need_pos - splitter_pos;
2472 if ((item_pos + item_size) < need_pos) {
2473 //new_item_rel_pos = need_pos - (item_pos + item_size);
2474 new_item_rel_pos = item_rel_pos + (need_pos - (item_pos + item_size));
2476 int new_prev = new_item_rel_pos / item_ind;
2477 if (need_pos < (splitter_pos + item_rel_pos)) {
2478 // Make previous workareas smaller, next - bigger
2479 // No problem to keep old size of the widget
2481 // Make previous workareas bigger, next - smaller
2482 if (new_this > splitter_size - new_item_rel_pos) {
2483 new_this = splitter_size - new_item_rel_pos;
2486 if (item_ind == nb - 1) {
2487 new_this = splitter_size - new_item_rel_pos;
2489 new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
2491 setSizes (szList, item_ind, new_prev, new_this, new_next);
2492 split->setSizes(szList);
2493 // Recompute new_item_rel_pos, as some windows can reject given size
2494 new_item_rel_pos = 0;
2495 QIntList szList1 = split->sizes();
2496 for (int i = 0; i < item_ind; i++) {
2497 new_item_rel_pos += szList1[i];
2502 // Process in sub-splitter
2503 int add_pos = setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
2507 // this can be if corresponding workarea is first in sub-splitter
2508 // or sub-splitter has another orientation
2510 // Resize ones again to reach precize position <->
2511 int need_pos_1 = splitter_pos + new_item_rel_pos + add_pos;
2513 // Move workarea inside splitter into required position <->
2514 int delta_1 = positionSimple(szList, nb, splitter_size, item_ind,
2515 new_item_rel_pos, need_pos_1, splitter_pos);
2516 split->setSizes(szList);
2517 // Recompute new_item_rel_pos, as some windows can reject given size
2518 new_item_rel_pos = 0;
2519 QIntList szList1 = split->sizes();
2520 for (int i = 0; i < item_ind; i++) {
2521 new_item_rel_pos += szList1[i];
2523 delta_1 = need_pos_1 - (splitter_pos + new_item_rel_pos);
2528 return setPosition(wid, sub_split, o, need_pos, splitter_pos);
2535 \brief Redistribute space among widgets equally.
2536 \param split splitter
2538 void QtxWorkstack::distributeSpace( QSplitter* split ) const
2543 QIntList szList = split->sizes();
2544 int size = ( split->orientation() == Qt::Horizontal ?
2545 split->width() : split->height() ) / szList.count();
2546 for ( QIntList::iterator it = szList.begin(); it != szList.end(); ++it )
2548 split->setSizes( szList );
2552 \brief Split widgets vertically.
2554 void QtxWorkstack::splitVertical()
2556 split( Qt::Horizontal );
2560 \brief Split widgets horizontally.
2562 void QtxWorkstack::splitHorizontal()
2564 split( Qt::Vertical );
2568 \brief Called when user activates "Rename" menu item.
2570 Changes widget title.
2572 void QtxWorkstack::onRename()
2578 QString newName = QInputDialog::getText( topLevelWidget(), tr( "Rename" ), tr( "Enter new name:" ),
2579 QLineEdit::Normal, myWorkWin->windowTitle(), &ok );
2580 if ( ok && !newName.isEmpty() )
2581 myWorkWin->setWindowTitle( newName );
2585 \brief Wrap area into the new splitter.
2587 \return new splitter
2589 QSplitter* QtxWorkstack::wrapSplitter( QtxWorkstackArea* area )
2594 QSplitter* pSplit = splitter( area );
2598 bool upd = pSplit->updatesEnabled();
2599 pSplit->setUpdatesEnabled( false );
2601 QIntList szList = pSplit->sizes();
2603 QSplitter* wrap = new QtxWorkstackSplitter( 0 );
2604 pSplit->insertWidget( pSplit->indexOf( area ) + 1, wrap );
2605 wrap->setVisible( true );
2606 wrap->addWidget( area );
2608 pSplit->setSizes( szList );
2610 pSplit->setUpdatesEnabled( upd );
2616 \brief Reparent and add widget.
2618 \param pWid parent widget
2619 \param after widget after which \a wid should be added
2621 void QtxWorkstack::insertWidget( QWidget* wid, QWidget* pWid, QWidget* after )
2623 if ( !wid || !pWid )
2626 QWidgetList moveList;
2627 const QObjectList& lst = pWid->children();
2629 for ( QObjectList::const_iterator it = lst.begin(); it != lst.end(); ++it )
2631 if ( found && ( (*it)->inherits( "QSplitter" ) ||
2632 (*it)->inherits( "QtxWorkstackArea" ) ) )
2633 moveList.append( (QWidget*)(*it) );
2638 QMap<QWidget*, bool> map;
2639 for ( QWidgetList::iterator it = moveList.begin(); it != moveList.end(); ++it )
2641 map.insert( *it, (*it)->isVisibleTo( (*it)->parentWidget() ) );
2642 (*it)->setParent( 0 );
2646 wid->setParent( pWid );
2648 for ( QWidgetList::iterator itr = moveList.begin(); itr != moveList.end(); ++itr )
2650 (*itr)->setParent( pWid );
2651 (*itr)->setVisible( map.contains( *itr ) ? map[*itr] : false );
2656 \brief Close active window.
2658 void QtxWorkstack::onCloseWindow()
2662 else if( activeWindow() )
2663 activeWindow()->close();
2667 \brief Called when workarea is destroyed.
2669 Set input focus to the neighbour area.
2671 \param obj workarea being destroyed
2673 void QtxWorkstack::onDestroyed( QObject* obj )
2675 QtxWorkstackArea* area = (QtxWorkstackArea*)obj;
2677 if ( area == myArea )
2682 QtxWorkstackArea* cur = neighbourArea( area );
2687 QApplication::postEvent( this, new QEvent( QEvent::User ) );
2691 \brief Called on window activating.
2692 \param area workarea being activated (not used)
2694 void QtxWorkstack::onWindowActivated( QWidget* /*area*/ )
2696 const QObject* obj = sender();
2697 if ( !obj->inherits( "QtxWorkstackArea" ) )
2700 setActiveArea( (QtxWorkstackArea*)obj );
2704 \brief Called on window deactivating.
2705 \param area workarea being deactivated
2707 void QtxWorkstack::onDeactivated( QtxWorkstackArea* area )
2709 if ( myArea != area )
2712 QList<QtxWorkstackArea*> lst;
2713 areas( mySplit, lst, true );
2715 int idx = lst.indexOf( area );
2722 QtxWorkstackArea* newArea = neighbourArea( area );
2723 if ( newArea && newArea->activeWidget() )
2724 newArea->activeWidget()->setFocus();
2726 QApplication::postEvent( this, new QEvent( QEvent::User ) );
2730 \brief Create and show popup menu for workarea.
2732 \param p popup position
2734 void QtxWorkstack::onContextMenuRequested( QWidget* w, QPoint p )
2736 QtxWorkstackArea* anArea = ::qobject_cast<QtxWorkstackArea*>( (QObject*)sender() );
2738 anArea = activeArea();
2743 QWidgetList lst = anArea->widgetList();
2744 if ( lst.isEmpty() )
2748 myWorkArea = anArea;
2750 QMenu* pm = new QMenu();
2752 if ( lst.count() > 1 )
2754 if ( !myActionsMap[SplitVertical]->isEnabled() )
2755 myActionsMap[SplitVertical]->setEnabled(true);
2756 pm->addAction( myActionsMap[SplitVertical] );
2757 if ( !myActionsMap[SplitHorizontal]->isEnabled() )
2758 myActionsMap[SplitHorizontal]->setEnabled(true);
2759 pm->addAction( myActionsMap[SplitHorizontal] );
2765 if ( myActionsMap[Close]->isEnabled() )
2766 pm->addAction( myActionsMap[Close] );
2767 if ( myActionsMap[Rename]->isEnabled() )
2768 pm->addAction( myActionsMap[Rename] );
2771 Qtx::simplifySeparators( pm );
2773 if ( !pm->actions().isEmpty() )
2783 \brief Add child widget.
2785 \param f widget flags
2786 \return child widget container
2788 QWidget* QtxWorkstack::addWindow( QWidget* w, Qt::WindowFlags f )
2793 return targetArea()->insertWidget( w, -1, f );
2797 \brief Handle custom events.
2798 \param e custom event (not used)
2800 void QtxWorkstack::customEvent( QEvent* /*e*/ )
2806 \brief Get splitter corresponding to the workarea.
2808 \return splitter corresponding to the workarea
2810 QSplitter* QtxWorkstack::splitter( QtxWorkstackArea* area ) const
2815 QSplitter* split = 0;
2817 QWidget* wid = area->parentWidget();
2818 if ( wid && wid->inherits( "QSplitter" ) )
2819 split = (QSplitter*)wid;
2825 \brief Get list of child splitters.
2826 \param split parent splitter
2827 \param splitList list to be filled with child splitters
2828 \param rec if \c true, perform recursive search of children
2830 void QtxWorkstack::splitters( QSplitter* split, QList<QSplitter*>& splitList, const bool rec ) const
2835 const QObjectList& objs = split->children();
2836 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
2839 splitters( (QSplitter*)*it, splitList, rec );
2840 if ( (*it)->inherits( "QSplitter" ) )
2841 splitList.append( (QSplitter*)*it );
2846 \brief Get list of child workareas.
2847 \param split parent splitter
2848 \param areaList list to be filled with child workareas
2849 \param rec if \c true, perform recursive search of children
2851 void QtxWorkstack::areas( QSplitter* split, QList<QtxWorkstackArea*>& areaList, const bool rec ) const
2856 const QObjectList& objs = split->children();
2857 for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
2859 if ( (*it)->inherits( "QtxWorkstackArea" ) )
2860 areaList.append( (QtxWorkstackArea*)*it );
2861 else if ( rec && (*it)->inherits( "QSplitter" ) )
2862 areas( (QSplitter*)*it, areaList, rec );
2867 \brief Get active workarea.
2868 \return active workarea
2870 QtxWorkstackArea* QtxWorkstack::activeArea() const
2876 \brief Get target area (for which the current operation should be done).
2878 Returns active workarea or current area (if there is no active workarea).
2879 If there are no workareas, create new workarea and return it.
2883 QtxWorkstackArea* QtxWorkstack::targetArea()
2885 QtxWorkstackArea* area = activeArea();
2887 area = currentArea();
2890 QList<QtxWorkstackArea*> lst;
2891 areas( mySplit, lst );
2892 if ( !lst.isEmpty() )
2897 area = createArea( mySplit );
2903 \brief Get current workarea.
2905 Current workarea is that one which has input focus.
2907 \return current area
2909 QtxWorkstackArea* QtxWorkstack::currentArea() const
2911 QtxWorkstackArea* area = 0;
2912 QWidget* wid = focusWidget();
2913 while ( wid && !area )
2915 if ( wid->inherits( "QtxWorkstackArea" ) )
2916 area = (QtxWorkstackArea*)wid;
2917 wid = wid->parentWidget();
2924 \brief Create new workarea.
2925 \param parent parent widget
2926 \return created workarea
2928 QtxWorkstackArea* QtxWorkstack::createArea( QWidget* parent ) const
2930 QtxWorkstackArea* area = new QtxWorkstackArea( parent );
2932 connect( area, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
2933 connect( area, SIGNAL( activated( QWidget* ) ), this, SLOT( onWindowActivated( QWidget* ) ) );
2934 connect( area, SIGNAL( contextMenuRequested( QWidget*, QPoint ) ),
2935 this, SLOT( onContextMenuRequested( QWidget*, QPoint ) ) );
2936 connect( area, SIGNAL( deactivated( QtxWorkstackArea* ) ), this, SLOT( onDeactivated( QtxWorkstackArea* ) ) );
2942 \brief Set active workarea.
2945 void QtxWorkstack::setActiveArea( QtxWorkstackArea* area )
2947 QWidget* oldCur = myWin;
2949 QtxWorkstackArea* oldArea = myArea;
2953 if ( myArea != oldArea )
2956 oldArea->updateActiveState();
2958 myArea->updateActiveState();
2962 myWin = myArea->activeWidget();
2964 if ( myWin && oldCur != myWin )
2965 emit windowActivated( myWin );
2969 \brief Get workarea which is nearest to \a area.
2970 \param area area for which neighbour is searched
2971 \return neighbour area (or 0 if not found)
2973 QtxWorkstackArea* QtxWorkstack::neighbourArea( QtxWorkstackArea* area ) const
2975 QList<QtxWorkstackArea*> lst;
2976 areas( mySplit, lst, true );
2977 int pos = lst.indexOf( area );
2981 QtxWorkstackArea* na = 0;
2982 for ( int i = pos - 1; i >= 0 && !na; i-- )
2984 if ( !lst.at( i )->isEmpty() )
2988 for ( int j = pos + 1; j < (int)lst.count() && !na; j++ )
2990 if ( !lst.at( j )->isEmpty() )
2997 \brief Get workarea covering point.
3001 QtxWorkstackArea* QtxWorkstack::areaAt( const QPoint& p ) const
3003 QtxWorkstackArea* area = 0;
3004 QList<QtxWorkstackArea*> lst;
3005 areas( mySplit, lst, true );
3006 for ( QList<QtxWorkstackArea*>::iterator it = lst.begin(); it != lst.end() && !area; ++it )
3008 QtxWorkstackArea* cur = *it;
3009 QRect r = cur->geometry();
3010 if ( cur->parentWidget() )
3011 r = QRect( cur->parentWidget()->mapToGlobal( r.topLeft() ), r.size() );
3012 if ( r.contains( p ) )
3019 \brief Update internal state.
3021 void QtxWorkstack::updateState()
3023 updateState( mySplit );
3027 \brief Update splitter state.
3028 \param split splitter to be updated
3030 void QtxWorkstack::updateState( QSplitter* split )
3032 QList<QSplitter*> recList;
3033 splitters( split, recList, false );
3034 for ( QList<QSplitter*>::iterator itr = recList.begin(); itr != recList.end(); ++itr )
3035 updateState( *itr );
3037 QList<QSplitter*> splitList;
3038 splitters( split, splitList, false );
3040 QList<QtxWorkstackArea*> areaList;
3041 areas( split, areaList, false );
3044 for ( QList<QtxWorkstackArea*>::iterator it = areaList.begin(); it != areaList.end(); ++it )
3046 if ( (*it)->isEmpty() )
3055 if ( split == mySplit )
3058 for ( QList<QSplitter*>::iterator iter = splitList.begin(); iter != splitList.end() && !vis; ++iter )
3059 vis = (*iter)->isVisibleTo( (*iter)->parentWidget() );
3061 if ( areaList.isEmpty() && splitList.isEmpty() )
3064 split->setVisible( vis );
3068 \brief Dump workstack configuration to the state description array.
3069 \param version number
3070 \return state byte array.
3072 QByteArray QtxWorkstack::saveState( int version ) const
3076 QDataStream stream( &data, QIODevice::WriteOnly );
3077 stream << QtxWorkstack::VersionMarker;
3079 saveState( stream );
3085 \brief Restore workstack configuration from the state description array.
3086 \param version number
3087 \return restore performing state
3089 bool QtxWorkstack::restoreState( const QByteArray& state, int version )
3091 if ( state.isEmpty() )
3094 QByteArray sd = state;
3095 QDataStream stream( &sd, QIODevice::ReadOnly );
3099 if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::VersionMarker || ver != version )
3102 return restoreState( stream );
3105 void QtxWorkstack::saveState( QDataStream& stream ) const
3107 mySplit->saveState( stream );
3110 bool QtxWorkstack::restoreState( QDataStream& stream )
3112 QMap<QString, QtxWorkstackChild*> map;
3113 QList<QtxWorkstackArea*> areaList;
3114 areas( mySplit, areaList, true );
3115 for ( QList<QtxWorkstackArea*>::const_iterator it = areaList.begin(); it != areaList.end(); ++it )
3117 QtxWorkstackArea* area = *it;
3118 QList<QtxWorkstackChild*> childList = area->childList();
3119 for ( QList<QtxWorkstackChild*>::iterator itr = childList.begin(); itr != childList.end(); ++itr )
3121 QtxWorkstackChild* c = *itr;
3125 map.insert( c->widget()->objectName(), c );
3127 qDebug( "QtxWorkstack::restoreState: found widget \"%s\"", (const char*)c->widget()->objectName().toUtf8() );
3133 if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::SplitMarker )
3136 QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this );
3138 layout()->addWidget( split );
3140 bool ok = split->restoreState( stream, map );
3145 mySplit->deleteLater();
3148 QList<QtxWorkstackArea*> aList;
3149 areas( mySplit, aList, true );
3151 QtxWorkstackArea* a = !aList.isEmpty() ? aList.first() : 0;
3152 for ( QMap<QString, QtxWorkstackChild*>::const_iterator it = map.begin(); it != map.end(); ++it )
3154 QtxWorkstackChild* c = it.value();
3156 c->widget()->setVisible( false );
3158 a->insertChild( c );
3160 c->setVisible( false );
3168 \brief Set resize mode of all splitters opaque or transparent.
3169 \param opaque opaque mode
3171 void QtxWorkstack::setOpaqueResize( bool opaque )
3173 QList<QSplitter*> splitList;
3174 splitters( mySplit, splitList, true );
3175 splitList << mySplit;
3176 foreach( QSplitter* split, splitList )
3177 split->setOpaqueResize( opaque );
3181 \brief Get resize mode of all splitters: opaque (\c true) or transparent (\c false).
3182 \return current opaque mode
3184 bool QtxWorkstack::opaqueResize() const
3186 return mySplit->opaqueResize();
3190 \brief Show/hide splitter state and area.
3191 \param wid widget (and parent area) will be shown/hidden
3192 \param parent_list parent splitters list
3193 \param split splitter will be shown/hidden
3194 \param visible splitter
3196 void QtxWorkstack::splitterVisible(QWidget* wid, QList<QSplitter*>& parent_list, QSplitter* split, bool visible)
3198 QList<QSplitter*> recList;
3199 splitters( split, recList, false );
3200 for ( QList<QSplitter*>::iterator itr = recList.begin(); itr != recList.end(); ++itr ) {
3201 parent_list.prepend( *itr );
3202 splitterVisible( wid, parent_list, *itr, visible );
3205 QList<QtxWorkstackArea*> areaList;
3206 areas( split, areaList, false );
3207 for ( QList<QtxWorkstackArea*>::const_iterator it = areaList.begin(); it != areaList.end(); ++it ) {
3208 QtxWorkstackArea* area = *it;
3209 bool isCurrentWidget = false;
3211 area->showTabBar(visible);
3213 // 1. Looking for the selected widget at the lowest level among all splitted areas.
3214 QList<QtxWorkstackChild*> childList = area->childList();
3215 for ( QList<QtxWorkstackChild*>::iterator itr = childList.begin(); itr != childList.end(); ++itr ) {
3216 QWidget* aCurWid = (*itr)->widget();
3217 if ( aCurWid == wid ) {
3218 isCurrentWidget = true;
3219 aCurWid->setVisible( true );
3222 aCurWid->setVisible( visible );
3225 // 2. Show/Hide other areas and widgets that don't contain the desired widget
3226 if ( !isCurrentWidget || visible )
3227 area->setVisible( visible );
3229 if ( !isCurrentWidget && !visible )
3232 // 3. Show/hide all parent widgets
3233 QSplitter* pSplit = splitter( area );
3234 int count = pSplit->count();
3235 for ( int i = 0; i < count; i++ ) {
3236 if ( pSplit->indexOf( area ) == i && !visible )
3238 pSplit->widget(i)->setVisible( visible );
3241 // 4. Show/hide all parent splitters don't contain the selected widget
3243 pSplit->setVisible( true );
3245 if ( isCurrentWidget && !visible ) {
3246 for ( QList<QSplitter*>::iterator itr = parent_list.begin(); itr != parent_list.end() && pSplit != mySplit; ++itr ) {
3247 if ( pSplit == *itr )
3249 QList<QSplitter*> splitList;
3250 splitters( *itr, splitList, false );
3251 for ( QList<QSplitter*>::iterator iter = splitList.begin(); iter != splitList.end(); ++iter ) {
3252 if ( pSplit == (*iter) ) {
3256 (*iter)->setVisible( false );
3264 \brief Show/hide splitters state and area.
3265 \param wid widget (and parent area) will be shown/hidden
3266 \param visible splitters
3268 void QtxWorkstack::splittersVisible( QWidget* wid, bool visible )
3270 QList<QSplitter*> parent_list;
3271 parent_list.append( mySplit );
3272 splitterVisible( wid, parent_list, mySplit, visible );
3276 \fn void QtxWorkstack::windowActivated( QWidget* w )
3277 \brief Emitted when the workstack's child widget \w is activated.
3278 \param w widget being activated
3282 \brief Gets area containing given widget
3284 \return pointer to QtxWorkstackArea* object
3286 QtxWorkstackArea* QtxWorkstack::wgArea( QWidget* wid ) const
3288 QtxWorkstackArea* resArea = 0;
3290 QList<QtxWorkstackArea*> areaList;
3291 areas( mySplit, areaList, true );
3293 QList<QtxWorkstackArea*>::ConstIterator it;
3294 for ( it = areaList.begin(); it != areaList.end() && !resArea; ++it )
3296 if ( (*it)->contains( wid ) )
3304 \brief Moves the first widget to the same area which the second widget belongs to
3305 \param wid widget to be moved
3306 \param wid_to widget specified the destination area
3307 \param before specifies whether the first widget has to be moved before or after
3309 \return \c true if operation is completed successfully, \c false otherwise
3311 bool QtxWorkstack::move( QWidget* wid, QWidget* wid_to, const bool before )
3313 if ( wid && wid_to )
3315 QtxWorkstackArea* area_src = wgArea( wid );
3316 QtxWorkstackArea* area_to = wgArea( wid_to );
3317 if ( area_src && area_to )
3319 // find index of the second widget
3320 QWidgetList wgList = area_to->widgetList();
3321 QWidgetList::ConstIterator it;
3323 for ( it = wgList.begin(); it != wgList.begin(); ++it, idx++ )
3325 if ( *it == wid_to )
3329 if ( idx < wgList.count() ) // paranoidal check
3333 area_src->removeWidget( wid, true );
3334 area_to->insertWidget( wid, idx );
3335 wid->showMaximized();
3344 \brief Group all windows in one area
3345 \return \c true if operation is completed successfully, \c false otherwise
3347 void QtxWorkstack::stack()
3349 QWidgetList wgList = windowList();
3350 if ( !wgList.count() )
3351 return; // nothing to do
3353 QtxWorkstackArea* area_to = 0;
3354 QWidgetList::ConstIterator it;
3355 for ( it = wgList.begin(); it != wgList.end(); ++it )
3357 QtxWorkstackArea* area_src = 0;
3360 area_to = wgArea( *it );
3364 area_src = wgArea( *it );
3366 if ( area_src != area_to )
3368 area_src->removeWidget( *it, true );
3369 area_to->insertWidget( *it, -1 );
3370 (*it)->showMaximized();
3375 QAction* QtxWorkstack::action( const int id ) const
3377 return myActionsMap.contains( id ) ? myActionsMap[id] : 0;