KDevelop API Documentation

propertyeditor.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2002-2004 by Alexander Dymo                             *
00003  *   cloudtemple@mskat.net                                                 *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU Library General Public License as       *
00007  *   published by the Free Software Foundation; either version 2 of the    *
00008  *   License, or (at your option) any later version.                       *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU Library General Public     *
00016  *   License along with this program; if not, write to the                 *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 #include "propertyeditor.h"
00021 
00022 #ifndef PURE_QT
00023 #include <klocale.h>
00024 #include <kdebug.h>
00025 #include <kiconloader.h>
00026 #else
00027 #include "compat_tools.h"
00028 #endif
00029 
00030 #include <qtable.h>
00031 #include <qlayout.h>
00032 #include <qpainter.h>
00033 #include <qptrlist.h>
00034 #include <qvaluelist.h>
00035 #include <qpushbutton.h>
00036 
00037 #include "property.h"
00038 #include "multiproperty.h"
00039 #include "propertymachinefactory.h"
00040 
00041 namespace PropertyLib{
00042 
00043 class PropertyItem: public KListViewItem{
00044 public:
00045     PropertyItem(PropertyEditor *parent, MultiProperty *property)
00046         :KListViewItem(parent, property->description()), m_editor(parent), m_property(property),
00047         m_changed(false)
00048     {
00049     }
00050     
00051     PropertyItem(PropertyEditor *editor, KListViewItem *parent, MultiProperty *property)
00052         :KListViewItem(parent, property->description()), m_editor(editor),
00053         m_property(property), m_changed(false)
00054     {
00055     }
00056     
00057 /*    int type() const
00058     {
00059         return m_property->type();
00060     }
00061     
00062     QString name() const
00063     {
00064         return m_property->name();
00065     }
00066         */
00067     MultiProperty *property() const
00068     {
00069         return m_property;
00070     }
00071     
00072     virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align)
00073     {
00074         if ((column == 0) && m_changed)
00075         {
00076             QFont font;
00077             font.setBold(true);
00078             p->setFont(font);
00079             p->setBrush(cg.highlight());
00080             p->setPen(cg.highlightedText());
00081         }
00082         if (column == 1)
00083         {
00084             QRect r(0, 0, m_editor->header()->sectionSize(1), height());
00085             //FIXME: this is ugly, but how else can we deal with ValueFromList properties?
00086             QVariant valueToDraw;
00087             if (m_property->type() == Property::ValueFromList)
00088                 valueToDraw = m_property->findValueDescription();
00089             else
00090                 valueToDraw = m_property->value();
00091             QColorGroup icg(cg);
00092             icg.setColor(QColorGroup::Background, backgroundColor());
00093             m_editor->machine(m_property)->propertyEditor->drawViewer(p, icg, r, valueToDraw);
00094             return;
00095         }
00096         KListViewItem::paintCell(p, cg, column, width, align);
00097     }
00098     
00099     virtual void setup()
00100     {
00101         KListViewItem::setup();
00102         setHeight(static_cast<int>(height()*1.5));
00103     }
00104     
00105     void setChanged(bool changed)
00106     {
00107         m_changed = changed;
00108     }
00109 
00110 private:
00111     PropertyEditor *m_editor;
00112     MultiProperty *m_property;
00113     bool m_changed;
00114 };
00115 
00116 
00117 class PropertyGroupItem: public KListViewItem{
00118 public:
00119     PropertyGroupItem(KListView *parent, const QString &name)
00120         :KListViewItem(parent, name)
00121     {
00122         init();
00123     }
00124     PropertyGroupItem(KListViewItem *parent, const QString &name)
00125         :KListViewItem(parent, name)
00126     {
00127         init();
00128     }
00129         
00130     virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align)
00131     {
00132         if (column == 0)
00133         {
00134             QFont font;
00135             font.setBold(true);
00136             p->setFont(font);
00137             p->setBrush(cg.highlight());
00138             p->setPen(cg.highlightedText());
00139         }
00140         KListViewItem::paintCell(p, cg, column, width, align);
00141     }
00142     virtual void setup()
00143     {
00144         KListViewItem::setup();
00145         setHeight(static_cast<int>(height()*1.4));
00146     }
00147 
00148 private:
00149     void init()
00150     {
00151         setOpen(true);
00152     }
00153 };
00154 
00155 class SeparatorItem: public KListViewItem{
00156 public:
00157     SeparatorItem(KListView *parent)
00158         :KListViewItem(parent)
00159     {
00160         setSelectable(false);
00161     }
00162 };
00163 
00164 PropertyEditor::PropertyEditor(QWidget *parent, const char *name)
00165     :KListView(parent, name)
00166 {
00167     setSorting(-1);
00168     
00169     addColumn(i18n("Name"));
00170     addColumn(i18n("Value"));
00171     setAllColumnsShowFocus(true);
00172     setColumnWidthMode(0, QListView::Maximum);
00173     setResizeMode(QListView::LastColumn);
00174 
00175     header()->setClickEnabled(false);
00176 
00177     connect(header(), SIGNAL(sizeChange(int, int, int)),
00178         this, SLOT(updateEditorSize()));
00179     connect(this, SIGNAL(currentChanged(QListViewItem*)),
00180         this, SLOT(slotClicked(QListViewItem*)));
00181 
00182     m_currentEditItem = 0;
00183     m_doubleClickForEdit = true;
00184     m_lastClickedItem = 0;    
00185     m_currentEditWidget = 0;
00186     m_list = 0;
00187     
00188     m_currentEditArea = new QWidget(viewport());
00189     m_currentEditArea->hide();
00190     m_undoButton = new QPushButton(m_currentEditArea);
00191     m_undoButton->setPixmap(SmallIcon("undo"));
00192     m_undoButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
00193     m_undoButton->resize(m_undoButton->height(), m_undoButton->height());
00194     m_undoButton->hide();
00195     connect(m_undoButton, SIGNAL(clicked()), this, SLOT(undo()));
00196     m_currentEditLayout = new QGridLayout(m_currentEditArea, 1, 2, 0, 0);
00197 //    m_currentEditLayout->addWidget(m_undoButton, 0, 1);
00198 }
00199 
00200 PropertyEditor::~PropertyEditor()
00201 {
00202     clearMachineCache();
00203 }
00204 
00205 void PropertyEditor::populateProperties(PropertyList *list)
00206 {
00207     if (list == 0)
00208         return;
00209     m_list = list;
00210     connect(m_list, SIGNAL(propertyValueChanged(Property*)), this, SLOT(propertyValueChanged(Property*)));
00211     const QValueList<QPair<QString, QValueList<QString> > >& groups = m_list->propertiesOfGroup();
00212     for (QValueList<QPair<QString, QValueList<QString> > >::const_iterator it = groups.begin();
00213         it != groups.end(); ++it)
00214     {
00215 //        qWarning("PropertyEditor::populateProperties:    adding group %s", (*it).first.ascii());
00216         PropertyGroupItem *group = 0;
00217         if ( (!(*it).first.isEmpty()) && ((*it).second.count() > 0) )
00218             group = new PropertyGroupItem(this, (*it).first);
00219         const QValueList<QString> &properties = (*it).second;
00220         for (QValueList<QString>::const_iterator it2 = properties.begin(); it2 != properties.end(); ++it2)
00221         {
00222 //            qWarning("PropertyEditor::populateProperties:    adding property %s", (*it2).ascii());
00223             if (group)
00224                 addProperty(group, *it2);
00225             else
00226                 addProperty(*it2);
00227         }
00228     }
00229     if (firstChild())
00230     {
00231         setCurrentItem(firstChild());
00232         setSelected(firstChild(), true);
00233         slotClicked(firstChild());
00234     }
00235 }
00236 
00237 void PropertyEditor::addProperty(PropertyGroupItem *group, const QString &name)
00238 {
00239     if ((*m_list)[name] == 0)
00240         return;
00241 //        qWarning("%s = name : object null ", name.ascii());
00242     PropertyItem *pitem = new PropertyItem(this, group, (*m_list)[name]);
00243     addChildProperties(pitem);
00244 }
00245 
00246 void PropertyEditor::addProperty(const QString &name)
00247 {
00248     if ((*m_list)[name] == 0)
00249         return;
00250 //        qWarning("%s = name : object null ", name.ascii());
00251     PropertyItem *pitem = new PropertyItem(this, (*m_list)[name]);
00252     addChildProperties(pitem);
00253 }
00254 
00255 void PropertyEditor::addChildProperties(PropertyItem *parent)
00256 {
00257     MultiProperty *prop = parent->property();
00258     //force machine creation to get detailed properties appended to current multiproperty
00259     if ( !m_registeredForType.contains(prop->type())
00260         && (PropertyMachineFactory::getInstance()->hasDetailedEditors(prop->type())) )
00261     {
00262         //FIXME: find better solution
00263         machine(prop);
00264     }
00265         
00266     qWarning("seeking children: count: %d", prop->details.count());
00267 
00268     parent->setOpen(true);
00269     for (QValueList<ChildProperty>::iterator it = prop->details.begin(); it != prop->details.end(); ++it)
00270     {
00271         qWarning("found child %s", (*it).name().ascii());
00272         new PropertyItem(this, parent, new MultiProperty(&m_detailedList, &(*it)));
00273     }
00274 }
00275 
00276 void PropertyEditor::clearProperties()
00277 {
00278     m_detailedList.clear();
00279     if (!m_list)
00280         return;
00281     
00282     hideEditor();
00283     
00284     disconnect(m_list, SIGNAL(propertyValueChanged(Property*)), this, SLOT(propertyValueChanged(Property*)));
00285     clear();
00286     delete m_list;
00287     m_list = 0;
00288 }
00289 
00290 void PropertyEditor::propertyValueChanged(Property *property)
00291 {
00292     if (m_currentEditWidget->propertyName() == property->name())
00293         m_currentEditWidget->setValue(property->value(), false);
00294     else
00295     {
00296         //repaint all items
00297         QListViewItemIterator it(this);
00298         while (it.current())
00299         {
00300             repaintItem(it.current());
00301             ++it;
00302         }        
00303     }
00304 }
00305 
00306 void PropertyEditor::propertyChanged(MultiProperty *property, const QVariant &value)
00307 {
00308     if (!property)
00309         return;
00310     
00311     kdDebug() << "editor: assign " << property->name().latin1() << " to " << value.toString().latin1() << endl;
00312     property->setValue(value, false);
00313     
00314     //highlight changed properties
00315     if (m_currentEditItem && (m_currentEditItem->property() == property))
00316     {
00317         m_currentEditItem->setChanged(true);
00318         repaintItem(m_currentEditItem);
00319     }
00320     
00321 /*    if (m_list->contains(name))
00322     {
00323         (*m_list)[name]->setValue(value, false);
00324 //    else if (m_detailedList->contains(*/
00325 }
00326 
00327 void PropertyEditor::hideEditor()
00328 {
00329     m_lastClickedItem = 0;
00330     m_currentEditItem = 0;
00331     if (m_currentEditWidget)
00332     {
00333         m_currentEditLayout->remove(m_currentEditWidget);
00334         m_currentEditWidget->hide();
00335     }
00336     m_currentEditLayout->remove(m_undoButton);
00337     m_undoButton->hide();
00338     m_currentEditArea->hide();
00339     m_currentEditWidget = 0;
00340 }
00341 
00342 void PropertyEditor::showEditor(PropertyItem *item)
00343 {
00344     m_currentEditItem = item;
00345     placeEditor(item);
00346     m_currentEditWidget->show();
00347     m_undoButton->show();
00348     m_currentEditArea->show();
00349 }
00350 
00351 void PropertyEditor::placeEditor(PropertyItem *item)
00352 {
00353     QRect r = itemRect(item);
00354     if (!r.size().isValid())
00355     {
00356         ensureItemVisible(item);
00357         r = itemRect(item);
00358     }
00359 
00360     r.setX(header()->sectionPos(1));
00361     r.setWidth(header()->sectionSize(1));
00362 
00363     // check if the column is fully visible
00364     if (visibleWidth() < r.right())
00365         r.setRight(visibleWidth());
00366 
00367     r = QRect(viewportToContents(r.topLeft()), r.size());
00368 
00369     if (item->pixmap(1))
00370     {
00371         r.setX(r.x() + item->pixmap(1)->width());
00372     }
00373 
00374     if (PropertyWidget* editor = prepareEditor(item))
00375     {
00376         m_currentEditLayout->addWidget(editor, 0, 0);
00377         m_currentEditLayout->addWidget(m_undoButton, 0, 1);
00378         m_currentEditArea->resize(r.size());
00379 //        m_currentEditLayout->invalidate();
00380         moveChild(m_currentEditArea, r.x(), r.y());
00381         m_currentEditWidget = editor;
00382     }
00383 }
00384 
00385 PropertyWidget* PropertyEditor::prepareEditor(PropertyItem *item)
00386 {
00387     PropertyWidget *editorWidget = 0;
00388 /*    if (item->depth() >= 2)
00389     {
00390         editorWidget = machine(item->name())->propertyEditor;    
00391         editorWidget->setValue(m_accessor->value(item->name()), false);
00392     }
00393     else
00394     {*/
00395     editorWidget = machine(item->property())->propertyEditor;
00396     editorWidget->setProperty(item->property());
00397     if (item->property()->type() == Property::ValueFromList)
00398         editorWidget->setValueList(item->property()->valueList());
00399     editorWidget->setValue(item->property()->value(), false);
00400     //}
00401     return editorWidget;
00402 }
00403 
00404 void PropertyEditor::updateEditorSize()
00405 {
00406     if (m_currentEditItem)
00407         placeEditor(m_currentEditItem);
00408 }
00409 
00410 void PropertyEditor::slotClicked(QListViewItem *item)
00411 {
00412     if (item == 0)
00413     {
00414         hideEditor();
00415         return;
00416     }
00417     if (item != m_lastClickedItem)
00418     {
00419         hideEditor();
00420         PropertyItem *it = dynamic_cast<PropertyItem*>(item);
00421         if (it)
00422         {
00423             showEditor(it);
00424         }
00425     }
00426 
00427     m_lastClickedItem = item;
00428 }
00429 
00430 Machine *PropertyEditor::machine(MultiProperty *property)
00431 {
00432     int type = property->type();
00433     QString name = property->name();
00434     QMap<QString, QVariant> values = property->valueList();
00435     if (m_registeredForType[type] == 0)
00436     {
00437         m_registeredForType[type] = PropertyMachineFactory::getInstance()->machineForProperty(property);
00438         connect(m_registeredForType[type]->propertyEditor, SIGNAL(propertyChanged(MultiProperty*, const QVariant&)),
00439             this, SLOT(propertyChanged(MultiProperty*, const QVariant&)));
00440         m_registeredForType[type]->propertyEditor->reparent(m_currentEditArea, 0, m_currentEditArea->childrenRect().topLeft());
00441         m_registeredForType[type]->propertyEditor->hide();
00442     }
00443     return m_registeredForType[type];
00444 }
00445 
00446 void PropertyEditor::clearMachineCache()
00447 {
00448     for (QMap<int, Machine* >::iterator it = m_registeredForType.begin(); it != m_registeredForType.end(); ++it)
00449     {
00450         delete it.data();
00451     }
00452     m_registeredForType.clear();
00453 }
00454 
00455 void PropertyEditor::undo()
00456 {
00457     if ((m_currentEditItem == 0) || (m_currentEditWidget == 0) 
00458         || (!m_currentEditWidget->isVisible()))
00459         return;
00460     
00461     m_currentEditWidget->undo();
00462     m_currentEditItem->setChanged(false);
00463     repaintItem(m_currentEditItem);
00464 }
00465 
00466 }
00467 
00468 #include "propertyeditor.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:37 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003