Salome HOME
Porting to Mandrake 10.1 and new products:
[modules/kernel.git] / src / PatchQt / qsplitterP.cxx
1 /////////////////////////////////////////////////////////////////////////////
2 // Module      : PatchQt
3 // File        : qsplitterP.cxx
4 // Description : the patch for Qt's QSplitter class (qsplitter.cpp)
5 /////////////////////////////////////////////////////////////////////////////
6
7 /****************************************************************************
8 ** $Id$
9 **
10 **  Splitter widget
11 **
12 **  Created:  980105
13 **
14 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
15 **
16 ** This file is part of the widgets module of the Qt GUI Toolkit.
17 **
18 ** This file may be distributed under the terms of the Q Public License
19 ** as defined by Trolltech AS of Norway and appearing in the file
20 ** LICENSE.QPL included in the packaging of this file.
21 **
22 ** This file may be distributed and/or modified under the terms of the
23 ** GNU General Public License version 2 as published by the Free Software
24 ** Foundation and appearing in the file LICENSE.GPL included in the
25 ** packaging of this file.
26 **
27 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
28 ** licenses may use this file in accordance with the Qt Commercial License
29 ** Agreement provided with the Software.
30 **
31 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
32 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
33 **
34 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
35 **   information about Qt Commercial License Agreements.
36 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
37 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
38 **
39 ** Contact info@trolltech.com if any conditions of this licensing are
40 ** not clear to you.
41 **
42 **********************************************************************/
43
44 #include "qsplitterP.h"
45 #ifndef QT_NO_COMPLEXWIDGETS
46
47 #include <qglobal.h>
48 #include <qpainter.h>
49 #include <qdrawutil.h>
50 #include <qbitmap.h>
51 #include <qlayout.h>
52 #include <private/qlayoutengine_p.h>
53 #if QT_VERSION < 300
54   #include <qlist.h>
55   #include <qarray.h>
56 #else
57   #include <qptrlist.h>  //qt3.x
58   #include <qmemarray.h> //qt3.x
59   #include <qstyle.h> //qt3.x
60 #endif
61
62 #include <qobjectlist.h>
63 #include <qapplication.h> //sendPostedEvents
64 using namespace std;
65
66 #define SPLITTER_ICON_WIDTH 10
67 #define SPLITTER_ICON_HEIGHT 12
68
69 static int mouseOffset;
70 static int opaqueOldPos = -1; //### there's only one mouse, but this is a bit risky
71
72 static const char* splitter_left_xpm[] = {
73   "5 5 2 1 0 0",
74   "     s none          m none  c none",
75   ".    s iconColor1    m black c black",
76   "   ..",
77   " ....",
78   ".....",
79   " ....",
80   "   .."
81 };
82
83 static const char* splitter_right_xpm[] = {
84   "5 5 2 1 0 0",
85   "     s iconColor1    m black c black",
86   ".    s none          m none  c none",
87   "  ...",
88   "    .",
89   "     ",
90   "    .",
91   "  ..."
92 };
93
94 static const char* splitter_up_xpm[] = {
95   "5 5 2 1 0 0",
96   "     s none          m none  c none",
97   ".    s iconColor1    m black c black",
98   "  .  ",
99   " ... ",
100   " ... ",
101   ".....",
102   "....."
103 };
104
105 static const char* splitter_down_xpm[] = {
106   "5 5 2 1 0 0",
107   "     s iconColor1    m black c black",
108   ".    s none          m none  c none",
109   "     ",
110   "     ",
111   ".   .",
112   ".   .",
113   ".. .."
114 };
115
116 QSplitterPHandle::QSplitterPHandle( Qt::Orientation o,
117                                   QSplitterP *parent, const char * name )
118     : QWidget( parent, name )
119 {
120   s = parent;
121   
122   left  = new QPushButton(this);
123   right = new QPushButton(this);
124   unleft  = new QPushButton(this);
125   unright = new QPushButton(this);
126   
127   setOrientation(o);
128   
129   left->setAutoDefault(false); unleft->setAutoDefault(false);   
130   right->setAutoDefault(false); unright->setAutoDefault(false);
131   left->setFlat(true); right->setFlat(true); unleft->setFlat(true); unright->setFlat(true);
132   left->setCursor( arrowCursor );       right->setCursor( arrowCursor );
133   unleft->setCursor( arrowCursor ); unright->setCursor( arrowCursor );
134
135   connect(left,    SIGNAL(clicked()), this, SLOT(onBeforeCompress()));
136   connect(right,   SIGNAL(clicked()), this, SLOT(onAfterCompress()));
137   connect(unleft,  SIGNAL(clicked()), this, SLOT(onBeforeUnCompress()));
138   connect(unright, SIGNAL(clicked()), this, SLOT(onAfterUnCompress()));
139 }
140
141 void QSplitterPHandle::onBeforeCompress() {
142   oldpos = s->pick(pos());
143   int pos = s->pick(s->widgetBefore(id())->pos());
144   s->compress(s->widgetBefore(id()));
145   s->moveSplitter(pos, id());
146   s->updateSplitterHandles();
147 }
148
149 void QSplitterPHandle::onBeforeUnCompress() {
150   s->unCompress(s->widgetBefore(id()));
151   s->moveSplitter(oldpos, id());
152   s->updateSplitterHandles();
153 }
154
155 void QSplitterPHandle::onAfterCompress() {
156   oldpos = s->pick(pos());
157   int pos = s->pick(s->widgetAfter(id())->pos()) + s->pick(s->widgetAfter(id())->size()) - s->pick(size());
158   s->compress(s->widgetAfter(id()));
159   s->moveSplitter(pos, id());
160   s->updateSplitterHandles();
161 }
162
163 void QSplitterPHandle::onAfterUnCompress() {
164   s->unCompress(s->widgetAfter(id()));
165   s->moveSplitter(oldpos, id());
166   s->updateSplitterHandles();
167 }
168
169 // VSR 21/11/02 -> ================================
170 void QSplitterPHandle::compressAfter() 
171 {
172   onAfterCompress();
173 }
174
175 void QSplitterPHandle::unCompressAfter() 
176 {
177   onAfterUnCompress();
178 }
179
180 void QSplitterPHandle::compressBefore() 
181 {
182   onBeforeCompress();
183 }
184
185 void QSplitterPHandle::unCompressBefore() 
186 {
187   onBeforeUnCompress();
188 }
189 // VSR 21/11/02 <- ================================
190
191 QSizePolicy QSplitterPHandle::sizePolicy() const
192 {
193     //### removeme 3.0
194     return QWidget::sizePolicy();
195 }
196
197 QSize QSplitterPHandle::sizeHint() const
198 {
199 #if QT_VERSION < 300
200   int sw = style().splitterWidth();
201   return QSize(sw,sw).expandedTo( QApplication::globalStrut() );
202 #else
203   int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this);
204   return (style().sizeFromContents(QStyle::CT_Splitter, s, QSize(sw, sw)).
205           expandedTo(QApplication::globalStrut()));
206 #endif
207 }
208
209 void QSplitterPHandle::setOrientation( Qt::Orientation o )
210 {
211     orient = o;
212 #ifndef QT_NO_CURSOR
213     if ( o == QSplitterP::Horizontal )
214         setCursor( splitHCursor );
215     else
216         setCursor( splitVCursor );
217 #endif
218
219         QPixmap lp, rp;
220         if ( orient == QSplitterP::Horizontal )
221         {
222                 lp = QPixmap(splitter_left_xpm);
223                 rp = QPixmap(splitter_right_xpm);
224         }
225         else
226         {
227                 lp = QPixmap(splitter_up_xpm);
228                 rp = QPixmap(splitter_down_xpm);
229         }
230         left->setPixmap(lp);
231         right->setPixmap(rp);
232         unleft->setPixmap(rp);
233         unright->setPixmap(lp);
234 }
235
236 void QSplitterPHandle::mouseMoveEvent( QMouseEvent *e )
237 {
238     if ( !(e->state()&LeftButton) )
239         return;
240     QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()))
241                  - mouseOffset;
242     if ( opaque() ) {
243         s->moveSplitter( pos, id() );
244     } else {
245         int min = pos; int max = pos;
246         s->getRange( id(), &min, &max );
247         s->setRubberband( QMAX( min, QMIN(max, pos )));
248     }
249 }
250
251 void QSplitterPHandle::mousePressEvent( QMouseEvent *e )
252 {
253     if ( e->button() == LeftButton )
254         mouseOffset = s->pick(e->pos());
255 }
256
257 void QSplitterPHandle::mouseReleaseEvent( QMouseEvent *e )
258 {
259     if ( !opaque() && e->button() == LeftButton ) {
260         QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos()));
261         s->setRubberband( -1 );
262         s->moveSplitter( pos, id() );
263     }
264 }
265
266 void QSplitterPHandle::paintEvent( QPaintEvent * )
267 {
268         updateButtonState();
269     QPainter p( this );
270     s->drawSplitter( &p, 0, 0, width(), height() );
271 }
272
273 void QSplitterPHandle::updateButtonState() {
274         if (!s->isCompressEnabled()) {
275                 left->hide();
276                 right->hide();
277                 unleft->hide();
278                 unright->hide();
279         }
280         else {
281                 if ( orient == QSplitterP::Horizontal )
282                 {
283                         left->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, 0 ),
284                                                                           QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
285                         right->setGeometry( QRect( QPoint( (width() - SPLITTER_ICON_WIDTH)/2, SPLITTER_ICON_HEIGHT ),
286                                                            QSize ( SPLITTER_ICON_WIDTH, SPLITTER_ICON_HEIGHT ) ) );
287                         unleft->setGeometry( left->geometry() );
288                         unright->setGeometry( right->geometry() );
289                 }
290                 else
291                 {
292                         left->setGeometry( QRect( QPoint( 0, (height() - SPLITTER_ICON_WIDTH)/2 ),
293                                                                           QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
294                         right->setGeometry( QRect( QPoint( SPLITTER_ICON_HEIGHT, (height() - SPLITTER_ICON_WIDTH)/2),
295                                                                            QSize ( SPLITTER_ICON_HEIGHT, SPLITTER_ICON_WIDTH ) ) );
296                         unleft->setGeometry( left->geometry() );
297                         unright->setGeometry( right->geometry() );
298                 }
299                 if ( s->isCompressed( s->widgetBefore( id() ) ) ) {
300                         left->hide();
301                         unleft->show();
302                         right->setEnabled(false);
303                 }
304                 else {
305                         unleft->hide();
306                         left->show();
307                         right->setEnabled(true);
308                 }
309                 if ( s->isCompressed( s->widgetAfter( id() ) ) ) {
310                         right->hide();
311                         unright->show();
312                         left->setEnabled(false);
313                 }
314                 else {
315                         unright->hide();
316                         right->show();
317                         left->setEnabled(true);
318                 }
319         }
320 }
321
322 class QSplitterPLayoutStruct
323 {
324 public:
325     QSplitterP::ResizeMode mode;
326     QCOORD sizer;
327     bool isSplitter;
328     QWidget *wid;
329 };
330
331 class QSplitterPData
332 {
333 public:
334     QSplitterPData() : opaque( FALSE ), firstShow( TRUE ) {}
335
336     QList<QSplitterPLayoutStruct> list;
337     bool opaque;
338     bool firstShow;
339 };
340
341
342 // NOT REVISED
343 /*!
344   \class QSplitter qsplitter.h
345   \brief The QSplitter class implements a splitter widget.
346
347   \ingroup organizers
348
349   A splitter lets the user control the size of child widgets by
350   dragging the boundary between the children. Any number of widgets
351   may be controlled.
352
353   To show a QListBox, a QListView and a QMultiLineEdit side by side:
354
355   \code
356     QSplitter *split = new QSplitter( parent );
357     QListBox *lb = new QListBox( split );
358     QListView *lv = new QListView( split );
359     QMultiLineEdit *ed = new QMultiLineEdit( split );
360   \endcode
361
362   In QSplitter the boundary can be either horizontal or vertical.  The
363   default is horizontal (the children are side by side) and you
364   can use setOrientation( QSplitter::Vertical ) to set it to vertical.
365
366   By default, all widgets can be as large or as small as the user
367   wishes, down to \link QWidget::minimumSizeHint() minimumSizeHint()\endlink.
368   You can naturally use setMinimumSize() and/or
369   setMaximumSize() on the children. Use setResizeMode() to specify that
370   a widget should keep its size when the splitter is resized.
371
372   QSplitter normally resizes the children only at the end of a
373   resize operation, but if you call setOpaqueResize( TRUE ), the
374   widgets are resized as often as possible.
375
376   The initial distribution of size between the widgets is determined
377   by the initial size of each widget. You can also use setSizes() to
378   set the sizes of all the widgets. The function sizes() returns the
379   sizes set by the user.
380
381   If you hide() a child, its space will be distributed among the other
382   children. When you show() it again, it will be reinstated.
383
384   <img src=qsplitter-m.png> <img src=qsplitter-w.png>
385
386   \sa QTabBar
387 */
388
389
390
391 QSize QSplitterP::minSize( const QWidget *w ) const
392 {
393  if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
394  QSize min = w->minimumSize();
395  QSize s;
396  if ( min.height() <= 0 || min.width() <= 0 )
397     s = w->minimumSizeHint();
398  if ( min.height() > 0 )
399     s.setHeight( min.height() );
400  if ( min.width() > 0 )
401     s.setWidth( min.width() );
402  return s.expandedTo(QSize(0,0));
403 }
404
405 QSize QSplitterP::maxSize( const QWidget* w ) const
406 {
407   if ( isCompressed(w) && (data->list.count() > 1 ) ) return QSize(0,0);
408   else return w->maximumSize();
409 }
410
411 /*!
412   Constructs a horizontal splitter.
413 */
414
415 QSplitterP::QSplitterP( QWidget *parent, const char *name )
416      :QFrame(parent,name,WPaintUnclipped)
417 {
418   orient = Horizontal;
419   init();
420 }
421
422
423 /*!
424   Constructs splitter with orientation \a o.
425 */
426
427 QSplitterP::QSplitterP( Orientation o, QWidget *parent, const char *name )
428     :QFrame(parent,name,WPaintUnclipped)
429 {
430   orient = o;
431   init();
432 }
433
434
435 /*!
436   Destructs the splitter.
437 */
438
439 QSplitterP::~QSplitterP()
440 {
441     data->list.setAutoDelete( TRUE );
442     delete data;
443 }
444
445
446 void QSplitterP::init()
447 {
448     data = new QSplitterPData;
449     if ( orient == Horizontal )
450         setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Minimum) );
451     else
452         setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed) );
453         compressed_widgets.clear();
454         compress_flag = false;
455 }
456
457
458 /*!
459   \fn void QSplitter::refresh()
460
461   Updates the splitter state. You should not need to call this
462   function during normal use of the splitter.
463 */
464
465
466 /*!  Sets the orientation to \a o.  By default the orientation is
467   horizontal (the widgets are side by side).
468
469   \sa orientation()
470 */
471
472 void QSplitterP::setOrientation( Orientation o )
473 {
474     if ( orient == o )
475         return;
476     orient = o;
477
478     if ( orient == Horizontal )
479         setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
480     else
481         setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
482
483     QSplitterPLayoutStruct *s = data->list.first();
484     while ( s ) {
485         if ( s->isSplitter )
486             ((QSplitterPHandle*)s->wid)->setOrientation( o );
487         s = data->list.next();  // ### next at end of loop, no iterator
488     }
489     recalc( isVisible() );
490 }
491
492
493 /*!
494    \fn Orientation QSplitter::orientation() const
495
496    Returns the orientation (\c Horizontal or \c Vertical) of the splitter.
497    \sa setOrientation()
498 */
499
500 /*!
501   \reimp
502 */
503 void QSplitterP::resizeEvent( QResizeEvent * )
504 {
505     doResize();
506 }
507
508
509 /*!
510   Inserts the widget \a w at the end, or at the beginning if \a first is TRUE
511
512   It is the responsibility of the caller of this function to make sure
513   that \a w is not already in the splitter, and to call recalcId if
514   needed.  (If \a first is TRUE, then recalcId is very probably
515   needed.)
516 */
517
518 QSplitterPLayoutStruct *QSplitterP::addWidget( QWidget *w, bool first )
519 {
520     QSplitterPLayoutStruct *s;
521     QSplitterPHandle *newHandle = 0;
522     if ( data->list.count() > 0 ) {
523         s = new QSplitterPLayoutStruct;
524         s->mode = KeepSize;
525         newHandle = new QSplitterPHandle( orientation(), this );
526         s->wid = newHandle;
527         newHandle->setId(data->list.count());
528         s->isSplitter = TRUE;
529         s->sizer = pick( newHandle->sizeHint() );
530         if ( first )
531             data->list.insert( 0, s );
532         else
533             data->list.append( s );
534     }
535     s = new QSplitterPLayoutStruct;
536     s->mode = Stretch;
537     s->wid = w;
538     if ( !testWState( WState_Resized ) && w->sizeHint().isValid() )
539         s->sizer = pick( w->sizeHint() );
540     else
541         s->sizer = pick( w->size() );
542     s->isSplitter = FALSE;
543     if ( first )
544         data->list.insert( 0, s );
545     else
546         data->list.append( s );
547     if ( newHandle && isVisible() )
548         newHandle->show(); //will trigger sending of post events
549     return s;
550 }
551
552
553 /*!
554   Tells the splitter that a child widget has been inserted/removed.
555 */
556
557 void QSplitterP::childEvent( QChildEvent *c )
558 {
559     if ( c->type() == QEvent::ChildInserted ) {
560         if ( !c->child()->isWidgetType() )
561             return;
562
563         if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
564             return;
565
566         QSplitterPLayoutStruct *s = data->list.first();
567         while ( s ) {
568             if ( s->wid == c->child() )
569                 return;
570             s = data->list.next();
571         }
572         addWidget( (QWidget*)c->child() );
573         recalc( isVisible() );
574
575     } else if ( c->type() == QEvent::ChildRemoved ) {
576         QSplitterPLayoutStruct *p = 0;
577         if ( data->list.count() > 1 )
578             p = data->list.at(1); //remove handle _after_ first widget.
579         QSplitterPLayoutStruct *s = data->list.first();
580         while ( s ) {
581             if ( s->wid == c->child() ) {
582                 data->list.removeRef( s );
583                 delete s;
584                 if ( p && p->isSplitter ) {
585                     data->list.removeRef( p );
586                     delete p->wid; //will call childEvent
587                     delete p;
588                 }
589                 recalcId();
590                 doResize();
591                 return;
592             }
593             p = s;
594             s = data->list.next();
595         }
596     }
597 }
598
599
600 /*!
601   Shows a rubber band at position \a p. If \a p is negative, the
602   rubber band is removed.
603 */
604
605 void QSplitterP::setRubberband( int p )
606 {
607     QPainter paint( this );
608     paint.setPen( gray );
609     paint.setBrush( gray );
610     paint.setRasterOp( XorROP );
611     QRect r = contentsRect();
612     const int rBord = 3; //Themable????
613 #if QT_VERSION < 300
614     const int sw = style().splitterWidth();
615 #else
616     int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
617 #endif
618     if ( orient == Horizontal ) {
619         if ( opaqueOldPos >= 0 )
620             paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(),
621                             2*rBord, r.height() );
622         if ( p >= 0 )
623             paint.drawRect( p  + sw/2 - rBord, r.y(), 2*rBord, r.height() );
624     } else {
625         if ( opaqueOldPos >= 0 )
626             paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord,
627                             r.width(), 2*rBord );
628         if ( p >= 0 )
629             paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord );
630     }
631     opaqueOldPos = p;
632 }
633
634
635 /*! \reimp */
636
637 bool QSplitterP::event( QEvent *e )
638 {
639     if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) {
640         recalc( isVisible() );
641         if ( e->type() == QEvent::Show )
642             data->firstShow = FALSE;
643     }
644     return QWidget::event( e );
645 }
646
647
648 /*!
649   Draws the splitter handle in the rectangle described by \a x, \a y,
650   \a w, \a h using painter \a p.
651   \sa QStyle::drawSplitter
652 */
653
654 void QSplitterP::drawSplitter( QPainter *p,
655                               QCOORD x, QCOORD y, QCOORD w, QCOORD h )
656 {
657 #if QT_VERSION < 300
658     style().drawSplitter( p, x, y, w, h, colorGroup(), orient );
659 #else
660     style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(),
661                           (orientation() == Qt::Horizontal ?
662                            QStyle::Style_Horizontal : 0));
663 #endif
664 }
665
666
667 /*!
668   Returns the id of the splitter to the right of or below the widget \a w,
669   or 0 if there is no such splitter.
670   (ie. it is either not in this QSplitter, or it is at the end).
671 */
672
673 int QSplitterP::idAfter( QWidget* w ) const
674 {
675     QSplitterPLayoutStruct *s = data->list.first();
676     bool seen_w = FALSE;
677     while ( s ) {
678         if ( s->isSplitter && seen_w )
679             return data->list.at();
680         if ( !s->isSplitter && s->wid == w )
681             seen_w = TRUE;
682         s = data->list.next();
683     }
684     return 0;
685 }
686
687 // VSR 21/11/02 -> ================================
688 QSplitterPHandle* QSplitterP::getHandleAfter(QWidget* w)
689 {
690   QSplitterPLayoutStruct *s = data->list.first();
691   bool seen_w = FALSE;
692   while ( s ) {
693     if ( s->isSplitter && seen_w )
694       return (QSplitterPHandle*)s->wid;
695     if ( !s->isSplitter && s->wid == w )
696       seen_w = TRUE;
697     s = data->list.next();
698   }
699   return 0;
700 }
701
702 QSplitterPHandle* QSplitterP::getHandleBefore(QWidget* w)
703 {
704   QSplitterPLayoutStruct *s = data->list.first();
705   QSplitterPHandle* h = 0;
706   while ( s ) {
707     if ( s->isSplitter )
708       h = (QSplitterPHandle*)s;
709     if ( !s->isSplitter && s->wid == w )
710       return h;
711     s = data->list.next();
712   }
713   return 0;
714 }
715 // VSR 21/11/02 <- ================================
716
717 QWidget* QSplitterP::widgetBefore( int id ) const
718 {
719     QSplitterPLayoutStruct *s = data->list.first();
720         QWidget* w;
721     while ( s ) {
722                 if ( !s->isSplitter ) {
723                         w = s->wid;
724                         if (idAfter(w) == id) return w;
725                 }
726                 s = data->list.next();
727     }
728     return 0;
729 }
730
731 QWidget* QSplitterP::widgetAfter( int id ) const
732 {
733     QSplitterPLayoutStruct *s = data->list.first();
734         bool seen_s = FALSE;
735     while ( s ) {
736         if ( !s->isSplitter && seen_s )
737             return s->wid;
738         if ( s->isSplitter && data->list.at() == id )
739             seen_s = TRUE;
740         s = data->list.next();
741     }
742     return 0;
743 }
744
745 void QSplitterP::unCompress(QWidget* w) {
746    compressed_widgets.remove(w);
747 }
748
749 void QSplitterP::compress(QWidget* w)
750 {
751   if (!isCompressed(w)) compressed_widgets.append(w);
752 }
753
754 bool QSplitterP::isCompressed(const QWidget* w) const {
755   QWidget* t = (QWidget*)w;
756   if (compressed_widgets.containsRef(t)==0) return false;
757   else return true;
758 }
759
760 /*!
761   Moves the left/top edge of the splitter handle with id \a id as
762   close as possible to \a p which is the distance from the left (or
763   top) edge of the widget.
764
765   \sa idAfter()
766 */
767 void QSplitterP::moveSplitter( QCOORD p, int id )
768 {
769     p = adjustPos( p, id );
770
771     QSplitterPLayoutStruct *s = data->list.at(id);
772     int oldP = orient == Horizontal? s->wid->x() : s->wid->y();
773     bool upLeft = p < oldP;
774
775     moveAfter( p, id, upLeft );
776     moveBefore( p-1, id-1, upLeft );
777
778     storeSizes();
779 }
780
781
782 void QSplitterP::setG( QWidget *w, int p, int s )
783 {
784     if ( orient == Horizontal )
785         w->setGeometry( p, contentsRect().y(), s, contentsRect().height() );
786     else
787         w->setGeometry( contentsRect().x(), p, contentsRect().width(), s );
788 }
789
790
791 /*!
792   Places the right/bottom edge of the widget at \a id at position \a pos.
793
794   \sa idAfter()
795 */
796
797 void QSplitterP::moveBefore( int pos, int id, bool upLeft )
798 {
799     QSplitterPLayoutStruct *s = data->list.at(id);
800     if ( !s )
801         return;
802     QWidget *w = s->wid;
803     if ( w->isHidden() ) {
804         moveBefore( pos, id-1, upLeft );
805     } else if ( s->isSplitter ) {
806         int dd = s->sizer;
807         if ( upLeft ) {
808             setG( w, pos-dd+1, dd );
809             moveBefore( pos-dd, id-1, upLeft );
810         } else {
811             moveBefore( pos-dd, id-1, upLeft );
812             setG( w, pos-dd+1, dd );
813         }
814     } else {
815         int left = pick( w->pos() );
816         int dd = pos - left + 1;
817         dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
818         int newLeft = pos-dd+1;
819         setG( w, newLeft, dd );
820         if ( left != newLeft )
821             moveBefore( newLeft-1, id-1, upLeft );
822     }
823 }
824
825
826 /*!
827   Places the left/top edge of the widget at \a id at position \a pos.
828
829   \sa idAfter()
830 */
831
832 void QSplitterP::moveAfter( int pos, int id, bool upLeft )
833 {
834     QSplitterPLayoutStruct *s = id < int(data->list.count()) ?
835                                data->list.at(id) : 0;
836     if ( !s )
837         return;
838     QWidget *w = s->wid;
839     if ( w->isHidden() ) {
840         moveAfter( pos, id+1, upLeft );
841     } else if ( pick( w->pos() ) == pos ) {
842         //No need to do anything if it's already there.
843         return;
844     } else if ( s->isSplitter ) {
845         int dd = s->sizer;
846         if ( upLeft ) {
847             setG( w, pos, dd );
848             moveAfter( pos+dd, id+1, upLeft );
849         } else {
850             moveAfter( pos+dd, id+1, upLeft );
851             setG( w, pos, dd );
852         }
853     } else {
854         int right = pick( w->geometry().bottomRight() );
855         int ddd = pick( QSize(contentsRect().width(), contentsRect().height() ) ) - pos;
856         int dd = QMIN(right - pos + 1, ddd);
857         dd = QMAX( pick(minSize(w)), QMIN(dd, pick(maxSize(w))));
858         int newRight = pos+dd-1;
859         setG( w, pos, dd );
860         moveAfter( newRight+1, id+1, upLeft );
861     }
862 }
863
864
865 /*!
866   Returns the valid range of the splitter with id \a id in \a min and \a max.
867
868   \sa idAfter()
869 */
870
871 void QSplitterP::getRange( int id, int *min, int *max )
872 {
873     int minB = 0;       //before
874     int maxB = 0;
875     int minA = 0;
876     int maxA = 0;       //after
877     int n = data->list.count();
878     if ( id < 0 || id >= n )
879         return;
880     int i;
881     for ( i = 0; i < id; i++ ) {
882         QSplitterPLayoutStruct *s = data->list.at(i);
883         if ( s->isSplitter ) {
884             minB += s->sizer;
885             maxB += s->sizer;
886         } else {
887             minB += pick( minSize(s->wid) );
888             maxB += pick( maxSize(s->wid) );
889         }
890     }
891     for ( i = id; i < n; i++ ) {
892         QSplitterPLayoutStruct *s = data->list.at(i);
893         if ( s->isSplitter ) {
894             minA += s->sizer;
895             maxA += s->sizer;
896         } else {
897             minA += pick( minSize(s->wid) );
898             maxA += pick( maxSize(s->wid) );
899         }
900     }
901     QRect r = contentsRect();
902     if ( min )
903         *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA );
904     if ( max )
905         *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA );
906
907 }
908
909
910 /*!
911   Returns the legal position closest to \a p of the splitter with id \a id.
912
913   \sa idAfter()
914 */
915
916 int QSplitterP::adjustPos( int p, int id )
917 {
918     int min = 0;
919     int max = 0;
920     getRange( id, &min, &max );
921     p = QMAX( min, QMIN( p, max ) );
922
923     return p;
924 }
925
926
927 void QSplitterP::doResize()
928 {
929     QRect r = contentsRect();
930     int i;
931     int n = data->list.count();
932     QArray<QLayoutStruct> a( n );
933     for ( i = 0; i< n; i++ ) {
934         a[i].init();
935         QSplitterPLayoutStruct *s = data->list.at(i);
936         if ( s->wid->isHidden() ) {
937             a[i].stretch = 0;
938             a[i].sizeHint = a[i].minimumSize = 0;
939             a[i].maximumSize = 0;
940         } else if ( s->isSplitter ) {
941             a[i].stretch = 0;
942             a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer;
943             a[i].empty = FALSE;
944         } else if ( s->mode == KeepSize ) {
945             a[i].stretch = 0;
946             a[i].minimumSize = pick( minSize(s->wid) );
947             a[i].sizeHint = s->sizer;
948             a[i].maximumSize = pick( maxSize(s->wid) );
949             a[i].empty = FALSE;
950         } else if ( s->mode == FollowSizeHint ) {
951             a[i].stretch = 0;
952             a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() );
953             a[i].maximumSize = pick( maxSize(s->wid) );
954             a[i].empty = FALSE;
955         } else { //proportional
956             a[i].stretch = s->sizer;
957             a[i].maximumSize = pick( maxSize(s->wid) );
958             a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) );
959             a[i].empty = FALSE;
960         }
961     }
962
963     qGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 );
964     for ( i = 0; i< n; i++ ) {
965         QSplitterPLayoutStruct *s = data->list.at(i);
966         if ( orient == Horizontal )
967             s->wid->setGeometry( a[i].pos, r.top(), a[i].size, r.height() );
968         else
969             s->wid->setGeometry( r.left(), a[i].pos, r.width(), a[i].size );
970     }
971
972 }
973
974
975 void QSplitterP::recalc( bool update )
976 {
977     int fi = 2*frameWidth();
978     int maxl = fi;
979     int minl = fi;
980     int maxt = QWIDGETSIZE_MAX;
981     int mint = fi;
982     int n = data->list.count();
983     bool first = TRUE;
984     /*
985       The splitter before a hidden widget is always hidden.
986       The splitter before the first visible widget is hidden.
987       The splitter before any other visible widget is visible.
988     */
989     for ( int i = 0; i< n; i++ ) {
990         QSplitterPLayoutStruct *s = data->list.at(i);
991         if ( !s->isSplitter ) {
992             QSplitterPLayoutStruct *p = (i > 0) ? p = data->list.at( i-1 ) : 0;
993             if ( p && p->isSplitter )
994                 if ( first || s->wid->isHidden() )
995                     p->wid->hide(); //may trigger new recalc
996                 else
997                     p->wid->show(); //may trigger new recalc
998             if ( !s->wid->isHidden() )
999                 first = FALSE;
1000         }
1001     }
1002
1003     bool empty=TRUE;
1004     for ( int j = 0; j< n; j++ ) {
1005         QSplitterPLayoutStruct *s = data->list.at(j);
1006         if ( !s->wid->isHidden() ) {
1007             empty = FALSE;
1008             if ( s->isSplitter ) {
1009                 minl += s->sizer;
1010                 maxl += s->sizer;
1011             } else {
1012                 QSize minS = minSize(s->wid);
1013                 minl += pick( minS );
1014                 maxl += pick( maxSize(s->wid) );
1015                 mint = QMAX( mint, trans( minS ));
1016                 int tm = trans( maxSize(s->wid) );
1017                 if ( tm > 0 )
1018                     maxt = QMIN( maxt, tm );
1019             }
1020         }
1021     }
1022     if ( empty )
1023         maxl = maxt = 0;
1024     else
1025         maxl = QMIN( maxl, QWIDGETSIZE_MAX );
1026     if ( maxt < mint )
1027         maxt = mint;
1028
1029     if ( orient == Horizontal ) {
1030         setMaximumSize( maxl, maxt );
1031         setMinimumSize( minl, mint );
1032     } else {
1033         setMaximumSize( maxt, maxl );
1034         setMinimumSize( mint, minl );
1035     }
1036     if ( update )
1037         doResize();
1038 }
1039
1040 /*! \enum QSplitter::ResizeMode
1041
1042   This enum type describes how QSplitter will resize each of its child widgets.  The currently defined values are: <ul>
1043
1044   <li> \c Stretch - the widget will be resized when the splitter
1045   itself is resized.
1046
1047   <li> \c KeepSize - QSplitter will try to keep this widget's size
1048   unchanged.
1049
1050   <li> \c FollowSizeHint - QSplitter will resize the widget when its
1051   size hint changes.
1052
1053   </ul>
1054
1055 */
1056
1057 /*!
1058   Sets resize mode of \a w to \a mode.
1059
1060   \sa ResizeMode
1061 */
1062
1063 void QSplitterP::setResizeMode( QWidget *w, ResizeMode mode )
1064 {
1065     processChildEvents();
1066     QSplitterPLayoutStruct *s = data->list.first();
1067     while ( s ) {
1068         if ( s->wid == w  ) {
1069             s->mode = mode;
1070             return;
1071         }
1072         s = data->list.next();
1073     }
1074     s = addWidget( w, TRUE );
1075     s->mode = mode;
1076 }
1077
1078
1079 /*!
1080   Returns TRUE if opaque resize is on, FALSE otherwise.
1081
1082   \sa setOpaqueResize()
1083 */
1084
1085 bool QSplitterP::opaqueResize() const
1086 {
1087     return data->opaque;
1088 }
1089
1090
1091 /*!
1092   Sets opaque resize to \a on. Opaque resize is initially turned off.
1093
1094   \sa opaqueResize()
1095 */
1096
1097 void QSplitterP::setOpaqueResize( bool on )
1098 {
1099     data->opaque = on;
1100 }
1101
1102
1103 /*!
1104   Moves \a w to the leftmost/top position.
1105 */
1106
1107 void QSplitterP::moveToFirst( QWidget *w )
1108 {
1109     processChildEvents();
1110     bool found = FALSE;
1111     QSplitterPLayoutStruct *s = data->list.first();
1112     while ( s ) {
1113         if ( s->wid == w  ) {
1114             found = TRUE;
1115             QSplitterPLayoutStruct *p = data->list.prev();
1116             if ( p ) { // not already at first place
1117                 data->list.take(); //take p
1118                 data->list.take(); // take s
1119                 data->list.insert( 0, p );
1120                 data->list.insert( 0, s );
1121             }
1122             break;
1123         }
1124         s = data->list.next();
1125     }
1126      if ( !found )
1127         addWidget( w, TRUE );
1128      recalcId();
1129 }
1130
1131
1132 /*!
1133   Moves \a w to the rightmost/bottom position.
1134 */
1135
1136 void QSplitterP::moveToLast( QWidget *w )
1137 {
1138     processChildEvents();
1139     bool found = FALSE;
1140     QSplitterPLayoutStruct *s = data->list.first();
1141     while ( s ) {
1142         if ( s->wid == w  ) {
1143             found = TRUE;
1144             data->list.take(); // take s
1145             QSplitterPLayoutStruct *p = data->list.current();
1146             if ( p ) { // the splitter handle after s
1147                 data->list.take(); //take p
1148                 data->list.append( p );
1149             }
1150             data->list.append( s );
1151             break;
1152         }
1153         s = data->list.next();
1154     }
1155      if ( !found )
1156         addWidget( w);
1157      recalcId();
1158 }
1159
1160
1161 void QSplitterP::recalcId()
1162 {
1163     int n = data->list.count();
1164     for ( int i = 0; i < n; i++ ) {
1165         QSplitterPLayoutStruct *s = data->list.at(i);
1166         if ( s->isSplitter )
1167             ((QSplitterPHandle*)s->wid)->setId(i);
1168     }
1169 }
1170
1171
1172 /*!\reimp
1173 */
1174 QSize QSplitterP::sizeHint() const
1175 {
1176     constPolish();
1177     int l = 0;
1178     int t = 0;
1179     if ( children() ) {
1180         const QObjectList * c = children();
1181         QObjectListIt it( *c );
1182         QObject * o;
1183
1184         while( (o=it.current()) != 0 ) {
1185             ++it;
1186             if ( o->isWidgetType() &&
1187                  !((QWidget*)o)->isHidden() ) {
1188                 QSize s = ((QWidget*)o)->sizeHint();
1189                 if ( s.isValid() ) {
1190                     l += pick( s );
1191                     t = QMAX( t, trans( s ) );
1192                 }
1193             }
1194         }
1195     }
1196     return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1197 }
1198
1199
1200 /*!
1201 \reimp
1202 */
1203
1204 QSize QSplitterP::minimumSizeHint() const
1205 {
1206     constPolish();
1207     int l = 0;
1208     int t = 0;
1209     if ( children() ) {
1210         const QObjectList * c = children();
1211         QObjectListIt it( *c );
1212         QObject * o;
1213
1214         while( (o=it.current()) != 0 ) {
1215             ++it;
1216             if ( o->isWidgetType() &&
1217                  !((QWidget*)o)->isHidden() ) {
1218                 QSize s = minSize((QWidget*)o);
1219                 if ( s.isValid() ) {
1220                     l += pick( s );
1221                     t = QMAX( t, trans( s ) );
1222                 }
1223             }
1224         }
1225     }
1226     return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l );
1227 }
1228
1229
1230
1231 /*!\reimp
1232 */
1233 QSizePolicy QSplitterP::sizePolicy() const
1234 {
1235     return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
1236 }
1237
1238
1239 /*!
1240   Calculates stretch parameters from current sizes
1241 */
1242
1243 void QSplitterP::storeSizes()
1244 {
1245     QSplitterPLayoutStruct *s = data->list.first();
1246     while ( s ) {
1247         if ( !s->isSplitter )
1248             s->sizer = pick( s->wid->size() );
1249         s = data->list.next();
1250     }
1251 }
1252
1253
1254 #if 0 // ### remove this code ASAP
1255
1256 /*!
1257   Hides \a w if \a hide is TRUE, and updates the splitter.
1258
1259   \warning Due to a limitation in the current implementation,
1260   calling QWidget::hide() will not work.
1261 */
1262
1263 void QSplitterP::setHidden( QWidget *w, bool hide )
1264 {
1265     if ( w == w1 ) {
1266         w1show = !hide;
1267     } else if ( w == w2 ) {
1268         w2show = !hide;
1269     } else {
1270 #ifdef CHECK_RANGE
1271         qWarning( "QSplitterP::setHidden(), unknown widget" );
1272 #endif
1273         return;
1274     }
1275     if ( hide )
1276         w->hide();
1277     else
1278         w->show();
1279     recalc( TRUE );
1280 }
1281
1282
1283 /*!
1284   Returns the hidden status of \a w
1285 */
1286
1287 bool QSplitterP::isHidden( QWidget *w ) const
1288 {
1289     if ( w == w1 )
1290         return !w1show;
1291      else if ( w == w2 )
1292         return !w2show;
1293 #ifdef CHECK_RANGE
1294     else
1295         qWarning( "QSplitterP::isHidden(), unknown widget" );
1296 #endif
1297     return FALSE;
1298 }
1299 #endif
1300
1301
1302 /*!
1303   Returns a list of the size parameters of all the widgets in this
1304   splitter.
1305
1306   Giving the values to setSizes() will give a splitter with the same
1307   layout as this one.
1308 */
1309
1310 QValueList<int> QSplitterP::sizes() const
1311 {
1312     if ( !testWState(WState_Polished) ) {
1313         QWidget* that = (QWidget*) this;
1314         that->polish();
1315     }
1316     QValueList<int> list;
1317     QSplitterPLayoutStruct *s = data->list.first();
1318     while ( s ) {
1319         if ( !s->isSplitter )
1320             list.append( s->sizer );
1321         s = data->list.next();
1322     }
1323     return list;
1324 }
1325
1326
1327
1328 /*!
1329   Sets the size parameters to the values given in \a list.
1330   If the splitterP is horizontal, the values set the sizes from
1331   left to right. If it is vertical, the sizes are applied from
1332   top to bottom.
1333   Extra values in \a list are ignored.
1334
1335   If \a list contains too few values, the result is undefined
1336   but the program will still be well-behaved.
1337 */
1338
1339 void QSplitterP::setSizes( QValueList<int> list )
1340 {
1341     processChildEvents();
1342     QValueList<int>::Iterator it = list.begin();
1343     QSplitterPLayoutStruct *s = data->list.first();
1344     while ( s && it != list.end() ) {
1345         if ( !s->isSplitter ) {
1346             s->sizer = *it;
1347             ++it;
1348         }
1349         s = data->list.next();
1350     }
1351     doResize();
1352 }
1353
1354
1355 /*!
1356   Gets all posted child events, ensuring that the internal state of
1357   the splitter is consistent with the programmer's idea.
1358 */
1359
1360 void QSplitterP::processChildEvents()
1361 {
1362     QApplication::sendPostedEvents( this, QEvent::ChildInserted );
1363 }
1364
1365
1366 /*!
1367   \reimp
1368 */
1369
1370 void QSplitterP::styleChange( QStyle& old )
1371 {
1372 #if QT_VERSION < 300
1373     int sw = style().splitterWidth();
1374 #else
1375     int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); //qt3.x
1376 #endif
1377     QSplitterPLayoutStruct *s = data->list.first();
1378     while ( s ) {
1379         if ( s->isSplitter )
1380             s->sizer = sw;
1381         s = data->list.next();
1382     }
1383     doResize();
1384     QFrame::styleChange( old );
1385 }
1386 #endif
1387
1388 bool QSplitterP::isCompressEnabled() const
1389
1390         return compress_flag; 
1391 }
1392
1393 void QSplitterP::setCompressEnabled(bool on) {
1394         compress_flag = on;
1395 }
1396
1397 void QSplitterP::updateSplitterHandles() const {
1398     QSplitterPLayoutStruct *s = data->list.first();
1399     while ( s ) {
1400         if ( s->isSplitter )
1401             ((QSplitterPHandle*)s->wid)->updateButtonState();
1402         s = data->list.next();
1403     }
1404 }