You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
481 lines
14 KiB
481 lines
14 KiB
/***************************************************************************
|
|
* Copyright (C) 2002-2004 by Alexander Dymo *
|
|
* cloudtemple@mskat.net *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Library General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of the *
|
|
* License, or (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
***************************************************************************/
|
|
#include "propertyeditor.h"
|
|
|
|
#ifndef PURE_QT
|
|
#include <klocale.h>
|
|
#include <kdebug.h>
|
|
#include <kiconloader.h>
|
|
#else
|
|
#include "compat_tools.h"
|
|
#endif
|
|
|
|
#include <qtable.h>
|
|
#include <qlayout.h>
|
|
#include <qpainter.h>
|
|
#include <qptrlist.h>
|
|
#include <qvaluelist.h>
|
|
#include <qpushbutton.h>
|
|
|
|
#include "property.h"
|
|
#include "multiproperty.h"
|
|
#include "propertymachinefactory.h"
|
|
|
|
namespace PropertyLib{
|
|
|
|
class PropertyItem: public KListViewItem{
|
|
public:
|
|
PropertyItem(PropertyEditor *parent, MultiProperty *property)
|
|
:KListViewItem(parent, property->description()), m_editor(parent), m_property(property),
|
|
m_changed(false)
|
|
{
|
|
}
|
|
|
|
PropertyItem(PropertyEditor *editor, KListViewItem *parent, MultiProperty *property)
|
|
:KListViewItem(parent, property->description()), m_editor(editor),
|
|
m_property(property), m_changed(false)
|
|
{
|
|
}
|
|
|
|
/* int type() const
|
|
{
|
|
return m_property->type();
|
|
}
|
|
|
|
QString name() const
|
|
{
|
|
return m_property->name();
|
|
}
|
|
*/
|
|
MultiProperty *property() const
|
|
{
|
|
return m_property;
|
|
}
|
|
|
|
virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align)
|
|
{
|
|
if ((column == 0) && m_changed)
|
|
{
|
|
QFont font;
|
|
font.setBold(true);
|
|
p->setFont(font);
|
|
p->setBrush(cg.highlight());
|
|
p->setPen(cg.highlightedText());
|
|
}
|
|
if (column == 1)
|
|
{
|
|
QRect r(0, 0, m_editor->header()->sectionSize(1), height());
|
|
//FIXME: this is ugly, but how else can we deal with ValueFromList properties?
|
|
QVariant valueToDraw;
|
|
if (m_property->type() == Property::ValueFromList)
|
|
valueToDraw = m_property->findValueDescription();
|
|
else
|
|
valueToDraw = m_property->value();
|
|
QColorGroup icg(cg);
|
|
#ifndef PURE_QT
|
|
icg.setColor(QColorGroup::Background, backgroundColor());
|
|
#else
|
|
icg.setColor(QColorGroup::Background, white);
|
|
#endif
|
|
m_editor->machine(m_property)->propertyEditor->drawViewer(p, icg, r, valueToDraw);
|
|
return;
|
|
}
|
|
KListViewItem::paintCell(p, cg, column, width, align);
|
|
}
|
|
|
|
virtual void setup()
|
|
{
|
|
KListViewItem::setup();
|
|
setHeight(static_cast<int>(height()*1.5));
|
|
}
|
|
|
|
void setChanged(bool changed)
|
|
{
|
|
m_changed = changed;
|
|
}
|
|
|
|
private:
|
|
PropertyEditor *m_editor;
|
|
MultiProperty *m_property;
|
|
bool m_changed;
|
|
};
|
|
|
|
|
|
class PropertyGroupItem: public KListViewItem{
|
|
public:
|
|
PropertyGroupItem(KListView *parent, const QString &name)
|
|
:KListViewItem(parent, name)
|
|
{
|
|
init();
|
|
}
|
|
PropertyGroupItem(KListViewItem *parent, const QString &name)
|
|
:KListViewItem(parent, name)
|
|
{
|
|
init();
|
|
}
|
|
|
|
virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align)
|
|
{
|
|
if (column == 0)
|
|
{
|
|
QFont font;
|
|
font.setBold(true);
|
|
p->setFont(font);
|
|
p->setBrush(cg.highlight());
|
|
p->setPen(cg.highlightedText());
|
|
}
|
|
KListViewItem::paintCell(p, cg, column, width, align);
|
|
}
|
|
virtual void setup()
|
|
{
|
|
KListViewItem::setup();
|
|
setHeight(static_cast<int>(height()*1.4));
|
|
}
|
|
|
|
private:
|
|
void init()
|
|
{
|
|
setOpen(true);
|
|
}
|
|
};
|
|
|
|
class SeparatorItem: public KListViewItem{
|
|
public:
|
|
SeparatorItem(KListView *parent)
|
|
:KListViewItem(parent)
|
|
{
|
|
setSelectable(false);
|
|
}
|
|
};
|
|
PropertyEditor::PropertyEditor(QWidget *parent, const char *name)
|
|
:KListView(parent, name)
|
|
{
|
|
setSorting(-1);
|
|
|
|
addColumn(i18n("Name"));
|
|
addColumn(i18n("Value"));
|
|
setAllColumnsShowFocus(true);
|
|
setColumnWidthMode(0, QListView::Maximum);
|
|
setResizeMode(QListView::LastColumn);
|
|
|
|
header()->setClickEnabled(false);
|
|
|
|
connect(header(), SIGNAL(sizeChange(int, int, int)),
|
|
this, SLOT(updateEditorSize()));
|
|
connect(this, SIGNAL(currentChanged(QListViewItem*)),
|
|
this, SLOT(slotClicked(QListViewItem*)));
|
|
|
|
m_currentEditItem = 0;
|
|
m_doubleClickForEdit = true;
|
|
m_lastClickedItem = 0;
|
|
m_currentEditWidget = 0;
|
|
m_list = 0;
|
|
|
|
m_currentEditArea = new QWidget(viewport());
|
|
m_currentEditArea->hide();
|
|
m_undoButton = new QPushButton(m_currentEditArea);
|
|
#ifndef PURE_QT
|
|
m_undoButton->setPixmap(SmallIcon("undo"));
|
|
#else
|
|
m_undoButton->setPixmap( QPixmap("undo.xpm") );
|
|
#endif
|
|
m_undoButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
|
|
m_undoButton->resize(m_undoButton->height(), m_undoButton->height());
|
|
m_undoButton->hide();
|
|
connect(m_undoButton, SIGNAL(clicked()), this, SLOT(undo()));
|
|
m_currentEditLayout = new QGridLayout(m_currentEditArea, 1, 2, 0, 0);
|
|
// m_currentEditLayout->addWidget(m_undoButton, 0, 1);
|
|
}
|
|
|
|
PropertyEditor::~PropertyEditor()
|
|
{
|
|
clearMachineCache();
|
|
}
|
|
|
|
void PropertyEditor::populateProperties(PropertyList *list)
|
|
{
|
|
if (list == 0)
|
|
return;
|
|
m_list = list;
|
|
connect(m_list, SIGNAL(propertyValueChanged(Property*)), this, SLOT(propertyValueChanged(Property*)));
|
|
const QValueList<QPair<QString, QValueList<QString> > >& groups = m_list->propertiesOfGroup();
|
|
for (QValueList<QPair<QString, QValueList<QString> > >::const_iterator it = groups.begin();
|
|
it != groups.end(); ++it)
|
|
{
|
|
// qWarning("PropertyEditor::populateProperties: adding group %s", (*it).first.ascii());
|
|
PropertyGroupItem *group = 0;
|
|
if ( (!(*it).first.isEmpty()) && ((*it).second.count() > 0) )
|
|
group = new PropertyGroupItem(this, (*it).first);
|
|
const QValueList<QString> &properties = (*it).second;
|
|
for (QValueList<QString>::const_iterator it2 = properties.begin(); it2 != properties.end(); ++it2)
|
|
{
|
|
// qWarning("PropertyEditor::populateProperties: adding property %s", (*it2).ascii());
|
|
if (group)
|
|
addProperty(group, *it2);
|
|
else
|
|
addProperty(*it2);
|
|
}
|
|
}
|
|
if (firstChild())
|
|
{
|
|
setCurrentItem(firstChild());
|
|
setSelected(firstChild(), true);
|
|
slotClicked(firstChild());
|
|
}
|
|
}
|
|
|
|
void PropertyEditor::addProperty(PropertyGroupItem *group, const QString &name)
|
|
{
|
|
if ((*m_list)[name] == 0)
|
|
return;
|
|
// qWarning("%s = name : object null ", name.ascii());
|
|
PropertyItem *pitem = new PropertyItem(this, group, (*m_list)[name]);
|
|
addChildProperties(pitem);
|
|
}
|
|
|
|
void PropertyEditor::addProperty(const QString &name)
|
|
{
|
|
if ((*m_list)[name] == 0)
|
|
return;
|
|
// qWarning("%s = name : object null ", name.ascii());
|
|
PropertyItem *pitem = new PropertyItem(this, (*m_list)[name]);
|
|
addChildProperties(pitem);
|
|
}
|
|
|
|
void PropertyEditor::addChildProperties(PropertyItem *parent)
|
|
{
|
|
MultiProperty *prop = parent->property();
|
|
//force machine creation to get detailed properties appended to current multiproperty
|
|
if ( !m_registeredForType.contains(prop->name())
|
|
&& (PropertyMachineFactory::getInstance()->hasDetailedEditors(prop->type())) )
|
|
{
|
|
//FIXME: find better solution
|
|
machine(prop);
|
|
}
|
|
|
|
// qWarning("seeking children: count: %d", prop->details.count());
|
|
|
|
parent->setOpen(true);
|
|
for (QValueList<ChildProperty>::iterator it = prop->details.begin(); it != prop->details.end(); ++it)
|
|
{
|
|
// qWarning("found child %s", (*it).name().ascii());
|
|
new PropertyItem(this, parent, new MultiProperty(&m_detailedList, &(*it)));
|
|
}
|
|
}
|
|
|
|
void PropertyEditor::clearProperties()
|
|
{
|
|
m_detailedList.clear();
|
|
if (!m_list)
|
|
return;
|
|
|
|
hideEditor();
|
|
|
|
disconnect(m_list, SIGNAL(propertyValueChanged(Property*)), this, SLOT(propertyValueChanged(Property*)));
|
|
clear();
|
|
delete m_list;
|
|
m_list = 0;
|
|
}
|
|
|
|
void PropertyEditor::propertyValueChanged(Property *property)
|
|
{
|
|
// qWarning("PropertyEditor::propertyValueChanged");
|
|
if (m_currentEditWidget->propertyName() == property->name())
|
|
m_currentEditWidget->setValue(property->value(), false);
|
|
else
|
|
{
|
|
// repaint all items
|
|
QListViewItemIterator it(this);
|
|
while (it.current())
|
|
{
|
|
repaintItem(it.current());
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PropertyEditor::propertyChanged(MultiProperty *property, const QVariant &value)
|
|
{
|
|
if (!property)
|
|
return;
|
|
|
|
qWarning("editor: assign %s to %s", property->name().latin1(), value.toString().latin1());
|
|
property->setValue(value, false);
|
|
|
|
//highlight changed properties
|
|
if (m_currentEditItem && (m_currentEditItem->property() == property))
|
|
{
|
|
m_currentEditItem->setChanged(true);
|
|
repaintItem(m_currentEditItem);
|
|
}
|
|
|
|
emit changed();
|
|
|
|
/* if (m_list->contains(name))
|
|
{
|
|
(*m_list)[name]->setValue(value, false);
|
|
// else if (m_detailedList->contains(*/
|
|
}
|
|
|
|
void PropertyEditor::hideEditor()
|
|
{
|
|
m_lastClickedItem = 0;
|
|
m_currentEditItem = 0;
|
|
if (m_currentEditWidget)
|
|
{
|
|
m_currentEditLayout->remove(m_currentEditWidget);
|
|
m_currentEditWidget->hide();
|
|
}
|
|
m_currentEditLayout->remove(m_undoButton);
|
|
m_undoButton->hide();
|
|
m_currentEditArea->hide();
|
|
m_currentEditWidget = 0;
|
|
}
|
|
|
|
void PropertyEditor::showEditor(PropertyItem *item)
|
|
{
|
|
m_currentEditItem = item;
|
|
placeEditor(item);
|
|
m_currentEditWidget->show();
|
|
m_undoButton->show();
|
|
m_currentEditArea->show();
|
|
}
|
|
|
|
void PropertyEditor::placeEditor(PropertyItem *item)
|
|
{
|
|
QRect r = itemRect(item);
|
|
if (!r.size().isValid())
|
|
{
|
|
ensureItemVisible(item);
|
|
r = itemRect(item);
|
|
}
|
|
|
|
r.setX(header()->sectionPos(1));
|
|
r.setWidth(header()->sectionSize(1));
|
|
|
|
// check if the column is fully visible
|
|
if (visibleWidth() < r.right())
|
|
r.setRight(visibleWidth());
|
|
|
|
r = QRect(viewportToContents(r.topLeft()), r.size());
|
|
|
|
if (item->pixmap(1))
|
|
{
|
|
r.setX(r.x() + item->pixmap(1)->width());
|
|
}
|
|
|
|
if (PropertyWidget* editor = prepareEditor(item))
|
|
{
|
|
m_currentEditLayout->addWidget(editor, 0, 0);
|
|
m_currentEditLayout->addWidget(m_undoButton, 0, 1);
|
|
m_currentEditArea->resize(r.size());
|
|
// m_currentEditLayout->invalidate();
|
|
moveChild(m_currentEditArea, r.x(), r.y());
|
|
m_currentEditWidget = editor;
|
|
}
|
|
}
|
|
|
|
PropertyWidget* PropertyEditor::prepareEditor(PropertyItem *item)
|
|
{
|
|
PropertyWidget *editorWidget = 0;
|
|
/* if (item->depth() >= 2)
|
|
{
|
|
editorWidget = machine(item->name())->propertyEditor;
|
|
editorWidget->setValue(m_accessor->value(item->name()), false);
|
|
}
|
|
else
|
|
{*/
|
|
editorWidget = machine(item->property())->propertyEditor;
|
|
editorWidget->setProperty(item->property());
|
|
if (item->property()->type() == Property::ValueFromList)
|
|
editorWidget->setValueList(item->property()->valueList());
|
|
editorWidget->setValue(item->property()->value(), false);
|
|
//}
|
|
return editorWidget;
|
|
}
|
|
|
|
void PropertyEditor::updateEditorSize()
|
|
{
|
|
if (m_currentEditItem)
|
|
placeEditor(m_currentEditItem);
|
|
}
|
|
|
|
void PropertyEditor::slotClicked(QListViewItem *item)
|
|
{
|
|
if (item == 0)
|
|
{
|
|
hideEditor();
|
|
return;
|
|
}
|
|
if (item != m_lastClickedItem)
|
|
{
|
|
hideEditor();
|
|
PropertyItem *it = dynamic_cast<PropertyItem*>(item);
|
|
if (it)
|
|
{
|
|
showEditor(it);
|
|
}
|
|
}
|
|
|
|
m_lastClickedItem = item;
|
|
}
|
|
|
|
Machine *PropertyEditor::machine(MultiProperty *property)
|
|
{
|
|
// int type = property->type();
|
|
QString name = property->name();
|
|
QMap<QString, QVariant> values = property->valueList();
|
|
if (m_registeredForType[name] == 0)
|
|
{
|
|
m_registeredForType[name] = PropertyMachineFactory::getInstance()->machineForProperty(property);
|
|
connect(m_registeredForType[name]->propertyEditor, SIGNAL(propertyChanged(MultiProperty*, const QVariant&)),
|
|
this, SLOT(propertyChanged(MultiProperty*, const QVariant&)));
|
|
m_registeredForType[name]->propertyEditor->reparent(m_currentEditArea, 0, m_currentEditArea->childrenRect().topLeft());
|
|
m_registeredForType[name]->propertyEditor->hide();
|
|
}
|
|
return m_registeredForType[name];
|
|
}
|
|
|
|
void PropertyEditor::clearMachineCache()
|
|
{
|
|
for (QMap<QString, Machine* >::iterator it = m_registeredForType.begin(); it != m_registeredForType.end(); ++it)
|
|
{
|
|
delete it.data();
|
|
}
|
|
m_registeredForType.clear();
|
|
}
|
|
|
|
void PropertyEditor::undo()
|
|
{
|
|
if ((m_currentEditItem == 0) || (m_currentEditWidget == 0)
|
|
|| (!m_currentEditWidget->isVisible()))
|
|
return;
|
|
|
|
m_currentEditWidget->undo();
|
|
m_currentEditItem->setChanged(false);
|
|
repaintItem(m_currentEditItem);
|
|
}
|
|
|
|
}
|
|
|
|
#ifndef PURE_QT
|
|
#include "propertyeditor.moc"
|
|
#endif
|