blob: 17c525b94cc6b1a154cd87d2c5ef392b1d0e17f0 [file] [log] [blame]
/****************************************************************************
**
** 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_resource.h"
#include "formwindow.h"
#include "dynamicpropertysheet.h"
#include "qdesigner_tabwidget_p.h"
#include "qdesigner_toolbox_p.h"
#include "qdesigner_stackedbox_p.h"
#include "qdesigner_toolbar_p.h"
#include "qdesigner_dockwidget_p.h"
#include "qdesigner_menu_p.h"
#include "qdesigner_menubar_p.h"
#include "qdesigner_membersheet_p.h"
#include "qtresourcemodel_p.h"
#include "qmdiarea_container.h"
#include "qwizard_container.h"
#include "layout_propertysheet.h"
#include <ui4_p.h>
#include <formbuilderextra_p.h>
#include <resourcebuilder_p.h>
#include <textbuilder_p.h>
#include <qdesigner_widgetitem_p.h>
// shared
#include <widgetdatabase_p.h>
#include <metadatabase_p.h>
#include <layout_p.h>
#include <layoutinfo_p.h>
#include <spacer_widget_p.h>
#include <pluginmanager_p.h>
#include <widgetfactory_p.h>
#include <abstractlanguage.h>
#include <abstractintrospection_p.h>
#include <qlayout_widget_p.h>
#include <qdesigner_utils_p.h>
#include <ui4_p.h>
// sdk
#include <QtDesigner/QDesignerPropertySheetExtension>
#include <QtDesigner/QDesignerFormEditorInterface>
#include <QtDesigner/QDesignerExtraInfoExtension>
#include <QtDesigner/QDesignerFormWindowToolInterface>
#include <QtDesigner/QExtensionManager>
#include <QtDesigner/QDesignerContainerExtension>
#include <abstractdialoggui_p.h>
#include <QtGui/QMenu>
#include <QtGui/QMessageBox>
#include <QtGui/QLayout>
#include <QtGui/QFormLayout>
#include <QtGui/QTabWidget>
#include <QtGui/QToolBox>
#include <QtGui/QStackedWidget>
#include <QtGui/QToolBar>
#include <QtGui/QTabBar>
#include <QtGui/QAction>
#include <QtGui/QActionGroup>
#include <QtGui/QButtonGroup>
#include <QtGui/QApplication>
#include <QtGui/QMainWindow>
#include <QtGui/QSplitter>
#include <QtGui/QMdiArea>
#include <QtGui/QWorkspace>
#include <QtGui/QMenuBar>
#include <QtGui/QFileDialog>
#include <QtGui/QHeaderView>
#include <QtGui/QWizardPage>
#include <private/qlayoutengine_p.h>
#include <QtCore/QBuffer>
#include <QtCore/QDir>
#include <QtCore/QMetaProperty>
#include <QtCore/qdebug.h>
#include <QtCore/QXmlStreamWriter>
Q_DECLARE_METATYPE(QWidgetList)
QT_BEGIN_NAMESPACE
namespace {
typedef QList<DomProperty*> DomPropertyList;
}
static const char *currentUiVersion = "4.0";
static const char *clipboardObjectName = "__qt_fake_top_level";
#define OLD_RESOURCE_FORMAT // Support pre 4.4 format.
namespace qdesigner_internal {
// -------------------- QDesignerResourceBuilder: A resource builder that works on the property sheet icon types.
class QDesignerResourceBuilder : public QResourceBuilder
{
public:
QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache);
void setPixmapCache(DesignerPixmapCache *pixmapCache) { m_pixmapCache = pixmapCache; }
void setIconCache(DesignerIconCache *iconCache) { m_iconCache = iconCache; }
bool isSaveRelative() const { return m_saveRelative; }
void setSaveRelative(bool relative) { m_saveRelative = relative; }
QStringList usedQrcFiles() const { return m_usedQrcFiles.keys(); }
#ifdef OLD_RESOURCE_FORMAT
QStringList loadedQrcFiles() const { return m_loadedQrcFiles.keys(); } // needed only for loading old resource attribute of <iconset> tag.
#endif
virtual QVariant loadResource(const QDir &workingDirectory, const DomProperty *icon) const;
virtual QVariant toNativeValue(const QVariant &value) const;
virtual DomProperty *saveResource(const QDir &workingDirectory, const QVariant &value) const;
virtual bool isResourceType(const QVariant &value) const;
private:
QDesignerFormEditorInterface *m_core;
DesignerPixmapCache *m_pixmapCache;
DesignerIconCache *m_iconCache;
const QDesignerLanguageExtension *m_lang;
bool m_saveRelative;
mutable QMap<QString, bool> m_usedQrcFiles;
mutable QMap<QString, bool> m_loadedQrcFiles;
};
QDesignerResourceBuilder::QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache) :
m_core(core),
m_pixmapCache(pixmapCache),
m_iconCache(iconCache),
m_lang(qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core)),
m_saveRelative(true)
{
}
static inline void setIconPixmap(QIcon::Mode m, QIcon::State s, const QDir &workingDirectory,
QString path, PropertySheetIconValue &icon,
const QDesignerLanguageExtension *lang = 0)
{
if (lang == 0 || !lang->isLanguageResource(path))
path = QFileInfo(workingDirectory, path).absoluteFilePath();
icon.setPixmap(m, s, PropertySheetPixmapValue(path));
}
QVariant QDesignerResourceBuilder::loadResource(const QDir &workingDirectory, const DomProperty *property) const
{
switch (property->kind()) {
case DomProperty::Pixmap: {
PropertySheetPixmapValue pixmap;
DomResourcePixmap *dp = property->elementPixmap();
if (!dp->text().isEmpty()) {
if (m_lang != 0 && m_lang->isLanguageResource(dp->text())) {
pixmap.setPath(dp->text());
} else {
pixmap.setPath(QFileInfo(workingDirectory, dp->text()).absoluteFilePath());
}
#ifdef OLD_RESOURCE_FORMAT
if (dp->hasAttributeResource())
m_loadedQrcFiles.insert(QFileInfo(workingDirectory, dp->attributeResource()).absoluteFilePath(), false);
#endif
}
return qVariantFromValue(pixmap);
}
case DomProperty::IconSet: {
PropertySheetIconValue icon;
DomResourceIcon *di = property->elementIconSet();
if (const int flags = iconStateFlags(di)) { // new, post 4.4 format
if (flags & NormalOff)
setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->elementNormalOff()->text(), icon, m_lang);
if (flags & NormalOn)
setIconPixmap(QIcon::Normal, QIcon::On, workingDirectory, di->elementNormalOn()->text(), icon, m_lang);
if (flags & DisabledOff)
setIconPixmap(QIcon::Disabled, QIcon::Off, workingDirectory, di->elementDisabledOff()->text(), icon, m_lang);
if (flags & DisabledOn)
setIconPixmap(QIcon::Disabled, QIcon::On, workingDirectory, di->elementDisabledOn()->text(), icon, m_lang);
if (flags & ActiveOff)
setIconPixmap(QIcon::Active, QIcon::Off, workingDirectory, di->elementActiveOff()->text(), icon, m_lang);
if (flags & ActiveOn)
setIconPixmap(QIcon::Active, QIcon::On, workingDirectory, di->elementActiveOn()->text(), icon, m_lang);
if (flags & SelectedOff)
setIconPixmap(QIcon::Selected, QIcon::Off, workingDirectory, di->elementSelectedOff()->text(), icon, m_lang);
if (flags & SelectedOn)
setIconPixmap(QIcon::Selected, QIcon::On, workingDirectory, di->elementSelectedOn()->text(), icon, m_lang);
} else {
#ifdef OLD_RESOURCE_FORMAT
setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->text(), icon, m_lang);
if (di->hasAttributeResource())
m_loadedQrcFiles.insert(QFileInfo(workingDirectory, di->attributeResource()).absoluteFilePath(), false);
#endif
}
return qVariantFromValue(icon);
}
default:
break;
}
return QVariant();
}
QVariant QDesignerResourceBuilder::toNativeValue(const QVariant &value) const
{
if (qVariantCanConvert<PropertySheetPixmapValue>(value)) {
if (m_pixmapCache)
return m_pixmapCache->pixmap(qVariantValue<PropertySheetPixmapValue>(value));
} else if (qVariantCanConvert<PropertySheetIconValue>(value)) {
if (m_iconCache)
return m_iconCache->icon(qVariantValue<PropertySheetIconValue>(value));
}
return value;
}
DomProperty *QDesignerResourceBuilder::saveResource(const QDir &workingDirectory, const QVariant &value) const
{
DomProperty *p = new DomProperty;
if (qVariantCanConvert<PropertySheetPixmapValue>(value)) {
const PropertySheetPixmapValue pix = qvariant_cast<PropertySheetPixmapValue>(value);
DomResourcePixmap *rp = new DomResourcePixmap;
const QString pixPath = pix.path();
switch (pix.pixmapSource(m_core)) {
case PropertySheetPixmapValue::LanguageResourcePixmap:
rp->setText(pixPath);
break;
case PropertySheetPixmapValue::ResourcePixmap: {
rp->setText(pixPath);
const QString qrcFile = m_core->resourceModel()->qrcPath(pixPath);
if (!qrcFile.isEmpty()) {
m_usedQrcFiles.insert(qrcFile, false);
#ifdef OLD_RESOURCE_FORMAT // Legacy: Add qrc path
rp->setAttributeResource(workingDirectory.relativeFilePath(qrcFile));
#endif
}
}
break;
case PropertySheetPixmapValue::FilePixmap:
rp->setText(m_saveRelative ? workingDirectory.relativeFilePath(pixPath) : pixPath);
break;
}
p->setElementPixmap(rp);
return p;
} else if (qVariantCanConvert<PropertySheetIconValue>(value)) {
const PropertySheetIconValue icon = qvariant_cast<PropertySheetIconValue>(value);
const QMap<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> pixmaps = icon.paths();
if (!pixmaps.isEmpty()) {
DomResourceIcon *ri = new DomResourceIcon;
QMapIterator<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> itPix(pixmaps);
while (itPix.hasNext()) {
const QIcon::Mode mode = itPix.next().key().first;
const QIcon::State state = itPix.key().second;
DomResourcePixmap *rp = new DomResourcePixmap;
const PropertySheetPixmapValue pix = itPix.value();
const PropertySheetPixmapValue::PixmapSource ps = pix.pixmapSource(m_core);
const QString pixPath = pix.path();
rp->setText(ps == PropertySheetPixmapValue::FilePixmap && m_saveRelative ? workingDirectory.relativeFilePath(pixPath) : pixPath);
if (state == QIcon::Off) {
switch (mode) {
case QIcon::Normal:
ri->setElementNormalOff(rp);
#ifdef OLD_RESOURCE_FORMAT // Legacy: Set Normal off as text/path in old format.
ri->setText(rp->text());
#endif
if (ps == PropertySheetPixmapValue::ResourcePixmap) {
// Be sure that ri->text() file comes from active resourceSet (i.e. make appropriate
// resourceSet active before calling this method).
const QString qrcFile = m_core->resourceModel()->qrcPath(ri->text());
if (!qrcFile.isEmpty()) {
m_usedQrcFiles.insert(qrcFile, false);
#ifdef OLD_RESOURCE_FORMAT // Legacy: Set Normal off as text/path in old format.
ri->setAttributeResource(workingDirectory.relativeFilePath(qrcFile));
#endif
}
}
break;
case QIcon::Disabled: ri->setElementDisabledOff(rp); break;
case QIcon::Active: ri->setElementActiveOff(rp); break;
case QIcon::Selected: ri->setElementSelectedOff(rp); break;
}
} else {
switch (mode) {
case QIcon::Normal: ri->setElementNormalOn(rp); break;
case QIcon::Disabled: ri->setElementDisabledOn(rp); break;
case QIcon::Active: ri->setElementActiveOn(rp); break;
case QIcon::Selected: ri->setElementSelectedOn(rp); break;
}
}
}
p->setElementIconSet(ri);
return p;
}
}
delete p;
return 0;
}
bool QDesignerResourceBuilder::isResourceType(const QVariant &value) const
{
if (qVariantCanConvert<PropertySheetPixmapValue>(value) || qVariantCanConvert<PropertySheetIconValue>(value))
return true;
return false;
}
// ------------------------- QDesignerTextBuilder
class QDesignerTextBuilder : public QTextBuilder
{
public:
QDesignerTextBuilder() {}
virtual QVariant loadText(const DomProperty *icon) const;
virtual QVariant toNativeValue(const QVariant &value) const;
virtual DomProperty *saveText(const QVariant &value) const;
};
QVariant QDesignerTextBuilder::loadText(const DomProperty *text) const
{
const DomString *str = text->elementString();
PropertySheetStringValue strVal(str->text());
if (str->hasAttributeComment()) {
strVal.setDisambiguation(str->attributeComment());
}
if (str->hasAttributeExtraComment()) {
strVal.setComment(str->attributeExtraComment());
}
if (str->hasAttributeNotr()) {
const QString notr = str->attributeNotr();
const bool translatable = !(notr == QLatin1String("true") || notr == QLatin1String("yes"));
if (!translatable)
strVal.setTranslatable(translatable);
}
return qVariantFromValue(strVal);
}
QVariant QDesignerTextBuilder::toNativeValue(const QVariant &value) const
{
if (qVariantCanConvert<PropertySheetStringValue>(value))
return qVariantFromValue(qVariantValue<PropertySheetStringValue>(value).value());
return value;
}
DomProperty *QDesignerTextBuilder::saveText(const QVariant &value) const
{
if (!qVariantCanConvert<PropertySheetStringValue>(value) && !qVariantCanConvert<QString>(value))
return 0;
DomProperty *property = new DomProperty();
DomString *domStr = new DomString();
if (qVariantCanConvert<PropertySheetStringValue>(value)) {
PropertySheetStringValue str = qVariantValue<PropertySheetStringValue>(value);
domStr->setText(str.value());
const QString property_comment = str.disambiguation();
if (!property_comment.isEmpty())
domStr->setAttributeComment(property_comment);
const QString property_extraComment = str.comment();
if (!property_extraComment.isEmpty())
domStr->setAttributeExtraComment(property_extraComment);
const bool property_translatable = str.translatable();
if (!property_translatable)
domStr->setAttributeNotr(QLatin1String("true"));
} else {
domStr->setText(value.toString());
}
property->setElementString(domStr);
return property;
}
QDesignerResource::QDesignerResource(FormWindow *formWindow) :
QEditorFormBuilder(formWindow->core()),
m_formWindow(formWindow),
m_topLevelSpacerCount(0),
m_copyWidget(false),
m_selected(0),
m_resourceBuilder(new QDesignerResourceBuilder(m_formWindow->core(), m_formWindow->pixmapCache(), m_formWindow->iconCache()))
{
setWorkingDirectory(formWindow->absoluteDir());
setResourceBuilder(m_resourceBuilder);
setTextBuilder(new QDesignerTextBuilder());
// ### generalise
const QString designerWidget = QLatin1String("QDesignerWidget");
const QString layoutWidget = QLatin1String("QLayoutWidget");
const QString widget = QLatin1String("QWidget");
m_internal_to_qt.insert(layoutWidget, widget);
m_internal_to_qt.insert(designerWidget, widget);
m_internal_to_qt.insert(QLatin1String("QDesignerDialog"), QLatin1String("QDialog"));
m_internal_to_qt.insert(QLatin1String("QDesignerMenuBar"), QLatin1String("QMenuBar"));
m_internal_to_qt.insert(QLatin1String("QDesignerMenu"), QLatin1String("QMenu"));
m_internal_to_qt.insert(QLatin1String("QDesignerDockWidget"), QLatin1String("QDockWidget"));
m_internal_to_qt.insert(QLatin1String("QDesignerQ3WidgetStack"), QLatin1String("Q3WidgetStack"));
// invert
QHash<QString, QString>::const_iterator cend = m_internal_to_qt.constEnd();
for (QHash<QString, QString>::const_iterator it = m_internal_to_qt.constBegin();it != cend; ++it ) {
if (it.value() != designerWidget && it.value() != layoutWidget)
m_qt_to_internal.insert(it.value(), it.key());
}
}
QDesignerResource::~QDesignerResource()
{
}
static inline QString messageBoxTitle()
{
return QApplication::translate("Designer", "Qt Designer");
}
void QDesignerResource::save(QIODevice *dev, QWidget *widget)
{
m_topLevelSpacerCount = 0;
QAbstractFormBuilder::save(dev, widget);
if (QSimpleResource::warningsEnabled() && m_topLevelSpacerCount != 0) {
const QString message = QApplication::translate("Designer", "This file contains top level spacers.<br>"
"They have <b>NOT</b> been saved into the form.");
const QString infoMessage = QApplication::translate("Designer", "Perhaps you forgot to create a layout?");
core()->dialogGui()->message(widget->window(), QDesignerDialogGuiInterface::TopLevelSpacerMessage,
QMessageBox::Warning, messageBoxTitle(), message, infoMessage,
QMessageBox::Ok);
}
}
void QDesignerResource::saveDom(DomUI *ui, QWidget *widget)
{
QAbstractFormBuilder::saveDom(ui, widget);
QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget);
Q_ASSERT(sheet != 0);
const QVariant classVar = sheet->property(sheet->indexOf(QLatin1String("objectName")));
QString classStr;
if (classVar.canConvert(QVariant::String))
classStr = classVar.toString();
else
classStr = qVariantValue<PropertySheetStringValue>(classVar).value();
ui->setElementClass(classStr);
for (int index = 0; index < m_formWindow->toolCount(); ++index) {
QDesignerFormWindowToolInterface *tool = m_formWindow->tool(index);
Q_ASSERT(tool != 0);
tool->saveToDom(ui, widget);
}
const QString author = m_formWindow->author();
if (!author.isEmpty()) {
ui->setElementAuthor(author);
}
const QString comment = m_formWindow->comment();
if (!comment.isEmpty()) {
ui->setElementComment(comment);
}
const QString exportMacro = m_formWindow->exportMacro();
if (!exportMacro.isEmpty()) {
ui->setElementExportMacro(exportMacro);
}
const QVariantMap designerFormData = m_formWindow->formData();
if (!designerFormData.empty()) {
DomPropertyList domPropertyList;
const QVariantMap::const_iterator cend = designerFormData.constEnd();
for (QVariantMap::const_iterator it = designerFormData.constBegin(); it != cend; ++it) {
if (DomProperty *prop = variantToDomProperty(this, widget->metaObject(), it.key(), it.value()))
domPropertyList += prop;
}
if (!domPropertyList.empty()) {
DomDesignerData* domDesignerFormData = new DomDesignerData;
domDesignerFormData->setElementProperty(domPropertyList);
ui->setElementDesignerdata(domDesignerFormData);
}
}
if (!m_formWindow->includeHints().isEmpty()) {
const QString local = QLatin1String("local");
const QString global = QLatin1String("global");
QList<DomInclude*> ui_includes;
foreach (QString includeHint, m_formWindow->includeHints()) {
if (includeHint.isEmpty())
continue;
DomInclude *incl = new DomInclude;
const QString location = includeHint.at(0) == QLatin1Char('<') ? global : local;
includeHint.remove(QLatin1Char('"'));
includeHint.remove(QLatin1Char('<'));
includeHint.remove(QLatin1Char('>'));
incl->setAttributeLocation(location);
incl->setText(includeHint);
ui_includes.append(incl);
}
DomIncludes *includes = new DomIncludes;
includes->setElementInclude(ui_includes);
ui->setElementIncludes(includes);
}
int defaultMargin = INT_MIN, defaultSpacing = INT_MIN;
m_formWindow->layoutDefault(&defaultMargin, &defaultSpacing);
if (defaultMargin != INT_MIN || defaultSpacing != INT_MIN) {
DomLayoutDefault *def = new DomLayoutDefault;
if (defaultMargin != INT_MIN)
def->setAttributeMargin(defaultMargin);
if (defaultSpacing != INT_MIN)
def->setAttributeSpacing(defaultSpacing);
ui->setElementLayoutDefault(def);
}
QString marginFunction, spacingFunction;
m_formWindow->layoutFunction(&marginFunction, &spacingFunction);
if (!marginFunction.isEmpty() || !spacingFunction.isEmpty()) {
DomLayoutFunction *def = new DomLayoutFunction;
if (!marginFunction.isEmpty())
def->setAttributeMargin(marginFunction);
if (!spacingFunction.isEmpty())
def->setAttributeSpacing(spacingFunction);
ui->setElementLayoutFunction(def);
}
QString pixFunction = m_formWindow->pixmapFunction();
if (!pixFunction.isEmpty()) {
ui->setElementPixmapFunction(pixFunction);
}
if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core()))
extra->saveUiExtraInfo(ui);
if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) {
const MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(m_formWindow->mainContainer());
const QStringList fakeSlots = item->fakeSlots();
const QStringList fakeSignals =item->fakeSignals();
if (!fakeSlots.empty() || !fakeSignals.empty()) {
DomSlots *domSlots = new DomSlots();
domSlots->setElementSlot(fakeSlots);
domSlots->setElementSignal(fakeSignals);
ui->setElementSlots(domSlots);
}
}
}
namespace {
enum LoadPreCheck { LoadPreCheckFailed, LoadPreCheckVersion3, LoadPreCheckVersionMismatch, LoadPreCheckOk };
// Pair of major, minor
typedef QPair<int, int> UiVersion;
}
static UiVersion uiVersion(const QString &attr)
{
const QStringList versions = attr.split(QLatin1Char('.'));
if (versions.empty())
return UiVersion(-1, -1);
bool ok = false;
UiVersion rc(versions.at(0).toInt(&ok), 0);
if (!ok)
return UiVersion(-1, -1);
if (versions.size() > 1) {
const int minorVersion = versions.at(1).toInt(&ok);
if (ok)
rc.second = minorVersion;
}
return rc;
}
// Read version and language attributes of an <UI> element.
static bool readUiAttributes(QIODevice *dev, QString *errorMessage,
QString *version,
QString *language)
{
const QString uiElement = QLatin1String("ui");
const QString versionAttribute = QLatin1String("version");
const QString languageAttribute = QLatin1String("language");
QXmlStreamReader reader(dev);
// Read up to first element
while (!reader.atEnd()) {
if (reader.readNext() == QXmlStreamReader::StartElement) {
const QStringRef tag = reader.name();
if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0) {
const QXmlStreamAttributes attributes = reader.attributes();
if (attributes.hasAttribute(versionAttribute))
*version = attributes.value(versionAttribute).toString();
if (attributes.hasAttribute(languageAttribute))
*language = attributes.value(languageAttribute).toString();
return true;
} else {
*errorMessage = QCoreApplication::translate("Designer", "Invalid UI file: The root element <ui> is missing.");
return false;
}
}
}
*errorMessage = QCoreApplication::translate("Designer", "An error has occurred while reading the UI file at line %1, column %2: %3")
.arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString());
return false;
}
// While loading a file, check language, version and extra extension
static LoadPreCheck loadPrecheck(QDesignerFormEditorInterface *core,
QIODevice *dev,
QString *errorMessage, QString *versionString)
{
QString language;
// Read attributes of <ui> and rewind
if (!readUiAttributes(dev, errorMessage, versionString, &language)) {
// XML error: Mimick the behaviour occurring if an XML error is
// detected later on, report to warning log and have embedding
// application display a dialog.
designerWarning(*errorMessage);
errorMessage->clear();
return LoadPreCheckFailed;
}
dev->seek(0);
// Check language unless extension present (Jambi)
if (!language.isEmpty() && !qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core)) {
if (language.toLower() != QLatin1String("c++")) {
// Jambi?!
*errorMessage = QApplication::translate("Designer", "This file cannot be read because it was created using %1.").arg(language);
return LoadPreCheckFailed;
}
}
// Version
if (!versionString->isEmpty()) {
const UiVersion version = uiVersion(*versionString);
switch (version.first) {
case 3:
return LoadPreCheckVersion3;
case 4:
break;
default:
*errorMessage = QApplication::translate("Designer", "This file was created using Designer from Qt-%1 and cannot be read.").arg(*versionString);
return LoadPreCheckVersionMismatch;
}
}
return LoadPreCheckOk;
}
QWidget *QDesignerResource::load(QIODevice *dev, QWidget *parentWidget)
{
// Run loadPreCheck for version and language
QString errorMessage;
QString version;
switch (loadPrecheck(core(), dev, &errorMessage, &version)) {
case LoadPreCheckFailed:
case LoadPreCheckVersionMismatch:
if (!errorMessage.isEmpty())
core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage,
QMessageBox::Warning, messageBoxTitle(), errorMessage, QMessageBox::Ok);
return 0;
case LoadPreCheckVersion3: {
QWidget *w = 0;
QByteArray ba;
if (runUIC( m_formWindow->fileName(), UIC_ConvertV3, ba, errorMessage)) {
QBuffer buffer(&ba);
buffer.open(QIODevice::ReadOnly);
w = load(&buffer, parentWidget);
if (w) {
// Force the form to pop up a save file dialog
m_formWindow->setFileName(QString());
} else {
errorMessage = QApplication::translate("Designer", "The converted file could not be read.");
}
}
if (w) {
const QString message = QApplication::translate("Designer",
"This file was created using Designer from Qt-%1 and"
" will be converted to a new form by Qt Designer.").arg(version);
const QString infoMessage = QApplication::translate("Designer",
"The old form has not been touched, but you will have to save the form"
" under a new name.");
core()->dialogGui()->message(parentWidget->window(),
QDesignerDialogGuiInterface::UiVersionMismatchMessage,
QMessageBox::Information, messageBoxTitle(), message, infoMessage,
QMessageBox::Ok);
return w;
}
const QString message = QApplication::translate("Designer",
"This file was created using Designer from Qt-%1 and "
"could not be read:\n%2").arg(version).arg(errorMessage);
const QString infoMessage = QApplication::translate("Designer",
"Please run it through <b>uic3&nbsp;-convert</b> to convert "
"it to Qt-4's ui format.");
core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage,
QMessageBox::Warning, messageBoxTitle(), message, infoMessage,
QMessageBox::Ok);
return 0;
}
case LoadPreCheckOk:
break;
}
return QEditorFormBuilder::load(dev, parentWidget);
}
bool QDesignerResource::saveRelative() const
{
return m_resourceBuilder->isSaveRelative();
}
void QDesignerResource::setSaveRelative(bool relative)
{
m_resourceBuilder->setSaveRelative(relative);
}
QWidget *QDesignerResource::create(DomUI *ui, QWidget *parentWidget)
{
// Load extra info extension. This is used by Jambi for preventing
// C++ UI files from being loaded
if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core())) {
if (!extra->loadUiExtraInfo(ui)) {
const QString errorMessage = QApplication::translate("Designer", "This file cannot be read because the extra info extension failed to load.");
core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage,
QMessageBox::Warning, messageBoxTitle(), errorMessage, QMessageBox::Ok);
return 0;
}
}
qdesigner_internal::WidgetFactory *factory = qobject_cast<qdesigner_internal::WidgetFactory*>(core()->widgetFactory());
Q_ASSERT(factory != 0);
QDesignerFormWindowInterface *previousFormWindow = factory->currentFormWindow(m_formWindow);
m_isMainWidget = true;
QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
QWidget *mainWidget = QAbstractFormBuilder::create(ui, parentWidget);
if (mainWidget && m_formWindow) {
m_formWindow->setAuthor(ui->elementAuthor());
m_formWindow->setComment(ui->elementComment());
m_formWindow->setExportMacro(ui->elementExportMacro());
// Designer data
QVariantMap designerFormData;
if (ui->hasElementDesignerdata()) {
const DomPropertyList domPropertyList = ui->elementDesignerdata()->elementProperty();
const DomPropertyList::const_iterator cend = domPropertyList.constEnd();
for (DomPropertyList::const_iterator it = domPropertyList.constBegin(); it != cend; ++it) {
const QVariant vprop = domPropertyToVariant(this, mainWidget->metaObject(), *it);
if (vprop.type() != QVariant::Invalid)
designerFormData.insert((*it)->attributeName(), vprop);
}
}
m_formWindow->setFormData(designerFormData);
m_formWindow->setPixmapFunction(ui->elementPixmapFunction());
if (DomLayoutDefault *def = ui->elementLayoutDefault()) {
m_formWindow->setLayoutDefault(def->attributeMargin(), def->attributeSpacing());
}
if (DomLayoutFunction *fun = ui->elementLayoutFunction()) {
m_formWindow->setLayoutFunction(fun->attributeMargin(), fun->attributeSpacing());
}
if (DomIncludes *includes = ui->elementIncludes()) {
const QString global = QLatin1String("global");
QStringList includeHints;
foreach (DomInclude *incl, includes->elementInclude()) {
QString text = incl->text();
if (text.isEmpty())
continue;
if (incl->hasAttributeLocation() && incl->attributeLocation() == global ) {
text = text.prepend(QLatin1Char('<')).append(QLatin1Char('>'));
} else {
text = text.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
}
includeHints.append(text);
}
m_formWindow->setIncludeHints(includeHints);
}
// Register all button groups the form builder adds as children of the main container for them to be found
// in the signal slot editor
const QObjectList mchildren = mainWidget->children();
if (!mchildren.empty()) {
QDesignerMetaDataBaseInterface *mdb = core()->metaDataBase();
const QObjectList::const_iterator cend = mchildren.constEnd();
for (QObjectList::const_iterator it = mchildren.constBegin(); it != cend; ++it)
if (QButtonGroup *bg = qobject_cast<QButtonGroup*>(*it))
mdb->add(bg);
}
// Load tools
for (int index = 0; index < m_formWindow->toolCount(); ++index) {
QDesignerFormWindowToolInterface *tool = m_formWindow->tool(index);
Q_ASSERT(tool != 0);
tool->loadFromDom(ui, mainWidget);
}
}
factory->currentFormWindow(previousFormWindow);
if (const DomSlots *domSlots = ui->elementSlots()) {
if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) {
QStringList fakeSlots;
QStringList fakeSignals;
if (addFakeMethods(domSlots, fakeSlots, fakeSignals)) {
MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(mainWidget);
item->setFakeSlots(fakeSlots);
item->setFakeSignals(fakeSignals);
}
}
}
if (mainWidget) {
// Initialize the mainwindow geometry. Has it been explicitly specified?
bool hasExplicitGeometry = false;
const QList<DomProperty *> properties = ui->elementWidget()->elementProperty();
if (!properties.empty()) {
const QString geometry = QLatin1String("geometry");
foreach (const DomProperty *p, properties)
if (p->attributeName() == geometry) {
hasExplicitGeometry = true;
break;
}
}
if (hasExplicitGeometry) {
// Geometry was specified explicitly: Verify that smartMinSize is respected
// (changed fonts, label wrapping policies, etc). This does not happen automatically in docked mode.
const QSize size = mainWidget->size();
const QSize minSize = size.expandedTo(qSmartMinSize(mainWidget));
if (minSize != size)
mainWidget->resize(minSize);
} else {
// No explicit Geometry: perform an adjustSize() to resize the form correctly before embedding it into a container
// (which might otherwise squeeze the form)
mainWidget->adjustSize();
}
// Some integration wizards create forms with main containers
// based on derived classes of QWidget and load them into Designer
// without the plugin existing. This will trigger the auto-promotion
// mechanism of Designer, which will set container=false for
// QWidgets. For the main container, force container=true and warn.
const QDesignerWidgetDataBaseInterface *wdb = core()->widgetDataBase();
const int wdbIndex = wdb->indexOfObject(mainWidget);
if (wdbIndex != -1) {
QDesignerWidgetDataBaseItemInterface *item = wdb->item(wdbIndex);
// Promoted main container that is not of container type
if (item->isPromoted() && !item->isContainer()) {
item->setContainer(true);
qWarning("** WARNING The form's main container is an unknown custom widget '%s'."
" Defaulting to a promoted instance of '%s', assuming container.",
item->name().toUtf8().constData(), item->extends().toUtf8().constData());
}
}
}
return mainWidget;
}
QWidget *QDesignerResource::create(DomWidget *ui_widget, QWidget *parentWidget)
{
const QString className = ui_widget->attributeClass();
if (!m_isMainWidget && className == QLatin1String("QWidget") && ui_widget->elementLayout().size() &&
!ui_widget->hasAttributeNative()) {
// ### check if elementLayout.size() == 1
QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget);
if (container == 0) {
// generate a QLayoutWidget iff the parent is not an QDesignerContainerExtension.
ui_widget->setAttributeClass(QLatin1String("QLayoutWidget"));
}
}
// save the actions
const QList<DomActionRef*> actionRefs = ui_widget->elementAddAction();
ui_widget->setElementAddAction(QList<DomActionRef*>());
QWidget *w = QAbstractFormBuilder::create(ui_widget, parentWidget);
// restore the actions
ui_widget->setElementAddAction(actionRefs);
if (w == 0)
return 0;
// ### generalize using the extension manager
QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(w);
QDesignerMenuBar *menuBar = qobject_cast<QDesignerMenuBar*>(w);
if (menu) {
menu->interactive(false);
menu->hide();
} else if (menuBar) {
menuBar->interactive(false);
}
foreach (DomActionRef *ui_action_ref, actionRefs) {
const QString name = ui_action_ref->attributeName();
if (name == QLatin1String("separator")) {
QAction *sep = new QAction(w);
sep->setSeparator(true);
w->addAction(sep);
addMenuAction(sep);
} else if (QAction *a = m_actions.value(name)) {
w->addAction(a);
} else if (QActionGroup *g = m_actionGroups.value(name)) {
w->addActions(g->actions());
} else if (QMenu *menu = qFindChild<QMenu*>(w, name)) {
w->addAction(menu->menuAction());
addMenuAction(menu->menuAction());
}
}
if (menu) {
menu->interactive(true);
menu->adjustSpecialActions();
} else if (menuBar) {
menuBar->interactive(true);
menuBar->adjustSpecialActions();
}
ui_widget->setAttributeClass(className); // fix the class name
applyExtensionDataFromDOM(this, core(), ui_widget, w, true);
// store user-defined scripts
if (MetaDataBase *metaDataBase = qobject_cast<MetaDataBase *>(core()->metaDataBase())) {
const QString designerSource = QLatin1String("designer");
const DomScripts domScripts = ui_widget->elementScript();
if (!domScripts.empty()) {
foreach (const DomScript *script, domScripts) {
if (script->hasAttributeSource() && script->attributeSource() == designerSource) {
metaDataBase->metaDataBaseItem(w)->setScript(script->text());
}
}
}
}
return w;
}
QLayout *QDesignerResource::create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget)
{
QLayout *l = QAbstractFormBuilder::create(ui_layout, layout, parentWidget);
if (QGridLayout *gridLayout = qobject_cast<QGridLayout*>(l)) {
QLayoutSupport::createEmptyCells(gridLayout);
} else {
if (QFormLayout *formLayout = qobject_cast<QFormLayout*>(l))
QLayoutSupport::createEmptyCells(formLayout);
}
// While the actual values are applied by the form builder, we still need
// to mark them as 'changed'.
LayoutPropertySheet::markChangedStretchProperties(core(), l, ui_layout);
return l;
}
QLayoutItem *QDesignerResource::create(DomLayoutItem *ui_layoutItem, QLayout *layout, QWidget *parentWidget)
{
if (ui_layoutItem->kind() == DomLayoutItem::Spacer) {
const DomSpacer *domSpacer = ui_layoutItem->elementSpacer();
const QHash<QString, DomProperty*> properties = propertyMap(domSpacer->elementProperty());
Spacer *spacer = static_cast<Spacer*>(core()->widgetFactory()->createWidget(QLatin1String("Spacer"), parentWidget));
if (domSpacer->hasAttributeName())
changeObjectName(spacer, domSpacer->attributeName());
core()->metaDataBase()->add(spacer);
spacer->setInteractiveMode(false);
applyProperties(spacer, ui_layoutItem->elementSpacer()->elementProperty());
spacer->setInteractiveMode(true);
if (m_formWindow) {
m_formWindow->manageWidget(spacer);
if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), spacer))
sheet->setChanged(sheet->indexOf(QLatin1String("orientation")), true);
}
return new QWidgetItem(spacer);
} else if (ui_layoutItem->kind() == DomLayoutItem::Layout && parentWidget) {
DomLayout *ui_layout = ui_layoutItem->elementLayout();
QLayoutWidget *layoutWidget = new QLayoutWidget(m_formWindow, parentWidget);
core()->metaDataBase()->add(layoutWidget);
if (m_formWindow)
m_formWindow->manageWidget(layoutWidget);
(void) create(ui_layout, 0, layoutWidget);
return new QWidgetItem(layoutWidget);
}
return QAbstractFormBuilder::create(ui_layoutItem, layout, parentWidget);
}
void QDesignerResource::changeObjectName(QObject *o, QString objName)
{
m_formWindow->unify(o, objName, true);
o->setObjectName(objName);
}
/* If the property is a enum or flag value, retrieve
* the existing enum/flag via property sheet and use it to convert */
static bool readDomEnumerationValue(const DomProperty *p,
const QDesignerPropertySheetExtension* sheet, int index,
QVariant &v)
{
switch (p->kind()) {
case DomProperty::Set: {
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 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 QDesignerResource::applyProperties(QObject *o, const QList<DomProperty*> &properties)
{
if (properties.empty())
return;
QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), o);
if (!sheet)
return;
QFormBuilderExtra *formBuilderExtra = QFormBuilderExtra::instance(this);
QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), o);
const bool dynamicPropertiesAllowed = dynamicSheet && dynamicSheet->dynamicPropertiesAllowed();
const QString objectNameProperty = QLatin1String("objectName");
const DomPropertyList::const_iterator cend = properties.constEnd();
for (DomPropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) {
const DomProperty *p = *it;
const QString propertyName = p->attributeName();
const int index = sheet->indexOf(propertyName);
QVariant v;
if (!readDomEnumerationValue(p, sheet, index, v))
v = toVariant(o->metaObject(), *it);
if (p->kind() == DomProperty::String) {
if (index != -1 && sheet->property(index).userType() == qMetaTypeId<PropertySheetKeySequenceValue>()) {
const DomString *key = p->elementString();
PropertySheetKeySequenceValue keyVal(QKeySequence(key->text()));
if (key->hasAttributeComment())
keyVal.setDisambiguation(key->attributeComment());
if (key->hasAttributeExtraComment())
keyVal.setComment(key->attributeExtraComment());
if (key->hasAttributeNotr()) {
const QString notr = key->attributeNotr();
const bool translatable = !(notr == QLatin1String("true") || notr == QLatin1String("yes"));
if (!translatable)
keyVal.setTranslatable(translatable);
}
v = qVariantFromValue(keyVal);
} else {
const DomString *str = p->elementString();
PropertySheetStringValue strVal(v.toString());
if (str->hasAttributeComment())
strVal.setDisambiguation(str->attributeComment());
if (str->hasAttributeExtraComment())
strVal.setComment(str->attributeExtraComment());
if (str->hasAttributeNotr()) {
const QString notr = str->attributeNotr();
const bool translatable = !(notr == QLatin1String("true") || notr == QLatin1String("yes"));
if (!translatable)
strVal.setTranslatable(translatable);
}
v = qVariantFromValue(strVal);
}
}
formBuilderExtra->applyPropertyInternally(o, propertyName, v);
if (index != -1) {
sheet->setProperty(index, v);
sheet->setChanged(index, true);
} else if (dynamicPropertiesAllowed) {
QVariant defaultValue = QVariant(v.type());
bool isDefault = (v == defaultValue);
if (qVariantCanConvert<PropertySheetIconValue>(v)) {
defaultValue = QVariant(QVariant::Icon);
isDefault = (qVariantValue<PropertySheetIconValue>(v) == PropertySheetIconValue());
} else if (qVariantCanConvert<PropertySheetPixmapValue>(v)) {
defaultValue = QVariant(QVariant::Pixmap);
isDefault = (qVariantValue<PropertySheetPixmapValue>(v) == PropertySheetPixmapValue());
} else if (qVariantCanConvert<PropertySheetStringValue>(v)) {
defaultValue = QVariant(QVariant::String);
isDefault = (qVariantValue<PropertySheetStringValue>(v) == PropertySheetStringValue());
} else if (qVariantCanConvert<PropertySheetKeySequenceValue>(v)) {
defaultValue = QVariant(QVariant::KeySequence);
isDefault = (qVariantValue<PropertySheetKeySequenceValue>(v) == PropertySheetKeySequenceValue());
}
if (defaultValue.type() != QVariant::UserType) {
const int idx = dynamicSheet->addDynamicProperty(p->attributeName(), defaultValue);
if (idx != -1) {
sheet->setProperty(idx, v);
sheet->setChanged(idx, !isDefault);
}
}
}
if (propertyName == objectNameProperty)
changeObjectName(o, o->objectName());
}
}
QWidget *QDesignerResource::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &_name)
{
QString name = _name;
QString className = widgetName;
if (m_isMainWidget)
m_isMainWidget = false;
QWidget *w = core()->widgetFactory()->createWidget(className, parentWidget);
if (!w)
return 0;
if (name.isEmpty()) {
QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase();
if (QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(w)))
name = qtify(item->name());
}
changeObjectName(w, name);
QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget);
if (!qobject_cast<QMenu*>(w) && (!parentWidget || !container)) {
m_formWindow->manageWidget(w);
if (parentWidget) {
QList<QWidget *> list = qVariantValue<QWidgetList>(parentWidget->property("_q_widgetOrder"));
list.append(w);
parentWidget->setProperty("_q_widgetOrder", qVariantFromValue(list));
QList<QWidget *> zOrder = qVariantValue<QWidgetList>(parentWidget->property("_q_zOrder"));
zOrder.append(w);
parentWidget->setProperty("_q_zOrder", qVariantFromValue(zOrder));
}
} else {
core()->metaDataBase()->add(w);
}
w->setWindowFlags(w->windowFlags() & ~Qt::Window);
// Make sure it is non-modal (for example, KDialog calls setModal(true) in the constructor).
w->setWindowModality(Qt::NonModal);
return w;
}
QLayout *QDesignerResource::createLayout(const QString &layoutName, QObject *parent, const QString &name)
{
QWidget *layoutBase = 0;
QLayout *layout = qobject_cast<QLayout*>(parent);
if (parent->isWidgetType())
layoutBase = static_cast<QWidget*>(parent);
else {
Q_ASSERT( layout != 0 );
layoutBase = layout->parentWidget();
}
LayoutInfo::Type layoutType = LayoutInfo::layoutType(layoutName);
if (layoutType == LayoutInfo::NoLayout) {
designerWarning(QCoreApplication::translate("QDesignerResource", "The layout type '%1' is not supported, defaulting to grid.").arg(layoutName));
layoutType = LayoutInfo::Grid;
}
QLayout *lay = core()->widgetFactory()->createLayout(layoutBase, layout, layoutType);
if (lay != 0)
changeObjectName(lay, name);
return lay;
}
// save
DomWidget *QDesignerResource::createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive)
{
QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(widget);
if (!item)
return 0;
if (qobject_cast<Spacer*>(widget) && m_copyWidget == false) {
++m_topLevelSpacerCount;
return 0;
}
const QDesignerWidgetDataBaseInterface *wdb = core()->widgetDataBase();
QDesignerWidgetDataBaseItemInterface *widgetInfo = 0;
const int widgetInfoIndex = wdb->indexOfObject(widget, false);
if (widgetInfoIndex != -1) {
widgetInfo = wdb->item(widgetInfoIndex);
// Recursively add all dependent custom widgets
QDesignerWidgetDataBaseItemInterface *customInfo = widgetInfo;
while (customInfo && customInfo->isCustom()) {
m_usedCustomWidgets.insert(customInfo, true);
const QString extends = customInfo->extends();
if (extends == customInfo->name()) {
break; // There are faulty files around that have name==extends
} else {
const int extendsIndex = wdb->indexOfClassName(customInfo->extends());
customInfo = extendsIndex != -1 ? wdb->item(extendsIndex) : static_cast<QDesignerWidgetDataBaseItemInterface *>(0);
}
}
}
DomWidget *w = 0;
if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(widget))
w = saveWidget(tabWidget, ui_parentWidget);
else if (QStackedWidget *stackedWidget = qobject_cast<QStackedWidget*>(widget))
w = saveWidget(stackedWidget, ui_parentWidget);
else if (QToolBox *toolBox = qobject_cast<QToolBox*>(widget))
w = saveWidget(toolBox, ui_parentWidget);
else if (QToolBar *toolBar = qobject_cast<QToolBar*>(widget))
w = saveWidget(toolBar, ui_parentWidget);
else if (QDesignerDockWidget *dockWidget = qobject_cast<QDesignerDockWidget*>(widget))
w = saveWidget(dockWidget, ui_parentWidget);
else if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget))
w = saveWidget(widget, container, ui_parentWidget);
else if (QWizardPage *wizardPage = qobject_cast<QWizardPage*>(widget))
w = saveWidget(wizardPage, ui_parentWidget);
else
w = QAbstractFormBuilder::createDom(widget, ui_parentWidget, recursive);
Q_ASSERT( w != 0 );
if (!qobject_cast<QLayoutWidget*>(widget) && w->attributeClass() == QLatin1String("QWidget")) {
w->setAttributeNative(true);
}
const QString className = w->attributeClass();
if (m_internal_to_qt.contains(className))
w->setAttributeClass(m_internal_to_qt.value(className));
w->setAttributeName(widget->objectName());
if (isPromoted( core(), widget)) { // is promoted?
Q_ASSERT(widgetInfo != 0);
w->setAttributeName(widget->objectName());
w->setAttributeClass(widgetInfo->name());
QList<DomProperty*> prop_list = w->elementProperty();
foreach (DomProperty *prop, prop_list) {
if (prop->attributeName() == QLatin1String("geometry")) {
if (DomRect *rect = prop->elementRect()) {
rect->setElementX(widget->x());
rect->setElementY(widget->y());
}
break;
}
}
} else if (widgetInfo != 0 && m_usedCustomWidgets.contains(widgetInfo)) {
if (widgetInfo->name() != w->attributeClass())
w->setAttributeClass(widgetInfo->name());
}
addExtensionDataToDOM(this, core(), w, widget);
addUserDefinedScripts(widget, w);
return w;
}
DomLayout *QDesignerResource::createDom(QLayout *layout, DomLayout *ui_parentLayout, DomWidget *ui_parentWidget)
{
QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(layout);
if (item == 0) {
layout = qFindChild<QLayout*>(layout);
// refresh the meta database item
item = core()->metaDataBase()->item(layout);
}
if (item == 0) {
// nothing to do.
return 0;
}
if (qobject_cast<QSplitter*>(layout->parentWidget()) != 0) {
// nothing to do.
return 0;
}
m_chain.push(layout);
DomLayout *l = QAbstractFormBuilder::createDom(layout, ui_parentLayout, ui_parentWidget);
Q_ASSERT(l != 0);
LayoutPropertySheet::stretchAttributesToDom(core(), layout, l);
m_chain.pop();
return l;
}
DomLayoutItem *QDesignerResource::createDom(QLayoutItem *item, DomLayout *ui_layout, DomWidget *ui_parentWidget)
{
DomLayoutItem *ui_item = 0;
if (Spacer *s = qobject_cast<Spacer*>(item->widget())) {
if (!core()->metaDataBase()->item(s))
return 0;
DomSpacer *spacer = new DomSpacer();
const QString objectName = s->objectName();
if (!objectName.isEmpty())
spacer->setAttributeName(objectName);
const QList<DomProperty*> properties = computeProperties(item->widget());
// ### filter the properties
spacer->setElementProperty(properties);
ui_item = new DomLayoutItem();
ui_item->setElementSpacer(spacer);
m_laidout.insert(item->widget(), true);
} else if (QLayoutWidget *layoutWidget = qobject_cast<QLayoutWidget*>(item->widget())) {
// Do not save a QLayoutWidget if it is within a layout (else it is saved as "QWidget"
Q_ASSERT(layoutWidget->layout());
DomLayout *l = createDom(layoutWidget->layout(), ui_layout, ui_parentWidget);
ui_item = new DomLayoutItem();
ui_item->setElementLayout(l);
m_laidout.insert(item->widget(), true);
} else if (!item->spacerItem()) { // we use spacer as fake item in the Designer
ui_item = QAbstractFormBuilder::createDom(item, ui_layout, ui_parentWidget);
} else {
return 0;
}
if (m_chain.size() && item->widget()) {
if (QGridLayout *grid = qobject_cast<QGridLayout*>(m_chain.top())) {
const int index = Utils::indexOfWidget(grid, item->widget());
int row, column, rowspan, colspan;
grid->getItemPosition(index, &row, &column, &rowspan, &colspan);
ui_item->setAttributeRow(row);
ui_item->setAttributeColumn(column);
if (colspan != 1)
ui_item->setAttributeColSpan(colspan);
if (rowspan != 1)
ui_item->setAttributeRowSpan(rowspan);
} else {
if (QFormLayout *form = qobject_cast<QFormLayout*>(m_chain.top())) {
const int index = Utils::indexOfWidget(form, item->widget());
int row, column, colspan;
getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan);
ui_item->setAttributeRow(row);
ui_item->setAttributeColumn(column);
if (colspan != 1)
ui_item->setAttributeColSpan(colspan);
}
}
}
return ui_item;
}
void QDesignerResource::createCustomWidgets(DomCustomWidgets *dom_custom_widgets)
{
QSimpleResource::handleDomCustomWidgets(core(), dom_custom_widgets);
}
DomTabStops *QDesignerResource::saveTabStops()
{
QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(m_formWindow);
Q_ASSERT(item);
QStringList tabStops;
foreach (QWidget *widget, item->tabOrder()) {
if (m_formWindow->mainContainer()->isAncestorOf(widget))
tabStops.append(widget->objectName());
}
if (tabStops.count()) {
DomTabStops *dom = new DomTabStops;
dom->setElementTabStop(tabStops);
return dom;
}
return 0;
}
void QDesignerResource::applyTabStops(QWidget *widget, DomTabStops *tabStops)
{
if (!tabStops)
return;
QList<QWidget*> tabOrder;
foreach (const QString &widgetName, tabStops->elementTabStop()) {
if (QWidget *w = qFindChild<QWidget*>(widget, widgetName)) {
tabOrder.append(w);
}
}
QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(m_formWindow);
Q_ASSERT(item);
item->setTabOrder(tabOrder);
}
/* Unmanaged container pages occur when someone adds a page in a custom widget
* constructor. They don't have a meta DB entry which causes createDom
* to return 0. */
inline QString msgUnmanagedPage(QDesignerFormEditorInterface *core,
QWidget *container, int index, QWidget *page)
{
return QCoreApplication::translate("QDesignerResource",
"The container extension of the widget '%1' (%2) returned a widget not managed by Designer '%3' (%4) when queried for page #%5.\n"
"Container pages should only be added by specifying them in XML returned by the domXml() method of the custom widget.").
arg(container->objectName(), WidgetFactory::classNameOf(core, container),
page->objectName(), WidgetFactory::classNameOf(core, page)).
arg(index);
}
DomWidget *QDesignerResource::saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget)
{
DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
QList<DomWidget*> ui_widget_list;
for (int i=0; i<container->count(); ++i) {
QWidget *page = container->widget(i);
Q_ASSERT(page);
if (DomWidget *ui_page = createDom(page, ui_widget)) {
ui_widget_list.append(ui_page);
} else {
if (QSimpleResource::warningsEnabled())
designerWarning(msgUnmanagedPage(core(), widget, i, page));
}
}
ui_widget->setElementWidget(ui_widget_list);
return ui_widget;
}
DomWidget *QDesignerResource::saveWidget(QStackedWidget *widget, DomWidget *ui_parentWidget)
{
DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
QList<DomWidget*> ui_widget_list;
if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
for (int i=0; i<container->count(); ++i) {
QWidget *page = container->widget(i);
Q_ASSERT(page);
if (DomWidget *ui_page = createDom(page, ui_widget)) {
ui_widget_list.append(ui_page);
} else {
if (QSimpleResource::warningsEnabled())
designerWarning(msgUnmanagedPage(core(), widget, i, page));
}
}
}
ui_widget->setElementWidget(ui_widget_list);
return ui_widget;
}
DomWidget *QDesignerResource::saveWidget(QToolBar *toolBar, DomWidget *ui_parentWidget)
{
DomWidget *ui_widget = QAbstractFormBuilder::createDom(toolBar, ui_parentWidget, false);
if (const QMainWindow *mainWindow = qobject_cast<QMainWindow*>(toolBar->parentWidget())) {
const bool toolBarBreak = mainWindow->toolBarBreak(toolBar);
const Qt::ToolBarArea area = mainWindow->toolBarArea(toolBar);
QList<DomProperty*> attributes = ui_widget->elementAttribute();
DomProperty *attr = new DomProperty();
attr->setAttributeName(QLatin1String("toolBarArea"));
attr->setElementEnum(QLatin1String(toolBarAreaMetaEnum().valueToKey(area)));
attributes << attr;
attr = new DomProperty();
attr->setAttributeName(QLatin1String("toolBarBreak"));
attr->setElementBool(toolBarBreak ? QLatin1String("true") : QLatin1String("false"));
attributes << attr;
ui_widget->setElementAttribute(attributes);
}
return ui_widget;
}
DomWidget *QDesignerResource::saveWidget(QDesignerDockWidget *dockWidget, DomWidget *ui_parentWidget)
{
DomWidget *ui_widget = QAbstractFormBuilder::createDom(dockWidget, ui_parentWidget, true);
if (QMainWindow *mainWindow = qobject_cast<QMainWindow*>(dockWidget->parentWidget())) {
const Qt::DockWidgetArea area = mainWindow->dockWidgetArea(dockWidget);
DomProperty *attr = new DomProperty();
attr->setAttributeName(QLatin1String("dockWidgetArea"));
attr->setElementNumber(int(area));
ui_widget->setElementAttribute(ui_widget->elementAttribute() << attr);
}
return ui_widget;
}
static void saveStringProperty(DomProperty *property, const PropertySheetStringValue &value)
{
DomString *str = new DomString();
str->setText(value.value());
const QString property_comment = value.disambiguation();
if (!property_comment.isEmpty())
str->setAttributeComment(property_comment);
const QString property_extraComment = value.comment();
if (!property_extraComment.isEmpty())
str->setAttributeExtraComment(property_extraComment);
const bool property_translatable = value.translatable();
if (!property_translatable)
str->setAttributeNotr(QLatin1String("true"));
property->setElementString(str);
}
static void saveKeySequenceProperty(DomProperty *property, const PropertySheetKeySequenceValue &value)
{
DomString *str = new DomString();
str->setText(value.value().toString());
const QString property_comment = value.disambiguation();
if (!property_comment.isEmpty())
str->setAttributeComment(property_comment);
const QString property_extraComment = value.comment();
if (!property_extraComment.isEmpty())
str->setAttributeExtraComment(property_extraComment);
const bool property_translatable = value.translatable();
if (!property_translatable)
str->setAttributeNotr(QLatin1String("true"));
property->setElementString(str);
}
DomWidget *QDesignerResource::saveWidget(QTabWidget *widget, DomWidget *ui_parentWidget)
{
DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
QList<DomWidget*> ui_widget_list;
if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
const int current = widget->currentIndex();
for (int i=0; i<container->count(); ++i) {
QWidget *page = container->widget(i);
Q_ASSERT(page);
DomWidget *ui_page = createDom(page, ui_widget);
if (!ui_page) {
if (QSimpleResource::warningsEnabled())
designerWarning(msgUnmanagedPage(core(), widget, i, page));
continue;
}
QList<DomProperty*> ui_attribute_list;
const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
// attribute `icon'
widget->setCurrentIndex(i);
QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget);
PropertySheetIconValue icon = qVariantValue<PropertySheetIconValue>(sheet->property(sheet->indexOf(QLatin1String("currentTabIcon"))));
DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), qVariantFromValue(icon));
if (p) {
p->setAttributeName(strings.iconAttribute);
ui_attribute_list.append(p);
}
// attribute `title'
p = textBuilder()->saveText(sheet->property(sheet->indexOf(QLatin1String("currentTabText"))));
if (p) {
p->setAttributeName(strings.titleAttribute);
ui_attribute_list.append(p);
}
// attribute `toolTip'
QVariant v = sheet->property(sheet->indexOf(QLatin1String("currentTabToolTip")));
if (!qVariantValue<PropertySheetStringValue>(v).value().isEmpty()) {
p = textBuilder()->saveText(v);
if (p) {
p->setAttributeName(strings.toolTipAttribute);
ui_attribute_list.append(p);
}
}
// attribute `whatsThis'
v = sheet->property(sheet->indexOf(QLatin1String("currentTabWhatsThis")));
if (!qVariantValue<PropertySheetStringValue>(v).value().isEmpty()) {
p = textBuilder()->saveText(v);
if (p) {
p->setAttributeName(strings.whatsThisAttribute);
ui_attribute_list.append(p);
}
}
ui_page->setElementAttribute(ui_attribute_list);
ui_widget_list.append(ui_page);
}
widget->setCurrentIndex(current);
}
ui_widget->setElementWidget(ui_widget_list);
return ui_widget;
}
DomWidget *QDesignerResource::saveWidget(QToolBox *widget, DomWidget *ui_parentWidget)
{
DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false);
QList<DomWidget*> ui_widget_list;
if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) {
const int current = widget->currentIndex();
for (int i=0; i<container->count(); ++i) {
QWidget *page = container->widget(i);
Q_ASSERT(page);
DomWidget *ui_page = createDom(page, ui_widget);
if (!ui_page) {
if (QSimpleResource::warningsEnabled())
designerWarning(msgUnmanagedPage(core(), widget, i, page));
continue;
}
// attribute `label'
QList<DomProperty*> ui_attribute_list;
const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
// attribute `icon'
widget->setCurrentIndex(i);
QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), widget);
PropertySheetIconValue icon = qVariantValue<PropertySheetIconValue>(sheet->property(sheet->indexOf(QLatin1String("currentItemIcon"))));
DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), qVariantFromValue(icon));
if (p) {
p->setAttributeName(strings.iconAttribute);
ui_attribute_list.append(p);
}
p = textBuilder()->saveText(sheet->property(sheet->indexOf(QLatin1String("currentItemText"))));
if (p) {
p->setAttributeName(strings.labelAttribute);
ui_attribute_list.append(p);
}
// attribute `toolTip'
QVariant v = sheet->property(sheet->indexOf(QLatin1String("currentItemToolTip")));
if (!qVariantValue<PropertySheetStringValue>(v).value().isEmpty()) {
p = textBuilder()->saveText(v);
if (p) {
p->setAttributeName(strings.toolTipAttribute);
ui_attribute_list.append(p);
}
}
ui_page->setElementAttribute(ui_attribute_list);
ui_widget_list.append(ui_page);
}
widget->setCurrentIndex(current);
}
ui_widget->setElementWidget(ui_widget_list);
return ui_widget;
}
DomWidget *QDesignerResource::saveWidget(QWizardPage *wizardPage, DomWidget *ui_parentWidget)
{
DomWidget *ui_widget = QAbstractFormBuilder::createDom(wizardPage, ui_parentWidget, true);
QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), wizardPage);
// Save the page id (string) attribute, append to existing attributes
const QString pageIdPropertyName = QLatin1String(QWizardPagePropertySheet::pageIdProperty);
const int pageIdIndex = sheet->indexOf(pageIdPropertyName);
if (pageIdIndex != -1 && sheet->isChanged(pageIdIndex)) {
DomProperty *property = variantToDomProperty(this, wizardPage->metaObject(), pageIdPropertyName, sheet->property(pageIdIndex));
Q_ASSERT(property);
property->elementString()->setAttributeNotr(QLatin1String("true"));
DomPropertyList attributes = ui_widget->elementAttribute();
attributes.push_back(property);
ui_widget->setElementAttribute(attributes);
}
return ui_widget;
}
// Do not save the 'currentTabName' properties of containers
static inline bool checkContainerProperty(const QWidget *w, const QString &propertyName)
{
if (qobject_cast<const QToolBox *>(w))
return QToolBoxWidgetPropertySheet::checkProperty(propertyName);
if (qobject_cast<const QTabWidget *>(w))
return QTabWidgetPropertySheet::checkProperty(propertyName);
if (qobject_cast<const QStackedWidget *>(w))
return QStackedWidgetPropertySheet::checkProperty(propertyName);
if (qobject_cast<const QMdiArea *>(w) || qobject_cast<const QWorkspace *>(w))
return QMdiAreaPropertySheet::checkProperty(propertyName);
return true;
}
bool QDesignerResource::checkProperty(QObject *obj, const QString &prop) const
{
const QDesignerMetaObjectInterface *meta = core()->introspection()->metaObject(obj);
const int pindex = meta->indexOfProperty(prop);
if (pindex != -1 && !(meta->property(pindex)->attributes(obj) & QDesignerMetaPropertyInterface::StoredAttribute))
return false;
if (prop == QLatin1String("objectName") || prop == QLatin1String("spacerName")) // ### don't store the property objectName
return false;
QWidget *check_widget = 0;
if (obj->isWidgetType())
check_widget = static_cast<QWidget*>(obj);
if (check_widget && prop == QLatin1String("geometry")) {
if (check_widget == m_formWindow->mainContainer())
return true; // Save although maincontainer is technically laid-out by embedding container
if (m_selected && m_selected == check_widget)
return true;
return !LayoutInfo::isWidgetLaidout(core(), check_widget);
}
if (check_widget && !checkContainerProperty(check_widget, prop))
return false;
if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), obj)) {
QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), obj);
const int pindex = sheet->indexOf(prop);
if (sheet->isAttribute(pindex))
return false;
if (!dynamicSheet || !dynamicSheet->isDynamicProperty(pindex))
return sheet->isChanged(pindex);
if (!sheet->isVisible(pindex))
return false;
return true;
}
return false;
}
bool QDesignerResource::addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout)
{
if (item->widget() == 0) {
return false;
}
QGridLayout *grid = qobject_cast<QGridLayout*>(layout);
QBoxLayout *box = qobject_cast<QBoxLayout*>(layout);
if (grid != 0) {
const int rowSpan = ui_item->hasAttributeRowSpan() ? ui_item->attributeRowSpan() : 1;
const int colSpan = ui_item->hasAttributeColSpan() ? ui_item->attributeColSpan() : 1;
grid->addWidget(item->widget(), ui_item->attributeRow(), ui_item->attributeColumn(), rowSpan, colSpan, item->alignment());
return true;
} else if (box != 0) {
box->addItem(item);
return true;
}
return QAbstractFormBuilder::addItem(ui_item, item, layout);
}
bool QDesignerResource::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
{
core()->metaDataBase()->add(widget); // ensure the widget is in the meta database
if (! QAbstractFormBuilder::addItem(ui_widget, widget, parentWidget) || qobject_cast<QMainWindow*> (parentWidget)) {
if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), parentWidget))
container->addWidget(widget);
}
if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) {
const int tabIndex = tabWidget->count() - 1;
const int current = tabWidget->currentIndex();
tabWidget->setCurrentIndex(tabIndex);
const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), parentWidget);
if (DomProperty *picon = attributes.value(strings.iconAttribute)) {
QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
sheet->setProperty(sheet->indexOf(QLatin1String("currentTabIcon")), v);
}
if (DomProperty *ptext = attributes.value(strings.titleAttribute)) {
QVariant v = textBuilder()->loadText(ptext);
sheet->setProperty(sheet->indexOf(QLatin1String("currentTabText")), v);
}
if (DomProperty *ptext = attributes.value(strings.toolTipAttribute)) {
QVariant v = textBuilder()->loadText(ptext);
sheet->setProperty(sheet->indexOf(QLatin1String("currentTabToolTip")), v);
}
if (DomProperty *ptext = attributes.value(strings.whatsThisAttribute)) {
QVariant v = textBuilder()->loadText(ptext);
sheet->setProperty(sheet->indexOf(QLatin1String("currentTabWhatsThis")), v);
}
tabWidget->setCurrentIndex(current);
} else if (QToolBox *toolBox = qobject_cast<QToolBox*>(parentWidget)) {
const int itemIndex = toolBox->count() - 1;
const int current = toolBox->currentIndex();
toolBox->setCurrentIndex(itemIndex);
const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), parentWidget);
if (DomProperty *picon = attributes.value(strings.iconAttribute)) {
QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon);
sheet->setProperty(sheet->indexOf(QLatin1String("currentItemIcon")), v);
}
if (DomProperty *ptext = attributes.value(strings.labelAttribute)) {
QVariant v = textBuilder()->loadText(ptext);
sheet->setProperty(sheet->indexOf(QLatin1String("currentItemText")), v);
}
if (DomProperty *ptext = attributes.value(strings.toolTipAttribute)) {
QVariant v = textBuilder()->loadText(ptext);
sheet->setProperty(sheet->indexOf(QLatin1String("currentItemToolTip")), v);
}
toolBox->setCurrentIndex(current);
}
return true;
}
bool QDesignerResource::copy(QIODevice *dev, const FormBuilderClipboard &selection)
{
m_copyWidget = true;
DomUI *ui = copy(selection);
m_laidout.clear();
m_copyWidget = false;
if (!ui)
return false;
QXmlStreamWriter writer(dev);
writer.setAutoFormatting(true);
writer.setAutoFormattingIndent(1);
writer.writeStartDocument();
ui->write(writer);
writer.writeEndDocument();
delete ui;
return true;
}
DomUI *QDesignerResource::copy(const FormBuilderClipboard &selection)
{
if (selection.empty())
return 0;
m_copyWidget = true;
DomWidget *ui_widget = new DomWidget();
ui_widget->setAttributeName(QLatin1String(clipboardObjectName));
bool hasItems = false;
// Widgets
if (!selection.m_widgets.empty()) {
QList<DomWidget*> ui_widget_list;
const int size = selection.m_widgets.size();
for (int i=0; i< size; ++i) {
QWidget *w = selection.m_widgets.at(i);
m_selected = w;
DomWidget *ui_child = createDom(w, ui_widget);
m_selected = 0;
if (ui_child)
ui_widget_list.append(ui_child);
}
if (!ui_widget_list.empty()) {
ui_widget->setElementWidget(ui_widget_list);
hasItems = true;
}
}
// actions
if (!selection.m_actions.empty()) {
QList<DomAction*> domActions;
foreach(QAction* action, selection.m_actions)
if (DomAction *domAction = createDom(action))
domActions += domAction;
if (!domActions.empty()) {
ui_widget-> setElementAction(domActions);
hasItems = true;
}
}
m_laidout.clear();
m_copyWidget = false;
if (!hasItems) {
delete ui_widget;
return 0;
}
// UI
DomUI *ui = new DomUI();
ui->setAttributeVersion(QLatin1String(currentUiVersion));
ui->setElementWidget(ui_widget);
ui->setElementResources(saveResources(m_resourceBuilder->usedQrcFiles()));
if (DomCustomWidgets *cws = saveCustomWidgets())
ui->setElementCustomWidgets(cws);
return ui;
}
FormBuilderClipboard QDesignerResource::paste(DomUI *ui, QWidget *widgetParent, QObject *actionParent)
{
QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
const int saved = m_isMainWidget;
m_isMainWidget = false;
FormBuilderClipboard rc;
// Widgets
const DomWidget *topLevel = ui->elementWidget();
initialize(ui);
const QList<DomWidget*> domWidgets = topLevel->elementWidget();
if (!domWidgets.empty()) {
const QPoint offset = m_formWindow->grid();
foreach (DomWidget* domWidget, domWidgets) {
if (QWidget *w = create(domWidget, widgetParent)) {
w->move(w->pos() + offset);
// ### change the init properties of w
rc.m_widgets.append(w);
}
}
}
const QList<DomAction*> domActions = topLevel->elementAction();
if (!domActions.empty())
foreach (DomAction *domAction, domActions)
if (QAction *a = create(domAction, actionParent))
rc.m_actions .append(a);
m_isMainWidget = saved;
if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core()))
extra->loadUiExtraInfo(ui);
createResources(ui->elementResources());
return rc;
}
FormBuilderClipboard QDesignerResource::paste(QIODevice *dev, QWidget *widgetParent, QObject *actionParent)
{
DomUI ui;
QXmlStreamReader reader(dev);
bool uiInitialized = false;
const QString uiElement = QLatin1String("ui");
while (!reader.atEnd()) {
if (reader.readNext() == QXmlStreamReader::StartElement) {
if (reader.name().compare(uiElement, Qt::CaseInsensitive)) {
ui.read(reader);
uiInitialized = true;
} else {
//: Parsing clipboard contents
reader.raiseError(QCoreApplication::translate("QDesignerResource", "Unexpected element <%1>").arg(reader.name().toString()));
}
}
}
if (reader.hasError()) {
//: Parsing clipboard contents
designerWarning(QCoreApplication::translate("QDesignerResource", "Error while pasting clipboard contents at line %1, column %2: %3")
.arg(reader.lineNumber()).arg(reader.columnNumber())
.arg(reader.errorString()));
uiInitialized = false;
} else if (uiInitialized == false) {
//: Parsing clipboard contents
designerWarning(QCoreApplication::translate("QDesignerResource", "Error while pasting clipboard contents: The root element <ui> is missing."));
}
if (!uiInitialized)
return FormBuilderClipboard();
FormBuilderClipboard clipBoard = paste(&ui, widgetParent, actionParent);
return clipBoard;
}
void QDesignerResource::layoutInfo(DomLayout *layout, QObject *parent, int *margin, int *spacing)
{
QAbstractFormBuilder::layoutInfo(layout, parent, margin, spacing);
}
DomCustomWidgets *QDesignerResource::saveCustomWidgets()
{
if (m_usedCustomWidgets.isEmpty())
return 0;
// We would like the list to be in order of the widget database indexes
// to ensure that base classes come first (nice optics)
QDesignerFormEditorInterface *core = m_formWindow->core();
QDesignerWidgetDataBaseInterface *db = core->widgetDataBase();
const bool isInternalWidgetDataBase = qobject_cast<const WidgetDataBase *>(db);
typedef QMap<int,DomCustomWidget*> OrderedDBIndexDomCustomWidgetMap;
OrderedDBIndexDomCustomWidgetMap orderedMap;
const QString global = QLatin1String("global");
foreach (QDesignerWidgetDataBaseItemInterface *item, m_usedCustomWidgets.keys()) {
const QString name = item->name();
DomCustomWidget *custom_widget = new DomCustomWidget;
custom_widget->setElementClass(name);
if (item->isContainer())
custom_widget->setElementContainer(item->isContainer());
if (!item->includeFile().isEmpty()) {
DomHeader *header = new DomHeader;
const IncludeSpecification spec = includeSpecification(item->includeFile());
header->setText(spec.first);
if (spec.second == IncludeGlobal) {
header->setAttributeLocation(global);
}
custom_widget->setElementHeader(header);
custom_widget->setElementExtends(item->extends());
}
if (isInternalWidgetDataBase) {
WidgetDataBaseItem *internalItem = static_cast<WidgetDataBaseItem *>(item);
const QStringList fakeSlots = internalItem->fakeSlots();
const QStringList fakeSignals = internalItem->fakeSignals();
if (!fakeSlots.empty() || !fakeSignals.empty()) {
DomSlots *domSlots = new DomSlots();
domSlots->setElementSlot(fakeSlots);
domSlots->setElementSignal(fakeSignals);
custom_widget->setElementSlots(domSlots);
}
const QString addPageMethod = internalItem->addPageMethod();
if (!addPageMethod.isEmpty())
custom_widget->setElementAddPageMethod(addPageMethod);
}
// Look up static per-class scripts of designer
if (DomScript *domScript = createScript(customWidgetScript(core, name), ScriptCustomWidgetPlugin))
custom_widget->setElementScript(domScript);
orderedMap.insert(db->indexOfClassName(name), custom_widget);
}
DomCustomWidgets *customWidgets = new DomCustomWidgets;
customWidgets->setElementCustomWidget(orderedMap.values());
return customWidgets;
}
bool QDesignerResource::canCompressMargins(QObject *object) const
{
if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) {
if (qobject_cast<QLayout *>(object)) {
const int l = sheet->property(sheet->indexOf(QLatin1String("leftMargin"))).toInt();
const int t = sheet->property(sheet->indexOf(QLatin1String("topMargin"))).toInt();
const int r = sheet->property(sheet->indexOf(QLatin1String("rightMargin"))).toInt();
const int b = sheet->property(sheet->indexOf(QLatin1String("bottomMargin"))).toInt();
if (l == t && l == r && l == b)
return true;
}
}
return false;
}
bool QDesignerResource::canCompressSpacings(QObject *object) const
{
if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) {
if (qobject_cast<QGridLayout *>(object)) {
const int h = sheet->property(sheet->indexOf(QLatin1String("horizontalSpacing"))).toInt();
const int v = sheet->property(sheet->indexOf(QLatin1String("verticalSpacing"))).toInt();
if (h == v)
return true;
}
}
return false;
}
QList<DomProperty*> QDesignerResource::computeProperties(QObject *object)
{
QList<DomProperty*> properties;
if (QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), object)) {
QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(core()->extensionManager(), object);
const int count = sheet->count();
QList<DomProperty *> marginProperties;
QList<DomProperty *> spacingProperties;
const bool compressMargins = canCompressMargins(object);
const bool compressSpacings = canCompressSpacings(object);
for (int index = 0; index < count; ++index) {
if (!sheet->isChanged(index) && (!dynamicSheet || !dynamicSheet->isDynamicProperty(index)))
continue;
const QString propertyName = sheet->propertyName(index);
// Suppress windowModality in legacy forms that have it set on child widgets
if (propertyName == QLatin1String("windowModality") && !sheet->isVisible(index))
continue;
const QVariant value = sheet->property(index);
if (DomProperty *p = createProperty(object, propertyName, value)) {
if (compressMargins && (propertyName == QLatin1String("leftMargin")
|| propertyName == QLatin1String("rightMargin")
|| propertyName == QLatin1String("topMargin")
|| propertyName == QLatin1String("bottomMargin"))) {
marginProperties.append(p);
} else if (compressSpacings && (propertyName == QLatin1String("horizontalSpacing")
|| propertyName == QLatin1String("verticalSpacing"))) {
spacingProperties.append(p);
} else {
properties.append(p);
}
}
}
if (compressMargins) {
if (marginProperties.count() == 4) { // if we have 3 it means one is reset so we can't compress
DomProperty *marginProperty = marginProperties.at(0);
marginProperty->setAttributeName(QLatin1String("margin"));
properties.append(marginProperty);
delete marginProperties.at(1);
delete marginProperties.at(2);
delete marginProperties.at(3);
} else {
properties += marginProperties;
}
}
if (compressSpacings) {
if (spacingProperties.count() == 2) {
DomProperty *spacingProperty = spacingProperties.at(0);
spacingProperty->setAttributeName(QLatin1String("spacing"));
properties.append(spacingProperty);
delete spacingProperties.at(1);
} else {
properties += spacingProperties;
}
}
}
return properties;
}
DomProperty *QDesignerResource::applyProperStdSetAttribute(QObject *object, const QString &propertyName, DomProperty *property)
{
if (!property)
return 0;
QExtensionManager *mgr = core()->extensionManager();
if (const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(mgr, object)) {
const QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension<QDesignerDynamicPropertySheetExtension*>(mgr, object);
const QDesignerPropertySheet *designerSheet = qobject_cast<QDesignerPropertySheet*>(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension)));
const int index = sheet->indexOf(propertyName);
if ((dynamicSheet && dynamicSheet->isDynamicProperty(index)) || (designerSheet && designerSheet->isDefaultDynamicProperty(index)))
property->setAttributeStdset(0);
}
return property;
}
// Optimistic check for a standard setter function
static inline bool hasSetter(QDesignerFormEditorInterface *core, QObject *object, const QString &propertyName)
{
const QDesignerMetaObjectInterface *meta = core->introspection()->metaObject(object);
const int pindex = meta->indexOfProperty(propertyName);
if (pindex == -1)
return true;
return meta->property(pindex)->hasSetter();
}
DomProperty *QDesignerResource::createProperty(QObject *object, const QString &propertyName, const QVariant &value)
{
if (!checkProperty(object, propertyName)) {
return 0;
}
if (qVariantCanConvert<PropertySheetFlagValue>(value)) {
const PropertySheetFlagValue f = qVariantValue<PropertySheetFlagValue>(value);
const QString flagString = f.metaFlags.toString(f.value, DesignerMetaFlags::FullyQualified);
if (flagString.isEmpty())
return 0;
DomProperty *p = new DomProperty;
// check if we have a standard cpp set function
if (!hasSetter(core(), object, propertyName))
p->setAttributeStdset(0);
p->setAttributeName(propertyName);
p->setElementSet(flagString);
return applyProperStdSetAttribute(object, propertyName, p);
} else if (qVariantCanConvert<PropertySheetEnumValue>(value)) {
const PropertySheetEnumValue e = qVariantValue<PropertySheetEnumValue>(value);
bool ok;
const QString id = e.metaEnum.toString(e.value, DesignerMetaEnum::FullyQualified, &ok);
if (!ok)
designerWarning(e.metaEnum.messageToStringFailed(e.value));
if (id.isEmpty())
return 0;
DomProperty *p = new DomProperty;
// check if we have a standard cpp set function
if (!hasSetter(core(), object, propertyName))
p->setAttributeStdset(0);
p->setAttributeName(propertyName);
p->setElementEnum(id);
return applyProperStdSetAttribute(object, propertyName, p);
} else if (qVariantCanConvert<PropertySheetStringValue>(value)) {
const PropertySheetStringValue strVal = qVariantValue<PropertySheetStringValue>(value);
DomProperty *p = new DomProperty;
if (!hasSetter(core(), object, propertyName))
p->setAttributeStdset(0);
p->setAttributeName(propertyName);
saveStringProperty(p, strVal);
return applyProperStdSetAttribute(object, propertyName, p);
} else if (qVariantCanConvert<PropertySheetKeySequenceValue>(value)) {
const PropertySheetKeySequenceValue keyVal = qVariantValue<PropertySheetKeySequenceValue>(value);
DomProperty *p = new DomProperty;
if (!hasSetter(core(), object, propertyName))
p->setAttributeStdset(0);
p->setAttributeName(propertyName);
saveKeySequenceProperty(p, keyVal);
return applyProperStdSetAttribute(object, propertyName, p);
}
return applyProperStdSetAttribute(object, propertyName, QAbstractFormBuilder::createProperty(object, propertyName, value));
}
QStringList QDesignerResource::mergeWithLoadedPaths(const QStringList &paths) const
{
QStringList newPaths = paths;
#ifdef OLD_RESOURCE_FORMAT
QStringList loadedPaths = m_resourceBuilder->loadedQrcFiles();
QStringListIterator it(loadedPaths);
while (it.hasNext()) {
const QString path = it.next();
if (!newPaths.contains(path))
newPaths << path;
}
#endif
return newPaths;
}
void QDesignerResource::createResources(DomResources *resources)
{
QStringList paths;
if (resources != 0) {
const QList<DomResource*> dom_include = resources->elementInclude();
foreach (DomResource *res, dom_include) {
QString path = QDir::cleanPath(m_formWindow->absoluteDir().absoluteFilePath(res->attributeLocation()));
while (!QFile::exists(path)) {
QWidget *dialogParent = m_formWindow->core()->topLevel();
const QString promptTitle = QApplication::translate("qdesigner_internal::QDesignerResource", "Loading qrc file", 0, QApplication::UnicodeUTF8);
const QString prompt = QApplication::translate("qdesigner_internal::QDesignerResource", "The specified qrc file <p><b>%1</b></p><p>could not be found. Do you want to update the file location?</p>", 0, QApplication::UnicodeUTF8).arg(path);
const QMessageBox::StandardButton answer = core()->dialogGui()->message(dialogParent, QDesignerDialogGuiInterface::ResourceLoadFailureMessage,
QMessageBox::Warning, promptTitle, prompt, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
if (answer == QMessageBox::Yes) {
const QFileInfo fi(path);
const QString fileDialogTitle = QApplication::translate("qdesigner_internal::QDesignerResource", "New location for %1", 0, QApplication::UnicodeUTF8).arg(fi.fileName());
const QString fileDialogPattern = QApplication::translate("qdesigner_internal::QDesignerResource", "Resource files (*.qrc)", 0, QApplication::UnicodeUTF8);
path = core()->dialogGui()->getOpenFileName(dialogParent, fileDialogTitle, fi.absolutePath(), fileDialogPattern);
if (path.isEmpty())
break;
} else {
break;
}
}
if (!path.isEmpty()) {
paths << path;
m_formWindow->addResourceFile(path);
}
}
}
#ifdef OLD_RESOURCE_FORMAT
paths = mergeWithLoadedPaths(paths);
#endif
QtResourceSet *resourceSet = m_formWindow->resourceSet();
if (resourceSet) {
QStringList oldPaths = resourceSet->activeQrcPaths();
QStringList newPaths = oldPaths;
QStringListIterator it(paths);
while (it.hasNext()) {
const QString path = it.next();
if (!newPaths.contains(path))
newPaths << path;
}
resourceSet->activateQrcPaths(newPaths);
} else {
resourceSet = m_formWindow->core()->resourceModel()->addResourceSet(paths);
m_formWindow->setResourceSet(resourceSet);
QObject::connect(m_formWindow->core()->resourceModel(), SIGNAL(resourceSetActivated(QtResourceSet*,bool)),
m_formWindow, SLOT(resourceSetActivated(QtResourceSet*,bool)));
}
}
DomResources *QDesignerResource::saveResources()
{
QStringList paths;
if (m_formWindow->saveResourcesBehaviour() == FormWindowBase::SaveAll) {
QtResourceSet *resourceSet = m_formWindow->resourceSet();
QList<DomResource*> dom_include;
if (resourceSet)
paths = resourceSet->activeQrcPaths();
} else if (m_formWindow->saveResourcesBehaviour() == FormWindowBase::SaveOnlyUsedQrcFiles) {
paths = m_resourceBuilder->usedQrcFiles();
}
return saveResources(paths);
}
DomResources *QDesignerResource::saveResources(const QStringList &qrcPaths)
{
QtResourceSet *resourceSet = m_formWindow->resourceSet();
QList<DomResource*> dom_include;
if (resourceSet) {
const QStringList activePaths = resourceSet->activeQrcPaths();
foreach (const QString &path, activePaths) {
if (qrcPaths.contains(path)) {
DomResource *dom_res = new DomResource;
QString conv_path = path;
if (m_resourceBuilder->isSaveRelative())
conv_path = m_formWindow->absoluteDir().relativeFilePath(path);
dom_res->setAttributeLocation(conv_path.replace(QDir::separator(), QLatin1Char('/')));
dom_include.append(dom_res);
}
}
}
DomResources *dom_resources = new DomResources;
dom_resources->setElementInclude(dom_include);
return dom_resources;
}
DomAction *QDesignerResource::createDom(QAction *action)
{
if (!core()->metaDataBase()->item(action) || action->menu())
return 0;
return QAbstractFormBuilder::createDom(action);
}
DomActionGroup *QDesignerResource::createDom(QActionGroup *actionGroup)
{
if (core()->metaDataBase()->item(actionGroup) != 0) {
return QAbstractFormBuilder::createDom(actionGroup);
}
return 0;
}
QAction *QDesignerResource::create(DomAction *ui_action, QObject *parent)
{
if (QAction *action = QAbstractFormBuilder::create(ui_action, parent)) {
core()->metaDataBase()->add(action);
return action;
}
return 0;
}
QActionGroup *QDesignerResource::create(DomActionGroup *ui_action_group, QObject *parent)
{
if (QActionGroup *actionGroup = QAbstractFormBuilder::create(ui_action_group, parent)) {
core()->metaDataBase()->add(actionGroup);
return actionGroup;
}
return 0;
}
DomActionRef *QDesignerResource::createActionRefDom(QAction *action)
{
if (!core()->metaDataBase()->item(action)
|| (!action->isSeparator() && !action->menu() && action->objectName().isEmpty()))
return 0;
return QAbstractFormBuilder::createActionRefDom(action);
}
void QDesignerResource::addMenuAction(QAction *action)
{
core()->metaDataBase()->add(action);
}
QAction *QDesignerResource::createAction(QObject *parent, const QString &name)
{
if (QAction *action = QAbstractFormBuilder::createAction(parent, name)) {
core()->metaDataBase()->add(action);
return action;
}
return 0;
}
QActionGroup *QDesignerResource::createActionGroup(QObject *parent, const QString &name)
{
if (QActionGroup *actionGroup = QAbstractFormBuilder::createActionGroup(parent, name)) {
core()->metaDataBase()->add(actionGroup);
return actionGroup;
}
return 0;
}
/* Apply the attributes to a widget via property sheet where appropriate,
* that is, the sheet handles attributive fake properties */
void QDesignerResource::applyAttributesToPropertySheet(const DomWidget *ui_widget, QWidget *widget)
{
const DomPropertyList attributes = ui_widget->elementAttribute();
if (attributes.empty())
return;
QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_formWindow->core()->extensionManager(), widget);
const DomPropertyList::const_iterator acend = attributes.constEnd();
for (DomPropertyList::const_iterator it = attributes.constBegin(); it != acend; ++it) {
const QString name = (*it)->attributeName();
const int index = sheet->indexOf(name);
if (index == -1) {
const QString msg = QString::fromUtf8("Unable to apply attributive property '%1' to '%2'. It does not exist.").arg(name, widget->objectName());
designerWarning(msg);
} else {
sheet->setProperty(index, domPropertyToVariant(this, widget->metaObject(), *it));
sheet->setChanged(index, true);
}
}
}
void QDesignerResource::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
{
QAbstractFormBuilder::loadExtraInfo(ui_widget, widget, parentWidget);
// Apply the page id attribute of a QWizardPage (which is an attributive fake property)
if (qobject_cast<const QWizardPage*>(widget))
applyAttributesToPropertySheet(ui_widget, widget);
}
// Add user defined scripts (dialog box) belonging to QWidget to DomWidget.
void QDesignerResource::addUserDefinedScripts(QWidget *w, DomWidget *ui_widget)
{
QDesignerFormEditorInterface *core = m_formWindow->core();
DomScripts domScripts = ui_widget->elementScript();
// Look up user-defined scripts of designer
if (const qdesigner_internal::MetaDataBase *metaDataBase = qobject_cast<const qdesigner_internal::MetaDataBase *>(core->metaDataBase())) {
if (const qdesigner_internal::MetaDataBaseItem *metaItem = metaDataBase->metaDataBaseItem(w)) {
addScript(metaItem->script(), ScriptDesigner, domScripts);
}
}
if (!domScripts.empty())
ui_widget->setElementScript(domScripts);
}
}
QT_END_NAMESPACE