ARB
NT_main.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : NT_main.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 <mg_merge.hxx>
14 #include <awti_import.hxx>
15 #include <insdel.h>
16 #include <macros.hxx>
17 
18 #include <awt.hxx>
19 #include <awt_misc.hxx>
20 #include <awt_sel_boxes.hxx>
21 #include <awt_TreeAwars.hxx>
22 
23 #include <aw_advice.hxx>
24 #include <aw_question.hxx>
25 #include <aw_awars.hxx>
26 #include <aw_edit.hxx>
27 #include <aw_file.hxx>
28 #include <aw_msg.hxx>
29 #include <aw_root.hxx>
30 
31 #include <arbdbt.h>
32 #include <adGene.h>
33 
34 #include <arb_version.h>
35 #include <arb_progress.h>
36 #include <arb_file.h>
37 
38 #include <signal.h>
39 
40 using namespace std;
41 
43 
45 
46 // NT_format_all_alignments may be called after any operation which causes
47 // unformatted alignments (e.g importing sequences)
48 //
49 // It tests all alignments whether they need to be formatted
50 // and asks the user if they should be formatted.
51 
53  GB_ERROR err = NULp;
54  GB_transaction ta(gb_main);
55  GB_topSecurityLevel unsecured(gb_main);
56 
57  long ali_count = GBT_count_alignments(gb_main);
58  if (ali_count) {
59  arb_progress progress("Formatting alignments", ali_count);
60  err = GBT_check_data(gb_main, NULp);
61 
62  AW_repeated_question question;
63  question.add_help("prompt/format_alignments.hlp");
64 
65  GBDATA *gb_presets = GBT_get_presets(gb_main);
66  for (GBDATA *gb_ali = GB_entry(gb_presets, "alignment");
67  gb_ali && !err;
68  gb_ali = GB_nextEntry(gb_ali))
69  {
70  GBDATA *gb_aligned = GB_search(gb_ali, "aligned", GB_INT);
71 
72  if (GB_read_int(gb_aligned) == 0) { // sequences in alignment are not formatted
73  enum FormatAction {
74  FA_ASK_USER = 0, // ask user
75  FA_FORMAT_ALL = 1, // format automatically w/o asking
76  FA_SKIP_ALL = 2, // skip automatically w/o asking
77  };
78  FormatAction format_action = FA_ASK_USER;
79  GBDATA *gb_ali_name = GB_entry(gb_ali, "alignment_name");
80  const char *ali_name = GB_read_char_pntr(gb_ali_name);
81 
82  {
83  bool is_ali_genom = strcmp(ali_name, GENOM_ALIGNMENT) == 0;
84  GBDATA *gb_auto_format = GB_entry(gb_ali, "auto_format");
85 
86  if (gb_auto_format) {
87  format_action = FormatAction(GB_read_int(gb_auto_format));
88  if (is_ali_genom) {
89  if (format_action != FA_SKIP_ALL) {
90  format_action = FA_SKIP_ALL; // always skip ali_genom
91  err = GB_write_int(gb_auto_format, FA_SKIP_ALL);
92  }
93  }
94  }
95  else if (is_ali_genom) {
96  format_action = FA_SKIP_ALL;
97  err = GBT_write_int(gb_ali, "auto_format", FA_SKIP_ALL); // always skip
98  }
99  }
100 
101  bool perform_format = false;
102  if (!err) {
103  switch (format_action) {
104  case FA_FORMAT_ALL: perform_format = true; break;
105  case FA_SKIP_ALL: perform_format = false; break;
106  default: {
107  char *qtext = GBS_global_string_copy("Alignment '%s' is not formatted. Format?", ali_name);
108  int answer = question.get_answer("format_alignments", qtext, "Format,Skip,Always format,Always skip", "all", false);
109 
110  switch (answer) {
111  case 2:
112  err = GBT_write_int(gb_ali, "auto_format", FA_FORMAT_ALL);
113  // fall-through
114  case 0:
115  perform_format = true;
116  break;
117 
118  case 3:
119  err = GBT_write_int(gb_ali, "auto_format", FA_SKIP_ALL);
120  break;
121  }
122 
123  free(qtext);
124  break;
125  }
126  }
127  }
128  if (!err && perform_format) {
129  err = ARB_format_alignment(gb_main, ali_name);
130  }
131  }
132  progress.inc_and_check_user_abort(err);
133  }
134 
135  if (err) progress.done();
136  }
137 
138  err = ta.close(err);
139  return err;
140 }
141 
142 
143 // --------------------------------------------------------------------------------
144 
145 
147  // called once on ARB_NTREE startup
148  arb_progress cons_progress("Checking consistency");
149 
151  if (!err) err = NT_repair_DB(GLOBAL.gb_main);
152 
153  return err;
154 }
155 
156 __ATTR__USERESULT static GB_ERROR startup_mainwindow_and_dbserver(AW_root *aw_root, const char *autorun_macro, TREE_canvas*& result_ntw) {
158 
159  GB_ERROR error = configure_macro_recording(aw_root, "ARB_NT", GLOBAL.gb_main); // @@@ problematic if called from startup-importer
160  if (!error) {
161  result_ntw = NT_create_main_window(aw_root);
162  if (GB_is_server(GLOBAL.gb_main)) {
164  if (!error) NT_repair_userland_problems();
165  }
166  }
167 
168  if (!error && autorun_macro) execute_macro(aw_root, autorun_macro); // @@@ triggering execution here is ok, but its a bad place to pass 'autorun_macro'. Should be handled more generally
169 
170  return error;
171 }
172 
173 static ARB_ERROR load_and_startup_main_window(AW_root *aw_root, const char *autorun_macro) {
174  char *db_server = aw_root->awar(AWAR_DB_PATH)->read_string();
175  GLOBAL.gb_main = GBT_open(db_server, "rw");
176 
178  if (!GLOBAL.gb_main) {
179  error = GB_await_error();
180  }
181  else {
182  aw_root->awar(AWAR_DB_PATH)->write_string(db_server);
183 
184 #define MAXNAMELEN 35
185  int len = strlen(db_server);
186  if (len>MAXNAMELEN) {
187  char *nameOnly = strrchr(db_server, '/');
188  if (nameOnly) {
189  nameOnly++;
190  len -= (nameOnly-db_server);
191  memmove(db_server, nameOnly, len+1);
192  if (len>MAXNAMELEN) {
193  strcpy(db_server+MAXNAMELEN-3, "...");
194  }
195  }
196  }
197 #if defined(DEBUG)
198  AWT_announce_db_to_browser(GLOBAL.gb_main, GBS_global_string("ARB database (%s)", db_server));
199 #endif // DEBUG
200 
201  TREE_canvas *dummy = NULp;
202  GB_ERROR problem = startup_mainwindow_and_dbserver(aw_root, autorun_macro, dummy);
203  aw_message_if(problem); // no need to terminate ARB
204  }
205 
206  free(db_server);
207  return error;
208 }
209 
210 #define AWAR_DB_FILTER AWAR_DBBASE "/filter"
211 #define AWAR_DB_DIRECTORY AWAR_DBBASE "/directory"
212 
214  AW_root *aw_root = aww->get_root();
215  char *db_server = aw_root->awar(AWAR_DB_PATH)->read_string();
216 
217  if (strlen(db_server)) {
218  if (aw_ask_sure(NULp, GBS_global_string("Are you sure to delete database %s\nNote: there is no way to undelete it afterwards", db_server))) {
219  GB_ERROR error = GB_delete_database(db_server);
220  if (error) {
221  aw_message(error);
222  }
223  else {
224  aw_root->awar(AWAR_DB_FILTER)->touch();
225  }
226  }
227  }
228  else {
229  aw_message("No database selected");
230  }
231  free(db_server);
232 }
233 
235  GLOBAL.aw_root = aw_root;
236 
238  nt_assert(gb_imported == GLOBAL.gb_main); // import-DB should already be used as main-DB
239  GLOBAL.gb_main = gb_imported;
240 
241  TREE_canvas *ntw = NULp;
243 
244  if (aw_root->awar(AWAR_IMPORT_AUTOCONF)->read_int()) {
246  }
247 
248  aw_root->awar(AWAR_TREE_REFRESH)->touch();
249 }
250 
251 static void nt_intro_start_existing(AW_window *aw_intro) {
252  aw_intro->hide();
254  nt_assert(contradicted(error, got_macro_ability(aw_intro->get_root())));
255  if (error) {
256  aw_intro->show();
257  aw_popup_ok(error.deliver());
258  }
259  else {
260  error.expect_no_error();
261  }
262 }
263 
264 static void nt_intro_start_merge(AW_window *aw_intro) {
265  AW_root *aw_root = aw_intro->get_root();
266  const char *dir = aw_root->awar(AWAR_DB_DIRECTORY)->read_char_pntr();
267  char *merge_args = GBS_global_string_copy("'%s' '%s'", dir, dir);
268 
269  NT_restart(aw_root, merge_args); // call arb_ntree as merge-tool on exit
270 }
271 
272 static void nt_intro_start_import(AW_window *aw_intro) {
273  aw_intro->hide();
274 
275  AW_root *aw_root = aw_intro->get_root();
276  aw_root->awar_string(AWAR_DB_PATH)->write_string("noname.arb");
277 
278  AWTI_open_import_window(aw_root, NULp, true, NULp, makeRootCallback(start_main_window_after_import));
280 
281  nt_assert(got_macro_ability(aw_root));
282 }
283 
285  AW_window_simple *aws = new AW_window_simple;
286  aws->init(awr, "ARB_INTRO", "ARB INTRO");
287  aws->load_xfig("arb_intro.fig");
288 
289  aws->callback(makeWindowCallback(NT_exit, EXIT_SUCCESS));
290  aws->at("close");
291  aws->create_button("EXIT", "Exit", "x");
292 
293  aws->at("help");
294  aws->callback(makeHelpCallback("arb_intro.hlp"));
295  aws->create_button("HELP", "HELP", "H");
296 
298 
299  aws->button_length(0);
300 
301  aws->at("logo");
302  aws->create_button(NULp, "#logo.xpm");
303 
304  aws->at("version");
305  aws->create_button(NULp, GBS_global_string("Version " ARB_VERSION "\n(" ARB_BUILD_DATE ")")); // version + date
306 
307  aws->at("copyright");
308  aws->create_button(NULp, GBS_global_string("(C) 1993-" ARB_BUILD_YEAR));
309 
310  aws->at("old");
311  aws->callback(nt_intro_start_existing);
312  aws->create_autosize_button("OPEN_SELECTED", "OPEN SELECTED", "O");
313 
314  aws->at("del");
315  aws->callback(nt_delete_database);
316  aws->create_autosize_button("DELETE_SELECTED", "DELETE SELECTED");
317 
318  aws->at("new_complex");
319  aws->callback(nt_intro_start_import);
320  aws->create_autosize_button("CREATE_AND_IMPORT", "CREATE AND IMPORT", "I");
321 
322  aws->at("merge");
323  aws->callback(nt_intro_start_merge);
324  aws->create_autosize_button("MERGE_TWO_DATABASES", "MERGE TWO ARB DATABASES", "O");
325 
326  aws->at("expert");
327  aws->create_toggle(AWAR_EXPERT);
328 
329  return aws;
330 }
331 
333  static bool avoid_recursion = false;
334 
335  if (!avoid_recursion) {
336  LocallyModify<bool> flag(avoid_recursion, true);
337 
338  char *value = awr->awar(AWAR_DB_PATH)->read_string();
339  char *lslash = strrchr(value, '/');
340 
341  char *name = lslash ? lslash+1 : value;
342 #if defined(DEBUG)
343  printf("writing '%s' to AWAR_DB_NAME\n", name);
344 #endif // DEBUG
345  awr->awar(AWAR_DB_NAME)->write_string(name);
346 
347  if (lslash) { // update value of directory
348  lslash[0] = 0;
349  awr->awar(AWAR_DB_DIRECTORY)->write_string(value);
350  lslash[0] = '/';
351  }
352 
353  free(value);
354  }
355 }
356 
357 class NtreeCommandLine : virtual Noncopyable {
358  int arg_count;
359  char const*const* args;
360 
361  bool help_requested;
362  bool do_import;
363 
364  const char *macro_name;
365 
366 public:
367  NtreeCommandLine(int argc_, char const*const* argv_)
368  : arg_count(argc_-1),
369  args(argv_+1),
370  help_requested(false),
371  do_import(false),
372  macro_name(NULp)
373  {}
374 
375  void shift() { ++args; --arg_count; }
376 
377  int free_args() const { return arg_count; }
378  const char *get_arg(int num) const { return num<arg_count ? args[num] : NULp; }
379 
380  bool wants_help() const { return help_requested; }
381  bool wants_import() const { return do_import; }
382  bool wants_merge() const { return arg_count == 2; }
383 
384  const char *autorun_macro() const { return macro_name; }
385 
386  void print_help(FILE *out) const {
387  fprintf(out,
388  "\n"
389  "arb_ntree version " ARB_VERSION_DETAILED "\n"
390  "(C) 1993-" ARB_BUILD_YEAR " Lehrstuhl fuer Mikrobiologie - TU Muenchen\n"
391  "http://www.arb-home.de/\n"
392  "(version build by: " ARB_BUILD_USER "@" ARB_BUILD_HOST ")\n"
393  "\n"
394  "Possible usage:\n"
395  " arb_ntree => start ARB (intro)\n"
396  " arb_ntree DB => start ARB with DB\n"
397  " arb_ntree DB1 DB2 => merge from DB1 into DB2\n"
398  " arb_ntree --import FILE => import FILE into new database (FILE may be a filemask)\n"
399  "\n"
400  "Additional arguments possible with command lines above:\n"
401  " --execute macroname => execute macro 'macroname' after startup\n"
402  "\n"
403  "Each DB argument may be one of the following:\n"
404  " database.arb -> use existing or new database\n"
405  " \":\" -> connect to database of a running instance of ARB\n"
406  " directory -> prompt for databases inside directory\n"
407  " filemask -> also prompt for DB, but more specific (e.g. \"prot*.arb\")\n"
408  "\n"
409  );
410  }
411 
414 
415  while (!error && arg_count>0 && args[0][0] == '-') {
416  const char *opt = args[0]+1;
417  if (opt[0] == '-') ++opt; // accept '-' or '--'
418  if (strcmp(opt, "help") == 0 || strcmp(opt, "h") == 0) { help_requested = true; }
419  else if (strcmp(opt, "execute") == 0) { shift(); macro_name = *args; }
420  else if (strcmp(opt, "import") == 0) { do_import = true; }
421 
422  // bunch of test switches to provoke various ways to terminate (see also http://bugs.arb-home.de/ticket/538)
423  else if (strcmp(opt, "crash") == 0) { GBK_terminate("crash requested"); }
424  else if (strcmp(opt, "trap") == 0) { arb_assert(0); }
425  else if (strcmp(opt, "sighup") == 0) { raise(SIGHUP); }
426  else if (strcmp(opt, "sigsegv") == 0) { raise(SIGSEGV); }
427  else if (strcmp(opt, "sigterm") == 0) { raise(SIGTERM); }
428  else if (strcmp(opt, "fail") == 0) { exit(EXIT_FAILURE); }
429  else if (strcmp(opt, "exit") == 0) { exit(EXIT_SUCCESS); }
430  // end of test switches ----------------------------------------
431 
432  else error = GBS_global_string("Unknown switch '%s'", args[0]);
433  shift();
434  }
435  // non-switch arguments remain in arg_count/args
436  if (!error) {
437  if (do_import && arg_count != 1) error = "expected exactly one file-name or file-mask behind --import";
438  else if (arg_count>2) error = "too many stray arguments given (max. 2 accepted)";
439  }
440  return error;
441  }
442 };
443 
444 enum ArgType { // args that might be specified on command line (for DB or FILE; see above)
452 };
453 
454 inline bool has_arb_suffix(const char *arg) {
455  const char *suffix = strstr(arg, ".arb");
456  if (suffix) {
457  return strcmp(suffix, ".arb") == 0;
458  }
459  return false;
460 }
461 
462 static ArgType detectArgType(const char *arg) {
463  if (strcmp(arg, ":") == 0) return RUNNING_DB;
464  if (GB_is_directory(arg)) return DIRECTORY;
465  if (strpbrk(arg, "*?")) return FILEMASK;
466  if (has_arb_suffix(arg)) {
467  return GB_is_regularfile(arg) ? EXISTING_DB : NEW_DB;
468  }
469 
470  GB_ERROR load_file_err = GBT_check_arb_file(arg);
471  if (!load_file_err) return EXISTING_DB;
472 
474 }
475 
477 
478 #define ABORTED_BY_USER "aborted by user"
479 
480 static ARB_ERROR check_argument_for_mode(const char *database, char *&browser_startdir, RunMode& mode) {
481  // Check whether 'database' is a
482  // - ARB database
483  // - directory name
484  // - file to import
485  //
486  // Modify 'mode' occordingly.
487  // Set 'browser_startdir'
488 
490  if (mode != IMPORT) {
491  if (!database) mode = BROWSE;
492  else {
493  GB_ERROR load_file_err = GBT_check_arb_file(database);
494  if (load_file_err) {
495  char *full_path = AW_unfold_path("PWD", database);
496 
497  enum Action { LOAD_DB, CONVERT_DB, BROWSE_DB, EXIT, NOIDEA };
498  Action action = NOIDEA;
499  if (GB_is_directory(full_path)) {
500  action = BROWSE_DB;
501  }
502  else {
503  if (!GB_is_regularfile(full_path)) {
504  const char *msg = GBS_global_string("'%s' is neither a known option nor a legal file- or directory-name.\n(Error: %s)",
505  full_path, load_file_err);
506 
507  int ans = aw_question(NULp, msg, "Browser,Exit");
508  action = ans ? EXIT : BROWSE_DB;
509  }
510  else {
511  const char *msg = GBS_global_string("Your file is not an original arb file\n(%s)", load_file_err);
512  action = (Action)aw_question(NULp, msg, "Continue (dangerous),Start Converter,Browser,Exit");
513  }
514  }
515 
516  switch (action) {
517  case CONVERT_DB: mode = IMPORT; break;
518  case LOAD_DB: break;
519  case NOIDEA: nt_assert(0); FALLTHROUGH; // in NDEBUG
520  case EXIT: error = ABORTED_BY_USER; break;
521  case BROWSE_DB: {
522  char *dir = nulldup(full_path);
523  while (dir && !GB_is_directory(dir)) freeset(dir, AW_extract_directory(dir));
524 
525  if (dir) {
527  reassign(browser_startdir, dir);
528  mode = BROWSE;
529  }
530  free(dir);
531  break;
532  }
533 
534  }
535  free(full_path);
536  }
537  }
538  }
539 
540  return error;
541 }
542 
543 class SelectedDatabase : virtual Noncopyable {
544  GBDATA*& gb_main;
545  char *name;
546  ArgType type;
547  char *role;
548 
549  void fix_name() {
550  if (type != RUNNING_DB && name[0]) {
551  const char *changed;
552 
553  if (type == NEW_DB) {
554  changed = GB_unfold_in_directory(GB_getcwd(), name);
555  }
556  else {
557  changed = GB_canonical_path(name);
558  }
559 
560  if (strcmp(name, changed) != 0) {
561  reselect_file(changed);
562  }
563  }
564  }
565 
566 public:
567  SelectedDatabase(GBDATA*& gb_main_, const char *name_, const char *role_)
568  : gb_main(gb_main_),
569  name(ARB_strdup(name_)),
570  type(detectArgType(name)),
571  role(ARB_strdup(role_))
572  {
573  fix_name();
574  }
576  free(role);
577  free(name);
578  }
579 
580  ArgType arg_type() const { return type; }
581 
582  bool needs_to_prompt() const {
583  return type == DIRECTORY || type == FILEMASK || type == UNKNOWN_ARG;
584  }
585 
586  const char *get_fullname() const { return name; }
587  const char *get_nameonly() const {
588  const char *slash = strrchr(name, '/');
589  return slash ? slash+1 : name;
590  }
591  const char *get_role() const { return role; }
592  const char *get_description() const { return GBS_global_string("%s (%s)", get_role(), get_nameonly()); }
593 
594  ArgType get_type() const { return type; }
595 
596  const char *get_dir() const {
597  const char *dir = NULp;
598  switch (type) {
599  case DIRECTORY:
600  dir = get_fullname();
601  break;
602 
603  case NEW_DB:
604  case FILEMASK:
605  case EXISTING_FILE:
606  case EXISTING_DB: {
607  char *dir_copy;
608  GB_split_full_path(name, &dir_copy, NULp, NULp, NULp);
609 
610  static SmartCharPtr dir_store;
611  dir_store = dir_copy;
612 
613  dir = dir_copy;
614  break;
615  }
616  case UNKNOWN_ARG:
617  case RUNNING_DB:
618  dir = ".";
619  break;
620  }
621  return dir;
622  }
623 
624  const char *get_mask() const {
625  const char *mask;
626  switch (type) {
627  case FILEMASK: {
628  char *mask_copy;
629  GB_split_full_path(name, NULp, &mask_copy, NULp, NULp);
630 
631  static SmartCharPtr mask_store;
632  mask_store = mask_copy;
633 
634  mask = mask_copy;
635  break;
636  }
637  default:
638  mask = ".arb";
639  break;
640  }
641  return mask;
642  }
643 
644  void reselect_file(const char *file) {
645  freedup(name, file);
646  type = detectArgType(name);
647  fix_name();
648  }
649  void reselect_from_awar(AW_root *aw_root, const char *awar_name) {
650  if (awar_name) {
651  const char *file = aw_root->awar(awar_name)->read_char_pntr();
652  if (file) reselect_file(file);
653  }
654  }
655 
656  GB_ERROR open_db_for_merge(bool is_source_db);
657  void close_db() { if (gb_main) GB_close(gb_main); }
658 };
659 
661  GB_ERROR error = NULp;
662  const char *openMode = "rw";
663 
664  switch (get_type()) {
665  case DIRECTORY:
666  case FILEMASK:
667  GBK_terminate("Program logic error (should have been prompted for explicit DB name)");
668  break;
669 
670  case UNKNOWN_ARG:
671  case EXISTING_FILE:
672  error = GBS_global_string("'%s' is no arb-database", get_fullname());
673  break;
674 
675  case NEW_DB:
676  if (is_source_db) {
677  error = GBS_global_string("'%s' has to exist", get_fullname());
678  break;
679  }
680  openMode = "crw"; // allow to create DB
681  break;
682 
683  case EXISTING_DB:
684  case RUNNING_DB:
685  break;
686  }
687 
688  if (!error) {
689  gb_main = GBT_open(get_fullname(), openMode);
690  if (!gb_main) error = GB_await_error();
691  else {
692  IF_DEBUG(AWT_announce_db_to_browser(gb_main, get_description()));
693  }
694  }
695 
696  return error;
697 }
698 
699 struct merge_scheme : virtual Noncopyable {
702 
703  char *awar_src;
704  char *awar_dst;
705 
707 
709  : src(src_),
710  dst(dst_),
711  awar_src(NULp),
712  awar_dst(NULp),
713  error(NULp)
714  {}
716  if (error) {
717  src->close_db();
718  dst->close_db();
719  }
720  delete src;
721  delete dst;
722  free(awar_src);
723  free(awar_dst);
724  }
725 
726 
727  void open_dbs() {
728  if (!error) error = src->open_db_for_merge(true);
729  if (!error) error = dst->open_db_for_merge(false);
730  }
731 
732  void fix_dst(AW_root *aw_root) { dst->reselect_from_awar(aw_root, awar_dst); }
733  void fix_src(AW_root *aw_root) { src->reselect_from_awar(aw_root, awar_src); }
734 
735  bool knows_dbs() const { return !src->needs_to_prompt() && !dst->needs_to_prompt(); }
736 };
737 
738 static bool merge_tool_running_as_client = true; // default to safe state (true avoids call of 'arb_clean' at exit)
739 static void exit_from_merge(const char *restart_args) {
740  if (merge_tool_running_as_client) { // there is a main ARB running
741  if (restart_args) NT_start(restart_args, true);
742  exit(EXIT_SUCCESS); // exit w/o killing clients (in contrast to NT_exit())
743  }
744  else {
745  NT_restart(AW_root::SINGLETON, null2empty(restart_args));
746  nt_assert(0);
747  }
748 }
749 
751  fputs("Error: merge aborted by user\n", stderr);
753 }
754 
756  AW_window_simple *aw_msg = new AW_window_simple;
757 
758  aw_msg->init(aw_root, "arb_merge_error", "ARB merge error");
759  aw_msg->recalc_size_atShow(AW_RESIZE_DEFAULT); // force size recalc (ignores user size)
760 
761  aw_msg->at(10, 10);
762  aw_msg->auto_space(10, 10);
763 
764  aw_msg->create_autosize_button(NULp, error, "", 2);
765  aw_msg->at_newline();
766 
767  aw_msg->callback(merge_startup_abort_cb);
768  aw_msg->create_autosize_button("OK", "Ok", "O", 2);
769 
770  aw_msg->window_fit();
771 
772  return aw_msg;
773 }
775  ms->fix_src(aw_root);
776  ms->fix_dst(aw_root);
777 
778  if (ms->knows_dbs()) {
779  ms->open_dbs();
780  }
781  else {
782  ms->error = "Need two databases to merge";
783  }
784 
785  AW_window *aw_result;
786  if (!ms->error) {
788  bool dst_is_new = ms->dst->arg_type() == NEW_DB;
789  aw_result = MERGE_create_main_window(aw_root, dst_is_new, exit_from_merge);
790 
791  nt_assert(got_macro_ability(aw_root));
792  }
793  else {
794  aw_result = merge_startup_error_window(aw_root, ms->error);
795  }
796  delete ms; // was allocated in startup_gui()
797  return aw_result;
798 }
799 
801  AW_window *aw_result;
802  if (ms->dst->needs_to_prompt()) {
803  aw_result = awt_create_load_box(aw_root, "Select", ms->dst->get_role(),
804  ms->dst->get_dir(), ms->dst->get_mask(),
805  &(ms->awar_dst),
806  AW_window::makeWindowReplacer(makeCreateWindowCallback(startup_merge_main_window, ms)),
807  makeWindowCallback(merge_startup_abort_cb), "Cancel");
808  }
809  else {
810  aw_result = startup_merge_main_window(aw_root, ms);
811  }
812  return aw_result;
813 }
814 
816  // if src_spec or dst_spec needs to be prompted for -> startup prompters with callbacks bound to continue
817  // otherwise just startup merge
818 
819  AW_window *aw_result;
820  if (ms->src->needs_to_prompt()) {
821  aw_result = awt_create_load_box(aw_root, "Select", ms->src->get_role(),
822  ms->src->get_dir(), ms->src->get_mask(),
823  &(ms->awar_src),
825  makeWindowCallback(merge_startup_abort_cb), "Cancel");
826  }
827  else {
828  aw_result = startup_merge_prompting_for_nonexplicit_dst_db(aw_root, ms);
829  }
830  return aw_result;
831 }
832 
834  {
835  char *message = ARB_strdup(GB_path_in_ARBLIB("message"));
836  char *stamp = ARB_strdup(GB_path_in_arbprop("msgtime"));
837  if (GB_time_of_file(message)>GB_time_of_file(stamp)) {
838  AW_edit(message);
839  AWT_system_cb(GBS_global_string("touch %s", stamp));
840  }
841  free(stamp);
842  free(message);
843  }
844 
845  // create some early awars
846  // Note: normally you don't like to add your awar-init-function here, but into nt_create_all_awars()
847 
848  AW_root* aw_root = GLOBAL.aw_root;
849 
850  AW_create_fileselection_awars(aw_root, AWAR_DBBASE, "", ".arb", "noname.arb");
851  aw_root->awar_string(AWAR_DB_NAME, "noname.arb");
853 
854  aw_root->awar_int(AWAR_EXPERT, 0);
855 
857 
859 
860  aw_root->setUserActionTracker(new NullTracker); // no macro recording inside prompters that may popup
861  if (!error) {
862  nt_assert(!cl.wants_help());
863 
864  RunMode mode = NORMAL;
865 
866  if (cl.wants_merge()) mode = MERGE;
867  else if (cl.wants_import()) mode = IMPORT;
868 
869  if (mode == MERGE) {
871 
872  merge_scheme *ms = new merge_scheme( // freed in startup_merge_main_window()
873  new SelectedDatabase(GLOBAL_gb_src, cl.get_arg(0), "Source DB for merge"),
874  new SelectedDatabase(GLOBAL_gb_dst, cl.get_arg(1), "Destination DB for merge"));
875 
877 
878  if (ms->src->arg_type() == RUNNING_DB && ms->dst->arg_type() == RUNNING_DB) {
879  error = "You cannot merge from running to running DB";
880  }
881  else {
882  aw_root->setUserActionTracker(new NullTracker); // no macro recording during startup of merge tool (file prompts)
884 
885  nt_assert(contradicted(aww, error));
886 
887  if (!error) {
888  aww->show();
889  aw_root->main_loop();
890  nt_assert(0);
891  }
892  }
893  }
894  else {
895  const char *database = NULp;
896  char *browser_startdir = ARB_strdup(".");
897 
898  if (cl.free_args() > 0) database = cl.get_arg(0);
899 
900  error = check_argument_for_mode(database, browser_startdir, mode);
901  if (!error) {
902  if (mode == IMPORT) {
903  AWTI_open_import_window(aw_root, database, true, NULp, makeRootCallback(start_main_window_after_import));
905 
906  nt_assert(got_macro_ability(aw_root));
907  aw_root->main_loop();
908  }
909  else if (mode == NORMAL) {
910  aw_root->awar(AWAR_DB_PATH)->write_string(database);
911  error = load_and_startup_main_window(aw_root, cl.autorun_macro());
912  if (!error) {
913  nt_assert(got_macro_ability(aw_root));
914  aw_root->main_loop();
915  }
916  }
917  else if (mode == BROWSE) {
918  aw_root->awar(AWAR_DB_DIRECTORY)->write_string(browser_startdir);
919  char *latest = GB_find_latest_file(browser_startdir, "/\\.(arb|a[0-9]{2})$/");
920  if (latest) {
921  int l = strlen(latest);
922  strcpy(latest+l-3, "arb");
923  aw_root->awar(AWAR_DB_PATH)->write_string(latest);
924  free(latest);
925  }
926  nt_create_intro_window(aw_root)->show();
927  aw_root->setUserActionTracker(new NullTracker); // no macro recording inside intro window
928  aw_root->main_loop();
929  }
930  }
931  free(browser_startdir);
932  }
933  }
934 
935  if (error) {
936  const char *msg = error.preserve();
937  if (strcmp(msg, ABORTED_BY_USER) != 0) aw_popup_ok(msg);
938  }
939 }
940 
941 int ARB_main(int argc, char *argv[]) {
942  {
943  // i really dont want 'arb_ntree --help' to startup the GUI
944  // hack: parse CL twice
945  NtreeCommandLine cl(argc, argv);
946  bool cl_ok = !cl.parse().deliver();
947  if (cl_ok) {
948  if (cl.wants_help()) {
949  cl.print_help(stderr);
950  return EXIT_SUCCESS;
951  }
952  }
953  }
954 
955  aw_initstatus();
956  GB_set_verbose();
957 
958  GB_shell shell;
959  AW_root *aw_root = AWT_create_root("ntree.arb", "ARB_NT", need_macro_ability(), &argc, &argv);
960 
961  GLOBAL.aw_root = aw_root;
962 
963  NtreeCommandLine cl(argc, argv);
964  ARB_ERROR error = cl.parse();
965 
966  if (!error) {
967  if (cl.wants_help()) {
968  cl.print_help(stderr);
969  }
970  else {
971  startup_gui(cl, error);
972  }
973  }
974 
975  int exitcode = EXIT_SUCCESS;
976  if (error) {
977  exitcode = EXIT_FAILURE;
978  fprintf(stderr, "arb_ntree: Error: %s\n", error.deliver());
979  }
980  else {
981  error.expect_no_error();
982  }
983 
984  delete aw_root;
985 
986  return exitcode;
987 }
988 
void reselect_file(const char *file)
Definition: NT_main.cxx:644
static __ATTR__USERESULT GB_ERROR startup_mainwindow_and_dbserver(AW_root *aw_root, const char *autorun_macro, TREE_canvas *&result_ntw)
Definition: NT_main.cxx:156
#define arb_assert(cond)
Definition: arb_assert.h:245
const char * GB_ERROR
Definition: arb_core.h:25
#define AWAR_DB_NAME
Definition: aw_awar_defs.hxx:6
GB_TYPES type
bool wants_merge() const
Definition: NT_main.cxx:382
const char * get_dir() const
Definition: NT_main.cxx:596
void MERGE_create_db_file_awars(AW_root *awr, AW_default aw_def, const char *src_name, const char *dst_name)
Definition: MG_main.cxx:395
static GB_ERROR nt_check_database_consistency()
Definition: NT_main.cxx:146
#define AWAR_DB_DIRECTORY
Definition: NT_main.cxx:211
GB_ERROR preserve() const
Definition: arb_error.h:141
GB_CSTR GB_path_in_arbprop(const char *relative_path)
Definition: adsocket.cxx:1109
const char * get_mask() const
Definition: NT_main.cxx:624
void NT_create_config_after_import(TREE_canvas *ntw, bool imported_from_scratch)
Definition: NT_edconf.cxx:1302
const char * get_role() const
Definition: NT_main.cxx:591
long GB_read_int(GBDATA *gbd)
Definition: arbdb.cxx:699
ArgType arg_type() const
Definition: NT_main.cxx:580
bool wants_import() const
Definition: NT_main.cxx:381
bool GB_is_server(GBDATA *gbd)
Definition: adcomm.cxx:1697
bool knows_dbs() const
Definition: NT_main.cxx:735
void load_xfig(const char *file, bool resize=true)
Definition: AW_window.cxx:717
const char * get_arg(int num) const
Definition: NT_main.cxx:378
SelectedDatabase(GBDATA *&gb_main_, const char *name_, const char *role_)
Definition: NT_main.cxx:567
AW_root * AWT_create_root(const char *properties, const char *program, UserActionTracker *user_tracker, int *argc, char ***argv)
int GBT_count_alignments(GBDATA *gb_main)
Definition: adali.cxx:33
bool needs_to_prompt() const
Definition: NT_main.cxx:582
void AW_edit(const char *path)
Definition: AW_edit.cxx:16
static AW_window * startup_merge_main_window(AW_root *aw_root, merge_scheme *ms)
Definition: NT_main.cxx:774
AW_window * awt_create_load_box(AW_root *aw_root, const char *action, const char *what, const char *default_directory, const char *file_extension, char **set_file_name_awar, const WindowCallback &ok_cb, const WindowCallback &close_cb, const char *close_button_text)
void print_help(FILE *out) const
Definition: NT_main.cxx:386
void open_dbs()
Definition: NT_main.cxx:727
AW_window * MERGE_create_main_window(AW_root *aw_root, bool dst_is_new, void(*exit_cb)(const char *))
Definition: MG_main.cxx:153
#define ARB_BUILD_USER
Definition: arb_build.h:6
GBDATA * GB_nextEntry(GBDATA *entry)
Definition: adquery.cxx:339
void AWTI_set_importDB_pointer(GBDATA *&dbPtr)
void aw_initstatus()
Definition: AW_status.cxx:766
static AW_window * merge_startup_error_window(AW_root *aw_root, GB_ERROR error)
Definition: NT_main.cxx:755
bool wants_help() const
Definition: NT_main.cxx:380
void AW_create_standard_fileselection(AW_window *aws, const char *awar_prefix)
Definition: aw_file.hxx:30
#define ARB_VERSION_DETAILED
Definition: arb_build.h:2
GB_ERROR GB_delete_database(GB_CSTR filename)
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
static void nt_intro_start_import(AW_window *aw_intro)
Definition: NT_main.cxx:272
long read_int() const
Definition: AW_awar.cxx:187
Action
Definition: NT_taxonomy.cxx:36
static WindowCallback makeWindowReplacer(const CreateWindowCallback &cwcb)
Definition: aw_window.hxx:562
#define MAXNAMELEN
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
AW_root * awr
Definition: awt_canvas.hxx:338
AW_root * aw_root
Definition: NT_local.h:35
static void nt_intro_start_merge(AW_window *aw_intro)
Definition: NT_main.cxx:264
static void nt_intro_start_existing(AW_window *aw_intro)
Definition: NT_main.cxx:251
STL namespace.
#define ARB_VERSION
Definition: arb_build.h:1
NtreeCommandLine(int argc_, char const *const *argv_)
Definition: NT_main.cxx:367
#define ARB_BUILD_HOST
Definition: arb_build.h:5
#define EXIT_SUCCESS
Definition: arb_a2ps.c:154
static ARB_ERROR check_argument_for_mode(const char *database, char *&browser_startdir, RunMode &mode)
Definition: NT_main.cxx:480
__ATTR__USERESULT GB_ERROR configure_macro_recording(AW_root *aw_root, const char *client_id, GBDATA *gb_main)
Definition: trackers.cxx:454
const char * get_fullname() const
Definition: NT_main.cxx:586
bool has_arb_suffix(const char *arg)
Definition: NT_main.cxx:454
static void start_main_window_after_import(AW_root *aw_root)
Definition: NT_main.cxx:234
GB_CSTR GB_canonical_path(const char *anypath)
Definition: adsocket.cxx:947
GBDATA * GBT_open(const char *path, const char *opent)
Definition: adtools.cxx:524
GBDATA * GLOBAL_gb_dst
Definition: MG_main.cxx:32
static void exit_from_merge(const char *restart_args)
Definition: NT_main.cxx:739
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:234
void setUserActionTracker(UserActionTracker *user_tracker)
Definition: AW_root.cxx:210
#define AWAR_DB_FILTER
Definition: NT_main.cxx:210
GB_ERROR open_db_for_merge(bool is_source_db)
Definition: NT_main.cxx:660
ARB_ERROR parse()
Definition: NT_main.cxx:412
const char * read_char_pntr() const
Definition: AW_awar.cxx:171
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:353
GBDATA * AWTI_acquire_imported_DB_and_cleanup_importer()
static AW_root * SINGLETON
Definition: aw_root.hxx:102
void show()
Definition: AW_window.cxx:1658
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
GB_ERROR ARB_format_alignment(GBDATA *Main, const char *alignment_name)
Definition: insdel.cxx:1439
static void merge_startup_abort_cb(AW_window *)
Definition: NT_main.cxx:750
#define ARB_BUILD_YEAR
Definition: arb_build.h:4
GB_ERROR deliver() const
Definition: arb_error.h:114
void MERGE_create_all_awars(AW_root *awr, AW_default aw_def)
Definition: MG_main.cxx:344
void aw_popup_ok(const char *msg)
void recalc_size_atShow(enum AW_SizeRecalc sr)
Definition: AW_window.cxx:1436
int ARB_main(int argc, char *argv[])
Definition: NT_main.cxx:941
#define AWAR_DB_PATH
Definition: aw_awar_defs.hxx:5
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:463
unsigned long GB_time_of_file(const char *path)
Definition: arb_file.cxx:44
char * GB_find_latest_file(const char *dir, const char *mask)
Definition: adfile.cxx:152
#define false
Definition: ureadseq.h:13
void NT_restart(AW_root *aw_root, const char *arb_ntree_args)
Definition: NT_extern.cxx:350
static ARB_ERROR load_and_startup_main_window(AW_root *aw_root, const char *autorun_macro)
Definition: NT_main.cxx:173
static bool merge_tool_running_as_client
Definition: NT_main.cxx:738
merge_scheme(SelectedDatabase *src_, SelectedDatabase *dst_)
Definition: NT_main.cxx:708
void message(char *errortext)
static char const * macro_name
Definition: mkptypes.cxx:81
void touch()
Definition: AW_awar.cxx:210
SelectedDatabase * dst
Definition: NT_main.cxx:701
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define AWAR_TREE_REFRESH
void AW_create_fileselection_awars(AW_root *awr, const char *awar_base, const char *directories, const char *filter, const char *file_name)
Definition: AW_file.cxx:72
#define ABORTED_BY_USER
Definition: NT_main.cxx:478
AW_HEADER_MAIN NT_global GLOBAL
Definition: NT_main.cxx:44
void fix_dst(AW_root *aw_root)
Definition: NT_main.cxx:732
void expect_no_error() const
Definition: arb_error.h:136
static ArgType detectArgType(const char *arg)
Definition: NT_main.cxx:462
#define AWAR_DBBASE
Definition: aw_awar_defs.hxx:4
SelectedDatabase * src
Definition: NT_main.cxx:700
#define AWAR_IMPORT_AUTOCONF
Definition: awti_import.hxx:26
void execute_macro(AW_root *root, const char *macroname)
Definition: macro_gui.cxx:180
ArgType
Definition: NT_main.cxx:444
static AW_window * nt_create_intro_window(AW_root *awr)
Definition: NT_main.cxx:284
char * AW_unfold_path(const char *pwd_envar, const char *path)
Definition: AW_file.cxx:51
UserActionTracker * need_macro_ability()
Definition: trackers.cxx:450
char * read_string() const
Definition: AW_awar.cxx:201
GB_CSTR GB_path_in_ARBLIB(const char *relative_path)
Definition: adsocket.cxx:1103
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
GB_CSTR GB_getcwd(void)
Definition: adfile.cxx:24
#define GENOM_ALIGNMENT
Definition: adGene.h:19
#define EXIT_FAILURE
Definition: arb_a2ps.c:157
GB_ERROR GB_write_int(GBDATA *gbd, long i)
Definition: arbdb.cxx:1220
GBDATA * GLOBAL_gb_src
Definition: MG_main.cxx:31
#define nt_assert(cond)
Definition: NT_local.h:27
TYPE get_type() const
Definition: probe_tree.h:64
bool got_macro_ability(AW_root *aw_root)
Definition: trackers.cxx:475
long int flag
Definition: f2c.h:39
#define AW_HEADER_MAIN
Definition: aw_window.hxx:36
void ARB_declare_global_awars(AW_root *aw_root, AW_default aw_def)
bool aw_ask_sure(const char *unique_id, const char *msg)
void main_loop()
Definition: AW_root.cxx:625
int aw_question(const char *unique_id, const char *question, const char *buttons, bool sameSizeButtons, const char *helpfile)
Definition: AW_question.cxx:26
fputs(TRACE_PREFIX, stderr)
#define ARB_BUILD_DATE
Definition: arb_build.h:3
int free_args() const
Definition: NT_main.cxx:377
TREE_canvas * NT_create_main_window(AW_root *aw_root)
Definition: NT_extern.cxx:1824
ArgType get_type() const
Definition: NT_main.cxx:594
const char * get_nameonly() const
Definition: NT_main.cxx:587
static AW_window * startup_merge_prompting_for_nonexplicit_dbs(AW_root *aw_root, merge_scheme *ms)
Definition: NT_main.cxx:815
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:580
GB_CSTR GB_unfold_in_directory(const char *relative_directory, const char *path)
Definition: adsocket.cxx:1070
GB_ERROR close(GB_ERROR error)
Definition: arbdbpp.cxx:32
static void nt_delete_database(AW_window *aww)
Definition: NT_main.cxx:213
bool GB_is_directory(const char *path)
Definition: arb_file.cxx:176
#define __ATTR__USERESULT
Definition: attributes.h:58
GB_ERROR NT_format_all_alignments(GBDATA *gb_main)
Definition: NT_main.cxx:52
void aw_message(const char *msg)
Definition: AW_status.cxx:932
GB_ERROR error
Definition: NT_main.cxx:706
void hide()
Definition: AW_window.cxx:1807
GB_ERROR NT_repair_DB(GBDATA *gb_main)
void NT_start(const char *arb_ntree_args, bool restart_with_new_ARB_PID)
Definition: NT_extern.cxx:328
AW_root * get_root()
Definition: aw_window.hxx:348
void GB_set_verbose()
Definition: ad_load.cxx:31
void GB_split_full_path(const char *fullpath, char **res_dir, char **res_fullname, char **res_name_only, char **res_suffix)
Definition: adsocket.cxx:1213
#define NULp
Definition: cxxforward.h:97
GBDATA * gb_main
Definition: NT_local.h:36
bool GB_is_regularfile(const char *path)
Definition: arb_file.cxx:76
FormatAction
Definition: AWTI_edit.cxx:35
void reselect_from_awar(AW_root *aw_root, const char *awar_name)
Definition: NT_main.cxx:649
void fix_src(AW_root *aw_root)
Definition: NT_main.cxx:733
static AW_window * startup_merge_prompting_for_nonexplicit_dst_db(AW_root *aw_root, merge_scheme *ms)
Definition: NT_main.cxx:800
char * awar_src
Definition: NT_main.cxx:703
GB_ERROR write_string(const char *aw_string)
static void startup_gui(NtreeCommandLine &cl, ARB_ERROR &error)
Definition: NT_main.cxx:833
void AWT_install_cb_guards()
void AWTI_open_import_window(AW_root *awr, const char *def_importname, bool do_exit, GBDATA *gb_main, const RootCallback &after_import_cb)
#define FALLTHROUGH
Definition: cxxforward.h:107
char * AW_extract_directory(const char *path)
Definition: AW_file.cxx:59
const char * autorun_macro() const
Definition: NT_main.cxx:384
GB_transaction ta(gb_var)
GB_ERROR GBT_write_int(GBDATA *gb_container, const char *fieldpath, long content)
Definition: adtools.cxx:471
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
Definition: arbdb.cxx:874
#define AWAR_EXPERT
GBDATA * gb_main
Definition: adname.cxx:33
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
GB_ERROR GBT_check_data(GBDATA *Main, const char *alignment_name)
Definition: adali.cxx:217
AW_window * aww
Definition: awt_canvas.hxx:337
GBDATA * GBT_get_presets(GBDATA *gb_main)
Definition: adali.cxx:29
#define IF_DEBUG(x)
Definition: arb_assert.h:303
GB_ERROR GBT_check_arb_file(const char *name)
Definition: ad_load.cxx:1369
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
void NT_exit(AW_window *aws, int exitcode)
Definition: NT_extern.cxx:341
RunMode
Definition: NT_main.cxx:476
const char * get_description() const
Definition: NT_main.cxx:592
void NT_repair_userland_problems(void)
static void AWAR_DB_PATH_changed_cb(AW_root *awr)
Definition: NT_main.cxx:332
#define AW_ROOT_DEFAULT
Definition: aw_base.hxx:106
char * awar_dst
Definition: NT_main.cxx:704
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
void inc_and_check_user_abort(GB_ERROR &error)
Definition: arb_progress.h:274
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
void AWT_initTreeAwarRegistry(GBDATA *gbmain)
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:625
Definition: arbdb.h:66
void AWT_system_cb(AW_window *, const char *command)
Definition: AWT_misc.cxx:84