| 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 |
|---|