Commit 8288829a authored by Volker Krause's avatar Volker Krause
Browse files

Initial work on separating schema and aggregation settings

parent 6b699202
set(analyzer_lib_srcs
core/aggregation.cpp
core/product.cpp
core/sample.cpp
core/schemaentry.cpp
......@@ -10,6 +11,8 @@ set(analyzer_lib_srcs
rest/restclient.cpp
rest/serverinfo.cpp
model/aggregationeditormodel.cpp
model/aggregationelementmodel.cpp
model/categoryaggregationmodel.cpp
model/datamodel.cpp
model/numericaggregationmodel.cpp
......@@ -35,6 +38,8 @@ set(analyzer_srcs
analytics/analyticsview.cpp
schemaeditor/aggregationeditwidget.cpp
schemaeditor/schemaeditor.cpp
schemaeditor/schemaeditwidget.cpp
schemaeditor/schemaentryitemeditorfactory.cpp
......
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "aggregation.h"
using namespace UserFeedback::Analyzer;
Aggregation::Aggregation() = default;
Aggregation::~Aggregation() = default;
Aggregation::Type Aggregation::type() const
{
return m_type;
}
void Aggregation::setType(Aggregation::Type t)
{
m_type = t;
}
QVector<Aggregation::Element> Aggregation::elements() const
{
return m_elements;
}
void Aggregation::setElements(const QVector<Aggregation::Element>& elements)
{
m_elements = elements;
}
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USERFEEDBACK_ANALYZER_AGGREGATION_H
#define USERFEEDBACK_ANALYZER_AGGREGATION_H
#include <core/schemaentry.h>
#include <core/schemaentryelement.h>
#include <QTypeInfo>
namespace UserFeedback {
namespace Analyzer {
class Aggregation
{
Q_GADGET
public:
enum Type {
None,
Category,
RatioSet,
Numeric,
XY
};
Q_ENUM(Type)
Aggregation();
~Aggregation();
Type type() const;
void setType(Type t);
struct Element {
SchemaEntry entry;
SchemaEntryElement element;
};
QVector<Element> elements() const;
void setElements(const QVector<Element> &elements);
private:
Type m_type = None;
QVector<Element> m_elements;
};
}
}
Q_DECLARE_TYPEINFO(UserFeedback::Analyzer::Aggregation, Q_MOVABLE_TYPE);
Q_DECLARE_METATYPE(UserFeedback::Analyzer::Aggregation::Element)
Q_DECLARE_METATYPE(UserFeedback::Analyzer::Aggregation::Type)
#endif // USERFEEDBACK_ANALYZER_AGGREGATION_H
......@@ -16,6 +16,7 @@
*/
#include "product.h"
#include "aggregation.h"
#include <QJsonArray>
#include <QJsonDocument>
......@@ -32,6 +33,7 @@ class ProductData : public QSharedData
public:
QString name;
QVector<SchemaEntry> schema;
QVector<Aggregation> aggregations;
};
}
......@@ -67,6 +69,16 @@ void Product::setSchema(const QVector<SchemaEntry> &schema)
d->schema = schema;
}
QVector<Aggregation> Product::aggregations() const
{
return d->aggregations;
}
void Product::setAggregations(const QVector<Aggregation>& aggregations)
{
d->aggregations = aggregations;
}
QByteArray Product::toJson() const
{
QJsonObject obj;
......@@ -84,6 +96,19 @@ static Product productFromJsonObject(const QJsonObject &obj)
Product product;
product.setName(obj.value(QStringLiteral("name")).toString());
product.setSchema(SchemaEntry::fromJson(obj.value(QStringLiteral("schema")).toArray()));
// ### temporary HACK
QVector<Aggregation> aggrs;
for (const auto &entry : product.schema()) {
for (const auto &elem : entry.elements()) {
Aggregation aggr;
aggr.setType(Aggregation::Category);
aggr.setElements({{ entry, elem }});
aggrs.push_back(aggr);
}
}
product.setAggregations(aggrs);
return product;
}
......
......@@ -29,6 +29,7 @@ class QString;
namespace UserFeedback {
namespace Analyzer {
class Aggregation;
class ProductData;
/** Product data. */
......@@ -48,6 +49,9 @@ public:
QVector<SchemaEntry> schema() const;
void setSchema(const QVector<SchemaEntry>& schema);
QVector<Aggregation> aggregations() const;
void setAggregations(const QVector<Aggregation> &aggregations);
QByteArray toJson() const;
static QVector<Product> fromJson(const QByteArray &data);
......
......@@ -103,7 +103,7 @@ MainWindow::MainWindow() :
connect(ui->actionAddProduct, &QAction::triggered, this, &MainWindow::createProduct);
connect(ui->actionDeleteProduct, &QAction::triggered, this, &MainWindow::deleteProduct);
connect(ui->schemaEdit, &SchemaEditWidget::productChanged, m_productModel, &ProductModel::reload);
connect(ui->schemaEdit, &SchemaEditor::productChanged, m_productModel, &ProductModel::reload);
ui->actionQuit->setShortcut(QKeySequence::Quit);
connect(ui->actionQuit, &QAction::triggered, QCoreApplication::instance(), &QCoreApplication::quit);
......
......@@ -31,7 +31,7 @@
<widget class="QStackedWidget" name="viewStack">
<widget class="UserFeedback::Analyzer::AnalyticsView" name="analyticsView"/>
<widget class="UserFeedback::Analyzer::SurveyEditor" name="surveyEditor"/>
<widget class="UserFeedback::Analyzer::SchemaEditWidget" name="schemaEdit"/>
<widget class="UserFeedback::Analyzer::SchemaEditor" name="schemaEdit"/>
</widget>
</item>
<item>
......@@ -292,9 +292,9 @@
<container>1</container>
</customwidget>
<customwidget>
<class>UserFeedback::Analyzer::SchemaEditWidget</class>
<class>UserFeedback::Analyzer::SchemaEditor</class>
<extends>QWidget</extends>
<header>schemaeditor/schemaeditwidget.h</header>
<header>schemaeditor/schemaeditor.h</header>
<container>1</container>
</customwidget>
<customwidget>
......
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "aggregationeditormodel.h"
#include <core/aggregation.h>
#include <core/util.h>
using namespace UserFeedback::Analyzer;
AggregationEditorModel::AggregationEditorModel(QObject* parent) :
QAbstractTableModel(parent)
{
}
AggregationEditorModel::~AggregationEditorModel() = default;
Product AggregationEditorModel::product() const
{
return m_product;
}
void AggregationEditorModel::setProduct(const Product& product)
{
m_product = product;
}
int AggregationEditorModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return 2;
}
int AggregationEditorModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
return m_product.aggregations().size();
}
QVariant AggregationEditorModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || !m_product.isValid())
return {};
if (role == Qt::DisplayRole) {
const auto aggr = m_product.aggregations().at(index.row());
switch (index.column()) {
case 0:
return Util::enumToString(aggr.type());
case 1:
if (aggr.elements().isEmpty())
return tr("<none>");
return QString(aggr.elements().at(0).entry.name() + QLatin1Char('.') + aggr.elements().at(0).element.name());
}
} else if (role == Qt::EditRole) {
const auto aggr = m_product.aggregations().at(index.row());
switch (index.column()) {
case 0:
return QVariant::fromValue(aggr.type());
case 1:
if (aggr.elements().isEmpty())
return {};
return QVariant::fromValue(aggr.elements().at(0));
}
}
return {};
}
QVariant AggregationEditorModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case 0: return tr("Type");
case 1: return tr("Element");
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
Qt::ItemFlags AggregationEditorModel::flags(const QModelIndex& index) const
{
const auto baseFlags = QAbstractTableModel::flags(index);
if (index.isValid())
return baseFlags | Qt::ItemIsEditable;
return baseFlags;
}
bool AggregationEditorModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (!index.isValid() || role != Qt::EditRole)
return false;
auto aggrs = m_product.aggregations();
auto &aggr = aggrs[index.row()];
switch (index.column()) {
case 0:
aggr.setType(value.value<Aggregation::Type>());
break;
case 1:
aggr.setElements({ value.value<Aggregation::Element>() });
break;
}
m_product.setAggregations(aggrs);
emit dataChanged(index, index);
return true;
}
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USERFEEDBACK_ANALYZER_AGGREGATIONEDITORMODEL_H
#define USERFEEDBACK_ANALYZER_AGGREGATIONEDITORMODEL_H
#include <core/product.h>
#include <QAbstractTableModel>
namespace UserFeedback {
namespace Analyzer {
class AggregationEditorModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit AggregationEditorModel(QObject *parent = nullptr);
~AggregationEditorModel();
Product product() const;
void setProduct(const Product &product);
int columnCount(const QModelIndex & parent) const override;
int rowCount(const QModelIndex & parent) const override;
QVariant data(const QModelIndex & index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Qt::ItemFlags flags(const QModelIndex & index) const override;
bool setData(const QModelIndex & index, const QVariant & value, int role) override;
private:
Product m_product;
};
}
}
#endif // USERFEEDBACK_ANALYZER_AGGREGATIONEDITORMODEL_H
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "aggregationelementmodel.h"
#include <core/product.h>
using namespace UserFeedback::Analyzer;
AggregationElementModel::AggregationElementModel(QObject* parent) :
QAbstractListModel(parent)
{
}
AggregationElementModel::~AggregationElementModel() = default;
void AggregationElementModel::setProduct(const Product& product)
{
beginResetModel();
m_elements.clear();
for (const auto &entry : product.schema()) {
for (const auto &elem : entry.elements())
m_elements.push_back({ entry, elem });
}
endResetModel();
}
int AggregationElementModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
return m_elements.size();
}
QVariant AggregationElementModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || m_elements.isEmpty())
return {};
const auto e = m_elements.at(index.row());
switch (role) {
case Qt::DisplayRole: return QString(e.entry.name() + QLatin1Char('.') + e.element.name());
case Qt::EditRole: return QVariant::fromValue(e);
}
return {};
}
QModelIndexList AggregationElementModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const
{
if (role == Qt::EditRole && value.userType() == qMetaTypeId<Aggregation::Element>() && hits == 1 && start.row() == 0) {
const auto cmp = value.value<Aggregation::Element>();
for (int i = 0; i < m_elements.size(); ++i) {
if (m_elements.at(i).entry == cmp.entry && m_elements.at(i).element == cmp.element)
return { index(i, 0) };
}
}
return QAbstractListModel::match(start, role, value, hits, flags);
}
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USERFEEDBACK_ANALYZER_AGGREGATIONELEMENTMODEL_H
#define USERFEEDBACK_ANALYZER_AGGREGATIONELEMENTMODEL_H
#include <core/aggregation.h>
#include <QAbstractListModel>
#include <QVector>
namespace UserFeedback {
namespace Analyzer {
class Product;
class AggregationElementModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit AggregationElementModel(QObject *parent = nullptr);
~AggregationElementModel();
void setProduct(const Product &product);
int rowCount(const QModelIndex & parent) const override;
QVariant data(const QModelIndex & index, int role) const override;
QModelIndexList match(const QModelIndex & start, int role, const QVariant & value, int hits, Qt::MatchFlags flags) const override;
private:
QVector<Aggregation::Element> m_elements;
};
}
}
#endif // USERFEEDBACK_ANALYZER_AGGREGATIONELEMENTMODEL_H
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "aggregationeditwidget.h"
#include "ui_aggregationeditwidget.h"
#include "schemaentryitemeditorfactory.h"
#include <model/aggregationeditormodel.h>
#include <QStyledItemDelegate>
using namespace UserFeedback::Analyzer;
AggregationEditWidget::AggregationEditWidget(QWidget* parent) :
QWidget(parent),
ui(new Ui::AggregationEditWidget),
m_model(new AggregationEditorModel(this)),
m_editorFactory(new SchemaEntryItemEditorFactory)
{
ui->setupUi(this);
ui->aggregationView->setModel(m_model);
qobject_cast<QStyledItemDelegate*>(ui->aggregationView->itemDelegate())->setItemEditorFactory(m_editorFactory);
}
AggregationEditWidget::~AggregationEditWidget() = default;
void AggregationEditWidget::setProduct(const Product& product)
{
m_model->setProduct(product);
m_editorFactory->setProduct(product);
}
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USERFEEDBACK_ANALYZER_AGGREGATIONEDITWIDGET_H
#define USERFEEDBACK_ANALYZER_AGGREGATIONEDITWIDGET_H
#include <QWidget>