/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the Qt Designer of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** 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.1, 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. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qdesigner_formbuilder_p.h" | |
#include "dynamicpropertysheet.h" | |
#include "qsimpleresource_p.h" | |
#include "widgetfactory_p.h" | |
#include "qdesigner_introspection_p.h" | |
#include <ui4_p.h> | |
#include <formbuilderextra_p.h> | |
// sdk | |
#include <QtDesigner/container.h> | |
#include <QtDesigner/customwidget.h> | |
#include <QtDesigner/propertysheet.h> | |
#include <QtDesigner/QExtensionManager> | |
#include <QtDesigner/QDesignerFormEditorInterface> | |
#include <QtDesigner/QDesignerFormWindowInterface> | |
#include <QtDesigner/QDesignerWidgetFactoryInterface> | |
#include <QtDesigner/QDesignerCustomWidgetInterface> | |
#include <abstractdialoggui_p.h> | |
// shared | |
#include <qdesigner_propertysheet_p.h> | |
#include <qdesigner_utils_p.h> | |
#include <formwindowbase_p.h> | |
#include <qtresourcemodel_p.h> | |
#include <scripterrordialog_p.h> | |
#include <QtGui/QWidget> | |
#include <QtGui/QMenu> | |
#include <QtGui/QToolBar> | |
#include <QtGui/QMenuBar> | |
#include <QtGui/QMainWindow> | |
#include <QtGui/QStyleFactory> | |
#include <QtGui/QStyle> | |
#include <QtGui/QApplication> | |
#include <QtGui/QAbstractScrollArea> | |
#include <QtGui/QMessageBox> | |
#include <QtGui/QPixmap> | |
#include <QtCore/QBuffer> | |
#include <QtCore/qdebug.h> | |
#include <QtCore/QCoreApplication> | |
QT_BEGIN_NAMESPACE | |
#ifndef QT_FORMBUILDER_NO_SCRIPT | |
static QString summarizeScriptErrors(const QFormScriptRunner::Errors &errors) | |
{ | |
QString rc = QCoreApplication::translate("QDesignerFormBuilder", "Script errors occurred:"); | |
foreach (QFormScriptRunner::Error error, errors) { | |
rc += QLatin1Char('\n'); | |
rc += error.errorMessage; | |
} | |
return rc; | |
} | |
#endif | |
namespace qdesigner_internal { | |
QDesignerFormBuilder::QDesignerFormBuilder(QDesignerFormEditorInterface *core, | |
Mode mode, | |
const DeviceProfile &deviceProfile) : | |
m_core(core), | |
m_mode(mode), | |
m_deviceProfile(deviceProfile), | |
m_pixmapCache(0), | |
m_iconCache(0), | |
m_ignoreCreateResources(false), | |
m_tempResourceSet(0), | |
m_mainWidget(true) | |
{ | |
Q_ASSERT(m_core); | |
#ifndef QT_FORMBUILDER_NO_SCRIPT | |
// Disable scripting in the editors. | |
QFormScriptRunner::Options options = formScriptRunner()->options(); | |
switch (m_mode) { | |
case DisableScripts: | |
options |= QFormScriptRunner::DisableScripts; | |
break; | |
case EnableScripts: | |
options |= QFormScriptRunner::DisableWarnings; | |
options &= ~QFormScriptRunner::DisableScripts; | |
break; | |
} | |
formScriptRunner()-> setOptions(options); | |
#endif | |
} | |
QString QDesignerFormBuilder::systemStyle() const | |
{ | |
return m_deviceProfile.isEmpty() ? | |
QString::fromUtf8(QApplication::style()->metaObject()->className()) : | |
m_deviceProfile.style(); | |
} | |
QWidget *QDesignerFormBuilder::createWidgetFromContents(const QString &contents, QWidget *parentWidget) | |
{ | |
QByteArray data = contents.toUtf8(); | |
QBuffer buffer(&data); | |
buffer.open(QIODevice::ReadOnly); | |
return load(&buffer, parentWidget); | |
} | |
QWidget *QDesignerFormBuilder::create(DomUI *ui, QWidget *parentWidget) | |
{ | |
m_mainWidget = true; | |
QtResourceSet *resourceSet = core()->resourceModel()->currentResourceSet(); | |
// reload resource properties; | |
createResources(ui->elementResources()); | |
core()->resourceModel()->setCurrentResourceSet(m_tempResourceSet); | |
m_ignoreCreateResources = true; | |
DesignerPixmapCache pixmapCache; | |
DesignerIconCache iconCache(&pixmapCache); | |
m_pixmapCache = &pixmapCache; | |
m_iconCache = &iconCache; | |
QWidget *widget = QFormBuilder::create(ui, parentWidget); | |
core()->resourceModel()->setCurrentResourceSet(resourceSet); | |
core()->resourceModel()->removeResourceSet(m_tempResourceSet); | |
m_tempResourceSet = 0; | |
m_ignoreCreateResources = false; | |
m_pixmapCache = 0; | |
m_iconCache = 0; | |
m_customWidgetsWithScript.clear(); | |
return widget; | |
} | |
QWidget *QDesignerFormBuilder::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name) | |
{ | |
QWidget *widget = 0; | |
if (widgetName == QLatin1String("QToolBar")) { | |
widget = new QToolBar(parentWidget); | |
} else if (widgetName == QLatin1String("QMenu")) { | |
widget = new QMenu(parentWidget); | |
} else if (widgetName == QLatin1String("QMenuBar")) { | |
widget = new QMenuBar(parentWidget); | |
} else { | |
widget = core()->widgetFactory()->createWidget(widgetName, parentWidget); | |
} | |
if (widget) { | |
widget->setObjectName(name); | |
if (QSimpleResource::hasCustomWidgetScript(m_core, widget)) | |
m_customWidgetsWithScript.insert(widget); | |
} | |
if (m_mainWidget) { // We need to apply the DPI here to take effect on size hints, etc. | |
m_deviceProfile.apply(m_core, widget, DeviceProfile::ApplyPreview); | |
m_mainWidget = false; | |
} | |
return widget; | |
} | |
bool QDesignerFormBuilder::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) | |
{ | |
// Use container extension or rely on scripts unless main window. | |
if (QFormBuilder::addItem(ui_widget, widget, parentWidget)) | |
return true; | |
if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(m_core->extensionManager(), parentWidget)) { | |
container->addWidget(widget); | |
return true; | |
} | |
return false; | |
} | |
bool QDesignerFormBuilder::addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout) | |
{ | |
return QFormBuilder::addItem(ui_item, item, layout); | |
} | |
QIcon QDesignerFormBuilder::nameToIcon(const QString &filePath, const QString &qrcPath) | |
{ | |
Q_UNUSED(filePath) | |
Q_UNUSED(qrcPath) | |
qWarning() << "QDesignerFormBuilder::nameToIcon() is obsoleted"; | |
return QIcon(); | |
} | |
QPixmap QDesignerFormBuilder::nameToPixmap(const QString &filePath, const QString &qrcPath) | |
{ | |
Q_UNUSED(filePath) | |
Q_UNUSED(qrcPath) | |
qWarning() << "QDesignerFormBuilder::nameToPixmap() is obsoleted"; | |
return QPixmap(); | |
} | |
/* If the property is a enum or flag value, retrieve | |
* the existing enum/flag type via property sheet and use it to convert */ | |
static bool readDomEnumerationValue(const DomProperty *p, | |
const QDesignerPropertySheetExtension* sheet, | |
QVariant &v) | |
{ | |
switch (p->kind()) { | |
case DomProperty::Set: { | |
const int index = sheet->indexOf(p->attributeName()); | |
if (index == -1) | |
return false; | |
const QVariant sheetValue = sheet->property(index); | |
if (qVariantCanConvert<PropertySheetFlagValue>(sheetValue)) { | |
const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(sheetValue); | |
bool ok = false; | |
v = f.metaFlags.parseFlags(p->elementSet(), &ok); | |
if (!ok) | |
designerWarning(f.metaFlags.messageParseFailed(p->elementSet())); | |
return true; | |
} | |
} | |
break; | |
case DomProperty::Enum: { | |
const int index = sheet->indexOf(p->attributeName()); | |
if (index == -1) | |
return false; | |
const QVariant sheetValue = sheet->property(index); | |
if (qVariantCanConvert<PropertySheetEnumValue>(sheetValue)) { | |
const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(sheetValue); | |
bool ok = false; | |
v = e.metaEnum.parseEnum(p->elementEnum(), &ok); | |
if (!ok) | |
designerWarning(e.metaEnum.messageParseFailed(p->elementEnum())); | |
return true; | |
} | |
} | |
break; | |
default: | |
break; | |
} | |
return false; | |
} | |
void QDesignerFormBuilder::applyProperties(QObject *o, const QList<DomProperty*> &properties) | |
{ | |
typedef QList<DomProperty*> DomPropertyList; | |
if (properties.empty()) | |
return; | |
QFormBuilderExtra *formBuilderExtra = QFormBuilderExtra::instance(this); | |
const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), o); | |
const QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), o); | |
const bool changingMetaObject = WidgetFactory::classNameOf(core(), o) == QLatin1String("QAxWidget"); | |
const QDesignerMetaObjectInterface *meta = core()->introspection()->metaObject(o); | |
const bool dynamicPropertiesAllowed = dynamicSheet && dynamicSheet->dynamicPropertiesAllowed(); | |
QDesignerPropertySheet *designerPropertySheet = qobject_cast<QDesignerPropertySheet *>( | |
core()->extensionManager()->extension(o, Q_TYPEID(QDesignerPropertySheetExtension))); | |
if (designerPropertySheet) { | |
if (designerPropertySheet->pixmapCache()) | |
designerPropertySheet->setPixmapCache(m_pixmapCache); | |
if (designerPropertySheet->iconCache()) | |
designerPropertySheet->setIconCache(m_iconCache); | |
} | |
const DomPropertyList::const_iterator cend = properties.constEnd(); | |
for (DomPropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) { | |
DomProperty *p = *it; | |
QVariant v; | |
if (!readDomEnumerationValue(p, sheet, v)) | |
v = toVariant(o->metaObject(), p); | |
if (v.isNull()) | |
continue; | |
const QString attributeName = p->attributeName(); | |
if (formBuilderExtra->applyPropertyInternally(o, attributeName, v)) | |
continue; | |
// refuse fake properties like current tab name (weak test) | |
if (!dynamicPropertiesAllowed) { | |
if (changingMetaObject) // Changes after setting control of QAxWidget | |
meta = core()->introspection()->metaObject(o); | |
if (meta->indexOfProperty(attributeName) == -1) | |
continue; | |
} | |
QObject *obj = o; | |
QAbstractScrollArea *scroll = qobject_cast<QAbstractScrollArea *>(o); | |
if (scroll && attributeName == QLatin1String("cursor") && scroll->viewport()) | |
obj = scroll->viewport(); | |
// a real property | |
obj->setProperty(attributeName.toUtf8(), v); | |
} | |
} | |
DomWidget *QDesignerFormBuilder::createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive) | |
{ | |
DomWidget *ui_widget = QFormBuilder::createDom(widget, ui_parentWidget, recursive); | |
QSimpleResource::addExtensionDataToDOM(this, m_core, ui_widget, widget); | |
return ui_widget; | |
} | |
QWidget *QDesignerFormBuilder::create(DomWidget *ui_widget, QWidget *parentWidget) | |
{ | |
QWidget *widget = QFormBuilder::create(ui_widget, parentWidget); | |
// Do not apply state if scripts are to be run in preview mode | |
QSimpleResource::applyExtensionDataFromDOM(this, m_core, ui_widget, widget, m_mode == DisableScripts); | |
return widget; | |
} | |
void QDesignerFormBuilder::createResources(DomResources *resources) | |
{ | |
if (m_ignoreCreateResources) | |
return; | |
QStringList paths; | |
if (resources != 0) { | |
const QList<DomResource*> dom_include = resources->elementInclude(); | |
foreach (DomResource *res, dom_include) { | |
QString path = QDir::cleanPath(workingDirectory().absoluteFilePath(res->attributeLocation())); | |
paths << path; | |
} | |
} | |
m_tempResourceSet = core()->resourceModel()->addResourceSet(paths); | |
} | |
QLayout *QDesignerFormBuilder::create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget) | |
{ | |
return QFormBuilder::create(ui_layout, layout, parentWidget); | |
} | |
void QDesignerFormBuilder::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) | |
{ | |
QFormBuilder::loadExtraInfo(ui_widget, widget, parentWidget); | |
} | |
QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, | |
const QString &styleName, | |
const QString &appStyleSheet, | |
const DeviceProfile &deviceProfile, | |
ScriptErrors *scriptErrors, | |
QString *errorMessage) | |
{ | |
scriptErrors->clear(); | |
// load | |
QDesignerFormBuilder builder(fw->core(), EnableScripts, deviceProfile); | |
builder.setWorkingDirectory(fw->absoluteDir()); | |
const bool warningsEnabled = QSimpleResource::setWarningsEnabled(false); | |
QByteArray bytes = fw->contents().toUtf8(); | |
QSimpleResource::setWarningsEnabled(warningsEnabled); | |
QBuffer buffer(&bytes); | |
buffer.open(QIODevice::ReadOnly); | |
QWidget *widget = builder.load(&buffer, 0); | |
if (!widget) { // Shouldn't happen | |
*errorMessage = QCoreApplication::translate("QDesignerFormBuilder", "The preview failed to build."); | |
return 0; | |
} | |
// Make sure palette is applied | |
const QString styleToUse = styleName.isEmpty() ? builder.deviceProfile().style() : styleName; | |
if (!styleToUse.isEmpty()) { | |
if (WidgetFactory *wf = qobject_cast<qdesigner_internal::WidgetFactory *>(fw->core()->widgetFactory())) { | |
if (styleToUse != wf->styleName()) | |
WidgetFactory::applyStyleToTopLevel(wf->getStyle(styleToUse), widget); | |
} | |
} | |
#ifndef QT_FORMBUILDER_NO_SCRIPT | |
// Check for script errors | |
*scriptErrors = builder.formScriptRunner()->errors(); | |
if (!scriptErrors->empty()) { | |
*errorMessage = summarizeScriptErrors(*scriptErrors); | |
delete widget; | |
return 0; | |
} | |
#endif | |
// Fake application style sheet by prepending. (If this doesn't work, fake by nesting | |
// into parent widget). | |
if (!appStyleSheet.isEmpty()) { | |
QString styleSheet = appStyleSheet; | |
styleSheet += QLatin1Char('\n'); | |
styleSheet += widget->styleSheet(); | |
widget->setStyleSheet(styleSheet); | |
} | |
return widget; | |
} | |
QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName) | |
{ | |
return createPreview(fw, styleName, QString()); | |
} | |
QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, | |
const QString &styleName, | |
const QString &appStyleSheet, | |
const DeviceProfile &deviceProfile, | |
QString *errorMessage) | |
{ | |
ScriptErrors scriptErrors; | |
return createPreview(fw, styleName, appStyleSheet, deviceProfile, &scriptErrors, errorMessage); | |
} | |
QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, | |
const QString &styleName, | |
const QString &appStyleSheet, | |
QString *errorMessage) | |
{ | |
ScriptErrors scriptErrors; | |
return createPreview(fw, styleName, appStyleSheet, DeviceProfile(), &scriptErrors, errorMessage); | |
} | |
QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet) | |
{ | |
ScriptErrors scriptErrors; | |
QString errorMessage; | |
QWidget *widget = createPreview(fw, styleName, appStyleSheet, DeviceProfile(), &scriptErrors, &errorMessage); | |
if (!widget) { | |
// Display Script errors or message box | |
QWidget *dialogParent = fw->core()->topLevel(); | |
if (scriptErrors.empty()) { | |
fw->core()->dialogGui()->message(dialogParent, QDesignerDialogGuiInterface::PreviewFailureMessage, | |
QMessageBox::Warning, QCoreApplication::translate("QDesignerFormBuilder", "Designer"), errorMessage, QMessageBox::Ok); | |
} else { | |
ScriptErrorDialog scriptErrorDialog(scriptErrors, dialogParent); | |
scriptErrorDialog.exec(); | |
} | |
return 0; | |
} | |
return widget; | |
} | |
QPixmap QDesignerFormBuilder::createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet) | |
{ | |
QWidget *widget = createPreview(fw, styleName, appStyleSheet); | |
if (!widget) | |
return QPixmap(); | |
const QPixmap rc = QPixmap::grabWidget (widget); | |
widget->deleteLater(); | |
return rc; | |
} | |
// ---------- NewFormWidgetFormBuilder | |
NewFormWidgetFormBuilder::NewFormWidgetFormBuilder(QDesignerFormEditorInterface *core, | |
Mode mode, | |
const DeviceProfile &deviceProfile) : | |
QDesignerFormBuilder(core, mode, deviceProfile) | |
{ | |
} | |
void NewFormWidgetFormBuilder::createCustomWidgets(DomCustomWidgets *dc) | |
{ | |
QSimpleResource::handleDomCustomWidgets(core(), dc); | |
} | |
} // namespace qdesigner_internal | |
QT_END_NAMESPACE |