source: branches/profile/EDIT4/ED4_members.cxx

Last change on this file was 12600, checked in by westram, 5 years ago
  • no longer use aw_popup_exit (causes resource problems)
    • either use GBK_terminate or pass back error
  • shutdown_macro_recording before exit during startup
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.1 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : ED4_members.cxx                                   //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include <arbdb.h>
12#include "ed4_class.hxx"
13#include <aw_msg.hxx>
14#include <aw_question.hxx>
15
16ED4_returncode ED4_members::search_target_species(ED4_extension *location,   ED4_properties prop,  ED4_base **found_member, ED4_level return_level)
17{
18    // who's extension falls within the given
19    // location thereby considering orientation given by
20    // prop (only pos[] is relevant) list has to be
21    // ordered in either x- or y- direction, ( binary
22    // search algorithm later ) returns index of found member,
23    // -1 if list is empty or no_of_members if search reached end of list
24    ED4_index   current_index = 0,
25        old_index,
26        rel_pos,                                                                // relative position, i.e. on screen, to check
27        rel_size;
28    AW_pos              abs_pos_x = 0,
29        abs_pos_y = 0,
30        abs_pos;                                                                // relative size of object, to check
31    ED4_base    *current_member;
32
33
34    current_member = member(0); // search list
35    if (! current_member) { // there's no list
36        return (ED4_R_IMPOSSIBLE);
37    }
38
39    // case for the device_manager:
40    if (current_member->is_area_manager()) {
41        current_member->to_area_manager()
42            ->get_multi_species_manager()
43            ->children->search_target_species(location, prop, found_member, return_level); // there are always the three areas !!!
44
45        if (*found_member) {
46            return ED4_R_OK;
47        }
48    }
49
50    current_member->parent->calc_world_coords(& abs_pos_x, & abs_pos_y);
51
52    if (prop & ED4_P_HORIZONTAL)                                                                // set extension-indexes rel_pos and rel_size according to properties
53    {
54        rel_pos = Y_POS;
55        rel_size = HEIGHT;
56        abs_pos = abs_pos_y;
57    }
58    else                                                                                        // i.e. prop & ED4_P_VERTICAL
59    {
60        rel_pos = X_POS;
61        rel_size = WIDTH;
62        abs_pos = abs_pos_x;
63    }
64
65
66    while (current_member &&
67             (location->position[rel_pos] >= (current_member->extension.position[rel_pos] + abs_pos)) &&        // just as long as possibility exists, to find the object
68             (location->position[rel_pos] >= abs_pos && location->position[rel_pos] <= current_member->parent->extension.size[rel_size] + abs_pos))
69    {
70        e4_assert(!current_member->is_root_group_manager());
71        if (current_member->is_group_manager() &&
72            !current_member->flag.hidden &&
73            !current_member->is_consensus_manager()) { // search_clicked_member for multi_species_manager in groups
74            current_member->to_group_manager()->children->search_target_species(location, prop, found_member, return_level);
75        }
76        else if (!(current_member->flag.hidden)   &&
77                  (location->position[rel_pos] <= (current_member->extension.position[rel_pos] +
78                                                   abs_pos + current_member->extension.size[rel_size])))                        // found a suitable member
79        {
80            if (return_level & ED4_L_MULTI_SPECIES) { // search for drag target
81                if (current_member->is_multi_species_manager()) {
82                    *found_member = current_member;                                     // we have to give back the multi_species_manager for
83                    // insertion
84                    current_member->to_multi_species_manager()->children->search_target_species(location, prop, found_member, return_level);
85                }
86                else if ((current_member->is_spacer_terminal()) && (current_index + 1 == no_of_members)) { // if we have found the last spacer
87                    *found_member = current_member->get_parent(ED4_L_MULTI_SPECIES);                            // in a group we can move the
88                    if ((*found_member) && !((*found_member)->parent->is_area_manager())) {
89                        *found_member = (*found_member)->parent->get_parent(ED4_L_MULTI_SPECIES);
90                    }
91                }
92                else if (!(current_member->is_terminal()) || (current_member->is_spacer_terminal())) { // object behind the group
93                    *found_member = current_member->get_parent(ED4_L_MULTI_SPECIES);
94                }
95
96            }
97            else                                                                        // search for drag target line
98            {
99                if (current_member->is_multi_species_manager()) {
100                    current_member->to_multi_species_manager()->children->search_target_species(location, prop, found_member, return_level);
101                }
102                else if ((current_member->is_spacer_terminal()) && (current_index + 1 == no_of_members)) { // if we have found the last spacer
103                    *found_member = current_member->get_parent(ED4_L_MULTI_SPECIES);   // in a group we can move the
104                    if ((*found_member) && !((*found_member)->parent->is_area_manager())) {
105                        *found_member = (*found_member)->parent;
106                    }
107                }
108                else if ((current_member->is_species_manager()) ||
109                         ((current_member->is_spacer_terminal()) && current_member->parent->is_multi_species_manager())) { // we are a species manager
110                    *found_member = current_member;
111                }
112            }
113
114        }
115
116        current_index++;                                                                // no hit => search on
117        current_member = member(current_index);
118
119        if (current_member) { // handle folding groups
120            old_index = current_index;
121            while (current_member && current_member->flag.hidden && current_index!=no_of_members) {
122                current_index ++;
123                current_member = member(current_index);
124            }
125
126            if (current_index != old_index) {
127                if (current_member &&
128                         !((location->position[rel_pos] >= (current_member->extension.position[rel_pos] + abs_pos)) &&
129                           (location->position[rel_pos] >= abs_pos && location->position[rel_pos] <= current_member->parent->extension.size[rel_size] + abs_pos)) &&
130                         (current_member->is_spacer_terminal()) && (current_index + 1 == no_of_members))
131                {
132                    if (return_level & ED4_L_MULTI_SPECIES)
133                        *found_member = current_member->get_parent(ED4_L_MULTI_SPECIES)->parent->get_parent(ED4_L_MULTI_SPECIES);
134                    else
135                        *found_member = current_member->get_parent(ED4_L_MULTI_SPECIES)->parent;
136                }
137            }
138        }
139
140        if (current_member) {
141            if (current_member->is_area_manager()) {
142                current_member->to_area_manager()
143                    ->get_multi_species_manager()
144                    ->children->search_target_species(location, prop, found_member, return_level);      // there are always the three areas !!!
145
146                if (*found_member) {
147                    return ED4_R_OK;
148                }
149            }
150        }
151    }
152
153    return ED4_R_OK;
154}
155
156ED4_returncode ED4_members::insert_member(ED4_base *new_member) {
157    // inserts a new member into current owners's member array and
158    // asks to adjust owner's bounding box
159
160    ED4_properties prop = owner()->spec.static_prop; // properties of parent object
161
162    ED4_index index;
163    if ((index = search_member(&(new_member->extension), prop)) < 0) {          // search list for a suitable position
164        index = 0;                                                              // list was empty
165    }
166    else if (index != no_of_members) {                                          // we want to insert new member just behind found position
167        index++;                                                                // if index == no_of_members we reached the end of the list
168    }                                                                           // and index already has the right value
169
170    if (index > 0) { // ensure to insert before group_end_spacer
171        if (member(index-1)) {
172            if (member(index-1)->is_spacer_terminal() && !owner()->is_device_manager()) { // only in group_manager
173                if (index > 1) {
174                    index --;
175                }
176            }
177        }
178    }
179
180    if (shift_list(index, 1) != ED4_R_OK) {    // insert new_member at index after shifting to the right
181        return (ED4_R_WARNING);
182    }
183
184    memberList[index] = new_member; // insert new member in list in just allocated memory
185    no_of_members ++;
186    new_member->index = index;
187
188    owner()->request_resize(); // tell owner about resize
189
190    return (ED4_R_OK);
191}
192
193ED4_returncode ED4_members::append_member(ED4_base *new_member) {
194    ED4_index index = no_of_members;
195
196    e4_assert(owner()->spec.allowed_to_contain(new_member->spec.level));
197 
198    if (index>=size_of_list) { // ensure free element
199        ED4_index new_size_of_list = (size_of_list*3)/2;        // resize to 1.5*size_of_list
200        ED4_base **new_member_list = (ED4_base**)GB_calloc(new_size_of_list, sizeof(*new_member_list));
201        if (!new_member_list) {
202            GB_memerr();
203            return ED4_R_IMPOSSIBLE;
204        }
205        memcpy(new_member_list, memberList, size_of_list*sizeof(*new_member_list));
206
207        freeset(memberList, new_member_list);
208        size_of_list = new_size_of_list;
209    }
210
211    if (index>0) { // ensure to insert before group_end_spacer
212        if (member(index-1)) {
213            if (member(index-1)->is_spacer_terminal() && !owner()->is_device_manager()) {
214                if (index>1) {
215                    index--;
216                }
217            }
218        }
219    }
220
221    if (shift_list(index, 1)!=ED4_R_OK) { // shift member if necessary
222        return ED4_R_WARNING;
223    }
224
225    memberList[index] = new_member;
226    no_of_members++;
227    new_member->index = index;
228
229    owner()->spec.announce_added(new_member->spec.level);
230    owner()->request_resize();
231
232    return ED4_R_OK;
233}
234
235ED4_returncode ED4_members::remove_member(ED4_base *member_to_del)
236{
237    if (!member_to_del || (no_of_members <= 0)) {
238        return (ED4_R_IMPOSSIBLE);
239    }
240
241    ED4_index index = member_to_del->index;
242
243    if (shift_list((index + 1), -1) != ED4_R_OK) {     // shift member list to left, starting at index+1
244        return (ED4_R_WARNING);
245    }
246
247    member_to_del->parent = 0; // avoid referencing wrong parent
248
249    no_of_members--;
250    e4_assert(members_ok());
251
252    owner()->request_resize();
253
254    return (ED4_R_OK);
255}
256
257ED4_returncode  ED4_members::shift_list(ED4_index start_index, int length) {
258    // shifts member_list of current object by |length| positions starting with start_index,
259    // if length is positive shift is to the right, allocating new memory if necessary
260    // if length is negative shift is to the left (up to position 0) without freeing memory
261
262    if (length>0) { // shift list to the right
263        if ((no_of_members + length) >= size_of_list) {   // member_list is full => allocate more memory
264            unsigned int   new_alloc_size = (unsigned int) ((size_of_list + length) * 1.3); // calculate new size of member_list for realloc()
265            ED4_base     **tmp_ptr        = (ED4_base **) realloc((char *) memberList, (new_alloc_size * sizeof(ED4_base *))); // try to realloc memory
266
267            if (! tmp_ptr) { // realloc() failed = > try malloc() and copy member_list
268                aw_message("ED4_members::shift_list: realloc problem!");
269                tmp_ptr = (ED4_base **) malloc((new_alloc_size * sizeof(ED4_base *)));
270
271                if (!tmp_ptr) return ED4_R_DESASTER; // malloc has failed, too
272
273                tmp_ptr = (ED4_base **) memcpy((char *) tmp_ptr,                    // malloc was successfull, now copy memory
274                                               (char *) memberList,
275                                               (new_alloc_size * sizeof(ED4_base *)));
276            }
277            memberList = tmp_ptr;
278            size_of_list = new_alloc_size;
279            for (ED4_index i = no_of_members; i < size_of_list; i++) memberList[i] = NULL; // clear free entries at the end of the list
280        }
281
282        for (ED4_index i = (no_of_members + length); i > start_index; i--) { // start shifting to the right
283            memberList[i] = memberList[i - length];
284            if (memberList[i] != NULL) (memberList[i])->index = i;
285        }
286    }
287    else if (length<0) { // shift list to the left, thereby not freeing any memory !
288        if ((start_index + length) < 0) {
289            aw_message("ED4_members::shift_list: shift is too far to the left!");
290            return ED4_R_WARNING;
291        }
292
293        for (ED4_index i = (start_index + length); i <= (no_of_members + length); i++) { // start shifting left
294            memberList[i] = memberList[i - length]; // length is negative
295            if (memberList[i] != NULL) (memberList[i])->index = i;
296        }
297    }
298
299    return ED4_R_OK;
300}
301
302
303ED4_returncode ED4_members::move_member(ED4_index old_pos, ED4_index new_pos) {
304    if (old_pos>=0 && old_pos<no_of_members && new_pos>=0 && new_pos<no_of_members) {
305        if (new_pos!=old_pos) {
306            ED4_base *moved_member = memberList[old_pos];
307
308            shift_list(old_pos+1, -1);
309            shift_list(new_pos, 1);
310
311            memberList[new_pos] = moved_member;
312            moved_member->index = new_pos;
313
314            e4_assert(members_ok());
315        }
316        return ED4_R_OK;
317    }
318
319    return ED4_R_IMPOSSIBLE;
320}
321
322ED4_index ED4_members::search_member(ED4_extension *location, ED4_properties prop)
323// searches member_list of current object for a member who's extension falls within the given location
324// thereby considering orientation given by prop (only pos[] is relevant)
325// list has to be ordered in either x- or y- direction, ( binary search algorithm later )
326// returns index of found member, -1 if list is empty or no_of_members if search reached end of list
327{
328    ED4_index   current_index = 0,
329        rel_pos,
330        rel_size;
331
332    ED4_base *current_member;
333
334    if (prop & ED4_P_HORIZONTAL) {   // set extension-indexes rel_pos and rel_size according to properties
335        rel_pos = Y_POS; rel_size = HEIGHT;
336    }
337    else { // i.e. prop & ED4_P_VERTICAL
338        rel_pos = X_POS; rel_size = WIDTH;
339    }
340
341    current_member = memberList[0]; // search list
342    if (! current_member) { // there's no list
343        return (-1);
344    }
345
346    current_index = 0;
347    while (current_member) { // just as long as possibility exists, to find the object
348        if (location->position[rel_pos] <= (current_member->extension.position[rel_pos] + current_member->extension.size[rel_size])) {  // found a suitable member
349            return (current_index);
350        }
351        current_index++; // no hit => search on
352        current_member = memberList[current_index];
353    }
354
355    return (no_of_members);                                                           // reached this position => no hit, return no_of_members
356}
357
358#ifdef ASSERTION_USED
359int ED4_members::members_ok() const {
360    int m;
361    int error = 0;
362
363    for (m=0; m<no_of_members; m++) {
364        ED4_base *base = memberList[m];
365
366        if (base->index!=m) {
367            printf("Member %i has illegal index %li\n", m, base->index);
368            error = 1;
369        }
370    }
371
372    return !error;
373}
374#endif // ASSERTION_USED
375
376ED4_members::ED4_members(ED4_manager *the_owner) {
377    my_owner   = the_owner;
378    memberList = (ED4_base **) calloc(1, sizeof(ED4_base*));
379    if (!memberList) GBK_terminate("out of memory");
380
381    memberList[0] = NULL;
382    no_of_members = 0;
383    size_of_list  = 1;
384}
385
386
387ED4_members::~ED4_members() {
388    free(memberList);
389}
390
Note: See TracBrowser for help on using the repository browser.