Back to index

salome-gui  6.5.0
QtxWorkstack.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 // File:      QtxWorkstack.cxx
00024 // Author:    Sergey TELKOV
00025 //
00026 #include "QtxWorkstack.h"
00027 
00028 #include "QtxAction.h"
00029 
00030 #include <QMenu>
00031 #include <QStyle>
00032 #include <QRegExp>
00033 #include <QLayout>
00034 #include <QPainter>
00035 #include <QDataStream>
00036 #include <QFocusEvent>
00037 #include <QMouseEvent>
00038 #include <QRubberBand>
00039 #include <QApplication>
00040 #include <QStyleOption>
00041 #include <QInputDialog>
00042 #include <QStackedWidget>
00043 #include <QAbstractButton>
00044 
00051 class QtxWorkstackArea::WidgetEvent : public QEvent
00052 {
00053 public:
00054   WidgetEvent( Type t, QtxWorkstackChild* w = 0 ) : QEvent( t ), myChild( w ) {};
00055 
00056   QtxWorkstackChild* child() const { return myChild; }
00057 
00058 private:
00059   QtxWorkstackChild* myChild;   // event receiver widget
00060 };
00061 
00068 class QtxWorkstackArea::RestoreEvent : public QtxWorkstackArea::WidgetEvent
00069 {
00070 public:
00071   RestoreEvent( Type t, int id, int f, QtxWorkstackChild* w )
00072   : WidgetEvent( t, w ), myId( id ), myFlags( f ) {};
00073 
00074   int                id() const { return myId; }
00075   int                flags() const { return myFlags; }
00076 
00077 private:
00078   int                myId;
00079   int                myFlags;
00080 };
00081 
00093 QtxWorkstackDrag::QtxWorkstackDrag( QtxWorkstack* ws, QtxWorkstackChild* child )
00094 : QObject( 0 ),
00095   myWS( ws ),
00096   myChild( child ),
00097   myTab( -1 ),
00098   myArea( 0 ),
00099   myTabRect( 0 ),
00100   myAreaRect( 0 )
00101 {
00102   QApplication::instance()->installEventFilter( this );
00103 }
00104 
00108 QtxWorkstackDrag::~QtxWorkstackDrag()
00109 {
00110   QApplication::instance()->removeEventFilter( this );
00111 
00112   endDrawRect();
00113 }
00114 
00121 bool QtxWorkstackDrag::eventFilter( QObject*, QEvent* e )
00122 {
00123   switch ( e->type() )
00124   {
00125   case QEvent::MouseMove:
00126     updateTarget( ((QMouseEvent*)e)->globalPos() );
00127     break;
00128   case QEvent::MouseButtonRelease:
00129     drawRect();
00130     endDrawRect();
00131     dropWidget();
00132     deleteLater();
00133     break;
00134   default:
00135     return false;
00136   }
00137   return true;
00138 }
00139 
00144 void QtxWorkstackDrag::updateTarget( const QPoint& p )
00145 {
00146   int tab = -1;
00147   QtxWorkstackArea* area = detectTarget( p, tab );
00148   setTarget( area, tab );
00149 }
00150 
00157 QtxWorkstackArea* QtxWorkstackDrag::detectTarget( const QPoint& p, int& tab ) const
00158 {
00159   if ( p.isNull() )
00160     return 0;
00161 
00162   QtxWorkstackArea* area = myWS->areaAt( p );
00163   if ( area )
00164     tab = area->tabAt( p );
00165   return area;
00166 }
00167 
00173 void QtxWorkstackDrag::setTarget( QtxWorkstackArea* area, const int tab )
00174 {
00175   if ( !area || ( myArea == area && tab == myTab ) )
00176     return;
00177 
00178   startDrawRect();
00179 
00180   if ( myArea )
00181     drawRect();
00182 
00183   myTab = tab;
00184   myArea = area;
00185 
00186   if ( myArea )
00187     drawRect();
00188 }
00189 
00195 void QtxWorkstackDrag::dropWidget()
00196 {
00197   if ( myArea )
00198     myArea->insertChild( myChild, myTab );
00199 }
00200 
00204 void QtxWorkstackDrag::drawRect()
00205 {
00206   if ( !myArea )
00207     return;
00208 
00209   QRect r = myArea->floatRect();
00210   int m = 2;
00211 
00212   r.setTop( r.top() + m + 2 );
00213   r.setLeft( r.left() + m + 2 );
00214   r.setRight( r.right() - m - 2 );
00215   r.setBottom( r.bottom() - m - 2 );
00216 
00217   if ( myAreaRect )
00218   {
00219     myAreaRect->setGeometry( r );
00220     myAreaRect->setVisible( r.isValid() );
00221   }
00222 
00223   QRect tr = myArea->floatTab( myTab );
00224 
00225   tr.setTop( tr.top() + m );
00226   tr.setLeft( tr.left() + m );
00227   tr.setRight( tr.right() - m );
00228   tr.setBottom( tr.bottom() - m );
00229 
00230   if ( myTabRect )
00231   {
00232     myTabRect->setGeometry( tr );
00233     myTabRect->setVisible( tr.isValid() );
00234   }
00235 }
00236 
00240 void QtxWorkstackDrag::endDrawRect()
00241 {
00242   delete myAreaRect;
00243   myAreaRect = 0;
00244 
00245   delete myTabRect;
00246   myTabRect = 0;
00247 }
00248 
00252 void QtxWorkstackDrag::startDrawRect()
00253 {
00254   if ( !myTabRect )
00255     myTabRect = new QRubberBand( QRubberBand::Rectangle );
00256 
00257   myTabRect->hide();
00258 
00259   if ( !myAreaRect )
00260     myAreaRect = new QRubberBand( QRubberBand::Rectangle );
00261 
00262   myAreaRect->hide();
00263 }
00264 
00265 
00266 /*
00267   \class CloseButton
00268   \brief Workstack area close button.
00269   \internal
00270 */
00271 class CloseButton : public QAbstractButton
00272 {
00273 public:
00274   CloseButton( QWidget* );
00275 
00276   QSize        sizeHint() const;
00277   QSize        minimumSizeHint() const;
00278 
00279   void enterEvent( QEvent* );
00280   void leaveEvent( QEvent* );
00281   void paintEvent( QPaintEvent* );
00282 };
00283 
00289 CloseButton::CloseButton( QWidget* parent )
00290 : QAbstractButton( parent )
00291 {
00292  setFocusPolicy( Qt::NoFocus );
00293 }
00294 
00300 QSize CloseButton::sizeHint() const
00301 {
00302   ensurePolished();
00303   int dim = 0;
00304   if( !icon().isNull() )
00305   {
00306     const QPixmap pm = icon().pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize ),
00307                                       QIcon::Normal );
00308     dim = qMax( pm.width(), pm.height() );
00309   }
00310   return QSize( dim + 4, dim + 4 );
00311 }
00312 
00318 QSize CloseButton::minimumSizeHint() const
00319 {
00320   return sizeHint();
00321 }
00322 
00328 void CloseButton::enterEvent( QEvent *event )
00329 {
00330   if ( isEnabled() )
00331     update();
00332   QAbstractButton::enterEvent( event );
00333 }
00334 
00340 void CloseButton::leaveEvent( QEvent *event )
00341 {
00342   if( isEnabled() )
00343     update();
00344   QAbstractButton::leaveEvent( event );
00345 }
00346 
00352 void CloseButton::paintEvent( QPaintEvent* )
00353 {
00354   QPainter p( this );
00355 
00356   QRect r = rect();
00357   QStyleOption opt;
00358   opt.init( this );
00359   opt.state |= QStyle::State_AutoRaise;
00360   if ( isEnabled() && underMouse() && !isChecked() && !isDown() )
00361     opt.state |= QStyle::State_Raised;
00362   if ( isChecked() )
00363     opt.state |= QStyle::State_On;
00364   if ( isDown() )
00365     opt.state |= QStyle::State_Sunken;
00366   style()->drawPrimitive( QStyle::PE_PanelButtonTool, &opt, &p, this );
00367 
00368   int shiftHorizontal = opt.state & QStyle::State_Sunken ? style()->pixelMetric( QStyle::PM_ButtonShiftHorizontal, &opt, this ) : 0;
00369   int shiftVertical = opt.state & QStyle::State_Sunken ? style()->pixelMetric( QStyle::PM_ButtonShiftVertical, &opt, this ) : 0;
00370 
00371   r.adjust( 2, 2, -2, -2 );
00372   r.translate( shiftHorizontal, shiftVertical );
00373 
00374   QPixmap pm = icon().pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize ), isEnabled() ?
00375                               underMouse() ? QIcon::Active : QIcon::Normal
00376                               : QIcon::Disabled,
00377                               isDown() ? QIcon::On : QIcon::Off );
00378   style()->drawItemPixmap( &p, r, Qt::AlignCenter, pm );
00379 }
00380 
00381 
00392 QtxWorkstackSplitter::QtxWorkstackSplitter( QWidget* parent )
00393 : QSplitter( parent )
00394 {
00395   setChildrenCollapsible( false );
00396 }
00397 
00401 QtxWorkstackSplitter::~QtxWorkstackSplitter()
00402 {
00403 }
00404 
00409 QtxWorkstack* QtxWorkstackSplitter::workstack() const
00410 {
00411   QtxWorkstack* ws = 0;
00412   QWidget* wid = parentWidget();
00413   while ( wid && !ws )
00414   {
00415     ws = ::qobject_cast<QtxWorkstack*>( wid );
00416     wid = wid->parentWidget();
00417   }
00418   return ws;
00419 }
00420 
00424 void QtxWorkstackSplitter::saveState( QDataStream& stream ) const
00425 {
00426   stream << QtxWorkstack::SplitMarker;
00427 
00428   uchar flags = 0;
00429   if ( orientation() == Qt::Horizontal )
00430     flags |= QtxWorkstack::Horizontal;
00431 
00432   stream << flags;
00433   stream << count();
00434 
00435   QList<int> sz = sizes();
00436   for ( QList<int>::const_iterator it = sz.begin(); it != sz.end(); ++it )
00437     stream << *it;
00438 
00439   for ( int i = 0; i < count(); i++ )
00440   {
00441     QWidget* wid = widget( i );
00442     QtxWorkstackSplitter* split = ::qobject_cast<QtxWorkstackSplitter*>( wid );
00443     if ( split )
00444       split->saveState( stream );
00445     else
00446     {
00447       QtxWorkstackArea* area = ::qobject_cast<QtxWorkstackArea*>( wid );
00448       if ( area )
00449               area->saveState( stream );
00450     }
00451   }
00452 }
00453 
00458 bool QtxWorkstackSplitter::restoreState( QDataStream& stream, QMap<QString, QtxWorkstackChild*>& map )
00459 {
00460   int num = 0;
00461   uchar flags = 0;
00462 
00463   stream >> flags;
00464   stream >> num;
00465 
00466   setOrientation( flags & QtxWorkstack::Horizontal ? Qt::Horizontal : Qt::Vertical );
00467 
00468   QList<int> sz;
00469   for ( int s = 0; s < num; s++ )
00470   {
00471     int sn = 0;
00472     stream >> sn;
00473     sz.append( sn );
00474   }
00475 
00476   bool ok = true;
00477   for ( int i = 0; i < num && ok; i++ )
00478   {
00479     int marker;
00480     stream >> marker;
00481 
00482     if ( stream.status() != QDataStream::Ok )
00483       return false;
00484 
00485     if ( marker == QtxWorkstack::SplitMarker )
00486     {
00487       QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this );
00488       addWidget( split );
00489       split->setVisible( true );
00490 
00491       ok = split->restoreState( stream, map );
00492     }
00493     else if ( marker == QtxWorkstack::AreaMarker )
00494     {
00495       QtxWorkstack* ws = workstack();
00496       QtxWorkstackArea* area = ws->createArea( this );
00497       addWidget( area );
00498       area->setVisible( true );
00499 
00500       ok = area->restoreState( stream, map );
00501     }
00502     else
00503       return false;
00504   }
00505 
00506   if ( ok )
00507     setSizes( sz );
00508 
00509   return ok;
00510 }
00511 
00522 QtxWorkstackArea::QtxWorkstackArea( QWidget* parent )
00523 : QFrame( parent )
00524 {
00525   setFrameStyle( QFrame::Panel | QFrame::Sunken );
00526 
00527   QVBoxLayout* base = new QVBoxLayout( this );
00528   base->setMargin( frameWidth() );
00529   base->setSpacing( 0 );
00530 
00531   QWidget* top = new QWidget( this );
00532   base->addWidget( top );
00533 
00534   QHBoxLayout* tl = new QHBoxLayout( top );
00535   tl->setMargin( 0 );
00536 
00537   myBar = new QtxWorkstackTabBar( top );
00538   tl->addWidget( myBar, 1 );
00539 
00540   CloseButton* close = new CloseButton( top );
00541   close->setIcon( style()->standardIcon( QStyle::SP_TitleBarCloseButton ) );
00542   myClose = close;
00543   tl->addWidget( myClose );
00544 
00545   myStack = new QStackedWidget( this );
00546 
00547   base->addWidget( myStack, 1 );
00548 
00549   connect( myClose, SIGNAL( clicked() ), this, SLOT( onClose() ) );
00550   connect( myBar, SIGNAL( currentChanged( int ) ), this, SLOT( onCurrentChanged( int ) ) );
00551   connect( myBar, SIGNAL( dragActiveTab() ), this, SLOT( onDragActiveTab() ) );
00552   connect( myBar, SIGNAL( contextMenuRequested( QPoint ) ), this, SLOT( onContextMenuRequested( QPoint ) ) );
00553 
00554   updateState();
00555 
00556   updateActiveState();
00557 
00558   QApplication::instance()->installEventFilter( this );
00559 }
00560 
00564 QtxWorkstackArea::~QtxWorkstackArea()
00565 {
00566   QApplication::instance()->removeEventFilter( this );
00567 }
00568 
00573 bool QtxWorkstackArea::isNull() const
00574 {
00575   return myList.isEmpty();
00576 }
00577 
00582 bool QtxWorkstackArea::isEmpty() const
00583 {
00584   bool res = false;
00585   for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !res; ++it )
00586     res = (*it)->visibility();
00587   return !res;
00588 }
00589 
00597 QtxWorkstackChild* QtxWorkstackArea::insertWidget( QWidget* wid, const int idx, Qt::WindowFlags f )
00598 {
00599   if ( !wid )
00600     return 0;
00601 
00602   QtxWorkstackChild* c = child( wid );
00603   if ( !c )
00604     c = new QtxWorkstackChild( wid, myStack, f );
00605 
00606   insertChild( c, idx );
00607 
00608   return c;
00609 }
00610 
00611 void QtxWorkstackArea::insertChild( QtxWorkstackChild* child, const int idx )
00612 {
00613   if ( !child )
00614     return;
00615 
00616   QtxWorkstackArea* a = child->area();
00617   if ( a && a != this )
00618     a->removeChild( child, false );
00619 
00620   int pos = myList.indexOf( child );
00621   if ( pos != -1 && ( pos == idx || ( idx < 0 && pos == (int)myList.count() - 1 ) ) )
00622     return;
00623 
00624   bool found = myList.contains( child );
00625 
00626   myList.removeAll( child );
00627   pos = idx < 0 ? myList.count() : idx;
00628   myList.insert( qMin( pos, (int)myList.count() ), child );
00629 
00630   if ( !found )
00631   {
00632     bool hasId = false;
00633     for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !hasId; ++it )
00634       hasId = (*it)->id() == child->id();
00635 
00636     if ( hasId || child->id() < 0 )
00637       child->setId( generateId() );
00638 
00639     connect( child, SIGNAL( destroyed( QObject* ) ), this, SLOT( onChildDestroyed( QObject* ) ) );
00640     connect( child, SIGNAL( shown( QtxWorkstackChild* ) ), this, SLOT( onChildShown( QtxWorkstackChild* ) ) );
00641     connect( child, SIGNAL( hidden( QtxWorkstackChild* ) ), this, SLOT( onChildHidden( QtxWorkstackChild* ) ) );
00642     connect( child, SIGNAL( activated( QtxWorkstackChild* ) ), this, SLOT( onChildActivated( QtxWorkstackChild* ) ) );
00643     connect( child, SIGNAL( captionChanged( QtxWorkstackChild* ) ), this, SLOT( onChildCaptionChanged( QtxWorkstackChild* ) ) );
00644   }
00645 
00646   updateState();
00647 
00648   setWidgetActive( child->widget() );
00649   child->widget()->setFocus();
00650 }
00651 
00656 void QtxWorkstackArea::onContextMenuRequested( QPoint p )
00657 {
00658   const QtxWorkstackTabBar* bar = ::qobject_cast<const QtxWorkstackTabBar*>( sender() );
00659   if ( !bar )
00660     return;
00661 
00662   QWidget* wid = 0;
00663   int idx = tabAt( p );
00664   if ( idx != -1 )
00665     wid = widget( myBar->tabId( idx ) );
00666 
00667   emit contextMenuRequested( wid, p );
00668 }
00669 
00675 void QtxWorkstackArea::removeWidget( QWidget* wid, const bool del )
00676 {
00677   removeChild( child( wid ), del );
00678 }
00679 
00685 void QtxWorkstackArea::removeChild( QtxWorkstackChild* child, const bool del )
00686 {
00687   if ( !myList.contains( child ) )
00688     return;
00689 
00690   myStack->removeWidget( child );
00691 
00692   if ( myBar->indexOf( child->id() ) != -1 )
00693     myBar->removeTab( myBar->indexOf( child->id() ) );
00694 
00695   myList.removeAll( child );
00696 
00697   if ( del )
00698     delete child;
00699   else if ( child->widget() )
00700   {
00701     disconnect( child, SIGNAL( destroyed( QObject* ) ), this, SLOT( onChildDestroyed( QObject* ) ) );
00702     disconnect( child, SIGNAL( shown( QtxWorkstackChild* ) ), this, SLOT( onChildShown( QtxWorkstackChild* ) ) );
00703     disconnect( child, SIGNAL( hidden( QtxWorkstackChild* ) ), this, SLOT( onChildHidden( QtxWorkstackChild* ) ) );
00704     disconnect( child, SIGNAL( activated( QtxWorkstackChild* ) ), this, SLOT( onChildActivated( QtxWorkstackChild* ) ) );
00705     disconnect( child, SIGNAL( captionChanged( QtxWorkstackChild* ) ), this, SLOT( onChildCaptionChanged( QtxWorkstackChild* ) ) );
00706   }
00707 
00708   if ( isNull() )
00709     deleteLater();
00710   else
00711     updateState();
00712 }
00713 
00714 QList<QtxWorkstackChild*> QtxWorkstackArea::childList() const
00715 {
00716   return myList;
00717 }
00718 
00723 QWidgetList QtxWorkstackArea::widgetList() const
00724 {
00725   QWidgetList lst;
00726   for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it )
00727   {
00728     QtxWorkstackChild* c = *it;
00729     if ( c->visibility() )
00730       lst.append( c->widget() );
00731   }
00732   return lst;
00733 }
00734 
00739 QWidget* QtxWorkstackArea::activeWidget() const
00740 {
00741   return widget( myBar->tabId( myBar->currentIndex() ) );
00742 }
00743 
00748 void QtxWorkstackArea::setActiveWidget( QWidget* wid )
00749 {
00750   myBar->setCurrentIndex( myBar->indexOf( widgetId( wid ) ) );
00751 }
00752 
00758 bool QtxWorkstackArea::contains( QWidget* wid ) const
00759 {
00760   return child( wid );
00761 }
00762 
00767 bool QtxWorkstackArea::isActive() const
00768 {
00769   QtxWorkstack* ws = workstack();
00770   if ( !ws )
00771     return false;
00772 
00773   return ws->activeArea() == this;
00774 }
00775 
00779 void QtxWorkstackArea::updateActiveState()
00780 {
00781   myBar->setActive( isActive() );
00782 }
00783 
00788 QtxWorkstack* QtxWorkstackArea::workstack() const
00789 {
00790   QtxWorkstack* ws = 0;
00791   QWidget* wid = parentWidget();
00792   while ( wid && !ws )
00793   {
00794     ws = ::qobject_cast<QtxWorkstack*>( wid );
00795     wid = wid->parentWidget();
00796   }
00797   return ws;
00798 }
00799 
00809 bool QtxWorkstackArea::eventFilter( QObject* o, QEvent* e )
00810 {
00811   if ( o->isWidgetType() )
00812   {
00813     QWidget* wid = (QWidget*)o;
00814     if ( e->type() == QEvent::FocusIn || e->type() == QEvent::MouseButtonPress )
00815     {
00816       bool ok = false;
00817       while ( !ok && wid && wid != myClose )
00818       {
00819         ok = wid == this;
00820         wid = wid->parentWidget();
00821       }
00822       if ( ok )
00823         QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)( e->type() == QEvent::FocusIn ? ActivateWidget : FocusWidget ) ) );
00824     }
00825   }
00826   return false;
00827 }
00828 
00832 void QtxWorkstackArea::saveState( QDataStream& stream ) const
00833 {
00834   stream << QtxWorkstack::AreaMarker;
00835   stream << myList.count();
00836   stream << myBar->tabId( myBar->currentIndex() );
00837   for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it )
00838   {
00839     QtxWorkstackChild* c = *it;
00840 
00841     stream << QtxWorkstack::WidgetMarker;
00842 
00843     stream << c->widget()->objectName();
00844     stream << c->id();
00845 
00846     uchar flags = 0;
00847     if ( c->visibility() )
00848       flags |= QtxWorkstack::Visible;
00849 
00850     stream << flags;
00851   }
00852 }
00853 
00858 bool QtxWorkstackArea::restoreState( QDataStream& stream, QMap<QString, QtxWorkstackChild*>& map )
00859 {
00860   int num = 0;
00861   int cur = -1;
00862 
00863   stream >> num;
00864   stream >> cur;
00865 
00866   QtxWorkstackChild* curChild = 0;
00867   for ( int i = 0; i < num; i++ )
00868   {
00869     int marker;
00870     stream >> marker;
00871 
00872     if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::WidgetMarker )
00873       return false;
00874 
00875     QString name;
00876     stream >> name;
00877 
00878     int id = -1;
00879     stream >> id;
00880 
00881     uchar flags = 0;
00882     stream >> flags;
00883 
00884     QtxWorkstackChild* c = map.contains( name ) ? map[name] : 0;
00885     if ( !c )
00886     {
00887       qWarning( "QtxWorkstack: Restored child widget \"%s\" not found.", (const char*)name.toLatin1() );
00888       return false;
00889     }
00890 
00891     map.remove( name );
00892 
00893     if ( id == cur )
00894       curChild = c;
00895 
00896     QApplication::postEvent( this, new RestoreEvent( (QEvent::Type)RestoreWidget, id, flags, c ) );
00897   }
00898 
00899   if ( curChild )
00900     QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)MakeCurrent, curChild ) );
00901 
00902   return true;
00903 }
00904 
00909 QRect QtxWorkstackArea::floatRect() const
00910 {
00911   QRect r = myStack->geometry();
00912   return QRect( mapToGlobal( r.topLeft() ), mapToGlobal( r.bottomRight() ) );
00913 }
00914 
00920 QRect QtxWorkstackArea::floatTab( const int idx ) const
00921 {
00922   QRect r = myBar->tabRect( idx );
00923   return QRect( myBar->mapToGlobal( r.topLeft() ), r.size() );
00924 }
00925 
00931 int QtxWorkstackArea::tabAt( const QPoint& pnt ) const
00932 {
00933   int idx = -1;
00934   QPoint p = myBar->mapFromGlobal( pnt );
00935   for ( int i = 0; i < myBar->count() && idx == -1; i++ )
00936   {
00937     QRect r = myBar->tabRect( i );
00938     if ( r.isValid() && r.contains( p ) )
00939       idx = i;
00940   }
00941   return idx;
00942 }
00943 
00948 void QtxWorkstackArea::customEvent( QEvent* e )
00949 {
00950   WidgetEvent* we = (WidgetEvent*)e;
00951 
00952   switch ( we->type() )
00953   {
00954   case ActivateWidget:
00955     myBar->updateActiveState();
00956     emit activated( activeWidget() );
00957     break;
00958   case FocusWidget:
00959     if ( activeWidget() )
00960     {
00961       if ( !activeWidget()->focusWidget() )
00962         activeWidget()->setFocus();
00963       else
00964       {
00965         if ( activeWidget()->focusWidget()->hasFocus() )
00966         {
00967           QFocusEvent in( QEvent::FocusIn );
00968                 QApplication::sendEvent( this, &in );
00969               }
00970         else
00971         {
00972           activeWidget()->focusWidget()->setFocus();
00973                 myBar->updateActiveState();
00974               }
00975       }
00976     }
00977     break;
00978   case MakeCurrent:
00979     if ( we->child()->widget() )
00980       setActiveWidget( we->child()->widget() );
00981     break;
00982   case RestoreWidget:
00983     if ( we->child() )
00984     {
00985       QtxWorkstackChild* c = we->child();
00986       RestoreEvent* re = (RestoreEvent*)we;
00987       if ( c->widget() )
00988         c->widget()->setVisible( re->flags() & QtxWorkstack::Visible );
00989       c->setId( re->id() );
00990       insertChild( c );
00991     }
00992     break;
00993   default:
00994     break;
00995   }
00996 }
00997 
01002 void QtxWorkstackArea::focusInEvent( QFocusEvent* e )
01003 {
01004   QFrame::focusInEvent( e );
01005 
01006   myBar->updateActiveState();
01007 
01008   emit activated( activeWidget() );
01009 }
01010 
01015 void QtxWorkstackArea::mousePressEvent( QMouseEvent* e )
01016 {
01017   QFrame::mousePressEvent( e );
01018 
01019   emit activated( activeWidget() );
01020 }
01021 
01025 void QtxWorkstackArea::onClose()
01026 {
01027   QWidget* wid = activeWidget();
01028   if ( wid )
01029     wid->close();
01030 }
01031 
01036 void QtxWorkstackArea::onCurrentChanged( int /*idx*/ )
01037 {
01038   updateCurrent();
01039 
01040   emit activated( activeWidget() );
01041 }
01042 
01046 void QtxWorkstackArea::onDragActiveTab()
01047 {
01048   QtxWorkstackChild* c = child( activeWidget() );
01049   if ( !c )
01050     return;
01051 
01052   new QtxWorkstackDrag( workstack(), c );
01053 }
01054 
01059 void QtxWorkstackArea::onChildDestroyed( QObject* obj )
01060 {
01061   removeChild( (QtxWorkstackChild*)obj, false );
01062 }
01063 
01068 void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c )
01069 {
01070   updateState();
01071 }
01072 
01077 void QtxWorkstackArea::onChildHidden( QtxWorkstackChild* c )
01078 {
01079   updateState();
01080 }
01081 
01086 void QtxWorkstackArea::onChildActivated( QtxWorkstackChild* c )
01087 {
01088   setWidgetActive( c->widget() );
01089 }
01090 
01095 void QtxWorkstackArea::onChildCaptionChanged( QtxWorkstackChild* c )
01096 {
01097   updateTab( c->widget() );
01098 }
01099 
01105 void QtxWorkstackArea::updateCurrent()
01106 {
01107   QWidget* cur = child( widget( myBar->tabId( myBar->currentIndex() ) ) );
01108   if ( cur )
01109     myStack->setCurrentWidget( cur );
01110 }
01111 
01116 void QtxWorkstackArea::updateTab( QWidget* wid )
01117 {
01118   int idx = myBar->indexOf( widgetId( wid ) );
01119   if ( idx < 0 )
01120     return;
01121 
01122   myBar->setTabIcon( idx, wid->windowIcon() );
01123   myBar->setTabText( idx, wid->windowTitle() );
01124 }
01125 
01131 QWidget* QtxWorkstackArea::widget( const int id ) const
01132 {
01133   QtxWorkstackChild* c = child( id );
01134 
01135   return c ? c->widget() : 0;
01136 }
01137 
01143 int QtxWorkstackArea::widgetId( QWidget* wid ) const
01144 {
01145   QtxWorkstackChild* c = child( wid );
01146 
01147   return c ? c->id() : -1;
01148 }
01149 
01154 void QtxWorkstackArea::setWidgetActive( QWidget* wid )
01155 {
01156   int id = widgetId( wid );
01157   if ( id < 0 )
01158     return;
01159 
01160   myBar->setCurrentIndex( myBar->indexOf( id ) );
01161 }
01162 
01166 void QtxWorkstackArea::updateState()
01167 {
01168   bool updBar = myBar->updatesEnabled();
01169   bool updStk = myStack->updatesEnabled();
01170   myBar->setUpdatesEnabled( false );
01171   myStack->setUpdatesEnabled( false );
01172 
01173   bool block = myBar->signalsBlocked();
01174   myBar->blockSignals( true );
01175 
01176   QWidget* prev = activeWidget();
01177 
01178   int idx = 0;
01179   for ( ChildList::iterator it = myList.begin(); it != myList.end(); ++it )
01180   {
01181     QtxWorkstackChild* cont = *it;
01182     QWidget* wid = cont->widget();;
01183     int id = cont->id();
01184 
01185     if ( id < 0 )
01186       continue;
01187 
01188     bool vis = cont->visibility();
01189 
01190     int cIdx = myBar->indexOf( id );
01191     if ( cIdx != -1 && ( !vis || myBar->indexOf( id ) != idx ) )
01192       myBar->removeTab( cIdx );
01193 
01194     if ( myBar->indexOf( id ) == -1 && vis )
01195       myBar->setTabId( myBar->insertTab( idx, wid->windowTitle() ), id );
01196 
01197     updateTab( wid );
01198 
01199     if ( !vis )
01200       myStack->removeWidget( cont );
01201     else if ( myStack->indexOf( cont ) < 0 )
01202       myStack->addWidget( cont );
01203 
01204     if ( vis )
01205       idx++;
01206   }
01207 
01208   int curId = widgetId( prev );
01209   if ( myBar->indexOf( curId ) < 0 )
01210   {
01211     QtxWorkstackChild* c = 0;
01212     int pos = myList.indexOf( child( prev ) );
01213     for ( int i = pos - 1; i >= 0 && !c; i-- )
01214     {
01215       if ( myList.at( i )->visibility() )
01216         c = myList.at( i );
01217     }
01218 
01219     for ( int j = pos + 1; j < (int)myList.count() && !c; j++ )
01220     {
01221       if ( myList.at( j )->visibility() )
01222         c = myList.at( j );
01223     }
01224 
01225     if ( c )
01226       curId = c->id();
01227   }
01228 
01229   myBar->setCurrentIndex( myBar->indexOf( curId ) );
01230 
01231   myBar->blockSignals( block );
01232 
01233   updateCurrent();
01234 
01235   myBar->updateActiveState();
01236 
01237   myBar->setUpdatesEnabled( updBar );
01238   myStack->setUpdatesEnabled( updStk );
01239   if ( updBar )
01240     myBar->update();
01241   if ( updStk )
01242     myStack->update();
01243 
01244   QResizeEvent re( myBar->size(), myBar->size() );
01245   QApplication::sendEvent( myBar, &re );
01246 
01247   myBar->updateGeometry();
01248 
01249   if ( isEmpty() )
01250   {
01251     hide();
01252     emit deactivated( this );
01253   }
01254   else
01255   {
01256     show();
01257     if ( prev != activeWidget() )
01258       emit activated( activeWidget() );
01259   }
01260 }
01261 
01266 int QtxWorkstackArea::generateId() const
01267 {
01268   QMap<int, int> map;
01269 
01270   for ( ChildList::const_iterator it = myList.begin(); it != myList.end(); ++it )
01271     map.insert( (*it)->id(), 0 );
01272 
01273   int id = 0;
01274   while ( map.contains( id ) )
01275     id++;
01276 
01277   return id;
01278 }
01279 
01285 QtxWorkstackChild* QtxWorkstackArea::child( QWidget* wid ) const
01286 {
01287   QtxWorkstackChild* res = 0;
01288   for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !res; ++it )
01289   {
01290     if ( (*it)->widget() == wid )
01291       res = *it;
01292   }
01293   return res;
01294 }
01295 
01296 QtxWorkstackChild* QtxWorkstackArea::child( const int id ) const
01297 {
01298   QtxWorkstackChild* c = 0;
01299   for ( ChildList::const_iterator it = myList.begin(); it != myList.end() && !c; ++it )
01300   {
01301     if ( (*it)->id() == id )
01302       c = *it;
01303   }
01304   return c;
01305 }
01306 
01338 QtxWorkstackChild::QtxWorkstackChild( QWidget* wid, QWidget* parent, Qt::WindowFlags f )
01339 : QWidget( parent ),
01340   myId( 0 ),
01341   myWidget( wid )
01342 {
01343   if ( myWidget )
01344   {
01345     myWidget->setParent( this, f );
01346     myWidget->installEventFilter( this );
01347     if ( myWidget->focusProxy() )
01348       myWidget->focusProxy()->installEventFilter( this );
01349     myWidget->setVisible( myWidget->isVisibleTo( myWidget->parentWidget() ) );
01350 
01351     QVBoxLayout* base = new QVBoxLayout( this );
01352     base->setMargin( 0 );
01353     base->addWidget( myWidget );
01354 
01355     connect( myWidget, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
01356   }
01357 }
01358 
01362 QtxWorkstackChild::~QtxWorkstackChild()
01363 {
01364   QApplication::instance()->removeEventFilter( this );
01365 
01366   if ( !widget() )
01367     return;
01368 
01369   disconnect( widget(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
01370 
01371   widget()->hide();
01372   widget()->removeEventFilter( this );
01373   if ( widget()->focusProxy() )
01374     widget()->focusProxy()->removeEventFilter( this );
01375 
01376   widget()->setParent( 0 );
01377 }
01378 
01383 QWidget* QtxWorkstackChild::widget() const
01384 {
01385   return myWidget;
01386 }
01387 
01391 int QtxWorkstackChild::id() const
01392 {
01393   return myId;
01394 }
01395 
01399 void QtxWorkstackChild::setId( const int id )
01400 {
01401   myId = id;
01402 }
01403 
01407 bool QtxWorkstackChild::visibility()
01408 {
01409   return myWidget ? myWidget->isVisibleTo( this ) : false;
01410 }
01411 
01412 QtxWorkstackArea* QtxWorkstackChild::area() const
01413 {
01414   QtxWorkstackArea* a = 0;
01415   QWidget* w = parentWidget();
01416   while ( !a && w )
01417   {
01418     a = ::qobject_cast<QtxWorkstackArea*>( w );
01419     w = w->parentWidget();
01420   }
01421 
01422   return a;
01423 }
01424 
01434 bool QtxWorkstackChild::eventFilter( QObject* o, QEvent* e )
01435 {
01436   if ( o->isWidgetType() )
01437   {
01438     if ( e->type() == QEvent::WindowTitleChange || e->type() == QEvent::WindowIconChange )
01439       emit captionChanged( this );
01440 
01441     if ( !e->spontaneous() && e->type() == QEvent::ShowToParent )
01442       emit shown( this );
01443 
01444     if ( !e->spontaneous() && e->type() == QEvent::HideToParent )
01445       emit hidden( this );
01446 
01447     if ( e->type() == QEvent::FocusIn )
01448       emit activated( this );
01449   }
01450   return QWidget::eventFilter( o, e );
01451 }
01452 
01457 void QtxWorkstackChild::onDestroyed( QObject* obj )
01458 {
01459   deleteLater();
01460 }
01461 
01466 void QtxWorkstackChild::childEvent( QChildEvent* e )
01467 {
01468   if ( e->removed() && e->child() == widget() )
01469   {
01470     myWidget = 0;
01471     deleteLater();
01472   }
01473   QWidget::childEvent( e );
01474 }
01475 
01510 QtxWorkstackTabBar::QtxWorkstackTabBar( QWidget* parent )
01511 : QTabBar( parent ),
01512   myId( -1 ),myActive(false)
01513 {
01514   setDrawBase( true );
01515   setElideMode( Qt::ElideNone );
01516 
01517   connect( this, SIGNAL( currentChanged( int ) ), this, SLOT( onCurrentChanged( int ) ) );
01518 }
01519 
01523 QtxWorkstackTabBar::~QtxWorkstackTabBar()
01524 {
01525 }
01526 
01532 int QtxWorkstackTabBar::tabId( const int index ) const
01533 {
01534   QVariant v = tabData( index );
01535   if ( !v.canConvert( QVariant::Int ) )
01536     return -1;
01537   return v.toInt();
01538 }
01539 
01545 void QtxWorkstackTabBar::setTabId( const int index, const int id )
01546 {
01547   setTabData( index, id );
01548 }
01549 
01555 int QtxWorkstackTabBar::indexOf( const int id ) const
01556 {
01557   int index = -1;
01558   for ( int i = 0; i < (int)count() && index < 0; i++ )
01559   {
01560     if ( tabId( i ) == id )
01561       index = i;
01562   }
01563   return index;
01564 }
01565 
01570 bool QtxWorkstackTabBar::isActive() const
01571 {
01572   return myActive;
01573 }
01574 
01579 void QtxWorkstackTabBar::setActive( const bool on )
01580 {
01581   if ( myActive == on )
01582     return;
01583 
01584   myActive = on;
01585   updateActiveState();
01586 }
01587 
01591 void QtxWorkstackTabBar::updateActiveState()
01592 {
01593   QColor bc = palette().color( QPalette::Text );
01594   QColor ac = isActive() ? palette().color( QPalette::Highlight ) : bc;
01595   for ( int i = 0; i < (int)count(); i++ )
01596     setTabTextColor( i, currentIndex() == i ? ac : bc );
01597 }
01598 
01603 void QtxWorkstackTabBar::onCurrentChanged( int /*index*/ )
01604 {
01605   updateActiveState();
01606 }
01607 
01612 void QtxWorkstackTabBar::mouseMoveEvent( QMouseEvent* e )
01613 {
01614   if ( myId != -1 && !tabRect( indexOf( myId ) ).contains( e->pos() ) )
01615   {
01616     myId = -1;
01617     emit dragActiveTab();
01618   }
01619 
01620   QTabBar::mouseMoveEvent( e );
01621 }
01622 
01627 void QtxWorkstackTabBar::mousePressEvent( QMouseEvent* e )
01628 {
01629   QTabBar::mousePressEvent( e );
01630 
01631   if ( e->button() == Qt::LeftButton )
01632     myId = tabId( currentIndex() );
01633 }
01634 
01639 void QtxWorkstackTabBar::mouseReleaseEvent( QMouseEvent* e )
01640 {
01641   QTabBar::mouseReleaseEvent( e );
01642 
01643   myId = -1;
01644 
01645   if ( e->button() == Qt::RightButton )
01646     emit contextMenuRequested( e->globalPos() );
01647 }
01648 
01653 void QtxWorkstackTabBar::contextMenuEvent( QContextMenuEvent* e )
01654 {
01655   if ( e->reason() != QContextMenuEvent::Mouse )
01656     emit contextMenuRequested( e->globalPos() );
01657 }
01658 
01663 void QtxWorkstackTabBar::changeEvent( QEvent* /*e*/ )
01664 {
01665   updateActiveState();
01666 }
01667 
01668 /*
01669 void QtxWorkstackTabBar::paintLabel( QPainter* p, const QRect& br, QTab* t, bool has_focus ) const
01670 {
01671   if ( currentTab() != t->identifier() )
01672   {
01673     QFont fnt = p->font();
01674     fnt.setUnderline( false );
01675     p->setFont( fnt );
01676   }
01677   QTabBar::paintLabel( p, br, t, has_focus );
01678 }
01679 */
01680 
01709 QtxWorkstack::QtxWorkstack( QWidget* parent )
01710 : QWidget( parent ),
01711   myWin( 0 ),
01712   myArea( 0 ),
01713   myWorkWin( 0 ),
01714   myWorkArea( 0 )
01715 {
01716   myActionsMap.insert( SplitVertical,   new QtxAction( QString(), tr( "Split vertically" ), 0, this ) );
01717   myActionsMap.insert( SplitHorizontal, new QtxAction( QString(), tr( "Split horizontally" ), 0, this ) );
01718   myActionsMap.insert( Close,           new QtxAction( QString(), tr( "Close" ), 0, this ) );
01719   myActionsMap.insert( Rename,          new QtxAction( QString(), tr( "Rename" ), 0, this ) );
01720 
01721   connect( myActionsMap[SplitVertical], SIGNAL( triggered( bool ) ), this, SLOT( splitVertical() ) );
01722   connect( myActionsMap[SplitHorizontal], SIGNAL( triggered( bool ) ), this, SLOT( splitHorizontal() ) );
01723   connect( myActionsMap[Close], SIGNAL( triggered( bool ) ), this, SLOT( onCloseWindow() ) );
01724   connect( myActionsMap[Rename], SIGNAL( triggered( bool ) ), this, SLOT( onRename() ) );
01725 
01726   // Action shortcut will work when action added in any widget.
01727   for ( QMap<int, QAction*>::iterator it = myActionsMap.begin(); it != myActionsMap.end(); ++it )
01728   {
01729     addAction( it.value() );
01730     it.value()->setShortcutContext( Qt::ApplicationShortcut );
01731   }
01732 
01733   QVBoxLayout* base = new QVBoxLayout( this );
01734   base->setMargin( 0 );
01735 
01736   mySplit = new QtxWorkstackSplitter( this );
01737   base->addWidget( mySplit );
01738 }
01739 
01743 QtxWorkstack::~QtxWorkstack()
01744 {
01745 }
01746 
01754 QWidgetList QtxWorkstack::windowList( QWidget* wid ) const
01755 {
01756   QList<QtxWorkstackArea*> lst;
01757   if ( !wid )
01758   {
01759     areas( mySplit, lst, true );
01760   }
01761   else
01762   {
01763     QtxWorkstackArea* area = wgArea( wid );
01764     if ( area )
01765       lst.append( area );
01766   }
01767 
01768   QWidgetList widList;
01769   for ( QList<QtxWorkstackArea*>::iterator it = lst.begin(); it != lst.end(); ++it )
01770   {
01771     QWidgetList wids = (*it)->widgetList();
01772     for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr )
01773       widList.append( *itr );
01774   }
01775 
01776   return widList;
01777 }
01778 
01783 QWidgetList QtxWorkstack::splitWindowList() const
01784 {
01785   return myArea ? myArea->widgetList() : QWidgetList();
01786 }
01787 
01792 QWidget* QtxWorkstack::activeWindow() const
01793 {
01794   return myWin;
01795 }
01796 
01805 void QtxWorkstack::split( const int o )
01806 {
01807   QtxWorkstackArea* area = myWorkArea;
01808   if ( !area )
01809     area = activeArea();
01810   if ( !area )
01811     return;
01812 
01813   if ( area->widgetList().count() < 2 )
01814     return;
01815 
01816   QWidget* curWid = area->activeWidget();
01817   if ( !curWid )
01818     return;
01819 
01820   QSplitter* s = splitter( area );
01821   QList<QtxWorkstackArea*> areaList;
01822   areas( s, areaList );
01823 
01824   QList<QSplitter*> splitList;
01825   splitters( s, splitList );
01826 
01827   QSplitter* trg = 0;
01828   if ( areaList.count() + splitList.count() < 2 || s->orientation() == o )
01829     trg = s;
01830 
01831   if ( !trg )
01832     trg = wrapSplitter( area );
01833 
01834   if ( !trg )
01835     return;
01836 
01837   trg->setOrientation( (Qt::Orientation)o );
01838 
01839   QtxWorkstackArea* newArea = createArea( 0 );
01840   trg->insertWidget( trg->indexOf( area ) + 1, newArea );
01841 
01842   area->removeWidget( curWid );
01843   newArea->insertWidget( curWid );
01844 
01845   distributeSpace( trg );
01846 
01847   curWid->show();
01848   curWid->setFocus();
01849 }
01850 
01861 void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType type )
01862 {
01863   if (!wid) return;
01864 
01865   // find area of the given widget
01866   QtxWorkstackArea* area = NULL;
01867   QList<QtxWorkstackArea*> allAreas;
01868   areas(mySplit, allAreas, true);
01869 
01870   for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it )
01871   {
01872     if ( (*it)->contains( wid ) )
01873       area = *it;
01874   }
01875 
01876   if ( !area )
01877     return;
01878 
01879   QWidget* curWid = area->activeWidget();
01880   if ( !curWid )
01881     return;
01882 
01883   QWidgetList wids = area->widgetList();
01884   if ( wids.count() < 2 )
01885     return;
01886 
01887   QSplitter* s = splitter( area );
01888   QList<QtxWorkstackArea*> areaList;
01889   areas( s, areaList );
01890 
01891   QList<QSplitter*> splitList;
01892   splitters(s, splitList);
01893 
01894   QSplitter* trg = 0;
01895   if (areaList.count() + splitList.count() < 2 || s->orientation() == o)
01896     trg = s;
01897 
01898   if (!trg) trg = wrapSplitter(area);
01899   if (!trg) return;
01900 
01901   trg->setOrientation(o);
01902 
01903   QtxWorkstackArea* newArea = createArea(0);
01904   insertWidget(newArea, trg, area);
01905 
01906   switch ( type )
01907   {
01908   case SplitStay:
01909     for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr )
01910     {
01911       QWidget* wid_i = *itr;
01912       if ( wid_i != wid )
01913       {
01914         area->removeWidget( wid_i );
01915         newArea->insertWidget( wid_i );
01916         wid_i->showMaximized();
01917       }
01918     }
01919     break;
01920   case SplitAt:
01921     {
01922       QWidgetList::iterator itr = wids.begin();
01923       for ( ; itr != wids.end() && *itr != wid; ++itr )
01924       {
01925       }
01926       for ( ; itr != wids.end(); ++itr )
01927       {
01928         area->removeWidget( *itr );
01929         newArea->insertWidget( *itr );
01930         (*itr)->showMaximized();
01931       }
01932     }
01933     break;
01934   case SplitMove:
01935     area->removeWidget( wid );
01936     newArea->insertWidget( wid );
01937     wid->showMaximized();
01938     break;
01939   }
01940 
01941   distributeSpace( trg );
01942 
01943   curWid->show();
01944   curWid->setFocus();
01945 }
01946 
01963 void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all )
01964 {
01965   if ( !wid1 || !wid2 )
01966     return;
01967 
01968   // find area of the widgets
01969   QtxWorkstackArea *area1 = 0, *area2 = 0;
01970   QList<QtxWorkstackArea*> allAreas;
01971   areas( mySplit, allAreas, true );
01972   for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !( area1 && area2 ); ++it )
01973   {
01974     if ( (*it)->contains( wid1 ) )
01975       area1 = *it;
01976 
01977     if ( (*it)->contains( wid2 ) )
01978       area2 = *it;
01979   }
01980 
01981   if ( !area1 || !area2 )
01982     return;
01983 
01984   QSplitter* s1 = splitter( area1 );
01985 
01986   QWidget* curWid = area1->activeWidget();
01987   if ( !curWid )
01988     return;
01989 
01990   if ( area1 == area2 )
01991   {
01992     if ( all )
01993     {
01994       // Set wid1 at first position, wid2 at second
01995       area1->insertWidget( wid1 );
01996       area1->insertWidget( wid2, 1 );
01997       wid1->showMaximized();
01998       wid2->showMaximized();
01999     }
02000     else
02001     {
02002       // Set wid2 right after wid1
02003       area1->removeWidget( wid2 );
02004       int wid1_ind = 0;
02005       QWidgetList wids1 = area1->widgetList();
02006       for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind );
02007       area1->insertWidget( wid2, wid1_ind + 1 );
02008       wid2->showMaximized();
02009     }
02010   }
02011   else
02012   {
02013     int wid1_ind = 0;
02014     QWidgetList wids1 = area1->widgetList();
02015     for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind );
02016     if ( all )
02017     {
02018       // Set wid2 right after wid1, other widgets from area2 right after wid2
02019       QWidgetList wids2 = area2->widgetList();
02020       QWidgetList::iterator itr2 = wids2.begin();
02021       for ( int ind = wid1_ind + 1; itr2 != wids2.end(); ++itr2, ++ind )
02022       {
02023         area2->removeWidget( *itr2 );
02024         if ( *itr2 == wid2 )
02025           area1->insertWidget( *itr2, wid1_ind + 1 );
02026         else
02027           area1->insertWidget( *itr2, ind );
02028         (*itr2)->showMaximized();
02029       }
02030     }
02031     else
02032     {
02033       // Set wid2 right after wid1
02034       area2->removeWidget( wid2 );
02035       area1->insertWidget( wid2, wid1_ind + 1 );
02036       wid2->showMaximized();
02037     }
02038   }
02039 
02040   distributeSpace( s1 );
02041 
02042   area1->setActiveWidget( curWid );
02043 
02044   wid2->show();
02045   wid1->setFocus();
02046   curWid->show();
02047   curWid->setFocus();
02048 }
02049 
02054 static void setSizes (QIntList& szList, const int item_ind,
02055                       const int new_near, const int new_this, const int new_farr)
02056 {
02057   // set size to all items before an item # <item_ind>
02058   int cur_pos = 0;
02059   QIntList::iterator its = szList.begin();
02060   for (; its != szList.end() && cur_pos < item_ind; ++its, ++cur_pos) {
02061     *its = new_near;
02062   }
02063   if (its == szList.end()) return;
02064   // set size to item # <item_ind>
02065   *its = new_this;
02066   ++its;
02067   // set size to all items after an item # <item_ind>
02068   for (; its != szList.end(); ++its) {
02069     *its = new_farr;
02070   }
02071 }
02072 
02081 void QtxWorkstack::SetRelativePositionInSplitter( QWidget* wid, const double position )
02082 {
02083   if ( position < 0.0 || 1.0 < position)
02084     return;
02085 
02086   if ( !wid )
02087     return;
02088 
02089   // find area of the given widget
02090   QtxWorkstackArea* area = NULL;
02091   QList<QtxWorkstackArea*> allAreas;
02092   areas( mySplit, allAreas, true );
02093   for ( QList<QtxWorkstackArea*>::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it )
02094   {
02095     if ( (*it)->contains( wid ) )
02096       area = *it;
02097   }
02098 
02099   if ( !area )
02100     return;
02101 
02102   QSplitter* split = splitter( area );
02103   if ( !split )
02104     return;
02105 
02106   // find index of the area in its splitter
02107   int item_ind = -1;
02108   bool isFound = false;
02109   const QObjectList& was = split->children();
02110   for ( QObjectList::const_iterator ito = was.begin(); ito != was.end() && !isFound; ++ito, ++item_ind )
02111   {
02112     if ( *ito == area )
02113       isFound = true;
02114   }
02115 
02116   if ( !isFound || item_ind == 0 )
02117     return;
02118 
02119   QIntList szList = split->sizes();
02120   int splitter_size = ( split->orientation() == Qt::Horizontal ? split->width() : split->height());
02121   int nb = szList.count();
02122 
02123   int new_prev = int( splitter_size * position / item_ind );
02124   if (nb == item_ind) return;
02125   int new_next = int( splitter_size * ( 1.0 - position ) / ( nb - item_ind ) );
02126   setSizes( szList, item_ind, new_prev, new_next, new_next );
02127   split->setSizes( szList );
02128 }
02129 
02140 void QtxWorkstack::SetRelativePosition( QWidget* wid, const Qt::Orientation o,
02141                                         const double position )
02142 {
02143   if ( position < 0.0 || 1.0 < position )
02144     return;
02145 
02146   if ( !wid )
02147     return;
02148 
02149   int splitter_size = o == Qt::Horizontal ? mySplit->width() : mySplit->height();
02150   int need_pos = int( position * splitter_size );
02151   int splitter_pos = 0;
02152 
02153   if ( setPosition( wid, mySplit, o, need_pos, splitter_pos ) != 0 )
02154   {
02155     // impossible to set required position
02156   }
02157 }
02158 
02164 void QtxWorkstack::setAccel( const int id, const int accel )
02165 {
02166   if ( !myActionsMap.contains( id ) )
02167     return;
02168 
02169   myActionsMap[id]->setShortcut( accel );
02170 }
02171 
02177 int QtxWorkstack::accel( const int id ) const
02178 {
02179   int res = 0;
02180   if ( myActionsMap.contains( id ) )
02181     res = myActionsMap[id]->shortcut();
02182   return res;
02183 }
02184 
02193 QIcon QtxWorkstack::icon( const int id ) const
02194 {
02195   QIcon ico;
02196   if ( myActionsMap.contains( id ) )
02197     ico = myActionsMap[id]->icon();
02198   return ico;
02199 }
02200 
02206 void QtxWorkstack::setIcon( const int id, const QIcon& icon )
02207 {
02208   if ( !myActionsMap.contains( id ) )
02209     return;
02210 
02211   myActionsMap[id]->setIcon( icon );
02212 }
02213 
02222 void QtxWorkstack::setMenuActions( const int flags )
02223 {
02224   myActionsMap[SplitVertical]->setVisible( flags & SplitVertical );
02225   myActionsMap[SplitHorizontal]->setVisible( flags & SplitHorizontal );
02226   myActionsMap[Close]->setVisible( flags & Close );
02227   myActionsMap[Rename]->setVisible( flags & Rename );
02228 }
02229 
02238 int QtxWorkstack::menuActions() const
02239 {
02240   int ret = 0;
02241   ret = ret | ( myActionsMap[SplitVertical]->isVisible() ? SplitVertical : 0 );
02242   ret = ret | ( myActionsMap[SplitHorizontal]->isVisible() ? SplitHorizontal : 0 );
02243   ret = ret | ( myActionsMap[Close]->isVisible() ? Close : 0 );
02244   ret = ret | ( myActionsMap[Rename]->isVisible() ? Rename : 0 );
02245   return ret;
02246 }
02247 
02252 static int positionSimple (QIntList& szList, const int nb, const int splitter_size,
02253                            const int item_ind, const int item_rel_pos,
02254                            const int need_pos, const int splitter_pos)
02255 {
02256   if (item_ind == 0) { // cannot move in this splitter
02257     return (need_pos - splitter_pos);
02258   }
02259 
02260   int delta = 0;
02261   int new_prev = 0;
02262   int new_this = szList[item_ind];
02263   int new_next = 0;
02264 
02265   bool isToCheck = false;
02266 
02267   if (need_pos < splitter_pos) {
02268     // Set size of all previous workareas to zero <--
02269     if (item_ind == nb - 1) {
02270       // item iz last in the splitter, it will occupy all the splitter
02271       new_this = splitter_size;
02272     } else {
02273       // recompute size of next items in splitter
02274       new_next = (splitter_size - new_this) / (nb - item_ind - 1);
02275     }
02276     delta = need_pos - splitter_pos;
02277 
02278   } else if (need_pos > (splitter_pos + splitter_size)) {
02279     // Set size of all next workareas to zero -->
02280     // recompute size of previous items in splitter
02281     new_this = 0;
02282     new_prev = (splitter_size - new_this) / item_ind;
02283     delta = need_pos - (splitter_pos + splitter_size - new_this);
02284 
02285   } else { // required position lays inside this splitter
02286     // Move workarea inside splitter into required position <->
02287     int new_item_rel_pos = need_pos - splitter_pos;
02288     new_prev = new_item_rel_pos / item_ind;
02289     if (need_pos < (splitter_pos + item_rel_pos)) {
02290       // Make previous workareas smaller, next - bigger
02291       // No problem to keep old size of the widget
02292     } else {
02293       // Make previous workareas bigger, next - smaller
02294       if (new_this > splitter_size - new_item_rel_pos) {
02295         new_this = splitter_size - new_item_rel_pos;
02296       }
02297       // jfa to do: in this case fixed size of next widgets could prevent right resizing
02298       isToCheck = true;
02299     }
02300     if (item_ind == nb - 1) {
02301       new_this = splitter_size - new_item_rel_pos;
02302     } else {
02303       new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
02304     }
02305     delta = 0;
02306   }
02307 
02308   setSizes (szList, item_ind, new_prev, new_this, new_next);
02309   return delta;
02310 }
02311 
02327 int QtxWorkstack::setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o,
02328                                const int need_pos, const int splitter_pos )
02329 {
02330   if ( !wid || !split )
02331     return need_pos - splitter_pos;
02332 
02333   // Find corresponding sub-splitter.
02334   // Find also index of appropriate item in current splitter.
02335   int cur_ind = 0, item_ind = 0;
02336   bool isBottom = false, isFound = false;
02337   QSplitter* sub_split = NULL;
02338   const QObjectList& objs = split->children();
02339   for ( QObjectList::const_iterator it = objs.begin(); it != objs.end() && !isFound; ++it )
02340   {
02341     QtxWorkstackArea* area = ::qobject_cast<QtxWorkstackArea*>( *it );
02342     if ( area )
02343     {
02344       if ( area->contains( wid ) )
02345       {
02346         item_ind = cur_ind;
02347         isBottom = true;
02348         isFound = true;
02349       }
02350       cur_ind++;
02351     }
02352     else if ( (*it)->inherits( "QSplitter" ) )
02353     {
02354       QList<QtxWorkstackArea*> areaList;
02355       areas( (QSplitter*)(*it), areaList, true );
02356       for ( QList<QtxWorkstackArea*>::iterator ita = areaList.begin(); ita != areaList.end() && !isFound; ++ita )
02357       {
02358         if ( (*ita)->contains( wid ) )
02359         {
02360           item_ind = cur_ind;
02361           isFound = true;
02362           sub_split = (QSplitter*)*it;
02363         }
02364       }
02365       cur_ind++;
02366     }
02367   }
02368 
02369   if ( !isFound )
02370     return ( need_pos - splitter_pos );
02371 
02372   if ( split->orientation() == o )
02373   {
02374     // Find coordinates of near and far sides of the appropriate item relatively current splitter
02375     int splitter_size = ( o == Qt::Horizontal ? split->width() : split->height() );
02376     QIntList szList = split->sizes();
02377     int nb = szList.count();
02378     int item_rel_pos = 0; // position of near side of item relatively this splitter
02379     for (int i = 0; i < item_ind; i++) {
02380       item_rel_pos += szList[i];
02381     }
02382     int item_size = szList[item_ind]; // size of item
02383     int item_pos = splitter_pos + item_rel_pos;
02384 
02385     // Resize splitter items to complete the conditions
02386     if (isBottom) {
02387       // I. Bottom of splitters stack reached
02388 
02389       int delta = positionSimple(szList, nb, splitter_size, item_ind, item_rel_pos, need_pos, splitter_pos);
02390       split->setSizes(szList);
02391       // Recompute delta, as some windows can reject given size
02392       int new_item_rel_pos = 0;
02393       QIntList szList1 = split->sizes();
02394       for (int i = 0; i < item_ind; i++) {
02395         new_item_rel_pos += szList1[i];
02396       }
02397       delta = need_pos - (splitter_pos + new_item_rel_pos);
02398       return delta;
02399 
02400     } else {
02401       // II. Bottom of splitters stack is not yet reached
02402 
02403       if (item_ind == 0) { // cannot move in this splitter
02404         // Process in sub-splitter
02405         return setPosition(wid, sub_split, o, need_pos, splitter_pos);
02406       }
02407 
02408       int new_prev = 0;
02409       int new_this = szList[item_ind];
02410       int new_next = 0;
02411 
02412       if (need_pos < splitter_pos) {
02413         // Set size of all previous workareas to zero <--
02414         if (item_ind == nb - 1) {
02415           new_this = splitter_size;
02416         } else {
02417           new_next = (splitter_size - new_this) / (nb - item_ind - 1);
02418         }
02419         setSizes (szList, item_ind, new_prev, new_this, new_next);
02420         split->setSizes(szList);
02421         // Recompute splitter_pos, as some windows can reject given size
02422         int new_item_rel_pos = 0;
02423         QIntList szList1 = split->sizes();
02424         for (int i = 0; i < item_ind; i++) {
02425           new_item_rel_pos += szList1[i];
02426         }
02427         // Process in sub-splitter
02428         return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
02429       } else if (need_pos > (splitter_pos + splitter_size)) {
02430         // Set size of all next workareas to zero -->
02431         new_prev = (splitter_size - new_this) / item_ind;
02432         setSizes (szList, item_ind, new_prev, new_this, new_next);
02433         split->setSizes(szList);
02434         // Recompute splitter_pos, as some windows can reject given size
02435         int new_item_rel_pos = 0;
02436         QIntList szList1 = split->sizes();
02437         for (int i = 0; i < item_ind; i++) {
02438           new_item_rel_pos += szList1[i];
02439         }
02440         // Process in sub-splitter
02441         return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
02442       } else {
02443         // Set appropriate size of all previous/next items <->
02444         int new_item_rel_pos = item_rel_pos;
02445         if (need_pos < item_pos || (item_pos + item_size) < need_pos) {
02446           // Move item inside splitter into required position <->
02447           int new_this = szList[item_ind];
02448           int new_next = 0;
02449           new_item_rel_pos = need_pos - splitter_pos;
02450           if ((item_pos + item_size) < need_pos) {
02451             //new_item_rel_pos = need_pos - (item_pos + item_size);
02452             new_item_rel_pos = item_rel_pos + (need_pos - (item_pos + item_size));
02453           }
02454           int new_prev = new_item_rel_pos / item_ind;
02455           if (need_pos < (splitter_pos + item_rel_pos)) {
02456             // Make previous workareas smaller, next - bigger
02457             // No problem to keep old size of the widget
02458           } else {
02459             // Make previous workareas bigger, next - smaller
02460             if (new_this > splitter_size - new_item_rel_pos) {
02461               new_this = splitter_size - new_item_rel_pos;
02462             }
02463           }
02464           if (item_ind == nb - 1) {
02465             new_this = splitter_size - new_item_rel_pos;
02466           } else {
02467             new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1);
02468           }
02469           setSizes (szList, item_ind, new_prev, new_this, new_next);
02470           split->setSizes(szList);
02471           // Recompute new_item_rel_pos, as some windows can reject given size
02472           new_item_rel_pos = 0;
02473           QIntList szList1 = split->sizes();
02474           for (int i = 0; i < item_ind; i++) {
02475             new_item_rel_pos += szList1[i];
02476           }
02477         } else {
02478           // Do nothing
02479         }
02480         // Process in sub-splitter
02481         int add_pos = setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos);
02482         if (add_pos == 0)
02483           return 0;
02484 
02485         // this can be if corresponding workarea is first in sub-splitter
02486         // or sub-splitter has another orientation
02487 
02488         // Resize ones again to reach precize position <->
02489         int need_pos_1 = splitter_pos + new_item_rel_pos + add_pos;
02490 
02491         // Move workarea inside splitter into required position <->
02492         int delta_1 = positionSimple(szList, nb, splitter_size, item_ind,
02493                                      new_item_rel_pos, need_pos_1, splitter_pos);
02494         split->setSizes(szList);
02495         // Recompute new_item_rel_pos, as some windows can reject given size
02496         new_item_rel_pos = 0;
02497         QIntList szList1 = split->sizes();
02498         for (int i = 0; i < item_ind; i++) {
02499           new_item_rel_pos += szList1[i];
02500         }
02501         delta_1 = need_pos_1 - (splitter_pos + new_item_rel_pos);
02502         return delta_1;
02503       }
02504     }
02505   } else {
02506     return setPosition(wid, sub_split, o, need_pos, splitter_pos);
02507   }
02508 
02509   return 0;
02510 }
02511 
02516 void QtxWorkstack::distributeSpace( QSplitter* split ) const
02517 {
02518   if ( !split )
02519     return;
02520 
02521   QIntList szList = split->sizes();
02522   int size = ( split->orientation() == Qt::Horizontal ?
02523                split->width() : split->height() ) / szList.count();
02524   for ( QIntList::iterator it = szList.begin(); it != szList.end(); ++it )
02525     *it = size;
02526   split->setSizes( szList );
02527 }
02528 
02532 void QtxWorkstack::splitVertical()
02533 {
02534   split( Qt::Horizontal );
02535 }
02536 
02540 void QtxWorkstack::splitHorizontal()
02541 {
02542   split( Qt::Vertical );
02543 }
02544 
02550 void QtxWorkstack::onRename()
02551 {
02552   if ( !myWorkWin )
02553     return;
02554 
02555   bool ok = false;
02556   QString newName = QInputDialog::getText( topLevelWidget(),  tr( "Rename" ), tr( "Enter new name:" ),
02557                                            QLineEdit::Normal, myWorkWin->windowTitle(), &ok );
02558   if ( ok && !newName.isEmpty() )
02559     myWorkWin->setWindowTitle( newName );
02560 }
02561 
02567 QSplitter* QtxWorkstack::wrapSplitter( QtxWorkstackArea* area )
02568 {
02569   if ( !area )
02570     return 0;
02571 
02572   QSplitter* pSplit = splitter( area );
02573   if ( !pSplit )
02574     return 0;
02575 
02576   bool upd = pSplit->updatesEnabled();
02577   pSplit->setUpdatesEnabled( false );
02578 
02579   QIntList szList = pSplit->sizes();
02580 
02581   QSplitter* wrap = new QtxWorkstackSplitter( 0 );
02582   pSplit->insertWidget( pSplit->indexOf( area ) + 1, wrap );
02583   wrap->setVisible( true );
02584   wrap->addWidget( area );
02585 
02586   pSplit->setSizes( szList );
02587 
02588   pSplit->setUpdatesEnabled( upd );
02589 
02590   return wrap;
02591 }
02592 
02599 void QtxWorkstack::insertWidget( QWidget* wid, QWidget* pWid, QWidget* after )
02600 {
02601   if ( !wid || !pWid )
02602     return;
02603 
02604   QWidgetList moveList;
02605   const QObjectList& lst = pWid->children();
02606   bool found = false;
02607   for ( QObjectList::const_iterator it = lst.begin(); it != lst.end(); ++it )
02608   {
02609     if ( found && ( (*it)->inherits( "QSplitter" ) ||
02610                     (*it)->inherits( "QtxWorkstackArea" ) ) )
02611       moveList.append( (QWidget*)(*it) );
02612     if ( *it == after )
02613       found = true;
02614   }
02615 
02616   QMap<QWidget*, bool> map;
02617   for ( QWidgetList::iterator it = moveList.begin(); it != moveList.end(); ++it )
02618   {
02619     map.insert( *it, (*it)->isVisibleTo( (*it)->parentWidget() ) );
02620     (*it)->setParent( 0 );
02621     (*it)->hide();
02622   }
02623 
02624   wid->setParent( pWid );
02625 
02626   for ( QWidgetList::iterator itr = moveList.begin(); itr != moveList.end(); ++itr )
02627   {
02628     (*itr)->setParent( pWid );
02629     (*itr)->setShown( map.contains( *itr ) ? map[*itr] : false );
02630   }
02631 }
02632 
02636 void QtxWorkstack::onCloseWindow()
02637 {
02638   if ( myWorkWin )
02639     myWorkWin->close();
02640   else if( activeWindow() )
02641     activeWindow()->close();
02642 }
02643 
02651 void QtxWorkstack::onDestroyed( QObject* obj )
02652 {
02653   QtxWorkstackArea* area = (QtxWorkstackArea*)obj;
02654 
02655   if ( area == myArea )
02656     myArea = 0;
02657 
02658   if ( !myArea )
02659   {
02660     QtxWorkstackArea* cur = neighbourArea( area );
02661     if ( cur )
02662       cur->setFocus();
02663   }
02664 
02665   QApplication::postEvent( this, new QEvent( QEvent::User ) );
02666 }
02667 
02672 void QtxWorkstack::onWindowActivated( QWidget* /*area*/ )
02673 {
02674   const QObject* obj = sender();
02675   if ( !obj->inherits( "QtxWorkstackArea" ) )
02676     return;
02677 
02678   setActiveArea( (QtxWorkstackArea*)obj );
02679 }
02680 
02685 void QtxWorkstack::onDeactivated( QtxWorkstackArea* area )
02686 {
02687   if ( myArea != area )
02688     return;
02689 
02690   QList<QtxWorkstackArea*> lst;
02691   areas( mySplit, lst, true );
02692 
02693   int idx = lst.indexOf( area );
02694   if ( idx == -1 )
02695     return;
02696 
02697   myWin = 0;
02698   myArea = 0;
02699 
02700   QtxWorkstackArea* newArea = neighbourArea( area );
02701   if ( newArea && newArea->activeWidget() )
02702     newArea->activeWidget()->setFocus();
02703 
02704   QApplication::postEvent( this, new QEvent( QEvent::User ) );
02705 }
02706 
02712 void QtxWorkstack::onContextMenuRequested( QWidget* w, QPoint p )
02713 {
02714   QtxWorkstackArea* anArea = ::qobject_cast<QtxWorkstackArea*>( (QObject*)sender() );
02715   if ( !anArea )
02716     anArea = activeArea();
02717 
02718   if ( !anArea )
02719     return;
02720 
02721   QWidgetList lst = anArea->widgetList();
02722   if ( lst.isEmpty() )
02723     return;
02724 
02725   myWorkWin = w;
02726   myWorkArea = anArea;
02727 
02728   QMenu* pm = new QMenu();
02729 
02730   if ( lst.count() > 1 )
02731   {
02732     if ( myActionsMap[SplitVertical]->isEnabled() )
02733       pm->addAction( myActionsMap[SplitVertical] );
02734     if ( myActionsMap[SplitHorizontal]->isEnabled() )
02735       pm->addAction( myActionsMap[SplitHorizontal] );
02736     pm->addSeparator();
02737   }
02738 
02739   if ( w )
02740   {
02741     if ( myActionsMap[Close]->isEnabled() )
02742       pm->addAction( myActionsMap[Close] );
02743     if ( myActionsMap[Rename]->isEnabled() )
02744       pm->addAction( myActionsMap[Rename] );
02745   }
02746 
02747   Qtx::simplifySeparators( pm );
02748 
02749   if ( !pm->actions().isEmpty() )
02750     pm->exec( p );
02751 
02752   delete pm;
02753 
02754   myWorkWin = 0;
02755   myWorkArea = 0;
02756 }
02757 
02764 QWidget* QtxWorkstack::addWindow( QWidget* w, Qt::WindowFlags f )
02765 {
02766   if ( !w )
02767     return 0;
02768 
02769   return targetArea()->insertWidget( w, -1, f );
02770 }
02771 
02776 void QtxWorkstack::customEvent( QEvent* /*e*/ )
02777 {
02778   updateState();
02779 }
02780 
02786 QSplitter* QtxWorkstack::splitter( QtxWorkstackArea* area ) const
02787 {
02788   if ( !area )
02789     return 0;
02790 
02791   QSplitter* split = 0;
02792 
02793   QWidget* wid = area->parentWidget();
02794   if ( wid && wid->inherits( "QSplitter" ) )
02795     split = (QSplitter*)wid;
02796 
02797   return split;
02798 }
02799 
02806 void QtxWorkstack::splitters( QSplitter* split, QList<QSplitter*>& splitList, const bool rec ) const
02807 {
02808   if ( !split )
02809     return;
02810 
02811   const QObjectList& objs = split->children();
02812   for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
02813   {
02814     if ( rec )
02815       splitters( (QSplitter*)*it, splitList, rec );
02816     if ( (*it)->inherits( "QSplitter" ) )
02817       splitList.append( (QSplitter*)*it );
02818   }
02819 }
02820 
02827 void QtxWorkstack::areas( QSplitter* split, QList<QtxWorkstackArea*>& areaList, const bool rec ) const
02828 {
02829   if ( !split )
02830     return;
02831 
02832   const QObjectList& objs = split->children();
02833   for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it )
02834   {
02835     if ( (*it)->inherits( "QtxWorkstackArea" ) )
02836       areaList.append( (QtxWorkstackArea*)*it );
02837     else if ( rec && (*it)->inherits( "QSplitter" ) )
02838       areas( (QSplitter*)*it, areaList, rec );
02839   }
02840 }
02841 
02846 QtxWorkstackArea* QtxWorkstack::activeArea() const
02847 {
02848   return myArea;
02849 }
02850 
02859 QtxWorkstackArea* QtxWorkstack::targetArea()
02860 {
02861   QtxWorkstackArea* area = activeArea();
02862   if ( !area )
02863     area = currentArea();
02864   if ( !area )
02865   {
02866     QList<QtxWorkstackArea*> lst;
02867     areas( mySplit, lst );
02868     if ( !lst.isEmpty() )
02869       area = lst.first();
02870   }
02871 
02872   if ( !area )
02873     area = createArea( mySplit );
02874 
02875   return area;
02876 }
02877 
02885 QtxWorkstackArea* QtxWorkstack::currentArea() const
02886 {
02887   QtxWorkstackArea* area = 0;
02888   QWidget* wid = focusWidget();
02889   while ( wid && !area )
02890   {
02891     if ( wid->inherits( "QtxWorkstackArea" ) )
02892       area = (QtxWorkstackArea*)wid;
02893     wid = wid->parentWidget();
02894   }
02895 
02896   return area;
02897 }
02898 
02904 QtxWorkstackArea* QtxWorkstack::createArea( QWidget* parent ) const
02905 {
02906   QtxWorkstackArea* area = new QtxWorkstackArea( parent );
02907 
02908   connect( area, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
02909   connect( area, SIGNAL( activated( QWidget* ) ), this, SLOT( onWindowActivated( QWidget* ) ) );
02910   connect( area, SIGNAL( contextMenuRequested( QWidget*, QPoint ) ),
02911            this, SLOT( onContextMenuRequested( QWidget*, QPoint ) ) );
02912   connect( area, SIGNAL( deactivated( QtxWorkstackArea* ) ), this, SLOT( onDeactivated( QtxWorkstackArea* ) ) );
02913 
02914   return area;
02915 }
02916 
02921 void QtxWorkstack::setActiveArea( QtxWorkstackArea* area )
02922 {
02923   QWidget* oldCur = myWin;
02924 
02925   QtxWorkstackArea* oldArea = myArea;
02926 
02927   myArea = area;
02928 
02929   if ( myArea != oldArea )
02930   {
02931     if ( oldArea )
02932       oldArea->updateActiveState();
02933     if ( myArea )
02934       myArea->updateActiveState();
02935   }
02936 
02937   if ( myArea )
02938     myWin = myArea->activeWidget();
02939 
02940   if ( myWin && oldCur != myWin )
02941     emit windowActivated( myWin );
02942 }
02943 
02949 QtxWorkstackArea* QtxWorkstack::neighbourArea( QtxWorkstackArea* area ) const
02950 {
02951   QList<QtxWorkstackArea*> lst;
02952   areas( mySplit, lst, true );
02953   int pos = lst.indexOf( area );
02954   if ( pos < 0 )
02955     return 0;
02956 
02957   QtxWorkstackArea* na = 0;
02958   for ( int i = pos - 1; i >= 0 && !na; i-- )
02959   {
02960     if ( !lst.at( i )->isEmpty() )
02961       na = lst.at( i );
02962   }
02963 
02964   for ( int j = pos + 1; j < (int)lst.count() && !na; j++ )
02965   {
02966     if ( !lst.at( j )->isEmpty() )
02967         na = lst.at( j );
02968   }
02969   return na;
02970 }
02971 
02977 QtxWorkstackArea* QtxWorkstack::areaAt( const QPoint& p ) const
02978 {
02979   QtxWorkstackArea* area = 0;
02980   QList<QtxWorkstackArea*> lst;
02981   areas( mySplit, lst, true );
02982   for ( QList<QtxWorkstackArea*>::iterator it = lst.begin(); it != lst.end() && !area; ++it )
02983   {
02984     QtxWorkstackArea* cur = *it;
02985     QRect r = cur->geometry();
02986     if ( cur->parentWidget() )
02987       r = QRect( cur->parentWidget()->mapToGlobal( r.topLeft() ), r.size() );
02988     if ( r.contains( p ) )
02989       area = cur;
02990   }
02991   return area;
02992 }
02993 
02997 void QtxWorkstack::updateState()
02998 {
02999   updateState( mySplit );
03000 }
03001 
03006 void QtxWorkstack::updateState( QSplitter* split )
03007 {
03008   QList<QSplitter*> recList;
03009   splitters( split, recList, false );
03010   for ( QList<QSplitter*>::iterator itr = recList.begin(); itr != recList.end(); ++itr )
03011     updateState( *itr );
03012 
03013   QList<QSplitter*> splitList;
03014   splitters( split, splitList, false );
03015 
03016   QList<QtxWorkstackArea*> areaList;
03017   areas( split, areaList, false );
03018 
03019   bool vis = false;
03020   for ( QList<QtxWorkstackArea*>::iterator it = areaList.begin(); it != areaList.end(); ++it )
03021   {
03022     if ( (*it)->isEmpty() )
03023       (*it)->hide();
03024     else
03025     {
03026       (*it)->show();
03027       vis = true;
03028     }
03029   }
03030 
03031   if ( split == mySplit )
03032     return;
03033 
03034   for ( QList<QSplitter*>::iterator iter = splitList.begin(); iter != splitList.end() && !vis; ++iter )
03035     vis = (*iter)->isVisibleTo( (*iter)->parentWidget() );
03036 
03037   if ( areaList.isEmpty() && splitList.isEmpty() )
03038     delete split;
03039   else
03040     split->setVisible( vis );
03041 }
03042 
03048 QByteArray QtxWorkstack::saveState( int version ) const
03049 {
03050   QByteArray data;
03051 
03052   QDataStream stream( &data, QIODevice::WriteOnly );
03053   stream << QtxWorkstack::VersionMarker;
03054   stream << version;
03055   saveState( stream );
03056 
03057   return data;
03058 }
03059 
03065 bool QtxWorkstack::restoreState( const QByteArray& state, int version )
03066 {
03067   if ( state.isEmpty() )
03068     return false;
03069 
03070   QByteArray sd = state;
03071   QDataStream stream( &sd, QIODevice::ReadOnly );
03072   int marker, ver;
03073   stream >> marker;
03074   stream >> ver;
03075   if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::VersionMarker || ver != version )
03076     return false;
03077 
03078   return restoreState( stream );
03079 }
03080 
03081 void QtxWorkstack::saveState( QDataStream& stream ) const
03082 {
03083   mySplit->saveState( stream );
03084 }
03085 
03086 bool QtxWorkstack::restoreState( QDataStream& stream )
03087 {
03088   QMap<QString, QtxWorkstackChild*> map;
03089   QList<QtxWorkstackArea*> areaList;
03090   areas( mySplit, areaList, true );
03091   for ( QList<QtxWorkstackArea*>::const_iterator it = areaList.begin(); it != areaList.end(); ++it )
03092   {
03093     QtxWorkstackArea* area = *it;
03094     QList<QtxWorkstackChild*> childList = area->childList();
03095     for ( QList<QtxWorkstackChild*>::iterator itr = childList.begin(); itr != childList.end(); ++itr )
03096     {
03097       QtxWorkstackChild* c = *itr;
03098       if ( !c->widget() )
03099         continue;
03100 
03101       map.insert( c->widget()->objectName(), c );
03102 
03103       qDebug( "QtxWorkstack::restoreState: found widget \"%s\"", (const char*)c->widget()->objectName().toLatin1() );
03104     }
03105   }
03106 
03107   int marker;
03108   stream >> marker;
03109   if ( stream.status() != QDataStream::Ok || marker != QtxWorkstack::SplitMarker )
03110     return false;
03111 
03112   QtxWorkstackSplitter* split = new QtxWorkstackSplitter( this );
03113   if ( layout() )
03114     layout()->addWidget( split );
03115 
03116   bool ok = split->restoreState( stream, map );
03117   if ( !ok )
03118     delete split;
03119   else
03120   {
03121     mySplit->deleteLater();
03122     mySplit = split;
03123 
03124     QList<QtxWorkstackArea*> aList;
03125     areas( mySplit, aList, true );
03126 
03127     QtxWorkstackArea* a = !aList.isEmpty() ? aList.first() : 0;
03128     for ( QMap<QString, QtxWorkstackChild*>::const_iterator it = map.begin(); it != map.end(); ++it )
03129     {
03130       QtxWorkstackChild* c = it.value();
03131       if ( c->widget() )
03132         c->widget()->setVisible( false );
03133       if ( a )
03134         a->insertChild( c );
03135       else
03136         c->setVisible( false );
03137     }
03138   }
03139 
03140   return ok;
03141 }
03142 
03147 void QtxWorkstack::setOpaqueResize( bool opaque )
03148 {
03149   QList<QSplitter*> splitList;
03150   splitters( mySplit, splitList, true );
03151   splitList << mySplit;
03152   foreach( QSplitter* split, splitList )
03153     split->setOpaqueResize( opaque );
03154 }
03155 
03160 bool QtxWorkstack::opaqueResize() const
03161 {
03162   return mySplit->opaqueResize();
03163 }
03164 
03165 
03177 QtxWorkstackArea* QtxWorkstack::wgArea( QWidget* wid ) const
03178 {
03179   QtxWorkstackArea* resArea = 0;
03180 
03181   QList<QtxWorkstackArea*> areaList;
03182   areas( mySplit, areaList, true );
03183 
03184   QList<QtxWorkstackArea*>::ConstIterator it;
03185   for ( it = areaList.begin(); it != areaList.end() && !resArea; ++it )
03186   {
03187     if ( (*it)->contains( wid ) )
03188       resArea = *it;
03189   }
03190 
03191   return resArea;
03192 }
03193 
03202 bool QtxWorkstack::move( QWidget* wid, QWidget* wid_to, const bool before )
03203 {
03204   if ( wid && wid_to )
03205   {
03206     QtxWorkstackArea* area_src = wgArea( wid );
03207     QtxWorkstackArea* area_to = wgArea( wid_to );
03208     if ( area_src && area_to )
03209     {
03210       // find index of the second widget
03211       QWidgetList wgList = area_to->widgetList();
03212       QWidgetList::ConstIterator it;
03213       int idx = 0;
03214       for ( it = wgList.begin(); it != wgList.begin(); ++it, idx++ )
03215       {
03216         if ( *it == wid_to )
03217           break;
03218       }
03219 
03220       if ( idx < wgList.count() ) // paranoidal check
03221       {
03222         if ( !before )
03223           idx++;
03224         area_src->removeWidget( wid, true );
03225         area_to->insertWidget( wid, idx );
03226         return true;
03227       }
03228     }
03229   }
03230   return false;
03231 }
03232 
03237 void QtxWorkstack::stack()
03238 {
03239   QWidgetList wgList = windowList();
03240   if ( !wgList.count() )
03241     return; // nothing to do
03242 
03243   QtxWorkstackArea* area_to = 0;
03244   QWidgetList::ConstIterator it;
03245   for ( it = wgList.begin(); it != wgList.end(); ++it )
03246   {
03247     QtxWorkstackArea* area_src = 0;
03248     if ( !area_to )
03249     {
03250       area_to = wgArea( *it );
03251       area_src = area_to;
03252     }
03253     else
03254       area_src = wgArea( *it );
03255 
03256     if ( area_src != area_to )
03257     {
03258       area_src->removeWidget( *it, true );
03259       area_to->insertWidget( *it, -1 );
03260       (*it)->showMaximized();
03261     }
03262   }
03263 }
03264 
03265 QAction* QtxWorkstack::action( const int id ) const
03266 {
03267   return myActionsMap.contains( id ) ? myActionsMap[id] : 0;
03268 }