source: branches/alilink/SL/DB_UI/info_window.h

Last change on this file was 16768, checked in by westram, 7 years ago
File size: 7.0 KB
Line 
1// ============================================================ //
2//                                                              //
3//   File      : info_window.h                                  //
4//   Purpose   :                                                //
5//                                                              //
6//   Coded by Ralf Westram (coder@reallysoft.de) in July 2013   //
7//   Institute of Microbiology (Technical University Munich)    //
8//   http://www.arb-home.de/                                    //
9//                                                              //
10// ============================================================ //
11
12#ifndef INFO_WINDOW_H
13#define INFO_WINDOW_H
14
15#ifndef AW_WINDOW_HXX
16#include <aw_window.hxx>
17#endif
18#ifndef DB_SCANNER_HXX
19#include <db_scanner.hxx>
20#endif
21#ifndef ARB_MSG_H
22#include <arb_msg.h>
23#endif
24#ifndef ARBDBT_H
25#include <arbdbt.h>
26#endif
27#ifndef ARB_UNORDERED_MAP_H
28#include <arb_unordered_map.h>
29#endif
30
31// --------------------
32//      InfoWindow
33
34class InfoWindow : virtual Noncopyable {
35    AW_window *aww;
36    DbScanner *scanner;
37    int        detach_id;
38
39    mutable bool used; // window in use (i.e. not yet popped down)
40
41    const ItemSelector& getSelector() const { return scanner->get_selector(); }
42    QUERY_ITEM_TYPE itemtype() const { return getSelector().type; }
43    const char *itemname() const { return getSelector().item_name; }
44
45    AW_root *get_root() const { return aww->get_root(); }
46
47    void update_window_title() const {
48        if (is_detached()) { // only change window titles of detached windows
49            char *title         = NULp;
50            char *mapped_item = scanner->get_mapped_item_id();
51            if (mapped_item) {
52                title = GBS_global_string_copy("%s information (%s)", mapped_item, itemname());
53                free(mapped_item);
54            }
55            else {
56                title = GBS_global_string_copy("Press 'Update' to attach selected %s", itemname());
57            }
58
59            arb_assert(title);
60            aww->set_window_title(title);
61            free(title);
62        }
63    }
64
65public:
66
67    static const int MAIN_WINDOW = 0;
68    typedef SmartPtr<InfoWindow> Ptr;
69    typedef void (*detached_uppopper)(AW_window*, const InfoWindow*);
70
71    InfoWindow(AW_window *aww_, DbScanner *scanner_, int detach_id_)
72        : aww(aww_),
73          scanner(scanner_),
74          detach_id(detach_id_),
75          used(true)
76    {}
77    ~InfoWindow() {
78        // @@@ should free 'scanner'
79    }
80
81    bool is_detached() const { return detach_id>MAIN_WINDOW; }
82    bool is_maininfo() const { return detach_id == MAIN_WINDOW; }
83    int getDetachID() const { return detach_id; }
84
85    GBDATA *get_gbmain() const { return scanner->get_gb_main(); }
86
87    bool is_used() const { return used; }
88    void set_used(bool used_) const {
89        arb_assert(!is_maininfo()); // cannot change for maininfo window (it is never reused!)
90        used = used_;
91    }
92
93    bool mapsOrganism() const {
94        const ItemSelector& sel = getSelector();
95
96        return
97            (sel.type == QUERY_ITEM_SPECIES) &&
98            (strcmp(sel.item_name, "organism") == 0);
99    }
100    bool handlesSameItemtypeAs(const InfoWindow& other) const {
101        QUERY_ITEM_TYPE type = itemtype();
102        if (type == other.itemtype()) {
103            return type != QUERY_ITEM_SPECIES || mapsOrganism() == other.mapsOrganism();
104        }
105        return false;
106    }
107
108    GBDATA *get_selected_item() const {
109        GBDATA         *gb_main = get_gbmain();
110        GB_transaction  ta(gb_main);
111        return getSelector().get_selected_item(gb_main, get_root());
112    }
113
114    void map_item(GBDATA *gb_item) const {
115        scanner->Map(gb_item, getSelector().change_key_path);
116    }
117    void map_selected_item() const { map_item(get_selected_item()); }
118    void attach_selected_item() const {
119        map_selected_item();
120        update_window_title();
121    }
122    void reuse() const {
123        arb_assert(is_detached());
124        set_used(true);
125        aww->activate();
126        attach_selected_item();
127    }
128    void reactivate() const {
129        arb_assert(is_maininfo());
130        arb_assert(is_used());
131        aww->activate();     // popup existing window
132        map_selected_item(); // force item update (did not follow while it was popped-down)
133    }
134    void hide() const { aww->hide(); }
135
136    void bind_to_selected_item() const;
137    void add_detach_area(detached_uppopper popup_detached_cb) const;
138
139    void display_selected_item() const;
140    void detach_selected_item(detached_uppopper popup_detached_cb) const;
141};
142
143class InfoWindowRegistry {
144    typedef arb_unordered_map<AW_window*, InfoWindow::Ptr> WinMap;
145    WinMap win;
146
147    InfoWindowRegistry(){} // InfoWindowRegistry is a singleton and always exists
148
149public:
150    const InfoWindow& registerInfoWindow(AW_window *aww, DbScanner *scanner, int detach_id) {
151        // registers a new instance of an InfoWindow
152        // returned reference is persistent
153        arb_assert(aww && scanner);
154        arb_assert(detach_id >= InfoWindow::MAIN_WINDOW);
155
156        arb_assert(!find(aww));
157
158        win[aww] = new InfoWindow(aww, scanner, detach_id);
159        return *win[aww];
160    }
161
162    const InfoWindow* find(AW_window *aww) {
163        // returns InfoWindow for 'aww' (or NULp if no such InfoWindow)
164        WinMap::iterator found = win.find(aww);
165        return found == win.end() ? NULp : &*found->second;
166    }
167
168    int allocate_detach_id(const InfoWindow& other) {
169        arb_assert(other.is_maininfo());
170
171        int maxUsedID = InfoWindow::MAIN_WINDOW;
172        for (WinMap::iterator i = win.begin(); i != win.end(); ++i) {
173            const InfoWindow::Ptr& info = i->second;
174            if (info->handlesSameItemtypeAs(other)) {
175                maxUsedID = std::max(maxUsedID, info->getDetachID());
176            }
177        }
178        return maxUsedID+1;
179    }
180    const InfoWindow *find_reusable_of_same_type_as(const InfoWindow& other) {
181        for (WinMap::iterator i = win.begin(); i != win.end(); ++i) {
182            const InfoWindow::Ptr& info = i->second;
183            if (info->handlesSameItemtypeAs(other) && !info->is_used()) return &*info;
184        }
185        return NULp;
186    }
187    const InfoWindow *find_maininfo_of_same_type_as(const InfoWindow& other) {
188        for (WinMap::iterator i = win.begin(); i != win.end(); ++i) {
189            const InfoWindow::Ptr& info = i->second;
190            if (info->handlesSameItemtypeAs(other) && info->is_used() && info->is_maininfo()) return &*info;
191        }
192        return NULp;
193    }
194
195    static InfoWindowRegistry infowin;
196
197    static void reactivate(AW_window *aww)  {
198        const InfoWindow *iwin = infowin.find(aww);
199        arb_assert(iwin); // not called with an info-window
200        if (iwin) iwin->reactivate();
201    }
202
203    static const char *localize_scanner_id(const char *scanner_id, int detach_id) {
204        return detach_id == InfoWindow::MAIN_WINDOW
205            ? scanner_id
206            : GBS_global_string("%s_%i", scanner_id, detach_id);
207    }
208};
209
210#else
211#error info_window.h included twice
212#endif // INFO_WINDOW_H
Note: See TracBrowser for help on using the repository browser.