Blender V4.5
spreadsheet_table.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_viewer_path.hh"
6
7#include "BLI_hash.hh"
8#include "BLI_listbase.h"
9
10#include "DNA_array_utils.hh"
11
12#include "BLO_read_write.hh"
13
14#include "spreadsheet_column.hh"
15#include "spreadsheet_table.hh"
16
18
20{
21 auto *table_id = MEM_callocN<SpreadsheetTableIDGeometry>(__func__);
22 table_id->base.type = SPREADSHEET_TABLE_ID_TYPE_GEOMETRY;
23 return table_id;
24}
25
37
39{
40 switch (eSpreadsheetTableIDType(src_table_id.type)) {
42 const auto &src = *reinterpret_cast<const SpreadsheetTableIDGeometry *>(&src_table_id);
43 auto *new_table_id = spreadsheet_table_id_new_geometry();
45 return &new_table_id->base;
46 }
47 }
48 return nullptr;
49}
50
52{
53 switch (eSpreadsheetTableIDType(table_id->type)) {
55 auto *table_id_ = reinterpret_cast<SpreadsheetTableIDGeometry *>(table_id);
56 BKE_viewer_path_clear(&table_id_->viewer_path);
57 MEM_SAFE_FREE(table_id_->instance_ids);
58 break;
59 }
60 }
61}
62
68
76
78{
79 switch (eSpreadsheetTableIDType(table_id->type)) {
81 const auto *table_id_ = reinterpret_cast<const SpreadsheetTableIDGeometry *>(table_id);
84 break;
85 }
86 }
87}
88
90{
91 switch (eSpreadsheetTableIDType(table_id->type)) {
93 auto *table_id_ = reinterpret_cast<SpreadsheetTableIDGeometry *>(table_id);
94 BKE_viewer_path_blend_read_data(reader, &table_id_->viewer_path);
96 reader, SpreadsheetInstanceID, table_id_->instance_ids_num, &table_id_->instance_ids);
97 break;
98 }
99 }
100}
101
103 const bke::id::IDRemapper &mappings)
104{
105 switch (eSpreadsheetTableIDType(table_id.type)) {
107 auto *table_id_ = reinterpret_cast<SpreadsheetTableIDGeometry *>(&table_id);
108 BKE_viewer_path_id_remap(&table_id_->viewer_path, mappings);
109 break;
110 }
111 }
112}
113
115{
116 switch (eSpreadsheetTableIDType(table_id.type)) {
118 auto *table_id_ = reinterpret_cast<SpreadsheetTableIDGeometry *>(&table_id);
119 BKE_viewer_path_foreach_id(data, &table_id_->viewer_path);
120 break;
121 }
122 }
123}
124
126{
127 if (a.type != b.type) {
128 return false;
129 }
131 switch (type) {
133 const auto &a_ = *reinterpret_cast<const SpreadsheetTableIDGeometry *>(&a);
134 const auto &b_ = *reinterpret_cast<const SpreadsheetTableIDGeometry *>(&b);
136 &a_.viewer_path, &b_.viewer_path, VIEWER_PATH_EQUAL_FLAG_IGNORE_ITERATION) &&
137 a_.geometry_component_type == b_.geometry_component_type &&
138 a_.attribute_domain == b_.attribute_domain &&
139 a_.object_eval_state == b_.object_eval_state && a_.layer_index == b_.layer_index &&
140 blender::Span(a_.instance_ids, a_.instance_ids_num) ==
141 blender::Span(b_.instance_ids, b_.instance_ids_num);
142 }
143 }
144 return true;
145}
146
148{
149 SpreadsheetTable *spreadsheet_table = MEM_callocN<SpreadsheetTable>(__func__);
150 spreadsheet_table->id = table_id;
151 return spreadsheet_table;
152}
153
155{
157 new_table->num_columns = src_table.num_columns;
158 new_table->columns = MEM_calloc_arrayN<SpreadsheetColumn *>(src_table.num_columns, __func__);
159 for (const int i : IndexRange(src_table.num_columns)) {
160 new_table->columns[i] = spreadsheet_column_copy(src_table.columns[i]);
161 }
162 return new_table;
163}
164
166{
168 for (const int i : IndexRange(table->num_columns)) {
170 }
171 MEM_SAFE_FREE(table->columns);
172 MEM_freeN(table);
173}
174
176{
177 BLO_write_struct(writer, SpreadsheetTable, table);
178 spreadsheet_table_id_blend_write(writer, table->id);
179 BLO_write_pointer_array(writer, table->num_columns, table->columns);
180 for (const int i : IndexRange(table->num_columns)) {
182 }
183}
184
186{
187 BLO_read_struct(reader, SpreadsheetTableID, &table->id);
188 spreadsheet_table_id_blend_read(reader, table->id);
189 BLO_read_pointer_array(reader, table->num_columns, reinterpret_cast<void **>(&table->columns));
190 for (const int i : IndexRange(table->num_columns)) {
191 BLO_read_struct(reader, SpreadsheetColumn, &table->columns[i]);
192 spreadsheet_column_blend_read(reader, table->columns[i]);
193 }
194}
195
197{
198 spreadsheet_table_id_remap_id(*table.id, mappings);
199}
200
205
207 const SpreadsheetTableID &table_id)
208{
209 return const_cast<SpreadsheetTable *>(
210 spreadsheet_table_find(const_cast<const SpaceSpreadsheet &>(sspreadsheet), table_id));
211}
212
214 const SpreadsheetTableID &table_id)
215{
216 for (const SpreadsheetTable *table : Span{sspreadsheet.tables, sspreadsheet.num_tables}) {
217 if (spreadsheet_table_id_match(table_id, *table->id)) {
218 return table;
219 }
220 }
221 return nullptr;
222}
223
225{
227 sspreadsheet.num_tables + 1, __func__);
228 std::copy_n(sspreadsheet.tables, sspreadsheet.num_tables, new_tables);
229 new_tables[sspreadsheet.num_tables] = table;
230 MEM_SAFE_FREE(sspreadsheet.tables);
231 sspreadsheet.tables = new_tables;
232 sspreadsheet.num_tables++;
233}
234
236{
237 uint32_t min_last_used = 0;
238 const int max_tables = 50;
239 if (sspreadsheet.num_tables > max_tables) {
240 Vector<uint32_t> last_used_times;
241 for (const SpreadsheetTable *table : Span(sspreadsheet.tables, sspreadsheet.num_tables)) {
242 last_used_times.append(table->last_used);
243 }
244 std::sort(last_used_times.begin(), last_used_times.end());
245 min_last_used = last_used_times[sspreadsheet.num_tables - max_tables];
246 }
247
249 &sspreadsheet.tables,
250 &sspreadsheet.num_tables,
251 [&](const SpreadsheetTable *table) {
252 if (!(table->flag & SPREADSHEET_TABLE_FLAG_MANUALLY_EDITED)) {
253 /* Remove tables that have never been modified manually. Those can be rebuilt from
254 * scratch if necessary. */
255 return true;
256 }
257 if (table->last_used < min_last_used) {
258 /* The table has not been used for a while and there are too many unused tables. So
259 * garbage collect this table. This does remove user-edited column widths and orders, but
260 * doesn't remove any actual data. */
261 return true;
262 }
264 case SPREADSHEET_TABLE_ID_TYPE_GEOMETRY: {
265 const SpreadsheetTableIDGeometry &table_id =
266 *reinterpret_cast<const SpreadsheetTableIDGeometry *>(table->id);
267 LISTBASE_FOREACH (ViewerPathElem *, elem, &table_id.viewer_path.path) {
268 if (elem->type == VIEWER_PATH_ELEM_TYPE_ID) {
269 const IDViewerPathElem &id_elem = reinterpret_cast<const IDViewerPathElem &>(
270 *elem);
271 if (!id_elem.id) {
272 /* Remove tables which reference an ID that does not exist anymore. */
273 return true;
274 }
275 }
276 }
277 break;
278 }
279 }
280 return false;
281 },
282 [](SpreadsheetTable **table) { spreadsheet_table_free(*table); });
283}
284
286{
287 /* Might not be reached exactly if there are many columns with the same last used time. */
288 const int max_unavailable_columns_target = 50;
289 int num_unavailable_columns = 0;
290 for (SpreadsheetColumn *column : Span(table.columns, table.num_columns)) {
291 if (!column->is_available()) {
292 num_unavailable_columns++;
293 }
294 }
295 if (num_unavailable_columns <= max_unavailable_columns_target) {
296 /* No need to remove columns. */
297 return;
298 }
299
300 /* Find the threshold time for unavailable columns to remove. */
301 Vector<uint32_t> last_used_times;
302 for (SpreadsheetColumn *column : Span(table.columns, table.num_columns)) {
303 if (!column->is_available()) {
304 last_used_times.append(column->last_used);
305 }
306 }
307 std::sort(last_used_times.begin(), last_used_times.end());
308 const int min_last_used = last_used_times[max_unavailable_columns_target];
309
311 &table.columns,
312 &table.num_columns,
313 [&](const SpreadsheetColumn *column) {
314 if (column->is_available()) {
315 /* Available columns should never be removed here. */
316 return false;
317 }
318 if (column->last_used > min_last_used) {
319 /* Columns that have been used recently are not removed. */
320 return false;
321 }
322 return true;
323 },
324 [](SpreadsheetColumn **column) { spreadsheet_column_free(*column); });
325}
326
328{
329 const int old_index = Span(sspreadsheet.tables, sspreadsheet.num_tables).first_index(&table);
330 dna::array::move_index(sspreadsheet.tables, sspreadsheet.num_tables, old_index, 0);
331}
332
333} // namespace blender::ed::spreadsheet
void BKE_viewer_path_copy(ViewerPath *dst, const ViewerPath *src)
void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const blender::bke::id::IDRemapper &mappings)
@ VIEWER_PATH_EQUAL_FLAG_IGNORE_ITERATION
void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_path)
void BKE_viewer_path_clear(ViewerPath *viewer_path)
void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer_path)
bool BKE_viewer_path_equal(const ViewerPath *a, const ViewerPath *b, ViewerPathEqualFlag flag=ViewerPathEqualFlag(0))
void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_path)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_write_pointer_array(BlendWriter *writer, int64_t num, const void *data_ptr)
void BLO_read_pointer_array(BlendDataReader *reader, int64_t array_size, void **ptr_p)
Definition readfile.cc:5402
eSpreadsheetTableIDType
@ SPREADSHEET_TABLE_ID_TYPE_GEOMETRY
switch((BMIterType) itype)
BMesh const char void * data
constexpr int64_t first_index(const T &search_value) const
Definition BLI_span.hh:377
void append(const T &value)
#define MEM_SAFE_FREE(v)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void remove_if(T **items, int *items_num, FunctionRef< bool(const T &)> predicate, void(*destruct_item)(T *))
void move_index(T *items, const int items_num, const int from_index, const int to_index)
void spreadsheet_table_move_to_front(SpaceSpreadsheet &sspreadsheet, SpreadsheetTable &table)
void spreadsheet_table_id_free(SpreadsheetTableID *table_id)
void spreadsheet_table_blend_write(BlendWriter *writer, const SpreadsheetTable *table)
void spreadsheet_table_id_blend_write(BlendWriter *writer, const SpreadsheetTableID *table_id)
void spreadsheet_column_blend_write(BlendWriter *writer, const SpreadsheetColumn *column)
void spreadsheet_table_blend_read(BlendDataReader *reader, SpreadsheetTable *table)
void spreadsheet_table_remove_unused(SpaceSpreadsheet &sspreadsheet)
void spreadsheet_column_blend_read(BlendDataReader *reader, SpreadsheetColumn *column)
void spreadsheet_table_id_free_content(SpreadsheetTableID *table_id)
SpreadsheetTableID * spreadsheet_table_id_copy(const SpreadsheetTableID &src_table_id)
void spreadsheet_table_id_copy_content_geometry(SpreadsheetTableIDGeometry &dst, const SpreadsheetTableIDGeometry &src)
void spreadsheet_table_id_blend_write_content_geometry(BlendWriter *writer, const SpreadsheetTableIDGeometry *table_id)
void spreadsheet_table_id_blend_read(BlendDataReader *reader, SpreadsheetTableID *table_id)
void spreadsheet_table_remove_unused_columns(SpreadsheetTable &table)
SpreadsheetTableIDGeometry * spreadsheet_table_id_new_geometry()
void spreadsheet_table_id_foreach_id(SpreadsheetTableID &table_id, LibraryForeachIDData *data)
SpreadsheetTable * spreadsheet_table_new(SpreadsheetTableID *table_id)
void spreadsheet_column_free(SpreadsheetColumn *column)
void spreadsheet_table_free(SpreadsheetTable *table)
void spreadsheet_table_foreach_id(SpreadsheetTable &table, LibraryForeachIDData *data)
bool spreadsheet_table_id_match(const SpreadsheetTableID &a, const SpreadsheetTableID &b)
SpreadsheetTable * spreadsheet_table_copy(const SpreadsheetTable &src_table)
void spreadsheet_table_remap_id(SpreadsheetTable &table, const bke::id::IDRemapper &mappings)
SpreadsheetColumn * spreadsheet_column_copy(const SpreadsheetColumn *src_column)
void spreadsheet_table_id_remap_id(SpreadsheetTableID &table_id, const bke::id::IDRemapper &mappings)
SpreadsheetTable * spreadsheet_table_find(SpaceSpreadsheet &sspreadsheet, const SpreadsheetTableID &table_id)
void spreadsheet_table_add(SpaceSpreadsheet &sspreadsheet, SpreadsheetTable *table)
SpreadsheetTable ** tables
SpreadsheetInstanceID * instance_ids
SpreadsheetColumn ** columns
SpreadsheetTableID * id
i
Definition text_draw.cc:230