Line data Source code
1 : /* File: consistency_lifeline.c; Copyright and License: see below */
2 :
3 : #include "consistency/consistency_lifeline.h"
4 : #include "ctrl_classifier_controller.h"
5 : #include "ctrl_diagram_controller.h"
6 : #include "set/data_full_id_list.h"
7 : #include "set/data_visible_set.h"
8 : #include "u8/u8_trace.h"
9 : #include "u8/u8_log.h"
10 :
11 : /*!
12 : * \brief constants of consistency_lifeline_t
13 : */
14 : enum consistency_lifeline_const_enum {
15 : CONSISTENCY_LIFELINE_CONST_MAX_TEMP_DIAGELES = DATA_VISIBLE_SET_MAX_CLASSIFIERS, /*!< maximum number of diagramelements in a diagram */
16 : };
17 :
18 47 : void consistency_lifeline_init( consistency_lifeline_t *this_,
19 : data_database_reader_t *db_reader,
20 : struct ctrl_classifier_controller_struct *clfy_ctrl,
21 : struct ctrl_diagram_controller_struct *diag_ctrl )
22 : {
23 47 : U8_TRACE_BEGIN();
24 47 : assert( NULL != db_reader );
25 47 : assert( NULL != clfy_ctrl );
26 47 : assert( NULL != diag_ctrl );
27 :
28 47 : (*this_).db_reader = db_reader;
29 47 : (*this_).clfy_ctrl = clfy_ctrl;
30 47 : (*this_).diag_ctrl = diag_ctrl;
31 47 : data_rules_init( &((*this_).rules) );
32 :
33 47 : U8_TRACE_END();
34 47 : }
35 :
36 47 : void consistency_lifeline_destroy( consistency_lifeline_t *this_ )
37 : {
38 47 : U8_TRACE_BEGIN();
39 :
40 47 : (*this_).db_reader = NULL;
41 47 : (*this_).clfy_ctrl = NULL;
42 47 : (*this_).diag_ctrl = NULL;
43 47 : data_rules_destroy( &((*this_).rules) );
44 :
45 47 : U8_TRACE_END();
46 47 : }
47 :
48 9 : u8_error_t consistency_lifeline_delete_lifelines ( consistency_lifeline_t *this_,
49 : const data_diagram_t *updated_diagram,
50 : consistency_stat_t *io_stat
51 : )
52 : {
53 9 : U8_TRACE_BEGIN();
54 9 : assert( NULL != updated_diagram );
55 9 : assert( NULL != io_stat );
56 9 : u8_error_t result = U8_ERROR_NONE;
57 :
58 9 : const data_diagram_type_t new_type = data_diagram_get_diagram_type ( updated_diagram );
59 9 : if ( ! data_rules_diagram_is_scenario( &((*this_).rules), new_type ) )
60 : {
61 : /* this diagram type must not have any lifelines */
62 : data_small_set_t lifelines_to_delete;
63 5 : data_small_set_init( &lifelines_to_delete );
64 :
65 : /* search all contained diagramelements */
66 5 : const data_row_t diagram_id = data_diagram_get_row ( updated_diagram );
67 : data_diagramelement_iterator_t diagramelement_iterator;
68 5 : data_diagramelement_iterator_init_empty( &diagramelement_iterator );
69 5 : result |= data_database_reader_get_diagramelements_by_diagram_id( (*this_).db_reader,
70 : diagram_id,
71 : &diagramelement_iterator
72 : );
73 5 : if ( U8_ERROR_NONE == result )
74 : {
75 : /* search the diagramelements */
76 12 : while ( data_diagramelement_iterator_has_next( &diagramelement_iterator ) )
77 : {
78 7 : result |= data_diagramelement_iterator_next( &diagramelement_iterator, &((*this_).temp_diagelement_buf) );
79 : const data_id_t feat_to_delete
80 7 : = data_diagramelement_get_focused_feature_data_id( &((*this_).temp_diagelement_buf) );
81 7 : if ( data_id_is_valid( &feat_to_delete ) )
82 : {
83 : /* diagramelement with a focused feature found */
84 : /* this must be copied into a local data set to make this class re-entrant for recursive calls */
85 3 : result |= data_small_set_add_obj( &lifelines_to_delete, feat_to_delete );
86 : }
87 : }
88 : }
89 : else
90 : {
91 0 : U8_LOG_ANOMALY( "consistency_lifeline_delete_lifelines could not load all diagram_elements of a diagram." );
92 : }
93 5 : result |= data_diagramelement_iterator_destroy( &diagramelement_iterator );
94 :
95 : /* delete all found lifelines */
96 : /* note that (*this_).temp_diagelement_buf cannot be used here any longer due to re-entrancy by recursion */
97 5 : const uint32_t lifelines_count = data_small_set_get_count( &lifelines_to_delete );
98 8 : for ( uint32_t index2 = 0; index2 < lifelines_count; index2 ++ )
99 : {
100 3 : const data_id_t delete_feat = data_small_set_get_id( &lifelines_to_delete, index2 );
101 3 : assert( data_id_get_table( &delete_feat ) == DATA_TABLE_FEATURE );
102 3 : result |= ctrl_classifier_controller_delete_feature( (*this_).clfy_ctrl,
103 : data_id_get_row( &delete_feat ),
104 : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND,
105 : io_stat
106 : );
107 : /* the current_diagele is already updated by another (recursive) consistency check. */
108 : }
109 :
110 5 : data_small_set_destroy( &lifelines_to_delete );
111 : }
112 :
113 9 : U8_TRACE_END_ERR( result );
114 9 : return result;
115 : }
116 :
117 9 : u8_error_t consistency_lifeline_create_lifelines( consistency_lifeline_t *this_,
118 : const data_diagram_t *updated_diagram,
119 : consistency_stat_t *io_stat )
120 : {
121 9 : U8_TRACE_BEGIN();
122 9 : assert( NULL != updated_diagram );
123 9 : assert( NULL != io_stat );
124 9 : u8_error_t result = U8_ERROR_NONE;
125 :
126 9 : const data_diagram_type_t new_type = data_diagram_get_diagram_type ( updated_diagram );
127 9 : if ( data_rules_diagram_is_scenario( &((*this_).rules), new_type ) )
128 : {
129 : /* this diagram type needs lifelines */
130 : data_full_id_t lifelines_to_create_buf[ CONSISTENCY_LIFELINE_CONST_MAX_TEMP_DIAGELES ];
131 : data_full_id_list_t lifelines_to_create;
132 4 : data_full_id_list_init( &lifelines_to_create,
133 : CONSISTENCY_LIFELINE_CONST_MAX_TEMP_DIAGELES,
134 : &lifelines_to_create_buf
135 : );
136 :
137 : /* search all contained diagramelements */
138 4 : const data_row_t diagram_id = data_diagram_get_row ( updated_diagram );
139 : data_diagramelement_iterator_t diagramelement_iterator;
140 4 : data_diagramelement_iterator_init_empty( &diagramelement_iterator );
141 4 : result |= data_database_reader_get_diagramelements_by_diagram_id( (*this_).db_reader,
142 : diagram_id,
143 : &diagramelement_iterator
144 : );
145 :
146 4 : if ( U8_ERROR_NONE == result )
147 : {
148 : /* search the diagramelements */
149 13 : while ( data_diagramelement_iterator_has_next( &diagramelement_iterator ) )
150 : {
151 5 : result |= data_diagramelement_iterator_next( &diagramelement_iterator,
152 : &((*this_).temp_diagelement_buf)
153 : );
154 5 : data_diagramelement_t *const current_diagele
155 : = &((*this_).temp_diagelement_buf);
156 : const data_row_t focused_feature
157 5 : = data_diagramelement_get_focused_feature_row( current_diagele );
158 :
159 5 : if ( DATA_ROW_VOID == focused_feature )
160 : {
161 : /* diagramelement without focused feature found */
162 : /* this must be copied into a local data set to make this class re-entrant for recursive calls */
163 : const data_full_id_t diagramelement_ids = {
164 4 : .primary_id = data_diagramelement_get_data_id( current_diagele ),
165 4 : .secondary_id = data_diagramelement_get_classifier_data_id( current_diagele )
166 : };
167 4 : result |= data_full_id_list_add( &lifelines_to_create, &diagramelement_ids );
168 : }
169 : }
170 : }
171 : else
172 : {
173 0 : U8_LOG_ANOMALY( "consistency_lifeline_create_lifelines could not load all diagram_elements of a diagram." );
174 : }
175 4 : result |= data_diagramelement_iterator_destroy( &diagramelement_iterator );
176 :
177 :
178 : /* create all missing lifelines */
179 : /* note that (*this_).private_temp_diagele_buf cannot be used here any longer due to re-entrancy by recursion */
180 4 : const uint32_t lifelines_count = data_full_id_list_get_length( &lifelines_to_create );
181 8 : for ( uint32_t index2 = 0; index2 < lifelines_count; index2 ++ )
182 : {
183 4 : const data_full_id_t *const diagramelement_ids = data_full_id_list_get_const( &lifelines_to_create, index2 );
184 4 : data_row_t lifeline_row = DATA_ROW_VOID;
185 : const u8_error_t create_err
186 4 : = consistency_lifeline_private_create_one_lifeline ( this_, diagramelement_ids, &lifeline_row );
187 4 : if (( create_err == U8_ERROR_NONE )&&( lifeline_row != DATA_ROW_VOID ))
188 : {
189 4 : consistency_stat_increment_lifelines( io_stat );
190 : }
191 4 : result |= create_err;
192 : }
193 :
194 4 : data_full_id_list_destroy( &lifelines_to_create );
195 : }
196 :
197 9 : U8_TRACE_END_ERR( result );
198 9 : return result;
199 : }
200 :
201 60 : u8_error_t consistency_lifeline_create_a_lifeline( consistency_lifeline_t *this_,
202 : const data_diagramelement_t *new_diagramelement,
203 : data_row_t *out_lifeline_row )
204 : {
205 60 : U8_TRACE_BEGIN();
206 60 : assert( NULL != new_diagramelement );
207 60 : assert( NULL != out_lifeline_row );
208 60 : u8_error_t result = U8_ERROR_NONE;
209 :
210 : /* load the diagram and check the type */
211 : data_diagram_t the_diag;
212 60 : result |= data_database_reader_get_diagram_by_id( (*this_).db_reader,
213 : data_diagramelement_get_diagram_row( new_diagramelement ),
214 : &the_diag
215 : );
216 :
217 60 : if ( U8_ERROR_NONE == result )
218 : {
219 60 : const data_diagram_type_t dig_type = data_diagram_get_diagram_type( &the_diag );
220 60 : if ( data_rules_diagram_is_scenario( &((*this_).rules), dig_type ) )
221 : {
222 : const data_full_id_t diagramelement_ids = {
223 13 : .primary_id = data_diagramelement_get_data_id( new_diagramelement ),
224 13 : .secondary_id = data_diagramelement_get_classifier_data_id( new_diagramelement )
225 : };
226 13 : result |= consistency_lifeline_private_create_one_lifeline ( this_, &diagramelement_ids, out_lifeline_row );
227 : }
228 : else
229 : {
230 : /* no lifeline in non-scenario diagrams */
231 47 : *out_lifeline_row = DATA_ROW_VOID;
232 : }
233 : }
234 : else
235 : {
236 : /* error: diagram type unknown */
237 0 : *out_lifeline_row = DATA_ROW_VOID;
238 : }
239 :
240 60 : U8_TRACE_END_ERR( result );
241 60 : return result;
242 : }
243 :
244 17 : u8_error_t consistency_lifeline_private_create_one_lifeline( consistency_lifeline_t *this_,
245 : const data_full_id_t *diagramelement_ids,
246 : data_row_t *out_lifeline_row )
247 : {
248 17 : U8_TRACE_BEGIN();
249 17 : assert( NULL != diagramelement_ids );
250 17 : assert( NULL != out_lifeline_row );
251 17 : u8_error_t result = U8_ERROR_NONE;
252 17 : const data_id_t diagramelement_id = data_full_id_get_primary_id( diagramelement_ids );
253 17 : assert( DATA_TABLE_DIAGRAMELEMENT == data_id_get_table( &diagramelement_id ) );
254 17 : const data_id_t classifier_id = data_full_id_get_secondary_id( diagramelement_ids );
255 17 : assert( DATA_TABLE_CLASSIFIER == data_id_get_table( &classifier_id ) );
256 :
257 : /* define the lifeline to create */
258 : data_feature_t new_lifeline;
259 17 : result |= data_feature_init_new( &new_lifeline,
260 : DATA_FEATURE_TYPE_LIFELINE,
261 : data_id_get_row( &classifier_id ),
262 : "", /* key */
263 : "", /* value or type */
264 : "", /* description */
265 : 0 /* list_order */
266 : );
267 :
268 : /* create the lifeline */
269 17 : data_row_t new_feature_id = DATA_ROW_VOID;
270 17 : result |= ctrl_classifier_controller_create_feature( (*this_).clfy_ctrl,
271 : &new_lifeline,
272 : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND,
273 : &new_feature_id
274 : );
275 :
276 : /* the newly created lifeline is the focused feature */
277 17 : result |= ctrl_diagram_controller_update_diagramelement_focused_feature_id( (*this_).diag_ctrl,
278 : data_id_get_row( &diagramelement_id ),
279 : new_feature_id,
280 : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND
281 : );
282 :
283 : /* cleanup */
284 17 : data_feature_destroy ( &new_lifeline );
285 17 : *out_lifeline_row = new_feature_id;
286 :
287 17 : U8_TRACE_END_ERR( result );
288 17 : return result;
289 : }
290 :
291 9 : u8_error_t consistency_lifeline_delete_a_lifeline( consistency_lifeline_t *this_,
292 : const data_diagramelement_t *deleted_diagramelement,
293 : consistency_stat_t *io_stat )
294 : {
295 9 : U8_TRACE_BEGIN();
296 9 : assert( NULL != deleted_diagramelement );
297 9 : assert( NULL != io_stat );
298 9 : u8_error_t result = U8_ERROR_NONE;
299 :
300 : /* delete the lifeline of the already deleted data_diagramelement_t */
301 : const data_row_t focused_feature_id
302 9 : = data_diagramelement_get_focused_feature_row( deleted_diagramelement );
303 9 : if ( DATA_ROW_VOID != focused_feature_id )
304 : {
305 5 : result |= ctrl_classifier_controller_delete_feature( (*this_).clfy_ctrl,
306 : focused_feature_id,
307 : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND,
308 : io_stat
309 : );
310 : }
311 :
312 9 : U8_TRACE_END_ERR( result );
313 9 : return result;
314 : }
315 :
316 9 : u8_error_t consistency_lifeline_unlink_lifeline( consistency_lifeline_t *this_,
317 : const data_feature_t *deleted_feature )
318 : {
319 9 : U8_TRACE_BEGIN();
320 9 : assert( NULL != deleted_feature );
321 9 : u8_error_t result = U8_ERROR_NONE;
322 :
323 9 : if ( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type ( deleted_feature ) )
324 : {
325 9 : const data_row_t classifier_id = data_feature_get_classifier_row ( deleted_feature );
326 9 : const data_row_t deleted_feature_id = data_feature_get_row( deleted_feature );
327 : data_small_set_t diag_ele_to_unlink;
328 9 : data_small_set_init( &diag_ele_to_unlink );
329 :
330 : /* search all diagramelements of the classifier */
331 : data_diagramelement_iterator_t diagramelement_iterator;
332 9 : data_diagramelement_iterator_init_empty( &diagramelement_iterator );
333 9 : result |= data_database_reader_get_diagramelements_by_classifier_id( (*this_).db_reader,
334 : classifier_id,
335 : &diagramelement_iterator
336 : );
337 :
338 9 : if ( U8_ERROR_NONE == result )
339 : {
340 : /* search the diagramelements */
341 30 : while ( data_diagramelement_iterator_has_next( &diagramelement_iterator ) )
342 : {
343 12 : result |= data_diagramelement_iterator_next( &diagramelement_iterator, &((*this_).temp_diagelement_buf) );
344 12 : data_diagramelement_t *const current_diagele
345 : = &((*this_).temp_diagelement_buf);
346 : const data_row_t focused_feature
347 12 : = data_diagramelement_get_focused_feature_row( current_diagele );
348 :
349 12 : if ( focused_feature == deleted_feature_id )
350 : {
351 : /* diagramelement with the just deleted focused feature found */
352 : /* this must be copied into a local data set to make this class re-entrant for recursive calls */
353 4 : const data_id_t diagele_id = data_diagramelement_get_data_id( current_diagele );
354 4 : result |= data_small_set_add_obj( &diag_ele_to_unlink, diagele_id );
355 : }
356 : }
357 : }
358 : else
359 : {
360 0 : U8_LOG_ANOMALY( "consistency_lifeline_unlink_lifeline could not load all lifelines of a classifier." );
361 : }
362 9 : result |= data_diagramelement_iterator_destroy( &diagramelement_iterator );
363 :
364 : /* unlink all found diagram elements (there should be exactly one) */
365 : /* note that (*this_).private_temp_diagele_buf cannot be used here any longer due to re-entrancy by recursion */
366 9 : const uint32_t diag_ele_count = data_small_set_get_count( &diag_ele_to_unlink );
367 9 : if ( diag_ele_count != 1 )
368 : {
369 5 : U8_LOG_ANOMALY_INT( "Unlinking a just deleted lifeline that had not exactly one occurrence:",
370 : diag_ele_count
371 : );
372 : }
373 13 : for ( uint32_t index2 = 0; index2 < diag_ele_count; index2 ++ )
374 : {
375 4 : const data_id_t diagele_to_unlink = data_small_set_get_id( &diag_ele_to_unlink, index2 );
376 4 : assert( data_id_get_table( &diagele_to_unlink ) == DATA_TABLE_DIAGRAMELEMENT );
377 4 : result |= ctrl_diagram_controller_update_diagramelement_focused_feature_id( (*this_).diag_ctrl,
378 : data_id_get_row( &diagele_to_unlink ),
379 : DATA_ROW_VOID,
380 : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND
381 : );
382 : }
383 :
384 9 : data_small_set_destroy( &diag_ele_to_unlink );
385 : }
386 :
387 9 : U8_TRACE_END_ERR( result );
388 9 : return result;
389 : }
390 :
391 :
392 : /*
393 : Copyright 2018-2026 Andreas Warnke
394 :
395 : Licensed under the Apache License, Version 2.0 (the "License");
396 : you may not use this file except in compliance with the License.
397 : You may obtain a copy of the License at
398 :
399 : http://www.apache.org/licenses/LICENSE-2.0
400 :
401 : Unless required by applicable law or agreed to in writing, software
402 : distributed under the License is distributed on an "AS IS" BASIS,
403 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
404 : See the License for the specific language governing permissions and
405 : limitations under the License.
406 : */
|