Commit 3ace9550 authored by Stefan Gerlach's avatar Stefan Gerlach

[locale] start using number locale in spreadsheet

parent 4d8b5e24
......@@ -43,14 +43,9 @@
#include "backend/worksheet/plots/cartesian/XYCurve.h"
#include "backend/worksheet/plots/cartesian/XYAnalysisCurve.h"
extern "C" {
#include <gsl/gsl_math.h>
#include <gsl/gsl_sort.h>
#include <gsl/gsl_statistics.h>
}
#include <array>
#include <unordered_map>
#include <KLocalizedString>
#include <KConfigGroup>
#include <KSharedConfig>
#include <QClipboard>
#include <QFont>
......@@ -59,7 +54,14 @@ extern "C" {
#include <QMenu>
#include <QThreadPool>
#include <KLocalizedString>
#include <array>
#include <unordered_map>
extern "C" {
#include <gsl/gsl_math.h>
#include <gsl/gsl_sort.h>
#include <gsl/gsl_statistics.h>
}
/**
* \class Column
......@@ -205,21 +207,22 @@ void Column::navigateTo(QAction* action) {
* copies the values of the column to the clipboard
*/
void Column::copyData() {
QLocale locale;
QString output;
int rows = rowCount();
//TODO: use locale of filter?
SET_NUMBER_LOCALE;
if (columnMode() == ColumnMode::Numeric) {
const Double2StringFilter* filter = static_cast<Double2StringFilter*>(outputFilter());
char format = filter->numericFormat();
for (int r = 0; r < rows; r++) {
output += locale.toString(valueAt(r), format, 16); // copy with max. precision
output += numberLocale.toString(valueAt(r), format, 16); // copy with max. precision
if (r < rows-1)
output += '\n';
}
} else if (columnMode() == ColumnMode::Integer || columnMode() == ColumnMode::BigInt) {
for (int r = 0; r < rowCount(); r++) {
output += QString::number(valueAt(r));
output += numberLocale.toString(valueAt(r));
if (r < rows-1)
output += '\n';
}
......
......@@ -34,24 +34,34 @@
#include "backend/core/datatypes/filter.h"
#include "backend/gsl/ExpressionParser.h"
#include <KConfigGroup>
#include <KSharedConfig>
ColumnPrivate::ColumnPrivate(Column* owner, AbstractColumn::ColumnMode mode) :
m_column_mode(mode), m_owner(owner) {
Q_ASSERT(owner != nullptr);
SET_NUMBER_LOCALE
switch (mode) {
case AbstractColumn::ColumnMode::Numeric:
m_input_filter = new String2DoubleFilter();
static_cast<String2DoubleFilter*>(m_input_filter)->setNumberLocale(numberLocale);
m_output_filter = new Double2StringFilter('g');
static_cast<Double2StringFilter*>(m_output_filter)->setNumberLocale(numberLocale);
m_data = new QVector<double>();
break;
case AbstractColumn::ColumnMode::Integer:
m_input_filter = new String2IntegerFilter();
static_cast<String2IntegerFilter*>(m_input_filter)->setNumberLocale(numberLocale);
m_output_filter = new Integer2StringFilter();
static_cast<Integer2StringFilter*>(m_output_filter)->setNumberLocale(numberLocale);
m_data = new QVector<int>();
break;
case AbstractColumn::ColumnMode::BigInt:
m_input_filter = new String2BigIntFilter();
static_cast<String2BigIntFilter*>(m_input_filter)->setNumberLocale(numberLocale);
m_output_filter = new BigInt2StringFilter();
static_cast<BigInt2StringFilter*>(m_output_filter)->setNumberLocale(numberLocale);
m_data = new QVector<qint64>();
break;
case AbstractColumn::ColumnMode::Text:
......@@ -90,22 +100,29 @@ ColumnPrivate::ColumnPrivate(Column* owner, AbstractColumn::ColumnMode mode) :
ColumnPrivate::ColumnPrivate(Column* owner, AbstractColumn::ColumnMode mode, void* data) :
m_column_mode(mode), m_data(data), m_owner(owner) {
SET_NUMBER_LOCALE
switch (mode) {
case AbstractColumn::ColumnMode::Numeric:
m_input_filter = new String2DoubleFilter();
static_cast<String2DoubleFilter*>(m_input_filter)->setNumberLocale(numberLocale);
m_output_filter = new Double2StringFilter();
static_cast<Double2StringFilter*>(m_output_filter)->setNumberLocale(numberLocale);
connect(static_cast<Double2StringFilter *>(m_output_filter), &Double2StringFilter::formatChanged,
m_owner, &Column::handleFormatChange);
break;
case AbstractColumn::ColumnMode::Integer:
m_input_filter = new String2IntegerFilter();
static_cast<String2IntegerFilter*>(m_input_filter)->setNumberLocale(numberLocale);
m_output_filter = new Integer2StringFilter();
static_cast<Integer2StringFilter*>(m_output_filter)->setNumberLocale(numberLocale);
connect(static_cast<Integer2StringFilter *>(m_output_filter), &Integer2StringFilter::formatChanged,
m_owner, &Column::handleFormatChange);
break;
case AbstractColumn::ColumnMode::BigInt:
m_input_filter = new String2BigIntFilter();
static_cast<String2BigIntFilter*>(m_input_filter)->setNumberLocale(numberLocale);
m_output_filter = new BigInt2StringFilter();
static_cast<BigInt2StringFilter*>(m_output_filter)->setNumberLocale(numberLocale);
connect(static_cast<BigInt2StringFilter *>(m_output_filter), &BigInt2StringFilter::formatChanged,
m_owner, &Column::handleFormatChange);
break;
......@@ -183,13 +200,14 @@ void ColumnPrivate::setColumnMode(AbstractColumn::ColumnMode mode) {
void* old_data = m_data;
// remark: the deletion of the old data will be done in the dtor of a command
AbstractSimpleFilter* filter = nullptr, *new_in_filter = nullptr, *new_out_filter = nullptr;
AbstractSimpleFilter* filter{nullptr}, *new_in_filter{nullptr}, *new_out_filter{nullptr};
bool filter_is_temporary = false; // it can also become outputFilter(), which we may not delete here
Column* temp_col = nullptr;
emit m_owner->modeAboutToChange(m_owner);
// determine the conversion filter and allocate the new data vector
SET_NUMBER_LOCALE
switch (m_column_mode) { // old mode
case AbstractColumn::ColumnMode::Numeric: {
disconnect(static_cast<Double2StringFilter*>(m_output_filter), &Double2StringFilter::formatChanged,
......@@ -335,18 +353,21 @@ void ColumnPrivate::setColumnMode(AbstractColumn::ColumnMode mode) {
break;
case AbstractColumn::ColumnMode::Numeric:
filter = new String2DoubleFilter();
//TODO: set number locale
filter_is_temporary = true;
temp_col = new Column("temp_col", *(static_cast<QVector<QString>*>(old_data)), m_column_mode);
m_data = new QVector<double>();
break;
case AbstractColumn::ColumnMode::Integer:
filter = new String2IntegerFilter();
//TODO: set number locale
filter_is_temporary = true;
temp_col = new Column("temp_col", *(static_cast<QVector<QString>*>(old_data)), m_column_mode);
m_data = new QVector<int>();
break;
case AbstractColumn::ColumnMode::BigInt:
filter = new String2BigIntFilter();
//TODO: set number locale
filter_is_temporary = true;
temp_col = new Column("temp_col", *(static_cast<QVector<QString>*>(old_data)), m_column_mode);
m_data = new QVector<qint64>();
......@@ -432,19 +453,25 @@ void ColumnPrivate::setColumnMode(AbstractColumn::ColumnMode mode) {
switch (mode) { // new mode
case AbstractColumn::ColumnMode::Numeric:
new_in_filter = new String2DoubleFilter();
static_cast<String2DoubleFilter*>(new_in_filter)->setNumberLocale(numberLocale);
new_out_filter = new Double2StringFilter();
static_cast<Double2StringFilter*>(new_out_filter)->setNumberLocale(numberLocale);
connect(static_cast<Double2StringFilter*>(new_out_filter), &Double2StringFilter::formatChanged,
m_owner, &Column::handleFormatChange);
break;
case AbstractColumn::ColumnMode::Integer:
new_in_filter = new String2IntegerFilter();
static_cast<String2IntegerFilter*>(new_in_filter)->setNumberLocale(numberLocale);
new_out_filter = new Integer2StringFilter();
static_cast<Integer2StringFilter*>(new_out_filter)->setNumberLocale(numberLocale);
connect(static_cast<Integer2StringFilter*>(new_out_filter), &Integer2StringFilter::formatChanged,
m_owner, &Column::handleFormatChange);
break;
case AbstractColumn::ColumnMode::BigInt:
new_in_filter = new String2BigIntFilter();
static_cast<String2BigIntFilter*>(new_in_filter)->setNumberLocale(numberLocale);
new_out_filter = new BigInt2StringFilter();
static_cast<BigInt2StringFilter*>(new_out_filter)->setNumberLocale(numberLocale);
connect(static_cast<BigInt2StringFilter*>(new_out_filter), &BigInt2StringFilter::formatChanged,
m_owner, &Column::handleFormatChange);
break;
......
......@@ -136,8 +136,10 @@ public:
mutable AbstractColumn::Properties properties{AbstractColumn::Properties::No}; // declares the properties of the curve (monotonic increasing/decreasing ...). Speed up algorithms
private:
//TODO: rename to m_columnMode
AbstractColumn::ColumnMode m_column_mode; // type of column data
void* m_data{nullptr}; //pointer to the data container (QVector<T>)
// TODO: rename to m_InputFilter, m_OutputFilter
AbstractSimpleFilter* m_input_filter{nullptr}; //input filter for string -> data type conversion
AbstractSimpleFilter* m_output_filter{nullptr}; //output filter for data type -> string conversion
QString m_formula;
......@@ -146,6 +148,7 @@ private:
QStringList m_formulaVariableColumnPaths;
bool m_formulaAutoUpdate{false};
IntervalAttribute<QString> m_formulas;
//TODO: rename to m_plotDesignation
AbstractColumn::PlotDesignation m_plot_designation{AbstractColumn::PlotDesignation::NoDesignation};
int m_width{0}; //column width in the view
Column* m_owner{nullptr};
......
......@@ -35,8 +35,9 @@ class BigInt2StringFilter : public AbstractSimpleFilter {
Q_OBJECT
public:
//! Standard constructor.
explicit BigInt2StringFilter() {}
void setNumberLocale(const QLocale& locale) { m_numberLocale = locale; m_useDefaultLocale = false; }
void setNumberLocaleToDefault() { m_useDefaultLocale = true; }
//! Return the data type of the column
AbstractColumn::ColumnMode columnMode() const override { return AbstractColumn::ColumnMode::Text; }
......@@ -48,7 +49,10 @@ public:
qint64 inputValue = m_inputs.value(0)->bigIntAt(row);
return QLocale().toString(inputValue);
if (m_useDefaultLocale)
return QLocale().toString(inputValue);
else
return m_numberLocale.toString(inputValue);
}
protected:
......@@ -56,7 +60,11 @@ protected:
bool inputAcceptable(int, const AbstractColumn *source) override {
return source->columnMode() == AbstractColumn::ColumnMode::BigInt;
}
private:
QLocale m_numberLocale;
bool m_useDefaultLocale{true};
};
#endif // ifndef BIGINT2STRING_FILTER_H
#endif // BIGINT2STRING_FILTER_H
......@@ -2,7 +2,7 @@
File : Double2IntegerFilter.h
Project : AbstractColumn
--------------------------------------------------------------------
Copyright : (C) 2017 Stefan Gerlach (stefan.gerlach@uni.kn)
Copyright : (C) 2017-2020 Stefan Gerlach (stefan.gerlach@uni.kn)
Description : conversion filter double -> int.
***************************************************************************/
......@@ -29,7 +29,6 @@
#define DOUBLE2INTEGER_FILTER_H
#include "../AbstractSimpleFilter.h"
#include <QLocale>
#include <cmath>
//! conversion filter double -> int.
......@@ -40,11 +39,12 @@ public:
Double2IntegerFilter() {}
int integerAt(int row) const override {
if (!m_inputs.value(0)) return 0;
if (!m_inputs.value(0))
return 0;
double value = m_inputs.value(0)->valueAt(row);
int result = 0;
int result{0};
if (!std::isnan(value))
result = (int)round(value);
//DEBUG("Double2Integer::integerAt() " << value << " -> " << result);
......
......@@ -2,8 +2,9 @@
File : Double2StringFilter.h
Project : AbstractColumn
--------------------------------------------------------------------
Copyright : (C) 2007 by Knut Franke, Tilman Benkert
Email (use @ for *) : knut.franke*gmx.de, thzs@gmx.net
Copyright : (C) 2007 by Knut Franke (knut.franke*gmx.de)
Copyright : (C) 2007 by Tilman Benkert (thzs@gmx.net)
Copyright : (C) 2020 by Stefan Gerlach (stefan.gerlach@uni.kn)
Description : Locale-aware conversion filter double -> QString.
***************************************************************************/
......@@ -38,8 +39,7 @@ class Double2StringFilter : public AbstractSimpleFilter {
Q_OBJECT
public:
//! Standard constructor.
explicit Double2StringFilter(char format='e', int digits=6) : m_format(format), m_digits(digits) {}
explicit Double2StringFilter(char format='g', int digits = 6) : m_format(format), m_digits(digits) {}
//! Set format character as in QString::number
void setNumericFormat(char format);
//! Set number of displayed digits
......@@ -48,6 +48,8 @@ public:
char numericFormat() const { return m_format; }
//! Get number of displayed digits
int numDigits() const { return m_digits; }
void setNumberLocale(const QLocale& locale) { m_numberLocale = locale; m_useDefaultLocale = false; }
void setNumberLocaleToDefault() { m_useDefaultLocale = true; }
//! Return the data type of the column
AbstractColumn::ColumnMode columnMode() const override { return AbstractColumn::ColumnMode::Text; }
......@@ -59,6 +61,8 @@ private:
char m_format;
//! Display digits or precision as in QString::number
int m_digits;
QLocale m_numberLocale;
bool m_useDefaultLocale{true};
//! \name XML related functions
//@{
......@@ -73,7 +77,10 @@ public:
if (m_inputs.value(0)->rowCount() <= row) return QString();
double inputValue = m_inputs.value(0)->valueAt(row);
if (std::isnan(inputValue)) return QString();
return QLocale().toString(inputValue, m_format, m_digits);
if (m_useDefaultLocale)
return QLocale().toString(inputValue, m_format, m_digits);
else
return m_numberLocale.toString(inputValue, m_format, m_digits);
}
protected:
......@@ -83,5 +90,5 @@ protected:
}
};
#endif // ifndef DOUBLE2STRING_FILTER_H
#endif // DOUBLE2STRING_FILTER_H
......@@ -2,7 +2,7 @@
File : Integer2StringFilter.h
Project : AbstractColumn
--------------------------------------------------------------------
Copyright : (C) 2017 Stefan Gerlach (stefan.gerlach@uni.kn)
Copyright : (C) 2017-2020 Stefan Gerlach (stefan.gerlach@uni.kn)
Description : Locale-aware conversion filter int -> QString.
***************************************************************************/
......@@ -35,8 +35,9 @@ class Integer2StringFilter : public AbstractSimpleFilter {
Q_OBJECT
public:
//! Standard constructor.
explicit Integer2StringFilter() {}
void setNumberLocale(const QLocale& locale) { m_numberLocale = locale; m_useDefaultLocale = false; }
void setNumberLocaleToDefault() { m_useDefaultLocale = true; }
//! Return the data type of the column
AbstractColumn::ColumnMode columnMode() const override { return AbstractColumn::ColumnMode::Text; }
......@@ -48,7 +49,10 @@ public:
int inputValue = m_inputs.value(0)->integerAt(row);
return QLocale().toString(inputValue);
if (m_useDefaultLocale)
return QLocale().toString(inputValue);
else
return m_numberLocale.toString(inputValue);
}
protected:
......@@ -56,7 +60,11 @@ protected:
bool inputAcceptable(int, const AbstractColumn *source) override {
return source->columnMode() == AbstractColumn::ColumnMode::Integer;
}
private:
QLocale m_numberLocale;
bool m_useDefaultLocale{true};
};
#endif // ifndef INTEGER2STRING_FILTER_H
#endif // INTEGER2STRING_FILTER_H
......@@ -37,8 +37,8 @@ class String2BigIntFilter : public AbstractSimpleFilter {
public:
String2BigIntFilter() : m_use_default_locale(true) {}
void setNumericLocale(const QLocale& locale) { m_numeric_locale = locale; m_use_default_locale = false; }
void setNumericLocaleToDefault() { m_use_default_locale = true; }
void setNumberLocale(const QLocale& locale) { m_numeric_locale = locale; m_use_default_locale = false; }
void setNumberLocaleToDefault() { m_use_default_locale = true; }
qint64 bigIntAt(int row) const override {
//DEBUG("String2BigInt::bigIntAt()");
......
......@@ -2,8 +2,8 @@
File : String2DoubleFilter.h
Project : AbstractColumn
--------------------------------------------------------------------
Copyright : (C) 2007 by Knut Franke
Email (use @ for *) : knut.franke*gmx.de
Copyright : (C) 2007 by Knut Franke (knut.franke*gmx.de)
Copyright : (C) 2020 by Stefan Gerlach (stefan.gerlach@uni.kn)
Description : Locale-aware conversion filter QString -> double.
***************************************************************************/
......@@ -38,21 +38,22 @@ class String2DoubleFilter : public AbstractSimpleFilter {
Q_OBJECT
public:
String2DoubleFilter() : m_use_default_locale(true) {}
void setNumericLocale(const QLocale& locale) { m_numeric_locale = locale; m_use_default_locale = false; }
void setNumericLocaleToDefault() { m_use_default_locale = true; }
String2DoubleFilter() {}
void setNumberLocale(const QLocale& locale) { m_numberLocale = locale; m_useDefaultLocale = false; }
void setNumberLocaleToDefault() { m_useDefaultLocale = true; }
double valueAt(int row) const override {
DEBUG("String2Double::valueAt()");
//DEBUG("String2Double::valueAt()");
if (!m_inputs.value(0)) return 0;
if (!m_inputs.value(0))
return 0;
double result;
bool valid;
if (m_use_default_locale) // we need a new QLocale instance here in case the default changed since the last call
if (m_useDefaultLocale) // we need a new QLocale instance here in case the default changed since the last call
result = QLocale().toDouble(m_inputs.value(0)->textAt(row), &valid);
else
result = m_numeric_locale.toDouble(m_inputs.value(0)->textAt(row), &valid);
result = m_numberLocale.toDouble(m_inputs.value(0)->textAt(row), &valid);
if (valid)
return result;
......@@ -69,8 +70,8 @@ protected:
}
private:
QLocale m_numeric_locale;
bool m_use_default_locale;
QLocale m_numberLocale;
bool m_useDefaultLocale{true};
};
#endif // ifndef STRING2DOUBLE_FILTER_H
......@@ -2,7 +2,7 @@
File : String2IntegerFilter.h
Project : AbstractColumn
--------------------------------------------------------------------
Copyright : (C) 2017 Stefan Gerlach (stefan.gerlach@uni.kn)
Copyright : (C) 2017-2020 Stefan Gerlach (stefan.gerlach@uni.kn)
Description : Locale-aware conversion filter QString -> int.
***************************************************************************/
......@@ -36,9 +36,9 @@ class String2IntegerFilter : public AbstractSimpleFilter {
Q_OBJECT
public:
String2IntegerFilter() : m_use_default_locale(true) {}
void setNumericLocale(const QLocale& locale) { m_numeric_locale = locale; m_use_default_locale = false; }
void setNumericLocaleToDefault() { m_use_default_locale = true; }
explicit String2IntegerFilter() {}
void setNumberLocale(const QLocale& locale) { m_numberLocale = locale; m_useDefaultLocale = false; }
void setNumberLocaleToDefault() { m_useDefaultLocale = true; }
int integerAt(int row) const override {
//DEBUG("String2Integer::integerAt()");
......@@ -48,10 +48,10 @@ public:
bool valid;
QString textValue = m_inputs.value(0)->textAt(row);
//DEBUG(" textValue = " << STDSTRING(textValue));
if (m_use_default_locale) // we need a new QLocale instance here in case the default changed since the last call
if (m_useDefaultLocale)
result = QLocale().toInt(textValue, &valid);
else
result = m_numeric_locale.toInt(textValue, &valid);
result = m_numberLocale.toInt(textValue, &valid);
//DEBUG(" result = " << result << " valid = " << valid);
if (valid)
......@@ -69,8 +69,8 @@ protected:
}
private:
QLocale m_numeric_locale;
bool m_use_default_locale;
QLocale m_numberLocale;
bool m_useDefaultLocale{true};
};
#endif // ifndef STRING2INTEGER_FILTER_H
......@@ -221,12 +221,13 @@ bool SpreadsheetModel::setData(const QModelIndex& index, const QVariant& value,
int row = index.row();
Column* column = m_spreadsheet->column(index.column());
SET_NUMBER_LOCALE
//DEBUG("SpreadsheetModel::setData() value = " << STDSTRING(value.toString()))
//don't do anything if no new value was provided
if (column->columnMode() == AbstractColumn::ColumnMode::Numeric) {
bool ok;
//TODO
QLocale locale;
double new_value = locale.toDouble(value.toString(), &ok);
double new_value = numberLocale.toDouble(value.toString(), &ok);
if (ok) {
if (column->valueAt(row) == new_value)
return false;
......
......@@ -87,7 +87,7 @@ SpreadsheetHeaderView::~SpreadsheetHeaderView() {
}
QSize SpreadsheetHeaderView::sizeHint() const {
DEBUG("SpreadsheetHeaderView::sizeHint()")
// DEBUG("SpreadsheetHeaderView::sizeHint()")
QSize master_size = QHeaderView::sizeHint();
if (m_showComments)
master_size.setHeight(master_size.height() + m_slave->sizeHint().height());
......@@ -105,7 +105,7 @@ void SpreadsheetHeaderView::setModel(QAbstractItemModel* model) {
}
void SpreadsheetHeaderView::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const {
DEBUG("SpreadsheetHeaderView::paintSection()")
// DEBUG("SpreadsheetHeaderView::paintSection()")
QRect master_rect = rect;
if (m_showComments)
master_rect = rect.adjusted(0, 0, 0, -m_slave->sizeHint().height());
......
......@@ -1390,8 +1390,7 @@ void SpreadsheetView::goToPreviousColumn() {
}
void SpreadsheetView::cutSelection() {
int first = firstSelectedRow();
if ( first < 0 )
if (firstSelectedRow() < 0)
return;
WAIT_CURSOR;
......@@ -1423,8 +1422,8 @@ void SpreadsheetView::copySelection() {
for (int c = 0; c < cols; c++) {
Column* col = m_spreadsheet->column(first_col + c);
columns << col;
const Double2StringFilter* out_fltr = static_cast<Double2StringFilter*>(col->outputFilter());
formats << out_fltr->numericFormat();
const auto* outFilter = static_cast<Double2StringFilter*>(col->outputFilter());
formats << outFilter->numericFormat();
}
SET_NUMBER_LOCALE
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment