source: tags/arb-6.0/ARB_GDE/GDE_event.cxx

Last change on this file was 12267, checked in by westram, 10 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
Line 
1#include "GDE_extglob.h"
2#include "GDE_awars.h"
3
4#include <awt_filter.hxx>
5#include <aw_window.hxx>
6#include <aw_root.hxx>
7#include <aw_question.hxx>
8#include <aw_awar.hxx>
9#include <aw_msg.hxx>
10#include <aw_file.hxx>
11#include <arb_progress.h>
12#include <AP_filter.hxx>
13
14#include <set>
15#include <string>
16
17#include <unistd.h>
18
19using namespace std;
20
21#define DEFAULT_COLOR 8
22extern adfiltercbstruct *agde_filter;
23
24/*
25  ReplaceArgs():
26  Replace all command line arguments with the appropriate values
27  stored for the chosen menu item.
28
29  Copyright (c) 1989-1990, University of Illinois board of trustees.  All
30  rights reserved.  Written by Steven Smith at the Center for Prokaryote Genome
31  Analysis.  Design and implementation guidance by Dr. Gary Olsen and Dr.
32  Carl Woese.
33
34  Copyright (c) 1990,1991,1992 Steven Smith at the Harvard Genome Laboratory.
35  All rights reserved.
36
37*/
38
39
40static char *ReplaceArgs(AW_root *awr, char *Action, GmenuItem *gmenuitem, int number)
41{
42    /*
43     *  The basic idea is to replace all of the symbols in the method
44     *  string with the values picked in the dialog box.  The method
45     *  is the general command line structure.  All arguments have two
46     *  parts : a label and a value.  Values are the
47     *  associated arguments that some flags require.  All symbols that
48     *  require argvalue replacement should have a '$' infront of the symbol
49     *  name in the itemmethod definition.
50     *
51     *  If '$symbol' is prefixed by '!' ARB_GDE does a label replacement, i.e. insert
52     *  the value visible in GUI. Only works for argchoice arguments!
53     *  This is intended for informational use (e.g. to write used settings
54     *  into the comment of a generated tree).
55     *
56     *  An example command line replacement would be:
57     *
58     *       itemmethod=>        "lpr -P $arg1 $arg2"
59     *
60     *       arglabel arg1=>     "To printer?"
61     *       argvalue arg1=>     "lw"
62     *
63     *       arglabel arg2=>     "File name?"
64     *       argvalue arg2=>     "foobar"
65     *
66     *   final command line:
67     *
68     *       lpr -P lw foobar
69     *
70     */
71
72    char       *textvalue  = 0;
73    const char *labelvalue = 0;
74
75    GmenuItemArg& currArg = gmenuitem->arg[number];
76
77    const char *symbol = currArg.symbol;
78    int         type   = currArg.type;
79
80    if (type == SLIDER) {
81        char *awarname = GDE_makeawarname(gmenuitem, number);
82        textvalue      = awr->awar(awarname)->read_as_string();
83        free(awarname);
84    }
85    else if (type == FILE_SELECTOR) {
86        char *awar_base = GDE_maketmpawarname(gmenuitem, number);
87        textvalue  = AW_get_selected_fullname(awr, awar_base);
88        free(awar_base);
89    }
90    else if (type == CHOOSER ||
91             type == CHOICE_TREE ||
92             type == CHOICE_SAI ||
93             type == CHOICE_MENU ||
94             type == CHOICE_LIST ||
95             type == CHOICE_WEIGHTS ||
96             type == TEXTFIELD)
97    {
98        char *awarname = GDE_makeawarname(gmenuitem, number);
99        textvalue      = awr->awar(awarname)->read_string();
100
101        if (currArg.choice) {
102            for (int c = 0; c<currArg.numchoices && !labelvalue; ++c) {
103                GargChoice& choice = currArg.choice[c];
104                if (choice.method) {
105                    if (strcmp(choice.method, textvalue) == 0) {
106                        labelvalue = choice.label;
107                    }
108                }
109            }
110        }
111    }
112
113    if (textvalue == NULL)  textvalue=(char *)calloc(1, sizeof(char));
114    if (symbol == NULL)     symbol="";
115
116    set<string>warned_about;
117    int conversion_warning = 0;
118   
119    for (int i, j = 0; (i=Find2(Action+j, symbol)) != -1;) {
120        i += j;
121        ++j;
122        if (i>0 && Action[i-1] == '$') {
123            const char *replaceBy = textvalue;
124            int         skip      = 1;
125
126            if (i>1 && Action[i-2] == '!') { // use label (if available)
127                if (labelvalue) {
128                    replaceBy = labelvalue;
129                    skip = 2; // skip '!'
130                }
131                else {
132                    aw_message(GBS_global_string("[ARB_GDE]: Cannot access label of '%s'\n", symbol));
133                    return NULL; // @@@ ignores ressources (should only occur during development)
134                }
135            }
136
137            int   repLen = strlen(replaceBy);
138            int   symLen = strlen(symbol);
139            int   newlen = strlen(Action)-skip-symLen+repLen+1;
140            char *temp   = (char *)calloc(newlen, 1);
141
142            strncat(temp, Action, i-skip);
143            strncat(temp, replaceBy, repLen);
144            strcat(temp, &(Action[i+symLen]));
145            freeset(Action, temp);
146        }
147        else {
148            if (warned_about.find(symbol) == warned_about.end()) {
149                fprintf(stderr,
150                        "old arb version converted '%s' to '%s' (now only '$%s' is converted)\n",
151                        symbol, textvalue, symbol);
152                conversion_warning++;
153                warned_about.insert(symbol);
154            }
155        }
156    }
157
158    if (conversion_warning) {
159        fprintf(stderr,
160                "Conversion warnings occurred in Action:\n'%s'\n",
161                Action);
162    }
163
164    free(textvalue);
165    return (Action);
166}
167
168static long LMAX(long a, long b)
169{
170    if (a>b) return a;
171    return b;
172}
173
174static void GDE_free(void **p) {
175    freenull(*p);
176}
177
178static char *ReplaceFile(char *Action, GfileFormat file)
179{
180    char *symbol, *method, *temp;
181    int i, newlen;
182    symbol = file.symbol;
183    method = file.name;
184
185    for (; (i=Find2(Action, symbol)) != -1;)
186    {
187        newlen = strlen(Action)-strlen(symbol) + strlen(method)+1;
188        temp = (char *)calloc(newlen, 1);
189        strncat(temp, Action, i);
190        strncat(temp, method, strlen(method));
191        strcat(temp, &(Action[i+strlen(symbol)]));
192        freeset(Action, temp);
193    }
194    return (Action);
195}
196
197static char *ReplaceString(char *Action, const char *old, const char *news)
198{
199    const char *symbol;
200    const char *method;
201    char *temp;
202    int i, newlen;
203
204    symbol = old;
205    method = news;
206
207    for (; (i=Find2(Action, symbol)) != -1;)
208    {
209        newlen = strlen(Action)-strlen(symbol) + strlen(method)+1;
210        temp = (char *)calloc(newlen, 1);
211        strncat(temp, Action, i);
212        strncat(temp, method, strlen(method));
213        strcat(temp, &(Action[i+strlen(symbol)]));
214        freeset(Action, temp);
215    }
216    return (Action);
217}
218
219static void GDE_freesequ(NA_Sequence *sequ) {
220    if (sequ) {
221        GDE_free((void**)&sequ->comments);
222        GDE_free((void**)&sequ->cmask);
223        GDE_free((void**)&sequ->baggage);
224        GDE_free((void**)&sequ->sequence);
225    }
226}
227
228static void GDE_freeali(NA_Alignment *dataset) {
229    if (dataset) {
230        GDE_free((void**)&dataset->id);
231        GDE_free((void**)&dataset->description);
232        GDE_free((void**)&dataset->authority);
233        GDE_free((void**)&dataset->cmask);
234        GDE_free((void**)&dataset->selection_mask);
235        GDE_free((void**)&dataset->alignment_name);
236
237        for (unsigned long i=0; i<dataset->numelements; i++) {
238            GDE_freesequ(dataset->element+i);
239        }
240    }
241}
242
243static void GDE_export(NA_Alignment *dataset, const char *align, long oldnumelements) {
244    GBDATA   *gb_main = db_access.gb_main;
245    GB_ERROR  error   = GB_begin_transaction(gb_main);
246
247    long  maxalignlen  = GBT_get_alignment_len(gb_main, align);
248    char *defaultAlign = NULL;
249
250    if (maxalignlen <= 0 && !error) {
251        GB_clear_error(); // clear "alignment not found" error
252
253        defaultAlign             = GBT_get_default_alignment(gb_main);
254        if (!defaultAlign) error = GB_await_error();
255        else {
256            align       = defaultAlign;
257            maxalignlen = GBT_get_alignment_len(gb_main, align);
258        }
259    }
260
261    long lotyp = 0;
262    if (!error) {
263        GB_alignment_type at = GBT_get_alignment_type(gb_main, align);
264
265        switch (at) {
266            case GB_AT_DNA:     lotyp = DNA;     break;
267            case GB_AT_RNA:     lotyp = RNA;     break;
268            case GB_AT_AA:      lotyp = PROTEIN; break;
269            case GB_AT_UNKNOWN: lotyp = DNA;     break;
270        }
271    }
272
273    unsigned long i;
274
275    AW_repeated_question overwrite_question;
276    AW_repeated_question checksum_change_question;
277   
278    arb_progress progress("importing", dataset->numelements-oldnumelements+1); // +1 avoids zero-progress
279    for (i = oldnumelements; !error && i < dataset->numelements; i++) {
280        NA_Sequence *sequ = dataset->element+i;
281        int seqtyp, issame = 0;
282
283        seqtyp = sequ->elementtype;
284        if ((seqtyp == lotyp) || ((seqtyp == DNA) && (lotyp == RNA)) || ((seqtyp == RNA) && (lotyp == DNA))) {
285            issame = 1;
286        }
287        else {
288            aw_message(GBS_global_string("Warning: sequence type of species '%s' changed", sequ->short_name));
289        }
290
291        if (sequ->tmatrix) {
292            for (long j = 0; j < sequ->seqlen; j++) {
293                sequ->sequence[j] = (char)sequ->tmatrix[sequ->sequence[j]];
294            }
295            sequ->sequence[sequ->seqlen] = 0;
296        }
297
298        char *savename = GBS_string_2_key(sequ->short_name);
299
300        sequ->gb_species = 0;
301
302        const char *new_seq = (const char *)sequ->sequence;
303        gde_assert(new_seq[sequ->seqlen] == 0);
304        gde_assert((int)strlen(new_seq) == sequ->seqlen);
305
306        if (!issame) {          // save as extended
307            GBDATA *gb_extended = GBT_find_or_create_SAI(db_access.gb_main, savename);
308
309            if (!gb_extended) error = GB_await_error();
310            else {
311                sequ->gb_species = gb_extended;
312                GBDATA *gb_data  = GBT_add_data(gb_extended, align, "data", GB_STRING);
313
314                if (!gb_data) error = GB_await_error();
315                else error          = GBT_write_sequence(gb_data, align, maxalignlen, new_seq);
316            }
317        }
318        else {                  // save as sequence
319            GBDATA *gb_species_data     = GBT_get_species_data(db_access.gb_main);
320            if (!gb_species_data) error = GB_await_error();
321            else {
322                GBDATA *gb_species = GBT_find_species_rel_species_data(gb_species_data, savename);
323
324                GB_push_my_security(db_access.gb_main);
325
326                if (gb_species) {   // new element that already exists !!!!
327                    const char *question =
328                        GBS_global_string("You are (re-)importing a species '%s'.\n"
329                                          "That species already exists in your database!\n"
330                                          "\n"
331                                          "Possible actions:\n"
332                                          "\n"
333                                          "       - overwrite existing species (all fields)\n"
334                                          "       - overwrite the sequence (does not change other fields)\n"
335                                          "       - skip import of the species\n"
336                                          "\n"
337                                          "Note: After aligning it's recommended to choose 'overwrite sequence'.",
338                                          savename);
339
340
341                    enum ReplaceMode { REPLACE_SPEC = 0, REIMPORT_SEQ = 1, SKIP_IMPORT  = 2, }
342                    replace_mode = (ReplaceMode)overwrite_question.get_answer("GDE_overwrite", question, "Overwrite species,Overwrite sequence only,Skip entry", "all", false);
343
344                    switch (replace_mode) {
345                        case SKIP_IMPORT:
346                            gb_species = 0;
347                            break;
348                        case REPLACE_SPEC:
349                            error      = GB_delete(gb_species);
350                            gb_species = NULL;
351                            if (error) break;
352                            // fall-through
353                        case REIMPORT_SEQ:
354                            gb_species = GBT_find_or_create_species_rel_species_data(gb_species_data, savename);
355                            if (!gb_species) error = GB_await_error();
356                            break;
357                    }
358                }
359                else {
360                    gb_species = GBT_find_or_create_species_rel_species_data(gb_species_data, savename);
361                    if (!gb_species) error = GB_await_error();
362                }
363
364                if (gb_species) {
365                    gde_assert(!error);
366                    sequ->gb_species = gb_species;
367
368                    GBDATA *gb_data     = GBT_add_data(gb_species, align, "data", GB_STRING); // does only add if not already existing
369                    if (!gb_data) error = GB_await_error();
370                    else {
371                        GBDATA *gb_old_data   = GBT_read_sequence(gb_species, align);
372                        bool    writeSequence = true;
373                        if (gb_old_data) {          // we already have data -> compare checksums
374                            const char *old_seq      = GB_read_char_pntr(gb_old_data);
375                            long        old_checksum = GBS_checksum(old_seq, 1, "-.");
376                            long        new_checksum = GBS_checksum(new_seq, 1, "-.");
377
378                            if (old_checksum != new_checksum) {
379                                char *question = GBS_global_string_copy("Warning: Sequence checksum of '%s' has changed\n", savename);
380                                enum ChangeMode {
381                                    ACCEPT_CHANGE = 0,
382                                    REJECT_CHANGE = 1,
383                                } change_mode = (ChangeMode)checksum_change_question.get_answer("GDE_accept", question, "Accept change,Reject", "all", false);
384
385                                if (change_mode == REJECT_CHANGE) writeSequence = false;
386
387                                aw_message(GBS_global_string("Warning: Sequence checksum for '%s' has changed (%s)",
388                                                             savename, writeSequence ? "accepted" : "rejected"));
389                                free(question);
390                            }
391                        }
392                        if (writeSequence) {
393                            error = GBT_write_sequence(gb_data, align, maxalignlen, new_seq);
394                        }
395                    }
396                }
397                GB_pop_my_security(db_access.gb_main);
398            }
399        }
400        free(savename);
401        progress.inc_and_check_user_abort(error);
402    }
403
404    // colormasks
405    for (i = 0; !error && i < dataset->numelements; i++) {
406        NA_Sequence *sequ = &(dataset->element[i]);
407
408        if (sequ->cmask) {
409            maxalignlen     = LMAX(maxalignlen, sequ->seqlen);
410            char *resstring = (char *)calloc((unsigned int)maxalignlen + 1, sizeof(char));
411            char *dummy     = resstring;
412
413            for (long j = 0; j < maxalignlen - sequ->seqlen; j++) *resstring++ = DEFAULT_COLOR;
414            for (long k = 0; k < sequ->seqlen; k++)               *resstring++ = (char)sequ->cmask[i];
415            *resstring = '\0';
416
417            GBDATA *gb_ali     = GB_search(sequ->gb_species, align, GB_CREATE_CONTAINER);
418            if (!gb_ali) error = GB_await_error();
419            else {
420                GBDATA *gb_color     = GB_search(gb_ali, "colmask", GB_BYTES);
421                if (!gb_color) error = GB_await_error();
422                else    error        = GB_write_bytes(gb_color, dummy, maxalignlen);
423            }
424            free(dummy);
425        }
426    }
427
428    if (!error && dataset->cmask) {
429        maxalignlen     = LMAX(maxalignlen, dataset->cmask_len);
430        char *resstring = (char *)calloc((unsigned int)maxalignlen + 1, sizeof(char));
431        char *dummy     = resstring;
432        long  k;
433
434        for (k = 0; k < maxalignlen - dataset->cmask_len; k++) *resstring++ = DEFAULT_COLOR;
435        for (k = 0; k < dataset->cmask_len; k++)               *resstring++ = (char)dataset->cmask[k];
436        *resstring = '\0';
437
438        GBDATA *gb_extended     = GBT_find_or_create_SAI(db_access.gb_main, "COLMASK");
439        if (!gb_extended) error = GB_await_error();
440        else {
441            GBDATA *gb_color     = GBT_add_data(gb_extended, align, "colmask", GB_BYTES);
442            if (!gb_color) error = GB_await_error();
443            else    error        = GB_write_bytes(gb_color, dummy, maxalignlen);
444        }
445
446        free(dummy);
447    }
448
449    progress.done();
450
451    GB_end_transaction_show_error(db_access.gb_main, error, aw_message);
452    free(defaultAlign);
453}
454
455static char *preCreateTempfile(const char *name) {
456    // creates a tempfile and returns heapcopy of fullpath
457    // exits in case of error
458    char *fullname = GB_create_tempfile(name);
459
460    if (!fullname) aw_message(GBS_global_string("[ARB_GDE]: %s", GB_await_error()));
461    return fullname;
462}
463
464void GDE_startaction_cb(AW_window *aw, GmenuItem *gmenuitem, AW_CL /*cd*/) {
465    AW_root   *aw_root           = aw->get_root();
466    AP_filter *filter2           = awt_get_filter(agde_filter);
467    char      *filter_name       = 0;      // aw_root->awar(AWAR_GDE_FILTER_NAME)->read_string()
468    char      *alignment_name    = strdup("ali_unknown");
469    bool       marked            = (aw_root->awar(AWAR_GDE_SPECIES)->read_int() != 0);
470    long       cutoff_stop_codon = aw_root->awar(AWAR_GDE_CUTOFF_STOPCODON)->read_int();
471    GmenuItem *current_item      = gmenuitem;
472    int        stop              = 0;
473
474    GapCompression compress = static_cast<GapCompression>(aw_root->awar(AWAR_GDE_COMPRESSION)->read_int());
475    arb_progress   progress(current_item->label);
476
477    {
478        GB_ERROR error = awt_invalid_filter(filter2);
479        if (error) {
480            aw_message(error);
481            stop = 1;
482        }
483    }
484
485    if (!stop && current_item->numinputs>0) {
486        TypeInfo typeinfo = UNKNOWN_TYPEINFO;
487        {
488            for (int j=0; j<current_item->numinputs; j++) {
489                if (j == 0) { typeinfo = current_item->input[j].typeinfo; }
490                else if (current_item->input[j].typeinfo != typeinfo) {
491                    aw_message("'intyped' must be same for all inputs (config error in GDE menu file)");
492                    stop = 1;
493                }
494            }
495        }
496        gde_assert(typeinfo != UNKNOWN_TYPEINFO);
497
498        if (!stop) {
499            DataSet->gb_main = db_access.gb_main;
500            GB_begin_transaction(DataSet->gb_main);
501            freeset(DataSet->alignment_name, GBT_get_default_alignment(DataSet->gb_main));
502            freedup(alignment_name, DataSet->alignment_name);
503
504            progress.subtitle("reading database");
505            if (db_access.get_sequences) {
506                stop = ReadArbdb2(DataSet, filter2, compress, cutoff_stop_codon, typeinfo);
507            }
508            else {
509                stop = ReadArbdb(DataSet, marked, filter2, compress, cutoff_stop_codon, typeinfo);
510            }
511            GB_commit_transaction(DataSet->gb_main);
512        }
513
514        if (!stop && DataSet->numelements==0) {
515            aw_message("no sequences selected");
516            stop = 1;
517        }
518    }
519
520    if (!stop) {
521        int select_mode = (DataSet && (current_item->numinputs>0)) ? ALL : NONE;
522        int pid         = getpid();
523
524        static int fileindx = 0;
525        for (int j=0; j<current_item->numinputs; j++) {
526            GfileFormat& gfile = current_item->input[j];
527
528            char buffer[GBUFSIZ];
529            sprintf(buffer, "gde%d_%d", pid, fileindx++);
530            gfile.name = preCreateTempfile(buffer);
531
532            switch (gfile.format) {
533                case GENBANK: WriteGen    (DataSet, gfile.name, select_mode); break;
534                case NA_FLAT: WriteNA_Flat(DataSet, gfile.name, select_mode); break;
535                case GDE:     WriteGDE    (DataSet, gfile.name, select_mode); break;
536                default: break;
537            }
538        }
539
540        for (int j=0; j<current_item->numoutputs; j++) {
541            char buffer[GBUFSIZ];
542            sprintf(buffer, "gde%d_%d", pid, fileindx++);
543            current_item->output[j].name = preCreateTempfile(buffer);
544        }
545
546        // Create the command line for external the function call
547        char *Action = strdup(current_item->method);
548
549        while (1) {
550            char *oldAction = strdup(Action);
551
552            for (int j=0; j<current_item->numargs; j++) Action = ReplaceArgs(aw_root, Action, gmenuitem, j);
553            bool changed = strcmp(oldAction, Action) != 0;
554            free(oldAction);
555
556            if (!changed) break;
557        }
558
559        for(int j=0; j<current_item->numinputs;  j++) Action = ReplaceFile(Action, current_item->input[j]);
560        for(int j=0; j<current_item->numoutputs; j++) Action = ReplaceFile(Action, current_item->output[j]);
561
562        filter_name = AWT_get_combined_filter_name(aw_root, "gde");
563        Action = ReplaceString(Action, "$FILTER", filter_name);
564
565        // call and go...
566        progress.subtitle("calling external program");
567        aw_message_if(GBK_system(Action));
568        free(Action);
569
570        long oldnumelements = DataSet->numelements;
571
572        for (int j=0; j<current_item->numoutputs; j++) {
573            switch (current_item->output[j].format) {
574                /* The LoadData routine must be reworked so that
575                 * OpenFileName uses it, and so I can remove the
576                 * major kluge in OpenFileName().
577                 */
578                case GENBANK:
579                case NA_FLAT:
580                case GDE:
581                    LoadData(current_item->output[j].name);
582                    break;
583                default:
584                    gde_assert(0);
585                    break;
586            }
587        }
588        for (int j=0; j<current_item->numoutputs; j++) {
589            if (!current_item->output[j].save) {
590                unlink(current_item->output[j].name);
591            }
592        }
593
594        for (int j=0; j<current_item->numinputs; j++) {
595            if (!current_item->input[j].save) {
596                unlink(current_item->input[j].name);
597            }
598        }
599
600        GDE_export(DataSet, alignment_name, oldnumelements);
601    }
602
603    free(alignment_name);
604    delete filter2;
605    free(filter_name);
606
607    GDE_freeali(DataSet);
608    freeset(DataSet, (NA_Alignment *)Calloc(1, sizeof(NA_Alignment)));
609    DataSet->rel_offset = 0;
610}
611
Note: See TracBrowser for help on using the repository browser.