/****************************************************************************
**
** 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 Mobility Components.
**
** $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 "interfacewidget.h"
#include "mandatorylineedit.h"
#include "errorcollector.h"
#include <qserviceinterfacedescriptor_p.h>
#include <QSpinBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QLabel>
#include <QStringList>
#include <QHash>
#include <QListView>
#include <QPushButton>
#include <QStringListModel>
#include <QDebug>
QTM_USE_NAMESPACE
class EditableListWidgetGroup : public QWidget
{
Q_OBJECT
public:
EditableListWidgetGroup(QWidget *parent = 0);
signals:
void dataChanged();
protected:
virtual int addItem() = 0;
virtual bool removeItemAt(int index) = 0;
virtual QStringList listValues() const = 0;
void initLayout(QLayout *addItemLayout, const QString &buttonAddText);
void refreshView();
void setAddButtonEnabled(bool enabled);
private slots:
void clickedAdd();
void clickedRemove();
void currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
private:
QString defaultValue() const;
QStringListModel *m_model;
QListView *m_listView;
QPushButton *m_buttonAdd;
QPushButton *m_buttonDel;
QGridLayout *m_grid;
};
EditableListWidgetGroup::EditableListWidgetGroup(QWidget *parent)
: QWidget(parent),
m_model(new QStringListModel(this)),
m_listView(new QListView),
m_buttonAdd(new QPushButton),
m_buttonDel(new QPushButton(tr("Delete"))),
m_grid(new QGridLayout)
{
m_listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
void EditableListWidgetGroup::initLayout(QLayout *addItemLayout, const QString &buttonAddText)
{
m_buttonAdd->setText(buttonAddText);
m_grid->setContentsMargins(0, 0, 0, 0);
m_grid->addWidget(m_listView, 0, 0);
m_grid->addWidget(m_buttonDel, 0, 1, Qt::AlignTop);
m_grid->addWidget(m_buttonAdd, 1, 1);
if (addItemLayout)
m_grid->addLayout(addItemLayout, 1, 0);
m_model->setStringList(QStringList(defaultValue()));
m_listView->setModel(m_model);
m_buttonAdd->setEnabled(false);
m_buttonDel->setEnabled(false);
connect(m_buttonAdd, SIGNAL(clicked()), SLOT(clickedAdd()));
connect(m_buttonDel, SIGNAL(clicked()), SLOT(clickedRemove()));
connect(m_listView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
SLOT(currentRowChanged(QModelIndex,QModelIndex)));
setLayout(m_grid);
}
void EditableListWidgetGroup::refreshView()
{
QStringList values = listValues();
if (values.isEmpty())
m_model->setStringList(QStringList(defaultValue()));
else
m_model->setStringList(values);
}
void EditableListWidgetGroup::setAddButtonEnabled(bool enabled)
{
m_buttonAdd->setEnabled(enabled);
}
void EditableListWidgetGroup::clickedAdd()
{
int index = addItem();
if (index >= 0) {
refreshView();
m_listView->setCurrentIndex(m_model->index(index));
emit dataChanged();
}
}
void EditableListWidgetGroup::clickedRemove()
{
QModelIndex index = m_listView->currentIndex();
if (index.isValid() && removeItemAt(index.row())) {
refreshView();
m_listView->setCurrentIndex(m_model->index(index.row() == 0 ? 0 : index.row()-1));
emit dataChanged();
}
}
void EditableListWidgetGroup::currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
{
Q_UNUSED(previous);
m_buttonDel->setEnabled(current.isValid() && listValues().count() > 0);
}
QString EditableListWidgetGroup::defaultValue() const
{
return tr("(None)");
}
class CapabilitiesWidget : public EditableListWidgetGroup
{
Q_OBJECT
public:
CapabilitiesWidget(QWidget *parent = 0);
void setCapabilities(const QStringList &values);
const QStringList &capabilities() const { return m_values; }
protected:
virtual int addItem();
virtual bool removeItemAt(int index);
virtual QStringList listValues() const;
private slots:
void valueToAddChanged(const QString &text);
private:
QStringList m_values;
QLineEdit *m_newValueEdit;
};
CapabilitiesWidget::CapabilitiesWidget(QWidget *parent)
: EditableListWidgetGroup(parent),
m_newValueEdit(new QLineEdit)
{
connect(m_newValueEdit, SIGNAL(textChanged(QString)),
SLOT(valueToAddChanged(QString)));
QHBoxLayout *box = new QHBoxLayout;
box->addWidget(m_newValueEdit);
initLayout(box, tr("Add"));
}
void CapabilitiesWidget::setCapabilities(const QStringList &values)
{
m_values = values;
refreshView();
}
int CapabilitiesWidget::addItem()
{
if (!m_newValueEdit->text().isEmpty()) {
m_values << m_newValueEdit->text();
m_newValueEdit->clear();
return m_values.count() - 1;
}
return -1;
}
bool CapabilitiesWidget::removeItemAt(int index)
{
if (index >= 0 && index < m_values.count()) {
m_values.removeAt(index);
return true;
}
return false;
}
QStringList CapabilitiesWidget::listValues() const
{
return m_values;
}
void CapabilitiesWidget::valueToAddChanged(const QString &text)
{
setAddButtonEnabled(!text.isEmpty());
}
class CustomPropertiesWidget : public EditableListWidgetGroup
{
Q_OBJECT
public:
CustomPropertiesWidget(QWidget *parent = 0);
void setProperties(const QHash<QString, QString> &values);
const QStringList &propertyKeys() const { return m_keys; }
const QHash<QString, QString> &properties() const { return m_pairs; }
protected:
virtual int addItem();
virtual bool removeItemAt(int index);
virtual QStringList listValues() const;
private slots:
void keyToAddChanged(const QString &text);
private:
QStringList m_keys;
QHash<QString, QString> m_pairs;
QLineEdit *m_newKeyEdit;
QLineEdit *m_newValueEdit;
};
CustomPropertiesWidget::CustomPropertiesWidget(QWidget *parent)
: EditableListWidgetGroup(parent),
m_newKeyEdit(new QLineEdit),
m_newValueEdit(new QLineEdit)
{
connect(m_newKeyEdit, SIGNAL(textChanged(QString)),
SLOT(keyToAddChanged(QString)));
QHBoxLayout *box = new QHBoxLayout;
box->addWidget(m_newKeyEdit);
box->addWidget(new QLabel(QLatin1String("=>")));
box->addWidget(m_newValueEdit);
initLayout(box, tr("Add / Modify"));
}
void CustomPropertiesWidget::setProperties(const QHash<QString, QString> &values)
{
m_pairs = values;
m_keys = m_pairs.keys();
refreshView();
}
int CustomPropertiesWidget::addItem()
{
int index = -1;
QString key = m_newKeyEdit->text();
if (!key.isEmpty()) {
index = m_keys.indexOf(key);
if (index < 0) {
m_keys << key;
index = m_keys.count() - 1;
}
m_pairs[key] = m_newValueEdit->text();
m_newKeyEdit->clear();
m_newValueEdit->clear();
}
return index;
}
bool CustomPropertiesWidget::removeItemAt(int index)
{
if (index >= 0 && index < m_keys.count()) {
m_pairs.remove(m_keys.takeAt(index));
return true;
}
return false;
}
QStringList CustomPropertiesWidget::listValues() const
{
QStringList values;
for (int i=0; i<m_keys.count(); i++)
values << (m_keys[i] + " => " + m_pairs[m_keys[i]]);
return values;
}
void CustomPropertiesWidget::keyToAddChanged(const QString &text)
{
setAddButtonEnabled(!text.isEmpty());
}
InterfaceWidget::InterfaceWidget(QWidget *parent)
: QWidget(parent),
m_name(new MandatoryLineEdit(tr("(Name required)"))),
m_verMajor(new QSpinBox),
m_verMinor(new QSpinBox),
m_desc(new QLineEdit),
m_capWidget(new CapabilitiesWidget),
m_customPropWidget(new CustomPropertiesWidget)
{
m_verMajor->setMinimum(1); // min version as documented for interfaces
QHBoxLayout *versions = new QHBoxLayout;
versions->addWidget(m_verMajor);
versions->addWidget(new QLabel(tr("(Major)")));
versions->addWidget(m_verMinor);
versions->addWidget(new QLabel(tr("(Minor)")));
QFormLayout *form = new QFormLayout;
form->addRow(tr("* Name"), m_name);
form->addRow(tr("* Version"), versions);
form->addRow(tr("Description"), m_desc);
form->addRow(tr("Capabilities"), m_capWidget);
form->addRow(tr("Custom attributes"), m_customPropWidget);
setLayout(form);
connect(m_name, SIGNAL(textEdited(QString)), SLOT(changedNameOrVersion()));
connect(m_verMajor, SIGNAL(valueChanged(int)), SLOT(changedNameOrVersion()));
connect(m_verMinor, SIGNAL(valueChanged(int)), SLOT(changedNameOrVersion()));
connect(m_desc, SIGNAL(textEdited(QString)), SIGNAL(dataChanged()));
connect(m_capWidget, SIGNAL(dataChanged()), SIGNAL(dataChanged()));
connect(m_customPropWidget, SIGNAL(dataChanged()), SIGNAL(dataChanged()));
}
void InterfaceWidget::init()
{
m_name->setFocus();
}
void InterfaceWidget::load(const QServiceInterfaceDescriptor &info)
{
const QServiceInterfaceDescriptorPrivate *p = QServiceInterfaceDescriptorPrivate::getPrivate(&info);
if (!p)
return;
m_name->setText(p->interfaceName);
m_verMajor->setValue(p->major);
m_verMinor->setValue(p->minor);
if (p->attributes.contains(QServiceInterfaceDescriptor::InterfaceDescription))
m_desc->setText(p->attributes[QServiceInterfaceDescriptor::InterfaceDescription].toString());
if (p->attributes.contains(QServiceInterfaceDescriptor::Capabilities))
m_capWidget->setCapabilities(p->attributes[QServiceInterfaceDescriptor::Capabilities].toStringList());
if (!p->customAttributes.isEmpty())
m_customPropWidget->setProperties(p->customAttributes);
}
void InterfaceWidget::validate(ErrorCollector *errors)
{
m_name->validate(errors);
}
void InterfaceWidget::writeXml(QXmlStreamWriter *writer) const
{
writer->writeTextElement(QLatin1String("name"), !m_name->hasText() ? QString() : m_name->text());
writer->writeTextElement(QLatin1String("version"),
QString("%1.%2").arg(m_verMajor->value()).arg(m_verMinor->value()));
writer->writeTextElement(QLatin1String("description"), m_desc->text());
writer->writeTextElement(QLatin1String("capabilities"),
m_capWidget->capabilities().join(QLatin1String(",")));
const QStringList &customPropKeys = m_customPropWidget->propertyKeys();
const QHash<QString, QString> &customProps = m_customPropWidget->properties();
for (int i=0; i<customPropKeys.count(); i++) {
writer->writeStartElement(QLatin1String("customproperty"));
writer->writeAttribute(QLatin1String("key"), customPropKeys[i]);
writer->writeCharacters(customProps[customPropKeys[i]]);
writer->writeEndElement();
}
}
QString InterfaceWidget::title() const
{
QString name = m_name->text().isEmpty() ? tr("[New Interface]") : m_name->text();
return QString("%1 %2.%3").arg(name).arg(m_verMajor->value()).arg(m_verMinor->value());
}
void InterfaceWidget::changedNameOrVersion()
{
emit titleChanged(title());
emit dataChanged();
}
#include "interfacewidget.moc"