| 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 | |
|---|
| 16 | ED4_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 | |
|---|
| 156 | ED4_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 | |
|---|
| 193 | ED4_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 | |
|---|
| 235 | ED4_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 | |
|---|
| 257 | ED4_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 | |
|---|
| 303 | ED4_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 | |
|---|
| 322 | ED4_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 |
|---|
| 359 | int 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 | |
|---|
| 376 | ED4_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 | |
|---|
| 387 | ED4_members::~ED4_members() { |
|---|
| 388 | free(memberList); |
|---|
| 389 | } |
|---|
| 390 | |
|---|