ARB
ED4_search.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : ED4_search.cxx //
4 // Purpose : //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // =============================================================== //
11 
12 #include <ed4_extern.hxx>
13 #include "ed4_awars.hxx"
14 #include "ed4_class.hxx"
15 #include "ed4_tools.hxx"
16 #include "ed4_edit_string.hxx"
17 
18 #include <fast_aligner.hxx>
19 
20 #include <awt_config_manager.hxx>
21 
22 #include <aw_awars.hxx>
23 #include <aw_file.hxx>
24 #include <aw_msg.hxx>
25 #include <aw_root.hxx>
26 #include <aw_question.hxx>
27 
28 #include <arbdbt.h>
29 
30 #include <climits>
31 #include <cctype>
32 #include <cerrno>
33 #include <map>
34 
36  "User1", "User2",
37  "Probe",
38  "Primer (local)", "Primer (region)", "Primer (global)",
39  "Signature (local)", "Signature (region)", "Signature (global)",
40  "Any"
41 };
42 
43 // --------------------------------------------------------------------------------
44 
45 struct SearchAwarList { // contains names of awars
46  const char *pattern,
50  *tu,
51  *pat_gaps,
52  *seq_gaps,
53  *reverse,
54  *complement,
55  *exact,
56  *show,
57  *openFolded,
58  *autoJump;
59 };
60 
61 class SearchSettings : virtual Noncopyable {
62  char *pattern;
63  int min_mismatches;
64  int max_mismatches;
65  ED4_SEARCH_CASE case_sensitive;
66  ED4_SEARCH_TU tu;
67  ED4_SEARCH_GAPS pat_gaps;
68  ED4_SEARCH_GAPS seq_gaps;
69  int reverse;
70  int complement;
71  int exact;
72  int open_folded;
73  int autoJump;
74 
75 public:
76 
77  void update(SearchAwarList *awarList) {
78  AW_root *root = ED4_ROOT->aw_root;
79 
80  freeset(pattern, root->awar(awarList->pattern)->read_string());
81 
82  min_mismatches = root->awar(awarList->min_mismatches)->read_int();
83  max_mismatches = root->awar(awarList->max_mismatches)->read_int();
84  case_sensitive = ED4_SEARCH_CASE(root->awar(awarList->case_sensitive)->read_int());
85  tu = ED4_SEARCH_TU(root->awar(awarList->tu)->read_int());
86  pat_gaps = ED4_SEARCH_GAPS(root->awar(awarList->pat_gaps)->read_int());
87  seq_gaps = ED4_SEARCH_GAPS(root->awar(awarList->seq_gaps)->read_int());
88  open_folded = root->awar(awarList->openFolded)->read_int();
89  autoJump = root->awar(awarList->autoJump)->read_int();
90  reverse = root->awar(awarList->reverse)->read_int();
91  complement = root->awar(awarList->complement)->read_int();
92  exact = root->awar(awarList->exact)->read_int();
93 
94  if (complement) {
95  if (IS_AMINO()) {
96  complement = 0;
97  root->awar(awarList->complement)->write_int(0);
98  aw_message("Search for complement is not supported for this alignment type (has been disabled)");
99  }
100  }
101  }
102 
103  SearchSettings(SearchAwarList *awarList) { pattern = NULp; update(awarList); }
104  ~SearchSettings() { delete pattern; }
105 
106  GB_CSTR get_pattern() const { return pattern; }
107  int get_min_mismatches() const { return min_mismatches; }
108  int get_max_mismatches() const { return max_mismatches; }
109  ED4_SEARCH_CASE get_case_sensitive() const { return case_sensitive; }
110  ED4_SEARCH_TU get_tu() const { return tu; }
111  ED4_SEARCH_GAPS get_pat_gaps() const { return pat_gaps; }
112  ED4_SEARCH_GAPS get_seq_gaps() const { return seq_gaps; }
113  int get_open_folded() const { return open_folded; }
114  int get_autoJump() const { return autoJump; }
115  int get_reverse() const { return reverse; }
116  int get_complement() const { return complement; }
117  int get_exact() const { return exact; }
118 };
119 
120 // --------------------------------------------------------------------------------
121 
122 class SearchTree;
123 typedef void (*reportMatch)(int start, int end, GB_CSTR comment, int mismatches[MAX_MISMATCHES]);
124 
125 class SearchTreeNode : virtual Noncopyable {
126  char c; // character
127  SearchTreeNode *son; // son != 0 (exception: FOUND)
128  SearchTreeNode *brother;
129  char *comment; // 0 or comment given in search pattern
130 
131  static SearchTreeNode FOUND;
132  static int start_offset;
133  static reportMatch report;
134  static int min_mismatches;
135  static int max_mismatches;
136  static int *uni2real; // transform unified positions to real sequence positions
137 
138 public:
139 
141  ~SearchTreeNode();
142 
143  SearchTreeNode *insert_unified_pattern(GB_CSTR pattern, GB_CSTR pattern_comment);
144  void findMatches(int off, GB_CSTR seq, int len, int mismatches, int mismatch_list[MAX_MISMATCHES]);
145 
146  // you must call the following functions before calling findMatches():
147 
148  static void set_start_offset(int off) { start_offset = off; }
149  static void set_report(reportMatch r, int *u2r) { report = r; uni2real = u2r; }
150  static void set_mismatches(int minMis, int maxMis) {
151  e4_assert(maxMis <= MAX_MISMATCHES);
152  e4_assert(minMis <= maxMis);
153  min_mismatches = minMis;
154  max_mismatches = maxMis;
155  }
156 };
157 
158 // --------------------------------------------------------------------------------
159 
160 SearchTreeNode SearchTreeNode::FOUND(NULp, NULp);
161 int SearchTreeNode::start_offset;
162 reportMatch SearchTreeNode::report;
163 int SearchTreeNode::min_mismatches;
164 int SearchTreeNode::max_mismatches;
165 int *SearchTreeNode::uni2real;
166 
168  comment = NULp;
169  if (pattern) {
170  e4_assert(pattern[0]);
171  c = pattern[0];
172  if (pattern[1]) {
173  son = new SearchTreeNode(pattern+1, pattern_comment);
174  }
175  else {
176  son = &FOUND;
177  comment = nulldup(pattern_comment);
178  }
179  }
180  else {
181  e4_assert(this==&FOUND);
182  c = 0;
183  son = NULp;
184  comment = nulldup(pattern_comment);
185  }
186  brother = NULp;
187 }
188 
190  if (brother!=&FOUND) delete brother;
191  if (son!=&FOUND) delete son;
192  delete comment;
193 }
194 
195 
197  if (this==&FOUND) {
198  if (pattern[0]) {
199  SearchTreeNode *neu = new SearchTreeNode(pattern, pattern_comment);
200 
201  neu->brother = &FOUND;
202  return neu;
203  }
204  return &FOUND;
205  }
206 
207  e4_assert(c);
208 
209  if (pattern[0]) { // pattern contains sth.
210  if (c==pattern[0]) {
211  e4_assert(son);
212  son = son->insert_unified_pattern(pattern+1, pattern_comment);
213  }
214  else {
215  if (brother) {
216  brother = brother->insert_unified_pattern(pattern, pattern_comment);
217  }
218  else {
219  brother = new SearchTreeNode(pattern, pattern_comment);
220  }
221  }
222  }
223  else { // empty pattern -> insert FOUND
224  if (brother) {
225  if (brother!=&FOUND) {
226  brother = brother->insert_unified_pattern(pattern, pattern_comment);
227  }
228  }
229  else {
230  brother = &FOUND;
231  }
232  }
233 
234  return this;
235 }
236 
237 void SearchTreeNode::findMatches(int off, GB_CSTR seq, int len, int mismatches, int mismatch_list[MAX_MISMATCHES]) {
238  e4_assert(mismatches <= MAX_MISMATCHES);
239  if (len) {
240  int matches = c=='?' || c==seq[0];
241  int use_mismatch = 0;
242 
243  if (!matches && mismatches<max_mismatches) {
244  bool c_is_gap = ED4_is_gap_character(c);
245  bool seq_is_gap = ED4_is_gap_character(seq[0]);
246 
247  if (c_is_gap==seq_is_gap) {
248  mismatch_list[mismatches] = uni2real[off];
249  mismatches++;
250  use_mismatch = 1;
251  matches = 1;
252  }
253  }
254 
255  if (matches) {
256  if (son==&FOUND) {
257  if (mismatches>=min_mismatches) {
258  report(uni2real[start_offset], uni2real[off], comment, mismatch_list);
259  }
260  }
261  else {
262  son->findMatches(off+1, seq+1, len-1, mismatches, mismatch_list);
263  }
264 
265  if (use_mismatch) {
266  mismatches--;
267  mismatch_list[mismatches] = -1;
268  }
269  }
270  }
271 
272  if (brother==&FOUND) {
273  if (mismatches>=min_mismatches) {
274  report(uni2real[start_offset], uni2real[off-1], comment, mismatch_list);
275  }
276  }
277  else if (brother) {
278  brother->findMatches(off, seq, len, mismatches, mismatch_list);
279  }
280 }
281 
282 // --------------------------------------------------------------------------------
283 
284 class SearchTree : virtual Noncopyable {
285  const SearchSettings *sett;
286  SearchTreeNode *root;
287  unsigned char unified[256];
288  int shortestPattern;
289 
290  static char unify_char(char c, int case_sensitive, int T_equal_U);
291 
292  char *unify_str(const char *data, int len, ED4_SEARCH_GAPS gaps, int *new_len, int **uni2real);
293  char *unify_pattern(const char *pattern, int *new_len);
294  char *unify_sequence(const char *sequence, int len, int *new_len, int **uni2real);
295 
296 public:
297 
298  SearchTree(const SearchSettings *s);
299  ~SearchTree();
300 
301  void findMatches(const char *seq, int len, reportMatch report);
302  int get_shortestPattern() const { return shortestPattern; }
303 };
304 
305 // --------------------------------------------------------------------------------
306 
307 static char *shortenString(char *s) {
308  char *end = strchr(s, '\0');
309 
310  while (end>s && isspace(end[-1])) {
311  *--end = 0;
312  }
313  while (isspace(s[0])) {
314  s++;
315  }
316 
317  return s;
318 }
319 
320 static void splitTokComment(char **tok, char **commentP) {
321  char *num = strchr(*tok, '#');
322 
323  if (num) {
324  num[0] = 0;
325  *commentP = shortenString(num+1);
326  }
327  else {
328  *commentP = NULp;
329  }
330 
331  *tok = shortenString(*tok);
332 }
333 
334 static char *appendComment(const char *s1, int l1, const char *s2) {
335  if (s1) {
336  int l2 = strlen(s2);
337  char *s = ARB_alloc<char>(l1+1+l2+1);
338 
339  sprintf(s, "%s %s", s1, s2);
340  return s;
341  }
342 
343  return NULp;
344 }
345 
347  sett = s;
348  root = NULp;
349  shortestPattern = INT_MAX;
350 
351  {
352  int i;
353  int case_sensitive = (sett->get_case_sensitive()==ED4_SC_CASE_SENSITIVE);
354  int T_equal_U = (sett->get_tu()==ED4_ST_T_EQUAL_U);
355 
356  for (i=0; i<256; i++) {
357  unified[i] = unify_char(i, case_sensitive, T_equal_U);
358  }
359  }
360 
361 #define INSERT_ROOT_PATTERN(tok, com) \
362  do { \
363  if (root) { \
364  root = root->insert_unified_pattern(tok, com); \
365  } \
366  else { \
367  root = new SearchTreeNode(tok, com); \
368  } \
369  } while (0)
370 
371 
372  {
373  char *pattern = ARB_strdup(sett->get_pattern());
374  const char *trenner = "\n,";
375  char *tok = strtok(pattern, trenner);
376  char *comment;
377  char T_or_U;
378  GB_ERROR T_or_U_error = GBT_determine_T_or_U(ED4_ROOT->alignment_type, &T_or_U, "complement");
379  bool show_T_or_U_error = false;
380 
381  while (tok) {
382  splitTokComment(&tok, &comment);
383  int uni_tok_len;
384  char *uni_tok = unify_pattern(tok, &uni_tok_len);
385 
386  if (uni_tok[0]) {
387  int s_exact = sett->get_exact();
388  int s_reverse = sett->get_reverse();
389  int s_complement = sett->get_complement();
390 
391  if (uni_tok_len<shortestPattern) {
392  shortestPattern = uni_tok_len;
393  }
394 
395  if (!s_exact || (!s_reverse && !s_complement)) {
396  // insert original search pattern if all patterns shall be used (!s_exact)
397  // or if neither s_reverse nor s_complement
398  INSERT_ROOT_PATTERN(uni_tok, comment);
399  }
400  int commentLen = comment ? strlen(comment) : 0;
401 
402  if (s_reverse) {
403  char *reverse = GBT_reverseNucSequence(uni_tok, uni_tok_len);
404 
405  if (!s_exact || !s_complement) {
406  char *reverseComment = appendComment(comment, commentLen, "(reverse)");
407 
408  INSERT_ROOT_PATTERN(reverse, reverseComment); // insert reverse pattern
409  free(reverseComment);
410  }
411  if (s_complement) {
413  if (T_or_U) {
414  char *revcomp = GBT_complementNucSequence(reverse, uni_tok_len, T_or_U);
415  char *revcompComment = appendComment(comment, commentLen, "(reverse complement)");
416  char *uni_revcomp = unify_pattern(revcomp, NULp);
417 
418  INSERT_ROOT_PATTERN(uni_revcomp, revcompComment); // insert reverse complement pattern
419 
420  free(uni_revcomp);
421  free(revcompComment);
422  free(revcomp);
423  }
424  else {
425  show_T_or_U_error = true; // only show error if it matters
426  }
427  }
428 
429  free(reverse);
430  }
431 
432  if (s_complement) {
434 
435  if (T_or_U) {
436  if (!s_exact || !s_reverse) {
437  char *complement = GBT_complementNucSequence(uni_tok, uni_tok_len, T_or_U);
438  char *complementComment = appendComment(comment, commentLen, "(complement)");
439  char *uni_complement = unify_pattern(complement, NULp);
440 
441  INSERT_ROOT_PATTERN(uni_complement, complementComment); // insert complement pattern
442 
443  free(uni_complement);
444  free(complementComment);
445  free(complement);
446  }
447  }
448  else {
449  show_T_or_U_error = true; // only show error if it matters
450  }
451  }
452 
453  }
454 
455  tok = strtok(NULp, trenner);
456  free(uni_tok);
457  }
458  free(pattern);
459 
460  if (show_T_or_U_error && T_or_U_error) aw_message(T_or_U_error);
461  }
462 
463 #undef INSERT_ROOT_PATTERN
464 }
465 
467  delete root;
468 }
469 
470 char SearchTree::unify_char(char c, int case_sensitive, int T_equal_U) {
471  if (!case_sensitive) {
472  c = tolower(c);
473  }
474 
475  if (T_equal_U) {
476  if (c=='t') {
477  c = 'u';
478  }
479  else if (c=='T') {
480  c = 'U';
481  }
482  }
483 
484  if (c=='.') {
485  c = '-';
486  }
487 
488  return c;
489 }
490 
491 char *SearchTree::unify_str(const char *data, int len, ED4_SEARCH_GAPS gaps, int *new_len, int **uni2real) {
492  char *p = ARB_alloc<char>(len+1);
493  char *pp = p;
494  int nlen = 0;
495  int realPos = 0;
496 
497  if (uni2real) {
498  int *u2r = *uni2real;
499 
500  if (gaps==ED4_SG_CONSIDER_GAPS) {
501  while (realPos<len) {
502  *pp++ = unified[(unsigned char)data[realPos]];
503  u2r[nlen++] = realPos++;
504  }
505  }
506  else {
507  while (realPos<len) {
508  unsigned char c = data[realPos];
509 
510  if (!ED4_is_gap_character(c)) {
511  *pp++ = unified[c];
512  u2r[nlen++] = realPos;
513  }
514  realPos++;
515  }
516  }
517  }
518  else {
519  if (gaps==ED4_SG_CONSIDER_GAPS) {
520  while (realPos<len) {
521  *pp++ = unified[(unsigned char)data[realPos++]];
522  nlen++;
523  }
524  }
525  else {
526  while (realPos<len) {
527  unsigned char c = data[realPos++];
528 
529  if (!ED4_is_gap_character(c)) {
530  *pp++ = unified[c];
531  nlen++;
532  }
533  }
534  }
535  }
536 
537  // ---------------
538 
539  pp[0] = 0;
540  if (new_len) {
541  *new_len = nlen;
542  }
543  return p;
544 }
545 
546 char *SearchTree::unify_pattern(const char *pattern, int *new_len) {
547  int len = strlen(pattern);
548  return unify_str(pattern, len, sett->get_pat_gaps(), new_len, NULp);
549 }
550 
551 char *SearchTree::unify_sequence(const char *sequence, int len, int *new_len, int **uni2real) {
552  return unify_str(sequence, len, sett->get_seq_gaps(), new_len, uni2real);
553 }
554 
555 void SearchTree::findMatches(const char *seq, int len, reportMatch report) {
556  if (root) {
557  int new_len;
558  int *uni2real = ARB_alloc<int>(len);
559  char *uni_seq = unify_sequence(seq, len, &new_len, &uni2real);
560 
561  int off;
562  char *useq = uni_seq;
563  int mismatch_list[MAX_MISMATCHES];
564 
565  for (off=0; off<MAX_MISMATCHES; off++) {
566  mismatch_list[off] = -1;
567  }
568 
569  SearchTreeNode::set_report(report, uni2real);
571 
572  for (off=0; off<new_len; off++, useq++) {
574  root->findMatches(off, useq, new_len-off, 0, mismatch_list);
575  }
576 
577  free(uni_seq);
578  free(uni2real);
579  }
580 }
581 
582 // --------------------------------------------------------------------------------
583 
584 #define AWAR_NAME(t, s) ED4_AWAR_##t##_SEARCH_##s
585 
586 #define AWAR_LIST(t) \
587  AWAR_NAME(t, PATTERN), \
588  AWAR_NAME(t, MIN_MISMATCHES), \
589  AWAR_NAME(t, MAX_MISMATCHES), \
590  AWAR_NAME(t, CASE), \
591  AWAR_NAME(t, TU), \
592  AWAR_NAME(t, PAT_GAPS), \
593  AWAR_NAME(t, SEQ_GAPS), \
594  AWAR_NAME(t, REVERSE), \
595  AWAR_NAME(t, COMPLEMENT), \
596  AWAR_NAME(t, EXACT), \
597  AWAR_NAME(t, SHOW), \
598  AWAR_NAME(t, OPEN_FOLDED), \
599  AWAR_NAME(t, AUTO_JUMP)
600 
602  { AWAR_LIST(USER1) },
603  { AWAR_LIST(USER2) },
604  { AWAR_LIST(PROBE) },
605  { AWAR_LIST(PRIMER1) },
606  { AWAR_LIST(PRIMER2) },
607  { AWAR_LIST(PRIMER3) },
608  { AWAR_LIST(SIG1) },
609  { AWAR_LIST(SIG2) },
610  { AWAR_LIST(SIG3) },
611 };
612 
614  return ED4_ROOT->aw_root->awar(awar_list[type].show)->read_int();
615 }
616 
624 };
625 
626 // --------------------------------------------------------------------------------
627 
628 static SearchSettings *settings[SEARCH_PATTERNS]; // last searched settings for each type
629 static SearchTree *tree[SEARCH_PATTERNS]; // Search trees for each type
630 
631 // --------------------------------------------------------------------------------
632 
634  // check awar values
635  if (action & (TEST_MIN_MISMATCH|TEST_MAX_MISMATCH)) {
636  int mimi = root->awar(awar_list[type].min_mismatches)->read_int();
637  int mami = root->awar(awar_list[type].max_mismatches)->read_int();
638 
639  if (mimi>mami) {
640  if (action & TEST_MIN_MISMATCH) { // max has changed
641  root->awar(awar_list[type].min_mismatches)->write_int(mami);
642  }
643  if (action & TEST_MAX_MISMATCH) { // min has changed
644  root->awar(awar_list[type].max_mismatches)->write_int(mimi);
645  }
646  }
647  }
648 
649  // init new search
650 
651  recalc :
653  if (!settings[type]) return;
654  settings[type]->update(&awar_list[type]);
655 
656  if (action & RECALC_SEARCH_TREE) {
657  delete tree[type];
658  tree[type] = new SearchTree(settings[type]);
659  }
660 
661  if (action & (RECALC_SEARCH_TREE|TEST_MIN_MISMATCH|TEST_MAX_MISMATCH)) {
662  int patLen = tree[type]->get_shortestPattern();
663  int maxMis = root->awar(awar_list[type].max_mismatches)->read_int();
664 
665  if (patLen < 3*maxMis) {
666  int maxMaxMis = tree[type]->get_shortestPattern()/3;
667 
668  aw_message(GBS_global_string("Too many mismatches (patterns of length=%i allow only %i max. mismatches)", patLen, maxMaxMis));
669 
670  root->awar(awar_list[type].max_mismatches)->write_int(maxMaxMis);
671  if (root->awar(awar_list[type].min_mismatches)->read_int() > maxMaxMis) {
672  root->awar(awar_list[type].min_mismatches)->write_int(maxMaxMis);
673  }
674  goto recalc;
675  }
676  }
677 
678  if (action & REFRESH_IF_SHOWN) {
679  if (resultsAreShown(type)) {
680  action = (enum search_params_changed_action)(action|REFRESH_ALWAYS);
681  }
682  }
683 
684  if (settings[type]->get_autoJump() && (action & DO_AUTO_JUMP)) { // auto jump
685  for (ED4_window *win = ED4_ROOT->first_window; win; win = win->next) {
686  ED4_LocalWinContext uses(win);
687 
688  ED4_cursor *cursor = &current_cursor();
689  bool jumped = false;
690 
691  if (cursor->owner_of_cursor && cursor->owner_of_cursor->is_sequence_terminal()) {
692  int pos = cursor->get_sequence_pos();
693  ED4_sequence_terminal *seq_term = cursor->owner_of_cursor->to_sequence_terminal();
694  ED4_SearchResults *result = &seq_term->results();
695 
696  result->search(seq_term);
697  ED4_SearchPosition *found = result->get_last_starting_before(type, pos+1, 0);
698  int bestPos = -1;
699 
700  if (found) {
701  bestPos = found->get_start_pos();
702  }
703 
704  if (pos>=1) {
705  found = result->get_first_starting_after(type, pos-1, 0);
706  if (found) {
707  int next_pos = found->get_start_pos();
708 
709  if (abs(pos-next_pos)<abs(pos-bestPos)) {
710  bestPos = next_pos;
711  }
712  }
713  }
714 
715  if (bestPos!=-1) {
716  if (bestPos == pos) {
717  jumped = true; // already there
718  }
719  else {
720  jumped = seq_term->setCursorTo(cursor, bestPos, 1, ED4_JUMP_KEEP_POSITION);
721  }
722  }
723  }
724 
725  if (!jumped) {
727  }
728  }
729  }
730 
732  root->awar(ED4_AWAR_SEARCH_RESULT_CHANGED)->touch(); // trigger refresh in SECEDIT
733 }
734 
736 #define cb(action) add_callback(makeRootCallback(searchParamsChanged, ED4_SearchPositionType(i), search_params_changed_action(action)));
737 
738  for (int i=0; i<SEARCH_PATTERNS; i++) {
739  root->awar_string(awar_list[i].pattern, NULp, GLOBAL_gb_main) ->cb(REFRESH_IF_SHOWN | RECALC_SEARCH_TREE | DO_AUTO_JUMP);
749  root->awar_int(awar_list[i].show, 1, GLOBAL_gb_main) ->cb(REFRESH_ALWAYS);
750  root->awar_int(awar_list[i].openFolded, 1, GLOBAL_gb_main) ->cb(0);
751  root->awar_int(awar_list[i].autoJump, 1, GLOBAL_gb_main) ->cb(DO_AUTO_JUMP);
752 
753  settings[i] = new SearchSettings(&awar_list[i]);
754  tree[i] = new SearchTree(settings[i]);
755  }
756 
758 
759 #undef cb
760 
761  // awars to save/load search parameters:
762  {
763  char *dir = ARB_strdup(GB_path_in_arbprop("search_settings"));
764  AW_create_fileselection_awars(root, ED4_SEARCH_SAVE_BASE, dir, ".asp", "noname.asp");
765  root->awar(ED4_SEARCH_SAVE_BASE"/directory")->write_string(dir);
766  free(dir);
767  }
768 }
769 
770 // --------------------------------------------------------------------------------
771 
772 char *ED4_SearchPosition::lastShownComment = NULp;
773 
774 ED4_SearchPosition::ED4_SearchPosition(int sp, int ep, ED4_SearchPositionType wf, GB_CSTR found_comment, int mismatches[MAX_MISMATCHES]) {
775  e4_assert(sp<=ep && sp>=0);
776  start_pos = sp;
777  end_pos = ep;
778  whatsFound = wf;
779  next = NULp;
780  comment = found_comment;
781  memcpy(mismatch, mismatches, sizeof(*mismatch)*MAX_MISMATCHES);
782 }
784  start_pos = other.start_pos;
785  end_pos = other.end_pos;
786  whatsFound = other.whatsFound;
787  next = NULp;
788  comment = ARB_strdup(other.comment);
789  memcpy(mismatch, other.mismatch, sizeof(mismatch[0])*MAX_MISMATCHES);
790 }
791 
793  ED4_SearchPosition *head = this;
794  ED4_SearchPosition *self = this;
795  ED4_SearchPosition *last = NULp;
796 
797  while (1) {
798  if (toAdd->cmp(*self)<=0) { // add before self
799  toAdd->next = self;
800  if (last) last->next = toAdd;
801  else head = toAdd;
802  break;
803  }
804  if (!self->next) { // add to end of list
805  self->next = toAdd;
806  break;
807  }
808  last = self;
809  self = self->next;
810  }
811 
812  return head;
813 }
815  ED4_SearchPosition *head = this;
816  ED4_SearchPosition *self = this;
817  ED4_SearchPosition *last = NULp;
818 
819  while (self) {
820  if (self->whatsFound == typeToRemove) { // remove self
821  ED4_SearchPosition **ptrToMe = last ? &(last->next) : &head;
822 
823  *ptrToMe = self->next;
824  self->next = NULp;
825  delete self;
826  self = *ptrToMe;
827  }
828  else { // do not remove
829  last = self;
830  self = self->next;
831  }
832  }
833 
834  return head;
835 }
836 
837 #ifdef TEST_SEARCH_POSITION
838 int ED4_SearchPosition::ok() const {
839 #ifndef NDEBUG
840  if (next) {
841  int c = cmp(*next);
842 
843  if (c>0) {
844  printf("ED4_SearchPosition: list not sorted\n");
845  return 0;
846  }
847 
848  return next->ok();
849  }
850 #endif
851  return 1;
852 }
853 #endif
854 
856  if (!comment) return NULp;
857  if (lastShownComment && strcmp(lastShownComment, comment)==0) return NULp; // do not show comment twice
858 
859  delete lastShownComment;
860  lastShownComment = ARB_strdup(comment);
861  return lastShownComment;
862 }
863 
865  ED4_SearchPosition *self = this->next;
866 
867  while (self) {
868  if (self->start_pos > pos) break; // none found
869  if (self->containsPos(pos)) return self;
870  self = self->next;
871  }
872  return NULp;
873 }
874 
875 // --------------------------------------------------------------------------------
876 
877 int ED4_SearchResults::initialized = 0;
878 int ED4_SearchResults::timeOfLastSearch[SEARCH_PATTERNS];
879 int ED4_SearchResults::timeOfNextSearch[SEARCH_PATTERNS];
880 int ED4_SearchResults::shown[SEARCH_PATTERNS];
881 int ED4_SearchResults::bufferSize;
882 char *ED4_SearchResults::buffer;
883 
885  if (!initialized) {
886  int i;
887 
888  for (i=0; i<SEARCH_PATTERNS; i++) {
889  timeOfLastSearch[i] = 0;
890  timeOfNextSearch[i] = 1;
892  }
893 
894  bufferSize = 100;
895  ARB_calloc(buffer, bufferSize);
896 
897  initialized = 1;
898  }
899 
900  arraySize = 0; // list-format
901  array = NULp;
902  first = NULp;
903  int i;
904  for (i=0; i<SEARCH_PATTERNS; i++) {
905  timeOf[i] = 0;
906  }
907 }
908 
910  delete first;
911  free(array);
912 }
913 
914 // --------------------------------------------------------------------------------
915 
918 
919 static void reportSearchPosition(int start, int end, GB_CSTR comment, int mismatches[MAX_MISMATCHES]) {
920  ED4_SearchPosition *pos = new ED4_SearchPosition(start, end, reportType, comment, mismatches);
921  reportToResult->addSearchPosition(pos);
922 }
923 
924 // --------------------------------------------------------------------------------
925 
927  if (is_array()) {
928  to_list();
929  }
930 
931  if (first) {
932  first = first->insert(pos);
933 #ifdef TEST_SEARCH_POSITION
934  e4_assert(first->ok());
935 #endif
936  }
937  else {
938  first = pos;
939  }
940 }
941 
943  int i;
944  int needed[SEARCH_PATTERNS];
945  int st_needed = 0;
946 
947  for (i=0; i<SEARCH_PATTERNS; i++) {
948  if (timeOf[i]<timeOfNextSearch[i]) {
949  timeOf[i] = timeOfNextSearch[i];
950  timeOfLastSearch[i] = timeOfNextSearch[i];
951  needed[i] = 1;
952  st_needed = 1;
953  if (first) {
954  if (is_array()) {
955  to_list();
956  }
957  first = first->remove(ED4_SearchPositionType(i));
958 #if defined TEST_SEARCH_POSITION
959  e4_assert(!first || first->ok());
960 #endif
961  }
962  }
963  else {
964  needed[i] = 0;
965  }
966  }
967 
968  if (st_needed) {
969  int len;
970  char *seq = seq_terminal->resolve_pointer_to_string_copy(&len);
971 
972  if (seq) {
973  reportToResult = this;
974  for (i=0; i<SEARCH_PATTERNS; i++) {
975  reportType = ED4_SearchPositionType(i);
976  if (needed[i]) {
977  if (is_array()) {
978  to_list();
979  }
980  tree[i]->findMatches(seq, len, reportSearchPosition);
981  }
982  }
983  reportToResult = NULp;
984  }
985  free(seq);
986  }
987 }
988 
990  if (is_list()) {
991  const_cast<ED4_SearchResults*>(this)->to_array();
992  }
993 
994  int l = 0;
995  int h = arraySize-1;
996 
997  ED4_SearchPosition *pos = NULp;
998  int m = 0;
999 
1000  while (l<=h) {
1001  m = (l+h)/2;
1002  pos = array[m];
1003  if (pos->get_end_pos()<start) {
1004  l = m+1;
1005  }
1006  else if (pos->get_start_pos()>end) {
1007  h = m-1;
1008  }
1009  else {
1010  e4_assert(pos->get_end_pos()>=start && pos->get_start_pos()<=end);
1011  break;
1012  }
1013  }
1014 
1015  if (l>h) {
1016  return NULp;
1017  }
1018 
1019  if (pos) {
1020  int best_m = m;
1021 
1022  while (m>0) {
1023  m--;
1024  pos = array[m];
1025  if (pos->get_end_pos()>=start && pos->get_start_pos()<=end) {
1026  best_m = m;
1027  }
1028  }
1029  pos = array[best_m];
1030 
1031  while (pos) {
1032  if (type==ED4_ANY_PATTERN || pos->get_whatsFound()==type) {
1033  break;
1034  }
1035  pos = pos->get_next();
1036  }
1037 
1038  return pos;
1039  }
1040 
1041  return NULp;
1042 }
1043 
1045  ED4_SearchPosition *sp = first;
1046 
1047  while (sp) {
1048  if (type==ED4_ANY_PATTERN || sp->get_whatsFound()==type) {
1049  if (sp->get_start_pos()>pos && (!mustBeShown || resultsAreShown(sp->get_whatsFound()))) {
1050  break;
1051  }
1052  }
1053  sp = sp->get_next();
1054  }
1055 
1056  return sp;
1057 }
1058 
1060  ED4_SearchPosition *sp = first;
1061  ED4_SearchPosition *best = NULp;
1062 
1063  while (sp) {
1064  if (type==ED4_ANY_PATTERN || sp->get_whatsFound()==type) {
1065  if (sp->get_start_pos()<pos && (!mustBeShown || resultsAreShown(sp->get_whatsFound()))) {
1066  best = sp;
1067  }
1068  else {
1069  break;
1070  }
1071  }
1072  sp = sp->get_next();
1073  }
1074 
1075  return best;
1076 }
1077 
1079  if (type==ED4_ANY_PATTERN) {
1080  int i;
1081  for (i=0; i<SEARCH_PATTERNS; i++) {
1083  }
1084  }
1085  else {
1086  int next_unused_stamp = timeOfLastSearch[type] + 1;
1087 
1088  shown[type] = resultsAreShown(type);
1089  if (timeOfNextSearch[type]!=next_unused_stamp) {
1090  timeOfNextSearch[type] = next_unused_stamp;
1091  }
1092  }
1093 }
1094 
1096  int i;
1097 
1098  for (i=0; i<SEARCH_PATTERNS; i++) {
1099  timeOf[i] = 0;
1100  }
1101 }
1102 
1103 char *ED4_SearchResults::buildColorString(const ED4_sequence_terminal *seq_terminal, int start, int end) {
1104  // builds a char buffer (access is only valid from result[start] till result[end])
1105  int i;
1106  int st_shown = 0;
1107 
1108  e4_assert(start<=end); // confirming the condition
1109  for (i=0; i<SEARCH_PATTERNS; i++) {
1110  if (shown[i]) {
1111  st_shown = 1;
1112  break;
1113  }
1114  }
1115  if (!st_shown) {
1116  return NULp; // nothing shown
1117  }
1118 
1119  search(seq_terminal);
1120  if (!get_first()) {
1121  return NULp; // nothing found
1122  }
1123 
1124  int needed_size = end-start+1;
1125  if (needed_size>bufferSize) {
1126  free(buffer);
1127  bufferSize = needed_size;
1128  ARB_calloc(buffer, bufferSize);
1129  }
1130  else {
1131  memset(buffer, 0, sizeof(char)*needed_size);
1132  }
1133 
1134  // search first search-result that goes in between start-end
1135 
1136  ED4_SearchPosition *pos = get_first_at(ED4_ANY_PATTERN, start, end);
1137  e4_assert(!pos || (pos->get_start_pos()<=end && pos->get_end_pos()>=start));
1138 
1139  int correct_neg_values = 0;
1140 
1141  while (pos && pos->get_start_pos()<=end) {
1142  int what = int(pos->get_whatsFound());
1143 
1144  if (shown[what]) {
1145  int color = ED4_G_SBACK_0 + what;
1146  int s = std::max(pos->get_start_pos(), start)-start;
1147  int e = std::min(pos->get_end_pos(), end)-start;
1148 
1149  for (i=s; i<=e; i++) {
1150  if (buffer[i]==0 || abs(buffer[i])>abs(color)) {
1151  buffer[i] = color;
1152  }
1153  }
1154 
1155  const int *mismatches = pos->getMismatches();
1156 
1157  for (i=0; i<5 && mismatches[i]>=0; i++) {
1158  int mpos = mismatches[i];
1159 
1160  if (mpos>=start && mpos<=end) {
1161  int rpos = mpos-start;
1162  if (buffer[rpos]==color) {
1163  buffer[rpos] = -buffer[rpos];
1164  correct_neg_values = 1;
1165  }
1166  }
1167  }
1168  }
1169  pos = pos->get_next();
1170  }
1171 
1172  if (correct_neg_values) {
1173  for (i=end-start; i>=0; i--) {
1174  if (buffer[i]<0) {
1175  buffer[i] = ED4_G_MBACK;
1176  }
1177  }
1178  }
1179 
1180  return buffer-start;
1181 }
1182 
1184  // used by ED4_cursor::updateAwars to get search-comment
1185  ED4_SearchPosition *p = get_last_starting_before(ED4_ANY_PATTERN, pos, 0); // @@@ tofix: should find last_ending before
1186  ED4_SearchPosition *best = NULp;
1187 
1188  if (!p) {
1189  p = get_first();
1190  }
1191 
1192  if (p && !p->containsPos(pos)) {
1193  p = p->get_next_at(pos);
1194  }
1195 
1196  while (p) {
1197  e4_assert(p->containsPos(pos));
1199  if (shown[type]) {
1200  if (!best || type<best->get_whatsFound()) {
1201  best = p;
1202  }
1203  }
1204  p = p->get_next_at(pos);
1205  }
1206 
1207  return best;
1208 }
1209 
1210 void ED4_SearchResults::to_array() {
1211  e4_assert(is_list());
1212 
1213  ED4_SearchPosition *pos = first;
1214 
1215  {
1216  int a_arraySize = 0;
1217 
1218  while (pos) {
1219  a_arraySize++;
1220  pos = pos->get_next();
1221  }
1222  arraySize = a_arraySize;
1223  }
1224 
1225  ED4_SearchPosition **a_array = ARB_alloc<ED4_SearchPosition*>(arraySize);
1226 
1227  pos = first;
1228  for (int e=0; e<arraySize; e++) {
1229  e4_assert(pos);
1230  a_array[e] = pos;
1231  pos = pos->get_next();
1232  }
1233 
1234  array = a_array;
1235 }
1236 
1237 void ED4_SearchResults::to_list() {
1238  e4_assert(is_array());
1239 
1240  freenull(array);
1241  arraySize = 0;
1242 }
1243 
1244 
1245 // --------------------------------------------------------------------------------
1246 
1247 inline void decodeSearchDescriptor(int descriptor, int *direction, ED4_SearchPositionType *pattern) {
1248  *direction = descriptor&1 ? 1 : -1;
1249  *pattern = ED4_SearchPositionType(descriptor/2);
1250 }
1251 
1252 static int last_searchDescriptor = -1;
1253 
1255  if (last_searchDescriptor==-1) {
1256  return GBS_global_string("You have to search first, before you can repeat a search.");
1257  }
1258 
1259  ED4_search_cb(NULp, last_searchDescriptor, ed4w);
1260  return NULp;
1261 }
1262 
1263 void ED4_search_cb(UNFIXED, int searchDescriptor, ED4_window *ed4w) {
1264  ED4_LocalWinContext uses(ed4w);
1265 
1266  last_searchDescriptor = searchDescriptor;
1267 
1268  int direction;
1270  decodeSearchDescriptor(searchDescriptor, &direction, &pattern);
1271 
1272  int searchOnlyForShownPatterns = pattern==ED4_ANY_PATTERN;
1273 
1274  // detect position where to start searching
1275 
1276  ED4_terminal *terminal = NULp; // start search at this terminal
1277  int pos; // ... and at this position
1278 
1279  ED4_cursor *cursor = &current_cursor();
1280  if (cursor->owner_of_cursor) { // if cursor is shown -> use cursor position
1281  terminal = cursor->owner_of_cursor;
1282  pos = cursor->get_sequence_pos();
1283  }
1284  else { // start at end or beginning
1285  if (direction==1) {
1287  pos = INT_MIN;
1288  }
1289  else {
1290  terminal = ED4_ROOT->root_group_man->get_last_terminal();
1291  pos = INT_MAX;
1292  }
1293  }
1294 
1295  ED4_terminal *start_terminal = terminal;
1296  int start_pos = pos;
1297  int last_loop = 0;
1298 
1299  while (terminal) {
1300  if (terminal->is_sequence_terminal()) {
1301  ED4_sequence_terminal *seq_terminal = terminal->to_sequence_terminal();
1302  ED4_SearchResults& results = seq_terminal->results();
1303  ED4_SearchPosition *found = NULp;
1304 
1305  if (pattern==ED4_ANY_PATTERN || settings[pattern]->get_open_folded() || !terminal->is_in_folded_group()) {
1306  results.search(seq_terminal);
1307 
1308  if (direction==1) {
1309  found = results.get_first_starting_after(pattern, pos, searchOnlyForShownPatterns);
1310  }
1311  else {
1312  found = results.get_last_starting_before(pattern, pos, searchOnlyForShownPatterns);
1313  }
1314 
1315  if (found) {
1316  pos = found->get_start_pos();
1317  if (terminal==start_terminal && pos==start_pos) {
1318  if (searchOnlyForShownPatterns) {
1319  aw_message("There are no other shown patterns");
1320  }
1321  else {
1322  aw_message("This is the only occurrence of the search pattern");
1323  }
1324  }
1325  else {
1326  seq_terminal->setCursorTo(&current_cursor(), pos, true, ED4_JUMP_KEEP_POSITION);
1327  }
1328  break;
1329  }
1330  else if (last_loop) {
1331  if (searchOnlyForShownPatterns) {
1332  aw_message("There are no shown patterns");
1333  }
1334  else {
1335  aw_message("Search pattern was not found in any sequence");
1336  }
1337  break;
1338  }
1339  }
1340  }
1341 
1342  if (direction==1) {
1343  terminal = terminal->get_next_terminal();
1344  if (!terminal) terminal = ED4_ROOT->root_group_man->get_first_terminal();
1345  pos = INT_MIN;
1346  }
1347  else {
1348  terminal = terminal->get_prev_terminal();
1349  if (!terminal) terminal = ED4_ROOT->root_group_man->get_last_terminal();
1350  pos = INT_MAX;
1351  }
1352 
1353  if (terminal==start_terminal) {
1354  last_loop = 1;
1355  }
1356  }
1357 }
1358 
1362 
1363  while (terminal) {
1364  if (terminal->is_sequence_terminal()) {
1365  ED4_sequence_terminal *seq_terminal = terminal->to_sequence_terminal();
1366  ED4_SearchResults& results = seq_terminal->results();
1367 
1368  results.search(seq_terminal);
1369  ED4_SearchPosition *found = results.get_first_starting_after(pattern, INT_MIN, false);
1370 
1371  if (found) {
1372  ED4_species_manager *species_man = seq_terminal->get_parent(LEV_SPECIES)->to_species_manager();
1373  if (species_man->is_species_seq_manager()) {
1374  GBDATA *gbd = species_man->get_species_pointer();
1375  e4_assert(gbd);
1376  GB_write_flag(gbd, 1);
1377  }
1378  }
1379  }
1380 
1381  terminal = terminal->get_next_terminal();
1382  }
1383 }
1384 
1385 #define ESC '\\'
1386 
1387 static char *pattern2str(GB_CSTR p) {
1388  char *s = GB_give_buffer(strlen(p)*2);
1389  char *s1 = s;
1390  GB_CSTR p1 = p;
1391 
1392  while (1) {
1393  char c = *p1++;
1394 
1395  if (!c) {
1396  break;
1397  }
1398  else if (c==ESC) {
1399  *s1++ = ESC;
1400  *s1++ = ESC;
1401  }
1402  else if (c=='\n') {
1403  *s1++ = ESC;
1404  *s1++ = 'n';
1405  }
1406  else {
1407  *s1++ = c;
1408  }
1409  }
1410 
1411  *s1 = 0;
1412  return ARB_strdup(s);
1413 }
1414 
1415 static void str2pattern(char *s) { // works on string
1416  char *a = s;
1417  char *n = s;
1418 
1419  while (1) {
1420  char c = *a++;
1421 
1422  if (c==ESC) {
1423  c = *a++;
1424  if (c==ESC) {
1425  *n++ = ESC;
1426  }
1427  else if (c=='n') {
1428  *n++ = '\n';
1429  }
1430  else { // should not occur
1431  *n++ = ESC;
1432  *n++ = c;
1433  }
1434  }
1435  else {
1436  *n++ = c;
1437  if (!c) {
1438  break;
1439  }
1440  }
1441  }
1442 }
1443 
1444 #undef ESC
1445 
1447  GB_ERROR error = NULp;
1448  AW_root *root = ED4_ROOT->aw_root;
1449  char *filename = root->awar(ED4_SEARCH_SAVE_BASE"/file_name")->read_string();
1450 
1451  {
1452  FILE *in = fopen(filename, "rt");
1453  if (in) {
1454  fclose(in);
1455 
1456  char *question = GBS_global_string_copy("'%s' already exists", filename);
1457  if (aw_question("overwrite_search_params", question, "Overwrite,Cancel") != 0) {
1458  error = "Wont overwrite existing file";
1459  }
1460  }
1461  }
1462 
1463  if (!error) {
1464  FILE *out = fopen(filename, "wt");
1465 
1466  if (!out) {
1467  error = GBS_global_string("Can't write file '%s' (%s)", filename, strerror(errno));
1468  }
1469  else {
1470  SearchSettings *s = settings[type];
1471 
1472  char *fpat = pattern2str(s->get_pattern());
1473 
1474  fprintf(out,
1475  "pattern=%s\n"
1476  "minmis=%i\n"
1477  "maxmis=%i\n"
1478  "case=%i\n"
1479  "tu=%i\n"
1480  "patgaps=%i\n"
1481  "seqgaps=%i\n"
1482  "openfolded=%i\n"
1483  "autojump=%i\n"
1484  "reverse=%i\n"
1485  "complement=%i\n"
1486  "exact=%i\n",
1487  fpat,
1488  s->get_min_mismatches(),
1489  s->get_max_mismatches(),
1490  s->get_case_sensitive(),
1491  s->get_tu(),
1492  s->get_pat_gaps(),
1493  s->get_seq_gaps(),
1494  s->get_open_folded(),
1495  s->get_autoJump(),
1496  s->get_reverse(),
1497  s->get_complement(),
1498  s->get_exact());
1499 
1500  free(fpat);
1501  fclose(out);
1502  }
1503  }
1504 
1505  if (error) aw_message(error);
1506  else AW_POPDOWN(aw);
1507 
1508  free(filename);
1509 }
1510 
1512  GB_CSTR error = NULp;
1513  AW_root *root = ED4_ROOT->aw_root;
1514  char *filename = root->awar(ED4_SEARCH_SAVE_BASE"/file_name")->read_string();
1515  FILE *in = fopen(filename, "rt");
1516 
1517  if (!in) {
1518  error = GBS_global_string("File '%s' not found", filename);
1519  }
1520  else {
1521  SearchAwarList *al = &awar_list[type];
1522 
1523  while (1) {
1524  const int BUFFERSIZE = 10000;
1525  char buffer[BUFFERSIZE];
1526  if (!fgets(buffer, BUFFERSIZE, in)) break;
1527 
1528  char *content = strchr(buffer, '=');
1529  if (!content) {
1530  aw_message(GBS_global_string("Format error in '%s' - ignored!", filename));
1531  }
1532  else {
1533  *content++ = 0;
1534 
1535  if (strcmp(buffer, "pattern")==0) {
1536  str2pattern(content);
1537  root->awar(al->pattern)->write_string(content);
1538  }
1539  else {
1540  int value = atoi(content);
1541 
1542  if (strcmp(buffer, "minmis")==0) root->awar(al->min_mismatches)->write_int(value);
1543  else if (strcmp(buffer, "maxmis")==0) root->awar(al->max_mismatches)->write_int(value);
1544  else if (strcmp(buffer, "case")==0) root->awar(al->case_sensitive)->write_int(value);
1545  else if (strcmp(buffer, "tu")==0) root->awar(al->tu)->write_int(value);
1546  else if (strcmp(buffer, "patgaps")==0) root->awar(al->pat_gaps)->write_int(value);
1547  else if (strcmp(buffer, "seqgaps")==0) root->awar(al->seq_gaps)->write_int(value);
1548  else if (strcmp(buffer, "openfolded")==0) root->awar(al->openFolded)->write_int(value);
1549  else if (strcmp(buffer, "autojump")==0) root->awar(al->autoJump)->write_int(value);
1550  else if (strcmp(buffer, "reverse")==0) root->awar(al->reverse)->write_int(value);
1551  else if (strcmp(buffer, "complement")==0) root->awar(al->complement)->write_int(value);
1552  else if (strcmp(buffer, "exact")==0) root->awar(al->exact)->write_int(value);
1553  else {
1554  aw_message(GBS_global_string("Unknown tag '%s' in '%s' - ignored!", buffer, filename));
1555  }
1556  }
1557  }
1558  }
1559 
1560  fclose(in);
1561  }
1562 
1563  if (error) aw_message(error);
1564  else AW_POPDOWN(aw);
1565 
1566  free(filename);
1567 }
1568 
1569 static void aws_init_localized(AW_root *root, AW_window_simple *aws, GB_CSTR id_format, GB_CSTR title_format, GB_CSTR typeId, int winNum) {
1570  char *window_title = GBS_global_string_copy(title_format, typeId);
1571  char *window_id_src = GBS_global_string_copy(id_format, typeId, winNum);
1572  char *window_id = GBS_string_2_key(window_id_src);
1573 
1574  aws->init(root, window_id, window_title);
1575 
1576  free(window_id);
1577  free(window_id_src);
1578  free(window_title);
1579 }
1580 
1583  int winNum;
1584 
1586  : type(type_),
1587  winNum(winNum_)
1588  {}
1589 };
1590 
1591 static AW_window *loadsave_search_parameters(AW_root *root, const LoadSaveSearchParam *param, bool load) {
1592  AW_window_simple *aws = new AW_window_simple;
1593 
1594  if (load) {
1595  aws_init_localized(root, aws, "load_%s_search_para_%i", "Load %s Search Parameters", ED4_SearchPositionTypeId[param->type], param->winNum);
1596  }
1597  else {
1598  aws_init_localized(root, aws, "save_%s_search_para_%i", "Save %s Search Parameters", ED4_SearchPositionTypeId[param->type], param->winNum);
1599  }
1600 
1601  aws->load_xfig("edit4/save_search.fig");
1602 
1603  aws->at("close");
1604  aws->callback(AW_POPDOWN);
1605  aws->create_button("CLOSE", "CLOSE", "C");
1606 
1607  aws->callback(makeHelpCallback("e4_search.hlp"));
1608  aws->at("help");
1609  aws->create_button("HELP", "HELP", "H");
1610 
1612 
1613  aws->at("cancel");
1614  aws->callback(AW_POPDOWN);
1615  aws->create_button("CANCEL", "CANCEL", "C");
1616 
1617  aws->at("save");
1618  if (load) {
1619  aws->callback(makeWindowCallback(load_search_paras_from_file, param->type));
1620  aws->create_button("LOAD", "LOAD", "L");
1621  }
1622  else {
1623  aws->callback(makeWindowCallback(save_search_paras_to_file, param->type));
1624  aws->create_button("SAVE", "SAVE", "S");
1625  }
1626 
1627  return aws;
1628 }
1629 
1631  SearchAwarList *awarList = &awar_list[search_type];
1632 
1633  cdef.add(awarList->show, "show");
1634  cdef.add(awarList->openFolded, "openFolded");
1635  cdef.add(awarList->autoJump, "autoJump");
1636  cdef.add(awarList->pattern, "pattern");
1637  cdef.add(awarList->min_mismatches, "min_mismatches");
1638  cdef.add(awarList->max_mismatches, "max_mismatches");
1639  cdef.add(awarList->seq_gaps, "seq_gaps");
1640  cdef.add(awarList->pat_gaps, "pat_gaps");
1641  cdef.add(awarList->tu, "tu");
1642  cdef.add(awarList->case_sensitive, "case_sensitive");
1643  cdef.add(awarList->reverse, "reverse");
1644  cdef.add(awarList->complement, "complement");
1645  cdef.add(awarList->exact, "exact");
1646 }
1647 
1648 struct search_windows : public Noncopyable {
1649  AW_window_simple *windows[SEARCH_PATTERNS];
1650  search_windows() { for (int i = 0; i<SEARCH_PATTERNS; ++i) windows[i] = NULp; }
1651 };
1652 
1653 typedef std::map<ED4_window*, SmartPtr<search_windows> > search_window_map;
1654 
1656  ED4_WinContext uses(aww);
1657  ED4_window *ed4w = uses.get_ed4w();
1658 
1659  static search_window_map swm;
1660  { // create search windows pointer array for current ed4w
1661  search_window_map::iterator sw4win = swm.find(ed4w);
1662  if (sw4win == swm.end()) swm[ed4w] = new search_windows;
1663  }
1664 
1665  SmartPtr<search_windows> sw = swm[ed4w];
1666  AW_window_simple *aws = sw->windows[type];
1667  if (!aws) {
1668  SearchAwarList *awarList = &awar_list[type];
1669 
1670  sw->windows[type] = aws = new AW_window_simple;
1671 
1672  aws_init_localized(aww->get_root(), aws, "%s_search_%i", "%s Search", ED4_SearchPositionTypeId[type], ed4w->id);
1673  aws->load_xfig("edit4/search.fig");
1674 
1675  aws->at("close");
1676  aws->callback(AW_POPDOWN);
1677  aws->create_button("CLOSE", "CLOSE", "C");
1678 
1679  aws->at("help");
1680  aws->callback(makeHelpCallback("e4_search.hlp"));
1681  aws->create_button("HELP", "HELP", "H");
1682 
1683  LoadSaveSearchParam *param = new LoadSaveSearchParam(type, ed4w->id); // bound to callbacks (dont free)
1684 
1685  aws->at("load");
1686  aws->callback(makeCreateWindowCallback(loadsave_search_parameters, param, true));
1687  aws->create_button("LOAD", "LOAD", "L");
1688 
1689  aws->at("save");
1690  aws->callback(makeCreateWindowCallback(loadsave_search_parameters, param, false));
1691  aws->create_button("SAVE", "SAVE", "S");
1692 
1693  aws->at("next");
1694  aws->callback(makeWindowCallback(ED4_search_cb, ED4_encodeSearchDescriptor(+1, type), ed4w));
1695  aws->create_button("SEARCH_NEXT", "#edit/next.xpm", "N");
1696 
1697  aws->at("previous");
1698  aws->callback(makeWindowCallback(ED4_search_cb, ED4_encodeSearchDescriptor(-1, type), ed4w));
1699  aws->create_button("SEARCH_LAST", "#edit/last.xpm", "L");
1700 
1701  aws->at("mark");
1702  aws->callback(makeWindowCallback(ED4_mark_matching_species, type));
1703  aws->create_autosize_button("MARK_SPECIES", "Mark species with matches", "M");
1704 
1705  aws->at("show");
1706  aws->create_toggle(awarList->show);
1707 
1708  aws->at("open");
1709  aws->create_toggle(awarList->openFolded);
1710 
1711  aws->at("jump");
1712  aws->create_toggle(awarList->autoJump);
1713 
1714  aws->at("pattern");
1715  aws->create_text_field(awarList->pattern, 28, 17);
1716 
1717  aws->at("minmis");
1718  aws->create_toggle_field(awarList->min_mismatches, 1);
1719  aws->insert_default_toggle("0", "0", 0);
1720  aws->insert_toggle("1", "1", 1);
1721  aws->insert_toggle("2", "2", 2);
1722  aws->update_toggle_field();
1723 
1724  aws->at("maxmis");
1725  aws->create_toggle_field(awarList->max_mismatches, 1);
1726  aws->insert_default_toggle("0", "0", 0);
1727  aws->insert_toggle("1", "1", 1);
1728  aws->insert_toggle("2", "2", 2);
1729  aws->insert_toggle("3", "3", 3);
1730  aws->insert_toggle("4", "4", 4);
1731  aws->insert_toggle("5", "5", 5);
1732  aws->update_toggle_field();
1733 
1734  aws->at("seq_gaps");
1735  aws->create_toggle(awarList->seq_gaps);
1736  aws->at("pat_gaps");
1737  aws->create_toggle(awarList->pat_gaps);
1738  aws->at("tu");
1739  aws->create_toggle(awarList->tu);
1740  aws->at("case");
1741  aws->create_toggle(awarList->case_sensitive);
1742  aws->at("reverse");
1743  aws->create_toggle(awarList->reverse);
1744  aws->at("complement");
1745  aws->create_toggle(awarList->complement);
1746  aws->at("exact");
1747  aws->create_toggle(awarList->exact);
1748 
1749  aws->at("config");
1750  AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "search", makeConfigSetupCallback(setup_search_config, type));
1751  }
1752 
1753  aws->activate();
1754 }
1755 
1756 
1757 
static void set_mismatches(int minMis, int maxMis)
Definition: ED4_search.cxx:150
static void str2pattern(char *s)
const char * GB_ERROR
Definition: arb_core.h:25
static char * appendComment(const char *s1, int l1, const char *s2)
Definition: ED4_search.cxx:334
string result
GB_TYPES type
ED4_SEARCH_CASE get_case_sensitive() const
Definition: ED4_search.cxx:109
static void set_report(reportMatch r, int *u2r)
Definition: ED4_search.cxx:149
ED4_SEARCH_GAPS get_pat_gaps() const
Definition: ED4_search.cxx:111
void add(const char *awar_name, const char *config_name)
GB_CSTR GB_path_in_arbprop(const char *relative_path)
Definition: adsocket.cxx:1109
ED4_SearchPosition * get_next() const
Definition: ed4_search.hxx:87
ED4_SEARCH_GAPS get_seq_gaps() const
Definition: ED4_search.cxx:112
std::map< ED4_window *, SmartPtr< search_windows > > search_window_map
ED4_terminal * get_first_terminal(int start_index=0) const
static void setNewSearch(ED4_SearchPositionType type)
static char * pattern2str(GB_CSTR p)
AW_window_simple * windows[SEARCH_PATTERNS]
#define IS_NUCLEOTIDE()
Definition: ed4_tools.hxx:16
ED4_group_manager * is_in_folded_group() const
Definition: ED4_base.cxx:20
int get_end_pos() const
Definition: ed4_search.hxx:89
ED4_SearchResults & results() const
Definition: ed4_class.hxx:2005
char * GBT_complementNucSequence(const char *s, int len, char T_or_U)
Definition: adRevCompl.cxx:78
GB_CSTR get_comment() const
Definition: ED4_search.cxx:855
const char * tu
Definition: ED4_search.cxx:46
ED4_SearchPosition * get_first_at(ED4_SearchPositionType type, int start, int end) const
Definition: ED4_search.cxx:989
ED4_SEARCH_TU
Definition: ed4_search.hxx:20
const char * case_sensitive
Definition: ED4_search.cxx:46
void AW_create_standard_fileselection(AW_window *aws, const char *awar_prefix)
Definition: aw_file.hxx:30
void ED4_create_search_awars(AW_root *root)
Definition: ED4_search.cxx:735
void ED4_search_cb(UNFIXED, int searchDescriptor, ED4_window *ed4w)
int get_open_folded() const
Definition: ED4_search.cxx:113
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
char * GBT_reverseNucSequence(const char *s, int len)
Definition: adRevCompl.cxx:66
void AWT_insert_config_manager(AW_window *aww, AW_default default_file_, const char *id, const StoreConfigCallback &store_cb, const RestoreConfigCallback &load_or_reset_cb, const char *macro_id, const AWT_predefined_config *predef)
long read_int() const
Definition: AW_awar.cxx:187
static ED4_SearchResults * reportToResult
Definition: ED4_search.cxx:916
SearchSettings(SearchAwarList *awarList)
Definition: ED4_search.cxx:103
const int * getMismatches() const
Definition: ed4_search.hxx:93
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
ED4_root * ED4_ROOT
Definition: ED4_main.cxx:48
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
char * GBS_string_2_key(const char *str)
Definition: adstring.cxx:52
ED4_terminal * owner_of_cursor
Definition: ed4_class.hxx:649
static void load_search_paras_from_file(AW_window *aw, ED4_SearchPositionType type)
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
FILE * seq
Definition: rns.c:46
#define e4_assert(bed)
Definition: ed4_class.hxx:11
GBDATA * GLOBAL_gb_main
Definition: DI_main.cxx:27
int get_autoJump() const
Definition: ED4_search.cxx:114
struct Unfixed_cb_parameter * UNFIXED
Definition: cb_base.h:15
static HelixNrInfo * start
static bool initialized
Definition: AW_advice.cxx:36
void ED4_popup_search_window(AW_window *aww, ED4_SearchPositionType type)
const char * max_mismatches
Definition: ED4_search.cxx:46
static int resultsAreShown(ED4_SearchPositionType type)
Definition: ED4_search.cxx:613
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
int containsPos(int pos) const
Definition: ed4_search.hxx:95
ED4_SearchPosition * get_first() const
Definition: ed4_search.hxx:137
static AW_window * loadsave_search_parameters(AW_root *root, const LoadSaveSearchParam *param, bool load)
ED4_SearchPosition * insert(ED4_SearchPosition *toAdd)
Definition: ED4_search.cxx:792
ED4_SEARCH_GAPS
Definition: ed4_search.hxx:25
static void searchParamsChanged(AW_root *root, ED4_SearchPositionType type, search_params_changed_action action)
Definition: ED4_search.cxx:633
static SearchSettings * settings[SEARCH_PATTERNS]
Definition: ED4_search.cxx:628
ED4_terminal * get_last_terminal(int start_index=-1) const
Generic smart pointer.
Definition: smartptr.h:149
ED4_SearchPosition(int sp, int ep, ED4_SearchPositionType wf, GB_CSTR found_comment, int mismatches[MAX_MISMATCHES])
Definition: ED4_search.cxx:774
GB_BUFFER GB_give_buffer(size_t size)
Definition: arbdb.cxx:304
#define ED4_AWAR_SEARCH_RESULT_CHANGED
Definition: ed4_extern.hxx:75
ED4_SearchPositionType get_whatsFound() const
Definition: ed4_search.hxx:90
static void save_search_paras_to_file(AW_window *aw, ED4_SearchPositionType type)
ED4_window * first_window
Definition: ed4_class.hxx:1427
ED4_SearchPosition * get_first_starting_after(ED4_SearchPositionType type, int pos, int mustBeShown) const
ED4_terminal * get_next_terminal()
Definition: ED4_base.cxx:452
void touch()
Definition: AW_awar.cxx:210
const char * show
Definition: ED4_search.cxx:46
SearchTreeNode * insert_unified_pattern(GB_CSTR pattern, GB_CSTR pattern_comment)
Definition: ED4_search.cxx:196
static void error(const char *msg)
Definition: mkptypes.cxx:96
int get_complement() const
Definition: ED4_search.cxx:116
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
const char * reverse
Definition: ED4_search.cxx:46
char * buildColorString(const ED4_sequence_terminal *seq_terminal, int start, int end)
ED4_root_group_manager * root_group_man
Definition: ed4_class.hxx:1431
void addSearchPosition(ED4_SearchPosition *pos)
Definition: ED4_search.cxx:926
ED4_SEARCH_TU get_tu() const
Definition: ED4_search.cxx:110
ED4_SEARCH_CASE
Definition: ed4_search.hxx:15
int get_start_pos() const
Definition: ed4_search.hxx:88
#define cmp(h1, h2)
Definition: admap.cxx:50
GB_CSTR get_pattern() const
Definition: ED4_search.cxx:106
GB_ERROR ED4_repeat_last_search(ED4_window *ed4w)
const char * seq_gaps
Definition: ED4_search.cxx:46
const char * openFolded
Definition: ED4_search.cxx:46
static int last_searchDescriptor
char * read_string() const
Definition: AW_awar.cxx:201
int get_max_mismatches() const
Definition: ED4_search.cxx:108
void search(const ED4_sequence_terminal *seq_terminal)
Definition: ED4_search.cxx:942
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
static void set_start_offset(int off)
Definition: ED4_search.cxx:148
const char * pattern
Definition: ED4_search.cxx:46
SearchTree(const SearchSettings *s)
Definition: ED4_search.cxx:346
GB_alignment_type alignment_type
Definition: ed4_class.hxx:1441
bool setCursorTo(ED4_cursor *cursor, int seq_pos, bool unfoldGroups, ED4_CursorJumpType jump_type)
Definition: ed4_class.hxx:2198
ED4_SearchPositionType type
#define MAX_MISMATCHES
Definition: ed4_search.hxx:32
static ED4_SearchPositionType reportType
Definition: ED4_search.cxx:917
ED4_window * get_ed4w() const
Definition: ed4_class.hxx:1395
int aw_question(const char *unique_id, const char *question, const char *buttons, bool sameSizeButtons, const char *helpfile)
Definition: AW_question.cxx:26
ED4_cursor & current_cursor()
Definition: ed4_class.hxx:1405
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:580
TYPE * ARB_calloc(size_t nelem)
Definition: arb_mem.h:81
static void aws_init_localized(AW_root *root, AW_window_simple *aws, GB_CSTR id_format, GB_CSTR title_format, GB_CSTR typeId, int winNum)
void GB_write_flag(GBDATA *gbd, long flag)
Definition: arbdb.cxx:2737
int get_reverse() const
Definition: ED4_search.cxx:115
ED4_SearchPosition * get_shown_at(int pos) const
const char * autoJump
Definition: ED4_search.cxx:46
const size_t BUFFERSIZE
int ED4_encodeSearchDescriptor(int direction, ED4_SearchPositionType pattern)
Definition: ed4_search.hxx:50
#define AWAR_LIST(t)
Definition: ED4_search.cxx:586
void findMatches(int off, GB_CSTR seq, int len, int mismatches, int mismatch_list[MAX_MISMATCHES])
Definition: ED4_search.cxx:237
ED4_window * current_ed4w()
Definition: ed4_class.hxx:1403
static void setup_search_config(AWT_config_definition &cdef, ED4_SearchPositionType search_type)
AW_root * aw_root
Definition: ed4_class.hxx:1424
#define IS_AMINO()
Definition: ed4_tools.hxx:19
#define ESC
static void ED4_mark_matching_species(AW_window *, ED4_SearchPositionType pattern)
#define abs(x)
Definition: f2c.h:151
bool ED4_is_gap_character(char chr)
void aw_message(const char *msg)
Definition: AW_status.cxx:932
ED4_SearchPosition * get_last_starting_before(ED4_SearchPositionType type, int pos, int mustBeShown) const
static int pattern[maxsites+1]
AW_root * get_root()
Definition: aw_window.hxx:348
AW_window_simple * win
#define NULp
Definition: cxxforward.h:97
#define ED4_SEARCH_SAVE_BASE
Definition: ed4_awars.hxx:15
void request_refresh_for_sequence_terminals()
Definition: ED4_root.cxx:106
#define INSERT_ROOT_PATTERN(tok, com)
const char * exact
Definition: ED4_search.cxx:46
static void splitTokComment(char **tok, char **commentP)
Definition: ED4_search.cxx:320
GB_ERROR write_string(const char *aw_string)
int is_sequence_terminal() const
Definition: ed4_class.hxx:1088
static void reportSearchPosition(int start, int end, GB_CSTR comment, int mismatches[MAX_MISMATCHES])
Definition: ED4_search.cxx:919
int get_min_mismatches() const
Definition: ED4_search.cxx:107
const char * pat_gaps
Definition: ED4_search.cxx:46
char * resolve_pointer_to_string_copy(int *str_len=NULp) const FINAL_OVERRIDE
int get_sequence_pos() const
Definition: ED4_cursor.cxx:393
static char * shortenString(char *s)
Definition: ED4_search.cxx:307
GB_transaction ta(gb_var)
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
void(* reportMatch)(int start, int end, GB_CSTR comment, int mismatches[MAX_MISMATCHES])
Definition: ED4_search.cxx:123
ED4_SearchPositionType
Definition: ed4_search.hxx:34
search_params_changed_action
Definition: ED4_search.cxx:617
ED4_terminal * get_prev_terminal()
Definition: ED4_base.cxx:465
void update(SearchAwarList *awarList)
Definition: ED4_search.cxx:77
const char * complement
Definition: ED4_search.cxx:46
int get_exact() const
Definition: ED4_search.cxx:117
ED4_manager * get_parent(ED4_level lev) const
Definition: ed4_class.hxx:1823
#define min(a, b)
Definition: f2c.h:153
ED4_SearchPosition * remove(ED4_SearchPositionType typeToRemove)
Definition: ED4_search.cxx:814
const char * GB_CSTR
Definition: arbdb_base.h:25
ED4_SearchPosition * get_next_at(int pos) const
Definition: ED4_search.cxx:864
#define AW_ROOT_DEFAULT
Definition: aw_base.hxx:106
LoadSaveSearchParam(ED4_SearchPositionType type_, int winNum_)
GB_ERROR write_int(long aw_int)
const char * ED4_SearchPositionTypeId[SEARCH_PATTERNS+1]
Definition: ED4_search.cxx:35
int get_shortestPattern() const
Definition: ED4_search.cxx:302
SearchTreeNode(GB_CSTR pattern, GB_CSTR comment)
Definition: ED4_search.cxx:167
void findMatches(const char *seq, int len, reportMatch report)
Definition: ED4_search.cxx:555
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
void decodeSearchDescriptor(int descriptor, int *direction, ED4_SearchPositionType *pattern)
NOT4PERL GB_ERROR GBT_determine_T_or_U(GB_alignment_type alignment_type, char *T_or_U, const char *supposed_target)
Definition: adRevCompl.cxx:90
static struct SearchAwarList awar_list[SEARCH_PATTERNS]
Definition: ED4_search.cxx:601
const char * min_mismatches
Definition: ED4_search.cxx:46
#define max(a, b)
Definition: f2c.h:154
GB_write_int const char s
Definition: AW_awar.cxx:156