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