1 | // =============================================================== // |
---|
2 | // // |
---|
3 | // File : MG_trees.cxx // |
---|
4 | // Purpose : Merge trees between databases // |
---|
5 | // // |
---|
6 | // Institute of Microbiology (Technical University Munich) // |
---|
7 | // http://www.arb-home.de/ // |
---|
8 | // // |
---|
9 | // =============================================================== // |
---|
10 | |
---|
11 | #include "merge.hxx" |
---|
12 | #include <TreeAdmin.h> |
---|
13 | #include <awt_sel_boxes.hxx> |
---|
14 | #include <aw_root.hxx> |
---|
15 | #include <aw_awar.hxx> |
---|
16 | #include <aw_msg.hxx> |
---|
17 | #include <arbdbt.h> |
---|
18 | #include <arb_global_defs.h> |
---|
19 | |
---|
20 | #define AWAR_TREE_NAME_SRC AWAR_MERGE_TMP_SRC "tree_name" |
---|
21 | #define AWAR_TREE_NAME_DST AWAR_MERGE_TMP_DST "tree_name" |
---|
22 | |
---|
23 | #define AWAR_TREE_XFER_WHAT AWAR_MERGE_TMP "xfer_what" |
---|
24 | #define AWAR_TREE_OVERWRITE AWAR_MERGE_TMP "overwrite" |
---|
25 | |
---|
26 | enum TREE_XFER_MODE { |
---|
27 | XFER_SELECTED, |
---|
28 | XFER_ALL, |
---|
29 | XFER_MISSING, |
---|
30 | XFER_EXISTING, |
---|
31 | }; |
---|
32 | |
---|
33 | void MG_create_trees_awar(AW_root *aw_root, AW_default aw_def) { |
---|
34 | aw_root->awar_string(AWAR_TREE_NAME_SRC, NO_TREE_SELECTED, aw_def); |
---|
35 | aw_root->awar_string(AWAR_TREE_NAME_DST, NO_TREE_SELECTED, aw_def); |
---|
36 | |
---|
37 | aw_root->awar_int(AWAR_TREE_XFER_WHAT, XFER_SELECTED, aw_def); |
---|
38 | aw_root->awar_int(AWAR_TREE_OVERWRITE, 0, aw_def); |
---|
39 | |
---|
40 | TreeAdmin::create_awars(aw_root, aw_def, false); |
---|
41 | } |
---|
42 | |
---|
43 | static GB_ERROR transfer_tree(const char *tree_name, bool overwrite, const char *behind_name) { |
---|
44 | // transfer tree 'tree_name' from DB1->DB2. |
---|
45 | // |
---|
46 | // if 'overwrite' is true and tree already exists, overwrite tree w/o changing its position. |
---|
47 | // |
---|
48 | // if tree does not exist, insert it behind tree 'behind_name'. |
---|
49 | // if tree 'behind_name' does not exist or if 'behind_name' is NULp, insert at end. |
---|
50 | |
---|
51 | |
---|
52 | GB_ERROR error = NULp; |
---|
53 | GBDATA *gb_tree = GBT_find_tree(GLOBAL_gb_src, tree_name); |
---|
54 | if (!gb_tree) { |
---|
55 | if (strcmp(tree_name, NO_TREE_SELECTED) == 0) { |
---|
56 | error = "No tree selected in source DB"; |
---|
57 | } |
---|
58 | else { |
---|
59 | error = GBS_global_string("No tree '%s' in source DB", tree_name); |
---|
60 | } |
---|
61 | } |
---|
62 | else { |
---|
63 | GBDATA *gb_at_tree = NULp; |
---|
64 | GBT_ORDER_MODE next_to = GBT_BEHIND; |
---|
65 | |
---|
66 | if (behind_name && strcmp(behind_name, NO_TREE_SELECTED) != 0) { |
---|
67 | gb_at_tree = GBT_find_tree(GLOBAL_gb_dst, behind_name); |
---|
68 | if (!gb_at_tree) { |
---|
69 | error = GBS_global_string("Can't position tree behind '%s' (no such tree)", behind_name); |
---|
70 | } |
---|
71 | } |
---|
72 | |
---|
73 | if (!error) { |
---|
74 | GBDATA *gb_dest_tree = GBT_find_tree(GLOBAL_gb_dst, tree_name); |
---|
75 | if (gb_dest_tree) { |
---|
76 | if (!overwrite) { |
---|
77 | error = GBS_global_string("Tree '%s' already exists in destination DB", tree_name); |
---|
78 | } |
---|
79 | else { |
---|
80 | // keep position of existing tree |
---|
81 | GBDATA *gb_tree_infrontof = GBT_tree_infrontof(gb_dest_tree); |
---|
82 | if (gb_tree_infrontof) { |
---|
83 | next_to = GBT_BEHIND; |
---|
84 | gb_at_tree = gb_tree_infrontof; |
---|
85 | } |
---|
86 | else { |
---|
87 | GBDATA *gb_tree_behind = GBT_tree_behind(gb_dest_tree); |
---|
88 | next_to = GBT_INFRONTOF; |
---|
89 | gb_at_tree = gb_tree_behind; |
---|
90 | } |
---|
91 | |
---|
92 | error = GB_delete(gb_dest_tree); |
---|
93 | } |
---|
94 | } |
---|
95 | } |
---|
96 | |
---|
97 | if (!error) { |
---|
98 | GBDATA *gb_dest_tree_data = GBT_get_tree_data(GLOBAL_gb_dst); |
---|
99 | if (!gb_dest_tree_data) error = GB_await_error(); |
---|
100 | else { |
---|
101 | GBDATA *gb_dest_tree = GB_create_container(gb_dest_tree_data, tree_name); |
---|
102 | if (!gb_dest_tree) error = GB_await_error(); |
---|
103 | else { |
---|
104 | error = GB_copy_dropProtectMarksAndTempstate(gb_dest_tree, gb_tree); |
---|
105 | if (!error) { |
---|
106 | if (!gb_at_tree) { |
---|
107 | gb_at_tree = GBT_find_bottom_tree(GLOBAL_gb_dst); |
---|
108 | next_to = GBT_BEHIND; |
---|
109 | } |
---|
110 | if (gb_at_tree) { |
---|
111 | error = GBT_move_tree(gb_dest_tree, next_to, gb_at_tree); |
---|
112 | } |
---|
113 | } |
---|
114 | } |
---|
115 | } |
---|
116 | } |
---|
117 | } |
---|
118 | return error; |
---|
119 | } |
---|
120 | |
---|
121 | static void MG_transfer_tree(AW_window *aww) { |
---|
122 | AW_root *awr = aww->get_root(); |
---|
123 | |
---|
124 | TREE_XFER_MODE what = (TREE_XFER_MODE)awr->awar(AWAR_TREE_XFER_WHAT)->read_int(); |
---|
125 | |
---|
126 | AW_awar *awar_tree_source = awr->awar(AWAR_TREE_NAME_SRC); |
---|
127 | AW_awar *awar_tree_dest = awr->awar(AWAR_TREE_NAME_DST); |
---|
128 | |
---|
129 | bool overwrite = awr->awar(AWAR_TREE_OVERWRITE)->read_int(); |
---|
130 | |
---|
131 | char *source_name = awar_tree_source->read_string(); |
---|
132 | char *behind_name = awar_tree_dest->read_string(); |
---|
133 | |
---|
134 | char *select_dst = NULp; |
---|
135 | |
---|
136 | GB_ERROR error = GB_begin_transaction(GLOBAL_gb_dst); |
---|
137 | if (!error) error = GB_begin_transaction(GLOBAL_gb_src); |
---|
138 | |
---|
139 | int xferd_missing = 0; |
---|
140 | int xferd_existing = 0; |
---|
141 | |
---|
142 | if (!error) { |
---|
143 | switch (what) { |
---|
144 | case XFER_SELECTED: |
---|
145 | error = transfer_tree(source_name, overwrite, behind_name); |
---|
146 | if (!error) select_dst = ARB_strdup(source_name); |
---|
147 | break; |
---|
148 | |
---|
149 | case XFER_ALL: |
---|
150 | case XFER_EXISTING: |
---|
151 | for (GBDATA *gb_tree = GBT_find_top_tree(GLOBAL_gb_src); gb_tree && !error; gb_tree = GBT_tree_behind(gb_tree)) { |
---|
152 | const char *tree_name = GBT_get_tree_name(gb_tree); |
---|
153 | GBDATA *gb_exists = GBT_find_tree(GLOBAL_gb_dst, tree_name); |
---|
154 | |
---|
155 | if (gb_exists) { |
---|
156 | xferd_existing++; |
---|
157 | error = transfer_tree(tree_name, overwrite, NULp); |
---|
158 | } |
---|
159 | } |
---|
160 | if (what == XFER_EXISTING) break; |
---|
161 | FALLTHROUGH; // for XFER_ALL |
---|
162 | case XFER_MISSING: |
---|
163 | for (GBDATA *gb_tree = GBT_find_top_tree(GLOBAL_gb_src); gb_tree && !error; gb_tree = GBT_tree_behind(gb_tree)) { |
---|
164 | const char *tree_name = GBT_get_tree_name(gb_tree); |
---|
165 | GBDATA *gb_exists = GBT_find_tree(GLOBAL_gb_dst, tree_name); |
---|
166 | |
---|
167 | if (!gb_exists) { |
---|
168 | error = transfer_tree(tree_name, false, behind_name); |
---|
169 | xferd_missing++; |
---|
170 | if (!select_dst) select_dst = ARB_strdup(tree_name); // select first missing in dest box |
---|
171 | freedup(behind_name, tree_name); |
---|
172 | } |
---|
173 | } |
---|
174 | break; |
---|
175 | } |
---|
176 | } |
---|
177 | |
---|
178 | error = GB_end_transaction(GLOBAL_gb_dst, error); |
---|
179 | GB_end_transaction_show_error(GLOBAL_gb_src, error, aw_message); |
---|
180 | |
---|
181 | if (!error) { |
---|
182 | if (select_dst) awar_tree_dest->write_string(select_dst); |
---|
183 | |
---|
184 | if (what == XFER_SELECTED) { |
---|
185 | GB_transaction ta(GLOBAL_gb_src); |
---|
186 | GBDATA *gb_next = GBT_find_next_tree(GBT_find_tree(GLOBAL_gb_src, source_name)); |
---|
187 | awar_tree_source->write_string(gb_next ? GBT_get_tree_name(gb_next) : NO_TREE_SELECTED); |
---|
188 | } |
---|
189 | |
---|
190 | if (xferd_existing) { |
---|
191 | if (xferd_missing) aw_message(GBS_global_string("Transferred %i existing and %i missing trees", xferd_existing, xferd_missing)); |
---|
192 | else aw_message(GBS_global_string("Transferred %i existing trees", xferd_existing)); |
---|
193 | } |
---|
194 | else { |
---|
195 | if (xferd_missing) aw_message(GBS_global_string("Transferred %i missing trees", xferd_missing)); |
---|
196 | else { |
---|
197 | if (what != XFER_SELECTED) aw_message("No trees have been transferred"); |
---|
198 | } |
---|
199 | } |
---|
200 | } |
---|
201 | |
---|
202 | free(select_dst); |
---|
203 | free(behind_name); |
---|
204 | free(source_name); |
---|
205 | } |
---|
206 | |
---|
207 | AW_window *MG_create_merge_trees_window(AW_root *awr) { |
---|
208 | GB_ERROR error = MG_expect_renamed(); |
---|
209 | if (error) { |
---|
210 | aw_message(error); |
---|
211 | return NULp; // deny to open window before user has renamed species |
---|
212 | } |
---|
213 | |
---|
214 | AW_window_simple *aws = new AW_window_simple; |
---|
215 | |
---|
216 | aws->init(awr, "MERGE_TREES", "MERGE TREES"); |
---|
217 | aws->load_xfig("merge/trees.fig"); |
---|
218 | |
---|
219 | aws->button_length(7); |
---|
220 | |
---|
221 | aws->at("close"); |
---|
222 | aws->callback(AW_POPDOWN); |
---|
223 | aws->create_button("CLOSE", "CLOSE", "C"); |
---|
224 | |
---|
225 | aws->at("help"); |
---|
226 | aws->callback(makeHelpCallback("mg_trees.hlp")); |
---|
227 | aws->create_button("HELP", "HELP", "H"); |
---|
228 | |
---|
229 | aws->at("trees1"); |
---|
230 | awt_create_TREE_selection_list(GLOBAL_gb_src, aws, AWAR_TREE_NAME_SRC, true); |
---|
231 | |
---|
232 | aws->at("trees2"); |
---|
233 | awt_create_TREE_selection_list(GLOBAL_gb_dst, aws, AWAR_TREE_NAME_DST, true); |
---|
234 | |
---|
235 | static TreeAdmin::Spec src_spec(GLOBAL_gb_src, AWAR_TREE_NAME_SRC); |
---|
236 | static TreeAdmin::Spec dst_spec(GLOBAL_gb_dst, AWAR_TREE_NAME_DST); |
---|
237 | |
---|
238 | aws->button_length(15); |
---|
239 | |
---|
240 | aws->at("delete1"); |
---|
241 | aws->callback(makeWindowCallback(TreeAdmin::delete_tree_cb, &src_spec)); |
---|
242 | aws->create_button("DELETE TREE_DB1", "Delete Tree"); |
---|
243 | |
---|
244 | aws->at("delete2"); |
---|
245 | aws->callback(makeWindowCallback(TreeAdmin::delete_tree_cb, &dst_spec)); |
---|
246 | aws->create_button("DELETE_TREE_DB2", "Delete Tree"); |
---|
247 | |
---|
248 | aws->at("rename1"); |
---|
249 | aws->callback(makeCreateWindowCallback(TreeAdmin::create_rename_window, &src_spec)); |
---|
250 | aws->create_button("RENAME_TREE_DB1", "Rename Tree"); |
---|
251 | |
---|
252 | aws->at("rename2"); |
---|
253 | aws->callback(makeCreateWindowCallback(TreeAdmin::create_rename_window, &dst_spec)); |
---|
254 | aws->create_button("RENAME_TREE_DB2", "Rename Tree"); |
---|
255 | |
---|
256 | aws->at("transfer"); |
---|
257 | aws->callback(MG_transfer_tree); |
---|
258 | aws->create_autosize_button("TRANSFER_TREE", "Transfer"); |
---|
259 | |
---|
260 | aws->at("xfer_what"); |
---|
261 | aws->create_option_menu(AWAR_TREE_XFER_WHAT, true); |
---|
262 | aws->insert_default_option("selected tree", "s", XFER_SELECTED); |
---|
263 | aws->insert_option ("all trees", "a", XFER_ALL); |
---|
264 | aws->insert_option ("missing trees", "m", XFER_MISSING); |
---|
265 | aws->insert_option ("existing trees", "e", XFER_EXISTING); |
---|
266 | aws->update_option_menu(); |
---|
267 | |
---|
268 | aws->at("overwrite"); |
---|
269 | aws->label("Overwrite trees?"); |
---|
270 | aws->create_toggle(AWAR_TREE_OVERWRITE); |
---|
271 | |
---|
272 | aws->button_length(0); |
---|
273 | aws->shadow_width(1); |
---|
274 | aws->at("icon"); |
---|
275 | aws->callback(makeHelpCallback("mg_trees.hlp")); |
---|
276 | aws->create_button("HELP_MERGE", "#merge/icon.xpm"); |
---|
277 | |
---|
278 | return aws; |
---|
279 | } |
---|
280 | |
---|