~ubuntu-branches/debian/jessie/arb/jessie

« back to all changes in this revision

Viewing changes to AWT/AWT_input_mask.cxx

  • Committer: Package Import Robot
  • Author(s): Elmar Pruesse, Andreas Tille, Elmar Pruesse
  • Date: 2014-09-02 15:15:06 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20140902151506-jihq58b3iz342wif
Tags: 6.0.2-1
[ Andreas Tille ]
* New upstream version
  Closes: #741890
* debian/upstream -> debian/upstream/metadata
* debian/control:
   - Build-Depends: added libglib2.0-dev
   - Depends: added mafft, mrbayes
* debian/rules
   - Add explicite --remove-section=.comment option to manual strip call
* cme fix dpkg-control
* arb-common.dirs: Do not create unneeded lintian dir
* Add turkish debconf translation (thanks for the patch to Mert Dirik
  <mertdirik@gmail.com>)
  Closes: #757497

[ Elmar Pruesse ]
* patches removed:
   - 10_config.makefiles.patch,
     80_no_GL.patch
       removed in favor of creating file from config.makefile.template via 
       sed in debian/control
   - 20_Makefile_main.patch
       merged upstream
   - 21_Makefiles.patch
       no longer needed
   - 30_tmpfile_CVE-2008-5378.patch: 
       merged upstream
   - 50_fix_gcc-4.8.patch:
       merged upstream
   - 40_add_libGLU.patch:
       libGLU not needed for arb_ntree)
   - 60_use_debian_packaged_raxml.patch:
       merged upstream
   - 70_hardening.patch
       merged upstream
   - 72_add_math_lib_to_linker.patch
       does not appear to be needed
* patches added:
   - 10_upstream_r12793__show_db_load_progress:
       backported patch showing progress while ARB is loading a database
       (needed as indicator/splash screen while ARB is launching)
   - 20_upstream_r12794__socket_permissions:
       backported security fix
   - 30_upstream_r12814__desktop_keywords:
       backported add keywords to desktop (fixes lintian warning)
   - 40_upstream_r12815__lintian_spelling:
       backported fix for lintian reported spelling errors
   - 50_private_nameservers
       change configuration to put nameservers into users home dirs
       (avoids need for shared writeable directory)
   - 60_use_debian_phyml
       use phyml from debian package for both interfaces in ARB
* debian/rules:
   - create config.makefile from override_dh_configure target
   - use "make tarfile" in override_dh_install
   - remove extra cleaning not needed for ARB 6
   - use "dh_install --list-missing" to avoid missing files
   - added override_dh_fixperms target
* debian/control:
   - added libarb-dev package
   - Depends: added phyml, xdg-utils
   - Suggests: removed phyml
   - fix lintian duplicate-short-description (new descriptions)
* debian/*.install:
   - "unrolled" confusing globbing to select files
   - pick files from debian/tmp
   - moved all config files to /etc/arb
* debian/arb-common.templates: updated
* scripts:
   - removed arb-add-pt-server
   - launch-wrapper: 
     - only add demo.arb to newly created $ARBUSERDATA
     - pass commandline arguments through bin/arb wrapper
   - preinst: removing old PT server index files on upgrade from 5.5*
   - postinst: set setgid on shared PT dir
* rewrote arb.1 manfile
* added file icon for ARB databases
* using upstream arb_tcp.dat

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#include "awt_input_mask_internal.hxx"
16
16
 
17
17
#include <arbdbt.h>
 
18
#include <ad_cb.h>
 
19
#include <arb_file.h>
18
20
#include <awt_www.hxx>
 
21
#include <aw_edit.hxx>
 
22
#include <aw_file.hxx>
 
23
#include <aw_msg.hxx>
 
24
#include <aw_question.hxx>
19
25
 
20
26
#include <sys/stat.h>
21
27
#include <sys/types.h>
22
28
#include <dirent.h>
23
29
#include <climits>
 
30
#include <set>
24
31
 
25
32
using namespace std;
26
33
 
27
 
const char *awt_itemtype_names[AWT_IT_TYPES+1] =
 
34
static const char *awt_itemtype_names[AWT_IT_TYPES+1] =
28
35
{
29
36
 "Unknown",
30
37
 "Species", "Organism", "Gene", "Experiment",
45
52
 
46
53
// ---------------------
47
54
//      global awars
48
 
// ---------------------
49
55
 
50
56
#define AWAR_INPUT_MASK_BASE   "tmp/inputMask"
51
57
#define AWAR_INPUT_MASK_NAME   AWAR_INPUT_MASK_BASE"/name"
69
75
 
70
76
// ------------------------------------------
71
77
//      Callbacks from database and awars
72
 
// ------------------------------------------
73
78
 
74
79
static bool in_item_changed_callback  = false;
75
80
static bool in_field_changed_callback = false;
76
81
static bool in_awar_changed_callback  = false;
77
82
 
78
 
static void item_changed_cb(GBDATA */*gb_item*/, int *cl_awt_linked_to_item, GB_CB_TYPE type) {
 
83
static void item_changed_cb(GBDATA*, awt_linked_to_item *item_link, GB_CB_TYPE type) {
79
84
    if (!in_item_changed_callback) { // avoid deadlock
80
 
        in_item_changed_callback      = true;
81
 
        awt_linked_to_item *item_link = (awt_linked_to_item*)cl_awt_linked_to_item;
82
 
 
 
85
        LocallyModify<bool> flag(in_item_changed_callback, true);
83
86
        if (type&GB_CB_DELETE) { // handled child was deleted
84
87
            item_link->relink();
85
88
        }
86
 
        else if ((type&(GB_CB_CHANGED|GB_CB_SON_CREATED)) == (GB_CB_CHANGED|GB_CB_SON_CREATED)) {
 
89
        else if ((type&GB_CB_CHANGED_OR_SON_CREATED) == GB_CB_CHANGED_OR_SON_CREATED) {
87
90
            // child was created (not only changed)
88
91
            item_link->relink();
89
92
        }
90
93
        else if (type&GB_CB_CHANGED) { // only changed
91
94
            item_link->general_item_change();
92
95
        }
93
 
 
94
 
        in_item_changed_callback = false;
95
96
    }
96
97
}
97
98
 
98
 
static void field_changed_cb(GBDATA */*gb_item*/, int *cl_awt_input_handler, GB_CB_TYPE type) {
 
99
static void field_changed_cb(GBDATA*, awt_input_handler *handler, GB_CB_TYPE type) {
99
100
    if (!in_field_changed_callback) { // avoid deadlock
100
 
        in_field_changed_callback  = true;
101
 
        awt_input_handler *handler = (awt_input_handler*)cl_awt_input_handler;
102
 
 
 
101
        LocallyModify<bool> flag(in_field_changed_callback, true);
103
102
        if (type&GB_CB_DELETE) { // field was deleted from db -> relink this item
104
103
            handler->relink();
105
104
        }
106
105
        else if (type&GB_CB_CHANGED) {
107
106
            handler->db_changed();  // database entry was changed
108
107
        }
109
 
        in_field_changed_callback = false;
110
108
    }
111
109
}
112
110
 
113
 
static void awar_changed_cb(AW_root */*awr*/, AW_CL cl_awt_mask_awar_item) {
 
111
static void awar_changed_cb(AW_root*, awt_mask_awar_item *item) {
114
112
    if (!in_awar_changed_callback) { // avoid deadlock
115
 
        in_awar_changed_callback   = true;
116
 
        awt_mask_awar_item *item = (awt_mask_awar_item*)cl_awt_mask_awar_item;
 
113
        LocallyModify<bool> flag(in_awar_changed_callback, true);
117
114
        awt_assert(item);
118
115
        if (item) item->awar_changed();
119
 
        in_awar_changed_callback   = false;
120
116
    }
121
117
}
122
118
 
143
139
 
144
140
GB_ERROR awt_input_mask_id_list::add(const string& name, awt_mask_item *item) {
145
141
    awt_mask_item *existing = lookup(name);
146
 
    if (existing) return GB_export_errorf("ID '%s' already exists", name.c_str());
 
142
    if (existing) return GBS_global_string("ID '%s' already exists", name.c_str());
147
143
 
148
144
    id[name] = item;
149
145
    return 0;
150
146
}
151
147
GB_ERROR awt_input_mask_id_list::remove(const string& name) {
152
 
    if (!lookup(name)) return GB_export_errorf("ID '%s' does not exist", name.c_str());
 
148
    if (!lookup(name)) return GBS_global_string("ID '%s' does not exist", name.c_str());
153
149
    id.erase(name);
154
150
    return 0;
155
151
}
156
152
 
157
 
awt_mask_item::awt_mask_item(awt_input_mask_global *global_)
 
153
awt_mask_item::awt_mask_item(awt_input_mask_global& global_)
158
154
    : global(global_)
159
155
{
160
156
}
167
163
{
168
164
    GB_ERROR error = 0;
169
165
    if (has_name()) {
170
 
        error = GB_export_errorf("Element already has name (%s)", get_name().c_str());
 
166
        error = GBS_global_string("Element already has name (%s)", get_name().c_str());
171
167
    }
172
168
    else {
173
169
        name = new string(name_);
174
170
        if (is_global) {
175
 
            if (!mask_global()->has_global_id(*name)) { // do not add if variable already defined elsewhere
176
 
                error = mask_global()->add_global_id(*name, this);
 
171
            if (!mask_global().has_global_id(*name)) { // do not add if variable already defined elsewhere
 
172
                error = mask_global().add_global_id(*name, this);
177
173
            }
178
174
        }
179
175
        else {
180
 
            error = mask_global()->add_local_id(*name, this);
 
176
            error = mask_global().add_local_id(*name, this);
181
177
        }
182
178
    }
183
179
    return error;
187
183
{
188
184
    GB_ERROR error = 0;
189
185
    if (has_name()) {
190
 
        error = mask_global()->remove_id(*name);
 
186
        error = mask_global().remove_id(*name);
191
187
        name.SetNull();
192
188
    }
193
189
    return error;
194
190
}
195
191
 
196
 
awt_mask_awar_item::awt_mask_awar_item(awt_input_mask_global *global_, const string& awar_base, const string& default_value, bool saved_with_properties)
 
192
awt_mask_awar_item::awt_mask_awar_item(awt_input_mask_global& global_, const string& awar_base, const string& default_value, bool saved_with_properties)
197
193
    : awt_mask_item(global_)
198
194
{
199
195
    const char *root_name;
205
201
#if defined(DEBUG)
206
202
    printf("awarName='%s'\n", awarName.c_str());
207
203
#endif // DEBUG
208
 
    mask_global()->get_root()->awar_string(awarName.c_str(), default_value.c_str()); // create the awar
209
 
    add_awar_callbacks();
210
 
}
211
 
 
212
 
void awt_mask_awar_item::add_awar_callbacks() {
213
 
    AW_awar *var = awar();
214
 
    awt_assert(var);
215
 
    if (var) var->add_callback(awar_changed_cb, AW_CL(this));
216
 
}
217
 
void awt_mask_awar_item::remove_awar_callbacks() {
218
 
    AW_awar *var = awar();
219
 
    awt_assert(var);
220
 
    if (var) var->remove_callback((AW_RCB)awar_changed_cb, AW_CL(this), AW_CL(0));
221
 
}
222
 
 
223
 
awt_variable::awt_variable(awt_input_mask_global *global_, const string& id, bool is_global_, const string& default_value, GB_ERROR& error)
 
204
    mask_global().get_root()->awar_string(awarName.c_str(), default_value.c_str()); // create the awar
 
205
    add_awarItem_callbacks();
 
206
}
 
207
 
 
208
void awt_mask_awar_item::add_awarItem_callbacks() {
 
209
    AW_awar *var = awar();
 
210
    awt_assert(var);
 
211
    if (var) var->add_callback(makeRootCallback(awar_changed_cb, this));
 
212
}
 
213
void awt_mask_awar_item::remove_awarItem_callbacks() {
 
214
    AW_awar *var = awar();
 
215
    awt_assert(var);
 
216
    if (var) var->remove_callback(makeRootCallback(awar_changed_cb, this));
 
217
}
 
218
 
 
219
awt_variable::awt_variable(awt_input_mask_global& global_, const string& id, bool is_global_, const string& default_value, GB_ERROR& error)
224
220
    : awt_mask_awar_item(global_, generate_baseName(global_, id, is_global_), default_value, true)
225
221
    , is_global(is_global_)
226
222
{
234
230
string awt_script::get_value() const
235
231
{
236
232
    string                        result;
237
 
    AW_root                      *root     = mask_global()->get_root();
238
 
    const awt_item_type_selector *selector = mask_global()->get_selector();
239
 
    GBDATA                       *gbd      = selector->current(root);
 
233
    AW_root                      *root     = mask_global().get_root();
 
234
    const awt_item_type_selector *selector = mask_global().get_selector();
 
235
    GBDATA                       *gb_main  = mask_global().get_gb_main();
 
236
    GBDATA                       *gbd      = selector->current(root, gb_main);
240
237
 
241
238
    if (gbd) {
242
239
        char           *species_name    = root->awar(selector->get_self_awar())->read_string();
243
 
        GBDATA         *gb_main = mask_global()->get_gb_main();
244
240
        GB_transaction  tscope(gb_main);
245
241
 
246
242
        char *val = GB_command_interpreter(gb_main, species_name, script.c_str(), gbd, 0);
262
258
    return result;
263
259
}
264
260
 
265
 
GB_ERROR awt_script::set_value(const string& /*new_value*/)
 
261
GB_ERROR awt_script::set_value(const string& /* new_value */)
266
262
{
267
263
    return GBS_global_string("You cannot assign a value to script '%s'", has_name() ? get_name().c_str() : "<unnamed>");
268
264
}
270
266
GB_ERROR awt_linked_to_item::add_db_callbacks()
271
267
{
272
268
    GB_ERROR error = 0;
273
 
    if (gb_item) error = GB_add_callback(gb_item, (GB_CB_TYPE)(GB_CB_CHANGED|GB_CB_DELETE), item_changed_cb, (int*)this);
 
269
    if (gb_item) error = GB_add_callback(gb_item, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(item_changed_cb, this));
274
270
    return error;
275
271
}
276
272
 
277
273
void awt_linked_to_item::remove_db_callbacks() {
278
 
    GB_remove_callback(gb_item, (GB_CB_TYPE)(GB_CB_CHANGED|GB_CB_DELETE), item_changed_cb, (int*)this);
 
274
    if (!GB_inside_callback(gb_item, GB_CB_DELETE)) {
 
275
        GB_remove_callback(gb_item, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(item_changed_cb, this));
 
276
    }
279
277
}
280
278
 
281
 
awt_script_viewport::awt_script_viewport(awt_input_mask_global *global_, const awt_script *script_, const string& label_, long field_width_)
 
279
awt_script_viewport::awt_script_viewport(awt_input_mask_global& global_, const awt_script *script_, const string& label_, long field_width_)
282
280
    : awt_viewport(global_, generate_baseName(global_), "", false, label_)
283
281
    , script(script_)
284
282
    , field_width(field_width_)
293
291
GB_ERROR awt_script_viewport::link_to(GBDATA *gb_new_item)
294
292
{
295
293
    GB_ERROR       error = 0;
296
 
    GB_transaction dummy(mask_global()->get_gb_main());
 
294
    GB_transaction ta(mask_global().get_gb_main());
297
295
 
298
 
    remove_awar_callbacks();    // unbind awar callbacks temporarily
 
296
    remove_awarItem_callbacks();    // unbind awar callbacks temporarily
299
297
 
300
298
    if (item()) {
301
299
        remove_db_callbacks(); // ignore result (if handled db-entry was deleted, it returns an error)
308
306
        error = add_db_callbacks();
309
307
    }
310
308
 
311
 
    add_awar_callbacks();       // rebind awar callbacks
 
309
    add_awarItem_callbacks();       // rebind awar callbacks
312
310
 
313
311
    return error;
314
312
}
321
319
    aws->create_input_field(awar_name().c_str(), field_width);
322
320
}
323
321
 
324
 
void awt_script_viewport::db_changed()
325
 
{
326
 
    GB_ERROR error = 0;
 
322
void awt_script_viewport::db_changed() {
327
323
    awt_assert(script);
328
 
    string current_value = script->get_value();
329
 
    error                = awt_mask_awar_item::set_value(current_value);
 
324
    string   current_value = script->get_value();
 
325
    GB_ERROR error         = awt_mask_awar_item::set_value(current_value);
330
326
 
331
327
    if (error) aw_message(error);
332
328
}
337
333
 
338
334
GB_ERROR awt_input_handler::add_db_callbacks() {
339
335
    GB_ERROR error = awt_linked_to_item::add_db_callbacks();
340
 
    if (item() && gbd) error = GB_add_callback(gbd, (GB_CB_TYPE)(GB_CB_CHANGED|GB_CB_DELETE), field_changed_cb, (int*)this);
 
336
    if (item() && gbd) error = GB_add_callback(gbd, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(field_changed_cb, this));
341
337
    return error;
342
338
}
343
339
void awt_input_handler::remove_db_callbacks() {
344
340
    awt_linked_to_item::remove_db_callbacks();
345
 
    if (item() && gbd) GB_remove_callback(gbd, (GB_CB_TYPE)(GB_CB_CHANGED|GB_CB_DELETE), field_changed_cb, (int*)this);
 
341
    if (item() && gbd && !GB_inside_callback(gbd, GB_CB_DELETE)) {
 
342
        GB_remove_callback(gbd, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(field_changed_cb, this));
 
343
    }
346
344
}
347
345
 
348
 
awt_input_handler::awt_input_handler(awt_input_mask_global *global_, const string& child_path_, GB_TYPES type_, const string& label_)
 
346
awt_input_handler::awt_input_handler(awt_input_mask_global& global_, const string& child_path_, GB_TYPES type_, const string& label_)
349
347
    : awt_viewport(global_, generate_baseName(global_, child_path_), "", false, label_)
350
348
    , gbd(0)
351
349
    , child_path(child_path_)
361
359
 
362
360
GB_ERROR awt_input_handler::link_to(GBDATA *gb_new_item) {
363
361
    GB_ERROR       error = 0;
364
 
    GB_transaction dummy(mask_global()->get_gb_main());
 
362
    GB_transaction ta(mask_global().get_gb_main());
365
363
 
366
 
    remove_awar_callbacks(); // unbind awar callbacks temporarily
 
364
    remove_awarItem_callbacks(); // unbind awar callbacks temporarily
367
365
 
368
366
    if (item()) {
369
367
        remove_db_callbacks();  // ignore result (if handled db-entry was deleted, it returns an error)
387
385
        error = add_db_callbacks();
388
386
    }
389
387
 
390
 
    add_awar_callbacks(); // rebind awar callbacks
 
388
    add_awarItem_callbacks(); // rebind awar callbacks
391
389
 
392
390
    return error;
393
391
}
394
392
 
395
393
void awt_string_handler::awar_changed() {
396
394
    GBDATA   *gbdata    = data();
397
 
    GBDATA   *gb_main   = mask_global()->get_gb_main();
 
395
    GBDATA   *gb_main   = mask_global().get_gb_main();
398
396
    bool      relink_me = false;
399
397
    GB_ERROR  error     = 0;
400
398
 
401
399
    GB_push_transaction(gb_main);
402
400
 
403
 
    if (!mask_global()->edit_allowed()) error = "Editing is disabled. Check the 'Enable edit' switch!";
 
401
    if (!mask_global().edit_allowed()) error = "Editing is disabled. Check the 'Enable edit' switch!";
404
402
 
405
403
    if (!error && !gbdata) {
406
404
        const char *child   = get_child_path().c_str();
407
 
        const char *keypath = mask_global()->get_selector()->getKeyPath();
 
405
        const char *keypath = mask_global().get_selector()->getKeyPath();
408
406
 
409
407
        if (item()) {
410
408
            gbdata = GB_search(item(), child, GB_FIND);
419
417
            }
420
418
        }
421
419
        else {
422
 
            mask_global()->no_item_selected();
 
420
            mask_global().no_item_selected();
423
421
            aw_message(GBS_global_string("This had no effect, because no %s is selected",
424
 
                                         awt_itemtype_names[mask_global()->get_itemtype()]));
 
422
                                         awt_itemtype_names[mask_global().get_itemtype()]));
425
423
        }
426
424
    }
427
425
 
450
448
void awt_string_handler::db_changed() {
451
449
    GBDATA *gbdata = data();
452
450
    if (gbdata) { // gbdata may be zero, if field does not exist
453
 
        GB_transaction  dummy(mask_global()->get_gb_main());
 
451
        GB_transaction  ta(mask_global().get_gb_main());
454
452
        char           *content = GB_read_as_string(gbdata);
455
453
        awar()->write_string(db2awar(content).c_str());
456
454
        free(content);
462
460
 
463
461
// ----------------
464
462
//      Widgets
465
 
// ----------------
466
463
 
467
464
void awt_input_field::build_widget(AW_window *aws) {
468
465
    const string& lab = get_label();
501
498
        if (pos == default_position) ins_togg = &AW_window::insert_default_toggle;
502
499
        else ins_togg                         = &AW_window::insert_toggle;
503
500
 
504
 
        (aws->*ins_togg)(b->c_str(), mask_global()->hotkey(*b), b->c_str());
 
501
        (aws->*ins_togg)(b->c_str(), mask_global().hotkey(*b), b->c_str());
505
502
    }
506
503
 
507
504
    awt_assert(b == buttons.end() && v == values.end());
511
508
 
512
509
// -----------------------------------------
513
510
//      Special AWAR <-> DB translations
514
 
// -----------------------------------------
515
511
 
516
512
string awt_check_box::awar2db(const string& awar_content) const {
517
513
    GB_TYPES typ = type();
566
562
 
567
563
// -----------------------------------------
568
564
//      Routines to parse user-mask file
569
 
// -----------------------------------------
570
565
 
571
566
static GB_ERROR readLine(FILE *in, string& line, size_t& lineNo) {
572
567
    const int  BUFSIZE = 8000;
620
615
    }
621
616
    else {
622
617
        switch (line[para_sep]) {
623
 
            case ')' :
 
618
            case ')':
624
619
                was_last_parameter = true;
625
620
                break;
626
621
 
627
 
            case ',' :
 
622
            case ',':
628
623
                break;
629
624
 
630
 
            default :
 
625
            default:
631
626
                error = "',' or ')' expected after parameter";
632
627
                break;
633
628
        }
722
717
    return result;
723
718
}
724
719
 
725
 
string list_keywords(const char **allowed_keywords) {
 
720
static string list_keywords(const char **allowed_keywords) {
726
721
    string result;
727
722
    for (int i = 0; allowed_keywords[i]; ++i) {
728
723
        if (i) {
814
809
        continue;
815
810
    }
816
811
 
817
 
    if (start == string::npos || !isdigit(line[start]) ) {
 
812
    if (start == string::npos || !isdigit(line[start])) {
818
813
        scan_pos = start;
819
814
        error    = "digits (or+-) expected";
820
815
    }
923
918
inline const char *inputMaskDir(bool local) {
924
919
    if (local) {
925
920
        static char *local_mask_dir;
926
 
        if (!local_mask_dir) local_mask_dir = AWT_unfold_path(".arb_prop/inputMasks", "HOME");
 
921
        if (!local_mask_dir) local_mask_dir = strdup(GB_path_in_arbprop("inputMasks"));
927
922
        return local_mask_dir;
928
923
    }
929
924
 
930
925
    static char *global_mask_dir;
931
 
    if (!global_mask_dir) global_mask_dir = AWT_unfold_path("lib/inputMasks", "ARBHOME");
 
926
    if (!global_mask_dir) global_mask_dir = strdup(GB_path_in_ARBLIB("inputMasks"));
932
927
    return global_mask_dir;
933
928
}
934
929
 
940
935
#define ARB_INPUT_MASK_ID "ARB-Input-Mask"
941
936
 
942
937
static awt_input_mask_descriptor *quick_scan_input_mask(const string& mask_name, const string& filename, bool local) {
943
 
    FILE     *in     = fopen(filename.c_str(), "rt");
944
 
    size_t    lineNo = 0;
945
 
    GB_ERROR  error  = 0;
946
 
    int       hidden = 0; // defaults to 'not hidden'
 
938
    awt_input_mask_descriptor *res = 0;
 
939
    FILE     *in    = fopen(filename.c_str(), "rt");
 
940
    GB_ERROR  error = 0;
947
941
 
948
942
    if (in) {
949
943
        string   line;
 
944
        size_t   lineNo = 0;
950
945
        error = readLine(in, line, lineNo);
951
946
 
952
947
        if (!error && line == ARB_INPUT_MASK_ID) {
953
 
            bool   done = false;
 
948
            bool   done   = false;
 
949
            int    hidden = 0; // 0 = 'not hidden'
954
950
            string title;
955
951
            string itemtype;
956
952
 
964
960
                size_t at = line.find('@');
965
961
                size_t eq = line.find('=', at);
966
962
 
967
 
                if (at == string::npos || eq == string::npos)  {
 
963
                if (at == string::npos || eq == string::npos) {
968
964
                    continue; // ignore all other lines
969
965
                }
970
966
                else {
983
979
                }
984
980
                else {
985
981
                    if (title == "") title = mask_name;
986
 
                    return new awt_input_mask_descriptor(title.c_str(), mask_name.c_str(), itemtype.c_str(), local, hidden);
 
982
                    res = new awt_input_mask_descriptor(title.c_str(), mask_name.c_str(), itemtype.c_str(), local, hidden);
987
983
                }
988
984
            }
989
985
        }
 
986
        fclose(in);
990
987
    }
991
988
 
992
989
    if (error) {
996
993
#if defined(DEBUG)
997
994
    printf("Skipping '%s' (not a input mask)\n", filename.c_str());
998
995
#endif // DEBUG
999
 
    return 0;
 
996
    return res;
1000
997
}
1001
998
 
1002
 
static void AWT_edit_input_mask(AW_window *, AW_CL cl_mask_name, AW_CL cl_local) {
1003
 
    const string *mask_name = (const string *)cl_mask_name;
1004
 
    string        fullmask  = inputMaskFullname(*mask_name, (bool)cl_local);
1005
 
    
1006
 
    AWT_edit(fullmask.c_str()); // @@@ add callback and automatically reload input mask
 
999
static void AWT_edit_input_mask(AW_window *, const string *mask_name, bool local) {
 
1000
    string fullmask = inputMaskFullname(*mask_name, local);
 
1001
    AW_edit(fullmask.c_str()); // @@@ add callback and automatically reload input mask
1007
1002
}
1008
1003
 
1009
1004
//  ---------------------------------
1010
1005
//      input mask container :
1011
 
//  ---------------------------------
 
1006
 
1012
1007
typedef SmartPtr<awt_input_mask>        awt_input_mask_ptr;
1013
1008
typedef map<string, awt_input_mask_ptr> InputMaskList; // contains all active masks
1014
1009
static InputMaskList                    input_mask_list;
1015
1010
 
1016
 
static void awt_input_mask_awar_changed_cb(AW_root */*root*/, AW_CL cl_mask) {
1017
 
    awt_input_mask *mask = (awt_input_mask*)(cl_mask);
 
1011
static void awt_input_mask_awar_changed_cb(AW_root*, awt_input_mask *mask) {
1018
1012
    mask->relink();
1019
1013
}
1020
1014
static void link_mask_to_database(awt_input_mask_ptr mask) {
1021
 
    awt_input_mask_global         *global = mask->mask_global();
1022
 
    const awt_item_type_selector  *sel    = global->get_selector();
1023
 
    AW_root                       *root   = global->get_root();
 
1015
    awt_input_mask_global&        global = mask->mask_global();
 
1016
    const awt_item_type_selector *sel    = global.get_selector();
 
1017
    AW_root                      *root   = global.get_root();
1024
1018
 
1025
 
    sel->add_awar_callbacks(root, awt_input_mask_awar_changed_cb, (AW_CL)(&*mask));
1026
 
    awt_input_mask_awar_changed_cb(root, (AW_CL)(&*mask));
 
1019
    sel->add_awar_callbacks(root, makeRootCallback(awt_input_mask_awar_changed_cb, &*mask));
 
1020
    awt_input_mask_awar_changed_cb(root, &*mask);
1027
1021
}
1028
1022
static void unlink_mask_from_database(awt_input_mask_ptr mask) {
1029
 
    awt_input_mask_global        *global = mask->mask_global();
1030
 
    const awt_item_type_selector *sel    = global->get_selector();
1031
 
    AW_root                      *root   = global->get_root();
 
1023
    awt_input_mask_global&        global = mask->mask_global();
 
1024
    const awt_item_type_selector *sel    = global.get_selector();
 
1025
    AW_root                      *root   = global.get_root();
1032
1026
 
1033
 
    sel->remove_awar_callbacks(root, awt_input_mask_awar_changed_cb, (AW_CL)(&*mask));
 
1027
    sel->remove_awar_callbacks(root, makeRootCallback(awt_input_mask_awar_changed_cb, &*mask));
1034
1028
}
1035
1029
 
1036
1030
inline bool isInternalMaskName(const string& s) {
1037
1031
    return s[0] == '0' || s[0] == '1';
1038
1032
}
1039
1033
 
1040
 
static void awt_open_input_mask(AW_window *aww, AW_CL cl_internal_mask_name, AW_CL cl_mask_to_open, bool reload, bool hide_current) {
1041
 
    const string            *internal_mask_name = (const string *)cl_internal_mask_name;
1042
 
    const string            *mask_to_open       = (const string *)cl_mask_to_open;
1043
 
    InputMaskList::iterator  mask_iter          = input_mask_list.find(*internal_mask_name);
 
1034
static void awt_open_input_mask(AW_window *aww, const string *internal_mask_name, const string *mask_to_open, bool reload, bool hide_current) {
 
1035
    InputMaskList::iterator mask_iter = input_mask_list.find(*internal_mask_name);
1044
1036
 
1045
1037
    awt_assert(internal_mask_name && isInternalMaskName(*internal_mask_name));
1046
1038
    awt_assert(mask_to_open && isInternalMaskName(*mask_to_open));
1047
1039
 
1048
1040
    if (mask_iter != input_mask_list.end()) {
1049
1041
        awt_input_mask_ptr     mask   = mask_iter->second;
1050
 
        awt_input_mask_global *global = mask->mask_global();
 
1042
        awt_input_mask_global& global = mask->mask_global();
1051
1043
 
1052
 
        printf("aww=%p root=%p ; global=%p root=%p\n", aww, aww->get_root(), global, global->get_root());
1053
 
        awt_assert(aww->get_root() == global->get_root());
 
1044
        printf("aww=%p root=%p ; global=%p root=%p\n", aww, aww->get_root(), &global, global.get_root());
 
1045
        awt_assert(aww->get_root() == global.get_root());
1054
1046
 
1055
1047
        if (reload) mask->set_reload_on_reinit(true);
1056
1048
        if (hide_current) mask->hide();
1057
1049
        // @@@ hier sollte nicht der Selector der alten Maske verwendet werden, sondern anhand des Typs ein
1058
1050
        // Selector ausgewaehlt werden. Dazu muessen jedoch alle Selectoren registriert werden.
1059
 
        GB_ERROR error = AWT_initialize_input_mask(global->get_root(), global->get_gb_main(), global->get_selector(), mask_to_open->c_str(), global->is_local_mask());
 
1051
        GB_ERROR error = AWT_initialize_input_mask(global.get_root(), global.get_gb_main(), global.get_selector(), mask_to_open->c_str(), global.is_local_mask());
1060
1052
        // CAUTION: AWT_initialize_input_mask invalidates mask and mask_iter
1061
1053
        if (error && hide_current) {
1062
1054
            mask_iter = input_mask_list.find(*internal_mask_name);
1073
1065
#endif // DEBUG
1074
1066
}
1075
1067
 
1076
 
static void AWT_reload_input_mask(AW_window *aww, AW_CL cl_internal_mask_name) {
1077
 
    awt_open_input_mask(aww, cl_internal_mask_name, cl_internal_mask_name, true, true);
1078
 
}
1079
 
static void AWT_open_input_mask(AW_window *aww, AW_CL cl_internal_mask_name, AW_CL cl_mask_to_open) {
1080
 
    awt_open_input_mask(aww, cl_internal_mask_name, cl_mask_to_open, false, false);
1081
 
}
1082
 
static void AWT_change_input_mask(AW_window *aww, AW_CL cl_internal_mask_name, AW_CL cl_mask_to_open) {
1083
 
    awt_open_input_mask(aww, cl_internal_mask_name, cl_mask_to_open, false, true);
1084
 
}
1085
 
 
1086
 
 
 
1068
static void AWT_reload_input_mask(AW_window *aww, const string *internal_mask_name) {
 
1069
    awt_open_input_mask(aww, internal_mask_name, internal_mask_name, true, true);
 
1070
}
 
1071
static void AWT_open_input_mask(AW_window *aww, const string *internal_mask_name, const string *mask_to_open) {
 
1072
    awt_open_input_mask(aww, internal_mask_name, mask_to_open, false, false);
 
1073
}
 
1074
static void AWT_change_input_mask(AW_window *aww, const string *internal_mask_name, const string *mask_to_open) {
 
1075
    awt_open_input_mask(aww, internal_mask_name, mask_to_open, false, true);
 
1076
}
1087
1077
 
1088
1078
//  ------------------------------
1089
1079
//      class awt_mask_action
1090
 
//  ------------------------------
1091
 
// something that is performed i.e. when user pressed a mask button
1092
 
// used as callback parameter
 
1080
 
1093
1081
class awt_mask_action {
 
1082
    // something that is performed i.e. when user pressed a mask button
 
1083
    // used as callback parameter
1094
1084
private:
1095
1085
    virtual GB_ERROR action() = 0;
1096
1086
protected:
1108
1098
 
1109
1099
//  ------------------------------------------------------
1110
1100
//      class awt_assignment : public awt_mask_action
1111
 
//  ------------------------------------------------------
 
1101
 
1112
1102
class awt_assignment : public awt_mask_action {
1113
1103
private:
1114
1104
    string id_dest;
1115
1105
    string id_source;
1116
1106
 
1117
 
    virtual GB_ERROR action() {
 
1107
    virtual GB_ERROR action() OVERRIDE {
1118
1108
        GB_ERROR             error       = 0;
1119
 
        const awt_mask_item *item_source = mask->mask_global()->get_identified_item(id_source, error);
1120
 
        awt_mask_item       *item_dest   = mask->mask_global()->get_identified_item(id_dest, error);
 
1109
        const awt_mask_item *item_source = mask->mask_global().get_identified_item(id_source, error);
 
1110
        awt_mask_item       *item_dest   = mask->mask_global().get_identified_item(id_dest, error);
1121
1111
 
1122
1112
        if (!error) error = item_dest->set_value(item_source->get_value());
1123
1113
 
1129
1119
        , id_dest(id_dest_)
1130
1120
        , id_source(id_source_)
1131
1121
    {}
1132
 
    virtual ~awt_assignment() {}
 
1122
    virtual ~awt_assignment() OVERRIDE {}
1133
1123
};
1134
1124
 
1135
 
static void AWT_input_mask_perform_action(AW_window */*aww*/, AW_CL cl_awt_mask_action, AW_CL) {
1136
 
    awt_mask_action *action = (awt_mask_action*)cl_awt_mask_action;
 
1125
static void AWT_input_mask_perform_action(AW_window*, awt_mask_action *action) {
1137
1126
    action->perform_action();
1138
1127
}
1139
1128
 
1140
 
static void AWT_input_mask_browse_url(AW_window *aww, AW_CL cl_url_srt, AW_CL cl_mask_ptr) {
1141
 
    AW_root                      *root     = aww->get_root();
1142
 
    const string                 *url_srt  = (const string *)cl_url_srt;
1143
 
    const awt_input_mask         *mask     = (const awt_input_mask *)cl_mask_ptr;
1144
 
    const awt_input_mask_global  *global   = mask->mask_global();
1145
 
    const awt_item_type_selector *selector = global->get_selector();
1146
 
    GBDATA                       *gbd      = selector->current(root);
 
1129
static void AWT_input_mask_browse_url(AW_window *aww, const string *url_srt, const awt_input_mask *mask) {
 
1130
    const awt_input_mask_global&  global   = mask->mask_global();
 
1131
    const awt_item_type_selector *selector = global.get_selector();
 
1132
 
 
1133
    AW_root *root    = aww->get_root();
 
1134
    GBDATA  *gb_main = global.get_gb_main();
 
1135
    GBDATA  *gbd     = selector->current(root, gb_main);
1147
1136
 
1148
1137
    if (!gbd) {
1149
1138
        aw_message(GBS_global_string("You have to select a %s first", awt_itemtype_names[selector->get_item_type()]));
1150
1139
    }
1151
1140
    else {
1152
1141
        char     *name  = root->awar(selector->get_self_awar())->read_string();
1153
 
        GB_ERROR  error = awt_open_ACISRT_URL_by_gbd(root, global->get_gb_main(), gbd, name, url_srt->c_str());
 
1142
        GB_ERROR  error = awt_open_ACISRT_URL_by_gbd(root, gb_main, gbd, name, url_srt->c_str());
1154
1143
        if (error) aw_message(error);
1155
1144
        free(name);
1156
1145
    }
1159
1148
 
1160
1149
// ---------------------------
1161
1150
//      User Mask Commands
1162
 
// ---------------------------
1163
1151
 
1164
 
enum MaskCommand  {
 
1152
enum MaskCommand {
1165
1153
    CMD_TEXTFIELD,
1166
1154
    CMD_NUMFIELD,
1167
1155
    CMD_CHECKBOX,
1209
1197
 { "ASSIGN", CMD_ASSIGN },
1210
1198
 { "SCRIPT", CMD_SCRIPT },
1211
1199
 
1212
 
 { 0, CMD_UNKNOWN}
 
1200
 { 0, CMD_UNKNOWN }
1213
1201
};
1214
1202
 
1215
1203
inline MaskCommand findCommand(const string& cmd_name) {
1224
1212
}
1225
1213
 
1226
1214
static void parse_CMD_RADIO(string& line, size_t& scan_pos, GB_ERROR& error, const string& command,
1227
 
                            awt_mask_item_ptr& handler1, awt_mask_item_ptr& handler2, awt_input_mask_global *global)
 
1215
                            awt_mask_item_ptr& handler1, awt_mask_item_ptr& handler2, awt_input_mask_global& global)
1228
1216
{
1229
1217
    string         label, data_path;
1230
1218
    int            default_position = -1, orientation = -1;
1246
1234
        string val = "";
1247
1235
        if (!error) {
1248
1236
            int keyword_index;
1249
 
            const char *allowed_keywords[] = { "ALLOW_EDIT", 0};
 
1237
            const char *allowed_keywords[] = { "ALLOW_EDIT", 0 };
1250
1238
            scan_string_or_keyword_parameter(line, scan_pos, error, val, keyword_index, allowed_keywords);
1251
1239
 
1252
1240
            if (!error) {
1320
1308
 
1321
1309
// ----------------------------------
1322
1310
//      class awt_marked_checkbox
1323
 
// ----------------------------------
1324
1311
 
1325
1312
class awt_marked_checkbox : public awt_viewport, public awt_linked_to_item {
1326
1313
private:
1327
1314
 
1328
 
    string generate_baseName(awt_input_mask_global *global_) {
1329
 
        return GBS_global_string("%s/marked", global_->get_maskid().c_str());
 
1315
    string generate_baseName(awt_input_mask_global& global_) {
 
1316
        return GBS_global_string("%s/marked", global_.get_maskid().c_str());
1330
1317
    }
1331
1318
 
1332
1319
public:
1333
 
    awt_marked_checkbox(awt_input_mask_global *global_, const std::string& label_)
 
1320
    awt_marked_checkbox(awt_input_mask_global& global_, const std::string& label_)
1334
1321
        : awt_viewport(global_, generate_baseName(global_), "0", false, label_)
1335
1322
        , awt_linked_to_item()
1336
1323
    {}
1337
 
    virtual ~awt_marked_checkbox() {}
 
1324
    virtual ~awt_marked_checkbox() OVERRIDE {}
1338
1325
 
1339
 
    virtual GB_ERROR link_to(GBDATA *gb_new_item); // link to a new item
1340
 
    virtual GB_ERROR relink() { return link_to(mask_global()->get_selector()->current(mask_global()->get_root())); }
1341
 
    virtual void awar_changed();
1342
 
    virtual void db_changed();
1343
 
    virtual void general_item_change() { db_changed(); } // called if item was changed (somehow)
1344
 
    virtual void build_widget(AW_window *aws); // builds the widget at the current position
 
1326
    virtual GB_ERROR link_to(GBDATA *gb_new_item) OVERRIDE; // link to a new item
 
1327
    virtual GB_ERROR relink() OVERRIDE { return link_to(mask_global().get_selected_item()); }
 
1328
    virtual void awar_changed() OVERRIDE;
 
1329
    virtual void db_changed() OVERRIDE;
 
1330
    virtual void general_item_change() OVERRIDE { db_changed(); } // called if item was changed (somehow)
 
1331
    virtual void build_widget(AW_window *aws) OVERRIDE; // builds the widget at the current position
1345
1332
};
1346
1333
 
1347
1334
GB_ERROR awt_marked_checkbox::link_to(GBDATA *gb_new_item) { // link to a new item
1348
1335
    GB_ERROR       error = 0;
1349
 
    GB_transaction dummy(mask_global()->get_gb_main());
 
1336
    GB_transaction ta(mask_global().get_gb_main());
1350
1337
 
1351
 
    remove_awar_callbacks();    // unbind awar callbacks temporarily
 
1338
    remove_awarItem_callbacks();    // unbind awar callbacks temporarily
1352
1339
 
1353
1340
    if (item()) {
1354
1341
        remove_db_callbacks(); // ignore result (if handled db-entry was deleted, it returns an error)
1361
1348
        error = add_db_callbacks();
1362
1349
    }
1363
1350
 
1364
 
    add_awar_callbacks();       // rebind awar callbacks
 
1351
    add_awarItem_callbacks();       // rebind awar callbacks
1365
1352
    return error;
1366
1353
}
1367
1354
 
1369
1356
    if (item()) {
1370
1357
        string         value  = get_value();
1371
1358
        bool           marked = value == "yes";
1372
 
        GB_transaction dummy(mask_global()->get_gb_main());
 
1359
        GB_transaction ta(mask_global().get_gb_main());
1373
1360
        GB_write_flag(item(), marked);
1374
1361
    }
1375
1362
    else {
1376
 
        mask_global()->no_item_selected();
 
1363
        mask_global().no_item_selected();
1377
1364
    }
1378
1365
}
1379
1366
 
1380
1367
void awt_marked_checkbox::db_changed() {
1381
 
    bool marked = false;
1382
 
 
1383
1368
    if (item()) {
1384
 
        GB_transaction dummy(mask_global()->get_gb_main());
1385
 
        if (GB_read_flag(item())) marked = true;
1386
 
        set_value(marked ? "yes" : "no"); // @@@ TEST: moved into if (was below)
 
1369
        GB_transaction ta(mask_global().get_gb_main());
 
1370
        set_value(GB_read_flag(item()) ? "yes" : "no");
1387
1371
    }
1388
1372
}
1389
1373
 
1431
1415
    return 0;
1432
1416
}
1433
1417
 
 
1418
class ID_checker {
 
1419
    bool        reloading;
 
1420
    set<string> seen;
 
1421
    set<string> dup;
 
1422
    string      curr_id;
 
1423
 
 
1424
    bool is_known(const string& id) { return seen.find(id) != seen.end(); }
 
1425
 
 
1426
    string makeUnique(string id) {
 
1427
        if (is_known(id)) {
 
1428
            dup.insert(id);
 
1429
            for (int i = 0; ; ++i) {
 
1430
                string undup = GBS_global_string("%s%i", id.c_str(), i);
 
1431
                if (!is_known(undup)) {
 
1432
                    id = undup;
 
1433
                    break;
 
1434
                }
 
1435
            }
 
1436
        }
 
1437
        seen.insert(id);
 
1438
        return id;
 
1439
    }
 
1440
 
 
1441
public:
 
1442
    ID_checker(bool reloading_)
 
1443
        : reloading(reloading_)
 
1444
    {}
 
1445
 
 
1446
    const char *fromKey(const char *id) {
 
1447
        curr_id = makeUnique(id);
 
1448
        return reloading ? NULL : curr_id.c_str();
 
1449
    }
 
1450
    const char *fromText(const string& anystr) {
 
1451
        SmartCharPtr key = GBS_string_2_key(anystr.c_str());
 
1452
        return fromKey(&*key);
 
1453
    }
 
1454
 
 
1455
    bool seenDups() const { return !dup.empty(); }
 
1456
    const char *get_dup_error(const string& maskName) const {
 
1457
        string dupList;
 
1458
        for (set<string>::iterator d = dup.begin(); d != dup.end(); ++d) {
 
1459
            dupList = dupList+" '"+*d+"'";
 
1460
        }
 
1461
        return GBS_global_string("Warning: duplicated IDs seen in '%s':\n"
 
1462
                                 "%s\n"
 
1463
                                 "(they need to be unique; change button texts etc. to change them)",
 
1464
                                 maskName.c_str(), dupList.c_str());
 
1465
    }
 
1466
};
 
1467
 
1434
1468
static awt_input_mask_ptr awt_create_input_mask(AW_root *root, GBDATA *gb_main, const awt_item_type_selector *sel,
1435
1469
                                                const string& mask_name, bool local, GB_ERROR& error, bool reloading) {
1436
 
    size_t             lineNo = 0;
1437
1470
    awt_input_mask_ptr mask;
1438
1471
 
1439
1472
    error = 0;
1459
1492
        bool          show_marked = true;
1460
1493
 
1461
1494
        string line;
 
1495
        size_t lineNo  = 0;
1462
1496
        size_t err_pos = 0;     // 0 = unknown; string::npos = at end of line; else position+1;
1463
 
        error          = readLine(in, line, lineNo);
 
1497
 
 
1498
        error = readLine(in, line, lineNo);
1464
1499
 
1465
1500
        if (!error && line != ARB_INPUT_MASK_ID) {
1466
1501
            error = "'" ARB_INPUT_MASK_ID "' expected";
1473
1508
            if (line[0] == '#') continue; // ignore comments
1474
1509
 
1475
1510
            if (line == "@MASK_BEGIN") mask_began = true;
1476
 
            else  {
 
1511
            else {
1477
1512
                size_t at = line.find('@');
1478
1513
                size_t eq = line.find('=', at);
1479
1514
 
1516
1551
 
1517
1552
        // create window
1518
1553
        if (!error) {
1519
 
            awt_assert(!mask.Null());
 
1554
            awt_assert(!mask.isNull());
1520
1555
            AW_window_simple*& aws = mask->get_window();
1521
1556
            aws                    = new AW_window_simple;
1522
1557
 
1523
 
            // do not use callback ids for reloaded masks
1524
 
#define ID(id) (reloading ? NULL : id)
 
1558
            ID_checker ID(reloading);
1525
1559
 
1526
1560
            {
1527
 
                char *window_id = GBS_global_string_copy("INPUT_MASK_%s", mask->mask_global()->get_maskid().c_str()); // create a unique id for each mask
 
1561
                char *window_id = GBS_global_string_copy("INPUT_MASK_%s", mask->mask_global().get_maskid().c_str()); // create a unique id for each mask
1528
1562
                aws->init(root, window_id, title.c_str());
1529
1563
                free(window_id);
1530
1564
            }
 
1565
 
1531
1566
            aws->load_xfig(0, true);
1532
 
 
1533
 
            aws->recalc_size_at_show = 1; // ignore user size!
 
1567
            aws->recalc_size_atShow(AW_RESIZE_DEFAULT); // ignore user size!
1534
1568
 
1535
1569
            aws->auto_space(x_spacing, y_spacing);
1536
1570
            aws->at_newline();
1537
1571
 
1538
 
            aws->callback((AW_CB0)AW_POPDOWN);                          aws->create_button(ID("CLOSE"), "CLOSE", "C");
1539
 
            aws->callback( AW_POPUP_HELP,(AW_CL)"input_mask.hlp");      aws->create_button(ID("HELP"),"HELP","H");
 
1572
            aws->callback((AW_CB0)AW_POPDOWN);                  aws->create_button(ID.fromKey("CLOSE"), "CLOSE", "C");
 
1573
            aws->callback(makeHelpCallback("input_mask.hlp"));  aws->create_button(ID.fromKey("HELP"),  "HELP",  "H");
1540
1574
 
1541
1575
            if (edit_reload) {
1542
 
                aws->callback(AWT_edit_input_mask, (AW_CL)&mask->mask_global()->get_maskname(), (AW_CL)mask->mask_global()->is_local_mask());   aws->create_button(0, "EDIT","E");
1543
 
                aws->callback(AWT_reload_input_mask, (AW_CL)&mask->mask_global()->get_internal_maskname());                                     aws->create_button(0, "RELOAD","R");
 
1576
                aws->callback(makeWindowCallback(AWT_edit_input_mask, &mask->mask_global().get_maskname(), mask->mask_global().is_local_mask()));
 
1577
                aws->create_button(0, "!EDIT", "E");
 
1578
 
 
1579
                aws->callback(makeWindowCallback(AWT_reload_input_mask, &mask->mask_global().get_internal_maskname()));
 
1580
                aws->create_button(0, "RELOAD", "R");
1544
1581
            }
1545
1582
 
1546
1583
            if (edit_reload && edit_enable && show_marked) aws->at_newline();
1559
1596
 
1560
1597
            aws->at_newline();
1561
1598
 
1562
 
            vector<int> horizontal_lines; // y-positions of horizontal lines
 
1599
            vector<int>         horizontal_lines; // y-positions of horizontal lines
1563
1600
            map<string, size_t> referenced_ids; // all ids that where referenced by the script (size_t contains lineNo of last reference)
1564
1601
            map<string, size_t> declared_ids; // all ids that where declared by the script (size_t contains lineNo of declaration)
1565
1602
 
1576
1613
                if (line == "@MASK_END") {
1577
1614
                    mask_ended = true;
1578
1615
                }
1579
 
                else  {
1580
 
                PARSE_REST_OF_LINE:
 
1616
                else {
 
1617
                PARSE_REST_OF_LINE :
1581
1618
                    was_last_parameter = false;
1582
1619
                    size_t start       = next_non_white(line, 0);
1583
1620
                    if (start != string::npos) { // line contains sth
1600
1637
 
1601
1638
                                //  --------------------------------------
1602
1639
                                //      code for different commands :
1603
 
                                //  --------------------------------------
1604
1640
 
1605
1641
                                if (cmd == CMD_TEXTFIELD) {
1606
1642
                                    string label, data_path;
1659
1695
                                    string id, def_value;
1660
1696
 
1661
1697
                                    id                 = scan_identifier(line, scan_pos, error);
1662
 
                                    bool global_exists = mask->mask_global()->has_global_id(id);
1663
 
                                    bool local_exists  = mask->mask_global()->has_local_id(id);
 
1698
                                    bool global_exists = mask->mask_global().has_global_id(id);
 
1699
                                    bool local_exists  = mask->mask_global().has_local_id(id);
1664
1700
 
1665
1701
                                    if ((cmd == CMD_GLOBAL && local_exists) || (cmd == CMD_LOCAL && global_exists)) {
1666
 
                                        error = GB_export_errorf("ID '%s' already declared as %s ID (rename your local id)",
1667
 
                                                                 id.c_str(), cmd == CMD_LOCAL ? "global" : "local");
 
1702
                                        error = GBS_global_string("ID '%s' already declared as %s ID (rename your local id)",
 
1703
                                                                  id.c_str(), cmd == CMD_LOCAL ? "global" : "local");
1668
1704
                                    }
1669
1705
                                    else if (cmd == CMD_LOCAL && local_exists) {
1670
 
                                        error = GB_export_errorf("ID '%s' declared twice", id.c_str());
 
1706
                                        error = GBS_global_string("ID '%s' declared twice", id.c_str());
1671
1707
                                    }
1672
1708
 
1673
1709
                                    if (!error) def_value = scan_string_parameter(line, scan_pos, error);
1674
1710
                                    if (!error) {
1675
1711
                                        if (cmd == CMD_GLOBAL) {
1676
 
                                            if (!mask->mask_global()->has_global_id(id)) { // do not create globals more than once
 
1712
                                            if (!mask->mask_global().has_global_id(id)) { // do not create globals more than once
1677
1713
                                                // and never free them -> so we don't need pointer
1678
1714
                                                new awt_variable(mask->mask_global(), id, true, def_value, error);
1679
1715
                                            }
1680
 
                                            awt_assert(handler.Null());
 
1716
                                            awt_assert(handler.isNull());
1681
1717
                                        }
1682
1718
                                        else {
1683
1719
                                            handler = new awt_variable(mask->mask_global(), id, false, def_value, error);
1690
1726
                                    check_last_parameter(error, command);
1691
1727
 
1692
1728
                                    if (!error) {
1693
 
                                        if (lasthandler.Null()) {
 
1729
                                        if (lasthandler.isNull()) {
1694
1730
                                            error = "ID() may only be used BEHIND another element";
1695
1731
                                        }
1696
1732
                                        else {
1706
1742
 
1707
1743
                                    label             = scan_string_parameter(line, scan_pos, error);
1708
1744
                                    if (!error) id    = scan_identifier(line, scan_pos, error);
1709
 
                                    if (!error) item  = (awt_mask_item*)mask->mask_global()->get_identified_item(id, error);
 
1745
                                    if (!error) item  = (awt_mask_item*)mask->mask_global().get_identified_item(id, error);
1710
1746
                                    if (!error) width = scan_long_parameter(line, scan_pos, error, MIN_TEXTFIELD_SIZE, MAX_TEXTFIELD_SIZE);
1711
1747
                                    check_last_parameter(error, command);
1712
1748
 
1732
1768
                                    check_last_parameter(error, command);
1733
1769
 
1734
1770
                                    if (!error) {
1735
 
                                        char   *key                    = ID(GBS_string_2_key(label.c_str()));
1736
 
                                        AW_CB   cb                     = cmd == CMD_OPENMASK ? AWT_open_input_mask : AWT_change_input_mask;
1737
 
                                        string  mask_to_start_internal = find_internal_name(mask_to_start, local);
 
1771
                                        string mask_to_start_internal = find_internal_name(mask_to_start, local);
1738
1772
 
1739
1773
                                        if (mask_to_start_internal.length() == 0) {
1740
1774
                                            error = "Can't detect which mask to load";
1741
1775
                                        }
1742
1776
                                        else {
1743
 
                                            string *cl_arg1 = new string(mask->mask_global()->get_internal_maskname());
1744
 
                                            string *cl_arg2 = new string(mask_to_start_internal);
1745
 
 
1746
 
                                            awt_assert(cl_arg1);
1747
 
                                            awt_assert(cl_arg2);
1748
 
 
1749
 
                                            aws->callback( cb, (AW_CL)cl_arg1, (AW_CL)cl_arg2);
 
1777
                                            const char *key = ID.fromText(label);
 
1778
 
 
1779
                                            string *const internal_mask_name = new string(mask->mask_global().get_internal_maskname());
 
1780
                                            string *const mask_to_open       = new string(mask_to_start_internal);
 
1781
 
 
1782
                                            awt_assert(internal_mask_name);
 
1783
                                            awt_assert(mask_to_open);
 
1784
 
 
1785
                                            aws->callback(makeWindowCallback(cmd == CMD_OPENMASK ? AWT_open_input_mask : AWT_change_input_mask, internal_mask_name, mask_to_open));
 
1786
 
1750
1787
                                            aws->button_length(label.length()+2);
1751
1788
                                            aws->create_button(key, label.c_str());
1752
1789
                                        }
1753
 
 
1754
 
                                        free(key);
1755
1790
                                    }
1756
1791
                                }
1757
1792
                                else if (cmd == CMD_WWW) {
1761
1796
                                    check_last_parameter(error, command);
1762
1797
 
1763
1798
                                    if (!error) {
1764
 
                                        char *key = ID(GBS_string_2_key(button_text.c_str()));
1765
 
 
1766
 
                                        aws->callback(AWT_input_mask_browse_url, (AW_CL)new string(url_srt), (AW_CL)&*mask);
 
1799
                                        const char *key = ID.fromText(button_text);
 
1800
                                        aws->callback(makeWindowCallback(AWT_input_mask_browse_url, new string(url_srt), &*mask));
1767
1801
                                        aws->button_length(button_text.length()+2);
1768
1802
                                        aws->create_button(key, button_text.c_str());
1769
 
 
1770
 
                                        free(key);
1771
1803
                                    }
1772
1804
                                }
1773
1805
                                else if (cmd == CMD_ASSIGN) {
1781
1813
                                        referenced_ids[id_source] = lineNo;
1782
1814
                                        referenced_ids[id_dest]   = lineNo;
1783
1815
 
1784
 
                                        char *key = ID(GBS_string_2_key(button_text.c_str()));
1785
 
 
1786
 
                                        aws->callback(AWT_input_mask_perform_action, (AW_CL)new awt_assignment(mask, id_dest, id_source), 0);
 
1816
                                        const char *key = ID.fromText(button_text);
 
1817
                                        aws->callback(makeWindowCallback(AWT_input_mask_perform_action, static_cast<awt_mask_action*>(new awt_assignment(mask, id_dest, id_source))));
1787
1818
                                        aws->button_length(button_text.length()+2);
1788
1819
                                        aws->create_button(key, button_text.c_str());
1789
 
 
1790
 
                                        free(key);
1791
1820
                                    }
1792
1821
                                }
1793
1822
                                else if (cmd == CMD_TEXT) {
1796
1825
                                    check_last_parameter(error, command);
1797
1826
 
1798
1827
                                    if (!error) {
1799
 
                                        char *key = ID(GBS_string_2_key(text.c_str()));
1800
1828
                                        aws->button_length(text.length()+2);
1801
 
                                        aws->create_button(key, text.c_str());
1802
 
                                        free(key);
 
1829
                                        aws->create_button(NULL, text.c_str());
1803
1830
                                    }
1804
1831
                                }
1805
1832
                                else if (cmd == CMD_SELF) {
1806
1833
                                    check_no_parameter(line, scan_pos, error, command);
1807
1834
                                    if (!error) {
1808
 
                                        const awt_item_type_selector *selector         = mask->mask_global()->get_selector();
1809
 
                                        string                        button_awar_name = selector->get_self_awar();
1810
 
                                        char                         *key              = ID(GBS_string_2_key(button_awar_name.c_str()));
1811
 
 
 
1835
                                        const awt_item_type_selector *selector = mask->mask_global().get_selector();
1812
1836
                                        aws->button_length(selector->get_self_awar_content_length());
1813
 
                                        aws->create_button(key, button_awar_name.c_str());
1814
 
                                        free(key);
 
1837
                                        aws->create_button(NULL, selector->get_self_awar());
1815
1838
                                    }
1816
1839
                                }
1817
1840
                                else if (cmd == CMD_NEW_LINE) {
1841
1864
 
1842
1865
                                //  --------------------------
1843
1866
                                //      insert handler(s)
1844
 
                                //  --------------------------
1845
1867
 
1846
 
                                if (!handler.Null() && !error) {
1847
 
                                    if (!radio_edit_handler.Null()) { // special radio handler
 
1868
                                if (!handler.isNull() && !error) {
 
1869
                                    if (!radio_edit_handler.isNull()) { // special radio handler
1848
1870
                                        const awt_radio_button *radio = dynamic_cast<const awt_radio_button*>(&*handler);
1849
1871
                                        awt_assert(radio);
1850
1872
 
1898
1920
            if (!error) {
1899
1921
                for (map<string, size_t>::const_iterator r = referenced_ids.begin(); r != referenced_ids.end(); ++r) {
1900
1922
                    if (declared_ids.find(r->first) == declared_ids.end()) {
1901
 
                        error = GB_export_errorf("ID '%s' used in line #%zu was not declared", r->first.c_str(), r->second);
 
1923
                        error = GBS_global_string("ID '%s' used in line #%zu was not declared", r->first.c_str(), r->second);
1902
1924
                        aw_message(error);
1903
1925
                    }
1904
1926
                }
1928
1950
                aws->window_fit();
1929
1951
            }
1930
1952
 
1931
 
            // link to database
1932
1953
            if (!error) link_mask_to_database(mask);
1933
 
 
1934
 
#undef ID
 
1954
            if (ID.seenDups()) aw_message(ID.get_dup_error(mask_name));
1935
1955
        }
1936
1956
 
1937
1957
        if (error) {
1981
2001
    awt_input_mask_ptr       old_mask;
1982
2002
    bool                     unlink_old = false;
1983
2003
 
1984
 
    static list<awt_input_mask_ptr> mask_collector; // here old (aka reloaded) masks are kept
1985
 
    // (freeing masks is not possible, because of too many nested callbacks)
1986
 
 
1987
 
    // erase mask (so it loads again from scratch)
1988
 
    if (mask_iter != input_mask_list.end() && mask_iter->second->reload_on_reinit()) // reload wanted ?
1989
 
    {
1990
 
        old_mask  = mask_iter->second;
 
2004
    if (mask_iter != input_mask_list.end() && mask_iter->second->reload_on_reinit()) { // reload wanted ?
 
2005
        // erase mask (so it loads again from scratch)
 
2006
        old_mask = mask_iter->second;
1991
2007
        input_mask_list.erase(mask_iter);
1992
2008
        mask_iter = input_mask_list.end();
1993
2009
 
1994
2010
        old_mask->hide();
1995
 
        mask_collector.push_back(old_mask);
1996
2011
        unlink_old = true;
1997
2012
    }
1998
2013
 
2000
2015
        awt_input_mask_ptr newMask = awt_create_input_mask(root, gb_main, sel, mask_name, local, error, unlink_old);
2001
2016
        if (error) {
2002
2017
            error = GBS_global_string("Error reading %s (%s)", mask_name, error);
2003
 
            if (!old_mask.Null()) { // are we doing a reload or changemask ?
 
2018
            if (!old_mask.isNull()) { // are we doing a reload or changemask ?
2004
2019
                input_mask_list[internal_mask_name] = old_mask; // error loading modified mask -> put old one back to mask-list
2005
2020
                unlink_old                          = false;
2006
2021
            }
2017
2032
    }
2018
2033
 
2019
2034
    if (unlink_old) {
2020
 
        old_mask->relink(true); // unlink old mask from database ()
 
2035
        old_mask->unlink(); // unlink old mask from database ()
2021
2036
        unlink_mask_from_database(old_mask);
2022
2037
    }
2023
2038
 
2028
2043
// start of implementation of class awt_input_mask:
2029
2044
 
2030
2045
awt_input_mask::~awt_input_mask() {
2031
 
    relink(true); // unlink from DB
 
2046
    unlink();
2032
2047
    for (awt_mask_item_list::iterator h = handlers.begin(); h != handlers.end(); ++h) {
2033
2048
        (*h)->remove_name();
2034
2049
    }
2035
2050
}
2036
2051
 
2037
 
void awt_input_mask::relink(bool unlink) {
 
2052
void awt_input_mask::link_to(GBDATA *gb_item) {
2038
2053
    // this functions links/unlinks all registered item handlers to/from the database
2039
 
    const awt_item_type_selector *sel     = global.get_selector();
2040
 
    GBDATA                       *gb_item = unlink ? 0 : sel->current(global.get_root());
2041
 
 
2042
2054
    for (awt_mask_item_list::iterator h = handlers.begin(); h != handlers.end(); ++h) {
2043
 
         if ((*h)->is_linked_item()) (*h)->to_linked_item()->link_to(gb_item);
2044
 
//         if ((*h)->is_input_handler()) (*h)->to_input_handler()->link_to(gb_item);
2045
 
//         else if ((*h)->is_script_viewport()) (*h)->to_script_viewport()->link_to(gb_item);
 
2055
        if ((*h)->is_linked_item()) (*h)->to_linked_item()->link_to(gb_item);
2046
2056
    }
2047
2057
}
2048
2058
 
2050
2060
 
2051
2061
 
2052
2062
awt_input_mask_descriptor::awt_input_mask_descriptor(const char *title_, const char *maskname_, const char *itemtypename_, bool local, bool hidden_) {
2053
 
    title                = strdup(title_);
 
2063
    title = strdup(title_);
2054
2064
    internal_maskname    = (char*)malloc(strlen(maskname_)+2);
2055
2065
    internal_maskname[0] = local ? '0' : '1';
2056
2066
    strcpy(internal_maskname+1, maskname_);
2057
 
    //     maskname      = strdup(maskname_);
2058
2067
    itemtypename         = strdup(itemtypename_);
2059
2068
    local_mask           = local;
2060
2069
    hidden               = hidden_;
2064
2073
    free(internal_maskname);
2065
2074
    free(title);
2066
2075
}
 
2076
 
2067
2077
awt_input_mask_descriptor::awt_input_mask_descriptor(const awt_input_mask_descriptor& other) {
2068
2078
    title             = strdup(other.title);
2069
2079
    internal_maskname = strdup(other.internal_maskname);
2106
2116
        if (!GB_is_directory(dirname)) {
2107
2117
            if (scope == AWT_SCOPE_LOCAL) {         // in local scope
2108
2118
                GB_ERROR warning = GB_create_directory(dirname); // try to create directory
2109
 
                if (warning) fprintf(stderr, "Warning: %s\n", warning);
 
2119
                if (warning) GB_warning(warning);
2110
2120
            }
2111
2121
        }
2112
2122
 
2165
2175
 
2166
2176
// -----------------------------
2167
2177
//      Registered Itemtypes
2168
 
// -----------------------------
2169
 
 
2170
 
typedef void (*AWT_OpenMaskWindowCallback)(AW_window* aww, AW_CL cl_id, AW_CL);
2171
 
 
2172
 
//  --------------------------------------
2173
 
//      class AWT_registered_itemtype
2174
 
//  --------------------------------------
2175
 
// stores information about so-far-used item types
 
2178
 
2176
2179
class AWT_registered_itemtype {
2177
 
private:
2178
 
    AW_window_menu_modes       *awm; // the main window responsible for opening windows
2179
 
    AWT_OpenMaskWindowCallback  open_window_cb; // callback to open the window
 
2180
    // stores information about so-far-used item types
 
2181
    AW_window_menu_modes       *awm;                // the main window responsible for opening windows
 
2182
    AWT_OpenMaskWindowCallback  open_window_cb;     // callback to open the window
 
2183
    GBDATA                     *gb_main;
2180
2184
 
2181
2185
public:
2182
 
    AWT_registered_itemtype() : awm(0), open_window_cb(0) {}
2183
 
    AWT_registered_itemtype(AW_window_menu_modes *awm_, AWT_OpenMaskWindowCallback open_window_cb_)
 
2186
    AWT_registered_itemtype() : awm(0), open_window_cb(0), gb_main(0) {}
 
2187
    AWT_registered_itemtype(AW_window_menu_modes *awm_, AWT_OpenMaskWindowCallback open_window_cb_, GBDATA *gb_main_)
2184
2188
        : awm(awm_)
2185
2189
        , open_window_cb(open_window_cb_)
2186
 
    {}
 
2190
        , gb_main(gb_main_)
 
2191
    {}
 
2192
    AWT_registered_itemtype(const AWT_registered_itemtype& other)
 
2193
        : awm(other.awm),
 
2194
          open_window_cb(other.open_window_cb),
 
2195
          gb_main(other.gb_main)
 
2196
    {}
 
2197
    DECLARE_ASSIGNMENT_OPERATOR(AWT_registered_itemtype);
2187
2198
    virtual ~AWT_registered_itemtype() {}
2188
2199
 
2189
2200
    AW_window_menu_modes *getWindow() const { return awm; }
2190
2201
    AWT_OpenMaskWindowCallback getOpenCb() const { return open_window_cb; }
2191
2202
};
2192
2203
 
2193
 
static map<awt_item_type, AWT_registered_itemtype> registeredTypes;
 
2204
typedef map<awt_item_type, AWT_registered_itemtype> TypeRegistry;
 
2205
typedef TypeRegistry::const_iterator                TypeRegistryIter;
 
2206
 
 
2207
static TypeRegistry registeredTypes;
2194
2208
 
2195
2209
static GB_ERROR openMaskWindowByType(int mask_id, awt_item_type type) {
2196
 
    map<awt_item_type, AWT_registered_itemtype>::const_iterator registered = registeredTypes.find(type);
2197
 
    GB_ERROR                                                    error      = 0;
 
2210
    TypeRegistryIter registered = registeredTypes.find(type);
 
2211
    GB_ERROR         error      = 0;
2198
2212
 
2199
2213
    if (registered == registeredTypes.end()) error = GBS_global_string("Type '%s' not registered (yet)", awt_itemtype_names[type]);
2200
2214
    else registered->second.getOpenCb()(registered->second.getWindow(), (AW_CL)mask_id, (AW_CL)0);
2202
2216
    return error;
2203
2217
}
2204
2218
 
2205
 
static void registerType(awt_item_type type, AW_window_menu_modes *awm, AWT_OpenMaskWindowCallback open_window_cb) {
2206
 
    map<awt_item_type, AWT_registered_itemtype>::const_iterator alreadyRegistered = registeredTypes.find(type);
 
2219
static void registerType(awt_item_type type, AW_window_menu_modes *awm, AWT_OpenMaskWindowCallback open_window_cb, GBDATA *gb_main) {
 
2220
    TypeRegistryIter alreadyRegistered = registeredTypes.find(type);
2207
2221
    if (alreadyRegistered == registeredTypes.end()) {
2208
 
        registeredTypes[type] = AWT_registered_itemtype(awm, open_window_cb);
 
2222
        registeredTypes[type] = AWT_registered_itemtype(awm, open_window_cb, gb_main);
2209
2223
    }
2210
2224
#if defined(DEBUG)
2211
2225
    else {
2212
 
//         awt_assert(alreadyRegistered->second.getWindow() == awm);
2213
2226
        awt_assert(alreadyRegistered->second.getOpenCb() == open_window_cb);
2214
2227
    }
2215
2228
#endif // DEBUG
2217
2230
 
2218
2231
// ----------------------------------------------
2219
2232
//      Create a new input mask (interactive)
2220
 
// ----------------------------------------------
2221
2233
 
2222
2234
static void create_new_mask_cb(AW_window *aww) {
2223
2235
    AW_root *awr = aww->get_root();
2224
2236
 
2225
 
    string maskname = awr->awar(AWAR_INPUT_MASK_NAME)->read_string();
 
2237
    string maskname = awr->awar(AWAR_INPUT_MASK_NAME)->read_char_pntr();
2226
2238
    {
2227
2239
        size_t ext = maskname.find(".mask");
2228
2240
 
2233
2245
    }
2234
2246
 
2235
2247
 
2236
 
    string       itemname     = awr->awar(AWAR_INPUT_MASK_ITEM)->read_string();
2237
 
    int          scope        = awr->awar(AWAR_INPUT_MASK_SCOPE)->read_int();
2238
 
    int          hidden       = awr->awar(AWAR_INPUT_MASK_HIDDEN)->read_int();
2239
 
    bool         local        = scope == AWT_SCOPE_LOCAL;
2240
 
    string       maskfullname = inputMaskFullname(maskname, local);
2241
 
    bool         openMask     = false;
2242
 
    bool         closeWindow  = false;
2243
 
    const char  *error        = 0;
 
2248
    string itemname     = awr->awar(AWAR_INPUT_MASK_ITEM)->read_char_pntr();
 
2249
    int    scope        = awr->awar(AWAR_INPUT_MASK_SCOPE)->read_int();
 
2250
    int    hidden       = awr->awar(AWAR_INPUT_MASK_HIDDEN)->read_int();
 
2251
    bool   local        = scope == AWT_SCOPE_LOCAL;
 
2252
    string maskfullname = inputMaskFullname(maskname, local);
 
2253
    bool   openMask     = false;
 
2254
 
 
2255
    const char  *error = 0;
2244
2256
    struct stat  st;
2245
2257
 
2246
2258
    if (stat(maskfullname.c_str(), &st) == 0) { // file exists
2247
 
        int answer = aw_question("File does already exist", "Open mask,Cancel");
 
2259
        int answer = aw_question("overwrite_mask", "File does already exist", "Overwrite mask,Cancel");
2248
2260
        switch (answer) {
2249
2261
            case 0:
2250
2262
                openMask   = true;
2260
2272
        }
2261
2273
        if (!error) {
2262
2274
            add_new_input_mask(maskname, maskfullname, local);
2263
 
            openMask    = true;
2264
 
            closeWindow = true;
 
2275
            openMask = true;
2265
2276
        }
2266
2277
    }
2267
2278
 
2292
2303
    if (error) aw_message(error);
2293
2304
}
2294
2305
 
2295
 
static void create_new_input_mask(AW_window *aww, AW_CL cl_item_type, AW_CL) { // create new user mask (interactively)
 
2306
static void create_new_input_mask(AW_window *aww, awt_item_type item_type) { // create new user mask (interactively)
2296
2307
    static AW_window_simple *aws = 0;
2297
2308
 
2298
2309
    if (!aws) {
2305
2316
        aws->button_length(10);
2306
2317
        aws->callback(AW_POPDOWN);
2307
2318
        aws->create_button("CLOSE", "CLOSE", 0);
2308
 
        aws->callback(AW_POPUP_HELP,(AW_CL)"input_mask_new.hlp");
2309
 
        aws->create_button("HELP", "HELP","H");
 
2319
        aws->callback(makeHelpCallback("input_mask_new.hlp"));
 
2320
        aws->create_button("HELP", "HELP", "H");
2310
2321
 
2311
2322
        aws->at_newline();
2312
2323
 
2316
2327
        aws->at_newline();
2317
2328
 
2318
2329
        aws->label("Item type");
2319
 
        aws->create_option_menu(AWAR_INPUT_MASK_ITEM, "", "");
 
2330
        aws->create_option_menu(AWAR_INPUT_MASK_ITEM, true);
2320
2331
        for (int i = AWT_IT_UNKNOWN+1; i<AWT_IT_TYPES; ++i) {
2321
2332
            aws->insert_option(awt_itemtype_names[i], "", awt_itemtype_names[i]);
2322
2333
        }
2341
2352
        aws->at_newline();
2342
2353
 
2343
2354
        aws->callback(create_new_mask_cb);
2344
 
        aws->create_button("CREATE", "CREATE","C");
 
2355
        aws->create_button("CREATE", "CREATE", "C");
2345
2356
 
2346
2357
        aws->window_fit();
2347
2358
    }
2348
2359
 
2349
2360
    aws->activate();
2350
 
    aww->get_root()->awar(AWAR_INPUT_MASK_ITEM)->write_string(awt_itemtype_names[int(cl_item_type)]);
 
2361
    aww->get_root()->awar(AWAR_INPUT_MASK_ITEM)->write_string(awt_itemtype_names[item_type]);
2351
2362
}
2352
2363
 
2353
2364
// -----------------------------------------------------
2354
2365
//      Create User-Mask-Submenu for any application
2355
 
// -----------------------------------------------------
2356
 
 
2357
 
void AWT_create_mask_submenu(AW_window_menu_modes *awm, awt_item_type wanted_item_type, void (*open_window_cb)(AW_window* aww, AW_CL cl_id, AW_CL)) {
 
2366
 
 
2367
static bool hadMnemonic(char *availableMnemonics, char c) {
 
2368
    // return true if 'c' occurs in 'availableMnemonics' (case ignored)
 
2369
    // (in that case 'c' is removed from 'availableMnemonics').
 
2370
    // returns false otherwise.
 
2371
    char  lc   = tolower(c);
 
2372
    char *cand = strchr(availableMnemonics, lc);
 
2373
    if (cand) {
 
2374
        char *last = strchr(cand+1, 0)-1;
 
2375
        if (last>cand) {
 
2376
            cand[0] = last[0];
 
2377
            last[0] = 0;
 
2378
        }
 
2379
        else {
 
2380
            awt_assert(last == cand);
 
2381
            cand[0] = 0;
 
2382
        }
 
2383
        return true;
 
2384
    }
 
2385
    return false;
 
2386
}
 
2387
 
 
2388
static char *selectMnemonic(const char *orgTitle, char *availableMnemonics, char& mnemonic) {
 
2389
    // select (and remove) one from 'availableMnemonics' occurring in orgTitle
 
2390
    // return selected in 'mnemonic'
 
2391
    // return orgTitle (eventually modified if no matching mnemonic available)
 
2392
 
 
2393
    bool prevWasChar = false;
 
2394
    for (int startOfWord = 1; startOfWord>=0; --startOfWord) {
 
2395
        for (int i = 0; orgTitle[i]; ++i) {
 
2396
            char c = orgTitle[i];
 
2397
            if (isalnum(c)) {
 
2398
                if (!prevWasChar || !startOfWord) {
 
2399
                    if (hadMnemonic(availableMnemonics, c)) {
 
2400
                        mnemonic = c;
 
2401
                        return strdup(orgTitle);
 
2402
                    }
 
2403
                }
 
2404
                prevWasChar = true;
 
2405
            }
 
2406
            else prevWasChar = false;
 
2407
        }
 
2408
    }
 
2409
 
 
2410
    for (int i = 0; i<2; ++i) {
 
2411
        const char *takeAny = i ? availableMnemonics : "1234567890";
 
2412
        for (int t = 0; takeAny[t]; ++t) {
 
2413
            char c = takeAny[t];
 
2414
            if (hadMnemonic(availableMnemonics, c)) {
 
2415
                mnemonic = c;
 
2416
                return GBS_global_string_copy("%s [%c]", orgTitle, c);
 
2417
            }
 
2418
        }
 
2419
    }
 
2420
 
 
2421
    mnemonic = 0; // failed
 
2422
    return strdup(orgTitle);
 
2423
}
 
2424
 
 
2425
void AWT_create_mask_submenu(AW_window_menu_modes *awm, awt_item_type wanted_item_type, AWT_OpenMaskWindowCallback open_mask_window_cb, GBDATA *gb_main) {
2358
2426
    // add a user mask submenu at current position
2359
2427
    AW_root *awr = awm->get_root();
2360
2428
 
2362
2430
 
2363
2431
    awm->insert_sub_menu("User Masks", "k");
2364
2432
 
 
2433
    char *availableMnemonics = strdup("abcdefghijklmopqrstuvwxyz0123456789"); // 'n' excluded!
 
2434
 
2365
2435
    for (int scope = 0; scope <= 1; ++scope) {
2366
2436
        bool entries_made = false;
2367
2437
 
2368
 
        for (int id = 0; ;++id) {
 
2438
        for (int id = 0; ; ++id) {
2369
2439
            const awt_input_mask_descriptor *descriptor = AWT_look_input_mask(id);
2370
2440
 
2371
2441
            if (!descriptor) break;
2375
2445
 
2376
2446
            if (item_type == wanted_item_type) {
2377
2447
                if (!descriptor->is_hidden()) { // do not show masks with hidden-flag
2378
 
                    entries_made = true;
 
2448
                    entries_made        = true;
2379
2449
                    char *macroname2key = GBS_string_2_key(descriptor->get_internal_maskname());
2380
2450
#if defined(DEBUG) && 0
2381
2451
                    printf("added user-mask '%s' with id=%i\n", descriptor->get_maskname(), id);
2382
2452
#endif // DEBUG
2383
 
                    awm->insert_menu_topic(macroname2key, descriptor->get_title(), "", "input_mask.hlp", AWM_ALL, open_window_cb, (AW_CL)id, (AW_CL)0);
 
2453
                    char  mnemonic[2] = "x";
 
2454
                    char *mod_title   = selectMnemonic(descriptor->get_title(), availableMnemonics, mnemonic[0]);
 
2455
 
 
2456
                    awm->insert_menu_topic(macroname2key, mod_title, mnemonic, "input_mask.hlp", AWM_ALL, makeWindowCallback(open_mask_window_cb, id, gb_main));
 
2457
                    free(mod_title);
2384
2458
                    free(macroname2key);
2385
2459
                }
2386
 
                registerType(item_type, awm, open_window_cb);
 
2460
                registerType(item_type, awm, open_mask_window_cb, gb_main);
2387
2461
            }
2388
2462
            else if (item_type == AWT_IT_UNKNOWN) {
2389
2463
                aw_message(GBS_global_string("Unknown @ITEMTYPE '%s' in '%s'", descriptor->get_itemtypename(), descriptor->get_internal_maskname()));
2390
2464
            }
2391
2465
        }
2392
 
        if (entries_made) awm->insert_separator();
 
2466
        if (entries_made) awm->sep______________();
2393
2467
    }
2394
2468
 
2395
2469
    {
2397
2471
        char       *new_item_mask_id    = GBS_global_string_copy("new_%s_mask", itemname);
2398
2472
        char       *new_item_mask_label = GBS_global_string_copy("New %s mask..", itemname);
2399
2473
 
2400
 
        awm->insert_menu_topic(new_item_mask_id, new_item_mask_label, "N", "input_mask_new.hlp", AWM_ALL, create_new_input_mask, (AW_CL)wanted_item_type, (AW_CL)0);
 
2474
        awm->insert_menu_topic(new_item_mask_id, new_item_mask_label, "N", "input_mask_new.hlp", AWM_ALL, makeWindowCallback(create_new_input_mask, wanted_item_type));
2401
2475
 
2402
2476
        free(new_item_mask_label);
2403
2477
        free(new_item_mask_id);
2404
 
    }    
 
2478
    }
 
2479
    free(availableMnemonics);
2405
2480
    awm->close_sub_menu();
2406
2481
}
2407
2482
 
2408
2483
void AWT_destroy_input_masks() {
 
2484
    // unlink from DB manually - there are too many smartptrs to
 
2485
    // get rid of all of them before DB gets destroyed on exit
 
2486
    for (InputMaskList::iterator i = input_mask_list.begin();
 
2487
         i != input_mask_list.end();
 
2488
         ++i)
 
2489
    {
 
2490
        i->second->unlink(); 
 
2491
    }
2409
2492
    input_mask_list.clear();
2410
2493
}
2411
2494
 
 
2495
 
 
2496
void awt_item_type_selector::add_awar_callbacks(AW_root *root, const RootCallback& cb) const {
 
2497
    root->awar(get_self_awar())->add_callback(cb);
 
2498
}
 
2499
 
 
2500
void awt_item_type_selector::remove_awar_callbacks(AW_root *root, const RootCallback& cb) const {
 
2501
    root->awar(get_self_awar())->remove_callback(cb);
 
2502
}