File indexing completed on 2024-05-05 05:46:20

0001 /***************************************************************************
0002  *   Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>                     *
0003  *   Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>            *
0004  *   Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>                     *
0005  *   Copyright (C) 2006 David Saxton <david@bluehaze.org>                  *
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or modify  *
0008  *   it under the terms of the GNU General Public License as published by  *
0009  *   the Free Software Foundation; either version 2 of the License, or     *
0010  *   (at your option) any later version.                                   *
0011  ***************************************************************************/
0012 
0013 #include "propertyeditor.h"
0014 #include "item.h"
0015 #include "itemgroup.h"
0016 #include "iteminterface.h"
0017 #include "ktechlab.h"
0018 #include "propertyeditorcolor.h"
0019 #include "propertyeditorfile.h"
0020 #include "propertyeditorinput.h"
0021 #include "propertyeditorlist.h"
0022 
0023 #include "drawparts/drawpart.h"
0024 
0025 #include <KIconLoader>
0026 #include <KLocalizedString>
0027 
0028 #include <QApplication>
0029 #include <QEvent>
0030 #include <QFontMetrics>
0031 #include <QHeaderView>
0032 #include <QIcon>
0033 #include <QPushButton>
0034 #include <QStyledItemDelegate>
0035 #include <QTimer>
0036 
0037 #include <ktechlab_debug.h>
0038 
0039 struct PropertyEditorStyledItemColProperty : public QStyledItemDelegate {
0040     PropertyEditor *m_propEditor;
0041 
0042     PropertyEditorStyledItemColProperty(PropertyEditor *propEditor)
0043         : QStyledItemDelegate(propEditor)
0044         , m_propEditor(propEditor)
0045     {
0046     }
0047 
0048     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
0049     {
0050         //         if ( depth() == 0 )
0051         //             return;
0052         QTableWidgetItem *itemPtr = m_propEditor->item(index.row(), index.column());
0053         if (!itemPtr) {
0054             qCWarning(KTL_LOG) << " null item";
0055             return;
0056         }
0057         PropertyEditorItem *itemProp = dynamic_cast<PropertyEditorItem *>(itemPtr);
0058         if (!itemProp) {
0059             qCWarning(KTL_LOG) << " cannot cast item";
0060             return;
0061         }
0062 
0063         m_propEditor->contentsMargins();
0064         int margin = 3; // listView()->itemMargin(); // TODO set decent value
0065 
0066         const int width = option.rect.width();
0067         const int height = option.rect.height();
0068         const int top = option.rect.top();
0069         const int left = option.rect.left();
0070 
0071         const bool isHighlighted = m_propEditor->currentRow() == index.row();
0072 
0073         painter->save();
0074 
0075         // qCWarning(KTL_LOG) << " draw col " << index.column() << " row " << index.row()
0076         //    << " isHighlighted=" << isHighlighted << " state_selected=" << option.state.testFlag(QStyle::State_Selected);
0077 
0078         if (isHighlighted || option.state.testFlag(QStyle::State_Selected)) {
0079             painter->fillRect(left, top, width, height, option.palette.highlight());
0080             painter->setPen(option.palette.color(QPalette::BrightText) /* highlightedText() */);
0081         } else {
0082             QColor bgColor = option.palette.color(QPalette::Base); // 2018.12.07
0083             painter->fillRect(left, top, width, height, QBrush(bgColor));
0084         }
0085 
0086         QFont f = option.font;
0087 
0088         if (itemProp->property()->changed() || (!itemProp->property()->isAdvanced())) {
0089             f.setBold(true);
0090         }
0091 
0092         painter->setFont(f);
0093         painter->drawText(QRect(left + margin, top, width - 1, height - 1), Qt::AlignVCenter, itemProp->text());
0094 
0095         // qCWarning(KTL_LOG) << " draw " << itemProp->text() << " at " << option.rect;
0096 
0097         painter->setPen(QColor(200, 200, 200)); // like in table view
0098         painter->drawLine(left + width - 1, top, left + width - 1, top + height - 1);
0099 
0100         painter->setPen(QColor(200, 200, 200)); // like in t.v.
0101         painter->drawLine(left - 50, top + height - 1, left + width - 1, top + height - 1);
0102 
0103         painter->restore();
0104     }
0105     /*
0106     virtual QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const {
0107         // TODO
0108     }
0109     */
0110 };
0111 
0112 struct PropertyEditorStyledItemColValue : public QStyledItemDelegate {
0113     PropertyEditor *m_propEditor;
0114 
0115     PropertyEditorStyledItemColValue(PropertyEditor *propEditor)
0116         : QStyledItemDelegate(propEditor)
0117         , m_propEditor(propEditor)
0118     {
0119     }
0120 
0121     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
0122     {
0123         //         if ( depth() == 0 )
0124         //             return;
0125 
0126         QTableWidgetItem *itemPtr = m_propEditor->item(index.row(), index.column());
0127         if (!itemPtr) {
0128             qCWarning(KTL_LOG) << " null item";
0129             return;
0130         }
0131         PropertyEditorItem *itemProp = dynamic_cast<PropertyEditorItem *>(itemPtr);
0132         if (!itemProp) {
0133             qCWarning(KTL_LOG) << " cannot cast item";
0134             return;
0135         }
0136 
0137         int margin = 3; // listView()->itemMargin();  // TODO set decent value
0138 
0139         const int width = option.rect.width();
0140         const int height = option.rect.height();
0141         const int top = option.rect.top();
0142         const int left = option.rect.left();
0143 
0144         // const bool isHighlighted = m_propEditor->currentRow() == index.row(); // TODO
0145 
0146         QColor bgColor = option.palette.color(QPalette::Window); // backgroundColor(0); // 2018.06.02 - is this better?
0147 
0148         painter->save();
0149 
0150         Property *property = itemProp->property();
0151         switch (property->type()) {
0152             //          case QVariant::Pixmap:
0153             //          {
0154             //              p->fillRect(0,0,width,height(),QBrush(backgroundColor()));
0155             //              p->drawPixmap(margin, margin, m_property->value().toPixmap());
0156             //              break;
0157             //          }
0158 
0159         case Variant::Type::Color: {
0160             painter->fillRect(left, top, width, height, QBrush(bgColor));
0161             // QColor ncolor = m_property->value().toColor();
0162             QColor ncolor = property->value().value<QColor>();
0163             painter->setBrush(ncolor);
0164             painter->drawRect(left + margin, top + margin, width - 2 * margin, height - 2 * margin);
0165             //                 QColorGroup nGroup(cg);
0166             break;
0167         }
0168 
0169         case Variant::Type::Bool: {
0170             painter->fillRect(left, top, width, height, QBrush(bgColor));
0171             if (property->value().toBool()) {
0172                 QIcon dialogOkIcon = QIcon::fromTheme("dialog-ok");
0173                 QPixmap okPixmap = dialogOkIcon.pixmap(KIconLoader::SizeSmall);
0174                 painter->drawPixmap(left + margin, top + height / 2 - 8, okPixmap);
0175                 painter->drawText(QRect(left + margin + 20, top, width, height - 1), Qt::AlignVCenter, i18n("Yes"));
0176             } else {
0177                 QIcon dialogCancelIcon = QIcon::fromTheme("dialog-cancel");
0178                 QPixmap cancelPixmap = dialogCancelIcon.pixmap(KIconLoader::SizeSmall);
0179                 painter->drawPixmap(left + margin, top + height / 2 - 8, cancelPixmap);
0180                 painter->drawText(QRect(left + margin + 20, top, width, height - 1), Qt::AlignVCenter, i18n("No"));
0181             }
0182             break;
0183         }
0184 
0185         case Variant::Type::PenStyle: {
0186             painter->fillRect(left, top, width, height, QBrush(bgColor));
0187 
0188             Qt::PenStyle style = DrawPart::nameToPenStyle(property->value().toString());
0189             int penWidth = 3;
0190             QPen pen(Qt::black, penWidth, style);
0191             painter->setPen(pen);
0192             painter->drawLine(left + height / 2, top + height / 2 - 1, left + width - height / 2, top + height / 2 - 1);
0193             break;
0194         }
0195 
0196 #if 0
0197             case Variant::Type::PenCapStyle:
0198             {
0199                 p->fillRect(0,0,width,height, QBrush(bgColor));
0200 
0201                 PenCapStyle style = DrawPart::nameToPenCapStyle( property->value().toString() );
0202                 int penWidth = 6;
0203                 QPen pen( black, penWidth, SolidLine, style, MiterJoin );
0204                 p->setPen( pen );
0205                 p->drawLine( width/2-10, height/2-2, width/2+10, height/2-2 );
0206                 break;
0207             }
0208 #endif
0209 
0210         case Variant::Type::None:
0211         case Variant::Type::Int:
0212         case Variant::Type::Raw:
0213         case Variant::Type::Double:
0214         case Variant::Type::String:
0215         case Variant::Type::Multiline:
0216         case Variant::Type::RichText:
0217         case Variant::Type::Select:
0218         case Variant::Type::Combo:
0219         case Variant::Type::FileName:
0220         case Variant::Type::VarName:
0221         case Variant::Type::PenCapStyle:
0222         case Variant::Type::Port:
0223         case Variant::Type::Pin:
0224         case Variant::Type::SevenSegment:
0225         case Variant::Type::KeyPad: {
0226             QStyledItemDelegate::paint(painter, option, index);
0227             break;
0228         }
0229         }
0230 
0231         painter->setPen(QColor(200, 200, 200)); // like in t.v.
0232         painter->drawLine(left - 50, top + height - 1, left + width, top + height - 1);
0233 
0234         painter->restore();
0235     }
0236     /*
0237     virtual QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const {
0238         // TODO
0239     }
0240     */
0241 };
0242 
0243 PropertyEditor::PropertyEditor(QWidget *parent)
0244     : QTableWidget(parent)
0245     //, m_items(101, false) // 2018.08.13 - unused
0246     , justClickedItem(false)
0247     , m_lastCellWidgetRow(-1)
0248     , m_lastCellWidgetCol(-1)
0249     , m_colPropertyDelegate(nullptr)
0250     , m_colValueDelegate(nullptr)
0251 {
0252     // m_items.setAutoDelete(false); // 2018.08.13 - unused
0253 
0254     setColumnCount(2);
0255     QStringList headerLabels;
0256     headerLabels.append(i18n("Property"));
0257     headerLabels.append(i18n("Value"));
0258     setHorizontalHeaderLabels(headerLabels);
0259     // addColumn( i18n("Property") );    // 2018.08.13 - ported to QTableWidget
0260     // addColumn( i18n("Value") );
0261 
0262     m_colPropertyDelegate = new PropertyEditorStyledItemColProperty(this);
0263     setItemDelegateForColumn(0, m_colPropertyDelegate);
0264 
0265     m_colValueDelegate = new PropertyEditorStyledItemColValue(this);
0266     setItemDelegateForColumn(1, m_colValueDelegate);
0267 
0268     m_topItem = nullptr;
0269     m_editItem = nullptr;
0270 
0271     connect(this, &PropertyEditor::clicked, this, &PropertyEditor::slotClicked);
0272     connect(this, &PropertyEditor::itemActivated, this, &PropertyEditor::slotCurrentChanged);
0273     //  connect(this, SIGNAL(expanded(Q3ListViewItem *)), this, SLOT(slotExpanded(Q3ListViewItem *)));  // TODO
0274     //  connect(this, SIGNAL(collapsed(Q3ListViewItem *)), this, SLOT(slotCollapsed(Q3ListViewItem *)));
0275 
0276     // connect(this, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(slotCurrentCellChanged(int, int, int, int)));
0277     connect(this, &PropertyEditor::currentCellChanged, this, &PropertyEditor::slotCurrentCellChanged);
0278 
0279     //  connect(header(), SIGNAL(sizeChange( int, int, int )), this, SLOT(slotColumnSizeChanged( int, int, int ))); // TODO
0280     //  connect(header(), SIGNAL(clicked( int )), this, SLOT(moveEditor()));
0281     //  connect(header(), SIGNAL(sectionHandleDoubleClicked ( int )), this, SLOT(slotColumnSizeChanged( int )));
0282 
0283     m_defaults = new QPushButton(viewport());
0284     m_defaults->setFocusPolicy(Qt::NoFocus);
0285     setFocusPolicy(Qt::ClickFocus);
0286     m_defaults->setIcon(QIcon::fromTheme("edit-undo"));
0287     m_defaults->setToolTip(i18n("Undo changes"));
0288     m_defaults->hide();
0289     connect(m_defaults, &QPushButton::clicked, this, &PropertyEditor::resetItem);
0290 
0291     // TODO
0292     const int itemMargin = 2;
0293     // setRootIsDecorated( false );
0294     // setShowSortIndicator( false );
0295     // setTooltipColumn(0); // TODO equivalent?
0296     setSortingEnabled(false /*true*/); // note: enabling it causes crashes, apperently
0297     horizontalHeader()->setSortIndicatorShown(false);
0298     horizontalHeader()->setContentsMargins(itemMargin, itemMargin, itemMargin, itemMargin);
0299     // setItemMargin(2); // needed?
0300     horizontalHeader()->setSectionResizeMode(QHeaderView::QHeaderView::Stretch);
0301     horizontalHeader()->setSectionsMovable(false);
0302     // header()->setMovingEnabled( false );
0303     verticalHeader()->setVisible(false);
0304     // setTreeStepSize(0);
0305     setSelectionMode(QAbstractItemView::SingleSelection);
0306 
0307     m_baseRowHeight = QFontMetrics(font()).height() + itemMargin * 2;
0308 }
0309 
0310 PropertyEditor::~PropertyEditor()
0311 {
0312     // note: delete m_colPropertyDelegate and m_colValueDelegate
0313 }
0314 
0315 void PropertyEditor::slotClicked(const QModelIndex &index)
0316 {
0317     if (!index.isValid())
0318         return;
0319 
0320     // 2019.01.19 - moved to slotCurrentCellChanged()
0321     //     if (index.column() == 1) {
0322     //         // PropertyEditorItem *i = static_cast<PropertyEditorItem *>(item);// 2018.08.13 - not needed
0323     //         createEditor(index);
0324     //     }
0325 
0326     justClickedItem = true;
0327 }
0328 
0329 void PropertyEditor::slotCurrentChanged(QTableWidgetItem * /*itemParam*/)
0330 {
0331     // TODO
0332     //  if (itemParam == firstChild())
0333     //  {
0334     //      Q3ListViewItem *oldItem = item;
0335     //      while (item && (!item->isSelectable() || !item->isVisible()))
0336     //          item = item->itemBelow();
0337     //
0338     //      if (item && item!=oldItem)
0339     //      {
0340     //          setSelected(item,true);
0341     //          return;
0342     //      }
0343     //  }
0344 }
0345 
0346 void PropertyEditor::slotCurrentCellChanged(int currentRow, int currentColumn, int /*previousRow*/, int /*previousColumn*/)
0347 {
0348     viewport()->repaint(); // force a repaint to clear the "selected" background on items
0349 
0350     if (currentColumn == 0) {
0351         setCurrentCell(currentRow, 1); // move focus to the value column
0352     }
0353     if (currentColumn == 1) {
0354         createEditor(currentIndex());
0355     }
0356 }
0357 
0358 void PropertyEditor::slotExpanded(QTableWidgetItem *item)
0359 {
0360     if (!item)
0361         return;
0362     moveEditor();
0363 }
0364 
0365 void PropertyEditor::slotCollapsed(QTableWidgetItem *item)
0366 {
0367     if (!item)
0368         return;
0369     moveEditor();
0370 }
0371 
0372 void PropertyEditor::createEditor(const QModelIndex &index)
0373 {
0374     PropertyEditorItem *i = dynamic_cast<PropertyEditorItem *>(item(index.row(), index.column()));
0375     if (!i) {
0376         qCWarning(KTL_LOG) << "no item";
0377         return;
0378     }
0379 
0380     //  int y = viewportToContents(QPoint(0, itemRect(i).y())).y();
0381     //  QRect geometry(columnWidth(0), y, columnWidth(1), i->height());
0382 
0383     // delete m_currentEditor;
0384     // m_currentEditor->deleteLater();
0385     if (m_lastCellWidgetRow >= 0 && m_lastCellWidgetCol >= 0) {
0386         removeCellWidget(m_lastCellWidgetRow, m_lastCellWidgetCol);
0387         m_lastCellWidgetRow = -1;
0388         m_lastCellWidgetCol = -1;
0389     }
0390     m_currentEditor = nullptr;
0391 
0392     m_editItem = i;
0393 
0394     PropertySubEditor *editor = nullptr;
0395     switch (i->type()) {
0396     case Variant::Type::String:
0397         editor = new PropertyEditorInput(viewport(), i->property());
0398         break;
0399 
0400     case Variant::Type::Port:
0401     case Variant::Type::Pin:
0402     case Variant::Type::Combo:
0403     case Variant::Type::VarName:
0404     case Variant::Type::Select:
0405     case Variant::Type::PenStyle:
0406     case Variant::Type::PenCapStyle:
0407     case Variant::Type::SevenSegment:
0408     case Variant::Type::KeyPad:
0409         editor = new PropertyEditorList(viewport(), i->property());
0410         break;
0411 
0412     case Variant::Type::FileName:
0413         qCDebug(KTL_LOG) << "creating PropertyEditorFile";
0414         editor = new PropertyEditorFile(viewport(), i->property());
0415         break;
0416 
0417     case Variant::Type::Int:
0418         editor = new PropertyEditorSpin(viewport(), i->property());
0419         break;
0420 
0421     case Variant::Type::Double:
0422         editor = new PropertyEditorDblSpin(viewport(), i->property());
0423         break;
0424 
0425     case Variant::Type::Color:
0426         editor = new PropertyEditorColor(viewport(), i->property());
0427         break;
0428 
0429     case Variant::Type::Bool:
0430         editor = new PropertyEditorBool(viewport(), i->property());
0431         break;
0432 
0433     case Variant::Type::Raw:
0434     case Variant::Type::Multiline:
0435     case Variant::Type::RichText:
0436     case Variant::Type::None:
0437         break;
0438     }
0439 
0440     if (editor) {
0441         // addChild(editor);
0442         // moveChild(editor, geometry.x(), geometry.y());
0443         m_lastCellWidgetRow = index.row();
0444         m_lastCellWidgetCol = index.column();
0445         setCellWidget(index.row(), index.column(), editor);
0446         editor->show();
0447 
0448         editor->setFocus();
0449     }
0450 
0451     m_currentEditor = editor;
0452     showDefaultsButton(i->property()->changed());
0453 }
0454 
0455 void PropertyEditor::showDefaultsButton(bool show)
0456 {
0457     QRect editItemRect = visualItemRect(m_editItem);
0458     int y = editItemRect.y(); // viewportToContents(QPoint(0, itemRect(m_editItem).y())).y(); // TODO
0459     QRect geometry(columnWidth(0), y, columnWidth(1), editItemRect.height() /* m_editItem->height() TOOD */);
0460     m_defaults->resize(m_baseRowHeight, m_baseRowHeight);
0461 
0462     if (!show) {
0463         if (m_currentEditor) {
0464             if (m_currentEditor->leavesTheSpaceForRevertButton()) {
0465                 geometry.setWidth(geometry.width() - m_defaults->width());
0466             }
0467             m_currentEditor->resize(geometry.width(), geometry.height());
0468         }
0469         m_defaults->hide();
0470         return;
0471     }
0472 
0473     QPoint p = geometry.topLeft(); // = contentsToViewport(QPoint(0, geometry.y())); // TODO
0474     m_defaults->move(geometry.x() + geometry.width() - m_defaults->width(), p.y());
0475     if (m_currentEditor) {
0476         m_currentEditor->move(m_currentEditor->x(), p.y());
0477         m_currentEditor->resize(geometry.width() - m_defaults->width(), geometry.height());
0478     }
0479     m_defaults->show();
0480 }
0481 
0482 void PropertyEditor::updateDefaultsButton()
0483 {
0484     QTableWidgetItem *currItem = currentItem();
0485     if (!currItem) {
0486         m_editItem = nullptr;
0487         return;
0488     }
0489     m_editItem = dynamic_cast<PropertyEditorItem*>(currItem);
0490     if (!m_editItem) {
0491         qCWarning(KTL_LOG) << "failed to cast current item to PropertyEditorItem, " << currItem;
0492         return;
0493     }
0494     qCDebug(KTL_LOG) << "currentItem=" << currentItem();
0495     qCDebug(KTL_LOG) << "m_editItem=" << m_editItem;
0496     qCDebug(KTL_LOG) << "m_editItem->property=" << m_editItem->property();
0497     showDefaultsButton(m_editItem->property()->changed());
0498     repaint(); // m_editItem->repaint();
0499 }
0500 
0501 void PropertyEditor::slotColumnSizeChanged(int section, int, int newS)
0502 {
0503     if (m_currentEditor) {
0504         if (section == 0) {
0505             m_currentEditor->move(newS, m_currentEditor->y());
0506         } else {
0507             if (m_defaults->isVisible())
0508                 m_currentEditor->resize(newS - m_defaults->width(), m_currentEditor->height());
0509             else
0510                 m_currentEditor->resize(newS - (m_currentEditor->leavesTheSpaceForRevertButton() ? m_defaults->width() : 0), m_currentEditor->height());
0511         }
0512     }
0513 }
0514 
0515 void PropertyEditor::slotColumnSizeChanged(int section)
0516 {
0517     setColumnWidth(1, viewport()->width() - columnWidth(0));
0518     slotColumnSizeChanged(section, 0, horizontalHeader()->sectionSize(section));
0519     if (m_currentEditor) {
0520         if (m_defaults->isVisible())
0521             m_currentEditor->resize(columnWidth(1) - m_defaults->width(), m_currentEditor->height());
0522         else
0523             m_currentEditor->resize(columnWidth(1) - (m_currentEditor->leavesTheSpaceForRevertButton() ? m_defaults->width() : 0), m_currentEditor->height());
0524     }
0525 }
0526 
0527 void PropertyEditor::reset()
0528 {
0529     // if ( m_currentEditor )
0530     //  m_currentEditor->deleteLater();
0531     if (m_lastCellWidgetRow >= 0 && m_lastCellWidgetCol >= 0) {
0532         removeCellWidget(m_lastCellWidgetRow, m_lastCellWidgetCol);
0533         m_lastCellWidgetRow = -1;
0534         m_lastCellWidgetCol = -1;
0535     }
0536     m_currentEditor = nullptr;
0537 
0538     if (m_defaults->isVisible())
0539         m_defaults->hide();
0540 
0541     // clear();
0542     QTableWidget::reset();
0543     m_editItem = nullptr;
0544     m_topItem = nullptr;
0545 }
0546 
0547 QSize PropertyEditor::sizeHint() const
0548 {
0549     return QSize(QFontMetrics(font()).horizontalAdvance(horizontalHeaderItem(0)->text() + horizontalHeaderItem(1)->text() + "   "), QTableWidget::sizeHint().height());
0550 }
0551 
0552 void PropertyEditor::create(ItemGroup *b)
0553 {
0554     qCDebug(KTL_LOG) << "b=" << b;
0555     m_pItemGroup = b;
0556 
0557     // QCString selectedPropertyName1, selectedPropertyName2;
0558     //     QByteArray selectedPropertyName1, selectedPropertyName2;     // 2018.08. 13 - dead code
0559 
0560     fill();
0561     /* 2018.08. 13 - dead code
0562         //select prev. selecteed item
0563         PropertyEditorItem * item = 0;
0564         if (!selectedPropertyName2.isEmpty()) //try other one for old buffer
0565             item = m_items[selectedPropertyName2];
0566         if (!item && !selectedPropertyName1.isEmpty()) //try old one for current buffer
0567             item = m_items[selectedPropertyName1];
0568         if (item)
0569         {
0570             setItemSelected(item, true);
0571             scrollToItem(item);
0572         } else {
0573             qCWarning(KTL_LOG) << "no item to select ";
0574         }
0575     */
0576     qCDebug(KTL_LOG) << "column count= " << columnCount() << "rowCount=" << rowCount();
0577 }
0578 
0579 void PropertyEditor::fill()
0580 {
0581     reset();
0582 
0583     if (!m_pItemGroup || !m_pItemGroup->activeItem()) {
0584         qCWarning(KTL_LOG) << " no active item " << m_pItemGroup;
0585         return;
0586     }
0587 
0588     if (!m_topItem) {
0589         m_topItem = new PropertyEditorItem(this, "Top Item");
0590     }
0591 
0592     // m_items.clear();  // 2018.08.13 - unused
0593     setRowCount(0); // remove all items from the table
0594 
0595     VariantDataMap *vmap = m_pItemGroup->activeItem()->variantMap();
0596     // Build the list
0597     for (VariantDataMap::iterator vait = vmap->begin(); vait != vmap->end(); ++vait) {
0598         Variant *v = *vait;
0599         if (v->isHidden()) {
0600             continue;
0601         }
0602         qCDebug(KTL_LOG) << "add variant id=" << v->id() << " v=" << v;
0603 
0604         switch (v->type()) {
0605         case Variant::Type::String:
0606         case Variant::Type::Port:
0607         case Variant::Type::Pin:
0608         case Variant::Type::Combo:
0609         case Variant::Type::VarName:
0610         case Variant::Type::Select:
0611         case Variant::Type::PenStyle:
0612         case Variant::Type::PenCapStyle:
0613         case Variant::Type::SevenSegment:
0614         case Variant::Type::KeyPad:
0615         case Variant::Type::FileName:
0616         case Variant::Type::Int:
0617         case Variant::Type::Double:
0618         case Variant::Type::Color:
0619         case Variant::Type::Bool:
0620             // These are all handled by the ItemEditor
0621             break;
0622 
0623         case Variant::Type::Raw:
0624         case Variant::Type::Multiline:
0625         case Variant::Type::None:
0626         case Variant::Type::RichText:
0627             // These are not handled by the ItemEditor
0628             continue;
0629         }
0630 
0631         const int nextRow = rowCount();
0632         setRowCount(nextRow + 1);
0633         {
0634             QTableWidgetItem *itemPropName = new PropertyEditorItem(m_topItem, v);
0635             itemPropName->setText(v->editorCaption());
0636             itemPropName->setFlags(Qt::ItemIsEnabled);
0637             setItem(nextRow, 0, itemPropName);
0638         }
0639         {
0640             PropertyEditorItem *itemPropValue = new PropertyEditorItem(m_topItem, v);
0641             itemPropValue->setText(v->displayString());
0642             connect(v, SIGNAL(valueChanged(QVariant, QVariant)), itemPropValue, SLOT(propertyValueChanged()));
0643             // TODO ‘virtual void PropertyEditorItem::propertyValueChanged()’ is protected within this context
0644             // connect(v, qOverload<QVariant, QVariant>(&Variant::valueChanged),
0645             //        itemPropValue, &PropertyEditorItem::propertyValueChanged);
0646             itemPropValue->updateValue();
0647             setItem(nextRow, 1, itemPropValue);
0648         }
0649         // m_items.insert( v->id().latin1(), item ); // 2018.08.13 - unused
0650     }
0651 }
0652 
0653 void PropertyEditor::setFocus()
0654 {
0655     selectedItems();
0656     PropertyEditorItem *item = static_cast<PropertyEditorItem *>(selectedItem());
0657     if (item) {
0658         if (!justClickedItem) {
0659             scrollToItem(item);
0660         }
0661         justClickedItem = false;
0662     } else {
0663         // select an item before focusing
0664         item = static_cast<PropertyEditorItem *>(itemAt(QPoint(10, 1)));
0665         if (item) {
0666             scrollToItem(item);      // ensureItemVisible(item);
0667             item->setSelected(true); // setSelected(item, true);
0668         }
0669     }
0670     if (m_currentEditor) {
0671         m_currentEditor->setFocus();
0672     } else {
0673         QTableWidget::setFocus();
0674     }
0675 }
0676 
0677 void PropertyEditor::resetItem()
0678 {
0679     if (m_editItem) {
0680         ItemInterface::self()->slotSetData(m_editItem->property()->id(), m_editItem->property()->defaultValue());
0681     }
0682 }
0683 
0684 void PropertyEditor::moveEditor()
0685 {
0686     if (!m_currentEditor)
0687         return;
0688 
0689     QPoint p = QPoint(0, visualItemRect(m_editItem).y()); //  = contentsToViewport(QPoint(0, itemPos(m_editItem))); // TODO
0690     m_currentEditor->move(m_currentEditor->x(), p.y());
0691     if (m_defaults->isVisible()) {
0692         m_defaults->move(m_defaults->x(), p.y());
0693     }
0694 }
0695 
0696 void PropertyEditor::resizeEvent(QResizeEvent *ev)
0697 {
0698     QTableWidget::resizeEvent(ev);
0699     updateDefaultsButton();
0700     //  if(m_defaults->isVisible())
0701     //  {
0702     //         rect();
0703     //      QRect r = visualItemRect(m_editItem) ; // = itemRect(m_editItem); // TODO
0704     //      if(r.y()) { // r.y() == 0 if the item is not visible on the screen
0705     //          m_defaults->move(r.x() + r.width() - m_defaults->width(), r.y());
0706     //         }
0707     //  }
0708     //
0709     //  if ( m_currentEditor )
0710     //  {
0711     //      m_currentEditor->resize(
0712     //          columnWidth(1)-((m_currentEditor->leavesTheSpaceForRevertButton()||m_defaults->isVisible()) ? m_defaults->width() : 0),
0713     //          m_currentEditor->height());
0714     //  }
0715 }
0716 
0717 bool PropertyEditor::handleKeyPress(QKeyEvent * /*ev*/)
0718 {
0719 #if 0 // TODO
0720     const int k = ev->key();
0721     const Qt::ButtonState s = ev->state();
0722 
0723     //selection moving
0724     QTableWidgetItem *item = 0;
0725 
0726     if ((s==Qt::NoButton && k==Qt::Key_Up) || k==Qt::Key_Backtab) {
0727         //find prev visible
0728         item = selectedItem() ? selectedItem()->itemAbove() : 0;
0729         while (item && (!item->flags().testFlag(Qt::ItemIsSelectable) || !item->isVisible()))
0730             item = item->itemAbove();
0731         if (!item)
0732             return true;
0733     }
0734     else if (s==Qt::NoButton && (k==Qt::Key_Down || k==Qt::Key_Tab)) {
0735         //find next visible
0736         item = selectedItem() ? selectedItem()->itemBelow() : 0;
0737         while (item && (!item->flags().testFlag(Qt::ItemIsSelectable) || !item->isVisible()))
0738             item = item->itemBelow();
0739         if (!item)
0740             return true;
0741     }
0742     else if(s==Qt::NoButton && k==Qt::Key_Home) {
0743         if (m_currentEditor && m_currentEditor->hasFocus())
0744             return false;
0745         //find 1st visible
0746         item = firstChild();
0747         while (item && (!item->flags().testFlag(Qt::ItemIsSelectable) || !item->isVisible()))
0748             item = item->itemBelow();
0749     }
0750     else if(s==Qt::NoButton && k==Qt::Key_End) {
0751         if (m_currentEditor && m_currentEditor->hasFocus())
0752             return false;
0753         //find last visible
0754         item = selectedItem();
0755         Q3ListViewItem *lastVisible = item;
0756         while (item) { // && (!item->isSelectable() || !item->isVisible()))
0757             item = item->itemBelow();
0758             if (item && item->flags().testFlag(Qt::ItemIsSelectable) && item->isVisible())
0759                 lastVisible = item;
0760         }
0761         item = lastVisible;
0762     }
0763     if(item) {
0764         ev->accept();
0765         scrollToItem(item);
0766         item->setSelected(true); // setSelected(item, true);
0767         return true;
0768     }
0769 #endif
0770     return false;
0771 }
0772 
0773 PropertyEditorItem *PropertyEditor::selectedItem()
0774 {
0775     QModelIndexList selList = selectedIndexes();
0776     if (selList.empty()) {
0777         return nullptr;
0778     }
0779     if (selList.size() > 1) {
0780         qCWarning(KTL_LOG) << " unexpected selection size of " << selList.size();
0781     }
0782     QModelIndex selIndex = selList.first();
0783     PropertyEditorItem *itemProp = dynamic_cast<PropertyEditorItem *>(item(selIndex.row(), selIndex.column()));
0784     if (!itemProp) {
0785         qCWarning(KTL_LOG) << " failed to cast " << selIndex;
0786     }
0787     return itemProp;
0788 }
0789 
0790 #include "moc_propertyeditor.cpp"