mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-24 16:04:16 +02:00
8b54ea400b
Follow-up to #1088, covering its review comments and one behaviour change found while testing the feature: - MaterialList::load() names the columns from the machine key line when the file has one, instead of from the translated label line above it. A catalogue written in another language fills the element fields again, and saving no longer replaces the key line with labels. - The entry picked after "New entry" is found by comparing the columns one by one instead of comparing the two maps as a whole: the entry form leaves the empty columns out, so the record never matched the line that had just been written and the search was cleared for nothing. The search is now only given up when it really hides the new line. - Applying a catalogue entry pushes an undo command only when the live edit is on. In the properties window, where there is none, the fields wait for "Apply", so "Cancel" gives the element its own values back instead of leaving the picked part in place. - Cells a file holds past the header are kept in MaterialRecord::extra and written back, so appending an article never shortens a line. - An empty cell of a column describing the article itself (MaterialList:: isArticleBound: description, designation, manufacturer, order number, supplier, model, ratings, dimensions, auxiliary block) clears the field, so an element never keeps the manufacturer of the part picked before. An empty cell of any other column (function, comment, notes, plant, location, quantity, unity), and any column the file does not hold at all, leaves the field alone. - Comments left where the review asked for them: the corner button lookup, the ';' separator fallback, the search filter cost.
127 lines
4.6 KiB
C++
127 lines
4.6 KiB
C++
/*
|
|
Copyright 2006-2026 The QElectroTech Team
|
|
This file is part of QElectroTech.
|
|
|
|
QElectroTech is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
QElectroTech 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifndef MATERIALLIST_H
|
|
#define MATERIALLIST_H
|
|
|
|
#include <QByteArray>
|
|
#include <QChar>
|
|
#include <QList>
|
|
#include <QMap>
|
|
#include <QSize>
|
|
#include <QString>
|
|
#include <QStringList>
|
|
|
|
/**
|
|
@brief One line of the material file.
|
|
|
|
Keys are column names : either a canonical element information key
|
|
(description, manufacturer...) or the raw name of a column added by
|
|
the user, which QElectroTech does not know about and therefore never
|
|
Transfers to an element, but keeps intact when a row is appended.
|
|
*/
|
|
struct MaterialRecord
|
|
{
|
|
QMap<QString, QString> values;
|
|
//Cells written after the last column of the header, kept as they
|
|
//are so that appending an article never shortens a line the user
|
|
//wrote wider than the header itself.
|
|
QStringList extra;
|
|
|
|
QString value(const QString &column) const {return values.value(column);}
|
|
void setValue(const QString &column, const QString &value) {values.insert(column, value);}
|
|
bool operator==(const MaterialRecord &other) const {return values == other.values;}
|
|
};
|
|
|
|
/**
|
|
@brief The whole content of a material file.
|
|
|
|
Both the column names and the separator are read from the file rather
|
|
than imposed, so a file edited in a spreadsheet keeps working : the
|
|
separator is detected (;, tab or ,), unknown columns are preserved, and
|
|
only the header cells that can be matched to a known element
|
|
information are canonicalized.
|
|
*/
|
|
struct MaterialListData
|
|
{
|
|
QStringList columns;
|
|
QList<MaterialRecord> records;
|
|
QChar separator = QLatin1Char(';');
|
|
|
|
bool isEmpty() const {return columns.isEmpty() && records.isEmpty();}
|
|
};
|
|
|
|
/**
|
|
@brief The MaterialList class reads and writes the material file (a CSV
|
|
file listing purchasable articles) and maps its columns onto element
|
|
informations.
|
|
|
|
This is a pure data class : it does not know anything about widgets,
|
|
so it stays usable from the tests and from the command line.
|
|
*/
|
|
class MaterialList
|
|
{
|
|
public:
|
|
//Settings
|
|
static QString settingsKey();
|
|
static QString configuredPath();
|
|
static void setConfiguredPath(const QString &path);
|
|
static QString defaultPath();
|
|
static QString defaultFileName();
|
|
|
|
//Geometry of the selection window, remembered from one opening
|
|
//to the next : column widths are part of how the user reads his
|
|
//own catalogue and must not be lost when the window closes.
|
|
static QByteArray savedHeaderState();
|
|
static void saveHeaderState(const QByteArray &state);
|
|
static QSize savedDialogSize();
|
|
static void saveDialogSize(const QSize &size);
|
|
|
|
//Columns
|
|
static QStringList defaultColumns();
|
|
static QStringList columnsForBlock(int block);
|
|
static QString elementInfoKey(const QString &column, int block);
|
|
static bool isArticleBound(const QString &column);
|
|
static QString translatedColumn(const QString &column);
|
|
static QStringList translatedHeader(const QStringList &columns);
|
|
|
|
//File io
|
|
static bool load(const QString &path, MaterialListData *data, QString *error = nullptr);
|
|
static bool writeFile(const QString &path, const MaterialListData &data, QString *error = nullptr);
|
|
static bool appendRecord(const QString &path, const MaterialRecord &record, QString *error = nullptr);
|
|
static bool createFile(const QString &path, QString *error = nullptr);
|
|
static bool isEmptyFile(const QString &path);
|
|
|
|
//Csv helpers, public only to keep them testable
|
|
static QList<QStringList> parseCsv(const QString &content, QChar separator);
|
|
static QByteArray serializeCsv(const QList<QStringList> &header_lines,
|
|
const QList<QStringList> &rows,
|
|
QChar separator);
|
|
static QChar detectSeparator(const QString &first_line);
|
|
|
|
private:
|
|
static QString canonicalColumn(const QString &header_cell,
|
|
const QStringList &already_used,
|
|
const QMap<QString, QString> &alias_map);
|
|
static QMap<QString, QString> headerAliasMap();
|
|
static bool isMachineHeaderLine(const QStringList &label_line,
|
|
const QStringList &candidate,
|
|
const QMap<QString, QString> &alias_map);
|
|
};
|
|
|
|
#endif // MATERIALLIST_H
|