diff options
Diffstat (limited to 'lib/widgets/propeditor/propertyeditor.cpp')
-rw-r--r-- | lib/widgets/propeditor/propertyeditor.cpp | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/lib/widgets/propeditor/propertyeditor.cpp b/lib/widgets/propeditor/propertyeditor.cpp new file mode 100644 index 00000000..58c2b936 --- /dev/null +++ b/lib/widgets/propeditor/propertyeditor.cpp @@ -0,0 +1,480 @@ +/*************************************************************************** + * 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., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 |