src/gui/widgets/qdockwidgetlayout.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "QtGui/qwidget.h"
00025 #include "QtGui/qtabbar.h"
00026 #include "QtGui/qstyle.h"
00027 #include "QtCore/qvariant.h"
00028 #include "qdockwidgetlayout_p.h"
00029 #include "qdockwidget.h"
00030 #include "qmainwindow.h"
00031 #include "qwidgetanimator_p.h"
00032 #include "qmainwindowlayout_p.h"
00033 #include "private/qlayoutengine_p.h"
00034 #include <qdebug.h>
00035 
00036 #include <qpainter.h>
00037 #include <qstyleoption.h>
00038 
00039 #ifndef QT_NO_DOCKWIDGET
00040 
00041 enum { StateFlagVisible = 1, StateFlagFloating = 2 };
00042 
00043 static void checkLayoutInfo(const QDockAreaLayoutInfo &info)
00044 {
00045     return;
00046     int pos = pick(info.o, info.rect.topLeft());
00047     bool prev_gap = false;
00048     bool first = true;
00049     for (int i = 0; i < info.item_list.size(); ++i) {
00050         const QDockAreaLayoutItem &item = info.item_list.at(i);
00051         if (item.skip())
00052             continue;
00053 
00054         bool gap = item.gap;
00055         if (!first && !gap && !prev_gap)
00056             pos += info.sep;
00057 
00058         if (item.pos != pos) {
00059             qDebug() << "##### checkLayoutInfo(): incorrect pos:"
00060                         << i << item.pos << pos;
00061         }
00062 
00063         pos += item.size;
00064 
00065         prev_gap = gap;
00066         first = false;
00067     }
00068 
00069     int bottom = pick(info.o, info.rect.bottomRight());
00070     --pos;
00071     if (pos != bottom) {
00072         qDebug() << "##### checkLayoutInfo(): incorrect bottom pos:"
00073                     << bottom << pos;
00074     }
00075 }
00076 
00077 /*
00078 #ifndef QT_NO_TEXTSTREAM
00079 
00080 static void dump(QDebug debug, const QDockAreaLayoutInfo &info, QString indent);
00081 static void dump(QDebug debug, const QDockWidgetLayout &layout);
00082 
00083 static void dump(QDebug debug, const QDockAreaLayoutItem &item, QString indent)
00084 {
00085     debug << (const char*) indent.toLocal8Bit();
00086     if (item.skip())
00087         debug << "skip";
00088     if (item.gap)
00089         debug << "gap";
00090     debug << item.pos << item.size;
00091     if (item.widgetItem != 0)
00092         debug << item.widgetItem->widget();
00093     else if (item.subinfo != 0)
00094         dump(debug, *item.subinfo, indent);
00095     debug << '\n';
00096 }
00097 
00098 static void dump(QDebug debug, const QDockAreaLayoutInfo &info, QString indent)
00099 {
00100     debug << "Info(";
00101     if (info.tabbed) {
00102         debug << "tabbed " << info.currentTabId();
00103         if (info.tabBar != 0)
00104             debug << "tabBar " << info.tabBar->count();
00105         if (info.tabBar != 0 && info.tabBar->isVisible())
00106             debug << "tabBarVisble";
00107     }
00108     debug << "\n";
00109     for (int i = 0; i < info.item_list.count(); ++i)
00110         dump(debug, info.item_list.at(i), indent + QLatin1String("  "));
00111     debug << (const char*) indent.toLocal8Bit() << ")\n";
00112 }
00113 
00114 static void dump(QDebug debug, const QDockWidgetLayout &layout)
00115 {
00116     debug << "Top " << layout.docks[QDockWidgetLayout::TopPos].rect << "\n";
00117     dump(debug, layout.docks[QDockWidgetLayout::TopPos], QString());
00118     debug << "Left " << layout.docks[QDockWidgetLayout::LeftPos].rect << "\n";
00119     dump(debug, layout.docks[QDockWidgetLayout::LeftPos], QString());
00120     debug << "Bottom " << layout.docks[QDockWidgetLayout::BottomPos].rect << "\n";
00121     dump(debug, layout.docks[QDockWidgetLayout::BottomPos], QString());
00122     debug << "Right " << layout.docks[QDockWidgetLayout::RightPos].rect << "\n";
00123     dump(debug, layout.docks[QDockWidgetLayout::RightPos], QString());
00124 }
00125 #endif // QT_NO_TEXTSTREAM
00126 */
00127 
00128 /******************************************************************************
00129 ** QDockAreaLayoutItem
00130 */
00131 
00132 QDockAreaLayoutItem::QDockAreaLayoutItem(QWidgetItem *_widgetItem)
00133     : widgetItem(_widgetItem), subinfo(0), pos(0), size(-1), gap(false),
00134         keep_size(false)
00135 {
00136 }
00137 
00138 QDockAreaLayoutItem::QDockAreaLayoutItem(QDockAreaLayoutInfo *_subinfo)
00139     : widgetItem(0), subinfo(_subinfo), pos(0), size(-1), gap(false),
00140         keep_size(false)
00141 {
00142 }
00143 
00144 QDockAreaLayoutItem::QDockAreaLayoutItem(const QDockAreaLayoutItem &other)
00145     : widgetItem(other.widgetItem), subinfo(0), pos(other.pos),
00146         size(other.size), gap(other.gap), keep_size(other.keep_size)
00147 {
00148     if (other.subinfo != 0)
00149         subinfo = new QDockAreaLayoutInfo(*other.subinfo);
00150     Q_ASSERT(widgetItem == 0 || subinfo == 0);
00151 }
00152 
00153 QDockAreaLayoutItem::~QDockAreaLayoutItem()
00154 {
00155     delete subinfo;
00156 }
00157 
00158 bool QDockAreaLayoutItem::skip() const
00159 {
00160     if (gap)
00161         return false;
00162 
00163     if (widgetItem != 0) {
00164         QWidget *widget = widgetItem->widget();
00165         return widget->isWindow() || widget->isHidden();
00166     }
00167 
00168     if (subinfo != 0) {
00169         for (int i = 0; i < subinfo->item_list.count(); ++i) {
00170             if (!subinfo->item_list.at(i).skip())
00171                 return false;
00172         }
00173     }
00174 
00175     return true;
00176 }
00177 
00178 static QSize adjustForFrame(QWidget *widget)
00179 {
00180     if (widget->isWindow())
00181         return QSize(0, 0);
00182     int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth);
00183     QSize result(2*fw, fw);
00184 #ifdef Q_OS_WIN
00185     result += QSize(0, 3);
00186 #endif
00187     return result;
00188 }
00189 
00190 QSize QDockAreaLayoutItem::minimumSize() const
00191 {
00192     if (widgetItem != 0)
00193         return qSmartMinSize(widgetItem) + adjustForFrame(widgetItem->widget());
00194     if (subinfo != 0)
00195         return subinfo->minimumSize();
00196     return QSize(0, 0);
00197 }
00198 
00199 QSize QDockAreaLayoutItem::maximumSize() const
00200 {
00201     if (widgetItem != 0)
00202         return qSmartMaxSize(widgetItem);
00203     if (subinfo != 0)
00204         return subinfo->maximumSize();
00205     return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
00206 }
00207 
00208 bool QDockAreaLayoutItem::expansive(Qt::Orientation o) const
00209 {
00210     if (gap)
00211         return false;
00212     if (widgetItem != 0)
00213         return ((widgetItem->expandingDirections() & o) == o);
00214     if (subinfo != 0)
00215         return subinfo->expansive(o);
00216     return false;
00217 }
00218 
00219 QSize QDockAreaLayoutItem::sizeHint() const
00220 {
00221     if (widgetItem != 0) {
00222         QWidget *w = widgetItem->widget();
00223         QSize s = w->sizeHint().expandedTo(w->minimumSizeHint());
00224         if (w->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
00225             s.setWidth(0);
00226         if (w->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
00227             s.setHeight(0);
00228         s = s.boundedTo(w->maximumSize())
00229             .expandedTo(w->minimumSize());
00230 
00231         s += adjustForFrame(w);
00232         return s;
00233     }
00234     if (subinfo != 0)
00235         return subinfo->sizeHint();
00236     return QSize(-1, -1);
00237 }
00238 
00239 QDockAreaLayoutItem
00240     &QDockAreaLayoutItem::operator = (const QDockAreaLayoutItem &other)
00241 {
00242     widgetItem = other.widgetItem;
00243     if (other.subinfo == 0)
00244         subinfo = 0;
00245     else
00246         subinfo = new QDockAreaLayoutInfo(*other.subinfo);
00247     pos = other.pos;
00248     size = other.size;
00249     gap = other.gap;
00250 
00251     return *this;
00252 }
00253 
00254 /******************************************************************************
00255 ** QDockAreaLayoutInfo
00256 */
00257 
00258 static quintptr tabId(const QDockAreaLayoutItem &item)
00259 {
00260     if (item.widgetItem == 0)
00261         return 0;
00262     return reinterpret_cast<quintptr>(item.widgetItem->widget());
00263 }
00264 
00265 QDockAreaLayoutInfo::QDockAreaLayoutInfo()
00266     : sep(0), o(Qt::Horizontal), rect(0, 0, -1, -1), mainWindow(0)
00267 #ifndef QT_NO_TABBAR
00268     , tabbed(false), tabBar(0), tabBarShape(-1)
00269 #endif
00270 {
00271 }
00272 
00273 QDockAreaLayoutInfo::QDockAreaLayoutInfo(int _sep, Qt::Orientation _o, int tbshape,
00274                                             QMainWindow *window)
00275     : sep(_sep), o(_o), rect(0, 0, -1, -1), mainWindow(window)
00276 #ifndef QT_NO_TABBAR
00277     , tabbed(false), tabBar(0), tabBarShape(tbshape)
00278 #endif
00279 {
00280 #ifdef QT_NO_TABBAR
00281     Q_UNUSED(tbshape);
00282 #endif
00283 }
00284 
00285 QSize QDockAreaLayoutInfo::size() const
00286 {
00287     return isEmpty() ? QSize(0, 0) : rect.size();
00288 }
00289 
00290 void QDockAreaLayoutInfo::clear()
00291 {
00292     item_list.clear();
00293     rect = QRect(0, 0, -1, -1);
00294 #ifndef QT_NO_TABBAR
00295     tabbed = false;
00296     tabBar = 0;
00297 #endif
00298 }
00299 
00300 bool QDockAreaLayoutInfo::isEmpty() const
00301 {
00302     return next(-1) == -1;
00303 }
00304 
00305 QSize QDockAreaLayoutInfo::minimumSize() const
00306 {
00307     if (isEmpty())
00308         return QSize(0, 0);
00309 
00310     int a = 0, b = 0;
00311     bool first = true;
00312     for (int i = 0; i < item_list.size(); ++i) {
00313         const QDockAreaLayoutItem &item = item_list.at(i);
00314         if (item.skip())
00315             continue;
00316 
00317         QSize min_size = item.minimumSize();
00318 #ifndef QT_NO_TABBAR
00319         if (tabbed) {
00320             a = qMax(a, pick(o, min_size));
00321         } else
00322 #endif
00323         {
00324             if (!first)
00325                 a += sep;
00326             a += pick(o, min_size);
00327         }
00328         b = qMax(b, perp(o, min_size));
00329 
00330         first = false;
00331     }
00332 
00333     QSize result;
00334     rpick(o, result) = a;
00335     rperp(o, result) = b;
00336 
00337 #ifndef QT_NO_TABBAR
00338     if (tabbed) {
00339         QSize tbm = tabBarMinimumSize();
00340         switch (tabBarShape) {
00341             case QTabBar::RoundedNorth:
00342             case QTabBar::RoundedSouth:
00343                 result.rheight() += tbm.height();
00344                 result.rwidth() = qMax(tbm.width(), result.width());
00345                 break;
00346             case QTabBar::RoundedEast:
00347             case QTabBar::RoundedWest:
00348                 result.rheight() = qMax(tbm.height(), result.height());
00349                 result.rwidth() += tbm.width();
00350                 break;
00351             default:
00352                 break;
00353         }
00354     }
00355 #endif // QT_NO_TABBAR
00356 
00357     return result;
00358 }
00359 
00360 QSize QDockAreaLayoutInfo::maximumSize() const
00361 {
00362     if (isEmpty())
00363         return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
00364 
00365     int a = 0, b = QWIDGETSIZE_MAX;
00366 #ifndef QT_NO_TABBAR
00367     if (tabbed)
00368         a = QWIDGETSIZE_MAX;
00369 #endif
00370 
00371     bool first = true;
00372     for (int i = 0; i < item_list.size(); ++i) {
00373         const QDockAreaLayoutItem &item = item_list.at(i);
00374         if (item.skip())
00375             continue;
00376 
00377 
00378         QSize max_size = item.maximumSize();
00379 
00380 #ifndef QT_NO_TABBAR
00381         if (tabbed) {
00382             a = qMin(a, pick(o, max_size));
00383         } else
00384 #endif
00385         {
00386             if (!first)
00387                 a += sep;
00388             a += pick(o, max_size);
00389         }
00390         b = qMin(b, perp(o, max_size));
00391 
00392         a = qMin(a, int(QWIDGETSIZE_MAX));
00393         b = qMin(b, int(QWIDGETSIZE_MAX));
00394 
00395         first = false;
00396     }
00397 
00398     QSize result;
00399     rpick(o, result) = a;
00400     rperp(o, result) = b;
00401 
00402 #ifndef QT_NO_TABBAR
00403     if (tabbed) {
00404         QSize tbh = tabBarSizeHint();
00405         switch (tabBarShape) {
00406             case QTabBar::RoundedNorth:
00407             case QTabBar::RoundedSouth:
00408                 result.rheight() += tbh.height();
00409                 break;
00410             case QTabBar::RoundedEast:
00411             case QTabBar::RoundedWest:
00412                 result.rwidth() += tbh.width();
00413                 break;
00414             default:
00415                 break;
00416         }
00417     }
00418 #endif // QT_NO_TABBAR
00419 
00420     return result;
00421 }
00422 
00423 QSize QDockAreaLayoutInfo::sizeHint() const
00424 {
00425     if (isEmpty())
00426         return QSize(0, 0);
00427 
00428     int a = 0, b = 0;
00429     bool prev_gap = false;
00430     bool first = true;
00431     for (int i = 0; i < item_list.size(); ++i) {
00432         const QDockAreaLayoutItem &item = item_list.at(i);
00433         if (item.skip())
00434             continue;
00435 
00436         bool gap = item.gap;
00437 
00438         QSize size_hint = item.sizeHint();
00439 
00440 #ifndef QT_NO_TABBAR
00441         if (tabbed) {
00442             a = qMax(a, gap ? item.size : pick(o, size_hint));
00443         } else
00444 #endif
00445         {
00446             if (!first && !gap && !prev_gap)
00447                 a += sep;
00448             a += gap ? item.size : pick(o, size_hint);
00449         }
00450         b = qMax(b, perp(o, size_hint));
00451 
00452         prev_gap = gap;
00453         first = false;
00454     }
00455 
00456     QSize result;
00457     rpick(o, result) = a;
00458     rperp(o, result) = b;
00459 
00460 #ifndef QT_NO_TABBAR
00461     if (tabbed) {
00462         QSize tbh = tabBarSizeHint();
00463         switch (tabBarShape) {
00464             case QTabBar::RoundedNorth:
00465             case QTabBar::RoundedSouth:
00466                 result.rheight() += tbh.height();
00467                 result.rwidth() = qMax(tbh.width(), result.width());
00468                 break;
00469             case QTabBar::RoundedEast:
00470             case QTabBar::RoundedWest:
00471                 result.rheight() = qMax(tbh.height(), result.height());
00472                 result.rwidth() += tbh.width();
00473                 break;
00474             default:
00475                 break;
00476         }
00477     }
00478 #endif // QT_NO_TABBAR
00479 
00480     return result;
00481 }
00482 
00483 bool QDockAreaLayoutInfo::expansive(Qt::Orientation o) const
00484 {
00485     for (int i = 0; i < item_list.size(); ++i) {
00486         if (item_list.at(i).expansive(o))
00487             return true;
00488     }
00489     return false;
00490 }
00491 
00492 void QDockAreaLayoutInfo::fitItems()
00493 {
00494 #ifndef QT_NO_TABBAR
00495     if (tabbed) {
00496         return;
00497     }
00498 #endif
00499 
00500     QVector<QLayoutStruct> layout_struct_list(item_list.size()*2);
00501     int j = 0;
00502 
00503     int size = pick(o, rect.size());
00504     int min_size = pick(o, minimumSize());
00505 
00506     bool prev_gap = false;
00507     bool first = true;
00508     for (int i = 0; i < item_list.size(); ++i) {
00509         QDockAreaLayoutItem &item = item_list[i];
00510         if (item.skip())
00511             continue;
00512 
00513         bool gap = item.gap;
00514         if (!first && !gap && !prev_gap) {
00515             QLayoutStruct &ls = layout_struct_list[j++];
00516             ls.empty = false;
00517             ls.init();
00518             ls.minimumSize = sep;
00519             ls.maximumSize = sep;
00520             ls.sizeHint = sep;
00521         }
00522 
00523         if (item.keep_size) {
00524             int d = item.size - pick(o, item.minimumSize());
00525             if (min_size + d <= size)
00526                 min_size -= d;
00527             else
00528                 item.keep_size = false; // sorry, not enough space
00529         }
00530 
00531         QLayoutStruct &ls = layout_struct_list[j++];
00532         ls.init();
00533         ls.empty = false;
00534         if (gap || item.keep_size) {
00535             ls.minimumSize = ls.maximumSize = ls.sizeHint = item.size;
00536             ls.expansive = false;
00537             ls.stretch = 0;
00538         } else {
00539             ls.minimumSize = pick(o, item.minimumSize());
00540             ls.maximumSize = pick(o, item.maximumSize());
00541             ls.expansive = item.expansive(o);
00542             if (ls.expansive) {
00543                 ls.sizeHint = ls.minimumSize;
00544                 ls.stretch = item.size == -1 ? pick(o, item.sizeHint()) : item.size;
00545             } else {
00546                 ls.sizeHint = item.size == -1 ? pick(o, item.sizeHint()) : item.size;
00547             }
00548         }
00549 
00550         item.keep_size = false;
00551         prev_gap = gap;
00552         first = false;
00553     }
00554     layout_struct_list.resize(j);
00555 
00556     qGeomCalc(layout_struct_list, 0, j, pick(o, rect.topLeft()), size, 0);
00557 
00558     j = 0;
00559     prev_gap = false;
00560     first = true;
00561     for (int i = 0; i < item_list.size(); ++i) {
00562         QDockAreaLayoutItem &item = item_list[i];
00563         if (item.skip())
00564             continue;
00565 
00566         bool gap = item.gap;
00567         if (!first && !gap && !prev_gap)
00568             ++j;
00569 
00570         const QLayoutStruct &ls = layout_struct_list.at(j++);
00571         item.size = ls.size;
00572         item.pos = ls.pos;
00573 
00574         if (item.subinfo != 0) {
00575             item.subinfo->rect = itemRect(i);
00576             item.subinfo->fitItems();
00577         }
00578 
00579         prev_gap = gap;
00580         first = false;
00581     }
00582 
00583     checkLayoutInfo(*this);
00584 }
00585 
00586 static QDockWidgetLayout::DockPos dockPos(const QRect &rect, const QPoint &_pos,
00587                                                 Qt::Orientation o, bool nestingEnabled)
00588 {
00589     QPoint pos = _pos - rect.topLeft();
00590 
00591     int x = pos.x();
00592     int y = pos.y();
00593     int w = rect.width();
00594     int h = rect.height();
00595 
00596     // is it in the center?
00597     if (nestingEnabled) {
00598     /*             2/3
00599             +--------------+
00600             |              |
00601             |   CCCCCCCC   |
00602        2/3  |   CCCCCCCC   |
00603             |   CCCCCCCC   |
00604             |              |
00605             +--------------+     */
00606 
00607         QRect center(w/6, h/6, 2*w/3, 2*h/3);
00608         if (center.contains(pos))
00609             return QDockWidgetLayout::CenterPos;
00610     } else if (o == Qt::Horizontal) {
00611     /*             2/3
00612             +--------------+
00613             |   CCCCCCCC   |
00614             |   CCCCCCCC   |
00615             |   CCCCCCCC   |
00616             |   CCCCCCCC   |
00617             |   CCCCCCCC   |
00618             +--------------+     */
00619 
00620         if (x > w/6 && x < w*5/6)
00621             return QDockWidgetLayout::CenterPos;
00622     } else {
00623      /*
00624             +--------------+
00625             |              |
00626        2/3  |CCCCCCCCCCCCCC|
00627             |CCCCCCCCCCCCCC|
00628             |              |
00629             +--------------+     */
00630         if (y > h/6 && y < 5*h/6)
00631             return QDockWidgetLayout::CenterPos;
00632     }
00633 
00634     // not in the center. which edge?
00635     if (nestingEnabled) {
00636         if (o == Qt::Horizontal) {
00637     /*       1/3  1/3 1/3
00638             +------------+     (we've already ruled out the center)
00639             |LLLLTTTTRRRR|
00640             |LLLLTTTTRRRR|
00641             |LLLLBBBBRRRR|
00642             |LLLLBBBBRRRR|
00643             +------------+    */
00644 
00645             if (x < w/3)
00646                 return QDockWidgetLayout::LeftPos;
00647             if (x > 2*w/3)
00648                 return QDockWidgetLayout::RightPos;
00649             if (y < h/2)
00650                 return QDockWidgetLayout::TopPos;
00651             return QDockWidgetLayout::BottomPos;
00652         } else {
00653     /*      +------------+     (we've already ruled out the center)
00654         1/3 |TTTTTTTTTTTT|
00655             |LLLLLLRRRRRR|
00656         1/3 |LLLLLLRRRRRR|
00657         1/3 |BBBBBBBBBBBB|
00658             +------------+    */
00659 
00660             if (y < h/3)
00661                 return QDockWidgetLayout::TopPos;
00662             if (y > 2*h/3)
00663                 return QDockWidgetLayout::BottomPos;
00664             if (x < w/2)
00665                 return QDockWidgetLayout::LeftPos;
00666             return QDockWidgetLayout::RightPos;
00667         }
00668     } else {
00669         if (o == Qt::Horizontal) {
00670             return x < w/2
00671                     ? QDockWidgetLayout::LeftPos
00672                     : QDockWidgetLayout::RightPos;
00673         } else {
00674             return y < h/2
00675                     ? QDockWidgetLayout::TopPos
00676                     : QDockWidgetLayout::BottomPos;
00677         }
00678     }
00679 }
00680 
00681 QList<int> QDockAreaLayoutInfo::gapIndex(const QPoint& _pos, bool nestingEnabled) const
00682 {
00683     QList<int> result;
00684     QRect item_rect;
00685     int item_index = 0;
00686 
00687 #ifndef QT_NO_TABBAR
00688     if (tabbed) {
00689         item_rect = tabContentRect();
00690     } else
00691 #endif
00692     {
00693         int pos = pick(o, _pos);
00694 
00695         int last = -1;
00696         for (int i = 0; i < item_list.size(); ++i) {
00697             const QDockAreaLayoutItem &item = item_list.at(i);
00698             if (item.skip())
00699                 continue;
00700 
00701             last = i;
00702 
00703             if (item.pos + item.size < pos)
00704                 continue;
00705 
00706             if (item.subinfo != 0
00707 #ifndef QT_NO_TABBAR
00708                 && !item.subinfo->tabbed
00709 #endif
00710                 ) {
00711                 result = item.subinfo->gapIndex(_pos, nestingEnabled);
00712                 result.prepend(i);
00713                 return result;
00714             }
00715 
00716             item_rect = itemRect(i);
00717             item_index = i;
00718             break;
00719         }
00720 
00721         if (item_rect.isNull()) {
00722             result.append(last + 1);
00723             return result;
00724         }
00725     }
00726 
00727     Q_ASSERT(!item_rect.isNull());
00728 
00729     QDockWidgetLayout::DockPos dock_pos
00730         = dockPos(item_rect, _pos, o, nestingEnabled);
00731 
00732     switch (dock_pos) {
00733         case QDockWidgetLayout::LeftPos:
00734             if (o == Qt::Horizontal)
00735                 result << item_index;
00736             else
00737                 result << item_index << 0; // this subinfo doesn't exist yet, but insertGap()
00738                                            // handles this by inserting it
00739             break;
00740         case QDockWidgetLayout::RightPos:
00741             if (o == Qt::Horizontal)
00742                 result << item_index + 1;
00743             else
00744                 result << item_index << 1;
00745             break;
00746         case QDockWidgetLayout::TopPos:
00747             if (o == Qt::Horizontal)
00748                 result << item_index << 0;
00749             else
00750                 result << item_index;
00751             break;
00752         case QDockWidgetLayout::BottomPos:
00753             if (o == Qt::Horizontal)
00754                 result << item_index << 1;
00755             else
00756                 result << item_index + 1;
00757             break;
00758         case QDockWidgetLayout::CenterPos:
00759             result << (-item_index - 1) << 0;   // negative item_index means "on top of"
00760                                                 // -item_index - 1, insertGap()
00761                                                 // will insert a tabbed subinfo
00762             break;
00763         default:
00764             break;
00765     }
00766 
00767     return result;
00768 }
00769 
00770 static inline int shrink(QLayoutStruct &ls, int delta)
00771 {
00772     if (ls.empty)
00773         return 0;
00774     int old_size = ls.size;
00775     ls.size = qMax(ls.size - delta, ls.minimumSize);
00776     return old_size - ls.size;
00777 }
00778 
00779 static inline int grow(QLayoutStruct &ls, int delta)
00780 {
00781     if (ls.empty)
00782         return 0;
00783     int old_size = ls.size;
00784     ls.size = qMin(ls.size + delta, ls.maximumSize);
00785     return ls.size - old_size;
00786 }
00787 
00788 static int separatorMove(QVector<QLayoutStruct> &list, int index, int delta, int sep)
00789 {
00790     // adjust sizes
00791     int pos = -1;
00792     for (int i = 0; i < list.size(); ++i) {
00793         const QLayoutStruct &ls = list.at(i);
00794         if (!ls.empty) {
00795             pos = ls.pos;
00796             break;
00797         }
00798     }
00799     if (pos == -1)
00800         return 0;
00801 
00802     if (delta > 0) {
00803         int growlimit = 0;
00804         for (int i = 0; i<=index; ++i) {
00805             const QLayoutStruct &ls = list.at(i);
00806             if (ls.empty)
00807                 continue;
00808             if (ls.maximumSize == QLAYOUTSIZE_MAX) {
00809                 growlimit = QLAYOUTSIZE_MAX;
00810                 break;
00811             }
00812             growlimit += ls.maximumSize - ls.size;
00813         }
00814         if (delta > growlimit)
00815             delta = growlimit;
00816 
00817         int d = 0;
00818         for (int i = index + 1; d < delta && i < list.count(); ++i)
00819             d += shrink(list[i], delta - d);
00820         delta = d;
00821         d = 0;
00822         for (int i = index; d < delta && i >= 0; --i)
00823             d += grow(list[i], delta - d);
00824     } else if (delta < 0) {
00825         int growlimit = 0;
00826         for (int i = index + 1; i < list.count(); ++i) {
00827             const QLayoutStruct &ls = list.at(i);
00828             if (ls.empty)
00829                 continue;
00830             if (ls.maximumSize == QLAYOUTSIZE_MAX) {
00831                 growlimit = QLAYOUTSIZE_MAX;
00832                 break;
00833             }
00834             growlimit += ls.maximumSize - ls.size;
00835         }
00836         if (-delta > growlimit)
00837             delta = -growlimit;
00838 
00839         int d = 0;
00840         for (int i = index; d < -delta && i >= 0; --i)
00841             d += shrink(list[i], -delta - d);
00842         delta = -d;
00843         d = 0;
00844         for (int i = index + 1; d < -delta && i < list.count(); ++i)
00845             d += grow(list[i], -delta - d);
00846     }
00847 
00848     // adjust positions
00849     bool first = true;
00850     for (int i = 0; i < list.size(); ++i) {
00851         QLayoutStruct &ls = list[i];
00852         if (ls.empty)
00853             continue;
00854         if (!first)
00855             pos += sep;
00856         ls.pos = pos;
00857         pos += ls.size;
00858         first = false;
00859     }
00860 
00861     return delta;
00862 }
00863 
00864 int QDockAreaLayoutInfo::separatorMove(int index, int delta, QVector<QLayoutStruct> *cache)
00865 {
00866     Q_ASSERT(!tabbed);
00867 
00868     if (cache->isEmpty()) {
00869         QVector<QLayoutStruct> &list = *cache;
00870         list.resize(item_list.size());
00871         for (int i = 0; i < item_list.size(); ++i) {
00872             const QDockAreaLayoutItem &item = item_list.at(i);
00873             QLayoutStruct &ls = list[i];
00874             Q_ASSERT(!item.gap);
00875             if (item.skip()) {
00876                 ls.empty = true;
00877             } else {
00878                 ls.empty = false;
00879                 ls.pos = item.pos;
00880                 ls.size = item.size;
00881                 ls.minimumSize = pick(o, item.minimumSize());
00882                 ls.maximumSize = pick(o, item.maximumSize());
00883             }
00884         }
00885     }
00886 
00887     QVector<QLayoutStruct> list = *cache;
00888 
00889     delta = ::separatorMove(list, index, delta, sep);
00890 
00891     for (int i = 0; i < item_list.size(); ++i) {
00892         QDockAreaLayoutItem &item = item_list[i];
00893         if (item.skip())
00894             continue;
00895         QLayoutStruct &ls = list[i];
00896         item.size = ls.size;
00897         item.pos = ls.pos;
00898 
00899         if (item.subinfo != 0) {
00900             item.subinfo->rect = itemRect(i);
00901             item.subinfo->fitItems();
00902         }
00903     }
00904 
00905     return delta;
00906 }
00907 
00908 void QDockAreaLayoutInfo::unnest(int index)
00909 {
00910     QDockAreaLayoutItem &item = item_list[index];
00911     if (item.subinfo == 0)
00912         return;
00913     if (item.subinfo->item_list.count() > 1)
00914         return;
00915     Q_ASSERT(item.subinfo->item_list.count() != 0);
00916 
00917     if (item.subinfo->item_list.count() == 1) {
00918         QDockAreaLayoutItem &child = item.subinfo->item_list.first();
00919         if (child.widgetItem != 0) {
00920             item.widgetItem = child.widgetItem;
00921             delete item.subinfo;
00922             item.subinfo = 0;
00923         } else if (child.subinfo != 0) {
00924             QDockAreaLayoutInfo *tmp = item.subinfo;
00925             item.subinfo = child.subinfo;
00926             child.subinfo = 0;
00927             tmp->item_list.clear();
00928             delete tmp;
00929         }
00930     }
00931 }
00932 
00933 void QDockAreaLayoutInfo::remove(QList<int> path)
00934 {
00935     Q_ASSERT(!path.isEmpty());
00936 
00937     if (path.count() > 1) {
00938         int index = path.takeFirst();
00939         QDockAreaLayoutItem &item = item_list[index];
00940         Q_ASSERT(item.subinfo != 0);
00941         item.subinfo->remove(path);
00942         unnest(index);
00943     } else {
00944         int index = path.first();
00945         item_list.removeAt(index);
00946     }
00947 }
00948 
00949 QRect QDockAreaLayoutInfo::convertToWidget(QList<int> path, QWidgetItem *dockWidgetItem)
00950 {
00951     Q_ASSERT(!path.isEmpty());
00952 
00953     int index = path.takeFirst();
00954     if (index < 0)
00955         index = -index - 1;
00956 
00957     if (!path.isEmpty()) {
00958         const QDockAreaLayoutItem &item = item_list.at(index);
00959         Q_ASSERT(item.subinfo != 0);
00960         return item.subinfo->convertToWidget(path, dockWidgetItem);
00961     }
00962 
00963     QDockAreaLayoutItem &item = item_list[index];
00964 
00965     Q_ASSERT(item.gap);
00966     item.gap = false;
00967     Q_ASSERT(item.widgetItem == dockWidgetItem);
00968 
00969     QRect result;
00970 
00971 #ifndef QT_NO_TABBAR
00972     if (tabbed) {
00973         result = tabContentRect();
00974     } else
00975 #endif
00976     {
00977         int prev = this->prev(index);
00978         int next = this->next(index);
00979 
00980         if (prev != -1 && !item_list.at(prev).gap) {
00981             item.pos += sep;
00982             item.size -= sep;
00983         }
00984         if (next != -1 && !item_list.at(next).gap)
00985             item.size -= sep;
00986 
00987         QPoint pos;
00988         rpick(o, pos) = item.pos;
00989         rperp(o, pos) = perp(o, rect.topLeft());
00990         QSize s;
00991         rpick(o, s) = item.size;
00992         rperp(o, s) = perp(o, rect.size());
00993         result = QRect(pos, s);
00994     }
00995 
00996     return result;
00997 }
00998 
00999 QWidgetItem *QDockAreaLayoutInfo::convertToGap(QList<int> path)
01000 {
01001     Q_ASSERT(!path.isEmpty());
01002 
01003     if (path.count() > 1) {
01004         int index = path.takeFirst();
01005         const QDockAreaLayoutItem &item = item_list.at(index);
01006         Q_ASSERT(item.subinfo != 0);
01007         QWidgetItem *result = item.subinfo->convertToGap(path);
01008         return result;
01009     }
01010 
01011     int index = path.first();
01012     QDockAreaLayoutItem &item = item_list[index];
01013     int prev = this->prev(index);
01014     int next = this->next(index);
01015 
01016     Q_ASSERT(!item.gap);
01017     item.gap = true;
01018 
01019 #ifndef QT_NO_TABBAR
01020     if (tabbed) {
01021     } else
01022 #endif
01023     {
01024         if (prev != -1 && !item_list.at(prev).gap) {
01025             item.pos -= sep;
01026             item.size += sep;
01027         }
01028         if (next != -1 && !item_list.at(next).gap)
01029             item.size += sep;
01030     }
01031 
01032     return item.widgetItem;
01033 }
01034 
01035 #ifndef QT_NO_TABBAR
01036 
01037 quintptr QDockAreaLayoutInfo::currentTabId() const
01038 {
01039     if (!tabbed || tabBar == 0)
01040         return 0;
01041 
01042     int index = tabBar->currentIndex();
01043     if (index == -1)
01044         return 0;
01045 
01046     return qvariant_cast<quintptr>(tabBar->tabData(index));
01047 }
01048 
01049 void QDockAreaLayoutInfo::setCurrentTab(QWidget *widget)
01050 {
01051     setCurrentTabId(reinterpret_cast<quintptr>(widget));
01052 }
01053 
01054 void QDockAreaLayoutInfo::setCurrentTabId(quintptr id)
01055 {
01056     if (!tabbed || tabBar == 0)
01057         return;
01058 
01059     for (int i = 0; i < tabBar->count(); ++i) {
01060         if (qvariant_cast<quintptr>(tabBar->tabData(i)) == id) {
01061             tabBar->setCurrentIndex(i);
01062             return;
01063         }
01064     }
01065 
01066     qDebug("QDockAreaLayoutInfo::setCurrentTabId(): not found!");
01067 }
01068 
01069 #endif // QT_NO_TABBAR
01070 
01071 bool QDockAreaLayoutInfo::insertGap(QList<int> path, QWidgetItem *dockWidgetItem)
01072 {
01073     Q_ASSERT(!path.isEmpty());
01074 
01075     bool insert_tabbed = false;
01076     int index = path.takeFirst();
01077     if (index < 0) {
01078         insert_tabbed = true;
01079         index = -index - 1;
01080     }
01081 
01082 //    dump(qDebug() << "insertGap() before:" << index << tabIndex, *this, QString());
01083 
01084     if (!path.isEmpty()) {
01085         QDockAreaLayoutItem &item = item_list[index];
01086 
01087         if (item.subinfo == 0
01088 #ifndef QT_NO_TABBAR
01089             || item.subinfo->tabbed && !insert_tabbed
01090 #endif
01091             ) {
01092             // this is not yet a nested layout - make it
01093 
01094             QDockAreaLayoutInfo *subinfo = item.subinfo;
01095             QWidgetItem *widgetItem = item.widgetItem;
01096             QRect r = subinfo == 0 ? widgetItem->geometry() : subinfo->rect;
01097 
01098             Qt::Orientation opposite = o == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal;
01099 #ifdef QT_NO_TABBAR
01100             const int tabBarShape = 0;
01101 #endif
01102             QDockAreaLayoutInfo *new_info
01103                 = new QDockAreaLayoutInfo(sep, opposite, tabBarShape, mainWindow);
01104 
01105             item.subinfo = new_info;
01106             item.widgetItem = 0;
01107 
01108             QDockAreaLayoutItem new_item
01109                 = widgetItem == 0
01110                     ? QDockAreaLayoutItem(subinfo)
01111                     : QDockAreaLayoutItem(widgetItem);
01112             new_item.size = pick(opposite, r.size());
01113             new_item.pos = pick(opposite, r.topLeft());
01114             new_info->item_list.append(new_item);
01115 #ifndef QT_NO_TABBAR
01116             if (insert_tabbed) {
01117                 new_info->tabbed = true;
01118             }
01119 #endif
01120         }
01121 
01122         bool result = item.subinfo->insertGap(path, dockWidgetItem);
01123         return result;
01124     }
01125 
01126     // create the gap item
01127     QDockAreaLayoutItem gap_item;
01128     gap_item.gap = true;
01129     gap_item.widgetItem = dockWidgetItem;   // so minimumSize(), maximumSize() and
01130                                             // sizeHint() will work
01131 #ifndef QT_NO_TABBAR
01132     if (!tabbed)
01133 #endif
01134     {
01135         int prev = this->prev(index);
01136         int next = this->next(index - 1);
01137         // find out how much space we have in the layout
01138         int space = 0;
01139         if (isEmpty()) {
01140             space = pick(o, rect.size());
01141         } else {
01142             for (int i = 0; i < item_list.count(); ++i) {
01143                 const QDockAreaLayoutItem &item = item_list.at(i);
01144                 if (item.skip())
01145                     continue;
01146                 Q_ASSERT(!item.gap);
01147                 space += item.size - pick(o, item.minimumSize());
01148             }
01149         }
01150 
01151         // find the actual size of the gap
01152         int gap_size = 0;
01153         int sep_size = 0;
01154         if (isEmpty()) {
01155             gap_size = space;
01156             sep_size = 0;
01157         } else {
01158             gap_size = pick(o, dockWidgetItem->geometry().size());
01159             if (prev != -1 && !item_list.at(prev).gap)
01160                 sep_size += sep;
01161             if (next != -1 && !item_list.at(next).gap)
01162                 sep_size += sep;
01163         }
01164         if (gap_size + sep_size > space)
01165             gap_size = pick(o, gap_item.minimumSize());
01166         gap_item.size = gap_size + sep_size;
01167     }
01168 
01169     // finally, insert the gap
01170     item_list.insert(index, gap_item);
01171 
01172 //    dump(qDebug() << "insertGap() after:" << index << tabIndex, *this, QString());
01173 
01174     return true;
01175 }
01176 
01177 QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(QWidget *widget)
01178 {
01179     for (int i = 0; i < item_list.count(); ++i) {
01180         const QDockAreaLayoutItem &item = item_list.at(i);
01181         if (item.skip())
01182             continue;
01183 
01184 #ifndef QT_NO_TABBAR
01185         if (tabbed && widget == tabBar)
01186             return this;
01187 #endif
01188 
01189         if (item.widgetItem != 0 && item.widgetItem->widget() == widget)
01190             return this;
01191 
01192         if (item.subinfo != 0) {
01193             if (QDockAreaLayoutInfo *result = item.subinfo->info(widget))
01194                 return result;
01195         }
01196     }
01197 
01198     return 0;
01199 }
01200 
01201 QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(QList<int> path)
01202 {
01203     int index = path.takeFirst();
01204     if (index < 0)
01205         index = -index - 1;
01206     if (index >= item_list.count())
01207         return this;
01208     if (path.isEmpty() || item_list.at(index).subinfo == 0)
01209         return this;
01210     return item_list.at(index).subinfo->info(path);
01211 }
01212 
01213 QRect QDockAreaLayoutInfo::itemRect(int index) const
01214 {
01215     const QDockAreaLayoutItem &item = item_list.at(index);
01216 
01217     if (item.skip())
01218         return QRect();
01219 
01220     QRect result;
01221 
01222 #ifndef QT_NO_TABBAR
01223     if (tabbed) {
01224         if (tabId(item) == currentTabId())
01225             result = tabContentRect();
01226     } else
01227 #endif
01228     {
01229         QPoint pos;
01230         rpick(o, pos) = item.pos;
01231         rperp(o, pos) = perp(o, rect.topLeft());
01232         QSize s;
01233         rpick(o, s) = item.size;
01234         rperp(o, s) = perp(o, rect.size());
01235         result = QRect(pos, s);
01236     }
01237 
01238     return result;
01239 }
01240 
01241 QRect QDockAreaLayoutInfo::itemRect(QList<int> path) const
01242 {
01243     Q_ASSERT(!path.isEmpty());
01244 
01245     if (path.count() > 1) {
01246         const QDockAreaLayoutItem &item = item_list.at(path.takeFirst());
01247         Q_ASSERT(item.subinfo != 0);
01248         return item.subinfo->itemRect(path);
01249     }
01250 
01251     return itemRect(path.first());
01252 }
01253 
01254 QRect QDockAreaLayoutInfo::separatorRect(int index) const
01255 {
01256 #ifndef QT_NO_TABBAR
01257     if (tabbed)
01258         return QRect();
01259 #endif
01260 
01261     const QDockAreaLayoutItem &item = item_list.at(index);
01262     if (item.skip())
01263         return QRect();
01264 
01265     QPoint pos = rect.topLeft();
01266     rpick(o, pos) = item.pos + item.size;
01267     QSize s = rect.size();
01268     rpick(o, s) = sep;
01269 
01270     return QRect(pos, s);
01271 }
01272 
01273 QRect QDockAreaLayoutInfo::separatorRect(QList<int> path) const
01274 {
01275     Q_ASSERT(!path.isEmpty());
01276 
01277     if (path.count() > 1) {
01278         const QDockAreaLayoutItem &item = item_list.at(path.takeFirst());
01279         Q_ASSERT(item.subinfo != 0);
01280         return item.subinfo->separatorRect(path);
01281     }
01282     return separatorRect(path.first());
01283 }
01284 
01285 QList<int> QDockAreaLayoutInfo::findSeparator(const QPoint &_pos) const
01286 {
01287 #ifndef QT_NO_TABBAR
01288     if (tabbed)
01289         return QList<int>();
01290 #endif
01291 
01292     int pos = pick(o, _pos);
01293 
01294     for (int i = 0; i < item_list.size(); ++i) {
01295         const QDockAreaLayoutItem &item = item_list.at(i);
01296         if (item.skip() || item.gap)
01297             continue;
01298 
01299         if (item.pos + item.size > pos) {
01300             if (item.subinfo != 0) {
01301                 QList<int> result = item.subinfo->findSeparator(_pos);
01302                 if (!result.isEmpty()) {
01303                     result.prepend(i);
01304                     return result;
01305                 } else {
01306                     return QList<int>();
01307                 }
01308             }
01309         }
01310 
01311         int next = this->next(i);
01312         if (next == -1 || item_list.at(next).gap)
01313             continue;
01314 
01315         if (pos > item.pos + item.size && item.pos + item.size + sep > pos) {
01316             QList<int> result;
01317             result.append(i);
01318             return result;
01319         }
01320     }
01321 
01322     return QList<int>();
01323 }
01324 
01325 QList<int> QDockAreaLayoutInfo::indexOf(QWidget *widget, IndexOfFlag flag) const
01326 {
01327     for (int i = 0; i < item_list.size(); ++i) {
01328         const QDockAreaLayoutItem &item = item_list.at(i);
01329 
01330         if (item.subinfo != 0) {
01331             QList<int> result = item.subinfo->indexOf(widget, flag);
01332             if (!result.isEmpty()) {
01333                 result.prepend(i);
01334                 return result;
01335             }
01336             continue;
01337         }
01338 
01339         if (flag != IndexOfFindsAll) {
01340             if ((flag == IndexOfFindsVisible) == item.skip())
01341                 continue;
01342         }
01343 
01344         if (item.widgetItem->widget() == widget) {
01345             QList<int> result;
01346             result << i;
01347             return result;
01348         }
01349     }
01350 
01351     return QList<int>();
01352 }
01353 
01354 QMainWindowLayout *QDockAreaLayoutInfo::mainWindowLayout() const
01355 {
01356     QMainWindowLayout *result = qobject_cast<QMainWindowLayout*>(mainWindow->layout());
01357     Q_ASSERT(result != 0);
01358     return result;
01359 }
01360 
01361 void QDockAreaLayoutInfo::apply(bool animate)
01362 {
01363     QWidgetAnimator *widgetAnimator = mainWindowLayout()->widgetAnimator;
01364 
01365 #ifndef QT_NO_TABBAR
01366     if (tabbed) {
01367         QRect tab_rect;
01368         QSize tbh = tabBarSizeHint();
01369 
01370         if (tabBarVisible) {
01371             switch (tabBarShape) {
01372                 case QTabBar::RoundedNorth:
01373                     tab_rect = QRect(rect.left(), rect.top(), rect.width(), tbh.height());
01374                     break;
01375                 case QTabBar::RoundedSouth:
01376                     tab_rect = QRect(rect.left(), rect.bottom() - tbh.height() + 1,
01377                                         rect.width(), tbh.height());
01378                     break;
01379                 case QTabBar::RoundedEast:
01380                     tab_rect = QRect(rect.right() - tbh.width() + 1, rect.top(),
01381                                         tbh.width(), rect.height());
01382                     break;
01383                 case QTabBar::RoundedWest:
01384                     tab_rect = QRect(rect.left(), rect.top(),
01385                                         tbh.width(), rect.height());
01386                     break;
01387                 default:
01388                     break;
01389             }
01390         }
01391 
01392         if (tab_rect != tabBar->geometry())
01393             widgetAnimator->animate(tabBar, tab_rect, animate);
01394 //        dump(qDebug() << "QDockAreaLayoutInfo::apply():" << tabIndex, *this, QString());
01395     }
01396 #endif // QT_NO_TABBAR
01397 
01398     for (int i = 0; i < item_list.size(); ++i) {
01399         QDockAreaLayoutItem &item = item_list[i];
01400         if (item.gap || item.skip())
01401             continue;
01402         if (item.subinfo) {
01403             item.subinfo->apply(animate);
01404         } else {
01405             Q_ASSERT(item.widgetItem);
01406             QRect r = itemRect(i);
01407             QWidget *w = item.widgetItem->widget();
01408             widgetAnimator->animate(w, r, animate);
01409         }
01410     }
01411 }
01412 
01413 static void paintSep(QPainter *p, QWidget *w, const QRect &r, Qt::Orientation o, bool mouse_over)
01414 {
01415     QStyleOption opt(0);
01416     opt.state = QStyle::State_None;
01417     if (w->isEnabled())
01418         opt.state |= QStyle::State_Enabled;
01419     if (o != Qt::Horizontal)
01420         opt.state |= QStyle::State_Horizontal;
01421     if (mouse_over)
01422         opt.state |= QStyle::State_MouseOver;
01423     opt.rect = r;
01424     opt.palette = w->palette();
01425 
01426     w->style()->drawPrimitive(QStyle::PE_IndicatorDockWidgetResizeHandle, &opt, p, w);
01427 }
01428 
01429 QRegion QDockAreaLayoutInfo::separatorRegion() const
01430 {
01431     QRegion result;
01432 
01433     if (isEmpty())
01434         return result;
01435 #ifndef QT_NO_TABBAR
01436     if (tabbed)
01437         return result;
01438 #endif
01439 
01440     for (int i = 0; i < item_list.count(); ++i) {
01441         const QDockAreaLayoutItem &item = item_list.at(i);
01442 
01443         if (item.skip())
01444             continue;
01445 
01446         int next = this->next(i);
01447 
01448         if (item.subinfo)
01449             result |= item.subinfo->separatorRegion();
01450 
01451         if (next == -1)
01452             break;
01453         result |= separatorRect(i);
01454     }
01455 
01456     return result;
01457 }
01458 
01459 void QDockAreaLayoutInfo::paintSeparators(QPainter *p, QWidget *widget,
01460                                                     const QRegion &clip,
01461                                                     const QPoint &mouse) const
01462 {
01463     if (isEmpty())
01464         return;
01465 #ifndef QT_NO_TABBAR
01466     if (tabbed)
01467         return;
01468 #endif
01469 
01470     for (int i = 0; i < item_list.count(); ++i) {
01471         const QDockAreaLayoutItem &item = item_list.at(i);
01472 
01473         if (item.skip())
01474             continue;
01475 
01476         int next = this->next(i);
01477         if (item.gap || next != -1 && item_list.at(next).gap)
01478             continue;
01479 
01480         if (item.subinfo) {
01481             if (clip.contains(item.subinfo->rect))
01482                 item.subinfo->paintSeparators(p, widget, clip, mouse);
01483         }
01484 
01485         if (next == -1)
01486             break;
01487         QRect r = separatorRect(i);
01488         if (clip.contains(r))
01489             paintSep(p, widget, r, o, r.contains(mouse));
01490     }
01491 }
01492 
01493 int QDockAreaLayoutInfo::next(int index) const
01494 {
01495     for (int i = index + 1; i < item_list.size(); ++i) {
01496         if (!item_list.at(i).skip())
01497             return i;
01498     }
01499     return -1;
01500 }
01501 
01502 int QDockAreaLayoutInfo::prev(int index) const
01503 {
01504     for (int i = index - 1; i >= 0; --i) {
01505         if (!item_list.at(i).skip())
01506             return i;
01507     }
01508     return -1;
01509 }
01510 
01511 void QDockAreaLayoutInfo::tab(int index, QWidgetItem *dockWidgetItem)
01512 {
01513 #ifndef QT_NO_TABBAR
01514     if (tabbed) {
01515         item_list.append(QDockAreaLayoutItem(dockWidgetItem));
01516     } else {
01517         QDockAreaLayoutInfo *new_info
01518             = new QDockAreaLayoutInfo(sep, o, tabBarShape, mainWindow);
01519         item_list[index].subinfo = new_info;
01520         new_info->item_list.append(item_list.at(index).widgetItem);
01521         item_list[index].widgetItem = 0;
01522         new_info->item_list.append(dockWidgetItem);
01523         new_info->tabbed = true;
01524     }
01525 #endif // QT_NO_TABBAR
01526 }
01527 
01528 void QDockAreaLayoutInfo::split(int index, Qt::Orientation orientation,
01529                                        QWidgetItem *dockWidgetItem)
01530 {
01531     if (orientation == o) {
01532         item_list.insert(index + 1, QDockAreaLayoutItem(dockWidgetItem));
01533     } else {
01534 #ifdef QT_NO_TABBAR
01535         const int tabBarShape = 0;
01536 #endif
01537         QDockAreaLayoutInfo *new_info
01538             = new QDockAreaLayoutInfo(sep, orientation, tabBarShape, mainWindow);
01539         item_list[index].subinfo = new_info;
01540         new_info->item_list.append(item_list.at(index).widgetItem);
01541         item_list[index].widgetItem = 0;
01542         new_info->item_list.append(dockWidgetItem);
01543     }
01544 }
01545 
01546 QDockAreaLayoutItem &QDockAreaLayoutInfo::item(QList<int> path)
01547 {
01548     Q_ASSERT(!path.isEmpty());
01549     if (path.count() > 1) {
01550         QDockAreaLayoutItem &item = item_list[path.takeFirst()];
01551         Q_ASSERT(item.subinfo != 0);
01552         return item.subinfo->item(path);
01553     }
01554     return item_list[path.first()];
01555 }
01556 
01557 QLayoutItem *QDockAreaLayoutInfo::itemAt(int *x, int index) const
01558 {
01559     for (int i = 0; i < item_list.count(); ++i) {
01560         const QDockAreaLayoutItem &item = item_list.at(i);
01561         if (item.subinfo) {
01562             if (QLayoutItem *ret = item.subinfo->itemAt(x, index))
01563                 return ret;
01564         } else if (item.widgetItem) {
01565             if ((*x)++ == index)
01566                 return item.widgetItem;
01567         }
01568     }
01569     return 0;
01570 }
01571 
01572 QLayoutItem *QDockAreaLayoutInfo::takeAt(int *x, int index)
01573 {
01574     for (int i = 0; i < item_list.count(); ++i) {
01575         const QDockAreaLayoutItem &item = item_list.at(i);
01576         if (item.subinfo) {
01577             if (QLayoutItem *ret = item.subinfo->takeAt(x, index)) {
01578                 unnest(i);
01579                 return ret;
01580             }
01581         } else if (item.widgetItem) {
01582             if ((*x)++ == index) {
01583                 QLayoutItem *ret = item.widgetItem;
01584                 item_list.removeAt(i);
01585                 return ret;
01586             }
01587         }
01588     }
01589     return 0;
01590 }
01591 
01592 void QDockAreaLayoutInfo::deleteAllLayoutItems()
01593 {
01594     for (int i = 0; i < item_list.count(); ++i) {
01595         QDockAreaLayoutItem &item= item_list[i];
01596         if (item.subinfo) {
01597             item.subinfo->deleteAllLayoutItems();
01598         } else {
01599             delete item.widgetItem;
01600             item.widgetItem = 0;
01601         }
01602     }
01603 }
01604 
01605 void QDockAreaLayoutInfo::saveState(QDataStream &stream) const
01606 {
01607 #ifndef QT_NO_TABBAR
01608     if (tabbed) {
01609         stream << (uchar) TabMarker;
01610 
01611         // write the index in item_list of the widget that's currently on top.
01612         quintptr id = currentTabId();
01613         int index = -1;
01614         for (int i = 0; i < item_list.count(); ++i) {
01615             if (tabId(item_list.at(i)) == id) {
01616                 index = i;
01617                 break;
01618             }
01619         }
01620         stream << index;
01621     } else
01622 #endif // QT_NO_TABBAR
01623     {
01624         stream << (uchar) SequenceMarker;
01625     }
01626 
01627     stream << (uchar) o << item_list.count();
01628 
01629     for (int i = 0; i < item_list.count(); ++i) {
01630         const QDockAreaLayoutItem &item = item_list.at(i);
01631         if (item.widgetItem != 0) {
01632             stream << (uchar) WidgetMarker;
01633             QWidget *w = item.widgetItem->widget();
01634             QString name = w->objectName();
01635             if (name.isEmpty()) {
01636                 qWarning("QMainWindow::saveState(): 'objectName' not set for QDockWidget %p '%s;",
01637                          w, qPrintable(w->windowTitle()));
01638             }
01639             stream << name;
01640 
01641             uchar flags = 0;
01642             if (!w->isHidden())
01643                 flags |= StateFlagVisible;
01644             if (w->isWindow())
01645                 flags |= StateFlagFloating;
01646             stream << flags;
01647 
01648             if (w->isWindow()) {
01649                 stream << w->x() << w->y() << w->width() << w->height();
01650             } else {
01651                 stream << item.pos << item.size << pick(o, item.minimumSize())
01652                         << pick(o, item.maximumSize());
01653             }
01654         } else if (item.subinfo != 0) {
01655             stream << (uchar) SequenceMarker << item.pos << item.size << pick(o, item.minimumSize()) << pick(o, item.maximumSize());
01656             item.subinfo->saveState(stream);
01657         }
01658     }
01659 }
01660 
01661 bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, const QList<QDockWidget*> &widgets)
01662 {
01663     uchar marker;
01664     stream >> marker;
01665     if (marker != TabMarker && marker != SequenceMarker)
01666         return false;
01667 
01668 #ifndef QT_NO_TABBAR
01669     tabbed = marker == TabMarker;
01670 
01671     int index = -1;
01672     if (tabbed)
01673         stream >> index;
01674 #endif
01675 
01676     uchar orientation;
01677     stream >> orientation;
01678     o = static_cast<Qt::Orientation>(orientation);
01679 
01680     int cnt;
01681     stream >> cnt;
01682 
01683     for (int i = 0; i < cnt; ++i) {
01684         uchar nextMarker;
01685         stream >> nextMarker;
01686         if (nextMarker == WidgetMarker) {
01687             QString name;
01688             uchar flags;
01689             stream >> name >> flags;
01690             if (name.isEmpty()) {
01691                 qWarning("QMainWindow::restoreState: Cannot restore "
01692                          "a QDockWidget with an empty 'objectName'");
01693                 int dummy;
01694                 stream >> dummy >> dummy >> dummy >> dummy;
01695                 continue;
01696             }
01697 
01698             QDockWidget *widget = 0;
01699             for (int j = 0; j < widgets.count(); ++j) {
01700                 if (widgets.at(j)->objectName() == name) {
01701                     widget = widgets.at(j);
01702                     break;
01703                 }
01704             }
01705             if (widget == 0) {
01706                 qWarning("QMainWindow::restoreState(): cannot find a QDockWidget with "
01707                          "matching 'objectName' (looking for \"%s\").",
01708                          qPrintable(name));
01709                 int dummy;
01710                 stream >> dummy >> dummy >> dummy >> dummy;
01711                 continue;
01712             }
01713 
01714             QDockAreaLayoutItem item(new QWidgetItem(widget));
01715             if (flags & StateFlagFloating) {
01716                 widget->hide();
01717                 widget->setFloating(true);
01718                 int x, y, w, h;
01719                 stream >> x >> y >> w >> h;
01720                 widget->move(x, y);
01721                 widget->resize(w, h);
01722                 widget->setVisible(flags & StateFlagVisible);
01723             } else {
01724                 int dummy;
01725                 stream >> item.pos >> item.size >> dummy >> dummy;
01726                 widget->setFloating(false);
01727                 widget->setVisible(flags & StateFlagVisible);
01728             }
01729 
01730             item_list.append(item);
01731         } else if (nextMarker == SequenceMarker) {
01732             int dummy;
01733 #ifdef QT_NO_TABBAR
01734             const int tabBarShape = 0;
01735 #endif
01736             QDockAreaLayoutInfo *info = new QDockAreaLayoutInfo(sep, o,
01737                                                                 tabBarShape, mainWindow);
01738             QDockAreaLayoutItem item(info);
01739             stream >> item.pos >> item.size >> dummy >> dummy;
01740             if (!info->restoreState(stream, widgets))
01741                 return false;
01742 
01743             item_list.append(item);
01744         } else {
01745             return false;
01746         }
01747     }
01748 
01749 #ifndef QT_NO_TABBAR
01750     if (tabbed && index >= 0 && index < item_list.count()) {
01751         updateTabBar();
01752         setCurrentTabId(tabId(item_list.at(index)));
01753     }
01754 #endif
01755 
01756     return true;
01757 }
01758 
01759 #ifndef QT_NO_TABBAR
01760 void QDockAreaLayoutInfo::updateTabBar() const
01761 {
01762     if (!tabbed)
01763         return;
01764 
01765     QDockAreaLayoutInfo *that = const_cast<QDockAreaLayoutInfo*>(this);
01766 
01767     if (tabBar == 0) {
01768         that->tabBar = mainWindowLayout()->getTabBar();
01769         that->tabBar->setShape(static_cast<QTabBar::Shape>(tabBarShape));
01770     }
01771 
01772     bool blocked = tabBar->blockSignals(true);
01773     bool gap = false;
01774 
01775     int tab_idx = 0;
01776     bool changed = false;
01777     for (int i = 0; i < item_list.count(); ++i) {
01778         const QDockAreaLayoutItem &item = item_list.at(i);
01779         if (item.skip())
01780             continue;
01781         if (item.gap) {
01782             gap = true;
01783             continue;
01784         }
01785         if (item.widgetItem == 0)
01786             continue;
01787 
01788         QString title = item.widgetItem->widget()->windowTitle();
01789         quintptr id = tabId(item);
01790         if (tab_idx == tabBar->count()) {
01791             tabBar->insertTab(tab_idx, title);
01792 #ifndef QT_NO_TOOLTIP
01793             tabBar->setTabToolTip(tab_idx, title);
01794 #endif
01795             tabBar->setTabData(tab_idx, id);
01796             changed = true;
01797         } else if (qvariant_cast<quintptr>(tabBar->tabData(tab_idx)) != id) {
01798             if (tab_idx + 1 < tabBar->count()
01799                     && qvariant_cast<quintptr>(tabBar->tabText(tab_idx + 1)) == id)
01800                 tabBar->removeTab(tab_idx);
01801             else {
01802                 tabBar->insertTab(tab_idx, title);
01803 #ifndef QT_NO_TOOLTIP
01804                 tabBar->setTabToolTip(tab_idx, title);
01805 #endif
01806                 tabBar->setTabData(tab_idx, id);
01807             }
01808             changed = true;
01809         }
01810 
01811         if (title != tabBar->tabText(tab_idx)) {
01812             tabBar->setTabText(tab_idx, title);
01813 #ifndef QT_NO_TOOLTIP
01814             tabBar->setTabToolTip(tab_idx, title);
01815 #endif
01816             changed = true;
01817         }
01818 
01819         ++tab_idx;
01820     }
01821 
01822     while (tab_idx < tabBar->count()) {
01823         tabBar->removeTab(tab_idx);
01824         changed = true;
01825     }
01826 
01827     tabBar->blockSignals(blocked);
01828 
01829     that->tabBarVisible = gap || tabBar->count() > 1;
01830 
01831     if (changed) {
01832         that->tabBarMin = tabBar->minimumSizeHint();
01833         that->tabBarHint = tabBar->sizeHint();
01834     }
01835 }
01836 
01837 QSize QDockAreaLayoutInfo::tabBarMinimumSize() const
01838 {
01839     if (!tabbed)
01840         return QSize(0, 0);
01841 
01842     updateTabBar();
01843 
01844     return tabBarMin;
01845 }
01846 
01847 QSize QDockAreaLayoutInfo::tabBarSizeHint() const
01848 {
01849     if (!tabbed)
01850         return QSize(0, 0);
01851 
01852     updateTabBar();
01853 
01854     return tabBarHint;
01855 }
01856 
01857 QSet<QTabBar*> QDockAreaLayoutInfo::usedTabBars() const
01858 {
01859     QSet<QTabBar*> result;
01860 
01861     if (tabbed) {
01862         updateTabBar();
01863         result.insert(tabBar);
01864     }
01865 
01866     for (int i = 0; i < item_list.count(); ++i) {
01867         const QDockAreaLayoutItem &item = item_list.at(i);
01868         if (item.skip())
01869             continue;
01870         if (item.subinfo != 0)
01871             result += item.subinfo->usedTabBars();
01872     }
01873 
01874     return result;
01875 }
01876 
01877 QRect QDockAreaLayoutInfo::tabContentRect() const
01878 {
01879     if (!tabbed)
01880         return QRect();
01881 
01882     QRect result = rect;
01883     QSize tbh = tabBarSizeHint();
01884 
01885     if (tabBarVisible) {
01886         switch (tabBarShape) {
01887             case QTabBar::RoundedNorth:
01888                 result.adjust(0, tbh.height(), 0, 0);
01889                 break;
01890             case QTabBar::RoundedSouth:
01891                 result.adjust(0, 0, 0, -tbh.height());
01892                 break;
01893             case QTabBar::RoundedEast:
01894                 result.adjust(0, 0, -tbh.width(), 0);
01895                 break;
01896             case QTabBar::RoundedWest:
01897                 result.adjust(tbh.width(), 0, 0, 0);
01898                 break;
01899             default:
01900                 break;
01901         }
01902     }
01903 
01904     return result;
01905 }
01906 #endif // QT_NO_TABBAR
01907 
01908 /******************************************************************************
01909 ** QDockWidgetLayout
01910 */
01911 
01912 QDockWidgetLayout::QDockWidgetLayout(QMainWindow *win)
01913 {
01914     mainWindow = win;
01915     sep = win->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
01916 #ifndef QT_NO_TABBAR
01917     const int tabShape = QTabBar::RoundedSouth;
01918 #else
01919     const int tabShape = 0;
01920 #endif
01921     docks[LeftPos] = QDockAreaLayoutInfo(sep, Qt::Vertical, tabShape, win);
01922     docks[RightPos] = QDockAreaLayoutInfo(sep, Qt::Vertical, tabShape, win);
01923     docks[TopPos] = QDockAreaLayoutInfo(sep, Qt::Horizontal, tabShape, win);
01924     docks[BottomPos] = QDockAreaLayoutInfo(sep, Qt::Horizontal, tabShape, win);
01925     centralWidgetItem = 0;
01926     centralWidgetRect = QRect(0, 0, -1, -1);
01927 
01928     corners[Qt::TopLeftCorner] = Qt::TopDockWidgetArea;
01929     corners[Qt::TopRightCorner] = Qt::TopDockWidgetArea;
01930     corners[Qt::BottomLeftCorner] = Qt::BottomDockWidgetArea;
01931     corners[Qt::BottomRightCorner] = Qt::BottomDockWidgetArea;
01932 }
01933 
01934 bool QDockWidgetLayout::isValid() const
01935 {
01936     return rect.isValid();
01937 }
01938 
01939 void QDockWidgetLayout::saveState(QDataStream &stream) const
01940 {
01941     stream << (uchar) DockWidgetStateMarker;
01942     int cnt = 0;
01943     for (int i = 0; i < PosCount; ++i) {
01944         if (!docks[i].item_list.isEmpty())
01945             ++cnt;
01946     }
01947     stream << cnt;
01948     for (int i = 0; i < PosCount; ++i) {
01949         if (docks[i].item_list.isEmpty())
01950             continue;
01951         stream << i << docks[i].rect.size();
01952         docks[i].saveState(stream);
01953     }
01954 
01955     stream << centralWidgetRect.size();
01956 
01957     for (int i = 0; i < 4; ++i)
01958         stream << static_cast<int>(corners[i]);
01959 }
01960 
01961 bool QDockWidgetLayout::restoreState(QDataStream &stream, const QList<QDockWidget*> &dockwidgets)
01962 {
01963     uchar dmarker;
01964     stream >> dmarker;
01965     if (dmarker != DockWidgetStateMarker)
01966         return false;
01967     int cnt;
01968     stream >> cnt;
01969     for (int i = 0; i < cnt; ++i) {
01970         int pos;
01971         stream >> pos;
01972         QSize size;
01973         stream >> size;
01974         docks[pos].rect = QRect(QPoint(0, 0), size);
01975         if (!docks[pos].restoreState(stream, dockwidgets)) {
01976             stream.setStatus(QDataStream::ReadCorruptData);
01977             return false;
01978         }
01979     }
01980 
01981     QSize size;
01982     stream >> size;
01983     centralWidgetRect = QRect(QPoint(0, 0), size);
01984 
01985     bool ok = stream.status() == QDataStream::Ok;
01986 
01987     if (ok) {
01988         int cornerData[4];
01989         for (int i = 0; i < 4; ++i)
01990             stream >> cornerData[i];
01991         if (stream.status() == QDataStream::Ok) {
01992             for (int i = 0; i < 4; ++i)
01993                 corners[i] = static_cast<Qt::DockWidgetArea>(cornerData[i]);
01994         }
01995     }
01996 
01997     return ok;
01998 }
01999 
02000 QList<int> QDockWidgetLayout::indexOf(QDockWidget *dockWidget, IndexOfFlag flag) const
02001 {
02002     for (int i = 0; i < PosCount; ++i) {
02003         QList<int> result = docks[i].indexOf(dockWidget, flag);
02004         if (!result.isEmpty()) {
02005             result.prepend(i);
02006             return result;
02007         }
02008     }
02009     return QList<int>();
02010 }
02011 
02012 QList<int> QDockWidgetLayout::gapIndex(const QPoint &pos, bool nestingEnabled) const
02013 {
02014     for (int i = 0; i < PosCount; ++i) {
02015         const QDockAreaLayoutInfo &info = docks[i];
02016 
02017         if (!info.isEmpty() && info.rect.contains(pos)) {
02018             QList<int> result = docks[i].gapIndex(pos, nestingEnabled);
02019             if (!result.isEmpty())
02020                 result.prepend(i);
02021             return result;
02022         }
02023     }
02024 
02025     for (int i = 0; i < PosCount; ++i) {
02026         const QDockAreaLayoutInfo &info = docks[i];
02027 
02028         if (info.isEmpty()) {
02029             QRect r;
02030             switch (i) {
02031                 case LeftPos:
02032                     r = QRect(rect.left(), rect.top(), EmptyDropAreaSize, rect.height());
02033                     break;
02034                 case RightPos:
02035                     r = QRect(rect.right() - EmptyDropAreaSize, rect.top(),
02036                                 EmptyDropAreaSize, rect.height());
02037                     break;
02038                 case TopPos:
02039                     r = QRect(rect.left(), rect.top(), rect.width(), EmptyDropAreaSize);
02040                     break;
02041                 case BottomPos:
02042                     r = QRect(rect.left(), rect.bottom() - EmptyDropAreaSize,
02043                                 rect.width(), EmptyDropAreaSize);
02044                     break;
02045             }
02046             if (r.contains(pos))
02047                 return QList<int>() << i << 0;
02048         }
02049     }
02050 
02051     return QList<int>();
02052 }
02053 
02054 QList<int> QDockWidgetLayout::findSeparator(const QPoint &pos) const
02055 {
02056     QList<int> result;
02057     for (int i = 0; i < PosCount; ++i) {
02058         const QDockAreaLayoutInfo &info = docks[i];
02059         if (info.isEmpty())
02060             continue;
02061         if (separatorRect(i).contains(pos)) {
02062             result << i;
02063             break;
02064         } else if (info.rect.contains(pos)) {
02065             result = docks[i].findSeparator(pos);
02066             if (!result.isEmpty()) {
02067                 result.prepend(i);
02068                 break;
02069             }
02070         }
02071     }
02072 
02073     return result;
02074 }
02075 
02076 QDockAreaLayoutInfo *QDockWidgetLayout::info(QWidget *widget)
02077 {
02078     for (int i = 0; i < PosCount; ++i) {
02079         if (QDockAreaLayoutInfo *result = docks[i].info(widget))
02080             return result;
02081     }
02082 
02083     return 0;
02084 }
02085 
02086 QDockAreaLayoutInfo *QDockWidgetLayout::info(QList<int> path)
02087 {
02088     Q_ASSERT(!path.isEmpty());
02089     int index = path.takeFirst();
02090     Q_ASSERT(index >= 0 && index < PosCount);
02091 
02092     if (path.isEmpty())
02093         return &docks[index];
02094 
02095     return docks[index].info(path);
02096 }
02097 
02098 QDockAreaLayoutItem &QDockWidgetLayout::item(QList<int> path)
02099 {
02100     Q_ASSERT(!path.isEmpty());
02101     int index = path.takeFirst();
02102     Q_ASSERT(index >= 0 && index < PosCount);
02103     return docks[index].item(path);
02104 }
02105 
02106 QRect QDockWidgetLayout::itemRect(QList<int> path) const
02107 {
02108     Q_ASSERT(!path.isEmpty());
02109     int index = path.takeFirst();
02110     Q_ASSERT(index >= 0 && index < PosCount);
02111     return docks[index].itemRect(path);
02112 }
02113 
02114 QRect QDockWidgetLayout::separatorRect(int index) const
02115 {
02116     if (docks[index].isEmpty())
02117         return QRect();
02118     QRect r = docks[index].rect;
02119     switch (index) {
02120         case LeftPos:
02121             return QRect(r.right() + 1, r.top(), sep, r.height());
02122         case RightPos:
02123             return QRect(r.left() - sep, r.top(), sep, r.height());
02124         case TopPos:
02125             return QRect(r.left(), r.bottom() + 1, r.width(), sep);
02126         case BottomPos:
02127             return QRect(r.left(), r.top() - sep, r.width(), sep);
02128         default:
02129             break;
02130     }
02131     return QRect();
02132 }
02133 
02134 QRect QDockWidgetLayout::separatorRect(QList<int> path) const
02135 {
02136     Q_ASSERT(!path.isEmpty());
02137 
02138     int index = path.takeFirst();
02139     Q_ASSERT(index >= 0 && index < PosCount);
02140 
02141     if (path.isEmpty())
02142         return separatorRect(index);
02143     else
02144         return docks[index].separatorRect(path);
02145 }
02146 
02147 bool QDockWidgetLayout::insertGap(QList<int> path, QWidgetItem *dockWidgetItem)
02148 {
02149     Q_ASSERT(!path.isEmpty());
02150     int index = path.takeFirst();
02151     Q_ASSERT(index >= 0 && index < PosCount);
02152     return docks[index].insertGap(path, dockWidgetItem);
02153 }
02154 
02155 QRect QDockWidgetLayout::convertToWidget(QList<int> path, QWidgetItem *dockWidgetItem)
02156 {
02157     Q_ASSERT(!path.isEmpty());
02158     int index = path.takeFirst();
02159     Q_ASSERT(index >= 0 && index < PosCount);
02160     return docks[index].convertToWidget(path, dockWidgetItem);
02161 }
02162 
02163 QWidgetItem *QDockWidgetLayout::convertToGap(QList<int> path)
02164 {
02165     Q_ASSERT(!path.isEmpty());
02166     int index = path.takeFirst();
02167     Q_ASSERT(index >= 0 && index < PosCount);
02168     return docks[index].convertToGap(path);
02169 }
02170 
02171 void QDockWidgetLayout::remove(QList<int> path)
02172 {
02173     Q_ASSERT(!path.isEmpty());
02174     int index = path.takeFirst();
02175     Q_ASSERT(index >= 0 && index < PosCount);
02176     docks[index].remove(path);
02177 }
02178 
02179 static inline int qMin(int i1, int i2, int i3) { return qMin(i1, qMin(i2, i3)); }
02180 static inline int qMax(int i1, int i2, int i3) { return qMax(i1, qMax(i2, i3)); }
02181 
02182 void QDockWidgetLayout::getGrid(QVector<QLayoutStruct> *_ver_struct_list,
02183                                 QVector<QLayoutStruct> *_hor_struct_list)
02184 {
02185     QSize center_hint(0, 0);
02186     QSize center_min(0, 0);
02187     bool have_central = centralWidgetItem != 0 && !centralWidgetItem->isEmpty();
02188     if (have_central) {
02189         center_hint = centralWidgetRect.size();
02190         if (!center_hint.isValid())
02191             center_hint = centralWidgetItem->sizeHint();
02192         center_min = centralWidgetItem->minimumSize();
02193     }
02194 
02195     QRect center_rect = rect;
02196     if (!docks[LeftPos].isEmpty())
02197         center_rect.setLeft(rect.left() + docks[LeftPos].rect.width() + sep);
02198     if (!docks[TopPos].isEmpty())
02199         center_rect.setTop(rect.top() + docks[TopPos].rect.height() + sep);
02200     if (!docks[RightPos].isEmpty())
02201         center_rect.setRight(rect.right() - docks[RightPos].rect.width() - sep - 1);
02202     if (!docks[BottomPos].isEmpty())
02203         center_rect.setBottom(rect.bottom() - docks[BottomPos].rect.height() - sep - 1);
02204 
02205     QSize left_hint = docks[LeftPos].size();
02206     if (!left_hint.isValid())
02207         left_hint = docks[LeftPos].sizeHint();
02208     QSize left_min = docks[LeftPos].minimumSize();
02209     QSize left_max = docks[LeftPos].maximumSize();
02210     int left_sep = docks[LeftPos].isEmpty() ? 0 : sep;
02211 
02212     QSize right_hint = docks[RightPos].size();
02213     if (!right_hint.isValid())
02214         right_hint = docks[RightPos].sizeHint();
02215     QSize right_min = docks[RightPos].minimumSize();
02216     QSize right_max = docks[RightPos].maximumSize();
02217     int right_sep = docks[RightPos].isEmpty() ? 0 : sep;
02218 
02219     QSize top_hint = docks[TopPos].size();
02220     if (!top_hint.isValid())
02221         top_hint = docks[TopPos].sizeHint();
02222     QSize top_min = docks[TopPos].minimumSize();
02223     QSize top_max = docks[TopPos].maximumSize();
02224     int top_sep = docks[TopPos].isEmpty() ? 0 : sep;
02225 
02226     QSize bottom_hint = docks[BottomPos].size();
02227     if (!bottom_hint.isValid())
02228         bottom_hint = docks[BottomPos].sizeHint();
02229     QSize bottom_min = docks[BottomPos].minimumSize();
02230     QSize bottom_max = docks[BottomPos].maximumSize();
02231     int bottom_sep = docks[BottomPos].isEmpty() ? 0 : sep;
02232 
02233     if (_ver_struct_list != 0) {
02234         QVector<QLayoutStruct> &ver_struct_list = *_ver_struct_list;
02235         ver_struct_list.resize(3);
02236 
02237         // top --------------------------------------------------
02238 
02239         ver_struct_list[0].stretch = 0;
02240         ver_struct_list[0].sizeHint = top_hint.height();
02241         ver_struct_list[0].minimumSize = top_min.height();
02242         ver_struct_list[0].maximumSize = top_max.height();
02243         ver_struct_list[0].expansive = false;
02244         ver_struct_list[0].empty = docks[TopPos].isEmpty();
02245         ver_struct_list[0].pos = docks[TopPos].rect.top();
02246         ver_struct_list[0].size = docks[TopPos].rect.height();
02247 
02248         // center --------------------------------------------------
02249 
02250         ver_struct_list[1].stretch = center_hint.height();
02251         int left = left_hint.height();
02252         if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
02253             left -= top_hint.height() + top_sep;
02254         if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
02255             left -= bottom_hint.height() + bottom_sep;
02256         int right = right_hint.height();
02257         if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
02258             right -= top_hint.height() + top_sep;
02259         if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
02260             right -= bottom_hint.height() + bottom_sep;
02261         ver_struct_list[1].sizeHint = qMax(left, center_hint.height(), right);
02262 
02263         left = left_min.height();
02264         if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
02265             left -= top_min.height() + top_sep;
02266         if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
02267             left -= bottom_min.height() + bottom_sep;
02268         right = right_min.height();
02269         if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
02270             right -= top_min.height() + top_sep;
02271         if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
02272             right -= bottom_min.height() + bottom_sep;
02273         ver_struct_list[1].minimumSize = qMax(left, center_min.height(), right);
02274         ver_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
02275         ver_struct_list[1].expansive = have_central;
02276         ver_struct_list[1].empty = docks[LeftPos].isEmpty()
02277                                         && !have_central
02278                                         && docks[RightPos].isEmpty();
02279         ver_struct_list[1].pos = center_rect.top();
02280         ver_struct_list[1].size = center_rect.height();
02281 
02282         // bottom --------------------------------------------------
02283 
02284         ver_struct_list[2].stretch = 0;
02285         ver_struct_list[2].sizeHint = bottom_hint.height();
02286         ver_struct_list[2].minimumSize = bottom_min.height();
02287         ver_struct_list[2].maximumSize = bottom_max.height();
02288         ver_struct_list[2].expansive = false;
02289         ver_struct_list[2].empty = docks[BottomPos].isEmpty();
02290         ver_struct_list[2].pos = docks[BottomPos].rect.top();
02291         ver_struct_list[2].size = docks[BottomPos].rect.height();
02292 
02293         for (int i = 0; i < 3; ++i) {
02294             ver_struct_list[i].sizeHint
02295                 = qMax(ver_struct_list[i].sizeHint, ver_struct_list[i].minimumSize);
02296         }
02297     }
02298 
02299     if (_hor_struct_list != 0) {
02300         QVector<QLayoutStruct> &hor_struct_list = *_hor_struct_list;
02301         hor_struct_list.resize(3);
02302 
02303         // left --------------------------------------------------
02304 
02305         hor_struct_list[0].stretch = 0;
02306         hor_struct_list[0].sizeHint = left_hint.width();
02307         hor_struct_list[0].minimumSize = left_min.width();
02308         hor_struct_list[0].maximumSize = left_max.width();
02309         hor_struct_list[0].expansive = false;
02310         hor_struct_list[0].empty = docks[LeftPos].isEmpty();
02311         hor_struct_list[0].pos = docks[LeftPos].rect.left();
02312         hor_struct_list[0].size = docks[LeftPos].rect.width();
02313 
02314         // center --------------------------------------------------
02315 
02316         hor_struct_list[1].stretch = center_hint.width();
02317         int top = top_hint.width();
02318         if (corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea)
02319             top -= left_hint.width() + left_sep;
02320         if (corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea)
02321             top -= right_hint.width() + right_sep;
02322         int bottom = bottom_hint.width();
02323         if (corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea)
02324             bottom -= left_hint.width() + left_sep;
02325         if (corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea)
02326             bottom -= right_hint.width() + right_sep;
02327         hor_struct_list[1].sizeHint = qMax(top, center_hint.width(), bottom);
02328 
02329         top = top_min.width();
02330         if (corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea)
02331             top -= left_min.width() + left_sep;
02332         if (corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea)
02333             top -= right_min.width() + right_sep;
02334         bottom = bottom_min.width();
02335         if (corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea)
02336             bottom -= left_min.width() + left_sep;
02337         if (corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea)
02338             bottom -= right_min.width() + right_sep;
02339         hor_struct_list[1].minimumSize = qMax(top, center_min.width(), bottom);
02340         hor_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0;
02341         hor_struct_list[1].expansive = have_central;
02342         hor_struct_list[1].empty = !have_central;
02343         hor_struct_list[1].pos = center_rect.left();
02344         hor_struct_list[1].size = center_rect.width();
02345 
02346         // right --------------------------------------------------
02347 
02348         hor_struct_list[2].stretch = 0;
02349         hor_struct_list[2].sizeHint = right_hint.width();
02350         hor_struct_list[2].minimumSize = right_min.width();
02351         hor_struct_list[2].maximumSize = right_max.width();
02352         hor_struct_list[2].expansive = false;
02353         hor_struct_list[2].empty = docks[RightPos].isEmpty();
02354         hor_struct_list[2].pos = docks[RightPos].rect.left();
02355         hor_struct_list[2].size = docks[RightPos].rect.width();
02356 
02357         for (int i = 0; i < 3; ++i) {
02358             hor_struct_list[i].sizeHint
02359                 = qMax(hor_struct_list[i].sizeHint, hor_struct_list[i].minimumSize);
02360         }
02361     }
02362 }
02363 
02364 void QDockWidgetLayout::setGrid(QVector<QLayoutStruct> *ver_struct_list,
02365                                 QVector<QLayoutStruct> *hor_struct_list)
02366 {
02367 
02368     // top ---------------------------------------------------
02369 
02370     QRect r = docks[TopPos].rect;
02371     if (hor_struct_list != 0) {
02372         r.setLeft(corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea
02373                     || docks[LeftPos].isEmpty()
02374                         ? rect.left() : hor_struct_list->at(1).pos);
02375         r.setRight(corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea
02376                     || docks[RightPos].isEmpty()
02377                         ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
02378     }
02379     if (ver_struct_list != 0) {
02380         r.setTop(rect.top());
02381         r.setBottom(ver_struct_list->at(1).pos - sep - 1);
02382     }
02383     docks[TopPos].rect = r;
02384     docks[TopPos].fitItems();
02385 
02386     // bottom ---------------------------------------------------
02387 
02388     r = docks[BottomPos].rect;
02389     if (hor_struct_list != 0) {
02390         r.setLeft(corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea
02391                     || docks[LeftPos].isEmpty()
02392                         ? rect.left() : hor_struct_list->at(1).pos);
02393         r.setRight(corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea
02394                     || docks[RightPos].isEmpty()
02395                         ? rect.right() : hor_struct_list->at(2).pos - sep - 1);
02396     }
02397     if (ver_struct_list != 0) {
02398         r.setTop(ver_struct_list->at(2).pos);
02399         r.setBottom(rect.bottom());
02400     }
02401     docks[BottomPos].rect = r;
02402     docks[BottomPos].fitItems();
02403 
02404     // left ---------------------------------------------------
02405 
02406     r = docks[LeftPos].rect;
02407     if (hor_struct_list != 0) {
02408         r.setLeft(rect.left());
02409         r.setRight(hor_struct_list->at(1).pos - sep - 1);
02410     }
02411     if (ver_struct_list != 0) {
02412         r.setTop(corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea
02413                     || docks[TopPos].isEmpty()
02414                         ? rect.top() : ver_struct_list->at(1).pos);
02415         r.setBottom(corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea
02416                     || docks[BottomPos].isEmpty()
02417                         ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
02418     }
02419     docks[LeftPos].rect = r;
02420     docks[LeftPos].fitItems();
02421 
02422     // right ---------------------------------------------------
02423 
02424     r = docks[RightPos].rect;
02425     if (hor_struct_list != 0) {
02426         r.setLeft(hor_struct_list->at(2).pos);
02427         r.setRight(rect.right());
02428     }
02429     if (ver_struct_list != 0) {
02430         r.setTop(corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea
02431                     || docks[TopPos].isEmpty()
02432                         ? rect.top() : ver_struct_list->at(1).pos);
02433         r.setBottom(corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea
02434                     || docks[BottomPos].isEmpty()
02435                         ? rect.bottom() : ver_struct_list->at(2).pos - sep - 1);
02436     }
02437     docks[RightPos].rect = r;
02438     docks[RightPos].fitItems();
02439 
02440     // center ---------------------------------------------------
02441 
02442     if (hor_struct_list != 0) {
02443         centralWidgetRect.setLeft(hor_struct_list->at(1).pos);
02444         centralWidgetRect.setWidth(hor_struct_list->at(1).size);
02445     }
02446     if (ver_struct_list != 0) {
02447         centralWidgetRect.setTop(ver_struct_list->at(1).pos);
02448         centralWidgetRect.setHeight(ver_struct_list->at(1).size);
02449     }
02450 }
02451 
02452 void QDockWidgetLayout::fitLayout()
02453 {
02454     QVector<QLayoutStruct> ver_struct_list(3);
02455     QVector<QLayoutStruct> hor_struct_list(3);
02456     getGrid(&ver_struct_list, &hor_struct_list);
02457 
02458     qGeomCalc(ver_struct_list, 0, 3, rect.top(), rect.height(), sep);
02459     qGeomCalc(hor_struct_list, 0, 3, rect.left(), rect.width(), sep);
02460 
02461     setGrid(&ver_struct_list, &hor_struct_list);
02462 }
02463 
02464 void QDockWidgetLayout::clear()
02465 {
02466     for (int i = 0; i < PosCount; ++i)
02467         docks[i].clear();
02468 
02469     rect = QRect(0, 0, -1, -1);
02470     centralWidgetRect = QRect(0, 0, -1, -1);
02471 }
02472 
02473 QSize QDockWidgetLayout::sizeHint() const
02474 {
02475     int left_sep = docks[LeftPos].isEmpty() ? 0 : sep;
02476     int right_sep = docks[RightPos].isEmpty() ? 0 : sep;
02477     int top_sep = docks[TopPos].isEmpty() ? 0 : sep;
02478     int bottom_sep = docks[BottomPos].isEmpty() ? 0 : sep;
02479 
02480     QSize left = docks[LeftPos].sizeHint() + QSize(left_sep, 0);
02481     QSize right = docks[RightPos].sizeHint() + QSize(right_sep, 0);
02482     QSize top = docks[TopPos].sizeHint() + QSize(0, top_sep);
02483     QSize bottom = docks[BottomPos].sizeHint() + QSize(0, bottom_sep);
02484     QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->sizeHint();
02485 
02486     int row1 = top.width();
02487     int row2 = left.width() + center.width() + right.width();
02488     int row3 = bottom.width();
02489     int col1 = left.height();
02490     int col2 = top.height() + center.height() + bottom.height();
02491     int col3 = right.height();
02492 
02493     if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
02494         row1 += left.width();
02495     else
02496         col1 += top.height();
02497 
02498     if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
02499         row1 += right.width();
02500     else
02501         col3 += top.height();
02502 
02503     if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
02504         row3 += left.width();
02505     else
02506         col1 += bottom.height();
02507 
02508     if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
02509         row3 += right.width();
02510     else
02511         col3 += bottom.height();
02512 
02513     return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
02514 }
02515 
02516 QSize QDockWidgetLayout::minimumSize() const
02517 {
02518     int left_sep = docks[LeftPos].isEmpty() ? 0 : sep;
02519     int right_sep = docks[RightPos].isEmpty() ? 0 : sep;
02520     int top_sep = docks[TopPos].isEmpty() ? 0 : sep;
02521     int bottom_sep = docks[BottomPos].isEmpty() ? 0 : sep;
02522 
02523     QSize left = docks[LeftPos].minimumSize() + QSize(left_sep, 0);
02524     QSize right = docks[RightPos].minimumSize() + QSize(right_sep, 0);
02525     QSize top = docks[TopPos].minimumSize() + QSize(0, top_sep);
02526     QSize bottom = docks[BottomPos].minimumSize() + QSize(0, bottom_sep);
02527     QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->minimumSize();
02528 
02529     int row1 = top.width();
02530     int row2 = left.width() + center.width() + right.width();
02531     int row3 = bottom.width();
02532     int col1 = left.height();
02533     int col2 = top.height() + center.height() + bottom.height();
02534     int col3 = right.height();
02535 
02536     if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea)
02537         row1 += left.width();
02538     else
02539         col1 += top.height();
02540 
02541     if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea)
02542         row1 += right.width();
02543     else
02544         col3 += top.height();
02545 
02546     if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea)
02547         row3 += left.width();
02548     else
02549         col1 += bottom.height();
02550 
02551     if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea)
02552         row3 += right.width();
02553     else
02554         col3 += bottom.height();
02555 
02556     return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3));
02557 }
02558 
02559 void QDockWidgetLayout::addDockWidget(DockPos pos, QDockWidget *dockWidget,
02560                                              Qt::Orientation orientation)
02561 {
02562     QWidgetItem *dockWidgetItem = new QWidgetItem(dockWidget);
02563     QDockAreaLayoutInfo &info = docks[pos];
02564     if (orientation == info.o || info.isEmpty()) {
02565         QDockAreaLayoutItem new_item(dockWidgetItem);
02566         info.item_list.append(new_item);
02567 #ifndef QT_NO_TABBAR
02568         if (info.tabbed && !new_item.skip()) {
02569             info.updateTabBar();
02570             info.setCurrentTabId(tabId(new_item));
02571         }
02572 #endif
02573     } else {
02574 #ifndef QT_NO_TABBAR
02575         int tbshape = QTabBar::RoundedSouth;
02576         switch (pos) {
02577             case TopPos:
02578                 tbshape = QTabBar::RoundedNorth;
02579                 break;
02580             case BottomPos:
02581                 tbshape = QTabBar::RoundedSouth;
02582                 break;
02583             case RightPos:
02584                 tbshape = QTabBar::RoundedEast;
02585                 break;
02586             case LeftPos:
02587                 tbshape = QTabBar::RoundedWest;
02588                 break;
02589             default:
02590                 break;
02591         }
02592 #else
02593         int tbshape = 0;
02594 #endif
02595         QDockAreaLayoutInfo new_info(sep, orientation, tbshape, mainWindow);
02596         new_info.item_list.append(new QDockAreaLayoutInfo(info));
02597         new_info.item_list.append(dockWidgetItem);
02598         info = new_info;
02599     }
02600 }
02601 
02602 void QDockWidgetLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
02603 {
02604     QList<int> path = indexOf(first);
02605     if (path.isEmpty())
02606         return;