source: vendor/trolltech/current/src/widgets/qdockarea.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 41.0 KB
Line 
1/****************************************************************************
2** $Id: qdockarea.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of the QDockArea class
5**
6** Created : 001010
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the workspace module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition licenses may use this
22** file in accordance with the Qt Commercial License Agreement provided
23** with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qdockarea.h"
39
40#ifndef QT_NO_MAINWINDOW
41#include "qsplitter.h"
42#include "qlayout.h"
43#include "qptrvector.h"
44#include "qapplication.h"
45#include "qpainter.h"
46#include "qwidgetlist.h"
47#include "qmap.h"
48#include "qmainwindow.h"
49
50//#define QDOCKAREA_DEBUG
51
52struct Q_EXPORT DockData
53{
54 DockData() : w( 0 ), rect() {}
55 DockData( QDockWindow *dw, const QRect &r ) : w( dw ), rect( r ) {}
56 QDockWindow *w;
57 QRect rect;
58
59 Q_DUMMY_COMPARISON_OPERATOR( DockData )
60};
61
62static int fix_x( QDockWindow* w, int width = -1 ) {
63 if ( QApplication::reverseLayout() ) {
64 if ( width < 0 )
65 width = w->width();
66 return w->parentWidget()->width() - w->x() - width;
67 }
68 return w->x();
69}
70static int fix_x( QDockWindow* w, int x, int width = -1 ) {
71 if ( QApplication::reverseLayout() ) {
72 if ( width < 0 )
73 width = w->width();
74 return w->parentWidget()->width() - x - width;
75 }
76 return x;
77}
78
79static QPoint fix_pos( QDockWindow* w ) {
80 if ( QApplication::reverseLayout() ) {
81 QPoint p = w->pos();
82 p.rx() = w->parentWidget()->width() - p.x() - w->width();
83 return p;
84 }
85 return w->pos();
86}
87
88
89void QDockAreaLayout::setGeometry( const QRect &r )
90{
91 QLayout::setGeometry( r );
92 layoutItems( r );
93}
94
95QLayoutIterator QDockAreaLayout::iterator()
96{
97 return 0;
98}
99
100QSize QDockAreaLayout::sizeHint() const
101{
102 if ( !dockWindows || !dockWindows->first() )
103 return QSize( 0, 0 );
104
105 if ( dirty ) {
106 QDockAreaLayout *that = (QDockAreaLayout *) this;
107 that->layoutItems( geometry() );
108 }
109
110 int w = 0;
111 int h = 0;
112 QPtrListIterator<QDockWindow> it( *dockWindows );
113 QDockWindow *dw = 0;
114 it.toFirst();
115 int y = -1;
116 int x = -1;
117 int ph = 0;
118 int pw = 0;
119 while ( ( dw = it.current() ) != 0 ) {
120 int plush = 0, plusw = 0;
121 ++it;
122 if ( dw->isHidden() )
123 continue;
124 if ( hasHeightForWidth() ) {
125 if ( y != dw->y() )
126 plush = ph;
127 y = dw->y();
128 ph = dw->height();
129 } else {
130 if ( x != dw->x() )
131 plusw = pw;
132 x = dw->x();
133 pw = dw->width();
134 }
135 h = QMAX( h, dw->height() + plush );
136 w = QMAX( w, dw->width() + plusw );
137 }
138
139 if ( hasHeightForWidth() )
140 return QSize( 0, h );
141 return QSize( w, 0 );
142}
143
144bool QDockAreaLayout::hasHeightForWidth() const
145{
146 return orient == Horizontal;
147}
148
149void QDockAreaLayout::init()
150{
151 dirty = TRUE;
152 cached_width = 0;
153 cached_height = 0;
154 cached_hfw = -1;
155 cached_wfh = -1;
156}
157
158void QDockAreaLayout::invalidate()
159{
160 dirty = TRUE;
161 cached_width = 0;
162 cached_height = 0;
163}
164
165static int start_pos( const QRect &r, Qt::Orientation o )
166{
167 if ( o == Qt::Horizontal ) {
168 return QMAX( 0, r.x() );
169 } else {
170 return QMAX( 0, r.y() );
171 }
172}
173
174static void add_size( int s, int &pos, Qt::Orientation o )
175{
176 if ( o == Qt::Horizontal ) {
177 pos += s;
178 } else {
179 pos += s;
180 }
181}
182
183static int space_left( const QRect &r, int pos, Qt::Orientation o )
184{
185 if ( o == Qt::Horizontal ) {
186 return ( r.x() + r.width() ) - pos;
187 } else {
188 return ( r.y() + r.height() ) - pos;
189 }
190}
191
192static int dock_extent( QDockWindow *w, Qt::Orientation o, int maxsize )
193{
194 if ( o == Qt::Horizontal )
195 return QMIN( maxsize, QMAX( w->sizeHint().width(), w->fixedExtent().width() ) );
196 else
197 return QMIN( maxsize, QMAX( w->sizeHint().height(), w->fixedExtent().height() ) );
198}
199
200static int dock_strut( QDockWindow *w, Qt::Orientation o )
201{
202 if ( o != Qt::Horizontal ) {
203 int wid;
204 if ( ( wid = w->fixedExtent().width() ) != -1 )
205 return QMAX( wid, QMAX( w->minimumSize().width(), w->minimumSizeHint().width() ) );
206 return QMAX( w->sizeHint().width(), QMAX( w->minimumSize().width(), w->minimumSizeHint().width() ) );
207 } else {
208 int hei;
209 if ( ( hei = w->fixedExtent().height() ) != -1 )
210 return QMAX( hei, QMAX( w->minimumSizeHint().height(), w->minimumSize().height() ) );
211 return QMAX( w->sizeHint().height(), QMAX( w->minimumSizeHint().height(), w->minimumSize().height() ) );
212 }
213}
214
215static void set_geometry( QDockWindow *w, int pos, int sectionpos, int extent, int strut, Qt::Orientation o )
216{
217 if ( o == Qt::Horizontal )
218 w->setGeometry( fix_x( w, pos, extent), sectionpos, extent, strut );
219 else
220 w->setGeometry( sectionpos, pos, strut, extent );
221}
222
223static int size_extent( const QSize &s, Qt::Orientation o, bool swap = FALSE )
224{
225 return o == Qt::Horizontal ? ( swap ? s.height() : s.width() ) : ( swap ? s.width() : s.height() );
226}
227
228static int point_pos( const QPoint &p, Qt::Orientation o, bool swap = FALSE )
229{
230 return o == Qt::Horizontal ? ( swap ? p.y() : p.x() ) : ( swap ? p.x() : p.y() );
231}
232
233static void shrink_extend( QDockWindow *dw, int &dockExtend, int /*spaceLeft*/, Qt::Orientation o )
234{
235 QToolBar *tb = ::qt_cast<QToolBar*>(dw);
236 if ( o == Qt::Horizontal ) {
237 int mw = 0;
238 if ( !tb )
239 mw = dw->minimumWidth();
240 else
241 mw = dw->sizeHint().width();
242 dockExtend = mw;
243 } else {
244 int mh = 0;
245 if ( !tb )
246 mh = dw->minimumHeight();
247 else
248 mh = dw->sizeHint().height();
249 dockExtend = mh;
250 }
251}
252
253static void place_line( QValueList<DockData> &lastLine, Qt::Orientation o, int linestrut, int fullextent, int tbstrut, int maxsize, QDockAreaLayout * )
254{
255 QDockWindow *last = 0;
256 QRect lastRect;
257 for ( QValueList<DockData>::Iterator it = lastLine.begin(); it != lastLine.end(); ++it ) {
258 if ( tbstrut != -1 && ::qt_cast<QToolBar*>((*it).w) )
259 (*it).rect.setHeight( tbstrut );
260 if ( !last ) {
261 last = (*it).w;
262 lastRect = (*it).rect;
263 continue;
264 }
265 if ( !last->isStretchable() ) {
266 int w = QMIN( lastRect.width(), maxsize );
267 set_geometry( last, lastRect.x(), lastRect.y(), w, lastRect.height(), o );
268 } else {
269 int w = QMIN( (*it).rect.x() - lastRect.x(), maxsize );
270 set_geometry( last, lastRect.x(), lastRect.y(), w,
271 last->isResizeEnabled() ? linestrut : lastRect.height(), o );
272 }
273 last = (*it).w;
274 lastRect = (*it).rect;
275 }
276 if ( !last )
277 return;
278 if ( !last->isStretchable() ) {
279 int w = QMIN( lastRect.width(), maxsize );
280 set_geometry( last, lastRect.x(), lastRect.y(), w, lastRect.height(), o );
281 } else {
282 int w = QMIN( fullextent - lastRect.x() - ( o == Qt::Vertical ? 1 : 0 ), maxsize );
283 set_geometry( last, lastRect.x(), lastRect.y(), w,
284 last->isResizeEnabled() ? linestrut : lastRect.height(), o );
285 }
286}
287
288
289QSize QDockAreaLayout::minimumSize() const
290{
291 if ( !dockWindows || !dockWindows->first() )
292 return QSize( 0, 0 );
293
294 if ( dirty ) {
295 QDockAreaLayout *that = (QDockAreaLayout *) this;
296 that->layoutItems( geometry() );
297 }
298
299 int s = 0;
300
301 QPtrListIterator<QDockWindow> it( *dockWindows );
302 QDockWindow *dw = 0;
303 while ( ( dw = it.current() ) != 0 ) {
304 ++it;
305 if ( dw->isHidden() )
306 continue;
307 s = QMAX( s, dock_strut( dw, orientation() ) );
308 }
309
310 return orientation() == Horizontal ? QSize( 0, s ? s+2 : 0 ) : QSize( s, 0 );
311}
312
313
314
315int QDockAreaLayout::layoutItems( const QRect &rect, bool testonly )
316{
317 if ( !dockWindows || !dockWindows->first() )
318 return 0;
319
320 dirty = FALSE;
321
322 // some corrections
323 QRect r = rect;
324 if ( orientation() == Vertical )
325 r.setHeight( r.height() - 3 );
326
327 // init
328 lines.clear();
329 ls.clear();
330 QPtrListIterator<QDockWindow> it( *dockWindows );
331 QDockWindow *dw = 0;
332 int start = start_pos( r, orientation() );
333 int pos = start;
334 int sectionpos = 0;
335 int linestrut = 0;
336 QValueList<DockData> lastLine;
337 int tbstrut = -1;
338 int maxsize = size_extent( rect.size(), orientation() );
339 int visibleWindows = 0;
340
341 // go through all widgets in the dock
342 while ( ( dw = it.current() ) != 0 ) {
343 ++it;
344 if ( dw->isHidden() )
345 continue;
346 ++visibleWindows;
347 // find position for the widget: This is the maximum of the
348 // end of the previous widget and the offset of the widget. If
349 // the position + the width of the widget dosn't fit into the
350 // dock, try moving it a bit back, if possible.
351 int op = pos;
352 int dockExtend = dock_extent( dw, orientation(), maxsize );
353 if ( !dw->isStretchable() ) {
354 pos = QMAX( pos, dw->offset() );
355 if ( pos + dockExtend > size_extent( r.size(), orientation() ) - 1 )
356 pos = QMAX( op, size_extent( r.size(), orientation() ) - 1 - dockExtend );
357 }
358 if ( !lastLine.isEmpty() && !dw->newLine() && space_left( rect, pos, orientation() ) < dockExtend )
359 shrink_extend( dw, dockExtend, space_left( rect, pos, orientation() ), orientation() );
360 // if the current widget doesn't fit into the line anymore and it is not the first widget of the line
361 if ( !lastLine.isEmpty() &&
362 ( space_left( rect, pos, orientation() ) < dockExtend || dw->newLine() ) ) {
363 if ( !testonly ) // place the last line, if not in test mode
364 place_line( lastLine, orientation(), linestrut, size_extent( r.size(), orientation() ), tbstrut, maxsize, this );
365 // remember the line coordinats of the last line
366 if ( orientation() == Horizontal )
367 lines.append( QRect( 0, sectionpos, r.width(), linestrut ) );
368 else
369 lines.append( QRect( sectionpos, 0, linestrut, r.height() ) );
370 // do some clearing for the next line
371 lastLine.clear();
372 sectionpos += linestrut;
373 linestrut = 0;
374 pos = start;
375 tbstrut = -1;
376 }
377
378 // remeber first widget of a line
379 if ( lastLine.isEmpty() ) {
380 ls.append( dw );
381 // try to make the best position
382 int op = pos;
383 if ( !dw->isStretchable() )
384 pos = QMAX( pos, dw->offset() );
385 if ( pos + dockExtend > size_extent( r.size(), orientation() ) - 1 )
386 pos = QMAX( op, size_extent( r.size(), orientation() ) - 1 - dockExtend );
387 }
388 // do some calculations and add the remember the rect which the docking widget requires for the placing
389 QRect dwRect(pos, sectionpos, dockExtend, dock_strut( dw, orientation() ) );
390 lastLine.append( DockData( dw, dwRect ) );
391 if ( ::qt_cast<QToolBar*>(dw) )
392 tbstrut = QMAX( tbstrut, dock_strut( dw, orientation() ) );
393 linestrut = QMAX( dock_strut( dw, orientation() ), linestrut );
394 add_size( dockExtend, pos, orientation() );
395 }
396
397 // if some stuff was not placed/stored yet, do it now
398 if ( !testonly )
399 place_line( lastLine, orientation(), linestrut, size_extent( r.size(), orientation() ), tbstrut, maxsize, this );
400 if ( orientation() == Horizontal )
401 lines.append( QRect( 0, sectionpos, r.width(), linestrut ) );
402 else
403 lines.append( QRect( sectionpos, 0, linestrut, r.height() ) );
404 if ( *(--lines.end()) == *(--(--lines.end())) )
405 lines.remove( lines.at( lines.count() - 1 ) );
406
407 it.toFirst();
408 bool hadResizable = FALSE;
409 while ( ( dw = it.current() ) != 0 ) {
410 ++it;
411 if ( !dw->isVisibleTo( parentWidget ) )
412 continue;
413 hadResizable = hadResizable || dw->isResizeEnabled();
414 dw->updateSplitterVisibility( visibleWindows > 1 ); //!dw->area()->isLastDockWindow( dw ) );
415 }
416 return sectionpos + linestrut;
417}
418
419int QDockAreaLayout::heightForWidth( int w ) const
420{
421 if ( dockWindows->isEmpty() && parentWidget )
422 return parentWidget->minimumHeight();
423
424 if ( cached_width != w ) {
425 QDockAreaLayout * mthis = (QDockAreaLayout*)this;
426 mthis->cached_width = w;
427 int h = mthis->layoutItems( QRect( 0, 0, w, 0 ), TRUE );
428 mthis->cached_hfw = h;
429 return h;
430 }
431
432 return cached_hfw;
433}
434
435int QDockAreaLayout::widthForHeight( int h ) const
436{
437 if ( cached_height != h ) {
438 QDockAreaLayout * mthis = (QDockAreaLayout*)this;
439 mthis->cached_height = h;
440 int w = mthis->layoutItems( QRect( 0, 0, 0, h ), TRUE );
441 mthis->cached_wfh = w;
442 return w;
443 }
444 return cached_wfh;
445}
446
447
448
449
450/*!
451 \class QDockArea qdockarea.h
452 \brief The QDockArea class manages and lays out QDockWindows.
453
454 \ingroup application
455
456 A QDockArea is a container which manages a list of
457 \l{QDockWindow}s which it lays out within its area. In cooperation
458 with the \l{QDockWindow}s it is responsible for the docking and
459 undocking of \l{QDockWindow}s and moving them inside the dock
460 area. QDockAreas also handle the wrapping of \l{QDockWindow}s to
461 fill the available space as compactly as possible. QDockAreas can
462 contain QToolBars since QToolBar is a QDockWindow subclass.
463
464 QMainWindow contains four QDockAreas which you can use for your
465 QToolBars and QDockWindows, so in most situations you do not need
466 to use the QDockArea class directly. Although QMainWindow contains
467 support for its own dock areas it isn't convenient for adding new
468 QDockAreas. If you need to create your own dock areas we suggest
469 that you create a subclass of QWidget and add your QDockAreas to
470 your subclass.
471
472 \img qmainwindow-qdockareas.png QMainWindow's QDockAreas
473
474 \target lines
475 \e Lines. QDockArea uses the concept of lines. A line is a
476 horizontal region which may contain dock windows side-by-side. A
477 dock area may have room for more than one line. When dock windows
478 are docked into a dock area they are usually added at the right
479 hand side of the top-most line that has room (unless manually
480 placed by the user). When users move dock windows they may leave
481 empty lines or gaps in non-empty lines. Dock windows can be lined
482 up to minimize wasted space using the lineUp() function.
483
484 The QDockArea class maintains a position list of all its child
485 dock windows. Dock windows are added to a dock area from position
486 0 onwards. Dock windows are laid out sequentially in position
487 order from left to right, and in the case of multiple lines of
488 dock windows, from top to bottom. If a dock window is floated it
489 still retains its position since this is where the window will
490 return if the user double clicks its caption. A dock window's
491 position can be determined with hasDockWindow(). The position can
492 be changed with moveDockWindow().
493
494 To dock or undock a dock window use QDockWindow::dock() and
495 QDockWindow::undock() respectively. If you want to control which
496 dock windows can dock in a dock area use setAcceptDockWindow(). To
497 see if a dock area contains a particular dock window use
498 \l{hasDockWindow()}; to see how many dock windows a dock area
499 contains use count().
500
501 The streaming operators can write the positions of the dock
502 windows in the dock area to a QTextStream. The positions can be
503 read back later to restore the saved positions.
504
505 Save the positions to a QTextStream:
506 \code
507 ts << *myDockArea;
508 \endcode
509
510 Restore the positions from a QTextStream:
511 \code
512 ts >> *myDockArea;
513 \endcode
514*/
515
516/*!
517 \property QDockArea::handlePosition
518 \brief where the dock window splitter handle is placed in the dock
519 area
520
521 The default position is \c Normal.
522*/
523
524/*!
525 \property QDockArea::orientation
526 \brief the dock area's orientation
527
528 There is no default value; the orientation is specified in the
529 constructor.
530*/
531
532/*!
533 \enum QDockArea::HandlePosition
534
535 A dock window has two kinds of handles, the dock window handle
536 used for dragging the dock window, and the splitter handle used to
537 resize the dock window in relation to other dock windows using a
538 splitter. (The splitter handle is only visible for docked
539 windows.)
540
541 This enum specifies where the dock window splitter handle is
542 placed in the dock area.
543
544 \value Normal The splitter handles of dock windows are placed at
545 the right or bottom.
546
547 \value Reverse The splitter handles of dock windows are placed at
548 the left or top.
549*/
550
551/*!
552 Constructs a QDockArea with orientation \a o, HandlePosition \a h,
553 parent \a parent and called \a name.
554*/
555
556QDockArea::QDockArea( Orientation o, HandlePosition h, QWidget *parent, const char *name )
557 : QWidget( parent, name ), orient( o ), layout( 0 ), hPos( h )
558{
559 dockWindows = new QPtrList<QDockWindow>;
560 layout = new QDockAreaLayout( this, o, dockWindows, 0, 0, "toollayout" );
561 installEventFilter( this );
562}
563
564/*!
565 Destroys the dock area and all the dock windows docked in the dock
566 area.
567
568 Does not affect any floating dock windows or dock windows in other
569 dock areas, even if they first appeared in this dock area.
570 Floating dock windows are effectively top level windows and are
571 not child windows of the dock area. When a floating dock window is
572 docked (dragged into a dock area) its parent becomes the dock
573 area.
574*/
575
576QDockArea::~QDockArea()
577{
578 dockWindows->setAutoDelete( TRUE );
579 delete dockWindows;
580 dockWindows = 0;
581}
582
583/*!
584 Moves the QDockWindow \a w within the dock area. If \a w is not
585 already docked in this area, \a w is docked first. If \a index is
586 -1 or larger than the number of docked widgets, \a w is appended
587 at the end, otherwise it is inserted at the position \a index.
588*/
589
590void QDockArea::moveDockWindow( QDockWindow *w, int index )
591{
592 invalidateFixedSizes();
593 QDockWindow *dockWindow = 0;
594 int dockWindowIndex = findDockWindow( w );
595 if ( dockWindowIndex == -1 ) {
596 dockWindow = w;
597 dockWindow->reparent( this, QPoint( 0, 0 ), TRUE );
598 w->installEventFilter( this );
599 updateLayout();
600 setSizePolicy( QSizePolicy( orientation() == Horizontal ? QSizePolicy::Expanding : QSizePolicy::Minimum,
601 orientation() == Vertical ? QSizePolicy::Expanding : QSizePolicy::Minimum ) );
602 dockWindows->append( w );
603 } else {
604 if ( w->parent() != this )
605 w->reparent( this, QPoint( 0, 0 ), TRUE );
606 if ( index == - 1 ) {
607 dockWindows->removeRef( w );
608 dockWindows->append( w );
609 }
610 }
611
612 w->dockArea = this;
613 w->curPlace = QDockWindow::InDock;
614 w->updateGui();
615
616 if ( index != -1 && index < (int)dockWindows->count() ) {
617 dockWindows->removeRef( w );
618 dockWindows->insert( index, w );
619 }
620}
621
622/*!
623 Returns TRUE if the dock area contains the dock window \a w;
624 otherwise returns FALSE. If \a index is not 0 it will be set as
625 follows: if the dock area contains the dock window \a *index is
626 set to \a w's index position; otherwise \a *index is set to -1.
627*/
628
629bool QDockArea::hasDockWindow( QDockWindow *w, int *index )
630{
631 int i = dockWindows->findRef( w );
632 if ( index )
633 *index = i;
634 return i != -1;
635}
636
637int QDockArea::lineOf( int index )
638{
639 QPtrList<QDockWindow> lineStarts = layout->lineStarts();
640 int i = 0;
641 for ( QDockWindow *w = lineStarts.first(); w; w = lineStarts.next(), ++i ) {
642 if ( dockWindows->find( w ) >= index )
643 return i;
644 }
645 return i;
646}
647
648/*!
649 \overload
650
651 Moves the dock window \a w inside the dock area where \a p is the
652 new position (in global screen coordinates), \a r is the suggested
653 rectangle of the dock window and \a swap specifies whether or not
654 the orientation of the docked widget needs to be changed.
655
656 This function is used internally by QDockWindow. You shouldn't
657 need to call it yourself.
658*/
659
660void QDockArea::moveDockWindow( QDockWindow *w, const QPoint &p, const QRect &r, bool swap )
661{
662 invalidateFixedSizes();
663 int mse = -10;
664 bool hasResizable = FALSE;
665 for ( QDockWindow *dw = dockWindows->first(); dw; dw = dockWindows->next() ) {
666 if ( dw->isHidden() )
667 continue;
668 if ( dw->isResizeEnabled() )
669 hasResizable = TRUE;
670 if ( orientation() != Qt::Horizontal )
671 mse = QMAX( QMAX( dw->fixedExtent().width(), dw->width() ), mse );
672 else
673 mse = QMAX( QMAX( dw->fixedExtent().height(), dw->height() ), mse );
674 }
675 if ( !hasResizable && w->isResizeEnabled() ) {
676 if ( orientation() != Qt::Horizontal )
677 mse = QMAX( w->fixedExtent().width(), mse );
678 else
679 mse = QMAX( w->fixedExtent().height(), mse );
680 }
681
682 QDockWindow *dockWindow = 0;
683 int dockWindowIndex = findDockWindow( w );
684 QPtrList<QDockWindow> lineStarts = layout->lineStarts();
685 QValueList<QRect> lines = layout->lineList();
686 bool wasAloneInLine = FALSE;
687 QPoint pos = mapFromGlobal( p );
688 QRect lr = *lines.at( lineOf( dockWindowIndex ) );
689 if ( dockWindowIndex != -1 ) {
690 if ( lineStarts.find( w ) != -1 &&
691 ( dockWindowIndex < (int)dockWindows->count() - 1 && lineStarts.find( dockWindows->at( dockWindowIndex + 1 ) ) != -1 ||
692 dockWindowIndex == (int)dockWindows->count() - 1 ) )
693 wasAloneInLine = TRUE;
694 dockWindow = dockWindows->take( dockWindowIndex );
695 if ( !wasAloneInLine ) { // only do the pre-layout if the widget isn't the only one in its line
696 if ( lineStarts.findRef( dockWindow ) != -1 && dockWindowIndex < (int)dockWindows->count() )
697 dockWindows->at( dockWindowIndex )->setNewLine( TRUE );
698 layout->layoutItems( QRect( 0, 0, width(), height() ), TRUE );
699 }
700 } else {
701 dockWindow = w;
702 dockWindow->reparent( this, QPoint( 0, 0 ), TRUE );
703 if ( swap )
704 dockWindow->resize( dockWindow->height(), dockWindow->width() );
705 w->installEventFilter( this );
706 }
707
708 lineStarts = layout->lineStarts();
709 lines = layout->lineList();
710
711 QRect rect = QRect( mapFromGlobal( r.topLeft() ), r.size() );
712 if ( orientation() == Horizontal && QApplication::reverseLayout() ) {
713 rect = QRect( width() - rect.x() - rect.width(), rect.y(), rect.width(), rect.height() );
714 pos.rx() = width() - pos.x();
715 }
716 dockWindow->setOffset( point_pos( rect.topLeft(), orientation() ) );
717 if ( orientation() == Horizontal ) {
718 int offs = dockWindow->offset();
719 if ( width() - offs < dockWindow->minimumWidth() )
720 dockWindow->setOffset( width() - dockWindow->minimumWidth() );
721 } else {
722 int offs = dockWindow->offset();
723 if ( height() - offs < dockWindow->minimumHeight() )
724 dockWindow->setOffset( height() - dockWindow->minimumHeight() );
725 }
726
727 if ( dockWindows->isEmpty() ) {
728 dockWindows->append( dockWindow );
729 } else {
730 int dockLine = -1;
731 bool insertLine = FALSE;
732 int i = 0;
733 QRect lineRect;
734 // find the line which we touched with the mouse
735 for ( QValueList<QRect>::Iterator it = lines.begin(); it != lines.end(); ++it, ++i ) {
736 if ( point_pos( pos, orientation(), TRUE ) >= point_pos( (*it).topLeft(), orientation(), TRUE ) &&
737 point_pos( pos, orientation(), TRUE ) <= point_pos( (*it).topLeft(), orientation(), TRUE ) +
738 size_extent( (*it).size(), orientation(), TRUE ) ) {
739 dockLine = i;
740 lineRect = *it;
741 break;
742 }
743 }
744 if ( dockLine == -1 ) { // outside the dock...
745 insertLine = TRUE;
746 if ( point_pos( pos, orientation(), TRUE ) < 0 ) // insert as first line
747 dockLine = 0;
748 else
749 dockLine = (int)lines.count(); // insert after the last line ### size_t/int cast
750 } else { // inside the dock (we have found a dockLine)
751 if ( point_pos( pos, orientation(), TRUE ) <
752 point_pos( lineRect.topLeft(), orientation(), TRUE ) + 4 ) { // mouse was at the very beginning of the line
753 insertLine = TRUE; // insert a new line before that with the docking widget
754 } else if ( point_pos( pos, orientation(), TRUE ) >
755 point_pos( lineRect.topLeft(), orientation(), TRUE ) +
756 size_extent( lineRect.size(), orientation(), TRUE ) - 4 ) { // mouse was at the very and of the line
757 insertLine = TRUE; // insert a line after that with the docking widget
758 dockLine++;
759 }
760 }
761
762 if ( !insertLine && wasAloneInLine && lr.contains( pos ) ) // if we are alone in a line and just moved in there, re-insert it
763 insertLine = TRUE;
764
765#if defined(QDOCKAREA_DEBUG)
766 qDebug( "insert in line %d, and insert that line: %d", dockLine, insertLine );
767 qDebug( " (btw, we have %d lines)", lines.count() );
768#endif
769 QDockWindow *dw = 0;
770 if ( dockLine >= (int)lines.count() ) { // insert after last line
771 dockWindows->append( dockWindow );
772 dockWindow->setNewLine( TRUE );
773#if defined(QDOCKAREA_DEBUG)
774 qDebug( "insert at the end" );
775#endif
776 } else if ( dockLine == 0 && insertLine ) { // insert before first line
777 dockWindows->insert( 0, dockWindow );
778 dockWindows->at( 1 )->setNewLine( TRUE );
779#if defined(QDOCKAREA_DEBUG)
780 qDebug( "insert at the begin" );
781#endif
782 } else { // insert somewhere in between
783 // make sure each line start has a new line
784 for ( dw = lineStarts.first(); dw; dw = lineStarts.next() )
785 dw->setNewLine( TRUE );
786
787 // find the index of the first widget in the search line
788 int searchLine = dockLine;
789#if defined(QDOCKAREA_DEBUG)
790 qDebug( "search line start of %d", searchLine );
791#endif
792 QDockWindow *lsw = lineStarts.at( searchLine );
793 int index = dockWindows->find( lsw );
794 if ( index == -1 ) { // the linestart widget hasn't been found, try to find it harder
795 if ( lsw == w && dockWindowIndex <= (int)dockWindows->count())
796 index = dockWindowIndex;
797 else
798 index = 0;
799 if ( index < (int)dockWindows->count() )
800 (void)dockWindows->at( index ); // move current to index
801 }
802#if defined(QDOCKAREA_DEBUG)
803 qDebug( " which starts at %d", index );
804#endif
805 if ( !insertLine ) { // if we insert the docking widget in the existing line
806 // find the index for the widget
807 bool inc = TRUE;
808 bool firstTime = TRUE;
809 for ( dw = dockWindows->current(); dw; dw = dockWindows->next() ) {
810 if ( orientation() == Horizontal )
811 dw->setFixedExtentWidth( -1 );
812 else
813 dw->setFixedExtentHeight( -1 );
814 if ( !firstTime && lineStarts.find( dw ) != -1 ) // we are in the next line, so break
815 break;
816 if ( point_pos( pos, orientation() ) <
817 point_pos( fix_pos( dw ), orientation() ) + size_extent( dw->size(), orientation() ) / 2 ) {
818 inc = FALSE;
819 }
820 if ( inc )
821 index++;
822 firstTime = FALSE;
823 }
824#if defined(QDOCKAREA_DEBUG)
825 qDebug( "insert at index: %d", index );
826#endif
827 // if we insert it just before a widget which has a new line, transfer the newline to the docking widget
828 // but not if we didn't only mave a widget in its line which was alone in the line before
829 if ( !( wasAloneInLine && lr.contains( pos ) )
830 && index >= 0 && index < (int)dockWindows->count() &&
831 dockWindows->at( index )->newLine() && lineOf( index ) == dockLine ) {
832#if defined(QDOCKAREA_DEBUG)
833 qDebug( "get rid of the old newline and get me one" );
834#endif
835 dockWindows->at( index )->setNewLine( FALSE );
836 dockWindow->setNewLine( TRUE );
837 } else if ( wasAloneInLine && lr.contains( pos ) ) {
838 dockWindow->setNewLine( TRUE );
839 } else { // if we are somewhere in a line, get rid of the newline
840 dockWindow->setNewLine( FALSE );
841 }
842 } else { // insert in a new line, so make sure the dock widget and the widget which will be after it have a newline
843#if defined(QDOCKAREA_DEBUG)
844 qDebug( "insert a new line" );
845#endif
846 if ( index < (int)dockWindows->count() ) {
847#if defined(QDOCKAREA_DEBUG)
848 qDebug( "give the widget at %d a newline", index );
849#endif
850 QDockWindow* nldw = dockWindows->at( index );
851 if ( nldw )
852 nldw->setNewLine( TRUE );
853 }
854#if defined(QDOCKAREA_DEBUG)
855 qDebug( "give me a newline" );
856#endif
857 dockWindow->setNewLine( TRUE );
858 }
859 // finally insert the widget
860 dockWindows->insert( index, dockWindow );
861 }
862 }
863
864 if ( mse != -10 && w->isResizeEnabled() ) {
865 if ( orientation() != Qt::Horizontal )
866 w->setFixedExtentWidth( QMIN( QMAX( w->minimumWidth(), mse ), w->sizeHint().width() ) );
867 else
868 w->setFixedExtentHeight( QMIN( QMAX( w->minimumHeight(), mse ), w->sizeHint().height() ) );
869 }
870
871 updateLayout();
872 setSizePolicy( QSizePolicy( orientation() == Horizontal ? QSizePolicy::Expanding : QSizePolicy::Minimum,
873 orientation() == Vertical ? QSizePolicy::Expanding : QSizePolicy::Minimum ) );
874}
875
876/*!
877 Removes the dock window \a w from the dock area. If \a
878 makeFloating is TRUE, \a w gets floated, and if \a swap is TRUE,
879 the orientation of \a w gets swapped. If \a fixNewLines is TRUE
880 (the default) newlines in the area will be fixed.
881
882 You should never need to call this function yourself. Use
883 QDockWindow::dock() and QDockWindow::undock() instead.
884*/
885
886void QDockArea::removeDockWindow( QDockWindow *w, bool makeFloating, bool swap, bool fixNewLines )
887{
888 w->removeEventFilter( this );
889 QDockWindow *dockWindow = 0;
890 int i = findDockWindow( w );
891 if ( i == -1 )
892 return;
893 dockWindow = dockWindows->at( i );
894 dockWindows->remove( i );
895 QPtrList<QDockWindow> lineStarts = layout->lineStarts();
896 if ( fixNewLines && lineStarts.findRef( dockWindow ) != -1 && i < (int)dockWindows->count() )
897 dockWindows->at( i )->setNewLine( TRUE );
898 if ( makeFloating ) {
899 QWidget *p = parentWidget() ? parentWidget() : topLevelWidget();
900 dockWindow->reparent( p, WType_Dialog | WStyle_Customize | WStyle_NoBorder | WStyle_Tool, QPoint( 0, 0 ), FALSE );
901 }
902 if ( swap )
903 dockWindow->resize( dockWindow->height(), dockWindow->width() );
904 updateLayout();
905 if ( dockWindows->isEmpty() )
906 setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
907}
908
909int QDockArea::findDockWindow( QDockWindow *w )
910{
911 return dockWindows ? dockWindows->findRef( w ) : -1;
912}
913
914void QDockArea::updateLayout()
915{
916 layout->invalidate();
917 layout->activate();
918}
919
920/*! \reimp
921 */
922
923bool QDockArea::eventFilter( QObject *o, QEvent *e )
924{
925 if ( e->type() == QEvent::Close ) {
926 if ( ::qt_cast<QDockWindow*>(o) ) {
927 o->removeEventFilter( this );
928 QApplication::sendEvent( o, e );
929 if ( ( (QCloseEvent*)e )->isAccepted() )
930 removeDockWindow( (QDockWindow*)o, FALSE, FALSE );
931 return TRUE;
932 }
933 }
934 return FALSE;
935}
936
937/*! \internal
938
939 Invalidates the offset of the next dock window in the dock area.
940 */
941
942void QDockArea::invalidNextOffset( QDockWindow *dw )
943{
944 int i = dockWindows->find( dw );
945 if ( i == -1 || i >= (int)dockWindows->count() - 1 )
946 return;
947 if ( ( dw = dockWindows->at( ++i ) ) )
948 dw->setOffset( 0 );
949}
950
951/*!
952 \property QDockArea::count
953 \brief the number of dock windows in the dock area
954*/
955int QDockArea::count() const
956{
957 return dockWindows->count();
958}
959
960/*!
961 \property QDockArea::empty
962 \brief whether the dock area is empty
963*/
964
965bool QDockArea::isEmpty() const
966{
967 return dockWindows->isEmpty();
968}
969
970
971/*!
972 Returns a list of the dock windows in the dock area.
973*/
974
975QPtrList<QDockWindow> QDockArea::dockWindowList() const
976{
977 return *dockWindows;
978}
979
980/*!
981 Lines up the dock windows in this dock area to minimize wasted
982 space. If \a keepNewLines is TRUE, only space within lines is
983 cleaned up. If \a keepNewLines is FALSE the number of lines might
984 be changed.
985*/
986
987void QDockArea::lineUp( bool keepNewLines )
988{
989 for ( QDockWindow *dw = dockWindows->first(); dw; dw = dockWindows->next() ) {
990 dw->setOffset( 0 );
991 if ( !keepNewLines )
992 dw->setNewLine( FALSE );
993 }
994 layout->activate();
995}
996
997QDockArea::DockWindowData *QDockArea::dockWindowData( QDockWindow *w )
998{
999 DockWindowData *data = new DockWindowData;
1000 data->index = findDockWindow( w );
1001 if ( data->index == -1 ) {
1002 delete data;
1003 return 0;
1004 }
1005 QPtrList<QDockWindow> lineStarts = layout->lineStarts();
1006 int i = -1;
1007 for ( QDockWindow *dw = dockWindows->first(); dw; dw = dockWindows->next() ) {
1008 if ( lineStarts.findRef( dw ) != -1 )
1009 ++i;
1010 if ( dw == w )
1011 break;
1012 }
1013 data->line = i;
1014 data->offset = point_pos( QPoint( fix_x(w), w->y() ), orientation() );
1015 data->area = this;
1016 data->fixedExtent = w->fixedExtent();
1017 return data;
1018}
1019
1020void QDockArea::dockWindow( QDockWindow *dockWindow, DockWindowData *data )
1021{
1022 if ( !data )
1023 return;
1024
1025 dockWindow->reparent( this, QPoint( 0, 0 ), FALSE );
1026 dockWindow->installEventFilter( this );
1027 dockWindow->dockArea = this;
1028 dockWindow->updateGui();
1029
1030 if ( dockWindows->isEmpty() ) {
1031 dockWindows->append( dockWindow );
1032 } else {
1033 QPtrList<QDockWindow> lineStarts = layout->lineStarts();
1034 int index = 0;
1035 if ( (int)lineStarts.count() > data->line )
1036 index = dockWindows->find( lineStarts.at( data->line ) );
1037 if ( index == -1 ) {
1038 index = 0;
1039 (void)dockWindows->at( index );
1040 }
1041 bool firstTime = TRUE;
1042 int offset = data->offset;
1043 for ( QDockWindow *dw = dockWindows->current(); dw; dw = dockWindows->next() ) {
1044 if ( !firstTime && lineStarts.find( dw ) != -1 )
1045 break;
1046 if ( offset <
1047 point_pos( fix_pos( dw ), orientation() ) + size_extent( dw->size(), orientation() ) / 2 )
1048 break;
1049 index++;
1050 firstTime = FALSE;
1051 }
1052 if ( index >= 0 && index < (int)dockWindows->count() &&
1053 dockWindows->at( index )->newLine() && lineOf( index ) == data->line ) {
1054 dockWindows->at( index )->setNewLine( FALSE );
1055 dockWindow->setNewLine( TRUE );
1056 } else {
1057 dockWindow->setNewLine( FALSE );
1058 }
1059
1060 dockWindows->insert( index, dockWindow );
1061 }
1062 dockWindow->show();
1063
1064 dockWindow->setFixedExtentWidth( data->fixedExtent.width() );
1065 dockWindow->setFixedExtentHeight( data->fixedExtent.height() );
1066
1067 updateLayout();
1068 setSizePolicy( QSizePolicy( orientation() == Horizontal ? QSizePolicy::Expanding : QSizePolicy::Minimum,
1069 orientation() == Vertical ? QSizePolicy::Expanding : QSizePolicy::Minimum ) );
1070
1071}
1072
1073/*!
1074 Returns TRUE if dock window \a dw could be docked into the dock
1075 area; otherwise returns FALSE.
1076
1077 \sa setAcceptDockWindow()
1078*/
1079
1080bool QDockArea::isDockWindowAccepted( QDockWindow *dw )
1081{
1082 if ( !dw )
1083 return FALSE;
1084 if ( forbiddenWidgets.findRef( dw ) != -1 )
1085 return FALSE;
1086
1087 QMainWindow *mw = ::qt_cast<QMainWindow*>(parentWidget());
1088 if ( !mw )
1089 return TRUE;
1090 if ( !mw->hasDockWindow( dw ) )
1091 return FALSE;
1092 if ( !mw->isDockEnabled( this ) )
1093 return FALSE;
1094 if ( !mw->isDockEnabled( dw, this ) )
1095 return FALSE;
1096 return TRUE;
1097}
1098
1099/*!
1100 If \a accept is TRUE, dock window \a dw can be docked in the dock
1101 area. If \a accept is FALSE, dock window \a dw cannot be docked in
1102 the dock area.
1103
1104 \sa isDockWindowAccepted()
1105*/
1106
1107void QDockArea::setAcceptDockWindow( QDockWindow *dw, bool accept )
1108{
1109 if ( accept )
1110 forbiddenWidgets.removeRef( dw );
1111 else if ( forbiddenWidgets.findRef( dw ) == -1 )
1112 forbiddenWidgets.append( dw );
1113}
1114
1115void QDockArea::invalidateFixedSizes()
1116{
1117 for ( QDockWindow *dw = dockWindows->first(); dw; dw = dockWindows->next() ) {
1118 if ( orientation() == Qt::Horizontal )
1119 dw->setFixedExtentWidth( -1 );
1120 else
1121 dw->setFixedExtentHeight( -1 );
1122 }
1123}
1124
1125int QDockArea::maxSpace( int hint, QDockWindow *dw )
1126{
1127 int index = findDockWindow( dw );
1128 if ( index == -1 || index + 1 >= (int)dockWindows->count() ) {
1129 if ( orientation() == Horizontal )
1130 return dw->width();
1131 return dw->height();
1132 }
1133
1134 QDockWindow *w = 0;
1135 int i = 0;
1136 do {
1137 w = dockWindows->at( index + (++i) );
1138 } while ( i + 1 < (int)dockWindows->count() && ( !w || w->isHidden() ) );
1139 if ( !w || !w->isResizeEnabled() || i >= (int)dockWindows->count() ) {
1140 if ( orientation() == Horizontal )
1141 return dw->width();
1142 return dw->height();
1143 }
1144 int min = 0;
1145 QToolBar *tb = ::qt_cast<QToolBar*>(w);
1146 if ( orientation() == Horizontal ) {
1147 w->setFixedExtentWidth( -1 );
1148 if ( !tb )
1149 min = QMAX( w->minimumSize().width(), w->minimumSizeHint().width() );
1150 else
1151 min = w->sizeHint().width();
1152 } else {
1153 w->setFixedExtentHeight( -1 );
1154 if ( !tb )
1155 min = QMAX( w->minimumSize().height(), w->minimumSizeHint().height() );
1156 else
1157 min = w->sizeHint().height();
1158 }
1159
1160 int diff = hint - ( orientation() == Horizontal ? dw->width() : dw->height() );
1161
1162 if ( ( orientation() == Horizontal ? w->width() : w->height() ) - diff < min )
1163 hint = ( orientation() == Horizontal ? dw->width() : dw->height() ) + ( orientation() == Horizontal ? w->width() : w->height() ) - min;
1164
1165 diff = hint - ( orientation() == Horizontal ? dw->width() : dw->height() );
1166 if ( orientation() == Horizontal )
1167 w->setFixedExtentWidth( w->width() - diff );
1168 else
1169 w->setFixedExtentHeight( w->height() - diff );
1170 return hint;
1171}
1172
1173void QDockArea::setFixedExtent( int d, QDockWindow *dw )
1174{
1175 QPtrList<QDockWindow> lst;
1176 QDockWindow *w;
1177 for ( w = dockWindows->first(); w; w = dockWindows->next() ) {
1178 if ( w->isHidden() )
1179 continue;
1180 if ( orientation() == Horizontal ) {
1181 if ( dw->y() != w->y() )
1182 continue;
1183 } else {
1184 if ( dw->x() != w->x() )
1185 continue;
1186 }
1187 if ( orientation() == Horizontal )
1188 d = QMAX( d, w->minimumHeight() );
1189 else
1190 d = QMAX( d, w->minimumWidth() );
1191 if ( w->isResizeEnabled() )
1192 lst.append( w );
1193 }
1194 for ( w = lst.first(); w; w = lst.next() ) {
1195 if ( orientation() == Horizontal )
1196 w->setFixedExtentHeight( d );
1197 else
1198 w->setFixedExtentWidth( d );
1199 }
1200}
1201
1202bool QDockArea::isLastDockWindow( QDockWindow *dw )
1203{
1204 int i = dockWindows->find( dw );
1205 if ( i == -1 || i >= (int)dockWindows->count() - 1 )
1206 return TRUE;
1207 QDockWindow *w = 0;
1208 if ( ( w = dockWindows->at( ++i ) ) ) {
1209 if ( orientation() == Horizontal && dw->y() < w->y() )
1210 return TRUE;
1211 if ( orientation() == Vertical && dw->x() < w->x() )
1212 return TRUE;
1213 } else {
1214 return TRUE;
1215 }
1216 return FALSE;
1217}
1218
1219#ifndef QT_NO_TEXTSTREAM
1220
1221/*!
1222 \relates QDockArea
1223
1224 Writes the layout of the dock windows in dock area \a dockArea to
1225 the text stream \a ts.
1226
1227 \sa operator>>()
1228*/
1229
1230QTextStream &operator<<( QTextStream &ts, const QDockArea &dockArea )
1231{
1232 QString str;
1233 QPtrList<QDockWindow> l = dockArea.dockWindowList();
1234
1235 for ( QDockWindow *dw = l.first(); dw; dw = l.next() )
1236 str += "[" + QString( dw->caption() ) + "," + QString::number( (int)dw->offset() ) +
1237 "," + QString::number( (int)dw->newLine() ) + "," + QString::number( dw->fixedExtent().width() ) +
1238 "," + QString::number( dw->fixedExtent().height() ) + "," + QString::number( (int)!dw->isHidden() ) + "]";
1239 ts << str << endl;
1240
1241 return ts;
1242}
1243
1244/*!
1245 \relates QDockArea
1246
1247 Reads the layout description of the dock windows in dock area \a
1248 dockArea from the text stream \a ts and restores it. The layout
1249 description must have been previously written by the operator<<()
1250 function.
1251
1252 \sa operator<<()
1253*/
1254
1255QTextStream &operator>>( QTextStream &ts, QDockArea &dockArea )
1256{
1257 QString s = ts.readLine();
1258
1259 QString name, offset, newLine, width, height, visible;
1260
1261 enum State { Pre, Name, Offset, NewLine, Width, Height, Visible, Post };
1262 int state = Pre;
1263 QChar c;
1264 QPtrList<QDockWindow> l = dockArea.dockWindowList();
1265
1266 for ( int i = 0; i < (int)s.length(); ++i ) {
1267 c = s[ i ];
1268 if ( state == Pre && c == '[' ) {
1269 state++;
1270 continue;
1271 }
1272 if ( c == ',' &&
1273 ( state == Name || state == Offset || state == NewLine || state == Width || state == Height ) ) {
1274 state++;
1275 continue;
1276 }
1277 if ( state == Visible && c == ']' ) {
1278 for ( QDockWindow *dw = l.first(); dw; dw = l.next() ) {
1279 if ( QString( dw->caption() ) == name ) {
1280 dw->setNewLine( (bool)newLine.toInt() );
1281 dw->setOffset( offset.toInt() );
1282 dw->setFixedExtentWidth( width.toInt() );
1283 dw->setFixedExtentHeight( height.toInt() );
1284 if ( !(bool)visible.toInt() )
1285 dw->hide();
1286 else
1287 dw->show();
1288 break;
1289 }
1290 }
1291
1292 name = offset = newLine = width = height = visible = "";
1293
1294 state = Pre;
1295 continue;
1296 }
1297 if ( state == Name )
1298 name += c;
1299 else if ( state == Offset )
1300 offset += c;
1301 else if ( state == NewLine )
1302 newLine += c;
1303 else if ( state == Width )
1304 width += c;
1305 else if ( state == Height )
1306 height += c;
1307 else if ( state == Visible )
1308 visible += c;
1309 }
1310
1311 dockArea.QWidget::layout()->invalidate();
1312 dockArea.QWidget::layout()->activate();
1313 return ts;
1314}
1315#endif
1316
1317#endif //QT_NO_MAINWINDOW
Note: See TracBrowser for help on using the repository browser.