00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00058
00059
00060
00061
00062
00063
00064
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
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
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
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
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
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
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
00259 if ( !m_registeredForType.contains(prop->type())
00260 && (PropertyMachineFactory::getInstance()->hasDetailedEditors(prop->type())) )
00261 {
00262
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
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
00315 if (m_currentEditItem && (m_currentEditItem->property() == property))
00316 {
00317 m_currentEditItem->setChanged(true);
00318 repaintItem(m_currentEditItem);
00319 }
00320
00321
00322
00323
00324
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
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
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
00389
00390
00391
00392
00393
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"