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 | 
