Commit c9a7215f14cb2b1fe5c9de3c5c19e36c02027823
Committed by
GitHub
Merge pull request #550 from biometrics/csv
refactor csvGallery
Showing
1 changed file
with
42 additions
and
84 deletions
openbr/plugins/gallery/csv.cpp
| ... | ... | @@ -33,8 +33,6 @@ namespace br |
| 33 | 33 | class csvGallery : public FileGallery |
| 34 | 34 | { |
| 35 | 35 | Q_OBJECT |
| 36 | - Q_PROPERTY(int fileIndex READ get_fileIndex WRITE set_fileIndex RESET reset_fileIndex) | |
| 37 | - BR_PROPERTY(int, fileIndex, 0) | |
| 38 | 36 | |
| 39 | 37 | FileList files; |
| 40 | 38 | QStringList headers; |
| ... | ... | @@ -42,42 +40,30 @@ class csvGallery : public FileGallery |
| 42 | 40 | ~csvGallery() |
| 43 | 41 | { |
| 44 | 42 | f.close(); |
| 45 | - | |
| 46 | 43 | if (files.isEmpty()) return; |
| 47 | 44 | |
| 48 | - QMap<QString,QVariant> samples; | |
| 45 | + QSet<QString> samples; | |
| 49 | 46 | foreach (const File &file, files) |
| 50 | 47 | foreach (const QString &key, file.localKeys()) |
| 51 | - if (!samples.contains(key)) | |
| 52 | - samples.insert(key, file.value(key)); | |
| 53 | - | |
| 54 | - // Don't create columns in the CSV for these special fields | |
| 55 | - samples.remove("Points"); | |
| 56 | - samples.remove("Rects"); | |
| 48 | + samples.insert(key); | |
| 57 | 49 | |
| 58 | 50 | QStringList lines; |
| 59 | 51 | lines.reserve(files.size()+1); |
| 60 | 52 | |
| 61 | - QMap<QString, int> columnCounts; | |
| 62 | - | |
| 63 | - { // Make header | |
| 64 | - QStringList words; | |
| 65 | - words.append("File"); | |
| 66 | - foreach (const QString &key, samples.keys()) { | |
| 67 | - int count = 0; | |
| 68 | - words.append(getCSVElement(key, samples[key], true, count)); | |
| 69 | - columnCounts.insert(key, count); | |
| 70 | - } | |
| 71 | - lines.append(words.join(",")); | |
| 72 | - } | |
| 53 | + // Make header | |
| 54 | + QStringList keys = samples.values(); | |
| 55 | + keys.sort(); | |
| 56 | + lines.append(QStringList(QStringList("File") + keys).join(",")); | |
| 73 | 57 | |
| 74 | 58 | // Make table |
| 75 | 59 | foreach (const File &file, files) { |
| 76 | 60 | QStringList words; |
| 77 | 61 | words.append(file.name); |
| 78 | - foreach (const QString &key, samples.keys()) { | |
| 79 | - int count = columnCounts[key]; | |
| 80 | - words.append(getCSVElement(key, file.value(key), false, count)); | |
| 62 | + foreach (const QString &key, keys) { | |
| 63 | + QString value = QtUtils::toString(file.value(key)); | |
| 64 | + if (value.contains(",")) | |
| 65 | + value = '"' + value + '"'; | |
| 66 | + words.append(value); | |
| 81 | 67 | } |
| 82 | 68 | lines.append(words.join(",")); |
| 83 | 69 | } |
| ... | ... | @@ -94,32 +80,28 @@ class csvGallery : public FileGallery |
| 94 | 80 | *done = true; |
| 95 | 81 | return templates; |
| 96 | 82 | } |
| 97 | - QRegExp regexp("\\s*,\\s*"); | |
| 98 | 83 | |
| 99 | - if (f.pos() == 0) | |
| 100 | - { | |
| 101 | - // read a line | |
| 84 | + if (f.pos() == 0) { | |
| 85 | + // read header | |
| 102 | 86 | QByteArray lineBytes = f.readLine(); |
| 103 | 87 | QString line = QString::fromLocal8Bit(lineBytes).trimmed(); |
| 88 | + QRegExp regexp("\\s*,\\s*"); | |
| 104 | 89 | headers = line.split(regexp); |
| 105 | 90 | } |
| 106 | 91 | |
| 107 | - for (qint64 i = 0; i < this->readBlockSize && !f.atEnd(); i++){ | |
| 108 | - QByteArray lineBytes = f.readLine(); | |
| 109 | - QString line = QString::fromLocal8Bit(lineBytes).trimmed(); | |
| 92 | + for (qint64 i = 0; i < this->readBlockSize && !f.atEnd(); i++) { | |
| 93 | + const QVariantList values = parseLine(f.readLine()); | |
| 94 | + if (values.size() != headers.size()) continue; | |
| 110 | 95 | |
| 111 | - QStringList words = line.split(regexp); | |
| 112 | - if (words.size() != headers.size()) continue; | |
| 113 | - File fi; | |
| 114 | - for (int j=0; j<words.size(); j++) { | |
| 115 | - if (j == 0) fi.name = words[j]; | |
| 116 | - else fi.set(headers[j], words[j]); | |
| 96 | + File in; | |
| 97 | + for (int j=0; j<values.size(); j++) { | |
| 98 | + if (j == 0) in.name = values[j].toString(); | |
| 99 | + else in.set(headers[j], values[j].toString()); | |
| 117 | 100 | } |
| 118 | - templates.append(fi); | |
| 119 | - templates.last().file.set("progress", f.pos()); | |
| 101 | + in.set("progress", f.pos()); | |
| 102 | + templates.append(in); | |
| 120 | 103 | } |
| 121 | 104 | *done = f.atEnd(); |
| 122 | - | |
| 123 | 105 | return templates; |
| 124 | 106 | } |
| 125 | 107 | |
| ... | ... | @@ -128,51 +110,27 @@ class csvGallery : public FileGallery |
| 128 | 110 | files.append(t.file); |
| 129 | 111 | } |
| 130 | 112 | |
| 131 | - static QString getCSVElement(const QString &key, const QVariant &value, bool header, int & columnCount) | |
| 113 | + static QVariantList parseLine(const QByteArray bytes) | |
| 132 | 114 | { |
| 133 | - if (header) | |
| 134 | - columnCount = 1; | |
| 135 | - | |
| 136 | - if (value.canConvert<QString>()) { | |
| 137 | - if (header) return key; | |
| 138 | - else { | |
| 139 | - if (columnCount != 1) | |
| 140 | - qFatal("Inconsistent datatype for key %s, csv file cannot be generated", qPrintable(key)); | |
| 141 | - return value.value<QString>(); | |
| 142 | - } | |
| 143 | - } else if (value.canConvert<QPointF>()) { | |
| 144 | - const QPointF point = value.value<QPointF>(); | |
| 145 | - if (header) { | |
| 146 | - columnCount = 2; | |
| 147 | - return key+"_X,"+key+"_Y"; | |
| 148 | - } | |
| 149 | - else { | |
| 150 | - if (columnCount != 2) | |
| 151 | - qFatal("Inconsistent datatype for key %s, csv file cannot be generated", qPrintable(key)); | |
| 152 | - | |
| 153 | - return QString::number(point.x())+","+QString::number(point.y()); | |
| 154 | - } | |
| 155 | - } else if (value.canConvert<QRectF>()) { | |
| 156 | - const QRectF rect = value.value<QRectF>(); | |
| 157 | - if (header) { | |
| 158 | - columnCount = 4; | |
| 159 | - return key+"_X,"+key+"_Y,"+key+"_Width,"+key+"_Height"; | |
| 160 | - } | |
| 161 | - else { | |
| 162 | - if (columnCount != 4) | |
| 163 | - qFatal("Inconsistent datatype for key %s, csv file cannot be generated", qPrintable(key)); | |
| 164 | - | |
| 165 | - return QString::number(rect.x())+","+QString::number(rect.y())+","+QString::number(rect.width())+","+QString::number(rect.height()); | |
| 166 | - } | |
| 167 | - } else { | |
| 168 | - if (header) return key; | |
| 169 | - else { | |
| 170 | - QString output = QString::number(std::numeric_limits<float>::quiet_NaN()); | |
| 171 | - for (int i = 1; i < columnCount; i++) | |
| 172 | - output += "," + QString::number(std::numeric_limits<float>::quiet_NaN()); | |
| 173 | - return output; | |
| 174 | - } | |
| 115 | + bool inQuote(false); | |
| 116 | + QVariantList values; | |
| 117 | + QString value = QString(); | |
| 118 | + const QString line = QString::fromLocal8Bit(bytes).trimmed(); | |
| 119 | + for (int i=0; i<line.size(); i++) { | |
| 120 | + const QChar c = line[i]; | |
| 121 | + if (c == '"') { | |
| 122 | + inQuote = !inQuote; | |
| 123 | + continue; | |
| 124 | + } else if (c == ',' && !inQuote) { | |
| 125 | + values.append(QVariant(value)); | |
| 126 | + value = QString(); | |
| 127 | + } else | |
| 128 | + value.append(c); | |
| 175 | 129 | } |
| 130 | + if (!value.isEmpty()) | |
| 131 | + values.append(QVariant(value)); | |
| 132 | + | |
| 133 | + return values; | |
| 176 | 134 | } |
| 177 | 135 | }; |
| 178 | 136 | ... | ... |