File indexing completed on 2024-12-08 07:18:48
0001 /* This file is part of the KDE project 0002 Copyright (C) 2008-2018 Jarosław Staniek <staniek@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KPropertyEditorView.h" 0021 #include "KPropertyEditorDataModel_p.h" 0022 #include "KProperty.h" 0023 #include "KPropertySet.h" 0024 #include "KPropertyWidgetsFactory.h" 0025 #include "KPropertyWidgetsPluginManager.h" 0026 #include "kproperty_debug.h" 0027 #include "KPropertyUtils.h" 0028 #include "KPropertyUtils_p.h" 0029 0030 #include <QIcon> 0031 #include <QPointer> 0032 #include <QItemDelegate> 0033 #include <QPainter> 0034 #include <QMouseEvent> 0035 #include <QToolTip> 0036 #include <QApplication> 0037 #include <QHeaderView> 0038 #include <QLineEdit> 0039 0040 #if 0 // not sure if we should use it, better to fix Oxygen? 0041 #include <kexiutils/styleproxy.h> 0042 0043 //! Used to alter the widget's style at design time 0044 class EditorViewStyle : public KexiUtils::StyleProxy 0045 { 0046 public: 0047 explicit EditorViewStyle(QStyle* parentStyle) : KexiUtils::StyleProxy(parentStyle) 0048 { 0049 } 0050 0051 virtual void drawPrimitive(PrimitiveElement elem, const QStyleOption* option, 0052 QPainter* painter, const QWidget* widget) const 0053 { 0054 /* if (elem == PE_PanelLineEdit) { 0055 const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame*>(option); 0056 if (panel) { 0057 QStyleOptionFrame alteredOption(*panel); 0058 alteredOption.lineWidth = 0; 0059 KexiUtils::StyleProxy::drawPrimitive(elem, &alteredOption, 0060 painter, widget); 0061 return; 0062 } 0063 }*/ 0064 KexiUtils::StyleProxy::drawPrimitive(elem, option, 0065 painter, widget); 0066 } 0067 }; 0068 #endif 0069 0070 static bool effectiveValueSyncPolicy(const KProperty *property, bool defaultValue) 0071 { 0072 if (property->valueSyncPolicy() == KProperty::ValueSyncPolicy::Editor) { 0073 return defaultValue; 0074 } 0075 return property->valueSyncPolicy() == KProperty::ValueSyncPolicy::Auto; 0076 } 0077 0078 //---------- 0079 0080 class ItemDelegate : public QItemDelegate 0081 { 0082 public: 0083 explicit ItemDelegate(KPropertyEditorView *parent); 0084 ~ItemDelegate() override; 0085 void paint(QPainter *painter, 0086 const QStyleOptionViewItem &option, const QModelIndex &index) const override; 0087 QSize sizeHint(const QStyleOptionViewItem &option, 0088 const QModelIndex &index) const override; 0089 QWidget * createEditor(QWidget *parent, 0090 const QStyleOptionViewItem &option, const QModelIndex &index) const override; 0091 mutable QPointer<QWidget> m_currentEditor; 0092 }; 0093 0094 ItemDelegate::ItemDelegate(KPropertyEditorView *parent) 0095 : QItemDelegate(parent) 0096 { 0097 } 0098 0099 ItemDelegate::~ItemDelegate() 0100 { 0101 } 0102 0103 static int getIconSize(int fontPixelSize) 0104 { 0105 return fontPixelSize * 0.85; 0106 } 0107 0108 static int typeForProperty(const KProperty* prop) 0109 { 0110 if (prop->listData()) 0111 return KProperty::ValueFromList; 0112 else 0113 return prop->type(); 0114 } 0115 0116 void ItemDelegate::paint(QPainter *painter, 0117 const QStyleOptionViewItem &option, 0118 const QModelIndex &index) const 0119 { 0120 QStyleOptionViewItem alteredOption(option); 0121 const KPropertyUtilsPrivate::PainterSaver saver(painter); 0122 const KPropertyEditorDataModel *editorModel = qobject_cast<const KPropertyEditorDataModel*>(index.model()); 0123 if (!editorModel) { 0124 return; 0125 } 0126 0127 QRect r(option.rect); 0128 bool modified = false; 0129 const QColor gridLineColor(qobject_cast<KPropertyEditorView*>(parent())->gridLineColor()); 0130 if (gridLineColor.isValid()) { 0131 alteredOption.rect.setTop(alteredOption.rect.top() + 1); 0132 } 0133 if (index.column()==0) { 0134 r.setWidth(r.width() - 1); 0135 r.setLeft(-1); // to avoid displaying double left border 0136 0137 QVariant modifiedVariant( editorModel->data(index, KPropertyEditorDataModel::PropertyModifiedRole) ); 0138 if (modifiedVariant.isValid() && modifiedVariant.toBool()) { 0139 modified = true; 0140 QFont font(alteredOption.font); 0141 font.setBold(true); 0142 alteredOption.font = font; 0143 } 0144 } 0145 else { 0146 r.setLeft(r.left()-1); 0147 } 0148 const int x2 = alteredOption.rect.right(); 0149 const int y2 = alteredOption.rect.bottom(); 0150 const int iconSize = getIconSize( alteredOption.font.pixelSize() ); 0151 if (modified) { 0152 alteredOption.rect.setRight( alteredOption.rect.right() - iconSize * 1 ); 0153 } 0154 0155 const bool isGroupHeader(editorModel->data(index, KPropertyEditorDataModel::PropertyGroupRole).toBool()); 0156 if (!isGroupHeader) { 0157 KProperty *property = editorModel->propertyForIndex(index); 0158 const int t = typeForProperty( property ); 0159 bool useQItemDelegatePaint = true; // ValueDisplayInterface is used by default 0160 if (index.column() == 1 && KPropertyWidgetsPluginManager::self()->paint(t, painter, alteredOption, index)) { 0161 useQItemDelegatePaint = false; 0162 } 0163 if (useQItemDelegatePaint) { 0164 QItemDelegate::paint(painter, alteredOption, index); 0165 } 0166 0167 if (modified) { 0168 alteredOption.rect.setRight( alteredOption.rect.right() - iconSize * 3 / 2 ); 0169 int y1 = alteredOption.rect.top(); 0170 QLinearGradient grad(x2 - iconSize * 2, y1, x2 - iconSize / 2, y1); 0171 QColor color( 0172 alteredOption.palette.color( 0173 (alteredOption.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Base )); 0174 color.setAlpha(0); 0175 grad.setColorAt(0.0, color); 0176 color.setAlpha(255); 0177 grad.setColorAt(0.5, color); 0178 QBrush gradBrush(grad); 0179 painter->fillRect(x2 - iconSize * 2, y1, iconSize * 2, y2 - y1 + 1, gradBrush); 0180 0181 //!TODO 0182 //QPixmap revertIcon(QIcon::fromTheme(QLatin1String("edit-undo")).pixmap(iconSize, iconSize)); 0183 //revertIcon = KIconEffect().apply(revertIcon, KIconEffect::Colorize, 1.0, 0184 // alteredOption.palette.color( 0185 // (alteredOption.state & QStyle::State_Selected) ? QPalette::HighlightedText : QPalette::Text ), false); 0186 //painter->drawPixmap( x2 - iconSize - 2, 0187 // y1 + 1 + (alteredOption.rect.height() - revertIcon.height()) / 2, revertIcon); 0188 } 0189 } 0190 0191 if (gridLineColor.isValid()) { 0192 QPen pen(gridLineColor); 0193 painter->setPen(pen); 0194 painter->drawLine(r.topLeft(), r.topRight() + QPoint(1, 0)); 0195 painter->drawLine(r.bottomLeft() + QPoint(0, 1), r.bottomRight() + QPoint(1, 1)); 0196 if (!isGroupHeader) { 0197 painter->drawLine(r.topRight() + QPoint(1, 0), r.bottomRight() + QPoint(1, 1)); 0198 painter->drawLine(r.topLeft(), r.bottomLeft() + QPoint(0, 1)); 0199 } 0200 } 0201 else { 0202 QPen pen(alteredOption.palette.color(QPalette::AlternateBase)); 0203 painter->setPen(pen); 0204 painter->drawLine(r.topLeft(), r.topRight()); 0205 } 0206 //kprDebug()<<"rect:" << r << "viewport:" << painter->viewport() << "window:"<<painter->window(); 0207 } 0208 0209 QSize ItemDelegate::sizeHint(const QStyleOptionViewItem &option, 0210 const QModelIndex &index) const 0211 { 0212 QStyleOptionViewItem realOption(option); 0213 if (index.column() == 0) { 0214 // Measure for bold font because it might be used at any time if the property value is modified 0215 realOption.font.setBold(true); 0216 } 0217 return QItemDelegate::sizeHint(realOption, index) + QSize(0, 2); 0218 } 0219 0220 QWidget * ItemDelegate::createEditor(QWidget * parent, 0221 const QStyleOptionViewItem & option, const QModelIndex & index ) const 0222 { 0223 if (!index.isValid()) 0224 return nullptr; 0225 const KProperty *property = KPropertyUtils::propertyForIndex(index); 0226 if (property && property->isReadOnly()) { 0227 return nullptr; 0228 } 0229 const int t = property ? typeForProperty(property) : KProperty::String; 0230 QStyleOptionViewItem alteredOption(option); 0231 alteredOption.rect.setHeight(alteredOption.rect.height()+3); 0232 QWidget *w = KPropertyWidgetsPluginManager::self()->createEditor(t, parent, alteredOption, index); 0233 if (!w) { 0234 // fall back to String type 0235 w = KPropertyWidgetsPluginManager::self()->createEditor(KProperty::String, parent, alteredOption, index); 0236 } 0237 if (w) { 0238 if (-1 != w->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("commitData(QWidget*)").constData()) 0239 && property && !property->children()) 0240 { 0241 } 0242 } 0243 else { 0244 w = QItemDelegate::createEditor(parent, alteredOption, index); 0245 } 0246 QObject::disconnect(w, SIGNAL(commitData(QWidget*)), 0247 this, SIGNAL(commitData(QWidget*))); 0248 if (property && effectiveValueSyncPolicy(property, 0249 qobject_cast<KPropertyEditorView*>(this->parent())->isValueSyncEnabled())) 0250 { 0251 QObject::connect(w, SIGNAL(commitData(QWidget*)), 0252 this, SIGNAL(commitData(QWidget*)), Qt::UniqueConnection); 0253 } 0254 m_currentEditor = w; 0255 return w; 0256 } 0257 0258 //---------- 0259 0260 class Q_DECL_HIDDEN KPropertyEditorView::Private 0261 { 0262 public: 0263 explicit Private(KPropertyEditorView *view) 0264 : model(nullptr) 0265 , gridLineColor( KPropertyEditorView::defaultGridLineColor() ) 0266 , valueSync(true) 0267 , slotPropertyChangedEnabled(true) 0268 , q(view) 0269 { 0270 } 0271 0272 //! Expands group and parent property items if needed (based on settings) 0273 void expandIfNeeded() { 0274 if (!model) { 0275 return; 0276 } 0277 const int rowCount = model->rowCount(); 0278 for (int row = 0; row < rowCount; row++) { 0279 expandChildItemsIfNeeded(model->index(row, 0)); 0280 } 0281 } 0282 0283 //! Expands property child items in a subtree recursively if needed (based on settings) 0284 void expandChildItemsIfNeeded(const QModelIndex &parent) { 0285 if (!model) { 0286 return; 0287 } 0288 const bool isGroupHeader(model->data(parent, KPropertyEditorDataModel::PropertyGroupRole).toBool()); 0289 if (isGroupHeader) { 0290 if (groupItemsExpanded) { 0291 q->expand(parent); 0292 } 0293 } else { 0294 if (childPropertyItemsExpanded) { 0295 q->expand(parent); 0296 } 0297 } 0298 const int rowCount = model->rowCount(parent); 0299 for (int row = 0; row < rowCount; row++) { 0300 const QModelIndex child(model->index(row, 0, parent)); 0301 expandChildItemsIfNeeded(child); 0302 } 0303 } 0304 0305 QPointer<KPropertySet> set; 0306 KPropertyEditorDataModel *model; 0307 ItemDelegate *itemDelegate; 0308 QColor gridLineColor; 0309 bool valueSync; 0310 bool slotPropertyChangedEnabled; 0311 bool childPropertyItemsExpanded = true; 0312 bool groupItemsExpanded = true; 0313 bool groupsVisible = true; 0314 bool toolTipsVisible = false; 0315 0316 private: 0317 KPropertyEditorView * const q; 0318 }; 0319 0320 KPropertyEditorView::KPropertyEditorView(QWidget* parent) 0321 : QTreeView(parent) 0322 , d(new Private(this)) 0323 { 0324 setObjectName(QLatin1String("KPropertyEditorView")); 0325 setAlternatingRowColors(true); 0326 setSelectionBehavior(QAbstractItemView::SelectRows); 0327 setSelectionMode(QAbstractItemView::SingleSelection); 0328 setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); 0329 setAnimated(false); 0330 setAllColumnsShowFocus(true); 0331 header()->setSectionsMovable(false); 0332 0333 setEditTriggers( 0334 QAbstractItemView::CurrentChanged 0335 | QAbstractItemView::DoubleClicked 0336 | QAbstractItemView::EditKeyPressed 0337 | QAbstractItemView::AnyKeyPressed 0338 | QAbstractItemView::AllEditTriggers); 0339 0340 setItemDelegate(d->itemDelegate = new ItemDelegate(this)); 0341 } 0342 0343 KPropertyEditorView::~KPropertyEditorView() 0344 { 0345 delete d; 0346 } 0347 0348 void KPropertyEditorView::changeSet(KPropertySet *set, SetOptions options) 0349 { 0350 changeSetInternal(set, options, QByteArray()); 0351 } 0352 0353 void KPropertyEditorView::changeSet(KPropertySet *set, const QByteArray& propertyToSelect, SetOptions options) 0354 { 0355 changeSetInternal(set, options, propertyToSelect); 0356 } 0357 0358 void KPropertyEditorView::changeSetInternal(KPropertySet *set, SetOptions options, 0359 const QByteArray& propertyToSelect) 0360 { 0361 //! @todo port?? 0362 #if 0 0363 if (d->insideSlotValueChanged) { 0364 //changeSet() called from inside of slotValueChanged() 0365 //this is dangerous, because there can be pending events, 0366 //especially for the GUI stuff, so let's do delayed work 0367 d->setListLater_list = set; 0368 d->preservePrevSelection_preservePrevSelection = preservePrevSelection; 0369 d->preservePrevSelection_propertyToSelect = propertyToSelect; 0370 qApp->processEvents(QEventLoop::AllEvents); 0371 if (d->set) { 0372 //store prev. selection for this prop set 0373 if (d->currentItem) 0374 d->set->setPrevSelection(d->currentItem->property()->name()); 0375 kprDebug() << d->set->prevSelection(); 0376 } 0377 if (!d->setListLater_set) { 0378 d->setListLater_set = true; 0379 d->changeSetLaterTimer.setSingleShot(true); 0380 d->changeSetLaterTimer.start(10); 0381 } 0382 return; 0383 } 0384 #endif 0385 0386 const bool setChanged = d->set != set; 0387 if (d->set) { 0388 acceptInput(); 0389 //store prev. selection for this prop set 0390 QModelIndex index = currentIndex(); 0391 if (index.isValid()) { 0392 //! @todo This crashes when changing the interpreter type in the script plugin 0393 #if 0 0394 KProperty *property = d->model->propertyForIndex(index); 0395 //if (property->isNull()) 0396 // kprDebug() << "WTF? a NULL property?"; 0397 //else 0398 //d->set->setPreviousSelection(property->name()); 0399 #endif 0400 } 0401 else { 0402 d->set->setPreviousSelection(QByteArray()); 0403 } 0404 if (setChanged) { 0405 d->set->disconnect(this); 0406 } 0407 } 0408 0409 QByteArray selectedPropertyName1 = propertyToSelect; 0410 QByteArray selectedPropertyName2 = propertyToSelect; 0411 if (options & SetOption::PreservePreviousSelection) { 0412 //try to find prev. selection: 0413 //1. in new list's prev. selection 0414 if (set) 0415 selectedPropertyName1 = set->previousSelection(); 0416 //2. in prev. list's current selection 0417 if (d->set) 0418 selectedPropertyName2 = d->set->previousSelection(); 0419 } 0420 0421 if (setChanged) { 0422 d->set = set; 0423 } 0424 if (d->set && setChanged) { 0425 //receive property changes 0426 connect(d->set, SIGNAL(propertyChangedInternal(KPropertySet&,KProperty&)), 0427 this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&))); 0428 connect(d->set, SIGNAL(propertyReset(KPropertySet&,KProperty&)), 0429 this, SLOT(slotPropertyReset(KPropertySet&,KProperty&))); 0430 connect(d->set, SIGNAL(aboutToBeCleared()), this, SLOT(slotSetWillBeCleared())); 0431 connect(d->set, SIGNAL(aboutToBeDeleted()), this, SLOT(slotSetWillBeDeleted())); 0432 connect(d->set, &KPropertySet::readOnlyFlagChanged, 0433 this, &KPropertyEditorView::slotReadOnlyFlagChanged); 0434 } 0435 0436 KPropertyEditorDataModel *oldModel = d->model; 0437 const KPropertySetIterator::Order setOrder 0438 = (options & SetOption::AlphabeticalOrder) 0439 ? KPropertySetIterator::Order::Alphabetical 0440 : KPropertySetIterator::Order::Insertion; 0441 d->model = d->set ? new KPropertyEditorDataModel(this, setOrder) : nullptr; 0442 setModel( d->model ); 0443 delete oldModel; 0444 0445 if (d->model && d->set && !d->set->isEmpty()) { 0446 d->expandIfNeeded(); 0447 } 0448 0449 emit propertySetChanged(d->set); 0450 0451 if (d->set) { 0452 //select prev. selected item 0453 QModelIndex index; 0454 if (!selectedPropertyName2.isEmpty()) //try other one for old prop set 0455 index = d->model->indexForPropertyName( selectedPropertyName2 ); 0456 if (!index.isValid() && !selectedPropertyName1.isEmpty()) //try old one for current prop set 0457 index = d->model->indexForPropertyName( selectedPropertyName1 ); 0458 0459 if (index.isValid()) { 0460 setCurrentIndex(index); 0461 scrollTo(index); 0462 } 0463 } 0464 } 0465 0466 void KPropertyEditorView::slotSetWillBeCleared() 0467 { 0468 changeSet(nullptr, QByteArray()); 0469 } 0470 0471 void KPropertyEditorView::slotSetWillBeDeleted() 0472 { 0473 changeSet(nullptr, QByteArray()); 0474 } 0475 0476 void KPropertyEditorView::slotReadOnlyFlagChanged() 0477 { 0478 const QModelIndex index = currentIndex(); 0479 setCurrentIndex(QModelIndex()); 0480 if (index.isValid()) { 0481 selectionModel()->select(index, QItemSelectionModel::Select); 0482 setCurrentIndex(index); 0483 } 0484 } 0485 0486 void KPropertyEditorView::setValueSyncEnabled(bool set) 0487 { 0488 d->valueSync = set; 0489 } 0490 0491 bool KPropertyEditorView::isValueSyncEnabled() const 0492 { 0493 return d->valueSync; 0494 } 0495 0496 void KPropertyEditorView::setChildPropertyItemsExpanded(bool set) 0497 { 0498 d->childPropertyItemsExpanded = set; 0499 } 0500 0501 bool KPropertyEditorView::childPropertyItemsExpanded() const 0502 { 0503 return d->childPropertyItemsExpanded; 0504 } 0505 0506 void KPropertyEditorView::setGroupItemsExpanded(bool set) 0507 { 0508 d->groupItemsExpanded = set; 0509 } 0510 0511 bool KPropertyEditorView::groupItemsExpanded() const 0512 { 0513 return d->groupItemsExpanded; 0514 } 0515 0516 bool KPropertyEditorView::groupsVisible() const 0517 { 0518 return d->groupsVisible; 0519 } 0520 0521 void KPropertyEditorView::setGroupsVisible(bool set) 0522 { 0523 if (d->groupsVisible == set) { 0524 return; 0525 } 0526 if (d->model) { 0527 d->model->updateGroupsVisibility(); 0528 d->expandIfNeeded(); 0529 } 0530 viewport()->update(); 0531 } 0532 0533 void KPropertyEditorView::currentChanged( const QModelIndex & current, const QModelIndex & previous ) 0534 { 0535 QTreeView::currentChanged( current, previous ); 0536 } 0537 0538 bool KPropertyEditorView::edit( const QModelIndex & index, EditTrigger trigger, QEvent * event ) 0539 { 0540 bool result; 0541 if (!d->set || d->set->isReadOnly()) { 0542 result = false; 0543 } else { 0544 result = QTreeView::edit(index, trigger, event); 0545 } 0546 if (result) { 0547 QLineEdit *lineEditEditor = qobject_cast<QLineEdit*>(d->itemDelegate->m_currentEditor.data()); 0548 if (lineEditEditor) { 0549 lineEditEditor->deselect(); 0550 lineEditEditor->end(false); 0551 } 0552 } 0553 return result; 0554 } 0555 0556 void KPropertyEditorView::drawBranches( QPainter * painter, const QRect & rect, const QModelIndex & index ) const 0557 { 0558 QTreeView::drawBranches( painter, rect, index ); 0559 } 0560 0561 void KPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 0562 { 0563 if (!d->model) { 0564 return; 0565 } 0566 const KPropertyUtilsPrivate::PainterSaver saver(painter); 0567 const bool isGroupHeader(d->model->data(index, KPropertyEditorDataModel::PropertyGroupRole).toBool()); 0568 QStyleOptionViewItem alteredOption(option); 0569 QTreeView::drawRow(painter, alteredOption, index); 0570 if (isGroupHeader) { 0571 // Special case: group header should be displayed over both columns. There's an issue with 0572 // alternate background which is painted over text in the 2nd column, so draw the text here 0573 // by hand. 0574 QFont font(alteredOption.font); 0575 font.setBold(true); 0576 alteredOption.font = font; 0577 painter->setFont(font); 0578 painter->drawText( 0579 alteredOption.rect.adjusted(style()->pixelMetric(QStyle::PM_TreeViewIndentation), 0, 0, 0), 0580 index.data(Qt::DisplayRole).toString(), Qt::AlignLeft | Qt::AlignVCenter); 0581 } 0582 } 0583 0584 QRect KPropertyEditorView::revertButtonArea( const QModelIndex& index ) const 0585 { 0586 if (index.column() != 0 || !d->model) 0587 return QRect(); 0588 QVariant modifiedVariant( d->model->data(index, KPropertyEditorDataModel::PropertyModifiedRole) ); 0589 if (!modifiedVariant.isValid() || !modifiedVariant.toBool()) 0590 return QRect(); 0591 const int iconSize = getIconSize( fontInfo().pixelSize() ); 0592 int x2 = columnWidth(0); 0593 int x1 = x2 - iconSize - 2; 0594 QRect r(visualRect(index)); 0595 r.setLeft(x1); 0596 r.setRight(x2); 0597 return r; 0598 } 0599 0600 bool KPropertyEditorView::withinRevertButtonArea( int x, const QModelIndex& index ) const 0601 { 0602 QRect r(revertButtonArea( index )); 0603 if (!r.isValid()) 0604 return false; 0605 return r.left() < x && x < r.right(); 0606 } 0607 0608 void KPropertyEditorView::mousePressEvent ( QMouseEvent * event ) 0609 { 0610 QTreeView::mousePressEvent( event ); 0611 QModelIndex index = indexAt( event->pos() ); 0612 setCurrentIndex(index); 0613 if (withinRevertButtonArea( event->x(), index )) { 0614 undo(); 0615 } 0616 } 0617 0618 void KPropertyEditorView::undo() 0619 { 0620 if (!d->set || d->set->isReadOnly() || !d->model) 0621 return; 0622 0623 KProperty *property = d->model->propertyForIndex(currentIndex()); 0624 if (effectiveValueSyncPolicy(property, d->valueSync)) { 0625 property->resetValue(); 0626 } 0627 } 0628 0629 void KPropertyEditorView::acceptInput() 0630 { 0631 //! @todo 0632 } 0633 0634 void KPropertyEditorView::commitData( QWidget * editor ) 0635 { 0636 QAbstractItemView::commitData( editor ); 0637 } 0638 0639 bool KPropertyEditorView::viewportEvent( QEvent * event ) 0640 { 0641 if (event->type() == QEvent::ToolTip) { 0642 QHelpEvent *hevent = static_cast<QHelpEvent*>(event); 0643 const QModelIndex index = indexAt(hevent->pos()); 0644 if (index.column() == 0 && withinRevertButtonArea( hevent->x(), index )) { 0645 QRect r(revertButtonArea( index )); 0646 QToolTip::showText(hevent->globalPos(), tr("Undo changes"), this, r); 0647 } 0648 else { 0649 QToolTip::hideText(); 0650 } 0651 } 0652 return QTreeView::viewportEvent(event); 0653 } 0654 0655 QSize KPropertyEditorView::sizeHint() const 0656 { 0657 return viewportSizeHint(); 0658 } 0659 0660 KPropertySet* KPropertyEditorView::propertySet() const 0661 { 0662 return d->set; 0663 } 0664 0665 QColor KPropertyEditorView::gridLineColor() const 0666 { 0667 return d->gridLineColor; 0668 } 0669 0670 void KPropertyEditorView::setGridLineColor(const QColor& color) 0671 { 0672 d->gridLineColor = color; 0673 viewport()->update(); 0674 } 0675 0676 static QModelIndex findChildItem(const KProperty& property, const QModelIndex &parent) 0677 { 0678 if (parent.model() && KPropertyUtils::propertyForIndex(parent) == &property) { 0679 return parent; 0680 } 0681 int row = 0; 0682 while (true) { 0683 QModelIndex childItem = parent.child(row, 0); 0684 if (childItem.isValid()) { 0685 QModelIndex subchild = findChildItem(property, childItem); 0686 if (subchild.isValid()) { 0687 return subchild; 0688 } 0689 } 0690 else { 0691 return QModelIndex(); 0692 } 0693 row++; 0694 } 0695 } 0696 0697 void KPropertyEditorView::slotPropertyChanged(KPropertySet& set, KProperty& property) 0698 { 0699 Q_UNUSED(set); 0700 if (!d->slotPropertyChangedEnabled || !d->model) 0701 return; 0702 d->slotPropertyChangedEnabled = false; 0703 KProperty *realProperty = &property; 0704 while (realProperty->parent()) { // find top-level property 0705 realProperty = realProperty->parent(); 0706 } 0707 const QModelIndex parentIndex( d->model->indexForPropertyName(realProperty->name()) ); 0708 if (parentIndex.isValid()) { 0709 QModelIndex index = findChildItem(property, parentIndex); 0710 updateSubtree(index); 0711 } 0712 d->slotPropertyChangedEnabled = true; 0713 } 0714 0715 void KPropertyEditorView::updateSubtree(const QModelIndex &index) 0716 { 0717 if (!index.isValid() || !d->model) { 0718 return; 0719 } 0720 update(index); 0721 update(index.parent()); 0722 update(d->model->indexForColumn(index, 1)); 0723 update(d->model->indexForColumn(index.parent(), 1)); 0724 0725 KProperty *property = static_cast<KProperty*>(index.internalPointer()); 0726 if (property->children()) { 0727 int row = 0; 0728 foreach (KProperty* p, *property->children()) { 0729 updateSubtree(d->model->createIndex(row, 0, p)); 0730 ++row; 0731 } 0732 } 0733 } 0734 0735 void KPropertyEditorView::slotPropertyReset(KPropertySet& set, KProperty& property) 0736 { 0737 //! @todo OK? 0738 slotPropertyChanged(set, property); 0739 } 0740 0741 0742 bool KPropertyEditorView::toolTipsVisible() const 0743 { 0744 return d->toolTipsVisible; 0745 } 0746 0747 void KPropertyEditorView::setToolTipsVisible(bool set) 0748 { 0749 d->toolTipsVisible = set; 0750 }