source: trunk/tools/designer/src/lib/shared/widgetfactory.cpp@ 944

Last change on this file since 944 was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 33.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the Qt Designer of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "widgetfactory_p.h"
43#include "widgetdatabase_p.h"
44#include "metadatabase_p.h"
45#include "qlayout_widget_p.h"
46#include "qdesigner_widget_p.h"
47#include "qdesigner_tabwidget_p.h"
48#include "qdesigner_toolbox_p.h"
49#include "qdesigner_stackedbox_p.h"
50#include "qdesigner_toolbar_p.h"
51#include "qdesigner_menubar_p.h"
52#include "qdesigner_menu_p.h"
53#include "qdesigner_dockwidget_p.h"
54#include "qdesigner_utils_p.h"
55#include "formwindowbase_p.h"
56
57// shared
58#include "layoutinfo_p.h"
59#include "spacer_widget_p.h"
60#include "layout_p.h"
61#include "abstractintrospection_p.h"
62
63// sdk
64#include <QtDesigner/QDesignerFormEditorInterface>
65#include <QtDesigner/QDesignerContainerExtension>
66#include <QtDesigner/QDesignerCustomWidgetInterface>
67#include <QtDesigner/QExtensionManager>
68#include <QtDesigner/QDesignerPropertySheetExtension>
69#include <QtDesigner/QDesignerLanguageExtension>
70#include <QtDesigner/QDesignerFormWindowManagerInterface>
71#include <QtDesigner/QDesignerFormWindowCursorInterface>
72
73#include <QtGui/QtGui>
74#include <QtGui/QScrollBar>
75#include <QtGui/QFontComboBox>
76#include <QtGui/QAbstractSpinBox>
77#include <QtGui/QLineEdit>
78#include <QtGui/QButtonGroup>
79#include <QtGui/QStyle>
80#include <QtGui/QStyleFactory>
81#include <QtGui/QWizard>
82#include <QtCore/qdebug.h>
83#include <QtCore/QMetaObject>
84
85QT_BEGIN_NAMESPACE
86
87#ifdef Q_OS_WIN
88static inline bool isAxWidget(const QObject *o)
89{
90 // Is it one of QDesignerAxWidget/QDesignerAxPluginWidget?
91 static const char *axWidgetName = "QDesignerAx";
92 static const unsigned axWidgetNameLen = qstrlen(axWidgetName);
93 return qstrncmp(o->metaObject()->className(), axWidgetName, axWidgetNameLen) == 0;
94}
95#endif
96
97/* Dynamic boolean property indicating object was created by the factory
98 * for the form editor. */
99
100static const char *formEditorDynamicProperty = "_q_formEditorObject";
101
102namespace qdesigner_internal {
103
104// A friendly SpinBox that grants access to its QLineEdit
105class FriendlySpinBox : public QAbstractSpinBox {
106public:
107 friend class WidgetFactory;
108};
109
110// An event filter for form-combo boxes that prevents the embedded line edit
111// from getting edit focus (and drawing blue artifacts/lines). It catches the
112// ChildPolished event when the "editable" property flips to true and the
113// QLineEdit is created and turns off the LineEdit's focus policy.
114
115class ComboEventFilter : public QObject {
116public:
117 explicit ComboEventFilter(QComboBox *parent) : QObject(parent) {}
118 virtual bool eventFilter(QObject *watched, QEvent *event);
119};
120
121bool ComboEventFilter::eventFilter(QObject *watched, QEvent *event)
122{
123 if (event->type() == QEvent::ChildPolished) {
124 QComboBox *cb = static_cast<QComboBox*>(watched);
125 if (QLineEdit *le = cb->lineEdit())
126 le->setFocusPolicy(Qt::NoFocus);
127 }
128 return QObject::eventFilter(watched, event);
129}
130
131/* Watch out for QWizards changing their pages and make sure that not some
132 * selected widget becomes invisible on a hidden page (causing the selection
133 * handles to shine through). Select the wizard in that case in analogy to
134 * the QTabWidget event filters, etc. */
135
136class WizardPageChangeWatcher : public QObject {
137 Q_OBJECT
138public:
139 explicit WizardPageChangeWatcher(QWizard *parent);
140
141public slots:
142 void pageChanged();
143};
144
145WizardPageChangeWatcher::WizardPageChangeWatcher(QWizard *parent) :
146 QObject(parent)
147{
148 connect(parent, SIGNAL(currentIdChanged(int)), this, SLOT(pageChanged()));
149}
150
151void WizardPageChangeWatcher::pageChanged()
152{
153 /* Use a bit more conservative approach than that for the QTabWidget,
154 * change the selection only if a selected child becomes invisible by
155 * changing the page. */
156 QWizard *wizard = static_cast<QWizard *>(parent());
157 QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(wizard);
158 if (!fw)
159 return;
160 QDesignerFormWindowCursorInterface *cursor = fw->cursor();
161 const int selCount = cursor->selectedWidgetCount();
162 for (int i = 0; i < selCount; i++) {
163 if (!cursor->selectedWidget(i)->isVisible()) {
164 fw->clearSelection(false);
165 fw->selectWidget(wizard, true);
166 break;
167 }
168 }
169}
170
171// ---------------- WidgetFactory::Strings
172WidgetFactory::Strings::Strings() :
173 m_alignment(QLatin1String("alignment")),
174 m_bottomMargin(QLatin1String("bottomMargin")),
175 m_geometry(QLatin1String("geometry")),
176 m_leftMargin(QLatin1String("leftMargin")),
177 m_line(QLatin1String("Line")),
178 m_objectName(QLatin1String("objectName")),
179 m_spacerName(QLatin1String("spacerName")),
180 m_orientation(QLatin1String("orientation")),
181 m_q3WidgetStack(QLatin1String("Q3WidgetStack")),
182 m_qAction(QLatin1String("QAction")),
183 m_qButtonGroup(QLatin1String("QButtonGroup")),
184 m_qAxWidget(QLatin1String("QAxWidget")),
185 m_qDialog(QLatin1String("QDialog")),
186 m_qDockWidget(QLatin1String("QDockWidget")),
187 m_qLayoutWidget(QLatin1String("QLayoutWidget")),
188 m_qMenu(QLatin1String("QMenu")),
189 m_qMenuBar(QLatin1String("QMenuBar")),
190 m_qWidget(QLatin1String("QWidget")),
191 m_rightMargin(QLatin1String("rightMargin")),
192 m_sizeHint(QLatin1String("sizeHint")),
193 m_spacer(QLatin1String("Spacer")),
194 m_text(QLatin1String("text")),
195 m_title(QLatin1String("title")),
196 m_topMargin(QLatin1String("topMargin")),
197 m_windowIcon(QLatin1String("windowIcon")),
198 m_windowTitle(QLatin1String("windowTitle"))
199{
200}
201// ---------------- WidgetFactory
202QPointer<QWidget> *WidgetFactory::m_lastPassiveInteractor = new QPointer<QWidget>();
203bool WidgetFactory::m_lastWasAPassiveInteractor = false;
204const char *WidgetFactory::disableStyleCustomPaintingPropertyC = "_q_custom_style_disabled";
205
206WidgetFactory::WidgetFactory(QDesignerFormEditorInterface *core, QObject *parent)
207 : QDesignerWidgetFactoryInterface(parent),
208 m_core(core),
209 m_formWindow(0),
210 m_currentStyle(0)
211{
212}
213
214WidgetFactory::~WidgetFactory()
215{
216}
217
218QDesignerFormWindowInterface *WidgetFactory::currentFormWindow(QDesignerFormWindowInterface *fw)
219{
220 QDesignerFormWindowInterface *was = m_formWindow;
221 m_formWindow = fw;
222 return was;
223}
224
225void WidgetFactory::loadPlugins()
226{
227 m_customFactory.clear();
228
229 QDesignerPluginManager *pluginManager = m_core->pluginManager();
230
231 QList<QDesignerCustomWidgetInterface*> lst = pluginManager->registeredCustomWidgets();
232 foreach (QDesignerCustomWidgetInterface *c, lst) {
233 m_customFactory.insert(c->name(), c);
234 }
235}
236
237// Convencience to create non-widget objects. Returns 0 if unknown
238QObject* WidgetFactory::createObject(const QString &className, QObject* parent) const
239{
240 if (className.isEmpty()) {
241 qWarning("** WARNING %s called with an empty class name", Q_FUNC_INFO);
242 return 0;
243 }
244 if (className == m_strings.m_qAction)
245 return new QAction(parent);
246 if (className == m_strings.m_qButtonGroup)
247 return new QButtonGroup(parent);
248 return 0;
249}
250
251QWidget* WidgetFactory::createCustomWidget(const QString &className, QWidget *parentWidget, bool *creationError) const
252{
253 *creationError = false;
254 CustomWidgetFactoryMap::const_iterator it = m_customFactory.constFind(className);
255 if (it == m_customFactory.constEnd())
256 return 0;
257
258 QDesignerCustomWidgetInterface *factory = it.value();
259 QWidget *rc = factory->createWidget(parentWidget);
260 // shouldn't happen
261 if (!rc) {
262 *creationError = true;
263 designerWarning(tr("The custom widget factory registered for widgets of class %1 returned 0.").arg(className));
264 return 0;
265 }
266 // Figure out the base class unless it is known
267 static QSet<QString> knownCustomClasses;
268 if (!knownCustomClasses.contains(className)) {
269 QDesignerWidgetDataBaseInterface *wdb = m_core->widgetDataBase();
270 const int widgetInfoIndex = wdb->indexOfObject(rc, false);
271 if (widgetInfoIndex != -1) {
272 if (wdb->item(widgetInfoIndex)->extends().isEmpty()) {
273 const QDesignerMetaObjectInterface *mo = core()->introspection()->metaObject(rc)->superClass();
274 // If we hit on a 'Q3DesignerXXWidget' that claims to be a 'Q3XXWidget', step
275 // over.
276 if (mo && mo->className() == className)
277 mo = mo->superClass();
278 while (mo != 0) {
279 if (core()->widgetDataBase()->indexOfClassName(mo->className()) != -1) {
280 wdb->item(widgetInfoIndex)->setExtends(mo->className());
281 break;
282 }
283 mo = mo->superClass();
284 }
285 }
286 knownCustomClasses.insert(className);
287 }
288 }
289 // Since a language plugin may lie about its names, like Qt Jambi
290 // does, return immediately here...
291 QDesignerLanguageExtension *lang =
292 qt_extension<QDesignerLanguageExtension *>(m_core->extensionManager(), m_core);
293 if (lang)
294 return rc;
295
296#ifdef Q_OS_WIN
297 if (isAxWidget(rc))
298 return rc;
299#endif
300 // Check for mismatched class names which is hard to track.
301 // Perform literal comparison first for QAxWidget, for which a meta object hack is in effect.
302 const char *createdClassNameC = rc->metaObject()->className();
303 const QByteArray classNameB = className.toUtf8();
304 const char *classNameC = classNameB.constData();
305
306 if (qstrcmp(createdClassNameC, classNameC) && !rc->inherits(classNameC))
307 designerWarning(tr("A class name mismatch occurred when creating a widget using the custom widget factory registered for widgets of class %1."
308 " It returned a widget of class %2.").arg(className).arg(QString::fromUtf8(createdClassNameC)));
309 return rc;
310}
311
312
313QWidget *WidgetFactory::createWidget(const QString &widgetName, QWidget *parentWidget) const
314{
315 if (widgetName.isEmpty()) {
316 qWarning("** WARNING %s called with an empty class name", Q_FUNC_INFO);
317 return 0;
318 }
319 // Preview or for form window?
320 QDesignerFormWindowInterface *fw = m_formWindow;
321 if (! fw)
322 fw = QDesignerFormWindowInterface::findFormWindow(parentWidget);
323
324 QWidget *w = 0;
325 do {
326 // 1) custom. If there is an explicit failure(factory wants to indicate something is wrong),
327 // return 0, do not try to find fallback, which might be worse in the case of Q3 widget.
328 bool customWidgetCreationError;
329 w = createCustomWidget(widgetName, parentWidget, &customWidgetCreationError);
330 if (w) {
331 break;
332 } else {
333 if (customWidgetCreationError)
334 return 0;
335 }
336
337 // 2) Special widgets
338 if (widgetName == m_strings.m_line) {
339 w = new Line(parentWidget);
340 } else if (widgetName == m_strings.m_qDockWidget) {
341 w = new QDesignerDockWidget(parentWidget);
342 } else if (widgetName == m_strings.m_qMenuBar) {
343 w = new QDesignerMenuBar(parentWidget);
344 } else if (widgetName == m_strings.m_qMenu) {
345 w = new QDesignerMenu(parentWidget);
346 } else if (widgetName == m_strings.m_spacer) {
347 w = new Spacer(parentWidget);
348 } else if (widgetName == m_strings.m_qDockWidget) {
349 w = new QDesignerDockWidget(parentWidget);
350 } else if (widgetName == m_strings.m_qLayoutWidget) {
351 w = fw ? new QLayoutWidget(fw, parentWidget) : new QWidget(parentWidget);
352 } else if (widgetName == m_strings.m_qDialog) {
353 if (fw) {
354 w = new QDesignerDialog(fw, parentWidget);
355 } else {
356 w = new QDialog(parentWidget);
357 }
358 } else if (widgetName == m_strings.m_qWidget) {
359 /* We want a 'QDesignerWidget' that draws a grid only for widget
360 * forms and container extension pages (not for preview and not
361 * for normal QWidget children on forms (legacy) */
362 if (fw && parentWidget) {
363 if (qt_extension<QDesignerContainerExtension*>(m_core->extensionManager(), parentWidget)) {
364 w = new QDesignerWidget(fw, parentWidget);
365 } else {
366 if (const FormWindowBase *fwb = qobject_cast<FormWindowBase *>(fw))
367 if (parentWidget == fwb->formContainer())
368 w = new QDesignerWidget(fw, parentWidget);
369 }
370 }
371 if (!w)
372 w = new QWidget(parentWidget);
373 }
374 if (w)
375 break;
376
377 // 3) table
378 const QByteArray widgetNameBA = widgetName.toUtf8();
379 const char *widgetNameC = widgetNameBA.constData();
380
381 if (w) { // symmetry for macro
382 }
383
384#define DECLARE_LAYOUT(L, C)
385#define DECLARE_COMPAT_WIDGET(W, C) /*DECLARE_WIDGET(W, C)*/
386#define DECLARE_WIDGET(W, C) else if (!qstrcmp(widgetNameC, #W)) { Q_ASSERT(w == 0); w = new W(parentWidget); }
387#define DECLARE_WIDGET_1(W, C) else if (!qstrcmp(widgetNameC, #W)) { Q_ASSERT(w == 0); w = new W(0, parentWidget); }
388
389#include "widgets.table"
390
391#undef DECLARE_COMPAT_WIDGET
392#undef DECLARE_LAYOUT
393#undef DECLARE_WIDGET
394#undef DECLARE_WIDGET_1
395
396 if (w)
397 break;
398 // 4) fallBack
399 const QString fallBackBaseClass = m_strings.m_qWidget;
400 QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase();
401 QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfClassName(widgetName));
402 if (item == 0) {
403 // Emergency: Create, derived from QWidget
404 QString includeFile = widgetName.toLower();
405 includeFile += QLatin1String(".h");
406 item = appendDerived(db,widgetName, tr("%1 Widget").arg(widgetName),fallBackBaseClass,
407 includeFile, true, true);
408 Q_ASSERT(item);
409 }
410 QString baseClass = item->extends();
411 if (baseClass.isEmpty()) {
412 // Currently happens in the case of Q3-Support widgets
413 baseClass =fallBackBaseClass;
414 }
415 w = createWidget(baseClass, parentWidget);
416 promoteWidget(core(),w,widgetName);
417 } while (false);
418
419 Q_ASSERT(w != 0);
420 if (m_currentStyle)
421 w->setStyle(m_currentStyle);
422 initializeCommon(w);
423 if (fw) { // form editor initialization
424 initialize(w);
425 } else { // preview-only initialization
426 initializePreview(w);
427 }
428 return w;
429}
430
431QString WidgetFactory::classNameOf(QDesignerFormEditorInterface *c, const QObject* o)
432{
433 if (o == 0)
434 return QString();
435
436 const char *className = o->metaObject()->className();
437 if (!o->isWidgetType())
438 return QLatin1String(className);
439 const QWidget *w = static_cast<const QWidget*>(o);
440 // check promoted before designer special
441 const QString customClassName = promotedCustomClassName(c, const_cast<QWidget*>(w));
442 if (!customClassName.isEmpty())
443 return customClassName;
444 if (qobject_cast<const QDesignerMenuBar*>(w))
445 return QLatin1String("QMenuBar");
446 else if (qobject_cast<const QDesignerMenu*>(w))
447 return QLatin1String("QMenu");
448 else if (qobject_cast<const QDesignerDockWidget*>(w))
449 return QLatin1String("QDockWidget");
450 else if (qobject_cast<const QDesignerDialog*>(w))
451 return QLatin1String("QDialog");
452 else if (qobject_cast<const QDesignerWidget*>(w))
453 return QLatin1String("QWidget");
454#ifdef Q_OS_WIN
455 else if (isAxWidget(w))
456 return QLatin1String("QAxWidget");
457#endif
458 else if (qstrcmp(className, "QDesignerQ3WidgetStack") == 0)
459 return QLatin1String("Q3WidgetStack");
460
461 return QLatin1String(className);
462}
463
464QLayout *WidgetFactory::createUnmanagedLayout(QWidget *parentWidget, int type)
465{
466 switch (type) {
467 case LayoutInfo::HBox:
468 return new QHBoxLayout(parentWidget);
469 case LayoutInfo::VBox:
470 return new QVBoxLayout(parentWidget);
471 case LayoutInfo::Grid:
472 return new QGridLayout(parentWidget);
473 case LayoutInfo::Form:
474 return new QFormLayout(parentWidget);
475 default:
476 Q_ASSERT(0);
477 break;
478 }
479 return 0;
480}
481
482
483/*! Creates a layout on the widget \a widget of the type \a type
484 which can be \c HBox, \c VBox or \c Grid.
485*/
486
487QLayout *WidgetFactory::createLayout(QWidget *widget, QLayout *parentLayout, int type) const // ### (sizepolicy)
488{
489 QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase();
490
491 if (parentLayout == 0) {
492 QWidget *page = containerOfWidget(widget);
493 if (page) {
494 widget = page;
495 } else {
496 const QString msg = tr("The current page of the container '%1' (%2) could not be determined while creating a layout."
497"This indicates an inconsistency in the ui-file, probably a layout being constructed on a container widget.").arg(widget->objectName()).arg(classNameOf(core(), widget));
498 designerWarning(msg);
499 }
500 }
501
502 Q_ASSERT(metaDataBase->item(widget) != 0); // ensure the widget is managed
503
504 if (parentLayout == 0 && metaDataBase->item(widget->layout()) == 0) {
505 parentLayout = widget->layout();
506 }
507
508 QWidget *parentWidget = parentLayout != 0 ? 0 : widget;
509
510 QLayout *layout = createUnmanagedLayout(parentWidget, type);
511 metaDataBase->add(layout); // add the layout in the MetaDataBase
512
513 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), layout);
514
515 sheet->setChanged(sheet->indexOf(m_strings.m_objectName), true);
516 if (widget->inherits("Q3GroupBox")) {
517 layout->setContentsMargins(widget->style()->pixelMetric(QStyle::PM_LayoutLeftMargin),
518 widget->style()->pixelMetric(QStyle::PM_LayoutTopMargin),
519 widget->style()->pixelMetric(QStyle::PM_LayoutRightMargin),
520 widget->style()->pixelMetric(QStyle::PM_LayoutBottomMargin));
521 QGridLayout *grid = qobject_cast<QGridLayout *>(layout);
522 if (grid) {
523 grid->setHorizontalSpacing(-1);
524 grid->setVerticalSpacing(-1);
525 } else {
526 layout->setSpacing(-1);
527 }
528 layout->setAlignment(Qt::AlignTop);
529 // Just to ensure; before 4.3 orientation property was always set (now only for QSplitter class).
530 // Calling Q3GroupBox::setOrientation() invoked in turn setSpacing(0). Below fixes that
531 widget->layout()->setSpacing(-1);
532 } else if (widget->inherits("QLayoutWidget")) {
533 sheet->setProperty(sheet->indexOf(m_strings.m_leftMargin), 0);
534 sheet->setProperty(sheet->indexOf(m_strings.m_topMargin), 0);
535 sheet->setProperty(sheet->indexOf(m_strings.m_rightMargin), 0);
536 sheet->setProperty(sheet->indexOf(m_strings.m_bottomMargin), 0);
537 }
538
539 if (sheet) {
540 const int index = sheet->indexOf(m_strings.m_alignment);
541 if (index != -1)
542 sheet->setChanged(index, true);
543 }
544
545 if (metaDataBase->item(widget->layout()) == 0) {
546 Q_ASSERT(layout->parent() == 0);
547 QBoxLayout *box = qobject_cast<QBoxLayout*>(widget->layout());
548 if (!box) { // we support only unmanaged box layouts
549 const QString msg = tr("Attempt to add a layout to a widget '%1' (%2) which already has an unmanaged layout of type %3.\n"
550 "This indicates an inconsistency in the ui-file.").
551 arg(widget->objectName()).arg(classNameOf(core(), widget)).arg(classNameOf(core(), widget->layout()));
552 designerWarning(msg);
553 return 0;
554 }
555 box->addLayout(layout);
556 }
557
558 return layout;
559}
560
561/*! Returns the widget into which children should be inserted when \a
562 w is a container known to designer.
563
564 Usually, it is \a w itself, but there are exceptions (for example, a
565 tabwidget is known to designer as a container, but the child
566 widgets should be inserted into the current page of the
567 tabwidget. In this case, the current page of
568 the tabwidget would be returned.)
569 */
570QWidget* WidgetFactory::containerOfWidget(QWidget *w) const
571{
572 if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), w))
573 return container->widget(container->currentIndex());
574
575 return w;
576}
577
578/*! Returns the actual designer widget of the container \a w. This is
579 normally \a w itself, but it might be a parent or grand parent of \a w
580 (for example, when working with a tabwidget and \a w is the container which
581 contains and layouts children, but the actual widget known to
582 designer is the tabwidget which is the parent of \a w. In this case,
583 the tabwidget would be returned.)
584*/
585
586QWidget* WidgetFactory::widgetOfContainer(QWidget *w) const
587{
588 // ### cleanup
589 if (!w)
590 return 0;
591 if (w->parentWidget() && w->parentWidget()->parentWidget() &&
592 w->parentWidget()->parentWidget()->parentWidget() &&
593 qobject_cast<QToolBox*>(w->parentWidget()->parentWidget()->parentWidget()))
594 return w->parentWidget()->parentWidget()->parentWidget();
595
596 while (w != 0) {
597 if (core()->widgetDataBase()->isContainer(w) ||
598 (w && qobject_cast<QDesignerFormWindowInterface*>(w->parentWidget())))
599 return w;
600
601 w = w->parentWidget();
602 }
603
604 return w;
605}
606
607QDesignerFormEditorInterface *WidgetFactory::core() const
608{
609 return m_core;
610}
611
612// Necessary initializations for form editor/preview objects
613void WidgetFactory::initializeCommon(QWidget *widget) const
614{
615 // Apply style
616 if (m_currentStyle)
617 widget->setStyle(m_currentStyle);
618 // Prevent the wizard from emulating the Windows Vista Theme.
619 // This theme (in both Aero and Basic mode) is tricky to
620 // emulate properly in designer due to 1) the manipulation of the non-client area of
621 // the top-level window, and 2) the upper-right location of the Back button.
622 // The wizard falls back to QWizard::ModernStyle whenever the Vista theme
623 // would normally apply.
624 if (QWizard *wizard = qobject_cast<QWizard *>(widget)) {
625 wizard->setProperty("_q_wizard_vista_off", QVariant(true));
626 return;
627 }
628}
629
630// Necessary initializations for preview objects
631void WidgetFactory::initializePreview(QWidget *widget) const
632{
633
634 if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget)) {
635 QStackedWidgetPreviewEventFilter::install(stackedWidget); // Add browse button only.
636 return;
637 }
638}
639
640// Necessary initializations for form editor objects
641void WidgetFactory::initialize(QObject *object) const
642{
643 // Indicate that this is a form object (for QDesignerFormWindowInterface::findFormWindow)
644 object->setProperty(formEditorDynamicProperty, QVariant(true));
645 QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_core->extensionManager(), object);
646 if (!sheet)
647 return;
648
649 sheet->setChanged(sheet->indexOf(m_strings.m_objectName), true);
650
651 if (!object->isWidgetType()) {
652 if (qobject_cast<QAction*>(object))
653 sheet->setChanged(sheet->indexOf(m_strings.m_text), true);
654 return;
655 }
656
657 QWidget *widget = static_cast<QWidget*>(object);
658 const bool isMenu = qobject_cast<QMenu*>(widget);
659 const bool isMenuBar = !isMenu && qobject_cast<QMenuBar*>(widget);
660
661 widget->setAttribute(Qt::WA_TransparentForMouseEvents, false);
662 widget->setFocusPolicy((isMenu || isMenuBar) ? Qt::StrongFocus : Qt::NoFocus);
663
664 if (!isMenu)
665 sheet->setChanged(sheet->indexOf(m_strings.m_geometry), true);
666
667 if (qobject_cast<Spacer*>(widget)) {
668 sheet->setChanged(sheet->indexOf(m_strings.m_spacerName), true);
669 return;
670 }
671
672 const int o = sheet->indexOf(m_strings.m_orientation);
673 if (o != -1 && widget->inherits("QSplitter"))
674 sheet->setChanged(o, true);
675
676 if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget)) {
677 ToolBarEventFilter::install(toolBar);
678 sheet->setVisible(sheet->indexOf(m_strings.m_windowTitle), true);
679 toolBar->setFloatable(false); // prevent toolbars from being dragged off
680 return;
681 }
682
683 if (qobject_cast<QDockWidget*>(widget)) {
684 sheet->setVisible(sheet->indexOf(m_strings.m_windowTitle), true);
685 sheet->setVisible(sheet->indexOf(m_strings.m_windowIcon), true);
686 return;
687 }
688
689 if (isMenu) {
690 sheet->setChanged(sheet->indexOf(m_strings.m_title), true);
691 return;
692 }
693 // helpers
694 if (QToolBox *toolBox = qobject_cast<QToolBox*>(widget)) {
695 QToolBoxHelper::install(toolBox);
696 return;
697 }
698 if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget)) {
699 QStackedWidgetEventFilter::install(stackedWidget);
700 return;
701 }
702 if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(widget)) {
703 QTabWidgetEventFilter::install(tabWidget);
704 return;
705 }
706 // Prevent embedded line edits from getting focus
707 if (QAbstractSpinBox *asb = qobject_cast<QAbstractSpinBox *>(widget)) {
708 if (QLineEdit *lineEdit = static_cast<FriendlySpinBox*>(asb)->lineEdit())
709 lineEdit->setFocusPolicy(Qt::NoFocus);
710 return;
711 }
712 if (QComboBox *cb = qobject_cast<QComboBox *>(widget)) {
713 if (QFontComboBox *fcb = qobject_cast<QFontComboBox *>(widget)) {
714 fcb->lineEdit()->setFocusPolicy(Qt::NoFocus); // Always present
715 return;
716 }
717 cb->installEventFilter(new ComboEventFilter(cb));
718 return;
719 }
720 if (QWizard *wz = qobject_cast<QWizard *>(widget)) {
721 WizardPageChangeWatcher *pw = new WizardPageChangeWatcher(wz);
722 Q_UNUSED(pw);
723 }
724}
725
726static inline QString classNameOfStyle(const QStyle *s)
727{
728 return QLatin1String(s->metaObject()->className());
729}
730
731QString WidgetFactory::styleName() const
732{
733 return classNameOfStyle(style());
734}
735
736static inline bool isApplicationStyle(const QString &styleName)
737{
738 return styleName.isEmpty() || styleName == classNameOfStyle(qApp->style());
739}
740
741void WidgetFactory::setStyleName(const QString &styleName)
742{
743 m_currentStyle = isApplicationStyle(styleName) ? static_cast<QStyle*>(0) : getStyle(styleName);
744}
745
746QStyle *WidgetFactory::style() const
747{
748 return m_currentStyle ? m_currentStyle : qApp->style();
749}
750
751QStyle *WidgetFactory::getStyle(const QString &styleName)
752{
753 if (isApplicationStyle(styleName))
754 return qApp->style();
755
756 StyleCache::iterator it = m_styleCache.find(styleName);
757 if (it == m_styleCache.end()) {
758 QStyle *style = QStyleFactory::create(styleName);
759 if (!style) {
760 const QString msg = tr("Cannot create style '%1'.").arg(styleName);
761 designerWarning(msg);
762 return 0;
763 }
764 it = m_styleCache.insert(styleName, style);
765 }
766 return it.value();
767}
768
769void WidgetFactory::applyStyleTopLevel(const QString &styleName, QWidget *w)
770{
771 if (QStyle *style = getStyle(styleName))
772 applyStyleToTopLevel(style, w);
773}
774
775void WidgetFactory::applyStyleToTopLevel(QStyle *style, QWidget *widget)
776{
777 if (!style)
778 return;
779 const QPalette standardPalette = style->standardPalette();
780 if (widget->style() == style && widget->palette() == standardPalette)
781 return;
782
783 widget->setStyle(style);
784 widget->setPalette(standardPalette);
785 const QWidgetList lst = qFindChildren<QWidget*>(widget);
786 const QWidgetList::const_iterator cend = lst.constEnd();
787 for (QWidgetList::const_iterator it = lst.constBegin(); it != cend; ++it)
788 (*it)->setStyle(style);
789}
790
791// Check for 'interactor' click on a tab bar,
792// which can appear within a QTabWidget or as a standalone widget.
793
794static bool isTabBarInteractor(const QTabBar *tabBar)
795{
796 // Tabbar embedded in Q(Designer)TabWidget, ie, normal tab widget case
797 if (qobject_cast<const QTabWidget*>(tabBar->parentWidget()))
798 return true;
799
800 // Standalone tab bar on the form. Return true for tab rect areas
801 // only to allow the user to select the tab bar by clicking outside the actual tabs.
802 const int count = tabBar->count();
803 if (count == 0)
804 return false;
805
806 // click into current tab: No Interaction
807 const int currentIndex = tabBar->currentIndex();
808 const QPoint pos = tabBar->mapFromGlobal(QCursor::pos());
809 if (tabBar->tabRect(currentIndex).contains(pos))
810 return false;
811
812 // click outside: No Interaction
813 const QRect geometry = QRect(QPoint(0, 0), tabBar->size());
814 if (!geometry.contains(pos))
815 return false;
816 // click into another tab: Let's interact, switch tabs.
817 for (int i = 0; i < count; i++)
818 if (tabBar->tabRect(i).contains(pos))
819 return true;
820 return false;
821}
822
823bool WidgetFactory::isPassiveInteractor(QWidget *widget)
824{
825 static const QString qtPassive = QLatin1String("__qt__passive_");
826 if (m_lastPassiveInteractor != 0 && (QWidget*)(*m_lastPassiveInteractor) == widget)
827 return m_lastWasAPassiveInteractor;
828
829 if (QApplication::activePopupWidget() || widget == 0) // if a popup is open, we have to make sure that this one is closed, else X might do funny things
830 return true;
831
832 m_lastWasAPassiveInteractor = false;
833 (*m_lastPassiveInteractor) = widget;
834
835 if (const QTabBar *tabBar = qobject_cast<const QTabBar*>(widget)) {
836 if (isTabBarInteractor(tabBar))
837 m_lastWasAPassiveInteractor = true;
838 return m_lastWasAPassiveInteractor;
839#ifndef QT_NO_SIZEGRIP
840 } else if (qobject_cast<QSizeGrip*>(widget)) {
841 return (m_lastWasAPassiveInteractor = true);
842#endif
843 } else if (qobject_cast<QMdiSubWindow*>(widget))
844 return (m_lastWasAPassiveInteractor = true);
845 else if (qobject_cast<QAbstractButton*>(widget) && (qobject_cast<QTabBar*>(widget->parent()) || qobject_cast<QToolBox*>(widget->parent())))
846 return (m_lastWasAPassiveInteractor = true);
847 else if (qobject_cast<QMenuBar*>(widget))
848 return (m_lastWasAPassiveInteractor = true);
849 else if (qobject_cast<QToolBar*>(widget))
850 return (m_lastWasAPassiveInteractor = true);
851 else if (qobject_cast<QScrollBar*>(widget)) {
852 // A scroll bar is an interactor on a QAbstractScrollArea only.
853 if (const QWidget *parent = widget->parentWidget()) {
854 const QString objectName = parent->objectName();
855 static const QString scrollAreaVContainer = QLatin1String("qt_scrollarea_vcontainer");
856 void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow);
857 void formWindowAdded(QDesignerFormWindowInterface *formWindow);
858 static const QString scrollAreaHContainer = QLatin1String("qt_scrollarea_hcontainer");
859 if (objectName == scrollAreaVContainer || objectName == scrollAreaHContainer) {
860 m_lastWasAPassiveInteractor = true;
861 return m_lastWasAPassiveInteractor;
862 }
863 }
864 } else if (qstrcmp(widget->metaObject()->className(), "QDockWidgetTitle") == 0)
865 return (m_lastWasAPassiveInteractor = true);
866 else if (qstrcmp(widget->metaObject()->className(), "QWorkspaceTitleBar") == 0)
867 return (m_lastWasAPassiveInteractor = true);
868 else if (widget->objectName().startsWith(qtPassive))
869 return (m_lastWasAPassiveInteractor = true);
870 return m_lastWasAPassiveInteractor;
871}
872
873void WidgetFactory::formWindowAdded(QDesignerFormWindowInterface *formWindow)
874{
875 setFormWindowStyle(formWindow);
876}
877
878void WidgetFactory::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow)
879{
880 setFormWindowStyle(formWindow);
881}
882
883void WidgetFactory::setFormWindowStyle(QDesignerFormWindowInterface *formWindow)
884{
885 if (FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow))
886 setStyleName(fwb->styleName());
887}
888
889bool WidgetFactory::isFormEditorObject(const QObject *object)
890{
891 return object->property(formEditorDynamicProperty).isValid();
892}
893} // namespace qdesigner_internal
894
895QT_END_NAMESPACE
896
897#include "widgetfactory.moc"
Note: See TracBrowser for help on using the repository browser.