|
@@ -1,6 +1,6 @@
|
|
|
/*
|
|
|
XOWA: the XOWA Offline Wiki Application
|
|
|
-Copyright (C) 2012-2017 gnosygnu@gmail.com
|
|
|
+Copyright (C) 2012-2020 gnosygnu@gmail.com
|
|
|
|
|
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
|
|
or alternatively under the terms of the Apache License Version 2.0.
|
|
@@ -13,264 +13,299 @@ The terms of each license can be found in the source code repository:
|
|
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
|
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
|
|
*/
|
|
|
-package gplx.xowa.guis.views; import gplx.*; import gplx.xowa.*; import gplx.xowa.guis.*;
|
|
|
-import gplx.gfui.*; import gplx.gfui.kits.core.*; import gplx.gfui.draws.*; import gplx.gfui.controls.gxws.*; import gplx.gfui.controls.tabs.*; import gplx.gfui.controls.standards.*;
|
|
|
-import gplx.xowa.apps.apis.xowa.gui.browsers.*; import gplx.xowa.specials.*;
|
|
|
-import gplx.xowa.apps.urls.*;
|
|
|
-public class Xog_tab_mgr implements Gfo_evt_itm {
|
|
|
- private Ordered_hash tab_regy = Ordered_hash_.New(); private int tab_uid = 0;
|
|
|
- private boolean btns__hide_if_one; private int btns__height;
|
|
|
- public Xog_tab_mgr(Xog_win_itm win) {
|
|
|
- this.win = win;
|
|
|
- ev_mgr = new Gfo_evt_mgr(this);
|
|
|
- }
|
|
|
- public Gfo_evt_mgr Evt_mgr() {return ev_mgr;} private Gfo_evt_mgr ev_mgr;
|
|
|
- public Xog_win_itm Win() {return win;} private Xog_win_itm win;
|
|
|
- public Gfui_tab_mgr Tab_mgr() {return tab_mgr;} private Gfui_tab_mgr tab_mgr;
|
|
|
- public int Btns__min_chars() {return btns__min_chars;} private int btns__min_chars;
|
|
|
- public int Btns__max_chars() {return btns__max_chars;} private int btns__max_chars;
|
|
|
- public boolean Javascript_enabled() {return javascript_enabled;} private boolean javascript_enabled = true;
|
|
|
- private byte page_load_mode;
|
|
|
- public boolean Page_load_mode_is_url() {return page_load_mode == Gxw_html_load_tid_.Tid_url;}
|
|
|
- public void Init_by_kit(Gfui_kit kit) {
|
|
|
- tab_mgr = kit.New_tab_mgr("xowa.tab_mgr", win.Win_box());
|
|
|
- active_tab = Xog_tab_itm_.Null;
|
|
|
- Gfo_evt_mgr_.Sub_same_many(tab_mgr, this, Gfui_tab_mgr.Evt_tab_selected, Gfui_tab_mgr.Evt_tab_closed, Gfui_tab_mgr.Evt_tab_switched);
|
|
|
- win.App().Cfg().Bind_many_app(this, Cfg__page_load_mode
|
|
|
- , Cfg__place_on_top, Cfg__height, Cfg__hide_if_one, Cfg__curved, Cfg__close_btn_visible, Cfg__unselected_close_btn_visible, Cfg__max_chars, Cfg__min_chars);
|
|
|
- }
|
|
|
- public Xog_tab_itm Active_tab() {return active_tab;} private Xog_tab_itm active_tab;
|
|
|
- public Xog_tab_itm Active_tab_assert() {
|
|
|
- if (active_tab == Xog_tab_itm_.Null) this.Tabs_new_dflt(true);
|
|
|
- return active_tab;
|
|
|
- }
|
|
|
- public boolean Active_tab_is_null() {return active_tab == Xog_tab_itm_.Null;}
|
|
|
- private void Btns_text_recalc() {
|
|
|
- int len = this.Tabs_len();
|
|
|
- for (int i = 0; i < len; i++) {
|
|
|
- Xog_tab_itm tab_itm = this.Tabs_get_at(i);
|
|
|
- tab_itm.Tab_name_();
|
|
|
- }
|
|
|
- }
|
|
|
- public int Tabs_len() {return tab_regy.Count();}
|
|
|
- public Xog_tab_itm Tabs_new_init(Xowe_wiki wiki, Xoae_page page) {return this.Tabs_new(true, true, wiki, page);}
|
|
|
- public Xog_tab_itm Tabs_get_at(int i) {return (Xog_tab_itm)tab_regy.Get_at(i);}
|
|
|
- public Xog_tab_itm Tabs_new_dflt() {return Tabs_new_dflt(false);}
|
|
|
- public Xog_tab_itm Tabs_new_dflt(boolean focus) {
|
|
|
- boolean active_tab_is_null = this.Active_tab_is_null();
|
|
|
- Xowe_wiki cur_wiki = active_tab_is_null ? win.App().Usere().Wiki() : active_tab.Wiki();
|
|
|
- Xoa_ttl ttl = Xoa_ttl.Parse(cur_wiki, Xow_special_meta_.Itm__default_tab.Ttl_bry());
|
|
|
- Xoa_url url = cur_wiki.Utl__url_parser().Parse_by_urlbar_or_null(ttl.Full_db_as_str()); if (url == null) throw Err_.new_("url", "invalid url", "url", url);
|
|
|
- Xog_tab_itm rv = Tabs_new(focus, active_tab_is_null, cur_wiki, Xoae_page.New(cur_wiki, ttl));
|
|
|
- rv.Page_update_ui();
|
|
|
- rv.Show_url_bgn(url);
|
|
|
- return rv;
|
|
|
- }
|
|
|
- private Xog_tab_itm Tabs_new(boolean focus, boolean active_tab_is_null, Xowe_wiki wiki, Xoae_page page) {
|
|
|
- String tab_key = "tab_" + Int_.To_str(tab_uid++); int tab_idx = tab_regy.Count();
|
|
|
- Gfui_tab_itm_data tab_data = new Gfui_tab_itm_data(tab_key, tab_idx);
|
|
|
- Xog_tab_itm rv = new Xog_tab_itm(this, tab_data, wiki, page);
|
|
|
- Gfui_tab_itm tab_box = tab_mgr.Tabs_add(tab_data);
|
|
|
- rv.Make_html_box(tab_uid, tab_box, win, tab_mgr);
|
|
|
- rv.Html_itm().Js_enabled_(javascript_enabled);
|
|
|
- tab_box.Subs_add(rv.Html_itm().Html_box());
|
|
|
- tab_regy.Add(tab_key, rv);
|
|
|
- if ( focus
|
|
|
- || active_tab_is_null // NOTE: must select 1st tab, else nothing will show in tab box
|
|
|
- ) {
|
|
|
- tab_mgr.Tabs_select_by_idx(rv.Tab_idx());
|
|
|
- active_tab = rv;
|
|
|
- }
|
|
|
- Tabs_hide_if_one_chk(false);
|
|
|
- return rv;
|
|
|
- }
|
|
|
- public void Tabs_new_dupe(boolean focus) {
|
|
|
- if (this.Active_tab_is_null()) return;
|
|
|
- String url = active_tab.Page().Url().To_str();
|
|
|
- Tabs_new_dflt(focus);
|
|
|
- win.Page__navigate_by_url_bar(url);
|
|
|
- }
|
|
|
- public void Tabs_javascript_enabled_(boolean v) {
|
|
|
- this.javascript_enabled = v;
|
|
|
- int len = tab_regy.Count();
|
|
|
- for (int i = 0; i < len; i++) {
|
|
|
- Xog_tab_itm tab = Tabs_get_by_idx_or_warn(i);
|
|
|
- tab.Html_itm().Js_enabled_(v);
|
|
|
- }
|
|
|
- }
|
|
|
- private void Tabs_selected(String key) {
|
|
|
- Xog_tab_itm tab = Tabs_get_by_key_or_warn(key); if (tab == null) return;
|
|
|
- active_tab = tab;
|
|
|
- Xoae_page page = tab.Page();
|
|
|
- Xog_tab_itm_read_mgr.Update_selected_tab(win, page.Url(), page.Ttl());
|
|
|
- tab.Html_itm().Tab_selected(page);
|
|
|
- }
|
|
|
- public void Tabs_close_cur() {
|
|
|
- if (this.Active_tab_is_null()) return;
|
|
|
- Tabs__pub_close(active_tab);
|
|
|
- tab_mgr.Tabs_close_by_idx(active_tab.Tab_idx());
|
|
|
- Xog_tab_itm cur_tab = this.Active_tab(); // get new current tab for line below
|
|
|
- if (cur_tab != null) cur_tab.Html_box().Focus(); // NOTE: needed to focus tab box else tab button will be focused; DATE:2014-07-13
|
|
|
- }
|
|
|
- public void Tabs_close_others() {this.Tabs_close_to_bgn(); this.Tabs_close_to_end();}
|
|
|
- public void Tabs_close_to_bgn() {if (Active_tab_is_null()) return; Tabs_close_rng(0 , active_tab.Tab_idx());}
|
|
|
- public void Tabs_close_to_end() {if (Active_tab_is_null()) return; Tabs_close_rng(active_tab.Tab_idx() + 1 , tab_regy.Count());}
|
|
|
- public void Tabs_close_rng(int bgn, int end) {
|
|
|
- for (int i = bgn; i < end; i++) {
|
|
|
- Xog_tab_itm tab = Tabs_get_at(bgn);
|
|
|
- if (!Tabs__pub_close(tab)) return;
|
|
|
- }
|
|
|
- for (int i = bgn; i < end; i++)
|
|
|
- tab_mgr.Tabs_close_by_idx(bgn); // NOTE: close at bgn, not at i, b/c each close will remove a tab from collection
|
|
|
- }
|
|
|
- public boolean Tabs__pub_close_all() {return Tabs__pub_close_rng(0, this.Tabs_len());}
|
|
|
- public boolean Tabs__pub_close_rng(int bgn, int end) {
|
|
|
- boolean rv = true;
|
|
|
- for (int i = bgn; i < end; i++) {
|
|
|
- Xog_tab_itm tab = Tabs_get_at(i);
|
|
|
- boolean close_allowed = Tabs__pub_close(tab);
|
|
|
- if (!close_allowed) rv = false;
|
|
|
- }
|
|
|
- return rv;
|
|
|
- }
|
|
|
- public boolean Tabs__pub_close(Xog_tab_itm tab) {
|
|
|
- return tab.Page().Tab_data().Close_mgr().When_close(tab, Xoa_url.Null);
|
|
|
- }
|
|
|
- public void Tabs_close_undo() {
|
|
|
- if (closed_undo_list.Count() == 0) return;
|
|
|
- String url = (String)List_adp_.Pop(closed_undo_list);
|
|
|
- Tabs_new_dflt(true);
|
|
|
- win.Page__navigate_by_url_bar(url);
|
|
|
- }
|
|
|
- private List_adp closed_undo_list = List_adp_.New();
|
|
|
- private void Tabs_closed(String key) {
|
|
|
- Xog_tab_itm itm = Tabs_get_by_key_or_warn(key); if (itm == null) return;
|
|
|
- itm.Html_box().Html_dispose();
|
|
|
- closed_undo_list.Add(itm.Page().Url().To_str());
|
|
|
- tab_regy.Del(key);
|
|
|
- if (tab_regy.Count() == 0) {
|
|
|
- active_tab = Xog_tab_itm_.Null;
|
|
|
- Xog_tab_itm_read_mgr.Update_selected_tab_blank(win);
|
|
|
- }
|
|
|
- else
|
|
|
- Tabs_recalc_idx();
|
|
|
- Tabs_hide_if_one_chk(false);
|
|
|
- }
|
|
|
- private Xog_tab_itm Tabs_get_by_key_or_warn(String key) {
|
|
|
- Xog_tab_itm rv = (Xog_tab_itm)tab_regy.Get_by(key); if (rv == null) win.App().Usr_dlg().Warn_many("", "", "tab.selected could not find tab; key={0}", key);
|
|
|
- return rv;
|
|
|
- }
|
|
|
- private Xog_tab_itm Tabs_get_by_idx_or_warn(int idx) {
|
|
|
- Xog_tab_itm rv = (Xog_tab_itm)tab_regy.Get_at(idx); if (rv == null) win.App().Usr_dlg().Warn_many("", "", "tab.selected could not find tab; idx={0}", idx);
|
|
|
- return rv;
|
|
|
- }
|
|
|
- private void Tabs_recalc_idx() {
|
|
|
- int len = tab_regy.Count();
|
|
|
- for (int i = 0; i < len; i++) {
|
|
|
- Xog_tab_itm itm = Tabs_get_by_idx_or_warn(i);
|
|
|
- itm.Tab_idx_(i);
|
|
|
- }
|
|
|
- }
|
|
|
- public void Tabs_select(boolean fwd) {
|
|
|
- if (this.Active_tab_is_null()) return;
|
|
|
- int new_idx = TabBox_.Cycle(fwd, active_tab.Tab_idx(), tab_regy.Count());
|
|
|
- tab_mgr.Tabs_select_by_idx(new_idx);
|
|
|
- }
|
|
|
- public void Tabs_select_by_idx(int v) {
|
|
|
- if (v < 0 || v >= tab_regy.Count()) return;
|
|
|
- tab_mgr.Tabs_select_by_idx(v);
|
|
|
- }
|
|
|
- public void Tabs_move(boolean fwd) {
|
|
|
- if (this.Active_tab_is_null()) return;
|
|
|
- int src_idx = active_tab.Tab_idx();
|
|
|
- int trg_idx = TabBox_.Cycle(fwd, src_idx, tab_regy.Count());
|
|
|
- tab_mgr.Tabs_switch(src_idx, trg_idx);
|
|
|
- }
|
|
|
- private void Tabs_switched(String src_key, String trg_key) {
|
|
|
- Xog_tab_itm src_itm = Tabs_get_by_key_or_warn(src_key);
|
|
|
- Xog_tab_itm trg_itm = Tabs_get_by_key_or_warn(trg_key);
|
|
|
- src_itm.Switch_mem(trg_itm);
|
|
|
- active_tab = trg_itm; // NOTE: src_itm initiated switch, but trg_itm is now active b/c everything in src_itm has now been reparented to trg_itm; DATE:2014-05-12
|
|
|
- }
|
|
|
- public void Tabs_new_link(boolean focus, String link) { // handle empty link
|
|
|
- if (String_.Len_eq_0(link)) {
|
|
|
- if (this.Active_tab_is_null()) return;
|
|
|
- link = gplx.langs.htmls.encoders.Gfo_url_encoder_.Http_url.Decode_str(active_tab.Html_itm().Html_selected_get_active_or_selection()); // NOTE: must decode else url-encoded special pages don't work; EX:home/wiki/Special:XowaCfg%3Fgrp%3Dxowa.html.css; DATE:2017-01-02
|
|
|
- }
|
|
|
- if (String_.Len_eq_0(link)) {win.App().Usr_dlg().Prog_many("", "", "no link or text selected"); return;}
|
|
|
- Tabs_new_link(link, focus);
|
|
|
- }
|
|
|
- public void Tabs_new_link(String link, boolean focus) {
|
|
|
- Xowe_wiki wiki = active_tab.Wiki();
|
|
|
- Xog_tab_itm new_tab = Tabs_new(focus, false, wiki, Xoae_page.New(wiki, active_tab.Page().Ttl())); // NOTE: do not use ttl from link, else middle-clicking pages with anchors won't work; DATE:2015-05-03
|
|
|
- Xoa_url url = wiki.Utl__url_parser().Parse_by_urlbar_or_null(link); if (url == null) return; // NOTE: link must be of form domain/wiki/page; DATE:2014-05-27
|
|
|
- new_tab.Show_url_bgn(url);
|
|
|
- if (focus)
|
|
|
- tab_mgr.Tabs_select_by_idx(new_tab.Tab_idx());
|
|
|
- }
|
|
|
- private void Tabs_hide_if_one_chk(boolean force) {
|
|
|
- if (btns__hide_if_one || force) {// run code only if enabled or forced
|
|
|
- if (tab_regy.Count() == 1) {
|
|
|
- int desired_height = btns__hide_if_one ? 0 : btns__height;
|
|
|
- if (tab_mgr.Btns_height() != desired_height)
|
|
|
- tab_mgr.Btns_height_(desired_height);
|
|
|
- }
|
|
|
- else {
|
|
|
- if (tab_mgr.Btns_height() != btns__height)
|
|
|
- tab_mgr.Btns_height_(btns__height);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
|
|
|
- if (ctx.Match(k, Invk_tabs_new_dflt__at_dflt__focus_y)) Tabs_new_dflt(Bool_.Y);
|
|
|
- else if (ctx.Match(k, Invk_tabs_new_link__at_dflt__focus_n)) Tabs_new_link(Bool_.N, m.ReadStrOr("v", null));
|
|
|
- else if (ctx.Match(k, Invk_tabs_new_link__at_dflt__focus_y)) Tabs_new_link(Bool_.Y, m.ReadStrOr("v", null));
|
|
|
- else if (ctx.Match(k, Gfui_tab_mgr.Evt_tab_selected)) Tabs_selected(m.ReadStr("key"));
|
|
|
- else if (ctx.Match(k, Gfui_tab_mgr.Evt_tab_closed)) Tabs_closed(m.ReadStr("key"));
|
|
|
- else if (ctx.Match(k, Gfui_tab_mgr.Evt_tab_switched)) Tabs_switched(m.ReadStr("src"), m.ReadStr("trg"));
|
|
|
- else if (ctx.Match(k, Invk_tabs_close_cur)) Tabs_close_cur();
|
|
|
- else if (ctx.Match(k, Invk_tabs_select_bwd)) Tabs_select(Bool_.N);
|
|
|
- else if (ctx.Match(k, Invk_tabs_select_fwd)) Tabs_select(Bool_.Y);
|
|
|
- else if (ctx.Match(k, Invk_tabs_switch_cur_bwd)) Tabs_move(Bool_.N);
|
|
|
- else if (ctx.Match(k, Invk_tabs_switch_cur_fwd)) Tabs_move(Bool_.Y);
|
|
|
-
|
|
|
- else if (ctx.Match(k, Cfg__place_on_top)) tab_mgr.Btns_place_on_top_(m.ReadYn("v"));
|
|
|
- else if (ctx.Match(k, Cfg__height)) {btns__height = m.ReadInt("v"); tab_mgr.Btns_height_(btns__height);}
|
|
|
- else if (ctx.Match(k, Cfg__hide_if_one)) {btns__hide_if_one = m.ReadYn("v"); Tabs_hide_if_one_chk(true);}
|
|
|
- else if (ctx.Match(k, Cfg__curved)) tab_mgr.Btns_curved_(m.ReadYn("v"));
|
|
|
- else if (ctx.Match(k, Cfg__close_btn_visible)) tab_mgr.Btns_close_visible_(m.ReadYn("v"));
|
|
|
- else if (ctx.Match(k, Cfg__unselected_close_btn_visible)) tab_mgr.Btns_unselected_close_visible_(m.ReadYn("v"));
|
|
|
- else if (ctx.Match(k, Cfg__max_chars)) {btns__max_chars = m.ReadInt("v"); Btns_text_recalc();}
|
|
|
- else if (ctx.Match(k, Cfg__min_chars)) {btns__min_chars = m.ReadInt("v"); Btns_text_recalc();}
|
|
|
-
|
|
|
- else if (ctx.Match(k, Cfg__javascript_enabled)) Tabs_javascript_enabled_(m.ReadYnOrY("v")); // NOTE: must be "OrY" else broken cfg.db will break cfg_maint; DATE:2016-12-15
|
|
|
- else if (ctx.Match(k, Cfg__page_load_mode)) Page_load_mode_(m.ReadStr("v"));
|
|
|
- else return Gfo_invk_.Rv_unhandled;
|
|
|
- return this;
|
|
|
- }
|
|
|
- private void Page_load_mode_(String v) {
|
|
|
- page_load_mode = Gxw_html_load_tid_.Xto_tid(v);
|
|
|
- // Gfo_evt_mgr_.Pub_val(this, Evt_load_tid_changed, load_tid);
|
|
|
- }
|
|
|
-
|
|
|
- public static final String
|
|
|
- Invk_tabs_select_fwd = "tabs_select_fwd" , Invk_tabs_select_bwd = "tabs_select_bwd"
|
|
|
- , Invk_tabs_switch_cur_fwd = "tabs_switch_cur_fwd" , Invk_tabs_switch_cur_bwd = "tabs_switch_cur_bwd"
|
|
|
- , Invk_tabs_new_dflt__at_dflt__focus_y = "tabs_new_dflt__at_dflt__focus_y"
|
|
|
- , Invk_tabs_new_link__at_dflt__focus_n = "tabs_new_link__at_dflt__focus_n"
|
|
|
- , Invk_tabs_new_link__at_dflt__focus_y = "tabs_new_link__at_dflt__focus_y"
|
|
|
- , Invk_tabs_close_cur = "tabs_close_cur"
|
|
|
- ;
|
|
|
- private static final String
|
|
|
- Cfg__place_on_top = "xowa.gui.tabs.place_on_top"
|
|
|
- , Cfg__height = "xowa.gui.tabs.height"
|
|
|
- , Cfg__hide_if_one = "xowa.gui.tabs.hide_if_one"
|
|
|
- , Cfg__curved = "xowa.gui.tabs.curved"
|
|
|
- , Cfg__close_btn_visible = "xowa.gui.tabs.close_btn_visible"
|
|
|
- , Cfg__unselected_close_btn_visible = "xowa.gui.tabs.unselected_close_btn_visible"
|
|
|
- , Cfg__max_chars = "xowa.gui.tabs.max_chars"
|
|
|
- , Cfg__min_chars = "xowa.gui.tabs.min_chars"
|
|
|
- , Cfg__javascript_enabled = "xowa.gui.html_box.javascript_enabled"
|
|
|
- , Cfg__page_load_mode = "xowa.gui.html_box.page_load_mode"
|
|
|
- ;
|
|
|
-}
|
|
|
+package gplx.xowa.guis.views;
|
|
|
+
|
|
|
+import gplx.Bool_;
|
|
|
+import gplx.Err_;
|
|
|
+import gplx.GfoMsg;
|
|
|
+import gplx.Gfo_evt_itm;
|
|
|
+import gplx.Gfo_evt_mgr;
|
|
|
+import gplx.Gfo_evt_mgr_;
|
|
|
+import gplx.Gfo_invk_;
|
|
|
+import gplx.GfsCtx;
|
|
|
+import gplx.Int_;
|
|
|
+import gplx.List_adp;
|
|
|
+import gplx.List_adp_;
|
|
|
+import gplx.Ordered_hash;
|
|
|
+import gplx.Ordered_hash_;
|
|
|
+import gplx.String_;
|
|
|
+import gplx.gfui.controls.gxws.Gxw_html_load_tid_;
|
|
|
+import gplx.gfui.controls.standards.Gfui_tab_itm;
|
|
|
+import gplx.gfui.controls.standards.Gfui_tab_itm_data;
|
|
|
+import gplx.gfui.controls.standards.Gfui_tab_mgr;
|
|
|
+import gplx.gfui.controls.tabs.TabBox_;
|
|
|
+import gplx.gfui.kits.core.Gfui_kit;
|
|
|
+import gplx.gfui.kits.swts.Swt_html_utl;
|
|
|
+import gplx.xowa.Xoa_ttl;
|
|
|
+import gplx.xowa.Xoa_url;
|
|
|
+import gplx.xowa.Xoae_page;
|
|
|
+import gplx.xowa.Xowe_wiki;
|
|
|
+import gplx.xowa.htmls.hrefs.Xoh_href_;
|
|
|
+import gplx.xowa.specials.Xow_special_meta_;
|
|
|
+
|
|
|
+public class Xog_tab_mgr implements Gfo_evt_itm {
|
|
|
+ private Ordered_hash tab_regy = Ordered_hash_.New(); private int tab_uid = 0;
|
|
|
+ private boolean btns__hide_if_one; private int btns__height;
|
|
|
+ public Xog_tab_mgr(Xog_win_itm win) {
|
|
|
+ this.win = win;
|
|
|
+ ev_mgr = new Gfo_evt_mgr(this);
|
|
|
+ }
|
|
|
+ public Gfo_evt_mgr Evt_mgr() {return ev_mgr;} private Gfo_evt_mgr ev_mgr;
|
|
|
+ public Xog_win_itm Win() {return win;} private Xog_win_itm win;
|
|
|
+ public Gfui_tab_mgr Tab_mgr() {return tab_mgr;} private Gfui_tab_mgr tab_mgr;
|
|
|
+ public int Btns__min_chars() {return btns__min_chars;} private int btns__min_chars;
|
|
|
+ public int Btns__max_chars() {return btns__max_chars;} private int btns__max_chars;
|
|
|
+ public boolean Javascript_enabled() {return javascript_enabled;} private boolean javascript_enabled = true;
|
|
|
+ private byte page_load_mode;
|
|
|
+ public boolean Page_load_mode_is_url() {return page_load_mode == Gxw_html_load_tid_.Tid_url;}
|
|
|
+ public void Init_by_kit(Gfui_kit kit) {
|
|
|
+ tab_mgr = kit.New_tab_mgr("xowa.tab_mgr", win.Win_box());
|
|
|
+ active_tab = Xog_tab_itm_.Null;
|
|
|
+ Gfo_evt_mgr_.Sub_same_many(tab_mgr, this, Gfui_tab_mgr.Evt_tab_selected, Gfui_tab_mgr.Evt_tab_closed, Gfui_tab_mgr.Evt_tab_switched);
|
|
|
+ win.App().Cfg().Bind_many_app(this, Cfg__page_load_mode
|
|
|
+ , Cfg__place_on_top, Cfg__height, Cfg__hide_if_one, Cfg__curved, Cfg__close_btn_visible, Cfg__unselected_close_btn_visible, Cfg__max_chars, Cfg__min_chars);
|
|
|
+ }
|
|
|
+ public Xog_tab_itm Active_tab() {return active_tab;} private Xog_tab_itm active_tab;
|
|
|
+ public Xog_tab_itm Active_tab_assert() {
|
|
|
+ if (active_tab == Xog_tab_itm_.Null) this.Tabs_new_dflt(true);
|
|
|
+ return active_tab;
|
|
|
+ }
|
|
|
+ public boolean Active_tab_is_null() {return active_tab == Xog_tab_itm_.Null;}
|
|
|
+ private void Btns_text_recalc() {
|
|
|
+ int len = this.Tabs_len();
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
+ Xog_tab_itm tab_itm = this.Tabs_get_at(i);
|
|
|
+ tab_itm.Tab_name_();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public int Tabs_len() {return tab_regy.Count();}
|
|
|
+ public Xog_tab_itm Tabs_new_init(Xowe_wiki wiki, Xoae_page page) {return this.Tabs_new(true, true, wiki, page);}
|
|
|
+ public Xog_tab_itm Tabs_get_at(int i) {return (Xog_tab_itm)tab_regy.Get_at(i);}
|
|
|
+ public Xog_tab_itm Tabs_new_dflt() {return Tabs_new_dflt(false);}
|
|
|
+ public Xog_tab_itm Tabs_new_dflt(boolean focus) {
|
|
|
+ boolean active_tab_is_null = this.Active_tab_is_null();
|
|
|
+ Xowe_wiki cur_wiki = active_tab_is_null ? win.App().Usere().Wiki() : active_tab.Wiki();
|
|
|
+ Xoa_ttl ttl = Xoa_ttl.Parse(cur_wiki, Xow_special_meta_.Itm__default_tab.Ttl_bry());
|
|
|
+ Xoa_url url = cur_wiki.Utl__url_parser().Parse_by_urlbar_or_null(ttl.Full_db_as_str()); if (url == null) throw Err_.new_("url", "invalid url", "url", url);
|
|
|
+ Xog_tab_itm rv = Tabs_new(focus, active_tab_is_null, cur_wiki, Xoae_page.New(cur_wiki, ttl));
|
|
|
+ rv.Page_update_ui();
|
|
|
+ rv.Show_url_bgn(url);
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+ private Xog_tab_itm Tabs_new(boolean focus, boolean active_tab_is_null, Xowe_wiki wiki, Xoae_page page) {
|
|
|
+ String tab_key = "tab_" + Int_.To_str(tab_uid++); int tab_idx = tab_regy.Count();
|
|
|
+ Gfui_tab_itm_data tab_data = new Gfui_tab_itm_data(tab_key, tab_idx);
|
|
|
+ Xog_tab_itm rv = new Xog_tab_itm(this, tab_data, wiki, page);
|
|
|
+ Gfui_tab_itm tab_box = tab_mgr.Tabs_add(tab_data);
|
|
|
+ rv.Make_html_box(tab_uid, tab_box, win, tab_mgr);
|
|
|
+ rv.Html_itm().Js_enabled_(javascript_enabled);
|
|
|
+ tab_box.Subs_add(rv.Html_itm().Html_box());
|
|
|
+ tab_regy.Add(tab_key, rv);
|
|
|
+ if ( focus
|
|
|
+ || active_tab_is_null // NOTE: must select 1st tab, else nothing will show in tab box
|
|
|
+ ) {
|
|
|
+ tab_mgr.Tabs_select_by_idx(rv.Tab_idx());
|
|
|
+ active_tab = rv;
|
|
|
+ }
|
|
|
+ Tabs_hide_if_one_chk(false);
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+ public void Tabs_new_dupe(boolean focus) {
|
|
|
+ if (this.Active_tab_is_null()) return;
|
|
|
+ String url = active_tab.Page().Url().To_str();
|
|
|
+ Tabs_new_dflt(focus);
|
|
|
+ win.Page__navigate_by_url_bar(url);
|
|
|
+ }
|
|
|
+ public void Tabs_javascript_enabled_(boolean v) {
|
|
|
+ this.javascript_enabled = v;
|
|
|
+ int len = tab_regy.Count();
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
+ Xog_tab_itm tab = Tabs_get_by_idx_or_warn(i);
|
|
|
+ tab.Html_itm().Js_enabled_(v);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private void Tabs_selected(String key) {
|
|
|
+ Xog_tab_itm tab = Tabs_get_by_key_or_warn(key); if (tab == null) return;
|
|
|
+ active_tab = tab;
|
|
|
+ Xoae_page page = tab.Page();
|
|
|
+ Xog_tab_itm_read_mgr.Update_selected_tab(win, page.Url(), page.Ttl());
|
|
|
+ tab.Html_itm().Tab_selected(page);
|
|
|
+ }
|
|
|
+ public void Tabs_close_cur() {
|
|
|
+ if (this.Active_tab_is_null()) return;
|
|
|
+ Tabs__pub_close(active_tab);
|
|
|
+ tab_mgr.Tabs_close_by_idx(active_tab.Tab_idx());
|
|
|
+ Xog_tab_itm cur_tab = this.Active_tab(); // get new current tab for line below
|
|
|
+ if (cur_tab != null) cur_tab.Html_box().Focus(); // NOTE: needed to focus tab box else tab button will be focused; DATE:2014-07-13
|
|
|
+ }
|
|
|
+ public void Tabs_close_others() {this.Tabs_close_to_bgn(); this.Tabs_close_to_end();}
|
|
|
+ public void Tabs_close_to_bgn() {if (Active_tab_is_null()) return; Tabs_close_rng(0 , active_tab.Tab_idx());}
|
|
|
+ public void Tabs_close_to_end() {if (Active_tab_is_null()) return; Tabs_close_rng(active_tab.Tab_idx() + 1 , tab_regy.Count());}
|
|
|
+ public void Tabs_close_rng(int bgn, int end) {
|
|
|
+ for (int i = bgn; i < end; i++) {
|
|
|
+ Xog_tab_itm tab = Tabs_get_at(bgn);
|
|
|
+ if (!Tabs__pub_close(tab)) return;
|
|
|
+ }
|
|
|
+ for (int i = bgn; i < end; i++)
|
|
|
+ tab_mgr.Tabs_close_by_idx(bgn); // NOTE: close at bgn, not at i, b/c each close will remove a tab from collection
|
|
|
+ }
|
|
|
+ public boolean Tabs__pub_close_all() {return Tabs__pub_close_rng(0, this.Tabs_len());}
|
|
|
+ public boolean Tabs__pub_close_rng(int bgn, int end) {
|
|
|
+ boolean rv = true;
|
|
|
+ for (int i = bgn; i < end; i++) {
|
|
|
+ Xog_tab_itm tab = Tabs_get_at(i);
|
|
|
+ boolean close_allowed = Tabs__pub_close(tab);
|
|
|
+ if (!close_allowed) rv = false;
|
|
|
+ }
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+ public boolean Tabs__pub_close(Xog_tab_itm tab) {
|
|
|
+ return tab.Page().Tab_data().Close_mgr().When_close(tab, Xoa_url.Null);
|
|
|
+ }
|
|
|
+ public void Tabs_close_undo() {
|
|
|
+ if (closed_undo_list.Count() == 0) return;
|
|
|
+ String url = (String)List_adp_.Pop(closed_undo_list);
|
|
|
+ Tabs_new_dflt(true);
|
|
|
+ win.Page__navigate_by_url_bar(url);
|
|
|
+ }
|
|
|
+ private List_adp closed_undo_list = List_adp_.New();
|
|
|
+ private void Tabs_closed(String key) {
|
|
|
+ Xog_tab_itm itm = Tabs_get_by_key_or_warn(key); if (itm == null) return;
|
|
|
+ itm.Html_box().Html_dispose();
|
|
|
+ closed_undo_list.Add(itm.Page().Url().To_str());
|
|
|
+ tab_regy.Del(key);
|
|
|
+ if (tab_regy.Count() == 0) {
|
|
|
+ active_tab = Xog_tab_itm_.Null;
|
|
|
+ Xog_tab_itm_read_mgr.Update_selected_tab_blank(win);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ Tabs_recalc_idx();
|
|
|
+ Tabs_hide_if_one_chk(false);
|
|
|
+ }
|
|
|
+ private Xog_tab_itm Tabs_get_by_key_or_warn(String key) {
|
|
|
+ Xog_tab_itm rv = (Xog_tab_itm)tab_regy.Get_by(key); if (rv == null) win.App().Usr_dlg().Warn_many("", "", "tab.selected could not find tab; key={0}", key);
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+ private Xog_tab_itm Tabs_get_by_idx_or_warn(int idx) {
|
|
|
+ Xog_tab_itm rv = (Xog_tab_itm)tab_regy.Get_at(idx); if (rv == null) win.App().Usr_dlg().Warn_many("", "", "tab.selected could not find tab; idx={0}", idx);
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+ private void Tabs_recalc_idx() {
|
|
|
+ int len = tab_regy.Count();
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
+ Xog_tab_itm itm = Tabs_get_by_idx_or_warn(i);
|
|
|
+ itm.Tab_idx_(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public void Tabs_select(boolean fwd) {
|
|
|
+ if (this.Active_tab_is_null()) return;
|
|
|
+ int new_idx = TabBox_.Cycle(fwd, active_tab.Tab_idx(), tab_regy.Count());
|
|
|
+ tab_mgr.Tabs_select_by_idx(new_idx);
|
|
|
+ }
|
|
|
+ public void Tabs_select_by_idx(int v) {
|
|
|
+ if (v < 0 || v >= tab_regy.Count()) return;
|
|
|
+ tab_mgr.Tabs_select_by_idx(v);
|
|
|
+ }
|
|
|
+ public void Tabs_move(boolean fwd) {
|
|
|
+ if (this.Active_tab_is_null()) return;
|
|
|
+ int src_idx = active_tab.Tab_idx();
|
|
|
+ int trg_idx = TabBox_.Cycle(fwd, src_idx, tab_regy.Count());
|
|
|
+ tab_mgr.Tabs_switch(src_idx, trg_idx);
|
|
|
+ }
|
|
|
+ private void Tabs_switched(String src_key, String trg_key) {
|
|
|
+ Xog_tab_itm src_itm = Tabs_get_by_key_or_warn(src_key);
|
|
|
+ Xog_tab_itm trg_itm = Tabs_get_by_key_or_warn(trg_key);
|
|
|
+ src_itm.Switch_mem(trg_itm);
|
|
|
+ active_tab = trg_itm; // NOTE: src_itm initiated switch, but trg_itm is now active b/c everything in src_itm has now been reparented to trg_itm; DATE:2014-05-12
|
|
|
+ }
|
|
|
+ public void Tabs_new_link(boolean focus, String link) { // handle empty link
|
|
|
+ if (String_.Len_eq_0(link)) {
|
|
|
+ if (this.Active_tab_is_null()) return;
|
|
|
+ link = active_tab.Html_itm().Html_selected_get_active_or_selection();
|
|
|
+ // 2020-12-16|ISSUE#:823|Open in new tab creates links like `about:/wiki/PAGE_NAME` or `about:/site/WIKI_NAME/wiki/PAGE_NAME`
|
|
|
+ link = Swt_html_utl.NormalizeSwtUrl(link);
|
|
|
+ if (link.startsWith(Xoh_href_.Str__site)) {
|
|
|
+ link = link.substring(Xoh_href_.Str__site.length());
|
|
|
+ }
|
|
|
+ else if (link.startsWith(Xoh_href_.Str__wiki)) {
|
|
|
+ link = active_tab.Wiki().Domain_str() + link;
|
|
|
+ }
|
|
|
+ link = gplx.langs.htmls.encoders.Gfo_url_encoder_.Http_url.Decode_str(link); // NOTE: must decode else url-encoded special pages don't work; EX:home/wiki/Special:XowaCfg%3Fgrp%3Dxowa.html.css; DATE:2017-01-02
|
|
|
+ }
|
|
|
+ if (String_.Len_eq_0(link)) {win.App().Usr_dlg().Prog_many("", "", "no link or text selected"); return;}
|
|
|
+ Tabs_new_link(link, focus);
|
|
|
+ }
|
|
|
+ public void Tabs_new_link(String link, boolean focus) {
|
|
|
+ Xowe_wiki wiki = active_tab.Wiki();
|
|
|
+ Xog_tab_itm new_tab = Tabs_new(focus, false, wiki, Xoae_page.New(wiki, active_tab.Page().Ttl())); // NOTE: do not use ttl from link, else middle-clicking pages with anchors won't work; DATE:2015-05-03
|
|
|
+ Xoa_url url = wiki.Utl__url_parser().Parse_by_urlbar_or_null(link); if (url == null) return; // NOTE: link must be of form domain/wiki/page; DATE:2014-05-27
|
|
|
+ new_tab.Show_url_bgn(url);
|
|
|
+ if (focus)
|
|
|
+ tab_mgr.Tabs_select_by_idx(new_tab.Tab_idx());
|
|
|
+ }
|
|
|
+ private void Tabs_hide_if_one_chk(boolean force) {
|
|
|
+ if (btns__hide_if_one || force) {// run code only if enabled or forced
|
|
|
+ if (tab_regy.Count() == 1) {
|
|
|
+ int desired_height = btns__hide_if_one ? 0 : btns__height;
|
|
|
+ if (tab_mgr.Btns_height() != desired_height)
|
|
|
+ tab_mgr.Btns_height_(desired_height);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (tab_mgr.Btns_height() != btns__height)
|
|
|
+ tab_mgr.Btns_height_(btns__height);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
|
|
|
+ if (ctx.Match(k, Invk_tabs_new_dflt__at_dflt__focus_y)) Tabs_new_dflt(Bool_.Y);
|
|
|
+ else if (ctx.Match(k, Invk_tabs_new_link__at_dflt__focus_n)) Tabs_new_link(Bool_.N, m.ReadStrOr("v", null));
|
|
|
+ else if (ctx.Match(k, Invk_tabs_new_link__at_dflt__focus_y)) Tabs_new_link(Bool_.Y, m.ReadStrOr("v", null));
|
|
|
+ else if (ctx.Match(k, Gfui_tab_mgr.Evt_tab_selected)) Tabs_selected(m.ReadStr("key"));
|
|
|
+ else if (ctx.Match(k, Gfui_tab_mgr.Evt_tab_closed)) Tabs_closed(m.ReadStr("key"));
|
|
|
+ else if (ctx.Match(k, Gfui_tab_mgr.Evt_tab_switched)) Tabs_switched(m.ReadStr("src"), m.ReadStr("trg"));
|
|
|
+ else if (ctx.Match(k, Invk_tabs_close_cur)) Tabs_close_cur();
|
|
|
+ else if (ctx.Match(k, Invk_tabs_select_bwd)) Tabs_select(Bool_.N);
|
|
|
+ else if (ctx.Match(k, Invk_tabs_select_fwd)) Tabs_select(Bool_.Y);
|
|
|
+ else if (ctx.Match(k, Invk_tabs_switch_cur_bwd)) Tabs_move(Bool_.N);
|
|
|
+ else if (ctx.Match(k, Invk_tabs_switch_cur_fwd)) Tabs_move(Bool_.Y);
|
|
|
+
|
|
|
+ else if (ctx.Match(k, Cfg__place_on_top)) tab_mgr.Btns_place_on_top_(m.ReadYn("v"));
|
|
|
+ else if (ctx.Match(k, Cfg__height)) {btns__height = m.ReadInt("v"); tab_mgr.Btns_height_(btns__height);}
|
|
|
+ else if (ctx.Match(k, Cfg__hide_if_one)) {btns__hide_if_one = m.ReadYn("v"); Tabs_hide_if_one_chk(true);}
|
|
|
+ else if (ctx.Match(k, Cfg__curved)) tab_mgr.Btns_curved_(m.ReadYn("v"));
|
|
|
+ else if (ctx.Match(k, Cfg__close_btn_visible)) tab_mgr.Btns_close_visible_(m.ReadYn("v"));
|
|
|
+ else if (ctx.Match(k, Cfg__unselected_close_btn_visible)) tab_mgr.Btns_unselected_close_visible_(m.ReadYn("v"));
|
|
|
+ else if (ctx.Match(k, Cfg__max_chars)) {btns__max_chars = m.ReadInt("v"); Btns_text_recalc();}
|
|
|
+ else if (ctx.Match(k, Cfg__min_chars)) {btns__min_chars = m.ReadInt("v"); Btns_text_recalc();}
|
|
|
+
|
|
|
+ else if (ctx.Match(k, Cfg__javascript_enabled)) Tabs_javascript_enabled_(m.ReadYnOrY("v")); // NOTE: must be "OrY" else broken cfg.db will break cfg_maint; DATE:2016-12-15
|
|
|
+ else if (ctx.Match(k, Cfg__page_load_mode)) Page_load_mode_(m.ReadStr("v"));
|
|
|
+ else return Gfo_invk_.Rv_unhandled;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+ private void Page_load_mode_(String v) {
|
|
|
+ page_load_mode = Gxw_html_load_tid_.Xto_tid(v);
|
|
|
+ // Gfo_evt_mgr_.Pub_val(this, Evt_load_tid_changed, load_tid);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static final String
|
|
|
+ Invk_tabs_select_fwd = "tabs_select_fwd" , Invk_tabs_select_bwd = "tabs_select_bwd"
|
|
|
+ , Invk_tabs_switch_cur_fwd = "tabs_switch_cur_fwd" , Invk_tabs_switch_cur_bwd = "tabs_switch_cur_bwd"
|
|
|
+ , Invk_tabs_new_dflt__at_dflt__focus_y = "tabs_new_dflt__at_dflt__focus_y"
|
|
|
+ , Invk_tabs_new_link__at_dflt__focus_n = "tabs_new_link__at_dflt__focus_n"
|
|
|
+ , Invk_tabs_new_link__at_dflt__focus_y = "tabs_new_link__at_dflt__focus_y"
|
|
|
+ , Invk_tabs_close_cur = "tabs_close_cur"
|
|
|
+ ;
|
|
|
+ private static final String
|
|
|
+ Cfg__place_on_top = "xowa.gui.tabs.place_on_top"
|
|
|
+ , Cfg__height = "xowa.gui.tabs.height"
|
|
|
+ , Cfg__hide_if_one = "xowa.gui.tabs.hide_if_one"
|
|
|
+ , Cfg__curved = "xowa.gui.tabs.curved"
|
|
|
+ , Cfg__close_btn_visible = "xowa.gui.tabs.close_btn_visible"
|
|
|
+ , Cfg__unselected_close_btn_visible = "xowa.gui.tabs.unselected_close_btn_visible"
|
|
|
+ , Cfg__max_chars = "xowa.gui.tabs.max_chars"
|
|
|
+ , Cfg__min_chars = "xowa.gui.tabs.min_chars"
|
|
|
+ , Cfg__javascript_enabled = "xowa.gui.html_box.javascript_enabled"
|
|
|
+ , Cfg__page_load_mode = "xowa.gui.html_box.page_load_mode"
|
|
|
+ ;
|
|
|
+}
|