react-native-nitro-xlsx 0.1.2 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +8 -35
- package/NitroXlsx.podspec +21 -57
- package/Package.swift +35 -0
- package/README.md +243 -36
- package/android/CMakeLists.txt +17 -23
- package/android/build.gradle +6 -0
- package/android/cpp-adapter.cpp +12 -0
- package/android/src/main/java/com/margelo/nitro/xlsx/NitroXlsxPackage.kt +9 -0
- package/cpp/HybridNitroXlsx.cpp +32 -9
- package/cpp/HybridNitroXlsx.hpp +2 -1
- package/cpp/HybridXlsxConditionalFormat.cpp +252 -0
- package/cpp/HybridXlsxConditionalFormat.hpp +62 -0
- package/cpp/HybridXlsxConditionalFormats.cpp +46 -0
- package/cpp/HybridXlsxConditionalFormats.hpp +28 -0
- package/cpp/HybridXlsxWorkbook.cpp +162 -87
- package/cpp/HybridXlsxWorkbook.hpp +7 -1
- package/cpp/HybridXlsxWorksheet.cpp +456 -61
- package/cpp/HybridXlsxWorksheet.hpp +73 -26
- package/cpp/XlsxCacheDir.cpp +76 -0
- package/cpp/XlsxCacheDir.hpp +27 -0
- package/cpp/XlsxError.hpp +68 -0
- package/cpp/XlsxJson.cpp +185 -0
- package/cpp/XlsxJson.hpp +36 -0
- package/ios/XlsxCacheDir.mm +60 -0
- package/nitrogen/generated/android/NitroXlsx+autolinking.cmake +2 -0
- package/nitrogen/generated/shared/c++/HybridNitroXlsxSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridNitroXlsxSpec.hpp +5 -2
- package/nitrogen/generated/shared/c++/HybridXlsxConditionalFormatSpec.cpp +54 -0
- package/nitrogen/generated/shared/c++/HybridXlsxConditionalFormatSpec.hpp +95 -0
- package/nitrogen/generated/shared/c++/HybridXlsxConditionalFormatsSpec.cpp +24 -0
- package/nitrogen/generated/shared/c++/HybridXlsxConditionalFormatsSpec.hpp +68 -0
- package/nitrogen/generated/shared/c++/HybridXlsxWorkbookSpec.cpp +4 -0
- package/nitrogen/generated/shared/c++/HybridXlsxWorkbookSpec.hpp +7 -0
- package/nitrogen/generated/shared/c++/HybridXlsxWorksheetSpec.cpp +47 -19
- package/nitrogen/generated/shared/c++/HybridXlsxWorksheetSpec.hpp +52 -20
- package/package.json +5 -2
- package/scripts/prepare-openxlsx.js +126 -0
- package/scripts/run-cpp-tests.sh +14 -0
- package/src/__mocks__/react-native-nitro-modules.ts +1 -0
- package/src/__tests__/index.test.ts +76 -7
- package/src/index.ts +110 -9
- package/src/specs/NitroXlsx.nitro.ts +141 -42
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
#include "HybridXlsxWorksheet.hpp"
|
|
2
|
+
#include "XlsxError.hpp"
|
|
3
|
+
#include "XlsxJson.hpp"
|
|
4
|
+
#include <OpenXLSX/XLCellReference.hpp>
|
|
2
5
|
#include <cstring>
|
|
6
|
+
#include <cmath>
|
|
3
7
|
#include <fstream>
|
|
4
8
|
#include <chrono>
|
|
5
9
|
|
|
@@ -23,80 +27,174 @@ void HybridXlsxWorksheet::applyFormat(OpenXLSX::XLCell& cell, const std::optiona
|
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
void HybridXlsxWorksheet::writeString(double row, double col, const std::string& value, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
31
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
32
|
+
cell.value() = value;
|
|
33
|
+
applyFormat(cell, format);
|
|
34
|
+
});
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
void HybridXlsxWorksheet::writeNumber(double row, double col, double value, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
39
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
40
|
+
cell.value() = value;
|
|
41
|
+
applyFormat(cell, format);
|
|
42
|
+
});
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
void HybridXlsxWorksheet::writeBoolean(double row, double col, bool value, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
47
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
48
|
+
cell.value() = value;
|
|
49
|
+
applyFormat(cell, format);
|
|
50
|
+
});
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
void HybridXlsxWorksheet::writeBlank(double row, double col, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
55
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
56
|
+
applyFormat(cell, format);
|
|
57
|
+
});
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
void HybridXlsxWorksheet::writeFormula(double row, double col, const std::string& formula, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
62
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
63
|
+
cell.formula() = formula;
|
|
64
|
+
applyFormat(cell, format);
|
|
65
|
+
});
|
|
52
66
|
}
|
|
53
67
|
|
|
54
68
|
void HybridXlsxWorksheet::writeFormulaNum(double row, double col, const std::string& formula, double number, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
69
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
70
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
71
|
+
cell.formula() = formula;
|
|
72
|
+
cell.value() = number;
|
|
73
|
+
applyFormat(cell, format);
|
|
74
|
+
});
|
|
59
75
|
}
|
|
60
76
|
|
|
61
77
|
void HybridXlsxWorksheet::writeFormulaString(double row, double col, const std::string& formula, const std::string& str, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
78
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
79
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
80
|
+
cell.formula() = formula;
|
|
81
|
+
cell.value() = str;
|
|
82
|
+
applyFormat(cell, format);
|
|
83
|
+
});
|
|
66
84
|
}
|
|
67
85
|
|
|
68
86
|
void HybridXlsxWorksheet::writeFormulaBoolean(double row, double col, const std::string& formula, bool boolVal, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
87
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
88
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
89
|
+
cell.formula() = formula;
|
|
90
|
+
cell.value() = boolVal;
|
|
91
|
+
applyFormat(cell, format);
|
|
92
|
+
});
|
|
73
93
|
}
|
|
74
94
|
|
|
75
95
|
void HybridXlsxWorksheet::writeArrayFormula(double firstRow, double firstCol, double lastRow, double lastCol, const std::string& formula, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
76
|
-
|
|
77
|
-
|
|
96
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
97
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(firstRow), static_cast<unsigned int>(firstCol));
|
|
98
|
+
cell.formula() = formula;
|
|
99
|
+
applyFormat(cell, format);
|
|
100
|
+
});
|
|
78
101
|
}
|
|
79
102
|
|
|
80
103
|
void HybridXlsxWorksheet::writeDatetime(double row, double col, double datetime, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
104
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
105
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
106
|
+
cell.value() = datetime;
|
|
107
|
+
applyFormat(cell, format);
|
|
108
|
+
});
|
|
84
109
|
}
|
|
85
110
|
|
|
86
111
|
void HybridXlsxWorksheet::writeURL(double row, double col, const std::string& url, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
112
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
113
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), static_cast<unsigned int>(col));
|
|
114
|
+
cell.value() = url;
|
|
115
|
+
applyFormat(cell, format);
|
|
116
|
+
});
|
|
90
117
|
}
|
|
91
118
|
|
|
92
119
|
void HybridXlsxWorksheet::setColumn(double firstCol, double lastCol, double width, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
93
120
|
for (unsigned int c = static_cast<unsigned int>(firstCol); c <= static_cast<unsigned int>(lastCol); ++c) {
|
|
94
121
|
_worksheet.column(c).setWidth(static_cast<float>(width));
|
|
95
122
|
}
|
|
123
|
+
if (format.has_value()) {
|
|
124
|
+
// Apply format to entire column range by setting it on cells in the first row
|
|
125
|
+
// (OpenXLSX does not support column-level style; apply to first row cells as a hint)
|
|
126
|
+
auto hybridFormat = std::dynamic_pointer_cast<HybridXlsxCellFormat>(*format);
|
|
127
|
+
if (hybridFormat) {
|
|
128
|
+
auto styleIndex = hybridFormat->applyToDocument(_doc.styles());
|
|
129
|
+
for (unsigned int c = static_cast<unsigned int>(firstCol); c <= static_cast<unsigned int>(lastCol); ++c) {
|
|
130
|
+
OpenXLSX::XLCell cell = _worksheet.cell(1, c);
|
|
131
|
+
hybridFormat->applyToCell(cell, styleIndex);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
96
135
|
}
|
|
97
136
|
|
|
98
137
|
void HybridXlsxWorksheet::setRow(double row, double height, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
99
138
|
_worksheet.row(static_cast<unsigned int>(row)).setHeight(static_cast<float>(height));
|
|
139
|
+
if (format.has_value()) {
|
|
140
|
+
auto hybridFormat = std::dynamic_pointer_cast<HybridXlsxCellFormat>(*format);
|
|
141
|
+
if (hybridFormat) {
|
|
142
|
+
auto styleIndex = hybridFormat->applyToDocument(_doc.styles());
|
|
143
|
+
unsigned int colCount = _worksheet.columnCount();
|
|
144
|
+
for (unsigned int c = 1; c <= colCount; ++c) {
|
|
145
|
+
OpenXLSX::XLCell cell = _worksheet.cell(static_cast<unsigned int>(row), c);
|
|
146
|
+
hybridFormat->applyToCell(cell, styleIndex);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
bool HybridXlsxWorksheet::deleteRow(double row) {
|
|
153
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
154
|
+
return _worksheet.deleteRow(static_cast<uint32_t>(row));
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
bool HybridXlsxWorksheet::deleteColumn(double col) {
|
|
159
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
160
|
+
unsigned int targetCol = static_cast<unsigned int>(col);
|
|
161
|
+
if (targetCol < 1) {
|
|
162
|
+
throw XlsxError(xlsx_error::INVALID_ARGUMENT, "Column index must be >= 1");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
unsigned int lastCol = _worksheet.columnCount();
|
|
166
|
+
unsigned int lastRow = _worksheet.rowCount();
|
|
167
|
+
if (targetCol > lastCol) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Shift cell contents left for every row
|
|
172
|
+
for (unsigned int r = 1; r <= lastRow; ++r) {
|
|
173
|
+
for (unsigned int c = targetCol + 1; c <= lastCol; ++c) {
|
|
174
|
+
OpenXLSX::XLCell src = _worksheet.cell(r, c);
|
|
175
|
+
OpenXLSX::XLCell dst = _worksheet.cell(r, c - 1);
|
|
176
|
+
if (!src.empty()) {
|
|
177
|
+
dst.copyFrom(src);
|
|
178
|
+
dst.setCellFormat(src.cellFormat());
|
|
179
|
+
} else {
|
|
180
|
+
dst.clear(0);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Clear the trailing column
|
|
184
|
+
OpenXLSX::XLCell trailing = _worksheet.cell(r, lastCol);
|
|
185
|
+
trailing.clear(0);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Shift column widths / hidden state left
|
|
189
|
+
for (unsigned int c = targetCol + 1; c <= lastCol; ++c) {
|
|
190
|
+
OpenXLSX::XLColumn srcCol = _worksheet.column(c);
|
|
191
|
+
OpenXLSX::XLColumn dstCol = _worksheet.column(c - 1);
|
|
192
|
+
dstCol.setWidth(srcCol.width());
|
|
193
|
+
dstCol.setHidden(srcCol.isHidden());
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return true;
|
|
197
|
+
});
|
|
100
198
|
}
|
|
101
199
|
|
|
102
200
|
void HybridXlsxWorksheet::mergeRange(double firstRow, double firstCol, double lastRow, double lastCol, const std::string& value, const std::optional<std::shared_ptr<HybridXlsxCellFormatSpec>>& format) {
|
|
@@ -119,75 +217,251 @@ void HybridXlsxWorksheet::mergeRangeNum(double firstRow, double firstCol, double
|
|
|
119
217
|
applyFormat(cell, format);
|
|
120
218
|
}
|
|
121
219
|
|
|
122
|
-
void HybridXlsxWorksheet::
|
|
220
|
+
void HybridXlsxWorksheet::unmergeCells(double firstRow, double firstCol, double lastRow, double lastCol) {
|
|
221
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
222
|
+
OpenXLSX::XLCellReference topLeft(static_cast<unsigned int>(firstRow), static_cast<unsigned int>(firstCol));
|
|
223
|
+
OpenXLSX::XLCellReference bottomRight(static_cast<unsigned int>(lastRow), static_cast<unsigned int>(lastCol));
|
|
224
|
+
std::string rangeRef = topLeft.address() + ":" + bottomRight.address();
|
|
225
|
+
_worksheet.unmergeCells(rangeRef);
|
|
226
|
+
});
|
|
123
227
|
}
|
|
124
228
|
|
|
125
|
-
void HybridXlsxWorksheet::
|
|
229
|
+
void HybridXlsxWorksheet::hide() {
|
|
230
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
231
|
+
_worksheet.setVisibility(OpenXLSX::XLSheetState::Hidden);
|
|
232
|
+
});
|
|
126
233
|
}
|
|
127
234
|
|
|
128
|
-
void HybridXlsxWorksheet::
|
|
235
|
+
void HybridXlsxWorksheet::activate() {
|
|
236
|
+
_worksheet.setActive();
|
|
129
237
|
}
|
|
130
238
|
|
|
131
|
-
|
|
239
|
+
// ========== Sheet protection ==========
|
|
240
|
+
|
|
241
|
+
namespace {
|
|
242
|
+
// OpenXLSX defaults `set` to true when the argument is omitted
|
|
243
|
+
bool resolveSet(const std::optional<bool>& set) {
|
|
244
|
+
return set.value_or(true);
|
|
245
|
+
}
|
|
132
246
|
}
|
|
133
247
|
|
|
134
|
-
void HybridXlsxWorksheet::
|
|
248
|
+
void HybridXlsxWorksheet::protect(const std::optional<std::string>& password) {
|
|
249
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
250
|
+
if (password.has_value() && !password->empty()) {
|
|
251
|
+
if (!_worksheet.setPassword(*password)) {
|
|
252
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set sheet password");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (!_worksheet.protectSheet()) {
|
|
256
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to protect sheet");
|
|
257
|
+
}
|
|
258
|
+
});
|
|
135
259
|
}
|
|
136
260
|
|
|
137
|
-
void HybridXlsxWorksheet::
|
|
261
|
+
void HybridXlsxWorksheet::protectSheet(std::optional<bool> set) {
|
|
262
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
263
|
+
if (!_worksheet.protectSheet(resolveSet(set))) {
|
|
264
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set protectSheet");
|
|
265
|
+
}
|
|
266
|
+
});
|
|
138
267
|
}
|
|
139
268
|
|
|
140
|
-
void HybridXlsxWorksheet::
|
|
269
|
+
void HybridXlsxWorksheet::protectObjects(std::optional<bool> set) {
|
|
270
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
271
|
+
if (!_worksheet.protectObjects(resolveSet(set))) {
|
|
272
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set protectObjects");
|
|
273
|
+
}
|
|
274
|
+
});
|
|
141
275
|
}
|
|
142
276
|
|
|
143
|
-
void HybridXlsxWorksheet::
|
|
144
|
-
|
|
277
|
+
void HybridXlsxWorksheet::protectScenarios(std::optional<bool> set) {
|
|
278
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
279
|
+
if (!_worksheet.protectScenarios(resolveSet(set))) {
|
|
280
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set protectScenarios");
|
|
281
|
+
}
|
|
282
|
+
});
|
|
145
283
|
}
|
|
146
284
|
|
|
147
|
-
|
|
285
|
+
// ========== Password ==========
|
|
286
|
+
|
|
287
|
+
void HybridXlsxWorksheet::setPassword(const std::string& password) {
|
|
288
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
289
|
+
if (!_worksheet.setPassword(password)) {
|
|
290
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set password");
|
|
291
|
+
}
|
|
292
|
+
});
|
|
148
293
|
}
|
|
149
294
|
|
|
150
|
-
void HybridXlsxWorksheet::
|
|
151
|
-
|
|
152
|
-
_worksheet.
|
|
153
|
-
|
|
154
|
-
|
|
295
|
+
void HybridXlsxWorksheet::setPasswordHash(const std::string& hash) {
|
|
296
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
297
|
+
if (!_worksheet.setPasswordHash(hash)) {
|
|
298
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set password hash");
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
void HybridXlsxWorksheet::clearPassword() {
|
|
304
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
305
|
+
if (!_worksheet.clearPassword()) {
|
|
306
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to clear password");
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
void HybridXlsxWorksheet::clearSheetProtection() {
|
|
312
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
313
|
+
if (!_worksheet.clearSheetProtection()) {
|
|
314
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to clear sheet protection");
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// ========== Fine-grained permissions ==========
|
|
320
|
+
|
|
321
|
+
void HybridXlsxWorksheet::allowInsertColumns(std::optional<bool> set) {
|
|
322
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
323
|
+
if (!_worksheet.allowInsertColumns(resolveSet(set))) {
|
|
324
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set allowInsertColumns");
|
|
325
|
+
}
|
|
326
|
+
});
|
|
155
327
|
}
|
|
156
328
|
|
|
157
|
-
void HybridXlsxWorksheet::
|
|
329
|
+
void HybridXlsxWorksheet::allowInsertRows(std::optional<bool> set) {
|
|
330
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
331
|
+
if (!_worksheet.allowInsertRows(resolveSet(set))) {
|
|
332
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set allowInsertRows");
|
|
333
|
+
}
|
|
334
|
+
});
|
|
158
335
|
}
|
|
159
336
|
|
|
160
|
-
void HybridXlsxWorksheet::
|
|
337
|
+
void HybridXlsxWorksheet::allowDeleteColumns(std::optional<bool> set) {
|
|
338
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
339
|
+
if (!_worksheet.allowDeleteColumns(resolveSet(set))) {
|
|
340
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set allowDeleteColumns");
|
|
341
|
+
}
|
|
342
|
+
});
|
|
161
343
|
}
|
|
162
344
|
|
|
163
|
-
void HybridXlsxWorksheet::
|
|
345
|
+
void HybridXlsxWorksheet::allowDeleteRows(std::optional<bool> set) {
|
|
346
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
347
|
+
if (!_worksheet.allowDeleteRows(resolveSet(set))) {
|
|
348
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set allowDeleteRows");
|
|
349
|
+
}
|
|
350
|
+
});
|
|
164
351
|
}
|
|
165
352
|
|
|
166
|
-
void HybridXlsxWorksheet::
|
|
353
|
+
void HybridXlsxWorksheet::allowSelectLockedCells(std::optional<bool> set) {
|
|
354
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
355
|
+
if (!_worksheet.allowSelectLockedCells(resolveSet(set))) {
|
|
356
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set allowSelectLockedCells");
|
|
357
|
+
}
|
|
358
|
+
});
|
|
167
359
|
}
|
|
168
360
|
|
|
169
|
-
void HybridXlsxWorksheet::
|
|
361
|
+
void HybridXlsxWorksheet::allowSelectUnlockedCells(std::optional<bool> set) {
|
|
362
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
363
|
+
if (!_worksheet.allowSelectUnlockedCells(resolveSet(set))) {
|
|
364
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set allowSelectUnlockedCells");
|
|
365
|
+
}
|
|
366
|
+
});
|
|
170
367
|
}
|
|
171
368
|
|
|
172
|
-
void HybridXlsxWorksheet::
|
|
369
|
+
void HybridXlsxWorksheet::denyInsertColumns() {
|
|
370
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
371
|
+
if (!_worksheet.denyInsertColumns()) {
|
|
372
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to denyInsertColumns");
|
|
373
|
+
}
|
|
374
|
+
});
|
|
173
375
|
}
|
|
174
376
|
|
|
175
|
-
void HybridXlsxWorksheet::
|
|
377
|
+
void HybridXlsxWorksheet::denyInsertRows() {
|
|
378
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
379
|
+
if (!_worksheet.denyInsertRows()) {
|
|
380
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to denyInsertRows");
|
|
381
|
+
}
|
|
382
|
+
});
|
|
176
383
|
}
|
|
177
384
|
|
|
178
|
-
void HybridXlsxWorksheet::
|
|
385
|
+
void HybridXlsxWorksheet::denyDeleteColumns() {
|
|
386
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
387
|
+
if (!_worksheet.denyDeleteColumns()) {
|
|
388
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to denyDeleteColumns");
|
|
389
|
+
}
|
|
390
|
+
});
|
|
179
391
|
}
|
|
180
392
|
|
|
181
|
-
void HybridXlsxWorksheet::
|
|
393
|
+
void HybridXlsxWorksheet::denyDeleteRows() {
|
|
394
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
395
|
+
if (!_worksheet.denyDeleteRows()) {
|
|
396
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to denyDeleteRows");
|
|
397
|
+
}
|
|
398
|
+
});
|
|
182
399
|
}
|
|
183
400
|
|
|
184
|
-
void HybridXlsxWorksheet::
|
|
401
|
+
void HybridXlsxWorksheet::denySelectLockedCells() {
|
|
402
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
403
|
+
if (!_worksheet.denySelectLockedCells()) {
|
|
404
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to denySelectLockedCells");
|
|
405
|
+
}
|
|
406
|
+
});
|
|
185
407
|
}
|
|
186
408
|
|
|
187
|
-
void HybridXlsxWorksheet::
|
|
409
|
+
void HybridXlsxWorksheet::denySelectUnlockedCells() {
|
|
410
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
411
|
+
if (!_worksheet.denySelectUnlockedCells()) {
|
|
412
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to denySelectUnlockedCells");
|
|
413
|
+
}
|
|
414
|
+
});
|
|
188
415
|
}
|
|
189
416
|
|
|
190
|
-
|
|
417
|
+
// ========== Protection state ==========
|
|
418
|
+
|
|
419
|
+
bool HybridXlsxWorksheet::sheetProtected() {
|
|
420
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.sheetProtected(); });
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
bool HybridXlsxWorksheet::objectsProtected() {
|
|
424
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.objectsProtected(); });
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
bool HybridXlsxWorksheet::scenariosProtected() {
|
|
428
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.scenariosProtected(); });
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
bool HybridXlsxWorksheet::insertColumnsAllowed() {
|
|
432
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.insertColumnsAllowed(); });
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
bool HybridXlsxWorksheet::insertRowsAllowed() {
|
|
436
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.insertRowsAllowed(); });
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
bool HybridXlsxWorksheet::deleteColumnsAllowed() {
|
|
440
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.deleteColumnsAllowed(); });
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
bool HybridXlsxWorksheet::deleteRowsAllowed() {
|
|
444
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.deleteRowsAllowed(); });
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
bool HybridXlsxWorksheet::selectLockedCellsAllowed() {
|
|
448
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.selectLockedCellsAllowed(); });
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
bool HybridXlsxWorksheet::selectUnlockedCellsAllowed() {
|
|
452
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.selectUnlockedCellsAllowed(); });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
bool HybridXlsxWorksheet::passwordIsSet() {
|
|
456
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.passwordIsSet(); });
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
std::string HybridXlsxWorksheet::passwordHash() {
|
|
460
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.passwordHash(); });
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
std::string HybridXlsxWorksheet::sheetProtectionSummary() {
|
|
464
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] { return _worksheet.sheetProtectionSummary(); });
|
|
191
465
|
}
|
|
192
466
|
|
|
193
467
|
void HybridXlsxWorksheet::setColumnHidden(double firstCol, double lastCol, bool hidden) {
|
|
@@ -317,4 +591,125 @@ std::string HybridXlsxWorksheet::getName() {
|
|
|
317
591
|
return _worksheet.name();
|
|
318
592
|
}
|
|
319
593
|
|
|
594
|
+
void HybridXlsxWorksheet::applyRename(const std::string& oldName, const std::string& newName) {
|
|
595
|
+
_worksheet.setName(newName);
|
|
596
|
+
_worksheet.updateSheetName(oldName, newName);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
void HybridXlsxWorksheet::rewriteSheetNameRef(const std::string& oldName, const std::string& newName) {
|
|
600
|
+
_worksheet.updateSheetName(oldName, newName);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// ========== JSON import / export (this worksheet) ==========
|
|
604
|
+
|
|
605
|
+
std::vector<std::shared_ptr<AnyMap>> HybridXlsxWorksheet::toJSON(const std::optional<std::vector<std::string>>& keys) {
|
|
606
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
607
|
+
return worksheetToRecords(_worksheet, keys);
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
void HybridXlsxWorksheet::fromJSON(const std::vector<std::shared_ptr<AnyMap>>& data) {
|
|
612
|
+
withXlsxError(xlsx_error::INVALID_ARGUMENT, [&] {
|
|
613
|
+
recordsToWorksheet(_worksheet, data);
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
std::string HybridXlsxWorksheet::cellAddress(double row, double col) {
|
|
618
|
+
return OpenXLSX::XLCellReference(static_cast<uint32_t>(row), static_cast<uint16_t>(col)).address();
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// ========== Comments ==========
|
|
622
|
+
|
|
623
|
+
void HybridXlsxWorksheet::setComment(double row, double col, const std::string& text, std::optional<double> authorId) {
|
|
624
|
+
withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
625
|
+
std::string ref = cellAddress(row, col);
|
|
626
|
+
auto& comments = _worksheet.comments();
|
|
627
|
+
// Excel requires every comment's authorId to reference a real <author> entry.
|
|
628
|
+
// OpenXLSX does not auto-register authors, so ensure at least one exists here;
|
|
629
|
+
// otherwise the generated comments.xml has an empty <authors> + a dangling authorId,
|
|
630
|
+
// which Excel flags as "We found a problem with some content".
|
|
631
|
+
if (comments.authorCount() == 0) {
|
|
632
|
+
comments.addAuthor("Author"); // becomes index 0
|
|
633
|
+
}
|
|
634
|
+
uint16_t author = authorId.has_value() ? static_cast<uint16_t>(*authorId) : 0;
|
|
635
|
+
if (author >= comments.authorCount()) {
|
|
636
|
+
author = 0; // fall back to a valid author
|
|
637
|
+
}
|
|
638
|
+
if (!comments.set(ref, text, author)) {
|
|
639
|
+
throw XlsxError(xlsx_error::XLSX_ERROR, "Failed to set comment for cell " + ref);
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
std::string HybridXlsxWorksheet::getComment(double row, double col) {
|
|
645
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
646
|
+
return _worksheet.comments().get(cellAddress(row, col));
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
bool HybridXlsxWorksheet::hasComment(double row, double col) {
|
|
651
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
652
|
+
std::string text = _worksheet.comments().get(cellAddress(row, col));
|
|
653
|
+
return !text.empty();
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
bool HybridXlsxWorksheet::deleteComment(double row, double col) {
|
|
658
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
659
|
+
return _worksheet.comments().deleteComment(cellAddress(row, col));
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
double HybridXlsxWorksheet::getCommentCount() {
|
|
664
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
665
|
+
return static_cast<double>(_worksheet.comments().count());
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
double HybridXlsxWorksheet::addCommentAuthor(const std::string& author) {
|
|
670
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
671
|
+
return static_cast<double>(_worksheet.comments().addAuthor(author));
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
std::string HybridXlsxWorksheet::getCommentAuthor(double authorId) {
|
|
676
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
677
|
+
return _worksheet.comments().author(static_cast<uint16_t>(authorId));
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// ========== Conditional formatting ==========
|
|
682
|
+
|
|
683
|
+
std::shared_ptr<HybridXlsxConditionalFormatsSpec> HybridXlsxWorksheet::getConditionalFormats() {
|
|
684
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
685
|
+
return std::static_pointer_cast<HybridXlsxConditionalFormatsSpec>(
|
|
686
|
+
std::make_shared<HybridXlsxConditionalFormats>(_worksheet.conditionalFormats()));
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// ========== Formula / findCell ==========
|
|
691
|
+
|
|
692
|
+
bool HybridXlsxWorksheet::hasFormula(double row, double col) {
|
|
693
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
694
|
+
OpenXLSX::XLCellAssignable cell = _worksheet.findCell(static_cast<uint32_t>(row), static_cast<uint16_t>(col));
|
|
695
|
+
if (cell.empty()) return false;
|
|
696
|
+
return cell.hasFormula();
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
std::string HybridXlsxWorksheet::formula(double row, double col) {
|
|
701
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
702
|
+
OpenXLSX::XLCellAssignable cell = _worksheet.findCell(static_cast<uint32_t>(row), static_cast<uint16_t>(col));
|
|
703
|
+
if (cell.empty() || !cell.hasFormula()) return std::string();
|
|
704
|
+
return cell.formula().get();
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
bool HybridXlsxWorksheet::findCell(double row, double col) {
|
|
709
|
+
return withXlsxError(xlsx_error::XLSX_ERROR, [&] {
|
|
710
|
+
OpenXLSX::XLCellAssignable cell = _worksheet.findCell(static_cast<uint32_t>(row), static_cast<uint16_t>(col));
|
|
711
|
+
return !cell.empty();
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
|
|
320
715
|
}
|