tools/designer/src/lib/shared/qdesigner_widgetitem.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Designer of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qdesigner_widgetitem_p.h"
       
    43 #include "qdesigner_widget_p.h"
       
    44 #include "widgetfactory_p.h"
       
    45 
       
    46 #include <QtDesigner/QDesignerFormWindowInterface>
       
    47 #include <QtDesigner/QExtensionManager>
       
    48 #include <QtDesigner/QDesignerFormEditorInterface>
       
    49 #include <QtDesigner/QDesignerContainerExtension>
       
    50 #include <QtDesigner/QDesignerWidgetDataBaseInterface>
       
    51 
       
    52 #include <QtGui/QVBoxLayout>
       
    53 #include <QtGui/QHBoxLayout>
       
    54 #include <QtGui/QGridLayout>
       
    55 #include <QtGui/QFormLayout>
       
    56 #include <QtGui/QApplication>
       
    57 
       
    58 #include <QtCore/QTextStream>
       
    59 #include <QtCore/QDebug>
       
    60 #include <private/qlayout_p.h>
       
    61 
       
    62 QT_BEGIN_NAMESPACE
       
    63 
       
    64 enum { DebugWidgetItem = 0 };
       
    65 enum { MinimumLength = 10 };
       
    66 
       
    67 // Widget item creation function to be registered as factory method with
       
    68 // QLayoutPrivate
       
    69 static QWidgetItem *createDesignerWidgetItem(const QLayout *layout, QWidget *widget)
       
    70 {
       
    71     Qt::Orientations orientations;
       
    72     if (qdesigner_internal::QDesignerWidgetItem::check(layout, widget, &orientations)) {
       
    73         if (DebugWidgetItem)
       
    74             qDebug() << "QDesignerWidgetItem: Creating on " << layout << widget << orientations;
       
    75         return new qdesigner_internal::QDesignerWidgetItem(layout, widget, orientations);
       
    76     }
       
    77     if (DebugWidgetItem)
       
    78         qDebug() << "QDesignerWidgetItem: Noncontainer: " << layout << widget;
       
    79 
       
    80     return 0;
       
    81 }
       
    82 
       
    83 static QString sizePolicyToString(const QSizePolicy &p)
       
    84 {
       
    85     QString rc; {
       
    86         QTextStream str(&rc);
       
    87         str << "Control=" << p.controlType() << " expdirs=" << p.expandingDirections()
       
    88             << " hasHeightForWidth=" << p.hasHeightForWidth()
       
    89             << " H: Policy=" << p.horizontalPolicy()
       
    90             << " stretch=" << p.horizontalStretch()
       
    91             << " V: Policy=" << p.verticalPolicy()
       
    92             << " stretch=" << p.verticalStretch();
       
    93     }
       
    94     return rc;
       
    95 }
       
    96 
       
    97 // Find the layout the item is contained in, recursing over
       
    98 // child layouts
       
    99 static const QLayout *findLayoutOfItem(const QLayout *haystack, const QLayoutItem *needle)
       
   100 {
       
   101     const int count = haystack->count();
       
   102     for (int i = 0; i < count; i++) {
       
   103         QLayoutItem *item = haystack->itemAt(i);
       
   104         if (item == needle)
       
   105             return haystack;
       
   106         if (QLayout *childLayout =  item->layout())
       
   107             if (const QLayout *containing = findLayoutOfItem(childLayout, needle))
       
   108                 return containing;
       
   109     }
       
   110     return 0;
       
   111 }
       
   112 
       
   113 
       
   114 namespace qdesigner_internal {
       
   115 
       
   116 // ------------------ QDesignerWidgetItem
       
   117 QDesignerWidgetItem::QDesignerWidgetItem(const QLayout *containingLayout, QWidget *w, Qt::Orientations o) :
       
   118     QWidgetItemV2(w),
       
   119     m_orientations(o),
       
   120     m_nonLaidOutMinSize(w->minimumSizeHint()),
       
   121     m_nonLaidOutSizeHint(w->sizeHint()),
       
   122     m_cachedContainingLayout(containingLayout)
       
   123 {
       
   124     // Initialize the minimum size to prevent nonlaid-out frames/widgets
       
   125     // from being slammed to zero
       
   126     const QSize minimumSize = w->minimumSize();
       
   127     if (!minimumSize.isEmpty())
       
   128         m_nonLaidOutMinSize = minimumSize;
       
   129     expand(&m_nonLaidOutMinSize);
       
   130     expand(&m_nonLaidOutSizeHint);
       
   131     w->installEventFilter(this);
       
   132     connect(containingLayout, SIGNAL(destroyed()), this, SLOT(layoutChanged()));
       
   133     if (DebugWidgetItem )
       
   134         qDebug() << "QDesignerWidgetItem"  << w <<  sizePolicyToString(w->sizePolicy()) << m_nonLaidOutMinSize << m_nonLaidOutSizeHint;
       
   135 }
       
   136 
       
   137 void QDesignerWidgetItem::expand(QSize *s) const
       
   138 {
       
   139     // Expand the size if its too small
       
   140     if (m_orientations & Qt::Horizontal && s->width() <= 0)
       
   141         s->setWidth(MinimumLength);
       
   142     if (m_orientations & Qt::Vertical && s->height() <= 0)
       
   143         s->setHeight(MinimumLength);
       
   144 }
       
   145 
       
   146 QSize QDesignerWidgetItem::minimumSize() const
       
   147 {
       
   148     // Just track the size in case we are laid-out or stretched.
       
   149     const QSize baseMinSize = QWidgetItemV2::minimumSize();
       
   150     QWidget * w = constWidget();
       
   151     if (w->layout() || subjectToStretch(containingLayout(), w)) {
       
   152         m_nonLaidOutMinSize = baseMinSize;
       
   153         return baseMinSize;
       
   154     }
       
   155     // Nonlaid out: Maintain last laid-out size
       
   156     const QSize rc = baseMinSize.expandedTo(m_nonLaidOutMinSize);
       
   157     if (DebugWidgetItem > 1)
       
   158          qDebug() << "minimumSize" << constWidget() <<  baseMinSize << rc;
       
   159     return rc;
       
   160 }
       
   161 
       
   162 QSize QDesignerWidgetItem::sizeHint()    const
       
   163 {
       
   164     // Just track the size in case we are laid-out or stretched.
       
   165     const QSize baseSizeHint = QWidgetItemV2::sizeHint();
       
   166     QWidget * w = constWidget();
       
   167     if (w->layout() || subjectToStretch(containingLayout(), w)) {
       
   168         m_nonLaidOutSizeHint = baseSizeHint;
       
   169         return baseSizeHint;
       
   170     }
       
   171     // Nonlaid out: Maintain last laid-out size
       
   172     const QSize rc = baseSizeHint.expandedTo(m_nonLaidOutSizeHint);
       
   173     if (DebugWidgetItem > 1)
       
   174         qDebug() << "sizeHint" << constWidget() << baseSizeHint << rc;
       
   175     return rc;
       
   176 }
       
   177 
       
   178 bool QDesignerWidgetItem::subjectToStretch(const QLayout *layout, QWidget *w)
       
   179 {
       
   180     if (!layout)
       
   181         return false;
       
   182     // Are we under some stretch factor?
       
   183     if (const QBoxLayout *bl = qobject_cast<const QBoxLayout *>(layout)) {
       
   184         const int index = bl->indexOf(w);
       
   185         Q_ASSERT(index != -1);
       
   186         return bl->stretch(index) != 0;
       
   187     }
       
   188     if (const QGridLayout *cgl = qobject_cast<const QGridLayout *>(layout)) {
       
   189         QGridLayout *gl = const_cast<QGridLayout *>(cgl);
       
   190         const int index = cgl->indexOf(w);
       
   191         Q_ASSERT(index != -1);
       
   192         int row, column, rowSpan, columnSpan;
       
   193         gl->getItemPosition (index, &row, &column, &rowSpan, &columnSpan);
       
   194         const int rend = row + rowSpan;
       
   195         const int cend = column + columnSpan;
       
   196         for (int r = row; r < rend; r++)
       
   197             if (cgl->rowStretch(r) != 0)
       
   198                 return true;
       
   199         for (int c = column; c < cend; c++)
       
   200             if (cgl->columnStretch(c) != 0)
       
   201                 return true;
       
   202     }
       
   203     return false;
       
   204 }
       
   205 
       
   206 /* Return the orientations mask for a layout, specifying
       
   207  * in which directions squeezing should be prevented. */
       
   208 static Qt::Orientations layoutOrientation(const QLayout *layout)
       
   209 {
       
   210     if (const QBoxLayout *bl = qobject_cast<const QBoxLayout *>(layout)) {
       
   211         const QBoxLayout::Direction direction = bl->direction();
       
   212         return direction == QBoxLayout::LeftToRight || direction == QBoxLayout::RightToLeft ? Qt::Horizontal : Qt::Vertical;
       
   213     }
       
   214     if (qobject_cast<const QFormLayout*>(layout))
       
   215         return  Qt::Vertical;
       
   216     return Qt::Horizontal|Qt::Vertical;
       
   217 }
       
   218 
       
   219 // Check for a non-container extension container
       
   220 bool  QDesignerWidgetItem::isContainer(const QDesignerFormEditorInterface *core, QWidget *w)
       
   221 {
       
   222     if (!WidgetFactory::isFormEditorObject(w))
       
   223         return false;
       
   224     const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
       
   225     const int widx = wdb->indexOfObject(w);
       
   226     if (widx == -1 || !wdb->item(widx)->isContainer())
       
   227         return false;
       
   228     if (qt_extension<QDesignerContainerExtension*>(core->extensionManager(), w))
       
   229         return false;
       
   230     return true;
       
   231 }
       
   232 
       
   233 bool QDesignerWidgetItem::check(const QLayout *layout, QWidget *w, Qt::Orientations *ptrToOrientations)
       
   234 {
       
   235     // Check for form-editor non-containerextension-containers (QFrame, etc)
       
   236     // within laid-out form editor widgets. No check for managed() here as we
       
   237     // want container pages and widgets in the process of being morphed as
       
   238     // well. Avoid nested layouts (as the effective stretch cannot be easily
       
   239     // computed and may mess things up). Won't work for Q3 Group boxes.
       
   240     if (ptrToOrientations)
       
   241         *ptrToOrientations = 0;
       
   242 
       
   243     const QObject *layoutParent = layout->parent();
       
   244     if (!layoutParent || !layoutParent->isWidgetType() || !WidgetFactory::isFormEditorObject(layoutParent))
       
   245         return false;
       
   246 
       
   247     QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w);
       
   248     if (!fw || !isContainer(fw->core(), w))
       
   249         return false;
       
   250 
       
   251     // If it is a box, restrict to its orientation
       
   252     if (ptrToOrientations)
       
   253         *ptrToOrientations = layoutOrientation(layout);
       
   254 
       
   255     return true;
       
   256 }
       
   257 
       
   258 QSize QDesignerWidgetItem::nonLaidOutMinSize() const
       
   259 {
       
   260     return m_nonLaidOutMinSize;
       
   261 }
       
   262 
       
   263 void QDesignerWidgetItem::setNonLaidOutMinSize(const QSize &s)
       
   264 {
       
   265     if (DebugWidgetItem > 1)
       
   266         qDebug() << "setNonLaidOutMinSize" << constWidget() << s;
       
   267     m_nonLaidOutMinSize = s;
       
   268 }
       
   269 
       
   270 QSize QDesignerWidgetItem::nonLaidOutSizeHint() const
       
   271 {
       
   272     return m_nonLaidOutSizeHint;
       
   273 }
       
   274 
       
   275 void QDesignerWidgetItem::setNonLaidOutSizeHint(const QSize &s)
       
   276 {
       
   277     if (DebugWidgetItem > 1)
       
   278         qDebug() << "setNonLaidOutSizeHint" << constWidget() << s;
       
   279     m_nonLaidOutSizeHint = s;
       
   280 }
       
   281 
       
   282 void QDesignerWidgetItem::install()
       
   283 {
       
   284     QLayoutPrivate::widgetItemFactoryMethod = createDesignerWidgetItem;
       
   285 }
       
   286 
       
   287 void QDesignerWidgetItem::deinstall()
       
   288 {
       
   289     QLayoutPrivate::widgetItemFactoryMethod = 0;
       
   290 }
       
   291 
       
   292 const QLayout *QDesignerWidgetItem::containingLayout() const
       
   293 {
       
   294     if (!m_cachedContainingLayout) {
       
   295         if (QWidget *parentWidget = constWidget()->parentWidget())
       
   296             if (QLayout *parentLayout = parentWidget->layout()) {
       
   297                 m_cachedContainingLayout = findLayoutOfItem(parentLayout, this);
       
   298                 if (m_cachedContainingLayout)
       
   299                     connect(m_cachedContainingLayout, SIGNAL(destroyed()), this, SLOT(layoutChanged()));
       
   300             }
       
   301         if (DebugWidgetItem)
       
   302             qDebug() << Q_FUNC_INFO << " found " << m_cachedContainingLayout << " after reparenting " << constWidget();
       
   303     }
       
   304     return m_cachedContainingLayout;
       
   305 }
       
   306 
       
   307 void QDesignerWidgetItem::layoutChanged()        
       
   308 {
       
   309     if (DebugWidgetItem)
       
   310         qDebug() << Q_FUNC_INFO;
       
   311     m_cachedContainingLayout = 0;
       
   312 }
       
   313 
       
   314 bool QDesignerWidgetItem::eventFilter(QObject * /* watched */, QEvent *event)
       
   315 {    
       
   316     if (event->type() == QEvent::ParentChange)
       
   317         layoutChanged();
       
   318     return false;
       
   319 }
       
   320 
       
   321 // ------------------   QDesignerWidgetItemInstaller
       
   322 
       
   323 int QDesignerWidgetItemInstaller::m_instanceCount = 0;
       
   324 
       
   325 QDesignerWidgetItemInstaller::QDesignerWidgetItemInstaller()
       
   326 {
       
   327     if (m_instanceCount++ == 0) {
       
   328         if (DebugWidgetItem)
       
   329             qDebug() << "QDesignerWidgetItemInstaller: installing";
       
   330         QDesignerWidgetItem::install();
       
   331     }
       
   332 }
       
   333 
       
   334 QDesignerWidgetItemInstaller::~QDesignerWidgetItemInstaller()
       
   335 {
       
   336     if (--m_instanceCount == 0) {
       
   337         if (DebugWidgetItem)
       
   338             qDebug() << "QDesignerWidgetItemInstaller: deinstalling";
       
   339         QDesignerWidgetItem::deinstall();
       
   340     }
       
   341 }
       
   342 
       
   343 }
       
   344 
       
   345 QT_END_NAMESPACE