source: branches/species/MERGE/MG_main.cxx

Last change on this file was 19662, checked in by westram, 4 weeks ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : MG_main.cxx                                       //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "merge.hxx"
12#include <AW_rename.hxx>
13#include <app.hxx>
14#include <arb_spec.hxx>
15
16#include <macros.hxx>
17#include <MacroExitor.hxx>
18
19#include <aw_preset.hxx>
20#include <aw_awars.hxx>
21#include <aw_file.hxx>
22
23#include <arb_progress.h>
24#include <arb_file.h>
25
26// AISC_MKPT_PROMOTE:// source and destination DBs for merge:
27// AISC_MKPT_PROMOTE:extern GBDATA *GLOBAL_gb_src;
28// AISC_MKPT_PROMOTE:extern GBDATA *GLOBAL_gb_dst;
29
30GBDATA *GLOBAL_gb_src = NULp;
31GBDATA *GLOBAL_gb_dst = NULp;
32
33__ATTR__NORETURN static void (*MG_exit_cb)(const char *) = NULp;
34
35class MG_MacroExitor: public MacroExitor {
36    bool start_dst_db;
37
38    char *find_existing_directory_of(const char *fullpath) {
39        char *parent;
40        GB_split_full_path(fullpath, &parent, NULp, NULp, NULp);
41        return (parent && !GB_is_directory(parent)) ? NULp : parent;
42    }
43
44    __ATTR__NORETURN void perform_exit() OVERRIDE {
45        AW_root *awr          = get_root();
46        char    *restart_args = NULp;
47
48        {
49            const char *dst_db_name = awr->awar(AWAR_DB_DST"/file_name")->read_char_pntr();
50            if (start_dst_db) { // restart with destination DB
51                restart_args = GBK_singlequote(dst_db_name);
52            }
53            else if (!is_performing_delayed_exit() && // manual quit (not via macro)
54                     strcmp(dst_db_name, ":") != 0)   // target database is not client-DB (of a running arb instance)
55            {
56                // start intro window (prefer directory of destination database)
57                char *start_dir           = find_existing_directory_of(awr->awar(AWAR_DB_DST"/file_name")->read_char_pntr());
58                if (!start_dir) start_dir = find_existing_directory_of(awr->awar(AWAR_DB_SRC"/file_name")->read_char_pntr());
59
60                if (start_dir) {
61                    restart_args = GBK_singlequote(start_dir);
62                    freenull(start_dir);
63                }
64            }
65        }
66
67        ARB_disconnect_from_db(awr, GLOBAL_gb_src);
68        ARB_disconnect_from_db(awr, GLOBAL_gb_dst);
69
70        mg_assert(MG_exit_cb);
71        MG_exit_cb(restart_args); // effectively calls ../NTREE/NT_main.cxx@exit_from_merge
72    }
73
74    GBDATA* get_gbmain_checked_for_save() OVERRIDE {
75        return GLOBAL_gb_dst;
76    }
77
78public:
79    MG_MacroExitor(AW_root *aw_root_, bool start_dst_db_)
80        : MacroExitor(aw_root_, "ARB_MERGE"),
81          start_dst_db(start_dst_db_)
82    {}
83};
84
85static void MG_confirm_exit_restart_if(AW_window *aww, bool start_dst_db) {
86    // finally (may) exit ARB merge-tool using MG_MacroExitor::perform_exit above.
87    //
88    // Beforehand this will happen:
89    // - if no macro running -> asks user to confirm quit (and maybe aborts restart).
90    // - otherwise waits for macro to finish, then quits w/o question.
91
92    static SmartPtr<MG_MacroExitor> exitor;
93    if (exitor.isNull()) exitor = new MG_MacroExitor(aww->get_root(), start_dst_db);
94    exitor->maybe_exit_delayed();
95    if (!exitor->is_performing_delayed_exit()) exitor.setNull();
96}
97
98static void MG_save_cb(AW_window *aww, bool source_database) {
99    GBDATA     *gb_db_to_save = source_database ? GLOBAL_gb_src : GLOBAL_gb_dst;
100    const char *base_name     = source_database ? AWAR_DB_SRC : AWAR_DB_DST; // awar basename
101
102    AW_root    *awr   = aww->get_root();
103    char       *name  = awr->awar(GBS_global_string("%s/file_name", base_name))->read_string();
104    const char *atype = awr->awar(GBS_global_string("%s/type", base_name))->read_char_pntr();
105    const char *ctype = awr->awar(GBS_global_string("%s/compression", base_name))->read_char_pntr();
106    char       *type  = GBS_global_string_copy("%s%s", atype, ctype);
107
108    arb_progress progress(GBS_global_string("Saving %s database", source_database ? "source" : "target"));
109
110    awr->dont_save_awars_with_default_value(gb_db_to_save); // has to be done outside transaction!
111    GB_begin_transaction(gb_db_to_save);
112    GBT_check_data(gb_db_to_save, NULp);
113    GB_commit_transaction(gb_db_to_save);
114
115    GB_ERROR error = GB_save(gb_db_to_save, name, type);
116    if (error) aw_message(error);
117    else     AW_refresh_fileselection(awr, base_name);
118
119    free(type);
120    free(name);
121}
122
123static AW_window *MG_create_save_as_window(AW_root *aw_root, bool source_database) {
124    GBDATA     *gb_db_to_save = source_database ? GLOBAL_gb_src : GLOBAL_gb_dst;
125    const char *base_name     = source_database ? AWAR_DB_SRC : AWAR_DB_DST; // awar basename
126    const char *window_id     = source_database ? "MERGE_SAVE_DB_I" : "MERGE_SAVE_WHOLE_DB";
127
128    aw_root->awar_string(AWAR_DB_COMMENT, "<no description>", gb_db_to_save);
129
130    AW_window_simple *aws = new AW_window_simple;
131    aws->init(aw_root, window_id, GBS_global_string("Save whole %s database", source_database ? "source" : "target"));
132    aws->load_xfig("save_as.fig");
133
134    aws->at("close");
135    aws->callback(AW_POPDOWN);
136    aws->create_button("CLOSE", "CLOSE", "C");
137
138    aws->at("help");
139    aws->callback(makeHelpCallback("save.hlp"));
140    aws->create_button("HELP", "HELP", "H");
141
142    AW_create_standard_fileselection(aws, base_name);
143
144    aws->at("type");
145    AWT_insert_DBsaveType_selector(aws, GBS_global_string("%s/type", base_name));
146
147    aws->at("compression");
148    AWT_insert_DBcompression_selector(aws, GBS_global_string("%s/compression", base_name));
149
150    aws->at("save");
151    aws->callback(makeWindowCallback(MG_save_cb, source_database));
152    aws->create_button("SAVE", "SAVE", "S");
153
154    aws->at("comment");
155    aws->create_text_field(AWAR_DB_COMMENT);
156
157    return aws;
158}
159
160static void MG_save_quick_result_cb(AW_window *aww) {
161    char *name = aww->get_root()->awar(AWAR_DB_DST"/file_name")->read_string();
162
163    arb_progress progress("Saving database");
164    GB_begin_transaction(GLOBAL_gb_dst);
165    GBT_check_data(GLOBAL_gb_dst, NULp);
166    GB_commit_transaction(GLOBAL_gb_dst);
167
168    GB_ERROR error = GB_save_quick_as(GLOBAL_gb_dst, name);
169    if (error) aw_message(error);
170    else AW_refresh_fileselection(aww->get_root(), AWAR_DB_DST);
171
172    free(name);
173}
174
175static void MG_create_db_dependent_awars(AW_root *aw_root, GBDATA *gb_src, GBDATA *gb_dst) {
176    MG_create_db_dependent_rename_awars(aw_root, gb_src, gb_dst);
177}
178
179AW_window *MERGE_create_main_window(AW_root *aw_root, bool dst_is_new, __ATTR__NORETURN void (*exit_cb)(const char *)) {
180    // 'dst_is_new' == true -> setup dest DB according to source-DB
181    //
182    // GLOBAL_gb_src and GLOBAL_gb_dst have to be opened before
183
184    // @@@ add GB_is_client and use that here
185    bool src_is_client = GB_read_clients(GLOBAL_gb_src)<0;
186    bool dst_is_client = GB_read_clients(GLOBAL_gb_dst)<0;
187
188    MG_exit_cb = exit_cb;
189
190    mg_assert(contradicted(src_is_client, GB_is_server(GLOBAL_gb_src)));
191    mg_assert(contradicted(dst_is_client, GB_is_server(GLOBAL_gb_dst)));
192
193    mg_assert(!(src_is_client && dst_is_client));
194
195    bool save_src_enabled = !src_is_client;
196    bool save_dst_enabled = !dst_is_client;
197
198    {
199        GBDATA     *gb_main_4_macros = NULp;
200        const char *app_id           = NULp;
201
202        if (src_is_client) {
203            gb_main_4_macros = GLOBAL_gb_src;
204            app_id           = "ARB_MERGE_OUTOF";
205        }
206        else if (dst_is_client) {
207            gb_main_4_macros = GLOBAL_gb_dst;
208            app_id           = "ARB_MERGE_INTO";
209        }
210        else {
211            gb_main_4_macros = GLOBAL_gb_dst; // does not matter
212            app_id           = "ARB_MERGE";
213        }
214
215        GB_ERROR error = configure_macro_recording(aw_root, app_id, gb_main_4_macros);
216        aw_message_if(error);
217    }
218
219    mg_assert(aw_root);
220
221    {
222        GB_transaction ta_merge(GLOBAL_gb_src);
223        GB_transaction ta_dest(GLOBAL_gb_dst);
224
225        GBT_mark_all(GLOBAL_gb_dst, 0); // unmark everything in dest DB
226
227        // set DB-type to non-genome (compatibility to old DBs)
228        // when exporting to new DB (dest_is_new == true) -> use DB-type of merge-DB
229        bool merge_is_genome = GEN_is_genome_db(GLOBAL_gb_src, 0);
230
231        int dest_genome = 0;
232        if (dst_is_new) {
233            if (merge_is_genome) {
234                dest_genome = aw_question("select_dest_dbtype", "Enter destination DB-type", "Normal,Genome");
235            }
236            else {
237                dest_genome = 0; // from non-genome -> to non-genome
238            }
239        }
240
241        GEN_is_genome_db(GLOBAL_gb_dst, dest_genome); // does not change anything if type is already defined
242    }
243
244    {
245        GB_transaction ta_merge(GLOBAL_gb_src);
246        GB_transaction ta_dest(GLOBAL_gb_dst);
247
248        GB_change_my_security(GLOBAL_gb_dst, 6); // generally raises user securities in merge tool (allow anything)
249        GB_change_my_security(GLOBAL_gb_src, 6);
250
251        MG_create_db_dependent_awars(aw_root, GLOBAL_gb_src, GLOBAL_gb_dst);
252    }
253
254    {
255        GB_transaction ta_merge(GLOBAL_gb_src);
256        GB_transaction ta_dest(GLOBAL_gb_dst);
257
258        MG_set_renamed(false, aw_root, "Not renamed yet.");
259
260        AW_window_simple_menu *awm = new AW_window_simple_menu;
261        awm->init(aw_root, "ARB_MERGE", "ARB_MERGE");
262        awm->load_xfig("merge/main.fig");
263
264        // create menus
265#if defined(DEBUG)
266        AWT_create_debug_menu(awm);
267#endif // DEBUG
268
269        awm->create_menu("File", "F", AWM_ALL);
270        if (save_src_enabled) {
271            awm->insert_menu_topic("save_DB1", "Save source DB ...", "S", "save.hlp", AWM_ALL, makeCreateWindowCallback(MG_create_save_as_window, true));
272        }
273
274        awm->insert_menu_topic("quit", "Quit", "Q", "quit.hlp", AWM_ALL, makeWindowCallback(MG_confirm_exit_restart_if, false));
275        if (save_dst_enabled) {
276            awm->insert_menu_topic("quitnstart", "Quit & start target DB", "D", "quit.hlp", AWM_ALL, makeWindowCallback(MG_confirm_exit_restart_if, true));
277        }
278
279        insert_macro_menu_entry(awm, true);
280
281        awm->create_menu("Properties", "P", AWM_ALL);
282        AW_insert_common_property_menu_entries(awm);
283        awm->sep______________();
284        awm->insert_menu_topic("save_props", "Save properties (ntree.arb)", "p", "savedef.hlp", AWM_ALL, AW_save_properties);
285
286        awm->insert_help_topic("ARB_MERGE help", "M", "arb_merge.hlp", AWM_ALL, makeHelpCallback("arb_merge.hlp"));
287
288
289        // display involved databases
290        awm->button_length(28);
291
292        awm->at("db1"); awm->create_button(NULp, AWAR_DB_SRC"/name", NULp, "+");
293        awm->at("db2"); awm->create_button(NULp, AWAR_DB_DST"/name", NULp, "+");
294
295
296        // add main controls
297        awm->button_length(32);
298
299        {
300            // conditional section:
301            // when exporting into a new database there is no need to adapt alignments or names
302
303            if (dst_is_new) awm->sens_mask(AWM_DISABLED);
304
305            awm->at("alignment");
306            awm->callback(MG_create_merge_alignment_window);
307            awm->help_text("mg_alignment.hlp");
308            awm->create_button("CHECK_ALIGNMENTS", "Check alignments ...");
309
310            awm->at("names");
311            awm->callback(MG_create_merge_names_window);
312            awm->help_text("mg_names.hlp");
313            awm->create_button("CHECK_NAMES", "Check IDs ...");
314
315            if (dst_is_new) {
316                awm->sens_mask(AWM_ALL);
317                MG_set_renamed(true, aw_root, "Not necessary");
318            }
319        }
320
321        awm->at("species");
322        awm->callback(makeCreateWindowCallback(MG_create_merge_species_window, dst_is_new));
323        awm->help_text("mg_species.hlp");
324        awm->create_button("TRANSFER_SPECIES", "Transfer species ... ");
325
326        awm->at("extendeds");
327        awm->callback(MG_create_merge_SAIs_window);
328        awm->help_text("mg_extendeds.hlp");
329        awm->create_button("TRANSFER_SAIS", "Transfer SAIs ...");
330
331        awm->at("trees");
332        awm->callback(MG_create_merge_trees_window);
333        awm->help_text("mg_trees.hlp");
334        awm->create_button("TRANSFER_TREES", "Transfer trees ...");
335
336        awm->at("configs");
337        awm->callback(MG_create_merge_configs_window);
338        awm->help_text("mg_species_configs.hlp");
339        awm->create_button("TRANSFER_CONFIGS", "Transfer configurations ...");
340
341        {
342            // conditional section:
343            // allow save only when not merging into DB running inside ARB_NT
344
345            if (!save_dst_enabled) awm->sens_mask(AWM_DISABLED);
346
347            awm->at("save");
348            awm->callback(makeCreateWindowCallback(MG_create_save_as_window, false));
349            awm->help_text("save.hlp");
350            awm->create_button("SAVE_WHOLE_DB2", "Save whole target DB as ...");
351
352            awm->at("save_quick");
353            awm->callback(MG_save_quick_result_cb);
354            awm->help_text("save.hlp");
355            awm->create_button("SAVE_CHANGES_OF_DB2", "Quick-save changes of target DB");
356
357            awm->sens_mask(AWM_ALL);
358        }
359
360        awm->at("quit");
361        awm->callback(makeWindowCallback(MG_confirm_exit_restart_if, false));
362        awm->create_button("QUIT", save_dst_enabled ? "Quit" : "Close");
363
364        awm->activate();
365
366        return awm;
367    }
368}
369
370void MERGE_create_all_awars(AW_root *awr, AW_default aw_def) {
371    MG_create_trees_awar(awr, aw_def);
372    MG_create_config_awar(awr, aw_def);
373    MG_create_extendeds_awars(awr, aw_def);
374    MG_create_species_awars(awr, aw_def);
375    MG_create_gene_species_awars(awr, aw_def);
376
377    MG_create_rename_awars(awr, aw_def);
378
379#if defined(DEBUG)
380    AWT_create_db_browser_awars(awr, aw_def);
381#endif // DEBUG
382}
383
384inline const char *get_awar_name(const char *awar_base_name, const char *entry) {
385    return GBS_global_string("%s/%s", awar_base_name, entry);
386}
387
388static void filename_changed_cb(AW_root *awr, const char *awar_base_name) {
389    AW_awar *filename_awar = awr->awar(get_awar_name(awar_base_name, "file_name"));
390
391    char *name;
392    char *suffix;
393    GB_split_full_path(filename_awar->read_char_pntr(), NULp, NULp, &name, &suffix);
394
395    if (name) {
396        AW_awar    *name_awar = awr->awar(get_awar_name(awar_base_name, "name"));
397        const char *shown_name;
398        if (strcmp(name, ":") == 0 && !suffix) {
399            shown_name = ": (DB loaded in ARB_NT)";
400        }
401        else {
402            shown_name = GB_append_suffix(name, suffix);
403        }
404        name_awar->write_string(shown_name);
405    }
406
407    free(name);
408    free(suffix);
409}
410
411static void create_fileselection_and_name_awars(AW_root *awr, AW_default aw_def, const char *awar_base_name, const char *filename) {
412    AW_create_fileselection_awars(awr, awar_base_name, "", ".arb", filename);
413
414    awr->awar_string(get_awar_name(awar_base_name, "name"), "", aw_def); // create awar to display DB-names w/o path
415    AW_awar *filename_awar = awr->awar(get_awar_name(awar_base_name, "file_name")); // defined by AW_create_fileselection_awars above
416
417    filename_awar->add_callback(makeRootCallback(filename_changed_cb, awar_base_name));
418    filename_awar->touch(); // trigger callback once
419}
420
421void MERGE_create_db_file_awars(AW_root *awr, AW_default aw_def, const char *src_name, const char *dst_name) {
422    create_fileselection_and_name_awars(awr, aw_def, AWAR_DB_DST, dst_name);
423    create_fileselection_and_name_awars(awr, aw_def, AWAR_DB_SRC, src_name);
424}
425
Note: See TracBrowser for help on using the repository browser.