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.
tdevelop/lib/widgets/propeditor/propertyeditor.cpp

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