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