source: branches/stable/AWT/awt_input_mask_internal.hxx

Last change on this file was 16763, checked in by westram, 6 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.1 KB
Line 
1// ============================================================ //
2//                                                              //
3//   File      : awt_input_mask_internal.hxx                    //
4//   Purpose   : input mask internal classes                    //
5//                                                              //
6//   Coded by Ralf Westram (coder@reallysoft.de) in June 2009   //
7//   Institute of Microbiology (Technical University Munich)    //
8//   www.arb-home.de                                            //
9//                                                              //
10// ============================================================ //
11
12#ifndef AWT_INPUT_MASK_INTERNAL_HXX
13#define AWT_INPUT_MASK_INTERNAL_HXX
14
15#ifndef AWT_INPUT_MASK_HXX
16#include <awt_input_mask.hxx>
17#endif
18#ifndef AWT_HOTKEYS_HXX
19#include <awt_hotkeys.hxx>
20#endif
21#ifndef ARBDB_H
22#include <arbdb.h>
23#endif
24#ifndef AW_AWAR_HXX
25#include <aw_awar.hxx>
26#endif
27#ifndef AW_ROOT_HXX
28#include <aw_root.hxx>
29#endif
30#ifndef AW_WINDOW_HXX
31#include <aw_window.hxx>
32#endif
33#ifndef AWT_HXX
34#include "awt.hxx"
35#endif
36
37
38#ifndef _GLIBCXX_MAP
39#include <map>
40#endif
41#ifndef _GLIBCXX_LIST
42#include <list>
43#endif
44#ifndef _GLIBCXX_VECTOR
45#include <vector>
46#endif
47
48
49// ---------------------------
50//      forward references
51
52class awt_mask_item;
53class awt_linked_to_item;
54class awt_viewport;
55
56// --------------------------------------
57//      class awt_input_mask_id_list
58
59class awt_input_mask_id_list {
60private:
61    // maps ids to corresponding input_handlers
62    std::map<std::string, awt_mask_item*> id;
63
64public:
65    awt_input_mask_id_list() {}
66    virtual ~awt_input_mask_id_list() {}
67
68    awt_mask_item *lookup(const std::string& name) const {
69        std::map<std::string, awt_mask_item*>::const_iterator found = id.find(name);
70        return (found == id.end()) ? NULp : found->second;
71    }
72    GB_ERROR add(const std::string& name, awt_mask_item *item);
73    GB_ERROR remove(const std::string& name);
74    bool empty() const { return id.empty(); }
75};
76
77//  ------------------------------------
78//      class awt_input_mask_global
79//
80// data global to one input mask
81class awt_input_mask_global : virtual Noncopyable {
82private:
83    mutable AW_root *awr;
84    mutable GBDATA  *gb_main;
85    std::string      mask_name;                     // filename of mask-file
86    std::string      internal_mask_name;            // filename of mask-file (prefixed by 0( = local) or 1( = global))
87    std::string      mask_id;                       // key generated from mask_name
88    bool             local_mask;                    // true if mask was found in "$ARB_PROP/inputMasks"
89    awt_item_type    itemtype;                      // what kind of item do we handle ?
90
91    bool test_edit_enabled;                         // true -> the global awar AWAR_INPUT_MASKS_EDIT_ENABLE should be tested before writing to database
92
93    const awt_item_type_selector *sel;
94
95    awt_hotkeys                   hotkeys;
96    awt_input_mask_id_list        ids;              // local
97    static awt_input_mask_id_list global_ids;
98
99    static std::string generate_id(const std::string& mask_name_);
100
101
102public:
103    awt_input_mask_global(AW_root *awr_, GBDATA *gb_main_, const std::string& mask_name_, awt_item_type itemtype_, bool local, const awt_item_type_selector *sel_, bool test_edit_enabled_) :
104        awr(awr_),
105        gb_main(gb_main_),
106        mask_name(mask_name_),
107        internal_mask_name(std::string(1, local ? '0' : '1')+mask_name_),
108        mask_id(generate_id(mask_name_)),
109        local_mask(local),
110        itemtype(itemtype_),
111        test_edit_enabled(test_edit_enabled_),
112        sel(sel_)
113    {
114        awt_assert(mask_name_[0] != '0' && mask_name_[0] != '1');
115    }
116    virtual ~awt_input_mask_global() {
117        awt_assert(ids.empty());
118    }
119
120    bool is_local_mask() const { return local_mask; }
121    AW_root *get_root() const { return awr; }
122    GBDATA *get_gb_main() const { return gb_main; }
123    const std::string& get_maskname() const { return mask_name; }
124    const std::string& get_internal_maskname() const { return internal_mask_name; }
125    std::string get_maskid() const { return mask_id; }
126    awt_item_type get_itemtype() const { return itemtype; }
127    const awt_item_type_selector *get_selector() const { awt_assert(sel); return sel; }
128    const char* hotkey(const std::string& label)  { return hotkeys.hotkey(label); }
129
130    GBDATA *get_selected_item() const { return get_selector()->current(get_root(), get_gb_main()); }
131
132    bool has_local_id(const std::string& name) const { return ids.lookup(name); }
133    bool has_global_id(const std::string& name) const { return global_ids.lookup(name); }
134
135    GB_ERROR add_local_id(const std::string& name, awt_mask_item *handler) {
136        if (has_global_id(name)) return GBS_global_string("ID '%s' already defined as GLOBAL", name.c_str());
137        return ids.add(name, handler);
138    }
139
140    GB_ERROR add_global_id(const std::string& name, awt_mask_item *handler) {
141        if (has_local_id(name)) return GBS_global_string("ID '%s' already defined as LOCAL", name.c_str());
142        return global_ids.add(name, handler);
143    }
144
145    GB_ERROR remove_local_id(const std::string& name) { return ids.remove(name); }
146    GB_ERROR remove_id(const std::string& name) {
147        if (has_local_id(name)) return remove_local_id(name);
148        if (has_global_id(name)) return NULp; // global ids are only created (never removed)
149        return GBS_global_string("ID '%s' not found - can't remove id", name.c_str());
150    }
151
152    awt_mask_item *get_identified_item(const std::string& name, GB_ERROR& error) const {
153        awt_mask_item *found = NULp;
154        if (!error) {
155            found             = ids.lookup(name);
156            if (!found) found = global_ids.lookup(name);
157            if (!found) error = GBS_global_string("No item '%s' declared", name.c_str());
158        }
159        return found;
160    }
161
162    void no_item_selected() const;
163    bool edit_allowed() const;
164};
165
166//  ----------------------------
167//      class awt_mask_item
168//
169class awt_mask_item {
170    // works as base class for all elements of a input-mask
171
172    // basic item members
173    // awt_input_mask_global *global;    // reference  // @@@ make ref to make class copyable
174    awt_input_mask_global& global;
175    SmartPtr<std::string>  name;      // name of this item (optional -- caused i.e. by script command 'ID')
176
177public:
178    awt_mask_item(awt_input_mask_global& global_); // awar_base has to be unique (in every mask)
179    virtual ~awt_mask_item();
180
181    const awt_input_mask_global& mask_global() const { return global; }
182    awt_input_mask_global& mask_global() { return global; }
183
184    bool has_name() const { return !name.isNull(); }
185    const std::string& get_name() const { awt_assert(has_name()); return *name; }
186    GB_ERROR set_name(const std::string& name_, bool is_global);
187    GB_ERROR remove_name();
188
189    inline const awt_viewport *to_viewport() const;
190    inline awt_viewport *to_viewport();
191
192    inline const awt_linked_to_item *to_linked_item() const;
193    inline awt_linked_to_item *to_linked_item();
194
195    bool is_viewport() const { return to_viewport(); }
196    bool is_linked_item() const { return to_linked_item(); }
197
198    virtual std::string get_value() const                    = 0; // reads the current value of the item
199    virtual GB_ERROR set_value(const std::string& new_value) = 0; // assigns a new value to the item
200};
201
202//  --------------------------------
203//      class awt_mask_awar_item
204//
205// holds an awar
206class awt_mask_awar_item :  public awt_mask_item {
207private:
208    // awar related members
209    std::string     awarName;        // name of the awar
210
211protected:
212
213    void add_awarItem_callbacks();
214    void remove_awarItem_callbacks();
215
216public:
217    awt_mask_awar_item(awt_input_mask_global& global_, const std::string& awar_base, const std::string& default_value, bool saved_with_properties);
218    ~awt_mask_awar_item() OVERRIDE { remove_awarItem_callbacks(); }
219
220    virtual void awar_changed() = 0; // called when awar changes
221
222    std::string awar_name() const  { return awarName; }
223    const AW_awar *awar() const { return mask_global().get_root()->awar(awarName.c_str()); }
224    AW_awar *awar() { return mask_global().get_root()->awar(awarName.c_str()); }
225
226    std::string get_value() const OVERRIDE {  // reads the current value of the item
227        return const_cast<AW_awar*>(awar())->read_string();
228    }
229    GB_ERROR set_value(const std::string& new_value) OVERRIDE { // assigns a new value to the item
230        awar()->write_string(new_value.c_str());
231        return NULp; // an overloaded method may return an error
232    }
233};
234
235// ---------------------------
236//      class awt_viewport
237//
238// awar bound to a widget
239class awt_viewport : public awt_mask_awar_item {
240private:
241    std::string label;               // label of viewport
242
243public:
244    awt_viewport(awt_input_mask_global& global_, const std::string& awar_base, const std::string& default_value, bool saved_with_properties, const std::string& label_) :
245        awt_mask_awar_item(global_, awar_base, default_value, saved_with_properties),
246        label(label_)
247    {}
248    awt_viewport(const awt_mask_awar_item& ref_item, const std::string& label_) :
249        awt_mask_awar_item(ref_item),
250        label(label_)
251    {}
252    ~awt_viewport() OVERRIDE {}
253
254    const std::string& get_label() const { return label; }
255    virtual void build_widget(AW_window *aws) = 0; // builds the widget at the current position
256};
257
258// ---------------------------
259//      class awt_variable
260//
261// awar NOT bound to widget; is saved in properties
262class awt_variable : public awt_mask_awar_item {
263private:
264    bool is_global;
265
266    static std::string generate_baseName(const awt_input_mask_global& global_, const std::string& id, bool is_global_) {
267        // the generated name is NOT enumerated, because any reference to a variable should
268        // work on the same awar
269        return
270            is_global_
271            ? std::string("global_")+id
272            : std::string(GBS_global_string("local_%s_%s", global_.get_maskid().c_str(), id.c_str()));
273    }
274public:
275    awt_variable(awt_input_mask_global& global_, const std::string& id, bool is_global_, const std::string& default_value, GB_ERROR& error);
276    ~awt_variable() OVERRIDE;
277    void awar_changed() OVERRIDE {
278#if defined(DEBUG)
279        printf("awt_variable was changed\n");
280#endif // DEBUG
281    }
282};
283
284
285//  ------------------------
286//      class awt_script
287//
288class awt_script FINAL_TYPE : public awt_mask_item {
289private:
290    std::string script;
291
292public:
293    awt_script(awt_input_mask_global& global_, const std::string& script_) :
294        awt_mask_item(global_),
295        script(script_)
296    {}
297    ~awt_script() OVERRIDE {}
298
299    std::string get_value() const OVERRIDE; // reads the current value of the item
300    GB_ERROR set_value(const std::string& /* new_value */) OVERRIDE; // assigns a new value to the item
301};
302
303//  ---------------------------------
304//      class awt_linked_to_item
305//
306class awt_linked_to_item : virtual Noncopyable {
307private:
308    GBDATA                *gb_item; // item this handler is linked to
309    // if gb_item == 0 then no callbacks are installed
310
311protected:
312
313    virtual GB_ERROR add_db_callbacks();
314    virtual void     remove_db_callbacks();
315
316    void set_item(GBDATA *new_item) {
317#if defined(DEBUG)
318        printf("gb_item=%p new_item=%p\n", gb_item, new_item);
319#endif // DEBUG
320        gb_item = new_item;
321    }
322
323public:
324    awt_linked_to_item() : gb_item(NULp) {}
325    virtual ~awt_linked_to_item() {
326        awt_assert(!gb_item); // you forgot to call awt_linked_to_item::unlink from where you destroy 'this'
327    }
328
329    GBDATA *item() { return gb_item; }
330    virtual GB_ERROR link_to(GBDATA *gb_new_item) = 0; // link to a new item
331
332    GB_ERROR unlink() { return link_to(NULp); }
333    virtual GB_ERROR relink() = 0; // used by callbacks to relink awt_input_handler
334
335    virtual void general_item_change() {} // called if item was changed (somehow)
336    virtual void db_changed() = 0;
337};
338
339
340//  ---------------------------------
341//      class awt_script_viewport
342//
343class awt_script_viewport FINAL_TYPE : public awt_viewport, public awt_linked_to_item { // derived from a Noncopyable
344private:
345    const awt_script *script;
346    int               field_width;
347
348    static std::string generate_baseName(const awt_input_mask_global& global_) {
349        static int awar_counter = 0;
350        return GBS_global_string("%s/scriptview_%i", global_.get_maskid().c_str(), awar_counter++);
351    }
352
353public:
354    awt_script_viewport(awt_input_mask_global& global_, const awt_script *script_, const std::string& label_, long field_width_);
355    ~awt_script_viewport() OVERRIDE;
356
357    GB_ERROR link_to(GBDATA *gb_new_item) OVERRIDE; // link to a new item
358    GB_ERROR relink() OVERRIDE { return link_to(mask_global().get_selected_item()); }
359
360    void build_widget(AW_window *aws) OVERRIDE; // builds the widget at the current position
361    void awar_changed() OVERRIDE;
362    void db_changed() OVERRIDE;
363};
364
365
366//  --------------------------------
367//      class awt_input_handler
368//
369// an awt_input_handler is an awt_viewport bound to a database element
370class awt_input_handler : public awt_viewport, public awt_linked_to_item { // derived from a Noncopyable
371private:
372    GBDATA      *gbd;           // link to database
373    std::string  child_path;    // path in database from item to handled child
374    GB_TYPES     db_type;       // type of database field
375    bool         in_destructor;
376
377    GB_ERROR add_db_callbacks() FINAL_OVERRIDE;
378    void     remove_db_callbacks() FINAL_OVERRIDE;
379
380    static std::string generate_baseName(const awt_input_mask_global& global_, const std::string& child_path) {
381        // the generated name is enumerated to allow different awt_input_handler's to be linked
382        // to the same child_path
383        static int awar_counter = 0;
384        return GBS_global_string("%s/handler_%s_%i", global_.get_maskid().c_str(), child_path.c_str(), awar_counter++);
385    }
386
387
388public:
389    awt_input_handler(awt_input_mask_global& global_, const std::string& child_path_, GB_TYPES type_, const std::string& label_);
390    ~awt_input_handler() OVERRIDE;
391
392    GB_ERROR link_to(GBDATA *gb_new_item) FINAL_OVERRIDE; // link to a new item
393    GB_ERROR relink() FINAL_OVERRIDE { return link_to(mask_global().get_selected_item()); }
394
395    GBDATA *data() { return gbd; }
396
397    GB_TYPES type() const { return db_type; }
398    void set_type(GB_TYPES typ) { db_type = typ; }
399
400    const std::string& get_child_path() const { return child_path; }
401};
402
403typedef SmartPtr<awt_mask_item>      awt_mask_item_ptr;
404typedef std::list<awt_mask_item_ptr> awt_mask_item_list;
405
406//  --------------------------------
407//      class awt_string_handler
408//
409// this handler handles string fields
410class awt_string_handler : public awt_input_handler {
411private:
412    std::string  default_value;      // default value for awar if no data present
413
414public:
415    awt_string_handler(awt_input_mask_global& global_, const std::string& child_path_, const std::string& default_awar_value_, GB_TYPES default_type, const std::string& label_) :
416        awt_input_handler(global_, child_path_, default_type, label_),
417        default_value(default_awar_value_)
418    {
419    }
420    ~awt_string_handler() OVERRIDE {}
421
422    void awar_changed() OVERRIDE;
423    void db_changed() FINAL_OVERRIDE;
424
425    virtual std::string awar2db(const std::string& awar_content) const { return awar_content; }
426    virtual std::string db2awar(const std::string& db_content) const { return db_content; }
427
428    void build_widget(AW_window *aws) OVERRIDE = 0; // builds the widget at the current position
429};
430
431//  ------------------------------
432//      class awt_input_field
433//
434// awt_input_field holds a text field bound to a database string field
435class awt_input_field : public awt_string_handler {
436private:
437    int    field_width;
438
439public:
440    awt_input_field(awt_input_mask_global& global_, const std::string& child_path_, const std::string& label_, int field_width_, const std::string& default_value_, GB_TYPES default_type) :
441        awt_string_handler(global_, child_path_, default_value_, default_type, label_),
442        field_width(field_width_)
443    {}
444    ~awt_input_field() OVERRIDE {}
445
446    void build_widget(AW_window *aws) OVERRIDE;
447};
448
449//  -------------------------------
450//      class awt_text_viewport
451//
452class awt_text_viewport : public awt_viewport {
453private:
454    int    field_width;
455
456public:
457    awt_text_viewport(const awt_mask_awar_item *item, const std::string& label_, long field_width_) :
458        awt_viewport(*item, label_),
459        field_width(field_width_)
460    {}
461    ~awt_text_viewport() OVERRIDE {}
462
463    void awar_changed() OVERRIDE {
464#if defined(DEBUG)
465        printf("awt_text_viewport awar changed!\n");
466#endif // DEBUG
467    }
468    void build_widget(AW_window *aws) OVERRIDE;
469};
470
471
472//  -------------------------------------
473//      class awt_numeric_input_field
474//
475class awt_numeric_input_field : public awt_input_field {
476private:
477    long min, max;
478
479public:
480    awt_numeric_input_field(awt_input_mask_global& global_, const std::string& child_path_, const std::string& label_, int field_width_, long default_value_, long min_, long max_) :
481        awt_input_field(global_, child_path_, label_, field_width_, GBS_global_string("%li", default_value_), GB_FLOAT),
482        min(min_),
483        max(max_)
484    {}
485    ~awt_numeric_input_field() OVERRIDE {}
486
487    std::string awar2db(const std::string& awar_content) const OVERRIDE;
488};
489
490
491//  ---------------------------
492//      class awt_check_box
493//
494class awt_check_box : public awt_string_handler {
495private:
496
497public:
498    awt_check_box(awt_input_mask_global& global_, const std::string& child_path_, const std::string& label_, bool default_checked)
499        : awt_string_handler(global_, child_path_, default_checked ? "yes" : "no", GB_BITS, label_)
500    {}
501    ~awt_check_box() OVERRIDE {}
502
503    std::string awar2db(const std::string& awar_content) const OVERRIDE;
504    std::string db2awar(const std::string& db_content) const OVERRIDE;
505
506    void build_widget(AW_window *aws) OVERRIDE;
507};
508
509//  ------------------------------
510//      class awt_radio_button
511//
512class awt_radio_button : public awt_string_handler {
513private:
514    int            default_position;
515    bool           vertical;
516    std::vector<std::string> buttons; // the awar contains the names of the buttons
517    std::vector<std::string> values; // the database contains the names of the values
518
519public:
520    awt_radio_button(awt_input_mask_global& global_, const std::string& child_path_, const std::string& label_, int default_position_, bool vertical_, const std::vector<std::string>& buttons_, const std::vector<std::string>& values_) :
521        awt_string_handler(global_, child_path_, buttons_[default_position_], GB_STRING, label_),
522        default_position(default_position_),
523        vertical(vertical_),
524        buttons(buttons_),
525        values(values_)
526    {
527        awt_assert(buttons.size() == values.size());
528    }
529    ~awt_radio_button() OVERRIDE {}
530
531    std::string awar2db(const std::string& awar_content) const OVERRIDE;
532    std::string db2awar(const std::string& db_content) const OVERRIDE;
533
534    void build_widget(AW_window *aws) OVERRIDE;
535
536    size_t no_of_toggles() const { return buttons.size(); }
537    size_t default_toggle() const { return default_position; }
538};
539
540
541//  -----------------------------
542//      class awt_input_mask
543//
544// awt_input_mask holds the description of an input mask.
545// an input mask is an i/o-interface to a database entry.
546
547class awt_input_mask FINAL_TYPE : virtual Noncopyable {
548private:
549    awt_input_mask_global  global;
550    awt_mask_item_list     handlers;
551    AW_window_simple      *aws;
552    bool                   shall_reload_on_reinit;
553
554    void link_to(GBDATA *gbitem);
555   
556public:
557    awt_input_mask(AW_root *awr, GBDATA *gb_main, const std::string& mask_name_, awt_item_type itemtype_, bool local, const awt_item_type_selector *sel_, bool test_edit_enabled) :
558        global(awr, gb_main, mask_name_, itemtype_, local, sel_, test_edit_enabled),
559        aws(NULp),
560        shall_reload_on_reinit(false)
561    {}
562    // Initialization is done in awt_create_input_mask
563    // see also :  AWT_initialize_input_mask
564
565    virtual ~awt_input_mask();
566
567    void show() { aws->activate(); }
568    void hide() { aws->hide(); }
569
570    void set_reload_on_reinit(bool dest) { shall_reload_on_reinit = dest; }
571    bool reload_on_reinit() const { return shall_reload_on_reinit; }
572
573    AW_window_simple*& get_window() { return aws; }
574
575    const awt_input_mask_global& mask_global() const { return global; }
576    awt_input_mask_global& mask_global() { return global; }
577
578    void add_handler(awt_mask_item_ptr handler) { handlers.push_back(handler); }
579
580    void relink() { link_to(global.get_selected_item()); }
581    void unlink() { link_to(NULp); }
582};
583
584//  ----------------
585//      casts :
586
587inline const awt_linked_to_item *awt_mask_item::to_linked_item() const { const awt_linked_to_item *linked = dynamic_cast<const awt_linked_to_item*>(this); return linked; }
588inline       awt_linked_to_item *awt_mask_item::to_linked_item()       {       awt_linked_to_item *linked = dynamic_cast<      awt_linked_to_item*>(this); return linked; }
589
590inline const awt_viewport *awt_mask_item::to_viewport() const { const awt_viewport *viewport = dynamic_cast<const awt_viewport*>(this); return viewport; }
591inline       awt_viewport *awt_mask_item::to_viewport()       {       awt_viewport *viewport = dynamic_cast<      awt_viewport*>(this); return viewport; }
592
593#else
594#error awt_input_mask_internal.hxx included twice
595#endif // AWT_INPUT_MASK_INTERNAL_HXX
Note: See TracBrowser for help on using the repository browser.