Serializing JSON data Qt - c++

I'm using Qt and trying to take the following and convert it into JSON text, but when I attempt to compile it I get a symbols not found for architecture error.
I'm currently using the builtin Qt Json library as I do not know how to get QJson to work and compile statically into the code so that there are no dependencies.
// Create the message body
QVariantMap message;
message.insert("date", QDate::currentDate().toString());
message.insert("eventType", eventName);
message.insert("payload", messagePayload);
// Initialize the Serializer
QJson::Serializer serializer;
bool ok;
// Serialize the data
QByteArray json = serializer.serialize(message, &ok);
The compiler output is the following:
Undefined symbols for architecture x86_64:
"QJson::Serializer::serialize(QVariant const&, bool*)", referenced from:
SWebsocketClient::sendMessage(QString, QMap<QString, QVariant>) in swebsocketclient.o
Is this kindof the right way to do this, or is there a much better? I know this question has been asked elsewhere, however most of the articles linked to in other answers do not exist anymore.

You can always use this JSON library instead:
/*
* qvjson.h
*
* Created on: Apr 23, 2010
* Author: drh
*/
#ifndef QVJSON_H_
#define QVJSON_H_
#include <QMap>
#include <QList>
#include <QVariant>
#include <QRegExp>
class QvJson {
public:
QvJson();
virtual ~QvJson();
QVariant parseJson(const QString& jsonString);
// The jsonObject is a QVariant that may be a --
// -- QMap<QString, QVariant>
// -- QList<QVariant>
// -- QString
// -- integer
// -- real number
// -- bool
// -- null (implemented as a QVariant() object)
// Where QVariant appears in the above list, it may recursively
// be one of the above.
QString encodeJson(const QVariant& jsonObject);
private:
enum Error {
ErrorUnrecognizedToken,
ErrorMustBeString,
ErrorMissingColon,
ErrorMissingCommaOrClose,
ErrorNoClosingQuote,
ErrorEndOfInput,
ErrorInvalidNumericValue,
ErrorInvalidHexValue,
ErrorUnrecognizedObject
};
QRegExp mNonBlank;
QRegExp mFindQuote;
QString nextToken(const QString& jsonString, int& position);
QString peekToken(const QString& jsonString, int position);
QVariant parseInternal(const QString& jsonString, int& position, int nesting);
QVariant parseObject(const QString& jsonString, int& position, int nesting);
QVariant parseArray(const QString& jsonString, int& position, int nesting);
QVariant parseString(const QString& jsonString, int& position, int nesting);
QVariant parseBool(const QString& jsonString, int& position, int nesting);
QVariant parseNull(const QString& jsonString, int& position, int nesting);
QVariant parseNumber(const QString& jsonString, int& position, int nesting);
QVariant syntaxError(const QString& method, const QString& jsonString, int position, int nesting, Error error);
QString encodeObject(const QVariant& jsonObject);
QString encodeArray(const QVariant& jsonObject);
QString encodeString(const QVariant& jsonObject);
QString encodeString(const QString& value);
QString encodeNumeric(const QVariant& jsonObject);
QString encodeBool(const QVariant& jsonObject);
QString encodeNull(const QVariant& jsonObject);
QString encodingError(const QString& method, const QVariant& jsonObject, Error error);
};
#endif /* QVJSON_H_ */
/*
* qvjson.cpp
*
* Created on: Apr 23, 2010
* Author: drh
*/
#include "qvjson.h"
#include <QStringList>
#include <QMessageBox>
QvJson::QvJson() {
mNonBlank = QRegExp("\\S", Qt::CaseSensitive, QRegExp::RegExp);
mFindQuote = QRegExp("[^\\\\]\"", Qt::CaseSensitive, QRegExp::RegExp);
}
QvJson::~QvJson()
{
// TODO Auto-generated destructor stub
}
QVariant QvJson::parseJson(const QString& jsonString) {
int position = 0;
QVariant result;
result = parseInternal(jsonString, position, 0);
if (result.type() == QVariant::StringList) {
QMessageBox::critical(NULL, "", result.toString());
}
QString token(nextToken(jsonString, position));
if (!token.isEmpty()) {
QMessageBox::critical(NULL, "", QObject::tr("Invalid JSON string -- remaining token %1 at position %2.").arg(token).arg(position));
}
return result;
}
QString QvJson::nextToken(const QString& jsonString, int& position) {
if (position >= jsonString.count()) {
return QString();
}
while (jsonString.at(position) == ' ') {
position++;
if (position >= jsonString.count()) {
return QString();
}
}
if (jsonString.at(position).isLetter()) {
if (position + 4 < jsonString.count()) {
QString word = jsonString.mid(position, 4);
if ((word == "true") || (word == "null")) {
position += 4;
while (position < jsonString.count() && jsonString.at(position) == ' ') {
position++;
}
return word;
}
if ((word == "fals") && (position + 5 < jsonString.count()) && jsonString.at(position + 4) == 'e') {
position += 5;
while (position < jsonString.count() && jsonString.at(position) == ' ') {
position++;
}
return "false";
}
}
}
QString result = QString(jsonString.at(position));
position++;
while (position < jsonString.count() && jsonString.at(position) == ' ') {
position++;
}
return result;
}
// By virtue of its non-& position parm, this method "peeks" at the token without consuming it.
QString QvJson::peekToken(const QString& jsonString, int position) {
return (nextToken(jsonString, position));
}
QVariant QvJson::parseInternal(const QString& jsonString, int& position, int nesting) {
QString token(peekToken(jsonString, position));
QVariant result;
int startPosition = position; // For debug
Q_UNUSED(startPosition);
if (token.isNull()) {
result = syntaxError("parseInternal", jsonString, position, nesting + 1, ErrorEndOfInput);
}
else if (token == "{") {
result = parseObject(jsonString, position, nesting + 1);
}
else if (token == "[") {
result = parseArray(jsonString, position, nesting + 1);
}
else if (token == "\"") {
result = parseString(jsonString, position, nesting + 1);
}
else if ((token == "true") || (token == "false")) {
result = parseBool(jsonString, position, nesting + 1);
}
else if (token == "null") {
result = parseNull(jsonString, position, nesting + 1);
}
else if ((token == "-") || (token.at(0).isDigit())) {
result = parseNumber(jsonString, position, nesting + 1);
}
else {
result = syntaxError("parseInternal", jsonString, position, nesting + 1, ErrorUnrecognizedToken);
}
return result;
}
QVariant QvJson::parseObject(const QString& jsonString, int& position, int nesting) {
QMap<QString, QVariant> resultObject;
QString token;
int startPosition = position; // For debug
Q_UNUSED(startPosition);
token = nextToken(jsonString, position);
Q_ASSERT(token == "{");
// Handle case of empty object
token = peekToken(jsonString, position);
if (token == '}') {
return QVariant(resultObject);
}
do {
// Next item must be a string
token = peekToken(jsonString, position);
if (token != "\"") {
return syntaxError("parseObject", jsonString, position, nesting + 1, ErrorMustBeString);
}
QVariant propName;
propName = parseString(jsonString, position, nesting + 1);
// Check for error
if (propName.type() == QVariant::StringList) {
QStringList propNameError(propName.toStringList());
propNameError << QObject::tr("in parseObject(%1,%2)").arg(position).arg(nesting);
return QVariant(propNameError);
}
// Expect a ":"
token = nextToken(jsonString, position);
if (token != ":") {
return syntaxError("parseObject", jsonString, position, nesting + 1, ErrorMissingColon);
}
// Now get the value
QVariant propValue;
propValue = parseInternal(jsonString, position, nesting + 1);
// Check for error
if (propValue.type() == QVariant::StringList) {
QStringList propValueError(propValue.toStringList());
propValueError << QObject::tr("in parseObject(%1,%2)").arg(position).arg(nesting);
return QVariant(propValueError);
}
resultObject[propName.toString()] = propValue;
// Next token must be a "," or "}"
token = nextToken(jsonString, position);
if (token == "}") {
return QVariant(resultObject);
}
else if (token != ",") {
return syntaxError("parseObject", jsonString, position, nesting + 1, ErrorMissingCommaOrClose);
}
} while (true);
}
QVariant QvJson::parseArray(const QString& jsonString, int& position, int nesting) {
QList<QVariant> resultArray;
QString token;
token = nextToken(jsonString, position);
Q_ASSERT(token == "[");
// Handle case of empty object
token = peekToken(jsonString, position);
if (token == ']') {
return QVariant(resultArray);
}
do {
// Get the element of the array
QVariant propValue;
propValue = parseInternal(jsonString, position, nesting + 1);
// Check for error
if (propValue.type() == QVariant::StringList) {
QStringList propValueError(propValue.toStringList());
propValueError << QObject::tr("in parseObject(%1,%2)").arg(position).arg(nesting);
return QVariant(propValueError);
}
resultArray << propValue;
// Next token must be a "," or "]"
token = nextToken(jsonString, position);
if (token == "]") {
return QVariant(resultArray);
}
else if (token != ",") {
return syntaxError("parseArray", jsonString, position, nesting + 1, ErrorMissingCommaOrClose);
}
} while (true);
}
QVariant QvJson::parseString(const QString& jsonString, int& position, int nesting) {
QString result;
// Skip over the double quote character
Q_ASSERT(jsonString.at(position) == '"');
position++;
do {
if (position >= jsonString.count()) {
return syntaxError("parseString", jsonString, position, nesting, ErrorNoClosingQuote);
}
if (jsonString.at(position) == '"') {
break;
}
if (jsonString.at(position) == '\\') {
position++;
if (position >= jsonString.count()) {
return syntaxError("parseString", jsonString, position, nesting, ErrorNoClosingQuote);
}
switch (jsonString.at(position).unicode()) {
case 'b':
result.append('\b');
break;
case 'f':
result.append('\f');
break;
case 'n':
result.append('\n');
break;
case 'r':
result.append('\r');
break;
case 't':
result.append('\t');
break;
case 'u':
{
if (position + 4 >= jsonString.count()) {
return syntaxError("parseString", jsonString, position, nesting, ErrorNoClosingQuote);
}
QString hex = jsonString.mid(position + 1, 4);
bool ok;
int value = hex.toInt(&ok, 16);
if (!ok) {
return syntaxError("parseString", jsonString, position+1, nesting, ErrorInvalidHexValue);
}
result.append(QChar(value));
position += 4;
}
default:
result.append(jsonString.at(position));
}
position++;
}
else {
result.append(jsonString.at(position));
position++;
}
} while(true);
Q_ASSERT(jsonString.at(position) == '"');
position++;
return QVariant(result);
}
QVariant QvJson::parseBool(const QString& jsonString, int& position, int nesting) {
bool resultBool;
QString token;
token = nextToken(jsonString, position);
if (token == "true") {
resultBool = true;
}
else if (token == "false") {
resultBool = false;
}
else {
Q_ASSERT(false);
}
return QVariant(resultBool);
}
QVariant QvJson::parseNull(const QString& jsonString, int& position, int nesting) {
QString token;
token = nextToken(jsonString, position);
Q_ASSERT(token == "null");
Q_UNUSED(token);
return QVariant();
}
QVariant QvJson::parseNumber(const QString& jsonString, int& position, int nesting) {
int startPosition = position;
// Allow a leading minus sign
if (jsonString.at(position) == '-') position++;
if (position >= jsonString.count()) {
return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorEndOfInput);
}
// Allow one or more decimal digits
if (!jsonString.at(position).isDigit()) {
return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue);
}
while (position < jsonString.count() && jsonString.at(position).isDigit()) {
position++;
}
if (position >= jsonString.count() ||
(jsonString.at(position) != '.' && jsonString.at(position) != 'e' && jsonString.at(position) != 'E')) {
bool ok = false;
int resultInt = jsonString.mid(startPosition, position - startPosition).toInt(&ok);
if (!ok) {
return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue);
}
return QVariant(resultInt);
}
// Consume any fraction part
if (jsonString.at(position) == '.') {
position++;
while (position < jsonString.count() && jsonString.at(position).isDigit()) {
position++;
}
}
// Consume any exponent part
if (jsonString.at(position) == 'e' || jsonString.at(position) == 'E') {
position++;
// Consume +/- if present
if (jsonString.at(position) == '+' || jsonString.at(position) == '-') {
position++;
}
// Must have at least one digit
if (!jsonString.at(position).isDigit()) {
return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue);
}
while (position < jsonString.count() && jsonString.at(position).isDigit()) {
position++;
}
}
// Should have a valid floating point value at this point
bool ok = false;
qreal resultReal = jsonString.mid(startPosition, position - startPosition).toDouble(&ok);
if (!ok) {
return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue);
}
return QVariant(resultReal);
}
QVariant QvJson::syntaxError(const QString& method, const QString& jsonString, int position, int nesting, Error error) {
QString text;
switch (error) {
case ErrorInvalidNumericValue:
text = QObject::tr("Invalid numeric value");
break;
case ErrorInvalidHexValue:
text = QObject::tr("Invalid hex value");
break;
case ErrorEndOfInput:
text = QObject::tr("Unexpected end of input");
break;
case ErrorNoClosingQuote:
text = QObject::tr("No closing quote for literal string");
break;
case ErrorMissingColon:
text = QObject::tr("Missing ':' between attribute name and value");
break;
case ErrorMissingCommaOrClose:
text = QObject::tr("Missing comma, '}', or ']'");
break;
case ErrorMustBeString:
text = QObject::tr("The name of an attribute must be a valid character string");
break;
case ErrorUnrecognizedToken:
text = QObject::tr("The token was not recognized");
break;
default:
Q_ASSERT(false);
}
QString errorMsg = QObject::tr("*** Error %1 in QvJson::%2 at position %3 -- %4").arg(error).arg(method).arg(position).arg(text);
QStringList errorList;
errorList << errorMsg;
return QVariant(errorList);
}
QString QvJson::encodeJson(const QVariant& jsonObject) {
QVariant::Type type = jsonObject.type();
switch (type) {
case QVariant::Map:
return encodeObject(jsonObject);
case QVariant::List:
return encodeArray(jsonObject);
case QVariant::String:
return encodeString(jsonObject);
case QVariant::Int:
case QVariant::Double:
return encodeNumeric(jsonObject);
case QVariant::Bool:
return encodeBool(jsonObject);
case QVariant::Invalid:
return encodeNull(jsonObject);
default:
return encodingError("encodeJson", jsonObject, ErrorUnrecognizedObject);
}
}
QString QvJson::encodeObject(const QVariant& jsonObject) {
QString result("{ ");
QMap<QString, QVariant> map = jsonObject.toMap();
QMapIterator<QString, QVariant> i(map);
while (i.hasNext()) {
i.next();
result.append(encodeString(i.key()));
result.append(" : ");
result.append(encodeJson(i.value()));
if (i.hasNext()) {
result.append(", ");
}
}
result.append(" }");
return result;
}
QString QvJson::encodeArray(const QVariant& jsonObject) {
QString result("[ ");
QList<QVariant> list = jsonObject.toList();
for (int i = 0; i < list.count(); i++) {
result.append(encodeJson(list.at(i)));
if (i+1 < list.count()) {
result.append(", ");
}
}
result.append(" ]");
return result;
}
QString QvJson::encodeString(const QVariant &jsonObject) {
return encodeString(jsonObject.toString());
}
QString QvJson::encodeString(const QString& value) {
QString result = "\"";
for (int i = 0; i < value.count(); i++) {
ushort chr = value.at(i).unicode();
if (chr < 32) {
switch (chr) {
case '\b':
result.append("\\b");
break;
case '\f':
result.append("\\f");
break;
case '\n':
result.append("\\n");
break;
case '\r':
result.append("\\r");
break;
case '\t':
result.append("\\t");
break;
default:
result.append("\\u");
result.append(QString::number(chr, 16).rightJustified(4, '0'));
} // End switch
}
else if (chr > 255) {
result.append("\\u");
result.append(QString::number(chr, 16).rightJustified(4, '0'));
}
else {
result.append(value.at(i));
}
}
result.append('"');
QString displayResult = result; // For debug, since "result" often doesn't show
Q_UNUSED(displayResult);
return result;
}
QString QvJson::encodeNumeric(const QVariant& jsonObject) {
return jsonObject.toString();
}
QString QvJson::encodeBool(const QVariant& jsonObject) {
return jsonObject.toString();
}
QString QvJson::encodeNull(const QVariant& jsonObject) {
return "null";
}
QString QvJson::encodingError(const QString& method, const QVariant& jsonObject, Error error) {
QString text;
switch (error) {
case ErrorUnrecognizedObject:
text = QObject::tr("Unrecognized object type");
break;
default:
Q_ASSERT(false);
}
return QObject::tr("*** Error %1 in QvJson::%2 -- %3").arg(error).arg(method).arg(text);
}

Related

How to make selected checkbox Item color to Green in QT?

how to make selected items turn into green?
QVariant DomModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
DomItem *item = static_cast<DomItem*>(index.internalPointer());
const QDomNode node = item->node();
if ( role == Qt::CheckStateRole && (index.column() == 0) && hasChildren(index) )
{
return static_cast< int >( item->isChecked() ? Qt::Checked : Qt::Unchecked );
}
if (role == Qt::FontRole && item->isChecked()) {
QFont font;
font.setBold(true);
return font;
}
if (role != Qt::DisplayRole)
return QVariant();
switch (index.column()) {
case 0:
return node.nodeName();
case 1:
{
const QDomNamedNodeMap attributeMap = node.attributes();
QStringList attributes;
for (int i = 0; i < attributeMap.count(); ++i) {
QDomNode attribute = attributeMap.item(i);
attributes << attribute.nodeName() + "=\""
+ attribute.nodeValue() + '"';
}
return attributes.join(' ');
}
case 2:
return node.nodeValue().split('\n').join(' ');
default:
break;
}
return item->data(index.column());
}
In the role I have done Items which is selected to be Bold when checked, But how change that fonts color to green which is checked?
Please Look at this Image:
Take a look at role BackgroundRole:
if (role == Qt::BackgroundRole)
{
return QColor(Qt::lightGray);
}

How to write optimized constructor in a class >

I wrote writing an email class, but I am not sure if this is the best way to write this... here's the code for it...
class email
{
string value;
string domain;
string com;
string username;
string encrypted;
bool state ;
public:
email(const string& val)
:value{ val}, state{false},com(),domain(),username(),encrypted()
{
for (int i = 0; i < value.size(); ++i)
{
if (value[i] == '#')
{
username = value.substr(0, i);
for (int j = i; j < value.size(); ++j)
{
if (value[j] == '.')
{
domain = value.substr(i, j);
com = value.substr(j+1, value.size()-1);
state = true;
}
}
}
}
if (state)
{
for (auto letter : value)
{
if (letter == ';' || letter == '\'' || letter == '[' || letter == ']')
{
state = false;
}
}
} else throw "invalid string";
if (state)
{
encrypted = username;
for (int i = 0; i < username.size() / 2; ++i)
{
swap(encrypted[i], encrypted[encrypted.size() - 1 - i]);
encrypted[i] = static_cast<char>(static_cast<int>(encrypted[i]) + 3);
}
}else throw "invalid charecters";
}
const string& get_domain() { return domain; }
const string& get_username() { return username; }
const string& get_com() { return com; }
const string& get_enc() { return encrypted; }
const bool good () const { return state; }
};
It's not completed yet, this is just a quick sketch from what I can remember because I don't have the actual code right now, my question is should I make another class to support the email class.. or is this the right way? I wrote a lot of code inside the constructor, that's what I am worried about.
You could break the for loops, if you have done your stuff.
First for: after you found '#' you do not have to loop to the end
Third for: after you found an error, you could throw immediatelly

DragDrop on QTableView not working

I hame the following class that basically contains an std::vector<PassoProgramma>, and constitutes the model for a QTableView.
~ Programma.h ~
#ifndef PROGRAMMA_H
#define PROGRAMMA_H
#include <vector>
#include "PassoProgramma.h"
#include <QString>
#include <string>
#include <QAbstractTableModel>
#include <QFont>
class Programma : public QAbstractTableModel
{
Q_OBJECT
public:
Programma(QString, std::vector<PassoProgramma>, std::map<unsigned char, Asse>* const);
Programma(const std::string, std::map<unsigned char, Asse>* const);
void salva(const std::string, const std::string = "");
int sizeHintForRow() const ;
bool isIndexValid(const QModelIndex& index) const;
inline std::string getNome() const { return nome; };
inline std::vector<PassoProgramma>* const getPassi() { return &Passi; }
inline bool isSalvato() const { return salvato; }
int rowCount(const QModelIndex&) const override;
int columnCount(const QModelIndex&) const override;
QVariant data(const QModelIndex&, int) const override;
QVariant headerData(int, Qt::Orientation, int) const override;
bool dropMimeData(const QMimeData*, Qt::DropAction , int , int , const QModelIndex&) override;
bool removeRows(int, int, const QModelIndex&) override;
bool insertRows(int, int, const QModelIndex&) override;
bool moveRows(const QModelIndex&, const int, const int, const QModelIndex&, int) override;
QMimeData* mimeData(const QModelIndexList&) const override;
Qt::DropActions supportedDropActions() const override;
Qt::ItemFlags flags(const QModelIndex&) const override;
bool setData(const QModelIndex&, const QVariant&, int) override;
QStringList mimeTypes() const override;
PassoProgramma* operator[](int i)
{
if(i < Passi.size()) return &Passi.at(i);
else throw new std::exception();
};
static const QFont headerFont;
static const QFont dataFont;
private:
struct myLocale : std::numpunct<char>
{
protected :
char do_thousands_sep() const override { return '\0' ; }
char do_decimal_point() const override { return '.' ; }
std::string do_grouping() const override { return "" ; }
};
std::vector<PassoProgramma> Passi;
std::string nome;
bool salvato;
std::map<unsigned char, Asse>* const assi;
};
class ELoadException : public std::exception
{
private:
std::string message_;
public:
ELoadException(const std::string& message) : message_(message) {};
virtual const char* what() const throw()
{
return message_.c_str();
}
};
#endif
~ Programma.cpp ~
#include "Programma.h"
#include "Editor.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>
#include <regex>
#include <QSize>
#include <QMimeData>
#include <QDataStream>
const QFont Programma::headerFont("Open Sans", 17, QFont::Weight::DemiBold);
const QFont Programma::dataFont("Open Sans", 22, QFont::Weight::DemiBold);
inline std::string& ltrim(std::string& str, const std::string& chars = "\t\v\f ")
{
str.erase(0, str.find_first_not_of(chars));
return str;
}
inline std::string& rtrim(std::string& str, const std::string& chars = "\t\v\f ")
{
str.erase(str.find_last_not_of(chars) + 1);
return str;
}
inline std::string& trim(std::string& str, const std::string& chars = "\t\v\f ")
{
return ltrim(rtrim(str, chars), chars);
}
Programma::Programma(QString nome, std::vector<PassoProgramma> passi, std::map<unsigned char, Asse>* const assi) : Passi(passi), assi(assi)
{
this->nome = nome.toStdString();
}
Programma::Programma(std::string fileFullName, std::map<unsigned char, Asse>* const assi) : assi(assi)
{
std::ifstream stream;
try
{
stream.open(fileFullName, std::ios::in);
}
catch(std::exception& e)
{
std::stringstream st;
st << "Error opening file \"" << fileFullName << "\".\nError: " << e.what();
throw ELoadException(st.str());
}
int slash = fileFullName.find_last_of("/");
nome = fileFullName.substr(slash + 1);
Passi.reserve(100);
std::string line;
char* token;
unsigned int lineCount = 0, tokenCount;
while(std::getline(stream, line)) // Per ogni linea del file estraggo fino a 6 token
{
if(trim(line).length() == 0) continue;
// Controllo che la linea appena letta dal file contenga esattamente 2, 4 o 6 coppie <lettera, float>.
if(!std::regex_match(line, std::regex(R"(^(?:[A-Z] [-+]?[0-9]+(?:\.[0-9]+)?(?: |$)){1,3}$)")))
{
std::stringstream st;
st << "Line #" << lineCount << " of file \"" << fileFullName << "\" is invalid.";
throw ELoadException(st.str());
}
++lineCount;
PassoProgramma passo;
tokenCount = 0;
char* cstr = new char[line.length() + 1];
std::strcpy(cstr, line.c_str()); // Converto la stringa costante in char* non costante, per poterla fornire a strtok.
token = strtok(cstr, " ");
while(token)
{
++tokenCount;
switch(tokenCount)
{
case 1:
passo.asse1 = &assi->at(token[0]);
break;
case 2:
{
std::istringstream iStr(token);
iStr >> passo.target1;
break;
}
case 3:
passo.asse2 = &assi->at(token[0]);
break;
case 4:
{
std::istringstream iStr(token);
iStr >> passo.target2;
break;
}
case 5:
passo.asse3 = &assi->at(token[0]);
break;
case 6:
{
std::istringstream iStr(token);
iStr >> passo.target3;
break;
}
}
token = strtok(NULL, " "); // Vado al prossimo token senza cambiare la stringa da dividere
}
Passi.push_back(passo);
}
salvato = true;
}
void Programma::salva(const std::string path, const std::string nome /* facoltativo; se specificato costituir?? il nome del file */)
{
if(nome != "")
this->nome = nome;
std::stringstream destFileFullName("");
destFileFullName << path << "/" << this->nome << ".prg";
std::ofstream f;
f.imbue(std::locale(std::locale("en_US.UTF-8"), new Programma::myLocale()));
try
{
f.open(destFileFullName.str());
}
catch(std::exception& e)
{
std::stringstream st;
st << "Error writing to file \"" << st.str() << "\".\nError: " << e.what();
throw ELoadException(st.str());
}
for(const PassoProgramma& passo : Passi)
{
f << passo.toString() << std::endl;
}
// f.flush();
f.close();
salvato = true;
}
int Programma::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return Passi.size();
}
int Programma::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return 6;
}
QVariant Programma::data(const QModelIndex& index, int role) const
{
if(!index.isValid())
return QVariant();
if(role == Qt::TextAlignmentRole)
{
return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
}
else if(role == Qt::DisplayRole || role == Qt::EditRole)
{
switch(index.column())
{
case 0:
return QString(Passi.at(index.row()).asse1->asse);
break;
case 1:
return QString::number(Passi.at(index.row()).target1, 'f', Passi.at(index.row()).asse1->getCifreDecimali()).replace("-", Editor::MENO);
break;
case 2:
return (Passi.at(index.row()).getNumeroAssi() < 2) ? QVariant() : QString(Passi.at(index.row()).asse2->asse);
break;
case 3:
return (Passi.at(index.row()).getNumeroAssi() < 2) ? QVariant() : QString::number(Passi.at(index.row()).target2, 'f', Passi.at(index.row()).asse2->getCifreDecimali()).replace("-", Editor::MENO);
break;
case 4:
return (Passi.at(index.row()).getNumeroAssi() < 3) ? QVariant() : QString(Passi.at(index.row()).asse3->asse);
break;
case 5:
return (Passi.at(index.row()).getNumeroAssi() < 3) ? QVariant() : QString::number(Passi.at(index.row()).target3, 'f', Passi.at(index.row()).asse3->getCifreDecimali()).replace("-", Editor::MENO);
break;
}
}
else if(role == Qt::SizeHintRole)
{
switch(index.column())
{
case 0:
case 2:
case 4:
return QSize(50, 42);
case 1:
case 3:
case 5:
return QSize(105, 42);
}
}
else if(role == Qt::FontRole) return dataFont;
return QVariant();
}
QVariant Programma::headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
{
if(Qt::Orientation::Horizontal == orientation)
{
if(role == Qt::DisplayRole)
{
switch(section)
{
case 0:
case 2:
case 4:
return QString("ASSE");
case 1:
case 3:
case 5:
return QString("TARGET");
}
}
else if(role == Qt::TextAlignmentRole)
{
return Qt::AlignCenter;
}
else if(role == Qt::FontRole) return headerFont;
else if(role == Qt::SizeHintRole)
{
switch(section)
{
case 0:
case 2:
case 4: return QSize(50, 28);
case 1:
case 3:
case 5: return QSize(105, 28);
}
}
}
else
{
if(role == Qt::DisplayRole)
{
return QString::number(section + 1);
}
else if(role == Qt::TextAlignmentRole)
{
return Qt::AlignRight;
}
/*
else if(role == Qt::SizeHintRole)
{
return QSize(45, 45);
}
*/
else if(role == Qt::FontRole) return headerFont;
}
return QVariant();
}
int Programma::sizeHintForRow() const
{
return 42;
}
bool Programma::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
{
QByteArray encodedData = data->data("application/text");
QDataStream stream(&encodedData, QIODevice::ReadOnly);
QStringList newItems;
int rows = 0;
// I dati contengono una stringa multilinea: devo dividerli nelle varie linee.
while(!stream.atEnd())
{
QString text;
stream >> text;
newItems << text;
++rows;
}
// Divido ogni linea nei token di cui รจ composta.
for(int i = 0; i < rows; i++)
{
PassoProgramma nuovoPasso;
int tokenCount = 0;
std::string token(strtok(&(newItems[i].toStdString()[0]), " "));
while(token.length() > 0)
{
++tokenCount;
switch(tokenCount)
{
case 1:
nuovoPasso.asse1 = &assi->at(token[0]);;
break;
case 2:
{
nuovoPasso.target1 = std::stof(token);
break;
}
case 3:
nuovoPasso.asse2 = &assi->at(token[0]);
break;
case 4:
{
nuovoPasso.target2 = std::stof(token);
break;
}
case 5:
nuovoPasso.asse3 = &assi->at(token[0]);
break;
case 6:
{
nuovoPasso.target3 = std::stof(token);
break;
}
}
token = strtok(NULL, " "); // Va al prossimo token senza modificare la stringa da dividere
}
Passi.insert(Passi.begin() + row, nuovoPasso);
}
salvato = false;
return true;
}
bool Programma::removeRows(int row, int count, const QModelIndex& parent = QModelIndex())
{
if(row < 0 || row >= Passi.size() || count <= 0 || (row + count) > Passi.size())
{
return false;
}
beginRemoveRows(parent, row, row + count - 1);
Passi.erase(Passi.begin() + row, Passi.begin() + row + count);
endRemoveRows();
salvato = false;
return true;
}
bool Programma::insertRows(int row, int count, const QModelIndex& parent = QModelIndex())
{
if(row < 0 || count < 0 || row + count >= Passi.size())
{
return false;
}
beginInsertRows(parent, row, row + count - 1);
for(int i = 0; i < count; i++)
{
Passi.insert(Passi.begin() + row, PassoProgramma());
}
endInsertRows();
return true;
}
bool Programma::moveRows(const QModelIndex& sourceParent, const int sourceRow, const int count, const QModelIndex& destinationParent, int destinationChild)
{
for(int i = 0; i < count; ++i)
{
PassoProgramma toBeMoved = Passi.at(sourceRow + i);
Passi.insert(Passi.begin() + destinationChild + i, toBeMoved);
Passi.erase(Passi.begin() + sourceRow + i);
}
salvato = false;
return true;
}
QMimeData* Programma::mimeData(const QModelIndexList& indexes) const
{
QMimeData* mimeData = new QMimeData();
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
foreach(const QModelIndex& index, indexes)
{
if(index.isValid())
{
stream << Passi.at(index.row()).toString().c_str() << '\n';
}
}
mimeData->setData("application/text", encodedData);
return mimeData;
}
Qt::DropActions Programma::supportedDropActions() const
{
return Qt::MoveAction;
}
Qt::ItemFlags Programma::flags(const QModelIndex& index) const
{
if(index.isValid())
{
if(index.column() < 2 && Passi[index.row()].getNumeroAssi() == 0
|| index.column() < 4 && Passi[index.row()].getNumeroAssi() == 1
|| Passi[index.row()].getNumeroAssi() >= 2
)
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsEnabled;
}
return QAbstractItemModel::flags(index) & ~Qt::ItemIsEnabled;
}
bool Programma::setData(const QModelIndex& index, const QVariant& value, int role)
{
if(index.isValid() && role == Qt::EditRole)
{
switch(index.column())
{
case 0: Passi[index.row()].asse1 = &assi->at(value.toString()[0].toLatin1());
break;
case 1: Passi[index.row()].target1 = value.toString().replace(Editor::MENO, "-").toFloat();
break;
case 2: Passi[index.row()].asse2 = &assi->at(value.toString()[0].toLatin1());
break;
case 3: Passi[index.row()].target2 = value.toString().replace(Editor::MENO, "-").toFloat();
break;
case 4: Passi[index.row()].asse3 = &assi->at(value.toString()[0].toLatin1());
break;
case 5: Passi[index.row()].target3 = value.toString().replace(Editor::MENO, "-").toFloat();
break;
}
salvato = false;
emit dataChanged(index, index);
return true;
}
else return false;
}
bool Programma::isIndexValid(const QModelIndex& index) const
{
return index.row() >= 0 && index.row() < Passi.size() && index.isValid();
}
QStringList Programma::mimeTypes() const
{
return QStringList() << "application/text";
}
As you can see, I have overridden (and then implemented in Programma.cpp) all the basic events for moving, deleting and creating rows.
I have a button which deletes the current row and one that inserts a new row; furthermore, I wish to reorder the rows via drag&drop.
The aforementioned two buttons do work, but the drag&drop feature isn't working: the rows of the table do move, but none of the methods moveRows, mimeData and dropMimeData ever gets called. In consequence of this, the row header numbers follow the respective data; instead the headers should be renumebred automatically after each dragdrop.
Why does this happen?
I stitched to the examples provided in the Qt5 documentation.
Maybe my problem is trivial, but I'm developing in C++11 under Linux being a total newbie in both. (Only my boss knows why).

Make tree from mathematical expression by std::regex

Programm get string like:VARIABLE=EXPRESSION.
where VARIABLE is some letters and numbers, starting letter
and EXPRESSION is mathematical expression that can include:
1) + or *
2) ( or )
3) numbers (for example, 5; 3.8; 1e+18, 8.41E-10)
4) another names of variables.
I need to turn this into the tree (just in memory) using one regular exprassion.
How can i do this?
Was proposed method:
search for = out of ()
search for + out of ()
search for * out of ()
if somethig found - break expression in 2 parts, else we got number or variable.
Looks pretty simple, but i can't create this expressions.
I'm alse found how to put conditional operator into regular expression.
Mostly, i just need 3 regular exprassions for =, + and *.
Example:
http://i.stack.imgur.com/I8R12.png
As stated by n.m., regular expressions can't deal with nested parentheses. However there are simple alternatives that can parse nested parenthesis, such as recursive descent parsers.
Example:
enum TokenType
{
TTId,
TTNumber,
TTPlus,
TTMinus,
TTTimes,
TTDivide,
TTLParen,
TTRParen,
TTEndOfInput
};
TokenType token = TTEndOfInput;
string tokenValue;
int peekChar();
void nextChar();
void error(string msg); // doesn't return
Value *createConstant(string value);
Value *createReadVariable(string name);
Value *createAdd(Value *l, Value *r);
Value *createSubtract(Value *l, Value *r);
Value *createMultiply(Value *l, Value *r);
Value *createDivide(Value *l, Value *r);
Value *createNegate(Value *l, Value *r);
Value *expression();
void getToken()
{
token = TTEndOfInput;
tokenValue = "";
if(peekChar() == EOF)
return;
if(isalpha(peekChar()))
{
while(isalnum(peekChar()))
{
tokenValue += (char)peekChar();
nextChar();
}
token = TTId;
return;
}
if(isdigit(peekChar()) || peekChar() == '.')
{
while(isdigit(peekChar()))
{
tokenValue += (char)peekChar();
nextChar();
}
if(peekChar() == '.')
{
tokenValue += (char)peekChar();
nextChar();
while(isdigit(peekChar()))
{
tokenValue += (char)peekChar();
nextChar();
}
if(tokenValue == ".")
error("missing digit");
}
if(peekChar() == 'e')
{
tokenValue += (char)peekChar();
nextChar();
if(peekChar() == '+' || peekChar() == '-')
{
tokenValue += (char)peekChar();
nextChar();
}
if(!isdigit(peekChar()))
error("missing digit");
while(isdigit(peekChar()))
{
tokenValue += (char)peekChar();
nextChar();
}
}
token = TTNumber;
return;
}
switch(peekChar())
{
case '+':
token = TTPlus;
nextChar();
return;
case '-':
token = TTMinus;
nextChar();
return;
case '*':
token = TTTimes;
nextChar();
return;
case '/':
token = TTDivide;
nextChar();
return;
case '(':
token = TTLParen;
nextChar();
return;
case ')':
token = TTRParen;
nextChar();
return;
default:
error("invalid charater");
}
}
Value *topLevel()
{
Value *retval;
switch(token)
{
case TTId:
retval = createReadVariable(tokenValue);
getToken();
return retval;
case TTNumber:
retval = createConstant(tokenValue);
getToken();
return retval;
case TTLParen:
getToken();
retval = expression();
if(token != TTRParen)
error("expected )");
getToken();
return retval;
case TTMinus:
getToken();
return createNegate(topLevel());
default:
error("unexpected token");
}
}
Value *mulDiv()
{
Value *retval = topLevel();
while(token == TTTimes || token == TTDivide)
{
TokenType operation = token;
getToken();
Value *rhs = topLevel();
if(operation == TTTimes)
{
retval = createMultiply(retval, rhs);
}
else // operation == TTDivide
{
retval = createDivide(retval, rhs);
}
}
return retval;
}
Value *addSub()
{
Value *retval = mulDiv();
while(token == TTPlus || token == TTMinus)
{
TokenType operation = token;
getToken();
Value *rhs = mulDiv();
if(operation == TTPlus)
{
retval = createAdd(retval, rhs);
}
else // operation == TTMinus
{
retval = createSubtract(retval, rhs);
}
}
return retval;
}
Value *expression()
{
return addSub();
}
void error(string msg)
{
cerr << "error : " << msg << endl;
exit(1);
}
int main()
{
getToken();
Value *expressionTree = expression();
// ...
return 0;
}

QTreeView children are always pointer to the first top level node

I have followed the editableTreeView example provided with Qt and I'm having an interesting problem. Top level items can be added correctly but if I am to give one of them a child, its a pointer to the first top level item.
My code for the QAbstractItemModel is below.
#include "ModelItemNeural.h"
ModelItemNeural::ModelItemNeural(QObject *parent)
: QAbstractItemModel(parent)
{
counta = 0;
rootNode = new NeuralNode();
addNeuralNode(NeuralNode::NEURAL_NETWORK, 0, 0);
}
QModelIndex ModelItemNeural::index(int row, int column, const QModelIndex &parent) const
{
// Out of bounds and null rootNode check.
// if (rootNode == 0 || row < 0 || column < 0)
// {
// return QModelIndex();
// }
if (parent.isValid() && parent.column() != 0)
{
return QModelIndex();
}
NeuralNode* parentNode = nodeFromIndex(parent);
NeuralNode* childNode = parentNode->getInputs().value(row);
if (childNode == 0)
{
return QModelIndex();
}
return createIndex(row, column, childNode);
}
QModelIndex ModelItemNeural::parent(const QModelIndex &child) const
{
NeuralNode* node = nodeFromIndex(child);
if (node == 0)
{
return QModelIndex();
}
NeuralNode* parentNode = node->getParent();
if (parentNode == 0)
{
return QModelIndex();
}
NeuralNode* grandParentNode = parentNode->getParent();
if (grandParentNode == 0)
{
return QModelIndex();
}
int row = grandParentNode->getInputs().indexOf(parentNode);
return createIndex(row, 0, parentNode);
}
QVariant ModelItemNeural::data(const QModelIndex &index, int role) const
{
if (index.isValid() == false)
{
return QVariant();
}
if (role != Qt::DisplayRole)
{
return QVariant();
}
NeuralNode* node = nodeFromIndex(index);
if (node == 0)
{
return QVariant();
}
switch (index.column())
{
case 0:
{
// Stripping the name of the NeuralNode type.
QString name = typeid(node).name();
int index = name.indexOf(" ");
if (index >= 0)
{
name = name.remove(0, index + 1);
}
//return "Test";
return node->getId();
return name;
}
case 1:
{
return node->getWeight();
}
}
return QVariant();
}
QVariant ModelItemNeural::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch (section)
{
case 0:
{
return "Node";
}
case 1:
{
return "Weight";
}
}
}
return QVariant();
}
int ModelItemNeural::rowCount(const QModelIndex &parent) const
{
NeuralNode *parentItem = nodeFromIndex(parent);
return parentItem->childCount();
}
int ModelItemNeural::columnCount(const QModelIndex &parent) const
{
return rootNode->columnCount();
}
NeuralNode * ModelItemNeural::nodeFromIndex(const QModelIndex &index) const
{
if (index.isValid() == true)
{
return static_cast<NeuralNode *>(index.internalPointer());
}
else
{
return rootNode;
}
}
void ModelItemNeural::setRootNode(NeuralNode *rootNode)
{
delete this->rootNode;
this->rootNode = rootNode;
reset();
}
Qt::ItemFlags ModelItemNeural::flags(const QModelIndex &index) const
{
if (!index.isValid())
{
return 0;
}
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
bool ModelItemNeural::insertColumns(int position, int columns, const QModelIndex &parent)
{
bool success;
beginInsertColumns(parent, position, position + columns - 1);
success = rootNode->insertColumns(position, columns);
endInsertColumns();
return success;
}
bool ModelItemNeural::removeColumns(int position, int columns, const QModelIndex &parent)
{
bool success;
beginRemoveColumns(parent, position, position + columns - 1);
success = rootNode->removeColumns(position, columns);
endRemoveColumns();
if (rootNode->columnCount() == 0)
{
removeRows(0, rowCount());
}
return success;
}
bool ModelItemNeural::insertRows(int position, int rows, const QModelIndex &parent)
{
NeuralNode *parentItem = nodeFromIndex(parent);
counta++;
bool success;
beginInsertRows(parent, position, position + rows - 1);
switch (addedNode)
{
case NeuralNode::NEURALNODE:
{
default:
break;
}
case NeuralNode::NEURON:
{
success = parentItem->insertChildren(position, rows, new Neuron(NeuralNode::NEURON, counta + 100, counta));
break;
}
case NeuralNode::NEURAL_NETWORK:
{
success = parentItem->insertChildren(position, rows, new NeuralNetwork());
break;
}
case NeuralNode::SENSOR_INT:
{
success = parentItem->insertChildren(position, rows, new SensorInt());
break;
}
case NeuralNode::SENSOR_DOUBLE:
{
success = parentItem->insertChildren(position, rows, new SensorDouble());
break;
}
}
endInsertRows();
return success;
}
bool ModelItemNeural::removeRows(int position, int rows, const QModelIndex &parent)
{
NeuralNode *parentItem = nodeFromIndex(parent);
bool success = true;
beginRemoveRows(parent, position, position + rows - 1);
success = parentItem->removeChildren(position, rows);
endRemoveRows();
return success;
}
void ModelItemNeural::addNeuralNode(const NeuralNode::NeuralType& type, int position, int columns, const QModelIndex &parent)
{
addedNode = type;
if (columnCount(parent) == 0)
{
if (insertColumn(0, parent) == false)
{
return;
}
}
if (insertRow(0, parent) == false)
{
return;
}
//insertRows(position, columns, parent);
}
void ModelItemNeural::removeNeuralNode(const NeuralNode::NeuralType& type, int position, int columns, const QModelIndex &parent)
{
}
The code for the NeuralNode (items for the tree) is shown below
#include "NeuralNode.h"
NeuralNode::NeuralNode(NeuralNode *parent)
: id(0), type(NeuralNode::NEURALNODE), weight(0), parent(parent)
{
}
NeuralNode::NeuralNode(const NeuralType &type, NeuralNode *parent)
: id(id), type(type), weight(0), parent(parent)
{
}
NeuralNode::NeuralNode(const NeuralType &type, const int &id, NeuralNode *parent)
: id(id), type(type), weight(weight), parent(parent)
{
}
NeuralNode::NeuralNode(const NeuralType &type, const int &id, const double &weight, NeuralNode *parent)
: id(id), type(type), weight(weight), parent(parent)
{
}
bool NeuralNode::operator ==(const NeuralNode &node) const
{
if (this->id != node.id) // The id of this Neuron.
{
return false;
}
else if (weight != node.weight) // The weight of this Neuron.
{
return false;
}
else if (inputs != node.inputs) // The inputs to this NeuralNode.
{
return false;
}
else if (parent != node.parent) // The parent of the NeuralNode.
{
return false;
}
else
{
return true;
}
}
NeuralNode * NeuralNode::getParent() const
{
return parent;
}
void NeuralNode::setParent(NeuralNode *parent)
{
this->parent = parent;
}
QList<NeuralNode*> NeuralNode::getInputs() const
{
return inputs;
}
void NeuralNode::setInputs(const QList<NeuralNode*> &inputs)
{
this->inputs = inputs;
}
NeuralNode * NeuralNode::child(int number)
{
return inputs.value(number);
}
int NeuralNode::childCount() const
{
return inputs.count();
}
int NeuralNode::columnCount() const
{
return 2;
}
bool NeuralNode::insertChildren(int position, int count, NeuralNode* node)
{
if (position < 0 || position > inputs.length())
{
return false;
}
for (int row = 0; row < count; ++row)
{
inputs.insert(position, node);
}
return true;
}
bool NeuralNode::removeChildren(int position, int count)
{
if (position < 0 || position + count > inputs.length())
{
return false;
}
for (int row = 0; row < count; ++row)
{
delete inputs.takeAt(position);
}
return true;
}
int NeuralNode::childNumber() const
{
return inputs.length();
}
bool NeuralNode::insertColumns(int position, int columns)
{
if (position < 0)
{
return false;
}
for (int a = 0; a < inputs.length(); ++a)
{
inputs.at(a)->insertColumns(position, columns);
}
return true;
}
bool NeuralNode::removeColumns(int position, int columns)
{
if (position < 0)
{
return false;
}
for (int a = 0; inputs.length(); ++a)
{
inputs.at(a)->removeColumns(position, columns);
}
return true;
}
Here is what i've noticed.
Tracing through the index() call from my model does return indices for children of top level nodes.
calling ui->treeView->selectedModel()->currentIndex() always returns a invalid index (root). The same is true for ui->treeView->currentIndex().
I smell a problem with a pointer somewhere but I can't find it. Any help will be greatly appreciated.
Jec
Edit: Here is a crude graphic of the problem
Currently:
Root->A
B
C->A
What I Want:
Root->A
B
C->D
Where A, B, C and D are unique NeuralNodes. I should have no duplicates in the tree.
Thanks again.
it turns out of I forgot to link the children to their parents. Without a valid parent() the top level nodes are always added.