How to avoid to delete treemodel info when editing?











up vote
2
down vote

favorite
1












Good morning. I have finally created a treeconfig program to read a txt, then edit it in the interface, and then save it, but I have a problem.



I know that there is a treemodel example that is editable (http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html), but this one is not using libconfig.h++



I decided to use libconfig.h++ in my linux because I can filter which kind of information is appearing in the values (int/string/...), because in the other example without libconfig, it uses qVariant, and accept all the types of inputs.



So even comparing with the other example, I am not able to make the following work:
My problem is that when I try to edit one value, the information inside dissapears, and if I click outside the value, it becomes 0. How can I avoid this both things? I want to edit a string in the middle for example, or just not to delete then info when missclicking or something.



The images below show an attempt at editing the value for confTimeout. Note that the text inside disappears when it is clicked into edit-mode and that the text sets to 0 when it is clicked out of focus.









mainwindow.cpp



#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QTextStream>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

void MainWindow::setConfig(libconfig::Config *config)
{
tm = std::make_unique<TreeModel>(config, this);
ui->treeView->setModel(tm.get());
}

MainWindow::~MainWindow()
{
delete ui;
}

/*
void MainWindow::on_treeView_activated(const QModelIndex &index)
{
QString val = ui->treeView->model()->data(index).toString();
ui->lineEdit->setText(val);
}

*/

void MainWindow::on_pushButton_clicked()
{
tm->saveSettings();
}


treeitem.cpp



#include "treeitem.h"
#include <libconfig.h++>

static QVariant getIndexOrName(const libconfig::Setting &setting)
{
if (!setting.isRoot()) {
const auto &parent = setting.getParent();
if (parent.isArray() || parent.isList())
return setting.getIndex();
}

return setting.getName();
}

static QVariant getValueOrSize(const libconfig::Setting &setting)
{
using namespace libconfig;
switch (setting.getType()) {
// scalar types
case Setting::TypeInt:
return setting.operator int();

case Setting::TypeInt64:
return setting.operator long long();

case Setting::TypeFloat:
return setting.operator double();

case Setting::TypeString:
return setting.c_str();

case Setting::TypeBoolean:
return setting.operator bool();


// aggregate types
case Setting::TypeGroup:
return QString{"Group. Size: %1"}.arg(setting.getLength());

case Setting::TypeArray:
return QString{"Array. Size: %1"}.arg(setting.getLength());

case Setting::TypeList:
return QString{"List. Size: %1"}.arg(setting.getLength());


// not used
case Setting::TypeNone:
break;
}

return QVariant{};
}

static bool setValue(libconfig::Setting &setting, const QVariant &value)
{
using namespace libconfig;
switch (setting.getType()) {
// scalar types
case Setting::TypeInt:
if (value.canConvert(QVariant::Int)) {
setting = value.toInt();
return true;
}
case Setting::TypeInt64:
if (value.canConvert(QVariant::LongLong)) {
setting = value.toLongLong();
return true;
}
case Setting::TypeFloat:
if (value.canConvert(QVariant::Double)) {
setting = value.toFloat();
return true;
}
case Setting::TypeString:
if (value.canConvert(QVariant::String)) {
setting = value.toString().toStdString();
return true;
}
case Setting::TypeBoolean:
if (value.canConvert(QVariant::Bool)) {
setting = value.toBool();
return true;
}
default:
break;
}

return false;
}

TreeItem::TreeItem(libconfig::Setting *setting, TreeItem *parentItem)
: m_setting{setting}, m_parentItem{parentItem}
{
if (setting->isAggregate()) {
for (auto &setting : *setting) {
m_subSettings.push_back(new TreeItem(&setting, this));
}
}
}

TreeItem::~TreeItem() { qDeleteAll(m_subSettings); }

TreeItem *TreeItem::child(int row) { return m_subSettings.at(row); }

int TreeItem::childCount() const { return m_subSettings.size(); }

int TreeItem::columnCount() const { return 2; }

QVariant TreeItem::data(int column) const
{
switch (column) {
case 0:
return getIndexOrName(*m_setting);
case 1:
return getValueOrSize(*m_setting);
default:
return QVariant{};
}
}

bool TreeItem::setData(const QVariant &value)
{
if (m_setting->isAggregate())
return false;

return setValue(*m_setting, value);
}

int TreeItem::row() const
{
if (!m_parentItem)
return 0;

return m_parentItem->m_subSettings.indexOf(const_cast<TreeItem *>(this));
}

TreeItem *TreeItem::parentItem() { return m_parentItem; }


treemodel



    #include "treemodel.h"
#include "treeitem.h"

#include <QFile>
#include <libconfig.h++>
#include <QDateTime>

TreeModel::TreeModel(libconfig::Config *config, QObject *parent)
: QAbstractItemModel{parent}, m_rootSetting{std::make_unique<TreeItem>(
&(config->getRoot()), nullptr)}, m_config{config}
{
}

TreeModel::~TreeModel()
{
}

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole)
return QVariant();

TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

return item->data(index.column());
}

bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;

if (role != Qt::EditRole)
return false;

TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->setData(value);
}

Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{

if (!index.isValid())
//return Qt::NoItemFlags;
return 0;

//return QAbstractItemModel::flags(index);
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}

QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
return QVariant{};

switch (section) {
case 0:
return "Name";
case 1:
return "Value";
default:
return QVariant{};
}
}

QModelIndex TreeModel::index(int row, int column,
const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();

TreeItem *parentItem;

if (!parent.isValid())
parentItem = m_rootSetting.get();
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());

TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}

QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();

TreeItem *childItem = static_cast<TreeItem *>(index.internalPointer());
TreeItem *parentItem = childItem->parentItem();

if (parentItem == m_rootSetting.get())
return QModelIndex();

return createIndex(parentItem->row(), 0, parentItem);
}

int TreeModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (parent.column() > 0)
return 0;

if (!parent.isValid())
parentItem = m_rootSetting.get();
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());

return parentItem->childCount();
}

int TreeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
else
return m_rootSetting->columnCount();
}

bool TreeModel::saveSettings(QString filename) const
{
if (filename.isEmpty())
filename = QString::fromLocal8Bit(m_config->getRoot().getSourceFile());
QString today = QDateTime::currentDateTime().toString("_yyyy.MM.dd_hh:mm");
QFile::copy(filename, filename+today+".backup");
try {
m_config->writeFile(filename.toLocal8Bit().constData());
} catch (...) {
return false;
}

return true;
}


o



o



o



o



EDIT:::



First of all, thanks @vahancho and @trebuchetMS
.
I have tried with vahancho example, but it throws an issue



enter image description here



Also I tried with with other combinations, but he idea is not to allow for example a "string" where a "int" should be placed.



I have also checked again the editableTreeModel of QtExamples, but it allows a string where a int should be placed, and I do not want this



QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();

TreeItem *item = getItem(index);

return item->data(index.column());
}


Any idea?










share|improve this question
























  • QVariant... can also filter which type is being used.
    – TrebuchetMS
    Nov 14 at 11:55












  • May I ask what is the use of if (role != Qt::EditRole) return false; in TreeModel::setData()? Also the example provided uses if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();. In your TreeModel::data(), role != Qt::EditRole was removed. Is there explanation for this as well?
    – TrebuchetMS
    Nov 14 at 12:05










  • you could publish your project on github and thus be able to test your code easily
    – eyllanesc
    Nov 15 at 17:41










  • I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
    – Minikornio
    Nov 16 at 11:46

















up vote
2
down vote

favorite
1












Good morning. I have finally created a treeconfig program to read a txt, then edit it in the interface, and then save it, but I have a problem.



I know that there is a treemodel example that is editable (http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html), but this one is not using libconfig.h++



I decided to use libconfig.h++ in my linux because I can filter which kind of information is appearing in the values (int/string/...), because in the other example without libconfig, it uses qVariant, and accept all the types of inputs.



So even comparing with the other example, I am not able to make the following work:
My problem is that when I try to edit one value, the information inside dissapears, and if I click outside the value, it becomes 0. How can I avoid this both things? I want to edit a string in the middle for example, or just not to delete then info when missclicking or something.



The images below show an attempt at editing the value for confTimeout. Note that the text inside disappears when it is clicked into edit-mode and that the text sets to 0 when it is clicked out of focus.









mainwindow.cpp



#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QTextStream>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

void MainWindow::setConfig(libconfig::Config *config)
{
tm = std::make_unique<TreeModel>(config, this);
ui->treeView->setModel(tm.get());
}

MainWindow::~MainWindow()
{
delete ui;
}

/*
void MainWindow::on_treeView_activated(const QModelIndex &index)
{
QString val = ui->treeView->model()->data(index).toString();
ui->lineEdit->setText(val);
}

*/

void MainWindow::on_pushButton_clicked()
{
tm->saveSettings();
}


treeitem.cpp



#include "treeitem.h"
#include <libconfig.h++>

static QVariant getIndexOrName(const libconfig::Setting &setting)
{
if (!setting.isRoot()) {
const auto &parent = setting.getParent();
if (parent.isArray() || parent.isList())
return setting.getIndex();
}

return setting.getName();
}

static QVariant getValueOrSize(const libconfig::Setting &setting)
{
using namespace libconfig;
switch (setting.getType()) {
// scalar types
case Setting::TypeInt:
return setting.operator int();

case Setting::TypeInt64:
return setting.operator long long();

case Setting::TypeFloat:
return setting.operator double();

case Setting::TypeString:
return setting.c_str();

case Setting::TypeBoolean:
return setting.operator bool();


// aggregate types
case Setting::TypeGroup:
return QString{"Group. Size: %1"}.arg(setting.getLength());

case Setting::TypeArray:
return QString{"Array. Size: %1"}.arg(setting.getLength());

case Setting::TypeList:
return QString{"List. Size: %1"}.arg(setting.getLength());


// not used
case Setting::TypeNone:
break;
}

return QVariant{};
}

static bool setValue(libconfig::Setting &setting, const QVariant &value)
{
using namespace libconfig;
switch (setting.getType()) {
// scalar types
case Setting::TypeInt:
if (value.canConvert(QVariant::Int)) {
setting = value.toInt();
return true;
}
case Setting::TypeInt64:
if (value.canConvert(QVariant::LongLong)) {
setting = value.toLongLong();
return true;
}
case Setting::TypeFloat:
if (value.canConvert(QVariant::Double)) {
setting = value.toFloat();
return true;
}
case Setting::TypeString:
if (value.canConvert(QVariant::String)) {
setting = value.toString().toStdString();
return true;
}
case Setting::TypeBoolean:
if (value.canConvert(QVariant::Bool)) {
setting = value.toBool();
return true;
}
default:
break;
}

return false;
}

TreeItem::TreeItem(libconfig::Setting *setting, TreeItem *parentItem)
: m_setting{setting}, m_parentItem{parentItem}
{
if (setting->isAggregate()) {
for (auto &setting : *setting) {
m_subSettings.push_back(new TreeItem(&setting, this));
}
}
}

TreeItem::~TreeItem() { qDeleteAll(m_subSettings); }

TreeItem *TreeItem::child(int row) { return m_subSettings.at(row); }

int TreeItem::childCount() const { return m_subSettings.size(); }

int TreeItem::columnCount() const { return 2; }

QVariant TreeItem::data(int column) const
{
switch (column) {
case 0:
return getIndexOrName(*m_setting);
case 1:
return getValueOrSize(*m_setting);
default:
return QVariant{};
}
}

bool TreeItem::setData(const QVariant &value)
{
if (m_setting->isAggregate())
return false;

return setValue(*m_setting, value);
}

int TreeItem::row() const
{
if (!m_parentItem)
return 0;

return m_parentItem->m_subSettings.indexOf(const_cast<TreeItem *>(this));
}

TreeItem *TreeItem::parentItem() { return m_parentItem; }


treemodel



    #include "treemodel.h"
#include "treeitem.h"

#include <QFile>
#include <libconfig.h++>
#include <QDateTime>

TreeModel::TreeModel(libconfig::Config *config, QObject *parent)
: QAbstractItemModel{parent}, m_rootSetting{std::make_unique<TreeItem>(
&(config->getRoot()), nullptr)}, m_config{config}
{
}

TreeModel::~TreeModel()
{
}

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole)
return QVariant();

TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

return item->data(index.column());
}

bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;

if (role != Qt::EditRole)
return false;

TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->setData(value);
}

Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{

if (!index.isValid())
//return Qt::NoItemFlags;
return 0;

//return QAbstractItemModel::flags(index);
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}

QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
return QVariant{};

switch (section) {
case 0:
return "Name";
case 1:
return "Value";
default:
return QVariant{};
}
}

QModelIndex TreeModel::index(int row, int column,
const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();

TreeItem *parentItem;

if (!parent.isValid())
parentItem = m_rootSetting.get();
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());

TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}

QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();

TreeItem *childItem = static_cast<TreeItem *>(index.internalPointer());
TreeItem *parentItem = childItem->parentItem();

if (parentItem == m_rootSetting.get())
return QModelIndex();

return createIndex(parentItem->row(), 0, parentItem);
}

int TreeModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (parent.column() > 0)
return 0;

if (!parent.isValid())
parentItem = m_rootSetting.get();
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());

return parentItem->childCount();
}

int TreeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
else
return m_rootSetting->columnCount();
}

bool TreeModel::saveSettings(QString filename) const
{
if (filename.isEmpty())
filename = QString::fromLocal8Bit(m_config->getRoot().getSourceFile());
QString today = QDateTime::currentDateTime().toString("_yyyy.MM.dd_hh:mm");
QFile::copy(filename, filename+today+".backup");
try {
m_config->writeFile(filename.toLocal8Bit().constData());
} catch (...) {
return false;
}

return true;
}


o



o



o



o



EDIT:::



First of all, thanks @vahancho and @trebuchetMS
.
I have tried with vahancho example, but it throws an issue



enter image description here



Also I tried with with other combinations, but he idea is not to allow for example a "string" where a "int" should be placed.



I have also checked again the editableTreeModel of QtExamples, but it allows a string where a int should be placed, and I do not want this



QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();

TreeItem *item = getItem(index);

return item->data(index.column());
}


Any idea?










share|improve this question
























  • QVariant... can also filter which type is being used.
    – TrebuchetMS
    Nov 14 at 11:55












  • May I ask what is the use of if (role != Qt::EditRole) return false; in TreeModel::setData()? Also the example provided uses if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();. In your TreeModel::data(), role != Qt::EditRole was removed. Is there explanation for this as well?
    – TrebuchetMS
    Nov 14 at 12:05










  • you could publish your project on github and thus be able to test your code easily
    – eyllanesc
    Nov 15 at 17:41










  • I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
    – Minikornio
    Nov 16 at 11:46















up vote
2
down vote

favorite
1









up vote
2
down vote

favorite
1






1





Good morning. I have finally created a treeconfig program to read a txt, then edit it in the interface, and then save it, but I have a problem.



I know that there is a treemodel example that is editable (http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html), but this one is not using libconfig.h++



I decided to use libconfig.h++ in my linux because I can filter which kind of information is appearing in the values (int/string/...), because in the other example without libconfig, it uses qVariant, and accept all the types of inputs.



So even comparing with the other example, I am not able to make the following work:
My problem is that when I try to edit one value, the information inside dissapears, and if I click outside the value, it becomes 0. How can I avoid this both things? I want to edit a string in the middle for example, or just not to delete then info when missclicking or something.



The images below show an attempt at editing the value for confTimeout. Note that the text inside disappears when it is clicked into edit-mode and that the text sets to 0 when it is clicked out of focus.









mainwindow.cpp



#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QTextStream>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

void MainWindow::setConfig(libconfig::Config *config)
{
tm = std::make_unique<TreeModel>(config, this);
ui->treeView->setModel(tm.get());
}

MainWindow::~MainWindow()
{
delete ui;
}

/*
void MainWindow::on_treeView_activated(const QModelIndex &index)
{
QString val = ui->treeView->model()->data(index).toString();
ui->lineEdit->setText(val);
}

*/

void MainWindow::on_pushButton_clicked()
{
tm->saveSettings();
}


treeitem.cpp



#include "treeitem.h"
#include <libconfig.h++>

static QVariant getIndexOrName(const libconfig::Setting &setting)
{
if (!setting.isRoot()) {
const auto &parent = setting.getParent();
if (parent.isArray() || parent.isList())
return setting.getIndex();
}

return setting.getName();
}

static QVariant getValueOrSize(const libconfig::Setting &setting)
{
using namespace libconfig;
switch (setting.getType()) {
// scalar types
case Setting::TypeInt:
return setting.operator int();

case Setting::TypeInt64:
return setting.operator long long();

case Setting::TypeFloat:
return setting.operator double();

case Setting::TypeString:
return setting.c_str();

case Setting::TypeBoolean:
return setting.operator bool();


// aggregate types
case Setting::TypeGroup:
return QString{"Group. Size: %1"}.arg(setting.getLength());

case Setting::TypeArray:
return QString{"Array. Size: %1"}.arg(setting.getLength());

case Setting::TypeList:
return QString{"List. Size: %1"}.arg(setting.getLength());


// not used
case Setting::TypeNone:
break;
}

return QVariant{};
}

static bool setValue(libconfig::Setting &setting, const QVariant &value)
{
using namespace libconfig;
switch (setting.getType()) {
// scalar types
case Setting::TypeInt:
if (value.canConvert(QVariant::Int)) {
setting = value.toInt();
return true;
}
case Setting::TypeInt64:
if (value.canConvert(QVariant::LongLong)) {
setting = value.toLongLong();
return true;
}
case Setting::TypeFloat:
if (value.canConvert(QVariant::Double)) {
setting = value.toFloat();
return true;
}
case Setting::TypeString:
if (value.canConvert(QVariant::String)) {
setting = value.toString().toStdString();
return true;
}
case Setting::TypeBoolean:
if (value.canConvert(QVariant::Bool)) {
setting = value.toBool();
return true;
}
default:
break;
}

return false;
}

TreeItem::TreeItem(libconfig::Setting *setting, TreeItem *parentItem)
: m_setting{setting}, m_parentItem{parentItem}
{
if (setting->isAggregate()) {
for (auto &setting : *setting) {
m_subSettings.push_back(new TreeItem(&setting, this));
}
}
}

TreeItem::~TreeItem() { qDeleteAll(m_subSettings); }

TreeItem *TreeItem::child(int row) { return m_subSettings.at(row); }

int TreeItem::childCount() const { return m_subSettings.size(); }

int TreeItem::columnCount() const { return 2; }

QVariant TreeItem::data(int column) const
{
switch (column) {
case 0:
return getIndexOrName(*m_setting);
case 1:
return getValueOrSize(*m_setting);
default:
return QVariant{};
}
}

bool TreeItem::setData(const QVariant &value)
{
if (m_setting->isAggregate())
return false;

return setValue(*m_setting, value);
}

int TreeItem::row() const
{
if (!m_parentItem)
return 0;

return m_parentItem->m_subSettings.indexOf(const_cast<TreeItem *>(this));
}

TreeItem *TreeItem::parentItem() { return m_parentItem; }


treemodel



    #include "treemodel.h"
#include "treeitem.h"

#include <QFile>
#include <libconfig.h++>
#include <QDateTime>

TreeModel::TreeModel(libconfig::Config *config, QObject *parent)
: QAbstractItemModel{parent}, m_rootSetting{std::make_unique<TreeItem>(
&(config->getRoot()), nullptr)}, m_config{config}
{
}

TreeModel::~TreeModel()
{
}

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole)
return QVariant();

TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

return item->data(index.column());
}

bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;

if (role != Qt::EditRole)
return false;

TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->setData(value);
}

Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{

if (!index.isValid())
//return Qt::NoItemFlags;
return 0;

//return QAbstractItemModel::flags(index);
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}

QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
return QVariant{};

switch (section) {
case 0:
return "Name";
case 1:
return "Value";
default:
return QVariant{};
}
}

QModelIndex TreeModel::index(int row, int column,
const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();

TreeItem *parentItem;

if (!parent.isValid())
parentItem = m_rootSetting.get();
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());

TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}

QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();

TreeItem *childItem = static_cast<TreeItem *>(index.internalPointer());
TreeItem *parentItem = childItem->parentItem();

if (parentItem == m_rootSetting.get())
return QModelIndex();

return createIndex(parentItem->row(), 0, parentItem);
}

int TreeModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (parent.column() > 0)
return 0;

if (!parent.isValid())
parentItem = m_rootSetting.get();
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());

return parentItem->childCount();
}

int TreeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
else
return m_rootSetting->columnCount();
}

bool TreeModel::saveSettings(QString filename) const
{
if (filename.isEmpty())
filename = QString::fromLocal8Bit(m_config->getRoot().getSourceFile());
QString today = QDateTime::currentDateTime().toString("_yyyy.MM.dd_hh:mm");
QFile::copy(filename, filename+today+".backup");
try {
m_config->writeFile(filename.toLocal8Bit().constData());
} catch (...) {
return false;
}

return true;
}


o



o



o



o



EDIT:::



First of all, thanks @vahancho and @trebuchetMS
.
I have tried with vahancho example, but it throws an issue



enter image description here



Also I tried with with other combinations, but he idea is not to allow for example a "string" where a "int" should be placed.



I have also checked again the editableTreeModel of QtExamples, but it allows a string where a int should be placed, and I do not want this



QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();

TreeItem *item = getItem(index);

return item->data(index.column());
}


Any idea?










share|improve this question















Good morning. I have finally created a treeconfig program to read a txt, then edit it in the interface, and then save it, but I have a problem.



I know that there is a treemodel example that is editable (http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html), but this one is not using libconfig.h++



I decided to use libconfig.h++ in my linux because I can filter which kind of information is appearing in the values (int/string/...), because in the other example without libconfig, it uses qVariant, and accept all the types of inputs.



So even comparing with the other example, I am not able to make the following work:
My problem is that when I try to edit one value, the information inside dissapears, and if I click outside the value, it becomes 0. How can I avoid this both things? I want to edit a string in the middle for example, or just not to delete then info when missclicking or something.



The images below show an attempt at editing the value for confTimeout. Note that the text inside disappears when it is clicked into edit-mode and that the text sets to 0 when it is clicked out of focus.









mainwindow.cpp



#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QTextStream>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

void MainWindow::setConfig(libconfig::Config *config)
{
tm = std::make_unique<TreeModel>(config, this);
ui->treeView->setModel(tm.get());
}

MainWindow::~MainWindow()
{
delete ui;
}

/*
void MainWindow::on_treeView_activated(const QModelIndex &index)
{
QString val = ui->treeView->model()->data(index).toString();
ui->lineEdit->setText(val);
}

*/

void MainWindow::on_pushButton_clicked()
{
tm->saveSettings();
}


treeitem.cpp



#include "treeitem.h"
#include <libconfig.h++>

static QVariant getIndexOrName(const libconfig::Setting &setting)
{
if (!setting.isRoot()) {
const auto &parent = setting.getParent();
if (parent.isArray() || parent.isList())
return setting.getIndex();
}

return setting.getName();
}

static QVariant getValueOrSize(const libconfig::Setting &setting)
{
using namespace libconfig;
switch (setting.getType()) {
// scalar types
case Setting::TypeInt:
return setting.operator int();

case Setting::TypeInt64:
return setting.operator long long();

case Setting::TypeFloat:
return setting.operator double();

case Setting::TypeString:
return setting.c_str();

case Setting::TypeBoolean:
return setting.operator bool();


// aggregate types
case Setting::TypeGroup:
return QString{"Group. Size: %1"}.arg(setting.getLength());

case Setting::TypeArray:
return QString{"Array. Size: %1"}.arg(setting.getLength());

case Setting::TypeList:
return QString{"List. Size: %1"}.arg(setting.getLength());


// not used
case Setting::TypeNone:
break;
}

return QVariant{};
}

static bool setValue(libconfig::Setting &setting, const QVariant &value)
{
using namespace libconfig;
switch (setting.getType()) {
// scalar types
case Setting::TypeInt:
if (value.canConvert(QVariant::Int)) {
setting = value.toInt();
return true;
}
case Setting::TypeInt64:
if (value.canConvert(QVariant::LongLong)) {
setting = value.toLongLong();
return true;
}
case Setting::TypeFloat:
if (value.canConvert(QVariant::Double)) {
setting = value.toFloat();
return true;
}
case Setting::TypeString:
if (value.canConvert(QVariant::String)) {
setting = value.toString().toStdString();
return true;
}
case Setting::TypeBoolean:
if (value.canConvert(QVariant::Bool)) {
setting = value.toBool();
return true;
}
default:
break;
}

return false;
}

TreeItem::TreeItem(libconfig::Setting *setting, TreeItem *parentItem)
: m_setting{setting}, m_parentItem{parentItem}
{
if (setting->isAggregate()) {
for (auto &setting : *setting) {
m_subSettings.push_back(new TreeItem(&setting, this));
}
}
}

TreeItem::~TreeItem() { qDeleteAll(m_subSettings); }

TreeItem *TreeItem::child(int row) { return m_subSettings.at(row); }

int TreeItem::childCount() const { return m_subSettings.size(); }

int TreeItem::columnCount() const { return 2; }

QVariant TreeItem::data(int column) const
{
switch (column) {
case 0:
return getIndexOrName(*m_setting);
case 1:
return getValueOrSize(*m_setting);
default:
return QVariant{};
}
}

bool TreeItem::setData(const QVariant &value)
{
if (m_setting->isAggregate())
return false;

return setValue(*m_setting, value);
}

int TreeItem::row() const
{
if (!m_parentItem)
return 0;

return m_parentItem->m_subSettings.indexOf(const_cast<TreeItem *>(this));
}

TreeItem *TreeItem::parentItem() { return m_parentItem; }


treemodel



    #include "treemodel.h"
#include "treeitem.h"

#include <QFile>
#include <libconfig.h++>
#include <QDateTime>

TreeModel::TreeModel(libconfig::Config *config, QObject *parent)
: QAbstractItemModel{parent}, m_rootSetting{std::make_unique<TreeItem>(
&(config->getRoot()), nullptr)}, m_config{config}
{
}

TreeModel::~TreeModel()
{
}

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole)
return QVariant();

TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

return item->data(index.column());
}

bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;

if (role != Qt::EditRole)
return false;

TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->setData(value);
}

Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{

if (!index.isValid())
//return Qt::NoItemFlags;
return 0;

//return QAbstractItemModel::flags(index);
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}

QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
return QVariant{};

switch (section) {
case 0:
return "Name";
case 1:
return "Value";
default:
return QVariant{};
}
}

QModelIndex TreeModel::index(int row, int column,
const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();

TreeItem *parentItem;

if (!parent.isValid())
parentItem = m_rootSetting.get();
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());

TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}

QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();

TreeItem *childItem = static_cast<TreeItem *>(index.internalPointer());
TreeItem *parentItem = childItem->parentItem();

if (parentItem == m_rootSetting.get())
return QModelIndex();

return createIndex(parentItem->row(), 0, parentItem);
}

int TreeModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (parent.column() > 0)
return 0;

if (!parent.isValid())
parentItem = m_rootSetting.get();
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());

return parentItem->childCount();
}

int TreeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
else
return m_rootSetting->columnCount();
}

bool TreeModel::saveSettings(QString filename) const
{
if (filename.isEmpty())
filename = QString::fromLocal8Bit(m_config->getRoot().getSourceFile());
QString today = QDateTime::currentDateTime().toString("_yyyy.MM.dd_hh:mm");
QFile::copy(filename, filename+today+".backup");
try {
m_config->writeFile(filename.toLocal8Bit().constData());
} catch (...) {
return false;
}

return true;
}


o



o



o



o



EDIT:::



First of all, thanks @vahancho and @trebuchetMS
.
I have tried with vahancho example, but it throws an issue



enter image description here



Also I tried with with other combinations, but he idea is not to allow for example a "string" where a "int" should be placed.



I have also checked again the editableTreeModel of QtExamples, but it allows a string where a int should be placed, and I do not want this



QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();

TreeItem *item = getItem(index);

return item->data(index.column());
}


Any idea?







c++ qt qt5 qtreeview libconfig






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 16 at 11:44

























asked Nov 14 at 11:28









Minikornio

172




172












  • QVariant... can also filter which type is being used.
    – TrebuchetMS
    Nov 14 at 11:55












  • May I ask what is the use of if (role != Qt::EditRole) return false; in TreeModel::setData()? Also the example provided uses if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();. In your TreeModel::data(), role != Qt::EditRole was removed. Is there explanation for this as well?
    – TrebuchetMS
    Nov 14 at 12:05










  • you could publish your project on github and thus be able to test your code easily
    – eyllanesc
    Nov 15 at 17:41










  • I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
    – Minikornio
    Nov 16 at 11:46




















  • QVariant... can also filter which type is being used.
    – TrebuchetMS
    Nov 14 at 11:55












  • May I ask what is the use of if (role != Qt::EditRole) return false; in TreeModel::setData()? Also the example provided uses if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();. In your TreeModel::data(), role != Qt::EditRole was removed. Is there explanation for this as well?
    – TrebuchetMS
    Nov 14 at 12:05










  • you could publish your project on github and thus be able to test your code easily
    – eyllanesc
    Nov 15 at 17:41










  • I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
    – Minikornio
    Nov 16 at 11:46


















QVariant... can also filter which type is being used.
– TrebuchetMS
Nov 14 at 11:55






QVariant... can also filter which type is being used.
– TrebuchetMS
Nov 14 at 11:55














May I ask what is the use of if (role != Qt::EditRole) return false; in TreeModel::setData()? Also the example provided uses if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();. In your TreeModel::data(), role != Qt::EditRole was removed. Is there explanation for this as well?
– TrebuchetMS
Nov 14 at 12:05




May I ask what is the use of if (role != Qt::EditRole) return false; in TreeModel::setData()? Also the example provided uses if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();. In your TreeModel::data(), role != Qt::EditRole was removed. Is there explanation for this as well?
– TrebuchetMS
Nov 14 at 12:05












you could publish your project on github and thus be able to test your code easily
– eyllanesc
Nov 15 at 17:41




you could publish your project on github and thus be able to test your code easily
– eyllanesc
Nov 15 at 17:41












I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
– Minikornio
Nov 16 at 11:46






I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
– Minikornio
Nov 16 at 11:46














1 Answer
1






active

oldest

votes

















up vote
0
down vote













I think the problem is that your TreeModel::data() function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.



To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:



QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

// Returns the same data both in display and edit modes.
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
return item->data(index.column());
}
return QAbstractItemModel::data(index, role);
}





share|improve this answer





















  • it should have been && instead of this || !! now it works
    – Minikornio
    Nov 30 at 14:42











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53299167%2fhow-to-avoid-to-delete-treemodel-info-when-editing%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote













I think the problem is that your TreeModel::data() function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.



To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:



QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

// Returns the same data both in display and edit modes.
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
return item->data(index.column());
}
return QAbstractItemModel::data(index, role);
}





share|improve this answer





















  • it should have been && instead of this || !! now it works
    – Minikornio
    Nov 30 at 14:42















up vote
0
down vote













I think the problem is that your TreeModel::data() function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.



To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:



QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

// Returns the same data both in display and edit modes.
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
return item->data(index.column());
}
return QAbstractItemModel::data(index, role);
}





share|improve this answer





















  • it should have been && instead of this || !! now it works
    – Minikornio
    Nov 30 at 14:42













up vote
0
down vote










up vote
0
down vote









I think the problem is that your TreeModel::data() function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.



To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:



QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

// Returns the same data both in display and edit modes.
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
return item->data(index.column());
}
return QAbstractItemModel::data(index, role);
}





share|improve this answer












I think the problem is that your TreeModel::data() function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.



To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:



QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

// Returns the same data both in display and edit modes.
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
return item->data(index.column());
}
return QAbstractItemModel::data(index, role);
}






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 15 at 7:31









vahancho

15.3k32430




15.3k32430












  • it should have been && instead of this || !! now it works
    – Minikornio
    Nov 30 at 14:42


















  • it should have been && instead of this || !! now it works
    – Minikornio
    Nov 30 at 14:42
















it should have been && instead of this || !! now it works
– Minikornio
Nov 30 at 14:42




it should have been && instead of this || !! now it works
– Minikornio
Nov 30 at 14:42


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53299167%2fhow-to-avoid-to-delete-treemodel-info-when-editing%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

How to change which sound is reproduced for terminal bell?

Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

Can I use Tabulator js library in my java Spring + Thymeleaf project?