source: tags/ms_ra2q1/NTREE/NT_sort.cxx

Last change on this file was 17110, checked in by westram, 6 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : NT_sort.cxx                                       //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "NT_local.h"
12
13#include <item_sel_list.h>
14#include <aw_awar.hxx>
15#include <arb_progress.h>
16#include <aw_msg.hxx>
17#include <aw_root.hxx>
18#include <TreeNode.h>
19#include <arb_sort.h>
20#include <arb_global_defs.h>
21
22#define FIELD_FILTER_RESORT (1<<GB_STRING)|(1<<GB_INT)|(1<<GB_FLOAT) // field types supported by cmpByKey()
23
24#define CUSTOM_CRITERIA 3
25
26struct customCriterion {
27    char *key;
28    bool  reverse;
29    bool  is_valid;
30
31    void check_valid() {
32        is_valid = key && strcmp(key, NO_FIELD_SELECTED) != 0;
33    }
34
35    customCriterion() : key(NULp), reverse(false) { check_valid(); }
36    customCriterion(const char *key_, bool reverse_) : key(ARB_strdup(key_)), reverse(reverse_) { check_valid(); }
37    customCriterion(const customCriterion& other) : key(ARB_strdup(other.key)), reverse(other.reverse) { check_valid(); }
38    DECLARE_ASSIGNMENT_OPERATOR(customCriterion);
39    ~customCriterion() { free(key); }
40};
41
42static int cmpByKey(GBDATA *gbd1, GBDATA *gbd2, const customCriterion& by) {
43    int cmp = 0;
44    if (by.is_valid) {
45        GBDATA *gb_field1 = GB_entry(gbd1, by.key);
46        GBDATA *gb_field2 = GB_entry(gbd2, by.key);
47
48        if (gb_field1) {
49            if (gb_field2) {
50                switch (GB_read_type(gb_field1)) {
51                    case GB_STRING: {
52                        const char *s1 = GB_read_char_pntr(gb_field1);
53                        const char *s2 = GB_read_char_pntr(gb_field2);
54
55                        cmp = strcmp(s1, s2);
56                        break;
57                    }
58                    case GB_FLOAT: {
59                        float f1 = GB_read_float(gb_field1);
60                        float f2 = GB_read_float(gb_field2);
61
62                        cmp = f1<f2 ? -1 : (f1>f2 ? 1 : 0);
63                        break;
64                    }
65                    case GB_INT: {
66                        int i1 = GB_read_int(gb_field1);
67                        int i2 = GB_read_int(gb_field2);
68
69                        cmp = i1-i2;
70                        break;
71                    }
72                    default:
73                        cmp = 0; // other field type -> no idea how to compare
74                        break;
75                }
76
77                if (by.reverse) cmp = -cmp;
78            }
79            else cmp = -1;           // existing < missing!
80        }
81        else cmp = gb_field2 ? 1 : 0;
82    }
83    return cmp;
84}
85
86static bool customOrderIsStrict = true;
87static bool customDefinesOrder  = false;
88
89static int resort_data_by_customOrder(const void *v1, const void *v2, void *cd_sortBy) {
90    GBDATA *gbd1 = (GBDATA*)v1;
91    GBDATA *gbd2 = (GBDATA*)v2;
92
93    const customCriterion *sortBy = (const customCriterion *)cd_sortBy;
94
95    int cmp = 0;
96    for (int c = 0; !cmp && c<CUSTOM_CRITERIA; ++c) {
97        cmp = cmpByKey(gbd1, gbd2, sortBy[c]);
98    }
99
100    if (!cmp) customOrderIsStrict = false;
101    else customDefinesOrder       = true;
102
103    return cmp;
104}
105
106
107static GBDATA **gb_resort_data_list;
108static long    gb_resort_data_count;
109
110static void NT_resort_data_base_by_tree(TreeNode *tree, GBDATA *gb_species_data) {
111    if (tree) {
112        if (tree->is_leaf()) {
113            if (tree->gb_node) {
114                gb_resort_data_list[gb_resort_data_count++] = tree->gb_node;
115            }
116        }
117        else {
118            NT_resort_data_base_by_tree(tree->get_leftson(), gb_species_data);
119            NT_resort_data_base_by_tree(tree->get_rightson(), gb_species_data);
120        }
121    }
122}
123
124
125static GB_ERROR resort_data_base(TreeNode *tree, const customCriterion *sortBy) {
126    nt_assert(contradicted(tree, sortBy));
127
128    GB_ERROR error = GB_begin_transaction(GLOBAL.gb_main);
129    if (!error) {
130        GBDATA *gb_sd     = GBT_get_species_data(GLOBAL.gb_main);
131        if (!gb_sd) error = GB_await_error();
132        else {
133            if (tree) {
134                gb_resort_data_count = 0;
135                ARB_calloc(gb_resort_data_list, GB_nsons(gb_sd) + 256);
136                NT_resort_data_base_by_tree(tree, gb_sd);
137            }
138            else {
139                gb_resort_data_list = GBT_gen_species_array(GLOBAL.gb_main, &gb_resort_data_count);
140                GB_sort((void **)gb_resort_data_list, 0, gb_resort_data_count, resort_data_by_customOrder, (void*)sortBy);
141
142            }
143            error = GB_resort_data_base(GLOBAL.gb_main, gb_resort_data_list, gb_resort_data_count);
144            free(gb_resort_data_list);
145        }
146    }
147    return GB_end_transaction(GLOBAL.gb_main, error);
148}
149
150void NT_resort_data_by_phylogeny(AW_window*, TREE_canvas *ntw) {
151    arb_progress  progress("Sorting data");
152    GB_ERROR      error = NULp;
153    TreeNode     *tree  = NT_get_tree_root_of_canvas(ntw);
154
155    if (!tree)  error = "Please select/build a tree first";
156    if (!error) error = resort_data_base(tree, NULp);
157    if (error) aw_message(error);
158}
159
160#define AWAR_TREE_SORT1 "db_sort/sort_1"
161#define AWAR_TREE_SORT2 "db_sort/sort_2"
162#define AWAR_TREE_SORT3 "db_sort/sort_3"
163
164#define AWAR_TREE_REV1 "db_sort/rev1"
165#define AWAR_TREE_REV2 "db_sort/rev2"
166#define AWAR_TREE_REV3 "db_sort/rev3"
167
168static void NT_resort_data_by_user_criteria(AW_window *aw) {
169    arb_progress progress("Sorting data");
170
171    AW_root *aw_root = aw->get_root();
172
173    customCriterion sortBy[CUSTOM_CRITERIA];
174    sortBy[0] = customCriterion(aw_root->awar(AWAR_TREE_SORT1)->read_char_pntr(), aw_root->awar(AWAR_TREE_REV1)->read_int());
175    sortBy[1] = customCriterion(aw_root->awar(AWAR_TREE_SORT2)->read_char_pntr(), aw_root->awar(AWAR_TREE_REV2)->read_int());
176    sortBy[2] = customCriterion(aw_root->awar(AWAR_TREE_SORT3)->read_char_pntr(), aw_root->awar(AWAR_TREE_REV3)->read_int());
177
178    customOrderIsStrict = true;
179    customDefinesOrder  = false;
180
181    GB_ERROR error = resort_data_base(NULp, sortBy);
182
183    if (!error) {
184        if (!customDefinesOrder) error       = "Warning: No order is defined by the specified fields";
185        else if (!customOrderIsStrict) error = "Note: The specified fields do not define a strict order";
186    }
187
188    if (error) aw_message(error);
189}
190
191void NT_create_resort_awars(AW_root *awr, AW_default aw_def) {
192    awr->awar_string(AWAR_TREE_SORT1, "name",            aw_def);
193    awr->awar_string(AWAR_TREE_SORT2, "full_name",       aw_def);
194    awr->awar_string(AWAR_TREE_SORT3, NO_FIELD_SELECTED, aw_def);
195
196    awr->awar_int(AWAR_TREE_REV1, 0, aw_def);
197    awr->awar_int(AWAR_TREE_REV2, 0, aw_def);
198    awr->awar_int(AWAR_TREE_REV3, 0, aw_def);
199}
200
201AW_window *NT_create_resort_window(AW_root *awr) {
202    AW_window_simple *aws = new AW_window_simple;
203    aws->init(awr, "SORT_DB_ENTRIES", "SORT DATABASE");
204    aws->load_xfig("nt_sort.fig");
205
206    aws->at("close");
207    aws->callback(AW_POPDOWN);
208    aws->create_button("CLOSE", "CLOSE", "C");
209
210    aws->callback(makeHelpCallback("sp_sort_fld.hlp"));
211    aws->at("help");
212    aws->create_button("HELP", "HELP", "H");
213
214    create_itemfield_selection_button(aws, FieldSelDef(AWAR_TREE_SORT1, GLOBAL.gb_main, SPECIES_get_selector(), FIELD_FILTER_RESORT, "1st sort field"), "key1");
215    create_itemfield_selection_button(aws, FieldSelDef(AWAR_TREE_SORT2, GLOBAL.gb_main, SPECIES_get_selector(), FIELD_FILTER_RESORT, "2nd sort field"), "key2");
216    create_itemfield_selection_button(aws, FieldSelDef(AWAR_TREE_SORT3, GLOBAL.gb_main, SPECIES_get_selector(), FIELD_FILTER_RESORT, "3rd sort field"), "key3");
217
218    aws->at("rev1"); aws->label("Reverse"); aws->create_toggle(AWAR_TREE_REV1);
219    aws->at("rev2"); aws->label("Reverse"); aws->create_toggle(AWAR_TREE_REV2);
220    aws->at("rev3"); aws->label("Reverse"); aws->create_toggle(AWAR_TREE_REV3);
221
222    aws->at("go");
223    aws->callback(NT_resort_data_by_user_criteria);
224    aws->create_button("GO", "GO", "G");
225
226    return aws;
227}
Note: See TracBrowser for help on using the repository browser.