/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the Qt Designer of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "widgetfactory_p.h" #include "widgetdatabase_p.h" #include "metadatabase_p.h" #include "qlayout_widget_p.h" #include "qdesigner_widget_p.h" #include "qdesigner_tabwidget_p.h" #include "qdesigner_toolbox_p.h" #include "qdesigner_stackedbox_p.h" #include "qdesigner_toolbar_p.h" #include "qdesigner_menubar_p.h" #include "qdesigner_menu_p.h" #include "qdesigner_dockwidget_p.h" #include "qdesigner_utils_p.h" #include "formwindowbase_p.h" // shared #include "layoutinfo_p.h" #include "spacer_widget_p.h" #include "layout_p.h" #include "abstractintrospection_p.h" // sdk #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE #ifdef Q_OS_WIN static inline bool isAxWidget(const QObject *o) { // Is it one of QDesignerAxWidget/QDesignerAxPluginWidget? static const char *axWidgetName = "QDesignerAx"; static const unsigned axWidgetNameLen = qstrlen(axWidgetName); return qstrncmp(o->metaObject()->className(), axWidgetName, axWidgetNameLen) == 0; } #endif /* Dynamic boolean property indicating object was created by the factory * for the form editor. */ static const char *formEditorDynamicProperty = "_q_formEditorObject"; namespace qdesigner_internal { // A friendly SpinBox that grants access to its QLineEdit class FriendlySpinBox : public QAbstractSpinBox { public: friend class WidgetFactory; }; // An event filter for form-combo boxes that prevents the embedded line edit // from getting edit focus (and drawing blue artifacts/lines). It catches the // ChildPolished event when the "editable" property flips to true and the // QLineEdit is created and turns off the LineEdit's focus policy. class ComboEventFilter : public QObject { public: explicit ComboEventFilter(QComboBox *parent) : QObject(parent) {} virtual bool eventFilter(QObject *watched, QEvent *event); }; bool ComboEventFilter::eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::ChildPolished) { QComboBox *cb = static_cast(watched); if (QLineEdit *le = cb->lineEdit()) le->setFocusPolicy(Qt::NoFocus); } return QObject::eventFilter(watched, event); } /* Watch out for QWizards changing their pages and make sure that not some * selected widget becomes invisible on a hidden page (causing the selection * handles to shine through). Select the wizard in that case in analogy to * the QTabWidget event filters, etc. */ class WizardPageChangeWatcher : public QObject { Q_OBJECT public: explicit WizardPageChangeWatcher(QWizard *parent); public slots: void pageChanged(); }; WizardPageChangeWatcher::WizardPageChangeWatcher(QWizard *parent) : QObject(parent) { connect(parent, SIGNAL(currentIdChanged(int)), this, SLOT(pageChanged())); } void WizardPageChangeWatcher::pageChanged() { /* Use a bit more conservative approach than that for the QTabWidget, * change the selection only if a selected child becomes invisible by * changing the page. */ QWizard *wizard = static_cast(parent()); QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(wizard); if (!fw) return; QDesignerFormWindowCursorInterface *cursor = fw->cursor(); const int selCount = cursor->selectedWidgetCount(); for (int i = 0; i < selCount; i++) { if (!cursor->selectedWidget(i)->isVisible()) { fw->clearSelection(false); fw->selectWidget(wizard, true); break; } } } // ---------------- WidgetFactory::Strings WidgetFactory::Strings::Strings() : m_alignment(QLatin1String("alignment")), m_bottomMargin(QLatin1String("bottomMargin")), m_geometry(QLatin1String("geometry")), m_leftMargin(QLatin1String("leftMargin")), m_line(QLatin1String("Line")), m_objectName(QLatin1String("objectName")), m_spacerName(QLatin1String("spacerName")), m_orientation(QLatin1String("orientation")), m_q3WidgetStack(QLatin1String("Q3WidgetStack")), m_qAction(QLatin1String("QAction")), m_qButtonGroup(QLatin1String("QButtonGroup")), m_qAxWidget(QLatin1String("QAxWidget")), m_qDialog(QLatin1String("QDialog")), m_qDockWidget(QLatin1String("QDockWidget")), m_qLayoutWidget(QLatin1String("QLayoutWidget")), m_qMenu(QLatin1String("QMenu")), m_qMenuBar(QLatin1String("QMenuBar")), m_qWidget(QLatin1String("QWidget")), m_rightMargin(QLatin1String("rightMargin")), m_sizeHint(QLatin1String("sizeHint")), m_spacer(QLatin1String("Spacer")), m_text(QLatin1String("text")), m_title(QLatin1String("title")), m_topMargin(QLatin1String("topMargin")), m_windowIcon(QLatin1String("windowIcon")), m_windowTitle(QLatin1String("windowTitle")) { } // ---------------- WidgetFactory QPointer *WidgetFactory::m_lastPassiveInteractor = new QPointer(); bool WidgetFactory::m_lastWasAPassiveInteractor = false; const char *WidgetFactory::disableStyleCustomPaintingPropertyC = "_q_custom_style_disabled"; WidgetFactory::WidgetFactory(QDesignerFormEditorInterface *core, QObject *parent) : QDesignerWidgetFactoryInterface(parent), m_core(core), m_formWindow(0), m_currentStyle(0) { } WidgetFactory::~WidgetFactory() { } QDesignerFormWindowInterface *WidgetFactory::currentFormWindow(QDesignerFormWindowInterface *fw) { QDesignerFormWindowInterface *was = m_formWindow; m_formWindow = fw; return was; } void WidgetFactory::loadPlugins() { m_customFactory.clear(); QDesignerPluginManager *pluginManager = m_core->pluginManager(); QList lst = pluginManager->registeredCustomWidgets(); foreach (QDesignerCustomWidgetInterface *c, lst) { m_customFactory.insert(c->name(), c); } } // Convencience to create non-widget objects. Returns 0 if unknown QObject* WidgetFactory::createObject(const QString &className, QObject* parent) const { if (className.isEmpty()) { qWarning("** WARNING %s called with an empty class name", Q_FUNC_INFO); return 0; } if (className == m_strings.m_qAction) return new QAction(parent); if (className == m_strings.m_qButtonGroup) return new QButtonGroup(parent); return 0; } QWidget* WidgetFactory::createCustomWidget(const QString &className, QWidget *parentWidget, bool *creationError) const { *creationError = false; CustomWidgetFactoryMap::const_iterator it = m_customFactory.constFind(className); if (it == m_customFactory.constEnd()) return 0; QDesignerCustomWidgetInterface *factory = it.value(); QWidget *rc = factory->createWidget(parentWidget); // shouldn't happen if (!rc) { *creationError = true; designerWarning(tr("The custom widget factory registered for widgets of class %1 returned 0.").arg(className)); return 0; } // Figure out the base class unless it is known static QSet knownCustomClasses; if (!knownCustomClasses.contains(className)) { QDesignerWidgetDataBaseInterface *wdb = m_core->widgetDataBase(); const int widgetInfoIndex = wdb->indexOfObject(rc, false); if (widgetInfoIndex != -1) { if (wdb->item(widgetInfoIndex)->extends().isEmpty()) { const QDesignerMetaObjectInterface *mo = core()->introspection()->metaObject(rc)->superClass(); // If we hit on a 'Q3DesignerXXWidget' that claims to be a 'Q3XXWidget', step // over. if (mo && mo->className() == className) mo = mo->superClass(); while (mo != 0) { if (core()->widgetDataBase()->indexOfClassName(mo->className()) != -1) { wdb->item(widgetInfoIndex)->setExtends(mo->className()); break; } mo = mo->superClass(); } } knownCustomClasses.insert(className); } } // Since a language plugin may lie about its names, like Qt Jambi // does, return immediately here... QDesignerLanguageExtension *lang = qt_extension(m_core->extensionManager(), m_core); if (lang) return rc; #ifdef Q_OS_WIN if (isAxWidget(rc)) return rc; #endif // Check for mismatched class names which is hard to track. // Perform literal comparison first for QAxWidget, for which a meta object hack is in effect. const char *createdClassNameC = rc->metaObject()->className(); const QByteArray classNameB = className.toUtf8(); const char *classNameC = classNameB.constData(); if (qstrcmp(createdClassNameC, classNameC) && !rc->inherits(classNameC)) designerWarning(tr("A class name mismatch occurred when creating a widget using the custom widget factory registered for widgets of class %1." " It returned a widget of class %2.").arg(className).arg(QString::fromUtf8(createdClassNameC))); return rc; } QWidget *WidgetFactory::createWidget(const QString &widgetName, QWidget *parentWidget) const { if (widgetName.isEmpty()) { qWarning("** WARNING %s called with an empty class name", Q_FUNC_INFO); return 0; } // Preview or for form window? QDesignerFormWindowInterface *fw = m_formWindow; if (! fw) fw = QDesignerFormWindowInterface::findFormWindow(parentWidget); QWidget *w = 0; do { // 1) custom. If there is an explicit failure(factory wants to indicate something is wrong), // return 0, do not try to find fallback, which might be worse in the case of Q3 widget. bool customWidgetCreationError; w = createCustomWidget(widgetName, parentWidget, &customWidgetCreationError); if (w) { break; } else { if (customWidgetCreationError) return 0; } // 2) Special widgets if (widgetName == m_strings.m_line) { w = new Line(parentWidget); } else if (widgetName == m_strings.m_qDockWidget) { w = new QDesignerDockWidget(parentWidget); } else if (widgetName == m_strings.m_qMenuBar) { w = new QDesignerMenuBar(parentWidget); } else if (widgetName == m_strings.m_qMenu) { w = new QDesignerMenu(parentWidget); } else if (widgetName == m_strings.m_spacer) { w = new Spacer(parentWidget); } else if (widgetName == m_strings.m_qDockWidget) { w = new QDesignerDockWidget(parentWidget); } else if (widgetName == m_strings.m_qLayoutWidget) { w = fw ? new QLayoutWidget(fw, parentWidget) : new QWidget(parentWidget); } else if (widgetName == m_strings.m_qDialog) { if (fw) { w = new QDesignerDialog(fw, parentWidget); } else { w = new QDialog(parentWidget); } } else if (widgetName == m_strings.m_qWidget) { /* We want a 'QDesignerWidget' that draws a grid only for widget * forms and container extension pages (not for preview and not * for normal QWidget children on forms (legacy) */ if (fw && parentWidget) { if (qt_extension(m_core->extensionManager(), parentWidget)) { w = new QDesignerWidget(fw, parentWidget); } else { if (const FormWindowBase *fwb = qobject_cast(fw)) if (parentWidget == fwb->formContainer()) w = new QDesignerWidget(fw, parentWidget); } } if (!w) w = new QWidget(parentWidget); } if (w) break; // 3) table const QByteArray widgetNameBA = widgetName.toUtf8(); const char *widgetNameC = widgetNameBA.constData(); if (w) { // symmetry for macro } #define DECLARE_LAYOUT(L, C) #define DECLARE_COMPAT_WIDGET(W, C) /*DECLARE_WIDGET(W, C)*/ #define DECLARE_WIDGET(W, C) else if (!qstrcmp(widgetNameC, #W)) { Q_ASSERT(w == 0); w = new W(parentWidget); } #define DECLARE_WIDGET_1(W, C) else if (!qstrcmp(widgetNameC, #W)) { Q_ASSERT(w == 0); w = new W(0, parentWidget); } #include "widgets.table" #undef DECLARE_COMPAT_WIDGET #undef DECLARE_LAYOUT #undef DECLARE_WIDGET #undef DECLARE_WIDGET_1 if (w) break; // 4) fallBack const QString fallBackBaseClass = m_strings.m_qWidget; QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase(); QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfClassName(widgetName)); if (item == 0) { // Emergency: Create, derived from QWidget QString includeFile = widgetName.toLower(); includeFile += QLatin1String(".h"); item = appendDerived(db,widgetName, tr("%1 Widget").arg(widgetName),fallBackBaseClass, includeFile, true, true); Q_ASSERT(item); } QString baseClass = item->extends(); if (baseClass.isEmpty()) { // Currently happens in the case of Q3-Support widgets baseClass =fallBackBaseClass; } w = createWidget(baseClass, parentWidget); promoteWidget(core(),w,widgetName); } while (false); Q_ASSERT(w != 0); if (m_currentStyle) w->setStyle(m_currentStyle); initializeCommon(w); if (fw) { // form editor initialization initialize(w); } else { // preview-only initialization initializePreview(w); } return w; } QString WidgetFactory::classNameOf(QDesignerFormEditorInterface *c, const QObject* o) { if (o == 0) return QString(); const char *className = o->metaObject()->className(); if (!o->isWidgetType()) return QLatin1String(className); const QWidget *w = static_cast(o); // check promoted before designer special const QString customClassName = promotedCustomClassName(c, const_cast(w)); if (!customClassName.isEmpty()) return customClassName; if (qobject_cast(w)) return QLatin1String("QMenuBar"); else if (qobject_cast(w)) return QLatin1String("QMenu"); else if (qobject_cast(w)) return QLatin1String("QDockWidget"); else if (qobject_cast(w)) return QLatin1String("QDialog"); else if (qobject_cast(w)) return QLatin1String("QWidget"); #ifdef Q_OS_WIN else if (isAxWidget(w)) return QLatin1String("QAxWidget"); #endif else if (qstrcmp(className, "QDesignerQ3WidgetStack") == 0) return QLatin1String("Q3WidgetStack"); return QLatin1String(className); } QLayout *WidgetFactory::createUnmanagedLayout(QWidget *parentWidget, int type) { switch (type) { case LayoutInfo::HBox: return new QHBoxLayout(parentWidget); case LayoutInfo::VBox: return new QVBoxLayout(parentWidget); case LayoutInfo::Grid: return new QGridLayout(parentWidget); case LayoutInfo::Form: return new QFormLayout(parentWidget); default: Q_ASSERT(0); break; } return 0; } /*! Creates a layout on the widget \a widget of the type \a type which can be \c HBox, \c VBox or \c Grid. */ QLayout *WidgetFactory::createLayout(QWidget *widget, QLayout *parentLayout, int type) const // ### (sizepolicy) { QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase(); if (parentLayout == 0) { QWidget *page = containerOfWidget(widget); if (page) { widget = page; } else { const QString msg = tr("The current page of the container '%1' (%2) could not be determined while creating a layout." "This indicates an inconsistency in the ui-file, probably a layout being constructed on a container widget.").arg(widget->objectName()).arg(classNameOf(core(), widget)); designerWarning(msg); } } Q_ASSERT(metaDataBase->item(widget) != 0); // ensure the widget is managed if (parentLayout == 0 && metaDataBase->item(widget->layout()) == 0) { parentLayout = widget->layout(); } QWidget *parentWidget = parentLayout != 0 ? 0 : widget; QLayout *layout = createUnmanagedLayout(parentWidget, type); metaDataBase->add(layout); // add the layout in the MetaDataBase QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), layout); sheet->setChanged(sheet->indexOf(m_strings.m_objectName), true); if (widget->inherits("Q3GroupBox")) { layout->setContentsMargins(widget->style()->pixelMetric(QStyle::PM_LayoutLeftMargin), widget->style()->pixelMetric(QStyle::PM_LayoutTopMargin), widget->style()->pixelMetric(QStyle::PM_LayoutRightMargin), widget->style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); QGridLayout *grid = qobject_cast(layout); if (grid) { grid->setHorizontalSpacing(-1); grid->setVerticalSpacing(-1); } else { layout->setSpacing(-1); } layout->setAlignment(Qt::AlignTop); // Just to ensure; before 4.3 orientation property was always set (now only for QSplitter class). // Calling Q3GroupBox::setOrientation() invoked in turn setSpacing(0). Below fixes that widget->layout()->setSpacing(-1); } else if (widget->inherits("QLayoutWidget")) { sheet->setProperty(sheet->indexOf(m_strings.m_leftMargin), 0); sheet->setProperty(sheet->indexOf(m_strings.m_topMargin), 0); sheet->setProperty(sheet->indexOf(m_strings.m_rightMargin), 0); sheet->setProperty(sheet->indexOf(m_strings.m_bottomMargin), 0); } if (sheet) { const int index = sheet->indexOf(m_strings.m_alignment); if (index != -1) sheet->setChanged(index, true); } if (metaDataBase->item(widget->layout()) == 0) { Q_ASSERT(layout->parent() == 0); QBoxLayout *box = qobject_cast(widget->layout()); if (!box) { // we support only unmanaged box layouts const QString msg = tr("Attempt to add a layout to a widget '%1' (%2) which already has an unmanaged layout of type %3.\n" "This indicates an inconsistency in the ui-file."). arg(widget->objectName()).arg(classNameOf(core(), widget)).arg(classNameOf(core(), widget->layout())); designerWarning(msg); return 0; } box->addLayout(layout); } return layout; } /*! Returns the widget into which children should be inserted when \a w is a container known to designer. Usually, it is \a w itself, but there are exceptions (for example, a tabwidget is known to designer as a container, but the child widgets should be inserted into the current page of the tabwidget. In this case, the current page of the tabwidget would be returned.) */ QWidget* WidgetFactory::containerOfWidget(QWidget *w) const { if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), w)) return container->widget(container->currentIndex()); return w; } /*! Returns the actual designer widget of the container \a w. This is normally \a w itself, but it might be a parent or grand parent of \a w (for example, when working with a tabwidget and \a w is the container which contains and layouts children, but the actual widget known to designer is the tabwidget which is the parent of \a w. In this case, the tabwidget would be returned.) */ QWidget* WidgetFactory::widgetOfContainer(QWidget *w) const { // ### cleanup if (!w) return 0; if (w->parentWidget() && w->parentWidget()->parentWidget() && w->parentWidget()->parentWidget()->parentWidget() && qobject_cast(w->parentWidget()->parentWidget()->parentWidget())) return w->parentWidget()->parentWidget()->parentWidget(); while (w != 0) { if (core()->widgetDataBase()->isContainer(w) || (w && qobject_cast(w->parentWidget()))) return w; w = w->parentWidget(); } return w; } QDesignerFormEditorInterface *WidgetFactory::core() const { return m_core; } // Necessary initializations for form editor/preview objects void WidgetFactory::initializeCommon(QWidget *widget) const { // Apply style if (m_currentStyle) widget->setStyle(m_currentStyle); // Prevent the wizard from emulating the Windows Vista Theme. // This theme (in both Aero and Basic mode) is tricky to // emulate properly in designer due to 1) the manipulation of the non-client area of // the top-level window, and 2) the upper-right location of the Back button. // The wizard falls back to QWizard::ModernStyle whenever the Vista theme // would normally apply. if (QWizard *wizard = qobject_cast(widget)) { wizard->setProperty("_q_wizard_vista_off", QVariant(true)); return; } } // Necessary initializations for preview objects void WidgetFactory::initializePreview(QWidget *widget) const { if (QStackedWidget *stackedWidget = qobject_cast(widget)) { QStackedWidgetPreviewEventFilter::install(stackedWidget); // Add browse button only. return; } } // Necessary initializations for form editor objects void WidgetFactory::initialize(QObject *object) const { // Indicate that this is a form object (for QDesignerFormWindowInterface::findFormWindow) object->setProperty(formEditorDynamicProperty, QVariant(true)); QDesignerPropertySheetExtension *sheet = qt_extension(m_core->extensionManager(), object); if (!sheet) return; sheet->setChanged(sheet->indexOf(m_strings.m_objectName), true); if (!object->isWidgetType()) { if (qobject_cast(object)) sheet->setChanged(sheet->indexOf(m_strings.m_text), true); return; } QWidget *widget = static_cast(object); const bool isMenu = qobject_cast(widget); const bool isMenuBar = !isMenu && qobject_cast(widget); widget->setAttribute(Qt::WA_TransparentForMouseEvents, false); widget->setFocusPolicy((isMenu || isMenuBar) ? Qt::StrongFocus : Qt::NoFocus); if (!isMenu) sheet->setChanged(sheet->indexOf(m_strings.m_geometry), true); if (qobject_cast(widget)) { sheet->setChanged(sheet->indexOf(m_strings.m_spacerName), true); return; } const int o = sheet->indexOf(m_strings.m_orientation); if (o != -1 && widget->inherits("QSplitter")) sheet->setChanged(o, true); if (QToolBar *toolBar = qobject_cast(widget)) { ToolBarEventFilter::install(toolBar); sheet->setVisible(sheet->indexOf(m_strings.m_windowTitle), true); toolBar->setFloatable(false); // prevent toolbars from being dragged off return; } if (qobject_cast(widget)) { sheet->setVisible(sheet->indexOf(m_strings.m_windowTitle), true); sheet->setVisible(sheet->indexOf(m_strings.m_windowIcon), true); return; } if (isMenu) { sheet->setChanged(sheet->indexOf(m_strings.m_title), true); return; } // helpers if (QToolBox *toolBox = qobject_cast(widget)) { QToolBoxHelper::install(toolBox); return; } if (QStackedWidget *stackedWidget = qobject_cast(widget)) { QStackedWidgetEventFilter::install(stackedWidget); return; } if (QTabWidget *tabWidget = qobject_cast(widget)) { QTabWidgetEventFilter::install(tabWidget); return; } // Prevent embedded line edits from getting focus if (QAbstractSpinBox *asb = qobject_cast(widget)) { if (QLineEdit *lineEdit = static_cast(asb)->lineEdit()) lineEdit->setFocusPolicy(Qt::NoFocus); return; } if (QComboBox *cb = qobject_cast(widget)) { if (QFontComboBox *fcb = qobject_cast(widget)) { fcb->lineEdit()->setFocusPolicy(Qt::NoFocus); // Always present return; } cb->installEventFilter(new ComboEventFilter(cb)); return; } if (QWizard *wz = qobject_cast(widget)) { WizardPageChangeWatcher *pw = new WizardPageChangeWatcher(wz); Q_UNUSED(pw); } } static inline QString classNameOfStyle(const QStyle *s) { return QLatin1String(s->metaObject()->className()); } QString WidgetFactory::styleName() const { return classNameOfStyle(style()); } static inline bool isApplicationStyle(const QString &styleName) { return styleName.isEmpty() || styleName == classNameOfStyle(qApp->style()); } void WidgetFactory::setStyleName(const QString &styleName) { m_currentStyle = isApplicationStyle(styleName) ? static_cast(0) : getStyle(styleName); } QStyle *WidgetFactory::style() const { return m_currentStyle ? m_currentStyle : qApp->style(); } QStyle *WidgetFactory::getStyle(const QString &styleName) { if (isApplicationStyle(styleName)) return qApp->style(); StyleCache::iterator it = m_styleCache.find(styleName); if (it == m_styleCache.end()) { QStyle *style = QStyleFactory::create(styleName); if (!style) { const QString msg = tr("Cannot create style '%1'.").arg(styleName); designerWarning(msg); return 0; } it = m_styleCache.insert(styleName, style); } return it.value(); } void WidgetFactory::applyStyleTopLevel(const QString &styleName, QWidget *w) { if (QStyle *style = getStyle(styleName)) applyStyleToTopLevel(style, w); } void WidgetFactory::applyStyleToTopLevel(QStyle *style, QWidget *widget) { const QPalette standardPalette = style->standardPalette(); if (widget->style() == style && widget->palette() == standardPalette) return; widget->setStyle(style); widget->setPalette(standardPalette); const QWidgetList lst = qFindChildren(widget); const QWidgetList::const_iterator cend = lst.constEnd(); for (QWidgetList::const_iterator it = lst.constBegin(); it != cend; ++it) (*it)->setStyle(style); } // Check for 'interactor' click on a tab bar, // which can appear within a QTabWidget or as a standalone widget. static bool isTabBarInteractor(const QTabBar *tabBar) { // Tabbar embedded in Q(Designer)TabWidget, ie, normal tab widget case if (qobject_cast(tabBar->parentWidget())) return true; // Standalone tab bar on the form. Return true for tab rect areas // only to allow the user to select the tab bar by clicking outside the actual tabs. const int count = tabBar->count(); if (count == 0) return false; // click into current tab: No Interaction const int currentIndex = tabBar->currentIndex(); const QPoint pos = tabBar->mapFromGlobal(QCursor::pos()); if (tabBar->tabRect(currentIndex).contains(pos)) return false; // click outside: No Interaction const QRect geometry = QRect(QPoint(0, 0), tabBar->size()); if (!geometry.contains(pos)) return false; // click into another tab: Let's interact, switch tabs. for (int i = 0; i < count; i++) if (tabBar->tabRect(i).contains(pos)) return true; return false; } bool WidgetFactory::isPassiveInteractor(QWidget *widget) { static const QString qtPassive = QLatin1String("__qt__passive_"); if (m_lastPassiveInteractor != 0 && (QWidget*)(*m_lastPassiveInteractor) == widget) return m_lastWasAPassiveInteractor; 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 return true; m_lastWasAPassiveInteractor = false; (*m_lastPassiveInteractor) = widget; if (const QTabBar *tabBar = qobject_cast(widget)) { if (isTabBarInteractor(tabBar)) m_lastWasAPassiveInteractor = true; return m_lastWasAPassiveInteractor; } else if (qobject_cast(widget)) return (m_lastWasAPassiveInteractor = true); else if (qobject_cast(widget)) return (m_lastWasAPassiveInteractor = true); else if (qobject_cast(widget) && (qobject_cast(widget->parent()) || qobject_cast(widget->parent()))) return (m_lastWasAPassiveInteractor = true); else if (qobject_cast(widget)) return (m_lastWasAPassiveInteractor = true); else if (qobject_cast(widget)) return (m_lastWasAPassiveInteractor = true); else if (qobject_cast(widget)) { // A scroll bar is an interactor on a QAbstractScrollArea only. if (const QWidget *parent = widget->parentWidget()) { const QString objectName = parent->objectName(); static const QString scrollAreaVContainer = QLatin1String("qt_scrollarea_vcontainer"); void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); void formWindowAdded(QDesignerFormWindowInterface *formWindow); static const QString scrollAreaHContainer = QLatin1String("qt_scrollarea_hcontainer"); if (objectName == scrollAreaVContainer || objectName == scrollAreaHContainer) { m_lastWasAPassiveInteractor = true; return m_lastWasAPassiveInteractor; } } } else if (qstrcmp(widget->metaObject()->className(), "QDockWidgetTitle") == 0) return (m_lastWasAPassiveInteractor = true); else if (qstrcmp(widget->metaObject()->className(), "QWorkspaceTitleBar") == 0) return (m_lastWasAPassiveInteractor = true); else if (widget->objectName().startsWith(qtPassive)) return (m_lastWasAPassiveInteractor = true); return m_lastWasAPassiveInteractor; } void WidgetFactory::formWindowAdded(QDesignerFormWindowInterface *formWindow) { setFormWindowStyle(formWindow); } void WidgetFactory::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) { setFormWindowStyle(formWindow); } void WidgetFactory::setFormWindowStyle(QDesignerFormWindowInterface *formWindow) { if (FormWindowBase *fwb = qobject_cast(formWindow)) setStyleName(fwb->styleName()); } bool WidgetFactory::isFormEditorObject(const QObject *object) { return object->property(formEditorDynamicProperty).isValid(); } } // namespace qdesigner_internal QT_END_NAMESPACE #include "widgetfactory.moc"