/****************************************************************************
**
** Copyright (C) 2009 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$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qdesigner_integration_p.h"
#include "qdesigner_propertycommand_p.h"
#include "qdesigner_propertyeditor_p.h"
#include "qdesigner_objectinspector_p.h"
#include "widgetdatabase_p.h"
#include "pluginmanager_p.h"
#include "widgetfactory_p.h"
#include "qdesigner_widgetbox_p.h"
#include "qtgradientmanager.h"
#include "qtgradientutils.h"
#include "qtresourcemodel_p.h"
// sdk
#include <QtDesigner/QDesignerFormEditorInterface>
#include <QtDesigner/QDesignerFormWindowInterface>
#include <QtDesigner/QDesignerFormWindowManagerInterface>
#include <QtDesigner/QDesignerFormWindowCursorInterface>
#include <QtDesigner/QDesignerActionEditorInterface>
#include <QtDesigner/QDesignerWidgetBoxInterface>
#include <QtDesigner/QExtensionManager>
#include <QtDesigner/QDesignerResourceBrowserInterface>
#include <QtDesigner/QDesignerPropertySheetExtension>
#include <QtCore/QVariant>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
namespace qdesigner_internal {
// ---------------- DesignerIntegrationPrivate
class QDesignerIntegrationPrivate {
public:
QDesignerIntegrationPrivate()
: m_gradientManager(0),
m_fileWatcherBehaviour(QDesignerIntegration::PromptAndReload),
m_resourceEditingEnabled(true),
m_slotNavigationEnabled(false)
{}
QString m_gradientsPath;
QtGradientManager *m_gradientManager;
QDesignerIntegration::ResourceFileWatcherBehaviour m_fileWatcherBehaviour;
bool m_resourceEditingEnabled;
bool m_slotNavigationEnabled;
};
// -------------- QDesignerIntegration
// As of 4.4, the header will be distributed with the Eclipse plugin.
QDesignerIntegration::QDesignerIntegration(QDesignerFormEditorInterface *core, QObject *parent) :
QDesignerIntegrationInterface(core, parent),
m_d(new QDesignerIntegrationPrivate)
{
initialize();
}
QDesignerIntegration::~QDesignerIntegration()
{
QFile f(m_d->m_gradientsPath);
if (f.open(QIODevice::WriteOnly)) {
f.write(QtGradientUtils::saveState(m_d->m_gradientManager).toUtf8());
f.close();
}
delete m_d;
}
void QDesignerIntegration::initialize()
{
//
// integrate the `Form Editor component'
//
// Extensions
if (QDesignerPropertyEditor *designerPropertyEditor= qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor())) {
connect(designerPropertyEditor, SIGNAL(propertyValueChanged(QString,QVariant,bool)), this, SLOT(updateProperty(QString,QVariant,bool)));
connect(designerPropertyEditor, SIGNAL(resetProperty(QString)), this, SLOT(resetProperty(QString)));
connect(designerPropertyEditor, SIGNAL(addDynamicProperty(QString,QVariant)),
this, SLOT(addDynamicProperty(QString,QVariant)));
connect(designerPropertyEditor, SIGNAL(removeDynamicProperty(QString)),
this, SLOT(removeDynamicProperty(QString)));
} else {
connect(core()->propertyEditor(), SIGNAL(propertyChanged(QString,QVariant)),
this, SLOT(updatePropertyPrivate(QString,QVariant)));
}
connect(core()->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)),
this, SLOT(setupFormWindow(QDesignerFormWindowInterface*)));
connect(core()->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)),
this, SLOT(updateActiveFormWindow(QDesignerFormWindowInterface*)));
m_d->m_gradientManager = new QtGradientManager(this);
core()->setGradientManager(m_d->m_gradientManager);
QString designerFolder = QDir::homePath();
designerFolder += QDir::separator();
designerFolder += QLatin1String(".designer");
m_d->m_gradientsPath = designerFolder;
m_d->m_gradientsPath += QDir::separator();
m_d->m_gradientsPath += QLatin1String("gradients.xml");
QFile f(m_d->m_gradientsPath);
if (f.open(QIODevice::ReadOnly)) {
QtGradientUtils::restoreState(m_d->m_gradientManager, QString::fromAscii(f.readAll()));
f.close();
} else {
QFile defaultGradients(QLatin1String(":/trolltech/designer/defaultgradients.xml"));
if (defaultGradients.open(QIODevice::ReadOnly)) {
QtGradientUtils::restoreState(m_d->m_gradientManager, QString::fromAscii(defaultGradients.readAll()));
defaultGradients.close();
}
}
if (WidgetDataBase *widgetDataBase = qobject_cast<WidgetDataBase*>(core()->widgetDataBase()))
widgetDataBase->grabStandardWidgetBoxIcons();
}
void QDesignerIntegration::updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling)
{
QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
if (!formWindow)
return;
Selection selection;
getSelection(selection);
if (selection.empty())
return;
SetPropertyCommand *cmd = new SetPropertyCommand(formWindow);
// find a reference object to compare to and to find the right group
if (cmd->init(selection.selection(), name, value, propertyEditorObject(), enableSubPropertyHandling)) {
formWindow->commandHistory()->push(cmd);
} else {
delete cmd;
qDebug() << "Unable to set property " << name << '.';
}
emit propertyChanged(formWindow, name, value);
}
void QDesignerIntegration::updatePropertyPrivate(const QString &name, const QVariant &value)
{
updateProperty(name, value, true);
}
void QDesignerIntegration::resetProperty(const QString &name)
{
QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
if (!formWindow)
return;
Selection selection;
getSelection(selection);
if (selection.empty())
return;
ResetPropertyCommand *cmd = new ResetPropertyCommand(formWindow);
// find a reference object to find the right group
if (cmd->init(selection.selection(), name, propertyEditorObject())) {
formWindow->commandHistory()->push(cmd);
} else {
delete cmd;
qDebug() << "** WARNING Unable to reset property " << name << '.';
}
}
void QDesignerIntegration::addDynamicProperty(const QString &name, const QVariant &value)
{
QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
if (!formWindow)
return;
Selection selection;
getSelection(selection);
if (selection.empty())
return;
AddDynamicPropertyCommand *cmd = new AddDynamicPropertyCommand(formWindow);
if (cmd->init(selection.selection(), propertyEditorObject(), name, value)) {
formWindow->commandHistory()->push(cmd);
} else {
delete cmd;
qDebug() << "** WARNING Unable to add dynamic property " << name << '.';
}
}
void QDesignerIntegration::removeDynamicProperty(const QString &name)
{
QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
if (!formWindow)
return;
Selection selection;
getSelection(selection);
if (selection.empty())
return;
RemoveDynamicPropertyCommand *cmd = new RemoveDynamicPropertyCommand(formWindow);
if (cmd->init(selection.selection(), propertyEditorObject(), name)) {
formWindow->commandHistory()->push(cmd);
} else {
delete cmd;
qDebug() << "** WARNING Unable to remove dynamic property " << name << '.';
}
}
void QDesignerIntegration::updateActiveFormWindow(QDesignerFormWindowInterface *formWindow)
{
Q_UNUSED(formWindow);
updateSelection();
}
void QDesignerIntegration::setupFormWindow(QDesignerFormWindowInterface *formWindow)
{
connect(formWindow, SIGNAL(selectionChanged()), this, SLOT(updateSelection()));
connect(formWindow, SIGNAL(activated(QWidget*)), this, SLOT(activateWidget(QWidget*)));
}
void QDesignerIntegration::updateGeometry()
{
}
void QDesignerIntegration::updateSelection()
{
QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
QWidget *selection = 0;
if (formWindow) {
selection = formWindow->cursor()->current();
}
if (QDesignerActionEditorInterface *actionEditor = core()->actionEditor())
actionEditor->setFormWindow(formWindow);
if (QDesignerPropertyEditorInterface *propertyEditor = core()->propertyEditor())
propertyEditor->setObject(selection);
if (QDesignerObjectInspectorInterface *objectInspector = core()->objectInspector())
objectInspector->setFormWindow(formWindow);
}
void QDesignerIntegration::activateWidget(QWidget *widget)
{
Q_UNUSED(widget);
}
QWidget *QDesignerIntegration::containerWindow(QWidget *widget) const
{
// Find the parent window to apply a geometry to.
while (widget) {
if (widget->isWindow())
break;
if (!qstrcmp(widget->metaObject()->className(), "QMdiSubWindow"))
break;
widget = widget->parentWidget();
}
return widget;
}
void QDesignerIntegration::getSelection(Selection &s)
{
// Get multiselection from object inspector
if (QDesignerObjectInspector *designerObjectInspector = qobject_cast<QDesignerObjectInspector *>(core()->objectInspector())) {
designerObjectInspector->getSelection(s);
// Action editor puts actions that are not on the form yet
// into the property editor only.
if (s.empty())
if (QObject *object = core()->propertyEditor()->object())
s.objects.push_back(object);
} else {
// Just in case someone plugs in an old-style object inspector: Emulate selection
s.clear();
QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow();
if (!formWindow)
return;
QObject *object = core()->propertyEditor()->object();
if (object->isWidgetType()) {
QWidget *widget = static_cast<QWidget*>(object);
QDesignerFormWindowCursorInterface *cursor = formWindow->cursor();
if (cursor->isWidgetSelected(widget)) {
s.managed.push_back(widget);
} else {
s.unmanaged.push_back(widget);
}
} else {
s.objects.push_back(object);
}
}
}
QObject *QDesignerIntegration::propertyEditorObject()
{
QDesignerPropertyEditorInterface *propertyEditor = core()->propertyEditor();
if (!propertyEditor)
return 0;
return propertyEditor->object();
}
// Load plugins into widget database and factory.
void QDesignerIntegration::initializePlugins(QDesignerFormEditorInterface *formEditor)
{
// load the plugins
WidgetDataBase *widgetDataBase = qobject_cast<WidgetDataBase*>(formEditor->widgetDataBase());
if (widgetDataBase) {
widgetDataBase->loadPlugins();
}
if (WidgetFactory *widgetFactory = qobject_cast<WidgetFactory*>(formEditor->widgetFactory())) {
widgetFactory->loadPlugins();
}
if (widgetDataBase) {
widgetDataBase->grabDefaultPropertyValues();
}
}
void QDesignerIntegration::updateCustomWidgetPlugins()
{
QDesignerFormEditorInterface *formEditor = core();
if (QDesignerPluginManager *pm = formEditor->pluginManager())
pm->registerNewPlugins();
initializePlugins(formEditor);
// Do not just reload the last file as the WidgetBox merges the compiled-in resources
// and $HOME/.designer/widgetbox.xml. This would also double the scratchpad.
if (QDesignerWidgetBox *wb = qobject_cast<QDesignerWidgetBox*>(formEditor->widgetBox())) {
const QDesignerWidgetBox::LoadMode oldLoadMode = wb->loadMode();
wb->setLoadMode(QDesignerWidgetBox::LoadCustomWidgetsOnly);
wb->load();
wb->setLoadMode(oldLoadMode);
}
}
void QDesignerIntegration::emitObjectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, const QString &newName, const QString &oldName)
{
emit objectNameChanged(formWindow, object, newName, oldName);
}
void QDesignerIntegration::emitNavigateToSlot(const QString &objectName,
const QString &signalSignature,
const QStringList ¶meterNames)
{
emit navigateToSlot(objectName, signalSignature, parameterNames);
}
void QDesignerIntegration::emitNavigateToSlot(const QString &slotSignature)
{
emit navigateToSlot(slotSignature);
}
void QDesignerIntegration::requestHelp(const QDesignerFormEditorInterface *core, const QString &manual, const QString &document)
{
if (QDesignerIntegration *di = qobject_cast<QDesignerIntegration *>(core->integration()))
emit di->helpRequested(manual, document);
}
QDesignerResourceBrowserInterface *QDesignerIntegration::createResourceBrowser(QWidget *)
{
return 0;
}
void QDesignerIntegration::setResourceFileWatcherBehaviour(ResourceFileWatcherBehaviour behaviour)
{
m_d->m_fileWatcherBehaviour = behaviour;
core()->resourceModel()->setWatcherEnabled(behaviour != QDesignerIntegration::NoWatcher);
}
QDesignerIntegration::ResourceFileWatcherBehaviour QDesignerIntegration::resourceFileWatcherBehaviour() const
{
return m_d->m_fileWatcherBehaviour;
}
void QDesignerIntegration::setResourceEditingEnabled(bool enable)
{
m_d->m_resourceEditingEnabled = enable;
}
bool QDesignerIntegration::isResourceEditingEnabled() const
{
return m_d->m_resourceEditingEnabled;
}
void QDesignerIntegration::setSlotNavigationEnabled(bool enable)
{
m_d->m_slotNavigationEnabled = enable;
}
bool QDesignerIntegration::isSlotNavigationEnabled() const
{
return m_d->m_slotNavigationEnabled;
}
static QString fixHelpClassName(const QString &className)
{
// ### generalize using the Widget Data Base
if (className == QLatin1String("Line"))
return QLatin1String("QFrame");
if (className == QLatin1String("Spacer"))
return QLatin1String("QSpacerItem");
if (className == QLatin1String("QLayoutWidget"))
return QLatin1String("QLayout");
return className;
}
// Return class in which the property is defined
static QString classForProperty(QDesignerFormEditorInterface *core,
QObject *object,
const QString &property)
{
if (const QDesignerPropertySheetExtension *ps = qt_extension<QDesignerPropertySheetExtension *>(core->extensionManager(), object)) {
const int index = ps->indexOf(property);
if (index >= 0)
return ps->propertyGroup(index);
}
return QString();
}
QString QDesignerIntegration::contextHelpId() const
{
QObject *currentObject = core()->propertyEditor()->object();
if (!currentObject)
return QString();
// Return a help index id consisting of "class::property"
QString className;
QString currentPropertyName = core()->propertyEditor()->currentPropertyName();
if (!currentPropertyName.isEmpty())
className = classForProperty(core(), currentObject, currentPropertyName);
if (className.isEmpty()) {
currentPropertyName.clear(); // We hit on some fake property.
className = WidgetFactory::classNameOf(core(), currentObject);
}
QString helpId = fixHelpClassName(className);
if (!currentPropertyName.isEmpty()) {
helpId += QLatin1String("::");
helpId += currentPropertyName;
}
return helpId;
}
} // namespace qdesigner_internal
QT_END_NAMESPACE