#include "qpiconfigwidget.h" #include "qalgorithms.h" #include "qpiconfigvaluewidget.h" #include #include #include QPIConfigWidget::QPIConfigWidget(QWidget * parent, QPIConfig * c, bool on) : QTreeWidget(parent) , actionAddItem(this) , actionAddNode(this) , actionToItem(this) , actionToNode(this) , actionRemove(this) , actionExpandAll(this) , actionCollapseAll(this) { active = on; if (active) { setColumnCount(4); setColumnWidth(0, 150); setColumnWidth(1, 200); } else { setColumnCount(0); } setSelectionMode(ExtendedSelection); setVerticalScrollMode(ScrollPerPixel); actionAddItem.setIcon(QIcon(":/icons/item-add.png")); actionAddNode.setIcon(QIcon(":/icons/node-add.png")); actionToItem.setIcon(QIcon(":/icons/item.png")); actionToNode.setIcon(QIcon(":/icons/node.png")); actionRemove.setIcon(QIcon(":/icons/edit-delete.png")); popupMenu.addAction(&actionAddItem); popupMenu.addAction(&actionAddNode); popupMenu.addSeparator(); popupMenu.addAction(&actionRemove); popupMenu.addSeparator(); popupMenu.addAction(&actionExpandAll); popupMenu.addAction(&actionCollapseAll); viewport()->installEventFilter(this); connect(this, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(itemClicked(QTreeWidgetItem *, int))); connect(this, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(itemChanged(QTreeWidgetItem *, int))); connect(&actionAddItem, SIGNAL(triggered()), this, SLOT(on_actionAddItem_triggered())); connect(&actionAddNode, SIGNAL(triggered()), this, SLOT(on_actionAddNode_triggered())); connect(&actionRemove, SIGNAL(triggered()), this, SLOT(on_actionRemove_triggered())); connect(&actionExpandAll, SIGNAL(triggered()), this, SLOT(expandAll())); connect(&actionCollapseAll, SIGNAL(triggered()), this, SLOT(collapseAll())); read_only_name = read_only_value = read_only_type = read_only_comment = false; c_hidden << false << false << false << false; pi = c_pi = 0; translate(); setQPIConfig(c); } void QPIConfigWidget::changeEvent(QEvent * e) { QTreeWidget::changeEvent(e); if (e->type() == QEvent::LanguageChange) { translate(); return; } } bool QPIConfigWidget::eventFilter(QObject * o, QEvent * e) { if (e->type() == QEvent::MouseButtonPress) { if (viewport() == qobject_cast(o)) { pi = itemAt(((QMouseEvent *)e)->pos()); if (((QMouseEvent *)e)->buttons() == Qt::RightButton) { qApp->processEvents(); itemClicked(pi, 1); popupMenu.popup( #if QT_VERSION_MAJOR <= 5 ((QMouseEvent *)e)->globalPos() #else ((QMouseEvent *)e)->globalPosition().toPoint() #endif ); } } } return QTreeWidget::eventFilter(o, e); } void QPIConfigWidget::itemClicked(QTreeWidgetItem * item, int column) { if (item) { if ((column == 0 && !read_only_name) || (column == 3 && !read_only_comment)) { item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); } else { item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); } } bool node = true, ro = read_only_name || read_only_type || read_only_value; if (item) { if (itemTWidget(item)) { if (itemTWidget(item)->isEnabled()) { node = false; } } } actionAddItem.setVisible(node && !ro); actionAddNode.setVisible(node && !ro); actionRemove.setVisible(!ro && !selectedItems().isEmpty()); } void QPIConfigWidget::itemChanged(QTreeWidgetItem * item, int column) { if (item != c_pi) { c_pi = item; if (item) { c_name = item->text(0); c_comment = item->text(3); } return; } if (item == nullptr) { return; } if (c_name == item->text(0) && c_comment == item->text(3)) { return; } // qDebug() << "change" << item->text(0); QPIConfig::Entry * e = itemEntry(item); if (e == nullptr) { return; } if (column == 0) { buildFullNames(item); e->setName(item->text(column)); conf->buildFullNames(e->parent()); // qDebug() << itemCWidget(item)->full_name; } if (column == 3) { e->setComment(item->text(column)); } c_name = item->text(0); c_comment = item->text(3); emit changed(); } void QPIConfigWidget::typeChange(int t, UComboBox * c) { auto cw = reinterpret_cast(c->property("qpic_widget").toLongLong()); cw->setType(types.key(s_types[t])); conf->getValue(cw->full_name).setType(types.key(s_types[t])); emit changed(); } void QPIConfigWidget::valueChange(ConfigValueWidget * w, QString v) { conf->getValue(w->full_name).setValue(v); emit changed(); } void QPIConfigWidget::on_actionAddItem_triggered() { if (conf == nullptr || !active) { return; } QString fp; if (pi == nullptr) { pi = invisibleRootItem(); } else { fp = itemCWidget(pi)->full_name + conf->delim; } new_dialog.reset(); if (new_dialog.exec() == QDialog::Rejected) { return; } QPIConfig::Entry * e; if (pi->childCount() == 0) { // qDebug() << "pi empty, remove " << itemCWidget(pi)->full_name; conf->removeEntry(itemCWidget(pi)->full_name, false); } // qDebug() << "add " << fp + new_dialog.name(); e = &(conf->addEntry(fp + new_dialog.name(), new_dialog.value().isEmpty() ? "0" : new_dialog.value(), new_dialog.type(), false)); expandItem(pi); pi = addEntry(pi, e); pi->setText(0, new_dialog.name()); pi->setText(3, new_dialog.comment()); int ind = s_types.indexOf(types[new_dialog.type()]); if (ind < 0) { w_types.back()->setCurrentIndex(0); } else { w_types.back()->setCurrentIndex(ind); } emit changed(); } void QPIConfigWidget::on_actionAddNode_triggered() { if (conf == nullptr || !active) { return; } QString fp; if (pi == nullptr) { pi = invisibleRootItem(); } else { fp = itemCWidget(pi)->full_name + conf->delim; } new_dialog.reset(true); if (new_dialog.exec() == QDialog::Rejected) { return; } QPIConfig::Entry e; e._full_name = fp + new_dialog.name(); expandItem(pi); pi = addEntry(pi, &e, true); pi->setText(0, new_dialog.name()); pi->setText(3, new_dialog.comment()); setItemWidget(pi, 2, nullptr); emit changed(); } void QPIConfigWidget::on_actionRemove_triggered() { if (conf == nullptr || !active) { return; } QList si = selectedItems(); conf->buildFullNames(&(conf->root)); QPIConfig::Entry * e; for (QTreeWidgetItem * i: si) { e = itemEntry(i); if (e == nullptr) continue; // qDebug() << "remove " + e->_full_name; conf->removeEntry(e->_full_name, false); deleteEntry(i); } emit changed(); // show(); } void QPIConfigWidget::clear() { if (!active) return; bool hidden = isHidden(); hide(); QTreeWidget::clear(); qDeleteAll(w_values); qDeleteAll(w_types); w_values.clear(); w_types.clear(); if (!hidden) show(); } void QPIConfigWidget::buildTree() { if (!active) return; if (conf == nullptr) return; bool hidden = isHidden(); hide(); clear(); conf->buildFullNames(&(conf->root)); buildEntry(invisibleRootItem(), &conf->rootEntry()); if (!hidden) show(); } void QPIConfigWidget::setReadOnlyValue(bool yes) { read_only_value = yes; for (ConfigValueWidget * i: w_values) { i->setEnabled(!yes); } } void QPIConfigWidget::setReadOnlyType(bool yes) { read_only_type = yes; for (QComboBox * i: w_types) { i->setEnabled(!yes); i->setFrame(!yes); } } void QPIConfigWidget::buildEntry(QTreeWidgetItem * i, QPIConfig::Entry * e) { for (QPIConfig::Entry * j: e->children()) { buildEntry(addEntry(i, j, !j->isLeaf()), j); } } void QPIConfigWidget::buildFullNames(QTreeWidgetItem * i) { ConfigValueWidget *cw, *pw; cw = itemCWidget(i); if (i->parent()) { pw = itemCWidget(i->parent()); cw->full_name = pw->full_name + conf->delim + i->text(0); } else { cw->full_name = i->text(0); } for (int j = 0; j < i->childCount(); ++j) { buildFullNames(i->child(j)); } } QPIConfig::Entry * QPIConfigWidget::itemEntry(QTreeWidgetItem * i) { ConfigValueWidget * cfw = itemCWidget(i); if (!cfw) return nullptr; return &(conf->getValue(cfw->full_name)); } QTreeWidgetItem * QPIConfigWidget::addEntry(QTreeWidgetItem * i, QPIConfig::Entry * e, bool node) { if (conf == nullptr) return nullptr; ti = new QTreeWidgetItem(); ti->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); ti->setSizeHint(0, QSize(26, 26)); ti->setText(0, e->name()); ti->setText(3, e->comment()); w_values.push_back(new ConfigValueWidget); w_values.back()->setEntry(e); w_values.back()->setEnabled(!read_only_value); if (!node) { w_types.push_back(new UComboBox()); w_types.back()->addItems(s_types); w_types.back()->setCurrentIndex(s_types.indexOf(types[e->type().leftJustified(1).left(1)])); w_types.back()->setProperty("qpic_widget", QVariant(reinterpret_cast(w_values.back()))); w_types.back()->setEnabled(!read_only_type); w_types.back()->setFrame(!read_only_type); connect(w_types.back(), SIGNAL(currentIndexChanged(int, UComboBox *)), this, SLOT(typeChange(int, UComboBox *))); } connect(w_values.back(), SIGNAL(changed(ConfigValueWidget *, QString)), this, SLOT(valueChange(ConfigValueWidget *, QString))); i->addChild(ti); setItemWidget(ti, 1, w_values.back()); if (!node) { setItemWidget(ti, 2, w_types.back()); if (itemTWidget(i)) { w_types.remove(w_types.indexOf(itemTWidget(i))); setItemWidget(i, 2, nullptr); } } return ti; } void QPIConfigWidget::deleteEntry(QTreeWidgetItem * i) { ConfigValueWidget * vw; UComboBox * cb; int cc = i->childCount(); for (int j = 0; j < cc; ++j) { deleteEntry(i->child(0)); } vw = qobject_cast(itemWidget(i, 1)); cb = qobject_cast(itemWidget(i, 2)); if (vw) { w_values.remove(w_values.indexOf(vw)); delete vw; } if (cb) { w_types.remove(w_types.indexOf(cb)); delete cb; } delete i; } bool QPIConfigWidget::filter(const QString & f, QTreeWidgetItem * i) { if (i->childCount() == 0) { return filterItem(f, i); } bool found = false; for (int j = 0; j < i->childCount(); ++j) { if (filter(f, i->child(j))) { found = true; } } i->setHidden(!found); return found; } bool QPIConfigWidget::filterItem(const QString & f, QTreeWidgetItem * i) { if (f.isEmpty()) { i->setHidden(false); return true; } bool ret = (!isColumnHidden(0) && i->text(0).indexOf(f, 0, Qt::CaseInsensitive) >= 0) || (!isColumnHidden(1) && itemCWidget(i)->value.indexOf(f, 0, Qt::CaseInsensitive) >= 0) || (!isColumnHidden(3) && i->text(3).indexOf(f, 0, Qt::CaseInsensitive) >= 0); if (itemTWidget(i)) { ret = ret || (!isColumnHidden(2) && itemTWidget(i)->currentText().indexOf(f, 0, Qt::CaseInsensitive) >= 0); } i->setHidden(!ret); return ret; } void QPIConfigWidget::translate() { QStringList l; l << tr("Name") << tr("Value") << tr("Type") << tr("Comment"); if (active) setHeaderLabels(l); types.clear(); s_types.clear(); addTrEntry("s", "string"); addTrEntry("l", "string list"); addTrEntry("n", "integer"); addTrEntry("f", "float"); addTrEntry("b", "boolean"); addTrEntry("c", "color"); addTrEntry("r", "rectangle"); addTrEntry("a", "area"); addTrEntry("p", "point"); addTrEntry("v", "vector"); addTrEntry("i", "ip"); actionAddItem.setText(tr("Add item ...")); actionAddNode.setText(tr("Add node ...")); actionToItem.setText(tr("Convert to item")); actionToNode.setText(tr("Convert to node")); actionRemove.setText(tr("Remove")); actionExpandAll.setText(tr("Expand all")); actionCollapseAll.setText(tr("Collapse all")); if (!active) { return; } for (int i = 0; i < 4; ++i) { setColumnHidden(i, c_hidden[i]); } } QString QPIConfigWidget::writeToString() { if (conf == nullptr) { return QString(); } conf->buildFullNames(&(conf->root)); return conf->writeAllToString(); } void QPIConfigWidget::readFromString(QString str) { if (conf == nullptr) { return; } conf->readAllFromString(str); buildTree(); } UComboBox::UComboBox(QWidget * parent): QComboBox(parent) { connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(indexChange(int))); } void QPIConfigWidget::filter(const QString & f) { if (!active) { return; } filter(f, invisibleRootItem()); } void QPIConfigWidget::write() { if (conf == nullptr) { return; } conf->buildFullNames(&(conf->root)); conf->writeAll(); } void QPIConfigWidget::parse() { if (conf == nullptr) { clear(); } else { conf->readAll(); } } void QPIConfigWidget::setColumnNameVisible(bool yes) { setColumnHidden(0, !yes); c_hidden[0] = !yes; } void QPIConfigWidget::setColumnValueVisible(bool yes) { setColumnHidden(1, !yes); c_hidden[1] = !yes; } void QPIConfigWidget::setColumnCommentVisible(bool yes) { setColumnHidden(3, !yes); c_hidden[3] = !yes; } void QPIConfigWidget::setColumnTypeVisible(bool yes) { setColumnHidden(2, !yes); c_hidden[2] = !yes; } void QPIConfigWidget::setReadOnlyComment(bool yes) { read_only_comment = yes; } void QPIConfigWidget::setReadOnlyName(bool yes) { read_only_name = yes; } ConfigValueWidget * QPIConfigWidget::itemCWidget(QTreeWidgetItem * i) { return qobject_cast(itemWidget(i, 1)); } UComboBox * QPIConfigWidget::itemTWidget(QTreeWidgetItem * i) { return qobject_cast(itemWidget(i, 2)); } void QPIConfigWidget::addTrEntry(const QString & s, const QString & f) { types.insert(s, f); s_types << f; } void QPIConfigWidget::setQPIConfig(QPIConfig * c) { conf = c; buildTree(); } void UComboBox::indexChange(int i) { emit currentIndexChanged(i, this); }