Experimental json tree view

This commit is contained in:
Jan Käberich 2021-04-10 12:04:07 +02:00
parent ba62925b67
commit 28c9fe25b3
3 changed files with 305 additions and 0 deletions

View File

@ -0,0 +1,183 @@
#include "jsonpickerdialog.h"
#include "ui_jsonpickerdialog.h"
JSONPickerDialog::JSONPickerDialog(const nlohmann::json &json, QWidget *parent) :
QDialog(parent),
ui(new Ui::JSONPickerDialog),
model(new JSONModel(json))
{
ui->setupUi(this);
ui->treeView->setModel(model);
}
JSONPickerDialog::~JSONPickerDialog()
{
delete ui;
delete model;
}
JSONModel::JSONModel(const nlohmann::json &json, QObject *parent) :
json(json)
{
setupJsonInfo(json);
}
JSONModel::~JSONModel()
{
}
QModelIndex JSONModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
nlohmann::json const *parentItem;
if (!parent.isValid())
parentItem = &json;
else
parentItem = static_cast<nlohmann::json*>(parent.internalPointer());
auto it = parentItem->begin();
int rb = row;
while(rb) {
it++;
rb--;
}
nlohmann::json *childItem = const_cast<nlohmann::json*>(&*it);
if (childItem)
return createIndex(row, column, childItem);
return QModelIndex();
}
QModelIndex JSONModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
nlohmann::json *childItem = static_cast<nlohmann::json*>(index.internalPointer());
if (childItem == &json) {
return QModelIndex();
}
// find the parent of this entry and its position in the list
nlohmann::json *parentItem = const_cast<nlohmann::json*>(jsonInfo.at(childItem).parent);
auto it = parentItem->begin();
int row = 0;
while(&*it != childItem) {
it++;
row++;
}
return createIndex(row, 0, parentItem);
}
int JSONModel::rowCount(const QModelIndex &parent) const
{
const nlohmann::json *parentItem;
if (parent.column() > 0) {
return 0;
}
if (!parent.isValid()) {
parentItem = &json;
} else {
parentItem = static_cast<nlohmann::json*>(parent.internalPointer());
}
if (parentItem->is_object() || parentItem->is_array()) {
return parentItem->size();
} else {
return 0;
}
}
int JSONModel::columnCount(const QModelIndex &parent) const
{
return 2;
}
QVariant JSONModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
nlohmann::json *item = static_cast<nlohmann::json*>(index.internalPointer());
auto info = jsonInfo.at(item);
switch(role) {
case Qt::DisplayRole:
switch(index.column()) {
case 0:
return info.name;
case 1:
if(item->is_object() || item->is_array()) {
return QVariant();
} else {
return info.data;
}
}
case Qt::CheckStateRole: {
if(index.column() == 0) {
return info.enabled ? Qt::Checked : Qt::Unchecked;
} else {
return QVariant();
}
}
default:
return QVariant();
}
}
QVariant JSONModel::headerData(int section, Qt::Orientation orientation, int role) const
{
return QVariant();
}
bool JSONModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
nlohmann::json *item = static_cast<nlohmann::json*>(index.internalPointer());
auto info = jsonInfo.at(item);
if(role == Qt::CheckStateRole)
{
info.enabled = !info.enabled;
jsonInfo[item] = info;
emit dataChanged(index, index);
return true;
}
if (role != Qt::EditRole)
return false;
return true;
}
Qt::ItemFlags JSONModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) {
return Qt::NoItemFlags;
}
return Qt::ItemIsEditable | QAbstractItemModel::flags(index)|Qt::ItemIsUserCheckable;
}
void JSONModel::setupJsonInfo(const nlohmann::json &j)
{
for(auto it = j.begin();it != j.end(); it++) {
JSONInfo i;
i.parent = &j;
i.enabled = true;
if(j.is_object()) {
i.name = it.key().c_str();
} else if(j.is_array()) {
i.name = QString::number(it - j.begin() + 1);
}
if(it->is_object() || it->is_array()) {
setupJsonInfo(*it);
} else {
i.data = QString::fromStdString(it->dump());
}
jsonInfo[&*it] = i;
}
}

View File

@ -0,0 +1,55 @@
#ifndef JSONPICKERDIALOG_H
#define JSONPICKERDIALOG_H
#include <QDialog>
#include <QAbstractItemModel>
#include "json.hpp"
namespace Ui {
class JSONPickerDialog;
}
class JSONModel : public QAbstractItemModel
{
Q_OBJECT
public:
JSONModel(const nlohmann::json &json, QObject *parent = 0);
~JSONModel();
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
private:
void setupJsonInfo(const nlohmann::json &j);
const nlohmann::json &json;
class JSONInfo {
public:
const nlohmann::json *parent;
QString name;
QString data;
bool enabled;
};
std::map<const nlohmann::json*, JSONInfo> jsonInfo;
};
class JSONPickerDialog : public QDialog
{
Q_OBJECT
public:
explicit JSONPickerDialog(const nlohmann::json &json, QWidget *parent = nullptr);
~JSONPickerDialog();
private:
Ui::JSONPickerDialog *ui;
JSONModel *model;
};
#endif // JSONPICKERDIALOG_H

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>JSONPickerDialog</class>
<widget class="QDialog" name="JSONPickerDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="treeView"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>JSONPickerDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>JSONPickerDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>