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 | |
---|
34 | class 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 | |
---|
65 | public: |
---|
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 | return itemtype() == QUERY_ITEM_ORGANISM; |
---|
95 | } |
---|
96 | bool handlesSameItemtypeAs(const InfoWindow& other) const { |
---|
97 | return itemtype() == other.itemtype(); |
---|
98 | } |
---|
99 | |
---|
100 | GBDATA *get_selected_item() const { |
---|
101 | GBDATA *gb_main = get_gbmain(); |
---|
102 | GB_transaction ta(gb_main); |
---|
103 | return getSelector().get_selected_item(gb_main, get_root()); |
---|
104 | } |
---|
105 | |
---|
106 | void map_item(GBDATA *gb_item) const { |
---|
107 | scanner->Map(gb_item, getSelector().change_key_path); |
---|
108 | } |
---|
109 | void map_selected_item() const { map_item(get_selected_item()); } |
---|
110 | void attach_selected_item() const { |
---|
111 | map_selected_item(); |
---|
112 | update_window_title(); |
---|
113 | } |
---|
114 | void reuse() const { |
---|
115 | arb_assert(is_detached()); |
---|
116 | set_used(true); |
---|
117 | aww->activate(); |
---|
118 | attach_selected_item(); |
---|
119 | } |
---|
120 | void reactivate() const { |
---|
121 | arb_assert(is_maininfo()); |
---|
122 | arb_assert(is_used()); |
---|
123 | aww->activate(); // popup existing window |
---|
124 | map_selected_item(); // force item update (did not follow while it was popped-down) |
---|
125 | } |
---|
126 | void hide() const { aww->hide(); } |
---|
127 | |
---|
128 | void bind_to_selected_item() const; |
---|
129 | void add_detach_area(detached_uppopper popup_detached_cb) const; |
---|
130 | |
---|
131 | void display_selected_item() const; |
---|
132 | void detach_selected_item(detached_uppopper popup_detached_cb) const; |
---|
133 | }; |
---|
134 | |
---|
135 | class InfoWindowRegistry { |
---|
136 | typedef arb_unordered_map<AW_window*, InfoWindow::Ptr> WinMap; |
---|
137 | WinMap win; |
---|
138 | |
---|
139 | InfoWindowRegistry(){} // InfoWindowRegistry is a singleton and always exists |
---|
140 | |
---|
141 | public: |
---|
142 | const InfoWindow& registerInfoWindow(AW_window *aww, DbScanner *scanner, int detach_id) { |
---|
143 | // registers a new instance of an InfoWindow |
---|
144 | // returned reference is persistent |
---|
145 | arb_assert(aww && scanner); |
---|
146 | arb_assert(detach_id >= InfoWindow::MAIN_WINDOW); |
---|
147 | |
---|
148 | arb_assert(!find(aww)); |
---|
149 | |
---|
150 | win[aww] = new InfoWindow(aww, scanner, detach_id); |
---|
151 | return *win[aww]; |
---|
152 | } |
---|
153 | |
---|
154 | const InfoWindow* find(AW_window *aww) { |
---|
155 | // returns InfoWindow for 'aww' (or NULp if no such InfoWindow) |
---|
156 | WinMap::iterator found = win.find(aww); |
---|
157 | return found == win.end() ? NULp : &*found->second; |
---|
158 | } |
---|
159 | |
---|
160 | int allocate_detach_id(const InfoWindow& other) { |
---|
161 | arb_assert(other.is_maininfo()); |
---|
162 | |
---|
163 | int maxUsedID = InfoWindow::MAIN_WINDOW; |
---|
164 | for (WinMap::iterator i = win.begin(); i != win.end(); ++i) { |
---|
165 | const InfoWindow::Ptr& info = i->second; |
---|
166 | if (info->handlesSameItemtypeAs(other)) { |
---|
167 | maxUsedID = std::max(maxUsedID, info->getDetachID()); |
---|
168 | } |
---|
169 | } |
---|
170 | return maxUsedID+1; |
---|
171 | } |
---|
172 | const InfoWindow *find_reusable_of_same_type_as(const InfoWindow& other) { |
---|
173 | for (WinMap::iterator i = win.begin(); i != win.end(); ++i) { |
---|
174 | const InfoWindow::Ptr& info = i->second; |
---|
175 | if (info->handlesSameItemtypeAs(other) && !info->is_used()) return &*info; |
---|
176 | } |
---|
177 | return NULp; |
---|
178 | } |
---|
179 | const InfoWindow *find_maininfo_of_same_type_as(const InfoWindow& other) { |
---|
180 | for (WinMap::iterator i = win.begin(); i != win.end(); ++i) { |
---|
181 | const InfoWindow::Ptr& info = i->second; |
---|
182 | if (info->handlesSameItemtypeAs(other) && info->is_used() && info->is_maininfo()) return &*info; |
---|
183 | } |
---|
184 | return NULp; |
---|
185 | } |
---|
186 | |
---|
187 | static InfoWindowRegistry infowin; |
---|
188 | |
---|
189 | static void reactivate(AW_window *aww) { |
---|
190 | const InfoWindow *iwin = infowin.find(aww); |
---|
191 | arb_assert(iwin); // not called with an info-window |
---|
192 | if (iwin) iwin->reactivate(); |
---|
193 | } |
---|
194 | |
---|
195 | static const char *localize_scanner_id(const char *scanner_id, int detach_id) { |
---|
196 | return detach_id == InfoWindow::MAIN_WINDOW |
---|
197 | ? scanner_id |
---|
198 | : GBS_global_string("%s_%i", scanner_id, detach_id); |
---|
199 | } |
---|
200 | }; |
---|
201 | |
---|
202 | #else |
---|
203 | #error info_window.h included twice |
---|
204 | #endif // INFO_WINDOW_H |
---|