|
|
|
/***************************************************************************
|
|
|
|
* 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 <tqtable.h>
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqptrlist.h>
|
|
|
|
#include <tqvaluelist.h>
|
|
|
|
#include <tqpushbutton.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();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString name() const
|
|
|
|
{
|
|
|
|
return m_property->name();
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
MultiProperty *property() const
|
|
|
|
{
|
|
|
|
return m_property;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int align)
|
|
|
|
{
|
|
|
|
if ((column == 0) && m_changed)
|
|
|
|
{
|
|
|
|
TQFont font;
|
|
|
|
font.setBold(true);
|
|
|
|
p->setFont(font);
|
|
|
|
p->setBrush(cg.highlight());
|
|
|
|
p->setPen(cg.highlightedText());
|
|
|
|
}
|
|
|
|
if (column == 1)
|
|
|
|
{
|
|
|
|
TQRect r(0, 0, m_editor->header()->sectionSize(1), height());
|
|
|
|
//FIXME: this is ugly, but how else can we deal with ValueFromList properties?
|
|
|
|
TQVariant valueToDraw;
|
|
|
|
if (m_property->type() == Property::ValueFromList)
|
|
|
|
valueToDraw = m_property->findValueDescription();
|
|
|
|
else
|
|
|
|
valueToDraw = m_property->value();
|
|
|
|
TQColorGroup icg(cg);
|
|
|
|
#ifndef PURE_QT
|
|
|
|
icg.setColor(TQColorGroup::Background, backgroundColor(column));
|
|
|
|
#else
|
|
|
|
icg.setColor(TQColorGroup::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 TQString &name)
|
|
|
|
:KListViewItem(parent, name)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
PropertyGroupItem(KListViewItem *parent, const TQString &name)
|
|
|
|
:KListViewItem(parent, name)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int align)
|
|
|
|
{
|
|
|
|
if (column == 0)
|
|
|
|
{
|
|
|
|
TQFont 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(TQWidget *parent, const char *name)
|
|
|
|
:KListView(parent, name)
|
|
|
|
{
|
|
|
|
setSorting(-1);
|
|
|
|
|
|
|
|
addColumn(i18n("Name"));
|
|
|
|
addColumn(i18n("Value"));
|
|
|
|
setAllColumnsShowFocus(true);
|
|
|
|
setColumnWidthMode(0, TQListView::Maximum);
|
|
|
|
setResizeMode(TQListView::LastColumn);
|
|
|
|
|
|
|
|
header()->setClickEnabled(false);
|
|
|
|
|
|
|
|
connect(header(), TQT_SIGNAL(sizeChange(int, int, int)),
|
|
|
|
this, TQT_SLOT(updateEditorSize()));
|
|
|
|
connect(this, TQT_SIGNAL(currentChanged(TQListViewItem*)),
|
|
|
|
this, TQT_SLOT(slotClicked(TQListViewItem*)));
|
|
|
|
|
|
|
|
m_currentEditItem = 0;
|
|
|
|
m_doubleClickForEdit = true;
|
|
|
|
m_lastClickedItem = 0;
|
|
|
|
m_currentEditWidget = 0;
|
|
|
|
m_list = 0;
|
|
|
|
|
|
|
|
m_currentEditArea = new TQWidget(viewport());
|
|
|
|
m_currentEditArea->hide();
|
|
|
|
m_undoButton = new TQPushButton(m_currentEditArea);
|
|
|
|
#ifndef PURE_QT
|
|
|
|
m_undoButton->setPixmap(SmallIcon("undo"));
|
|
|
|
#else
|
|
|
|
m_undoButton->setPixmap( TQPixmap("undo.xpm") );
|
|
|
|
#endif
|
|
|
|
m_undoButton->setSizePolicy(TQSizePolicy::Maximum, TQSizePolicy::MinimumExpanding);
|
|
|
|
m_undoButton->resize(m_undoButton->height(), m_undoButton->height());
|
|
|
|
m_undoButton->hide();
|
|
|
|
connect(m_undoButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(undo()));
|
|
|
|
m_currentEditLayout = new TQGridLayout(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, TQT_SIGNAL(propertyValueChanged(Property*)), this, TQT_SLOT(propertyValueChanged(Property*)));
|
|
|
|
const TQValueList<TQPair<TQString, TQValueList<TQString> > >& groups = m_list->propertiesOfGroup();
|
|
|
|
for (TQValueList<TQPair<TQString, TQValueList<TQString> > >::const_iterator it = groups.begin();
|
|
|
|
it != groups.end(); ++it)
|
|
|
|
{
|
|
|
|
// tqWarning("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 TQValueList<TQString> &properties = (*it).second;
|
|
|
|
for (TQValueList<TQString>::const_iterator it2 = properties.begin(); it2 != properties.end(); ++it2)
|
|
|
|
{
|
|
|
|
// tqWarning("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 TQString &name)
|
|
|
|
{
|
|
|
|
if ((*m_list)[name] == 0)
|
|
|
|
return;
|
|
|
|
// tqWarning("%s = name : object null ", name.ascii());
|
|
|
|
PropertyItem *pitem = new PropertyItem(this, group, (*m_list)[name]);
|
|
|
|
addChildProperties(pitem);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PropertyEditor::addProperty(const TQString &name)
|
|
|
|
{
|
|
|
|
if ((*m_list)[name] == 0)
|
|
|
|
return;
|
|
|
|
// tqWarning("%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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// tqWarning("seeking children: count: %d", prop->details.count());
|
|
|
|
|
|
|
|
parent->setOpen(true);
|
|
|
|
for (TQValueList<ChildProperty>::iterator it = prop->details.begin(); it != prop->details.end(); ++it)
|
|
|
|
{
|
|
|
|
// tqWarning("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, TQT_SIGNAL(propertyValueChanged(Property*)), this, TQT_SLOT(propertyValueChanged(Property*)));
|
|
|
|
clear();
|
|
|
|
delete m_list;
|
|
|
|
m_list = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PropertyEditor::propertyValueChanged(Property *property)
|
|
|
|
{
|
|
|
|
// tqWarning("PropertyEditor::propertyValueChanged");
|
|
|
|
if (m_currentEditWidget->propertyName() == property->name())
|
|
|
|
m_currentEditWidget->setValue(property->value(), false);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// repaint all items
|
|
|
|
TQListViewItemIterator it(this);
|
|
|
|
while (it.current())
|
|
|
|
{
|
|
|
|
repaintItem(it.current());
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PropertyEditor::propertyChanged(MultiProperty *property, const TQVariant &value)
|
|
|
|
{
|
|
|
|
if (!property)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tqWarning("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)
|
|
|
|
{
|
|
|
|
TQRect 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 = TQRect(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(TQListViewItem *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();
|
|
|
|
TQString name = property->name();
|
|
|
|
TQMap<TQString, TQVariant> values = property->valueList();
|
|
|
|
if (m_registeredForType[name] == 0)
|
|
|
|
{
|
|
|
|
m_registeredForType[name] = PropertyMachineFactory::getInstance()->machineForProperty(property);
|
|
|
|
connect(m_registeredForType[name]->propertyEditor, TQT_SIGNAL(propertyChanged(MultiProperty*, const TQVariant&)),
|
|
|
|
this, TQT_SLOT(propertyChanged(MultiProperty*, const TQVariant&)));
|
|
|
|
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 (TQMap<TQString, 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
|