diff --git a/400_xowa/src/gplx/xowa/guis/views/Xog_tab_itm.java b/400_xowa/src/gplx/xowa/guis/views/Xog_tab_itm.java index 2f4e10f5f..77d70cb74 100644 --- a/400_xowa/src/gplx/xowa/guis/views/Xog_tab_itm.java +++ b/400_xowa/src/gplx/xowa/guis/views/Xog_tab_itm.java @@ -1,309 +1,310 @@ -/* -XOWA: the XOWA Offline Wiki Application -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. - -You may use XOWA according to either of these licenses as is most appropriate -for your project on a case-by-case basis. - -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.Bry_; -import gplx.Bry_find_; -import gplx.Err_; -import gplx.GfoMsg; -import gplx.Gfo_evt_mgr_; -import gplx.Gfo_invk; -import gplx.Gfo_invk_; -import gplx.Gfo_usr_dlg; -import gplx.GfsCtx; -import gplx.Int_; -import gplx.List_adp; -import gplx.String_; -import gplx.core.envs.Env_; -import gplx.core.threads.Gfo_thread_wkr; -import gplx.gfui.controls.elems.GfuiElem; -import gplx.gfui.controls.elems.GfuiElemKeys; -import gplx.gfui.controls.standards.Gfui_html; -import gplx.gfui.controls.standards.Gfui_tab_itm; -import gplx.gfui.controls.standards.Gfui_tab_itm_data; -import gplx.gfui.ipts.IptBnd_; -import gplx.gfui.ipts.IptCfg_; -import gplx.gfui.ipts.IptEventType_; -import gplx.gfui.ipts.IptKey_; -import gplx.gfui.ipts.IptMouseBtn_; -import gplx.gfui.kits.core.Gfui_kit; -import gplx.xowa.Xoa_app; -import gplx.xowa.Xoa_page; -import gplx.xowa.Xoa_ttl; -import gplx.xowa.Xoa_url; -import gplx.xowa.Xoa_url_; -import gplx.xowa.Xoae_app; -import gplx.xowa.Xoae_page; -import gplx.xowa.Xow_wiki; -import gplx.xowa.Xowe_wiki; -import gplx.xowa.files.Xof_file_wkr; -import gplx.xowa.files.Xog_redlink_thread; -import gplx.xowa.guis.Xoa_gui_mgr; -import gplx.xowa.guis.bnds.Xog_bnd_box_; -import gplx.xowa.guis.history.Xog_history_mgr; -import gplx.xowa.wikis.pages.Xopg_view_mode_; - -public class Xog_tab_itm implements Gfo_invk { - private Xog_win_itm win; - public Xog_tab_itm(Xog_tab_mgr tab_mgr, Gfui_tab_itm_data tab_data, Xowe_wiki wiki, Xoae_page page) { - this.tab_mgr = tab_mgr; this.tab_data = tab_data; this.wiki = wiki; this.page = page; - this.win = tab_mgr.Win(); - this.html_itm = new Xog_html_itm(this); - cmd_sync = win.Kit().New_cmd_sync(this); - } - public Xowe_wiki Wiki() {return wiki;} public void Wiki_(Xowe_wiki v) {this.wiki = v;} private Xowe_wiki wiki; - public Gfo_invk Cmd_sync() {return cmd_sync;} private Gfo_invk cmd_sync; - public void Make_html_box(int uid, Gfui_tab_itm tab_box, Xog_win_itm win, GfuiElem owner) { - this.tab_box = tab_box; - Xoae_app app = win.App(); Xoa_gui_mgr gui_mgr = win.Gui_mgr(); Gfui_kit kit = win.Kit(); - Gfui_html html_box = kit.New_html("html_box" + Int_.To_str(uid), owner); - html_box.Html_js_enabled_(tab_mgr.Javascript_enabled()); - html_box.Html_invk_src_(win); - html_itm.Html_box_(html_box); - if (app.Mode().Tid_is_gui()) { // NOTE: only run for gui; will cause firefox_addon to fail; DATE:2014-05-03 - // NOTE: must set source, else control will be empty, and key events will not be raised; DATE:2014-04-30 - // NOTE: use load_by_url for nightmode else load_by_mem causes "white flashing" DATE:2017-03-04 - if (app.Gui_mgr().Nightmode_mgr().Enabled()) { - html_box.Html_doc_html_load_by_url - ( app.Usere().Fsys_mgr().App_temp_html_dir().GenSubFil("tab_new.html") - , String_.new_u8(gplx.xowa.specials.xowa.default_tab.Default_tab_page.DEFAULT_HTML_NIGHT) - ); - } - else { - html_box.Html_doc_html_load_by_mem(""); - } - IptBnd_.ipt_to_(IptCfg_.Null, html_box, this, "popup", IptEventType_.MouseDown, IptMouseBtn_.Right); - IptBnd_.cmd_to_(IptCfg_.Null, html_box, win, Xog_win_itm.Invk_exit, IptKey_.add_(IptKey_.Alt, IptKey_.F4)); // WORKAROUND:SWT: xulrunner_v24 no longer sends Alt+F4 to SwtShell; must manually subscribe it to quit; DATE:2015-07-31 - Gfo_evt_mgr_.Sub_same(html_box, GfuiElemKeys.Evt_menu_detected, html_itm); - gui_mgr.Bnd_mgr().Bind(Xog_bnd_box_.Tid_browser_html, html_box); - if (!Env_.Mode_testing()) - kit.Set_mnu_popup(html_box, gui_mgr.Menu_mgr().Popup().Html_page().Under_mnu()); - } - } - public void Switch_mem(Xog_tab_itm comp) { - // switch html_itm.owner_tab reference only - html_itm.Switch_mem(comp.html_itm); - - // switch .html_itm, since the underlying CTabFolder has reparented the control - Xog_html_itm temp_html_itm = html_itm; - this.html_itm = comp.html_itm; - comp.html_itm = temp_html_itm; - - // switch .page, since its underlying html_box has changed and .page must reflect html_box - Xoae_page temp_page = page; - this.page = comp.page; - comp.page = temp_page; - page.Tab_data().Tab_(this); comp.Page().Tab_data().Tab_(comp); - - // switch .wiki also; ISSUE#:761; DATE:2020-07-17 - Xowe_wiki temp_wiki = wiki; - this.wiki = comp.wiki; - comp.wiki = temp_wiki; - - // switch .view_mode to match .page - byte temp_view_mode = view_mode; - this.view_mode = comp.view_mode; - comp.view_mode = temp_view_mode; - - // switch .history_mgr along with .page - Xog_history_mgr temp_history_mgr = history_mgr; - this.history_mgr = comp.history_mgr; - comp.history_mgr = temp_history_mgr; - } - public Gfui_tab_itm_data Tab_data() {return tab_data;} private Gfui_tab_itm_data tab_data; - public String Tab_key() {return tab_data.Key();} - public int Tab_idx() {return tab_data.Idx();} public void Tab_idx_(int v) {tab_data.Idx_(v);} - public Xog_tab_mgr Tab_mgr() {return tab_mgr;} private Xog_tab_mgr tab_mgr; - public Gfui_tab_itm Tab_box() {return tab_box;} private Gfui_tab_itm tab_box; - public boolean Tab_is_loading() {return tab_is_loading;} private boolean tab_is_loading; - public Xog_html_itm Html_itm() {return html_itm;} private Xog_html_itm html_itm; - public Gfui_html Html_box() {return html_itm.Html_box();} - public Xoae_page Page() {return page;} - public void Page_ref_(Xoae_page v) { - this.page = v; - this.wiki = page.Wikie(); // NOTE: must update wiki else back doesn't work; DATE:2015-03-05 - } - public void Page_(Xoae_page page) { - Page_ref_(page); - this.Page_update_ui(); // force tab button to update when page changes - } private Xoae_page page; - public void Page_update_ui() { - this.Tab_name_(); - tab_box.Tab_tip_text_(page.Url().To_str()); - } - public void Tab_name_() { - byte[] tab_name = page.Html_data().Custom_tab_name(); // Custom_tab_name set by Special:Default_tab or variants; DATE:2015-10-05 - if (tab_name == null) tab_name = page.Ttl().Full_txt(); // no custom_tab_name; use ttl's text - Tab_name_(String_.new_u8(tab_name)); - } - public void Tab_name_(String tab_name) { - tab_name = Xog_tab_itm_.Tab_name_min(tab_name, tab_mgr.Btns__min_chars()); - tab_name = Xog_tab_itm_.Tab_name_max(tab_name, tab_mgr.Btns__max_chars()); - tab_box.Tab_name_(tab_name); - } - public Xog_history_mgr History_mgr() {return history_mgr;} private Xog_history_mgr history_mgr = new Xog_history_mgr(); - public byte View_mode() {return view_mode;} private byte view_mode = Xopg_view_mode_.Tid__read; - public void View_mode_(byte v) { - view_mode = v; - if (view_mode != Xopg_view_mode_.Tid__read) // if read, don't bother adding "action=read" - page.Url().Qargs_mgr().Set_val_by_bry(Xoa_url_.Qarg__action, Xopg_view_mode_.To_bry(v)); - } - public void Pin_toggle() {} - public void Show_url_bgn(Xoa_url url) { - this.tab_is_loading = true; - Xoae_app app = win.App(); Gfo_usr_dlg usr_dlg = app.Usr_dlg(); - - // get new_tab_name - this.wiki = (Xowe_wiki)app.Wiki_mgr().Get_by_or_make_init_y(url.Wiki_bry()); // NOTE: must go before wiki.Props().Main_page(); DATE:2016-08-02; NOTE: must load wiki; DATE:2015-07-22 - if (url.Page_is_main()) url.Page_bry_(wiki.Props().Main_page()); // NOTE: must go before ttl.Make; DATE:2016-07-31 - Xoa_ttl ttl = wiki.Ttl_parse(url.Page_bry()); - if (ttl == null) {usr_dlg.Prog_one("", "", "title is invalid: ~{0}", String_.new_u8(url.Raw())); return;} - String new_tab_name = String_.new_u8(ttl.Full_txt()); - - // if clicking on anchor, just scroll; do not load page - if ( url.Anch_str() != null // url has anchor - && url.Eq_page(page.Url()) // url has same page_name as existing page - && url.Qargs_ary().length == 0 // url has no args; needed for Category:A?from=b#mw-pages - && String_.Eq(new_tab_name, tab_data.Name()) // NOTE: name will be null / empty when starting app and last session had page with #anchor; EX:Main_Page#Links; DATE:2016-07-21 - ) { - html_itm.Scroll_page_by_id_gui(url.Anch_str()); - return; - } - if (win.Page__async__working(url)) return; - if (page != null) page.Tab_data().Close_mgr().When_close(this, url); // cancel any current search cmds - app.Log_wtr().Queue_enabled_(true); - usr_dlg.Gui_wkr().Clear(); - if (url.Vnt_bry() != null) { - byte[] vnt = url.Vnt_bry(); - if (!Bry_.Eq(vnt, wiki.Lang().Vnt_mgr().Cur_itm().Key())) - wiki.Appe().Cfg().Set_bry_wiki(wiki, Xowe_wiki.Cfg__variant__current, vnt); - } - Tab_name_(new_tab_name); - usr_dlg.Prog_one("", "", "loading: ~{0}", String_.new_u8(ttl.Raw())); - - // DELETE: no longer seems needed; popups always disappear when navigating to new page; DATE:2018-11-11 - // if (wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled()) - // this.Html_box().Html_js_eval_script("if (window.xowa_popups_hide_all != null) window.xowa_popups_hide_all();"); // should be more configurable; DATE:2014-07-09 - - app.Thread_mgr_old().Page_load_mgr().Add_at_end(new Load_page_wkr(this, wiki, url, ttl)).Run(); - } - private void Show_url_loaded(Load_page_wkr wkr) { - Xowe_wiki wiki = wkr.Wiki(); Xoae_page page = wkr.Page(); - Xoa_url url = page.Url(); Xoa_ttl ttl = page.Ttl(); - Xoae_app app = wiki.Appe(); Gfo_usr_dlg usr_dlg = app.Usr_dlg(); - try { - if (page.Tab_data().Cancel_show()) return; // Special:Search canceled show; NOTE: must be inside try b/c finally handles thread - wiki.Parser_mgr().Ctx().Page_(page); - if ( page.Db().Page().Exists_n() - && !page.Commons_mgr().Xowa_mockup()) { // do not enter "missing" section if File_mockup; EX:en.wikipedia.org/wiki/File:Protoplanetary-disk.jpg DATE:2016-11-13 - if (wiki.Db_mgr().Save_mgr().Create_enabled() - || wiki.Page_mgr().Sync_mgr().Auto_enabled()) { - page = Xoae_page.New_edit(wiki, ttl); - page.Url_(url); // NOTE: need to set url else query args like action=edit will be lost; DATE:2019-03-20 - view_mode = Xopg_view_mode_.Tid__edit; - history_mgr.Add(page); // NOTE: must put new_page on stack so that pressing back will pop new_page, not previous page - Xog_tab_itm_read_mgr.Show_page(this, page, false); - } - else { - wkr.Page().Tab_data().Tab().Page_(page); // NOTE: must set tab's page to current page, so that switching to it will update url bar; EX:pt.b:A"MANUAL_DE_PROCEDURI_.Sectiunea:""CONTABILITATE_SI_MANAGEMENT_FINANCIAR""" DATE:2015-09-17 - if (page.Redirect_trail().Itms__len() > 0) - usr_dlg.Prog_many("", "", "could not find page in wiki: ~{0} (redirected from ~{1})", String_.new_u8(page.Url().Page_bry()), page.Redirect_trail().Itms__get_at_0th_or_null()); - else { - if (ttl.Ns().Id_is_file()) - usr_dlg.Prog_one("", "", "commons.wikimedia.org must be installed in order to view the file. See [[App/Wiki_types/Commons]]: ~{0}", String_.new_u8(url.Raw()));// HOME - else - usr_dlg.Prog_one("", "", "could not find page in wiki: ~{0}", String_.new_u8(url.Raw())); - } - } - app.Log_wtr().Queue_enabled_(false); - return; - } - // if (!page.Redirected()) page.Url_(url); // NOTE: handle redirect from commons; COMMENTED: part of redirect rewrite; DATE:2016-07-05 - if (page.Ttl().Anch_bgn() != Bry_find_.Not_found) page.Url().Anch_bry_(page.Ttl().Anch_txt()); // NOTE: occurs when page is a redirect to an anchor; EX: w:Duck race -> Rubber duck#Races - history_mgr.Add(page); - Xog_tab_itm_read_mgr.Show_page(this, page, true); - if (app.Usere().History_mgr().Enabled()) { - app.Usere().History_mgr().Add(page); - app.User().User_db_mgr().History_mgr().Update_async(app.Async_mgr(), ttl, url); - } - usr_dlg.Prog_none("", "", "rendering html"); - // html_itm.Html_box().Size_(tab_mgr.Tab_mgr().Size()); // COMMENTED: causes clicks on macosx to be off by 4 px; NOTE: must resize tab here, else scrolling to anchor in background tab doesn't work (html_box has size of 0, 0) DATE:2015-05-03 - // win.Page__async__bgn(this); - Gfo_thread_wkr async_wkr = null; - if (page.Html_data().Hdump_exists()) { -// wiki.File_mgr().Init_file_mgr_by_load(wiki); -// Xof_fsdb_mgr fsdb_mgr = wiki.File_mgr().Fsdb_mgr(); -// async_wkr = new Xof_file_wkr(wiki.File__orig_mgr(), fsdb_mgr.Bin_mgr(), fsdb_mgr.Mnt_mgr(), app.Usere().User_db_mgr().Cache_mgr(), wiki.File__repo_mgr(), html_itm, page, page.Hdump_mgr().Imgs()); - async_wkr = new Load_files_wkr(this); - if (wiki.Html__hdump_enabled() && page.Db().Page().Html_db_id() == -1) { - wiki.Html__hdump_mgr().Save_mgr().Save(page); - } - } - else - async_wkr = new Load_files_wkr(this); - - page.Html_data().Mode_wtxt_shown_y_(); - app.Thread_mgr_old().File_load_mgr().Add_at_end(async_wkr).Run(); - // app.Thread_mgr().Get_by_or_new("on_page_load").Add(new Xopg_img_thread(), new Xopg_rl_thread()); - } - finally { - app.Thread_mgr_old().Page_load_mgr().Resume(); - this.tab_is_loading = false; - } - } - public void Exec_async_hdump(Xoa_app app, Xow_wiki wiki, gplx.xowa.guis.cbks.js.Xog_js_wkr js_wkr, gplx.core.threads.Gfo_thread_pool thread_pool, Xoa_page page, List_adp imgs, int[] redlink_ary) { - if (imgs.Count() > 0) { - Xof_file_wkr file_thread = new Xof_file_wkr - ( wiki.File__orig_mgr(), wiki.File__bin_mgr(), wiki.File__mnt_mgr() - , app.User().User_db_mgr().Cache_mgr(), wiki.File__repo_mgr(), html_itm, page, imgs - ); - thread_pool.Add_at_end(file_thread); thread_pool.Run(); - } - if (redlink_ary.length > 0) { - Xog_redlink_thread redlink_thread = new Xog_redlink_thread(redlink_ary, js_wkr); - thread_pool.Add_at_end(redlink_thread); thread_pool.Run(); - } - } - public void Exec_notify(boolean pass, String msg) { - this.Html_box().Html_js_eval_proc_as_str("xowa.cmds.exec_by_str", "xowa.notify", "{\"text\":\"" + msg + "\",\"status\":\"" + (pass ? "success" : "error") + "\"}"); - } - @gplx.Internal protected void Show_url_failed(Load_page_wkr wkr) { - try { - Xog_tab_itm_read_mgr.Show_page_err(win, this, wkr.Wiki(), wkr.Url(), wkr.Ttl(), wkr.Exec_err()); - } finally { - wkr.Wiki().Appe().Thread_mgr_old().Page_load_mgr().Resume(); - } - } - public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { - if (ctx.Match(k, Invk_show_url_loaded_swt)) this.Show_url_loaded((Load_page_wkr)m.ReadObj("v")); - else if (ctx.Match(k, Invk_show_url_failed_swt)) this.Show_url_failed((Load_page_wkr)m.ReadObj("v")); - else return Gfo_invk_.Rv_unhandled; - return this; - } - public static final String Invk_show_url_loaded_swt = "show_url_loaded_swt", Invk_show_url_failed_swt = "show_url_failed_swt"; -} -class Load_files_wkr implements Gfo_thread_wkr { - private Xog_tab_itm tab; - public Load_files_wkr(Xog_tab_itm tab) {this.tab = tab;} - public String Thread__name() {return "xowa.load_files_wkr";} - public boolean Thread__resume() {return true;} - public void Thread__exec() { - try {Xog_async_wkr.Async(tab);} - catch (Exception e) { - tab.Tab_mgr().Win().App().Usr_dlg().Warn_many("error while running file wkr; page=~{0} err=~{1}", tab.Page().Url().To_str(), Err_.Message_gplx_full(e)); - } - } -} +/* +XOWA: the XOWA Offline Wiki Application +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. + +You may use XOWA according to either of these licenses as is most appropriate +for your project on a case-by-case basis. + +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.Bry_; +import gplx.Bry_find_; +import gplx.Err_; +import gplx.GfoMsg; +import gplx.Gfo_evt_mgr_; +import gplx.Gfo_invk; +import gplx.Gfo_invk_; +import gplx.Gfo_usr_dlg; +import gplx.GfsCtx; +import gplx.Int_; +import gplx.List_adp; +import gplx.String_; +import gplx.core.envs.Env_; +import gplx.core.threads.Gfo_thread_wkr; +import gplx.gfui.controls.elems.GfuiElem; +import gplx.gfui.controls.elems.GfuiElemKeys; +import gplx.gfui.controls.standards.Gfui_html; +import gplx.gfui.controls.standards.Gfui_tab_itm; +import gplx.gfui.controls.standards.Gfui_tab_itm_data; +import gplx.gfui.ipts.IptBnd_; +import gplx.gfui.ipts.IptCfg_; +import gplx.gfui.ipts.IptEventType_; +import gplx.gfui.ipts.IptKey_; +import gplx.gfui.ipts.IptMouseBtn_; +import gplx.gfui.kits.core.Gfui_kit; +import gplx.xowa.Xoa_app; +import gplx.xowa.Xoa_page; +import gplx.xowa.Xoa_ttl; +import gplx.xowa.Xoa_url; +import gplx.xowa.Xoa_url_; +import gplx.xowa.Xoae_app; +import gplx.xowa.Xoae_page; +import gplx.xowa.Xow_wiki; +import gplx.xowa.Xowe_wiki; +import gplx.xowa.files.Xof_file_wkr; +import gplx.xowa.files.Xog_redlink_thread; +import gplx.xowa.guis.Xoa_gui_mgr; +import gplx.xowa.guis.bnds.Xog_bnd_box_; +import gplx.xowa.guis.history.Xog_history_mgr; +import gplx.xowa.wikis.pages.Xopg_view_mode_; +import gplx.xowa.wikis.pages.dbs.Xopg_db_page; + +public class Xog_tab_itm implements Gfo_invk { + private Xog_win_itm win; + public Xog_tab_itm(Xog_tab_mgr tab_mgr, Gfui_tab_itm_data tab_data, Xowe_wiki wiki, Xoae_page page) { + this.tab_mgr = tab_mgr; this.tab_data = tab_data; this.wiki = wiki; this.page = page; + this.win = tab_mgr.Win(); + this.html_itm = new Xog_html_itm(this); + cmd_sync = win.Kit().New_cmd_sync(this); + } + public Xowe_wiki Wiki() {return wiki;} public void Wiki_(Xowe_wiki v) {this.wiki = v;} private Xowe_wiki wiki; + public Gfo_invk Cmd_sync() {return cmd_sync;} private Gfo_invk cmd_sync; + public void Make_html_box(int uid, Gfui_tab_itm tab_box, Xog_win_itm win, GfuiElem owner) { + this.tab_box = tab_box; + Xoae_app app = win.App(); Xoa_gui_mgr gui_mgr = win.Gui_mgr(); Gfui_kit kit = win.Kit(); + Gfui_html html_box = kit.New_html("html_box" + Int_.To_str(uid), owner); + html_box.Html_js_enabled_(tab_mgr.Javascript_enabled()); + html_box.Html_invk_src_(win); + html_itm.Html_box_(html_box); + if (app.Mode().Tid_is_gui()) { // NOTE: only run for gui; will cause firefox_addon to fail; DATE:2014-05-03 + // NOTE: must set source, else control will be empty, and key events will not be raised; DATE:2014-04-30 + // NOTE: use load_by_url for nightmode else load_by_mem causes "white flashing" DATE:2017-03-04 + if (app.Gui_mgr().Nightmode_mgr().Enabled()) { + html_box.Html_doc_html_load_by_url + ( app.Usere().Fsys_mgr().App_temp_html_dir().GenSubFil("tab_new.html") + , String_.new_u8(gplx.xowa.specials.xowa.default_tab.Default_tab_page.DEFAULT_HTML_NIGHT) + ); + } + else { + html_box.Html_doc_html_load_by_mem(""); + } + IptBnd_.ipt_to_(IptCfg_.Null, html_box, this, "popup", IptEventType_.MouseDown, IptMouseBtn_.Right); + IptBnd_.cmd_to_(IptCfg_.Null, html_box, win, Xog_win_itm.Invk_exit, IptKey_.add_(IptKey_.Alt, IptKey_.F4)); // WORKAROUND:SWT: xulrunner_v24 no longer sends Alt+F4 to SwtShell; must manually subscribe it to quit; DATE:2015-07-31 + Gfo_evt_mgr_.Sub_same(html_box, GfuiElemKeys.Evt_menu_detected, html_itm); + gui_mgr.Bnd_mgr().Bind(Xog_bnd_box_.Tid_browser_html, html_box); + if (!Env_.Mode_testing()) + kit.Set_mnu_popup(html_box, gui_mgr.Menu_mgr().Popup().Html_page().Under_mnu()); + } + } + public void Switch_mem(Xog_tab_itm comp) { + // switch html_itm.owner_tab reference only + html_itm.Switch_mem(comp.html_itm); + + // switch .html_itm, since the underlying CTabFolder has reparented the control + Xog_html_itm temp_html_itm = html_itm; + this.html_itm = comp.html_itm; + comp.html_itm = temp_html_itm; + + // switch .page, since its underlying html_box has changed and .page must reflect html_box + Xoae_page temp_page = page; + this.page = comp.page; + comp.page = temp_page; + page.Tab_data().Tab_(this); comp.Page().Tab_data().Tab_(comp); + + // switch .wiki also; ISSUE#:761; DATE:2020-07-17 + Xowe_wiki temp_wiki = wiki; + this.wiki = comp.wiki; + comp.wiki = temp_wiki; + + // switch .view_mode to match .page + byte temp_view_mode = view_mode; + this.view_mode = comp.view_mode; + comp.view_mode = temp_view_mode; + + // switch .history_mgr along with .page + Xog_history_mgr temp_history_mgr = history_mgr; + this.history_mgr = comp.history_mgr; + comp.history_mgr = temp_history_mgr; + } + public Gfui_tab_itm_data Tab_data() {return tab_data;} private Gfui_tab_itm_data tab_data; + public String Tab_key() {return tab_data.Key();} + public int Tab_idx() {return tab_data.Idx();} public void Tab_idx_(int v) {tab_data.Idx_(v);} + public Xog_tab_mgr Tab_mgr() {return tab_mgr;} private Xog_tab_mgr tab_mgr; + public Gfui_tab_itm Tab_box() {return tab_box;} private Gfui_tab_itm tab_box; + public boolean Tab_is_loading() {return tab_is_loading;} private boolean tab_is_loading; + public Xog_html_itm Html_itm() {return html_itm;} private Xog_html_itm html_itm; + public Gfui_html Html_box() {return html_itm.Html_box();} + public Xoae_page Page() {return page;} + public void Page_ref_(Xoae_page v) { + this.page = v; + this.wiki = page.Wikie(); // NOTE: must update wiki else back doesn't work; DATE:2015-03-05 + } + public void Page_(Xoae_page page) { + Page_ref_(page); + this.Page_update_ui(); // force tab button to update when page changes + } private Xoae_page page; + public void Page_update_ui() { + this.Tab_name_(); + tab_box.Tab_tip_text_(page.Url().To_str()); + } + public void Tab_name_() { + byte[] tab_name = page.Html_data().Custom_tab_name(); // Custom_tab_name set by Special:Default_tab or variants; DATE:2015-10-05 + if (tab_name == null) tab_name = page.Ttl().Full_txt(); // no custom_tab_name; use ttl's text + Tab_name_(String_.new_u8(tab_name)); + } + public void Tab_name_(String tab_name) { + tab_name = Xog_tab_itm_.Tab_name_min(tab_name, tab_mgr.Btns__min_chars()); + tab_name = Xog_tab_itm_.Tab_name_max(tab_name, tab_mgr.Btns__max_chars()); + tab_box.Tab_name_(tab_name); + } + public Xog_history_mgr History_mgr() {return history_mgr;} private Xog_history_mgr history_mgr = new Xog_history_mgr(); + public byte View_mode() {return view_mode;} private byte view_mode = Xopg_view_mode_.Tid__read; + public void View_mode_(byte v) { + view_mode = v; + if (view_mode != Xopg_view_mode_.Tid__read) // if read, don't bother adding "action=read" + page.Url().Qargs_mgr().Set_val_by_bry(Xoa_url_.Qarg__action, Xopg_view_mode_.To_bry(v)); + } + public void Pin_toggle() {} + public void Show_url_bgn(Xoa_url url) { + this.tab_is_loading = true; + Xoae_app app = win.App(); Gfo_usr_dlg usr_dlg = app.Usr_dlg(); + + // get new_tab_name + this.wiki = (Xowe_wiki)app.Wiki_mgr().Get_by_or_make_init_y(url.Wiki_bry()); // NOTE: must go before wiki.Props().Main_page(); DATE:2016-08-02; NOTE: must load wiki; DATE:2015-07-22 + if (url.Page_is_main()) url.Page_bry_(wiki.Props().Main_page()); // NOTE: must go before ttl.Make; DATE:2016-07-31 + Xoa_ttl ttl = wiki.Ttl_parse(url.Page_bry()); + if (ttl == null) {usr_dlg.Prog_one("", "", "title is invalid: ~{0}", String_.new_u8(url.Raw())); return;} + String new_tab_name = String_.new_u8(ttl.Full_txt()); + + // if clicking on anchor, just scroll; do not load page + if ( url.Anch_str() != null // url has anchor + && url.Eq_page(page.Url()) // url has same page_name as existing page + && url.Qargs_ary().length == 0 // url has no args; needed for Category:A?from=b#mw-pages + && String_.Eq(new_tab_name, tab_data.Name()) // NOTE: name will be null / empty when starting app and last session had page with #anchor; EX:Main_Page#Links; DATE:2016-07-21 + ) { + html_itm.Scroll_page_by_id_gui(url.Anch_str()); + return; + } + if (win.Page__async__working(url)) return; + if (page != null) page.Tab_data().Close_mgr().When_close(this, url); // cancel any current search cmds + app.Log_wtr().Queue_enabled_(true); + usr_dlg.Gui_wkr().Clear(); + if (url.Vnt_bry() != null) { + byte[] vnt = url.Vnt_bry(); + if (!Bry_.Eq(vnt, wiki.Lang().Vnt_mgr().Cur_itm().Key())) + wiki.Appe().Cfg().Set_bry_wiki(wiki, Xowe_wiki.Cfg__variant__current, vnt); + } + Tab_name_(new_tab_name); + usr_dlg.Prog_one("", "", "loading: ~{0}", String_.new_u8(ttl.Raw())); + + // DELETE: no longer seems needed; popups always disappear when navigating to new page; DATE:2018-11-11 + // if (wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled()) + // this.Html_box().Html_js_eval_script("if (window.xowa_popups_hide_all != null) window.xowa_popups_hide_all();"); // should be more configurable; DATE:2014-07-09 + + app.Thread_mgr_old().Page_load_mgr().Add_at_end(new Load_page_wkr(this, wiki, url, ttl)).Run(); + } + private void Show_url_loaded(Load_page_wkr wkr) { + Xowe_wiki wiki = wkr.Wiki(); Xoae_page page = wkr.Page(); + Xoa_url url = page.Url(); Xoa_ttl ttl = page.Ttl(); + Xoae_app app = wiki.Appe(); Gfo_usr_dlg usr_dlg = app.Usr_dlg(); + try { + if (page.Tab_data().Cancel_show()) return; // Special:Search canceled show; NOTE: must be inside try b/c finally handles thread + wiki.Parser_mgr().Ctx().Page_(page); + if ( page.Db().Page().Exists_n() + && !page.Commons_mgr().Xowa_mockup()) { // do not enter "missing" section if File_mockup; EX:en.wikipedia.org/wiki/File:Protoplanetary-disk.jpg DATE:2016-11-13 + if (wiki.Db_mgr().Save_mgr().Create_enabled() + || wiki.Page_mgr().Sync_mgr().Auto_enabled()) { + page = Xoae_page.New_edit(wiki, ttl); + page.Url_(url); // NOTE: need to set url else query args like action=edit will be lost; DATE:2019-03-20 + view_mode = Xopg_view_mode_.Tid__edit; + history_mgr.Add(page); // NOTE: must put new_page on stack so that pressing back will pop new_page, not previous page + Xog_tab_itm_read_mgr.Show_page(this, page, false); + } + else { + wkr.Page().Tab_data().Tab().Page_(page); // NOTE: must set tab's page to current page, so that switching to it will update url bar; EX:pt.b:A"MANUAL_DE_PROCEDURI_.Sectiunea:""CONTABILITATE_SI_MANAGEMENT_FINANCIAR""" DATE:2015-09-17 + if (page.Redirect_trail().Itms__len() > 0) + usr_dlg.Prog_many("", "", "could not find page in wiki: ~{0} (redirected from ~{1})", String_.new_u8(page.Url().Page_bry()), page.Redirect_trail().Itms__get_at_0th_or_null()); + else { + if (ttl.Ns().Id_is_file()) + usr_dlg.Prog_one("", "", "commons.wikimedia.org must be installed in order to view the file. See [[App/Wiki_types/Commons]]: ~{0}", String_.new_u8(url.Raw()));// HOME + else + usr_dlg.Prog_one("", "", "could not find page in wiki: ~{0}", String_.new_u8(url.Raw())); + } + } + app.Log_wtr().Queue_enabled_(false); + return; + } + // if (!page.Redirected()) page.Url_(url); // NOTE: handle redirect from commons; COMMENTED: part of redirect rewrite; DATE:2016-07-05 + if (page.Ttl().Anch_bgn() != Bry_find_.Not_found) page.Url().Anch_bry_(page.Ttl().Anch_txt()); // NOTE: occurs when page is a redirect to an anchor; EX: w:Duck race -> Rubber duck#Races + history_mgr.Add(page); + Xog_tab_itm_read_mgr.Show_page(this, page, true); + if (app.Usere().History_mgr().Enabled()) { + app.Usere().History_mgr().Add(page); + app.User().User_db_mgr().History_mgr().Update_async(app.Async_mgr(), ttl, url); + } + usr_dlg.Prog_none("", "", "rendering html"); + // html_itm.Html_box().Size_(tab_mgr.Tab_mgr().Size()); // COMMENTED: causes clicks on macosx to be off by 4 px; NOTE: must resize tab here, else scrolling to anchor in background tab doesn't work (html_box has size of 0, 0) DATE:2015-05-03 + // win.Page__async__bgn(this); + Gfo_thread_wkr async_wkr = null; + if (page.Html_data().Hdump_exists()) { +// wiki.File_mgr().Init_file_mgr_by_load(wiki); +// Xof_fsdb_mgr fsdb_mgr = wiki.File_mgr().Fsdb_mgr(); +// async_wkr = new Xof_file_wkr(wiki.File__orig_mgr(), fsdb_mgr.Bin_mgr(), fsdb_mgr.Mnt_mgr(), app.Usere().User_db_mgr().Cache_mgr(), wiki.File__repo_mgr(), html_itm, page, page.Hdump_mgr().Imgs()); + async_wkr = new Load_files_wkr(this); + if (wiki.Html__hdump_enabled() && page.Db().Page().Html_db_id() == Xopg_db_page.HTML_DB_ID_NULL) { + wiki.Html__hdump_mgr().Save_mgr().Save(page); + } + } + else + async_wkr = new Load_files_wkr(this); + + page.Html_data().Mode_wtxt_shown_y_(); + app.Thread_mgr_old().File_load_mgr().Add_at_end(async_wkr).Run(); + // app.Thread_mgr().Get_by_or_new("on_page_load").Add(new Xopg_img_thread(), new Xopg_rl_thread()); + } + finally { + app.Thread_mgr_old().Page_load_mgr().Resume(); + this.tab_is_loading = false; + } + } + public void Exec_async_hdump(Xoa_app app, Xow_wiki wiki, gplx.xowa.guis.cbks.js.Xog_js_wkr js_wkr, gplx.core.threads.Gfo_thread_pool thread_pool, Xoa_page page, List_adp imgs, int[] redlink_ary) { + if (imgs.Count() > 0) { + Xof_file_wkr file_thread = new Xof_file_wkr + ( wiki.File__orig_mgr(), wiki.File__bin_mgr(), wiki.File__mnt_mgr() + , app.User().User_db_mgr().Cache_mgr(), wiki.File__repo_mgr(), html_itm, page, imgs + ); + thread_pool.Add_at_end(file_thread); thread_pool.Run(); + } + if (redlink_ary.length > 0) { + Xog_redlink_thread redlink_thread = new Xog_redlink_thread(redlink_ary, js_wkr); + thread_pool.Add_at_end(redlink_thread); thread_pool.Run(); + } + } + public void Exec_notify(boolean pass, String msg) { + this.Html_box().Html_js_eval_proc_as_str("xowa.cmds.exec_by_str", "xowa.notify", "{\"text\":\"" + msg + "\",\"status\":\"" + (pass ? "success" : "error") + "\"}"); + } + @gplx.Internal protected void Show_url_failed(Load_page_wkr wkr) { + try { + Xog_tab_itm_read_mgr.Show_page_err(win, this, wkr.Wiki(), wkr.Url(), wkr.Ttl(), wkr.Exec_err()); + } finally { + wkr.Wiki().Appe().Thread_mgr_old().Page_load_mgr().Resume(); + } + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_show_url_loaded_swt)) this.Show_url_loaded((Load_page_wkr)m.ReadObj("v")); + else if (ctx.Match(k, Invk_show_url_failed_swt)) this.Show_url_failed((Load_page_wkr)m.ReadObj("v")); + else return Gfo_invk_.Rv_unhandled; + return this; + } + public static final String Invk_show_url_loaded_swt = "show_url_loaded_swt", Invk_show_url_failed_swt = "show_url_failed_swt"; +} +class Load_files_wkr implements Gfo_thread_wkr { + private Xog_tab_itm tab; + public Load_files_wkr(Xog_tab_itm tab) {this.tab = tab;} + public String Thread__name() {return "xowa.load_files_wkr";} + public boolean Thread__resume() {return true;} + public void Thread__exec() { + try {Xog_async_wkr.Async(tab);} + catch (Exception e) { + tab.Tab_mgr().Win().App().Usr_dlg().Warn_many("error while running file wkr; page=~{0} err=~{1}", tab.Page().Url().To_str(), Err_.Message_gplx_full(e)); + } + } +} diff --git a/400_xowa/src/gplx/xowa/guis/views/Xog_tab_itm_edit_mgr.java b/400_xowa/src/gplx/xowa/guis/views/Xog_tab_itm_edit_mgr.java index 77531af22..bf4219e65 100644 --- a/400_xowa/src/gplx/xowa/guis/views/Xog_tab_itm_edit_mgr.java +++ b/400_xowa/src/gplx/xowa/guis/views/Xog_tab_itm_edit_mgr.java @@ -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,148 +13,171 @@ 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.controls.standards.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.core.htmls.*; import gplx.xowa.wikis.pages.*; -import gplx.xowa.wikis.nss.*; -import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*; -public class Xog_tab_itm_edit_mgr { - public static void Save(Xog_tab_itm tab, boolean quick_save) { - if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles ctrl+s being pressed in read/html modes - - // get text and save directly to text_db - Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win(); - byte[] new_text = Get_new_text(tab, page.Db().Text().Text_bry()); - int page_id = page.Db().Page().Id(); - if (page.Edit_mode() == Xoa_page_.Edit_mode_create) { - page_id = wiki.Db_mgr().Save_mgr().Data_create(wiki, page.Ttl(), new_text); - page.Db().Page().Id_(page_id); - page.Edit_mode_update_(); // set to update so that next save does not try to create - } - else { - wiki.Db_mgr().Save_mgr().Data_update(page, new_text); - } - Invalidate(wiki); - page.Db().Text().Text_bry_(new_text); - - // refresh html - wiki.Parser_mgr().Parse(page, true); - if (wiki.Html__hdump_enabled()) wiki.Html__hdump_mgr().Save_mgr().Save(page); // must go after wiki.Parse - - // NOTE: show message after Parse, b/c Parse will flash "Loading page"; DATE:2014-05-17 - win_itm.Usr_dlg().Prog_many("", "", "saved ~{0} (~{1})" - , String_.new_u8(page.Ttl().Full_txt_raw()) - , Datetime_now.Get().XtoStr_fmt("HH:mm:ss.fff") - ); - - // full_save; save page and go to read mode - if (!quick_save) { - gplx.xowa.addons.wikis.pagebaks.Pagebaks_addon.On_page_saved(wiki.Appe(), wiki, page.Ttl(), new_text); - - // update categories - try { - wiki.Html_mgr().Page_wtr_mgr().Gen(page, Xopg_view_mode_.Tid__read); // NOTE: need to write html to fill Wtxt().Ctgs - gplx.xowa.addons.wikis.ctgs.edits.Xoctg_edit_mgr.Update(wiki, page.Ttl().Page_db(), page_id, page.Wtxt().Ctgs__to_ary()); - } catch (Exception e) { - Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to update categories; err=~{0}", Err_.Message_gplx_log(e)); - } - - // TODO: save html copy - //wiki.Db_mgr().Hdump_mgr().Save(page); - - // parse page and show it - page.Html_data().Edit_preview_(Bry_.Empty); - Xoae_page stack_page = tab.History_mgr().Cur_page(wiki); // NOTE: must be to CurPage() else changes will be lost when going Bwd,Fwd - stack_page.Db().Text().Text_bry_(page.Db().Text().Text_bry()); // NOTE: overwrite with "saved" changes - stack_page.Wikie().Parser_mgr().Parse(page, true); // NOTE: must reparse page if (a) Edit -> Read; or (b) "Options" save - page.Url_(Xoa_url.New(tab.Wiki().Domain_bry(), tab.Page().Ttl().Full_db())); - - // force full reload of page; needed to refresh page_modified; DATE:2017-03-06 - tab.Show_url_bgn(page.Url()); -// win_itm.Page__mode_(Xopg_view_mode_.Tid__read); -// win_itm.Page__async__bgn(tab); - } - } - public static void Preview(Xog_tab_itm tab) { - if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles preview somehow being called? - Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win(); - Xog_html_itm html_itm = tab.Html_itm(); - - byte[] new_text = Get_new_text(tab, null); - Xoae_page new_page = Xoae_page.New(wiki, page.Ttl()); - new_page.Url_(page.Url()); // NOTE: must set Url explicitly, else new_page will not have same url_args as old_page; broken when going to action=edit; DATE:2018-11-25 - new_page.Db().Page().Id_(page.Db().Page().Id()); // NOTE: page_id needed for sqlite (was not needed for xdat) - new_page.Db().Text().Text_bry_(new_text); - wiki.Parser_mgr().Parse(new_page, true); // refresh html - tab.Page_(new_page); new_page.Tab_data().Tab_(tab); // replace old page with new_page; DATE:2014-10-09 - - Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001(); - Xoh_page_wtr_wkr wkr = wiki.Html_mgr().Page_wtr_mgr().Wkr(Xopg_view_mode_.Tid__read); - wkr.Write_body(tmp_bfr, wiki.Parser_mgr().Ctx(), Xoh_wtr_ctx.Basic, new_page); - byte[] new_html = tmp_bfr.To_bry_and_rls(); - new_page.Html_data().Edit_preview_(new_html); - - Invalidate(wiki); - win_itm.Page__mode_(Xopg_view_mode_.Tid__edit); - html_itm.Scroll_page_by_id_gui(Xog_html_itm.Elem_id__first_heading);// NOTE: was originally directly; changed to call on thread; DATE:2014-05-03 - win_itm.Page__async__bgn(tab); // NOTE: needed to show images during preview; DATE:2014-06-21 - } - public static void Rename(Xog_tab_itm tab) { - if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles ctrl+r being pressed - Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win(); - if (Bry_.Eq(page.Ttl().Page_db(), wiki.Props().Main_page())) { - win_itm.Usr_dlg().Warn_many("", "", "The Main Page cannot be renamed"); - win_itm.Kit().Ask_ok("", "", "The Main Page cannot be renamed"); - return; - } - byte[] new_text = Bry_.new_u8(tab.Html_itm().Get_elem_value(Xog_html_itm.Elem_id__xowa_edit_rename_box)); - if (Bry_.Len_eq_0(new_text)) return; // no ttl given; exit - new_text = Xoa_ttl.Replace_spaces(new_text); // ttls cannot have spaces; only underscores - Xoa_ttl new_ttl = Xoa_ttl.Parse(wiki, new_text); - int new_ns_id = new_ttl.Ns().Id(); - if (new_ns_id != Xow_ns_.Tid__main) { - win_itm.Usr_dlg().Warn_many("", "", "The new page name must remain in the same namespace"); - return; - } - wiki.Db_mgr().Save_mgr().Data_rename(page, new_ns_id, new_text); - page.Ttl_(Xoa_ttl.Parse(wiki, Bry_.Add(page.Ttl().Ns().Name_db_w_colon(), new_text))); - win_itm.Page__mode_(Xopg_view_mode_.Tid__read); - win_itm.Usr_dlg().Prog_one("", "", "renamed page to {0}", String_.new_u8(page.Ttl().Full_txt_raw())); - } - public static void Focus(Xog_win_itm win, String elem_focus_id) { - Gfui_html html_box = win.Active_html_box(); - html_box.Focus(); - html_box.Html_js_eval_proc_as_str(Xog_js_procs.Doc__elem_focus, elem_focus_id); - } - public static void Debug(Xog_win_itm win, byte view_tid) { - Xog_tab_itm tab = win.Tab_mgr().Active_tab(); Xoae_page page = tab.Page(); - Xowe_wiki wiki = tab.Wiki(); Xop_ctx ctx = wiki.Parser_mgr().Ctx(); - ctx.Defn_trace().Clear(); // TODO_OLD: move_me - ctx.Defn_trace_(Xot_defn_trace_dbg.Instance); - Xoa_ttl ttl = page.Ttl(); - Xoae_page new_page = Xoae_page.New(wiki, ttl); - new_page.Url_(page.Url()); // NOTE: must set Url explicitly, else new_page will not have same url_args as old_page; broken when going to action=edit; DATE:2018-12-09 - byte[] data = tab.Html_itm().Get_elem_value_for_edit_box_as_bry(); - new_page.Db().Text().Text_bry_(data); - wiki.Parser_mgr().Parse(new_page, true); - Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_m001(); - bfr.Add(new_page.Root().Root_src()); - wiki.Parser_mgr().Ctx().Defn_trace().Print(data, bfr); - new_page.Db().Text().Text_bry_(bfr.To_bry_and_rls()); - byte old = tab.View_mode(); - tab.View_mode_(view_tid); - Xog_tab_itm_read_mgr.Show_page(tab, new_page, false); - tab.History_mgr().Add(new_page); - tab.View_mode_(old); - } - private static void Invalidate(Xowe_wiki wiki) {// invalidate everything on updates; especially needed for page transclusion; {{/my_subpage}} DATE:2014-04-10 - wiki.Parser_mgr().Scrib().Core_term(); - wiki.Cache_mgr().Free_mem__all(); - } - private static byte[] Get_new_text(Xog_tab_itm tab, byte[] orig) { - byte[] rv = tab.Html_itm().Get_elem_value_for_edit_box_as_bry(); - if (orig != null) // orig == null for Preview - rv = tab.Wiki().Parser_mgr().Hdr__section_editable__mgr().Merge_section(tab.Page().Url(), rv, orig); - rv = Bry_.Trim(rv, 0, rv.length, false, true, Bry_.Trim_ary_ws, true); // MW: trim all trailing ws; REF:EditPage.php!safeUnicodeInput; DATE:2014-04-25 - return rv; - } -} +package gplx.xowa.guis.views; + +import gplx.Bry_; +import gplx.Bry_bfr; +import gplx.Datetime_now; +import gplx.Err_; +import gplx.Gfo_usr_dlg_; +import gplx.String_; +import gplx.gfui.controls.standards.Gfui_html; +import gplx.xowa.Xoa_page_; +import gplx.xowa.Xoa_ttl; +import gplx.xowa.Xoa_url; +import gplx.xowa.Xoae_page; +import gplx.xowa.Xowe_wiki; +import gplx.xowa.htmls.Xoh_page_wtr_wkr; +import gplx.xowa.htmls.core.htmls.Xoh_wtr_ctx; +import gplx.xowa.parsers.Xop_ctx; +import gplx.xowa.parsers.tmpls.Xot_defn_trace_dbg; +import gplx.xowa.wikis.data.tbls.Xowd_page_itm; +import gplx.xowa.wikis.nss.Xow_ns_; +import gplx.xowa.wikis.pages.Xopg_view_mode_; + +public class Xog_tab_itm_edit_mgr { + public static void Save(Xog_tab_itm tab, boolean quick_save) { + if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles ctrl+s being pressed in read/html modes + + // get text and save directly to text_db + Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win(); + byte[] new_text = Get_new_text(tab, page.Db().Text().Text_bry()); + int page_id = page.Db().Page().Id(); + if (page.Edit_mode() == Xoa_page_.Edit_mode_create) { + page_id = wiki.Db_mgr().Save_mgr().Data_create(wiki, page.Ttl(), new_text); + page.Db().Page().Id_(page_id); + page.Edit_mode_update_(); // set to update so that next save does not try to create + } + else { + wiki.Db_mgr().Save_mgr().Data_update(page, new_text); + } + Invalidate(wiki); + page.Db().Text().Text_bry_(new_text); + + // refresh html + wiki.Parser_mgr().Parse(page, true); + if (wiki.Html__hdump_enabled()) wiki.Html__hdump_mgr().Save_mgr().Save(page); // must go after wiki.Parse + + // NOTE: show message after Parse, b/c Parse will flash "Loading page"; DATE:2014-05-17 + win_itm.Usr_dlg().Prog_many("", "", "saved ~{0} (~{1})" + , String_.new_u8(page.Ttl().Full_txt_raw()) + , Datetime_now.Get().XtoStr_fmt("HH:mm:ss.fff") + ); + + // full_save; save page and go to read mode + if (!quick_save) { + gplx.xowa.addons.wikis.pagebaks.Pagebaks_addon.On_page_saved(wiki.Appe(), wiki, page.Ttl(), new_text); + + // update categories + try { + wiki.Html_mgr().Page_wtr_mgr().Gen(page, Xopg_view_mode_.Tid__read); // NOTE: need to write html to fill Wtxt().Ctgs + gplx.xowa.addons.wikis.ctgs.edits.Xoctg_edit_mgr.Update(wiki, page.Ttl().Page_db(), page_id, page.Wtxt().Ctgs__to_ary()); + } catch (Exception e) { + Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to update categories; err=~{0}", Err_.Message_gplx_log(e)); + } + + // reload html_db_id b/c it gets cleared in Xopg_db_page; ISSUE#:699; DATE:2020-08-06 + Xowd_page_itm rv = new Xowd_page_itm(); + wiki.Data__core_mgr().Tbl__page().Select_by_ttl(rv, page.Ttl().Ns(), page.Ttl().Page_db()); + page.Db().Page().Html_db_id_(rv.Html_db_id()); + + // save html + wiki.Html__hdump_mgr().Save_mgr().Save(page, true); + + // parse page and show it + page.Html_data().Edit_preview_(Bry_.Empty); + Xoae_page stack_page = tab.History_mgr().Cur_page(wiki); // NOTE: must be to CurPage() else changes will be lost when going Bwd,Fwd + stack_page.Db().Text().Text_bry_(page.Db().Text().Text_bry()); // NOTE: overwrite with "saved" changes + stack_page.Wikie().Parser_mgr().Parse(page, true); // NOTE: must reparse page if (a) Edit -> Read; or (b) "Options" save + page.Url_(Xoa_url.New(tab.Wiki().Domain_bry(), tab.Page().Ttl().Full_db())); + + // force full reload of page; needed to refresh page_modified; DATE:2017-03-06 + tab.Show_url_bgn(page.Url()); +// win_itm.Page__mode_(Xopg_view_mode_.Tid__read); +// win_itm.Page__async__bgn(tab); + } + } + public static void Preview(Xog_tab_itm tab) { + if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles preview somehow being called? + Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win(); + Xog_html_itm html_itm = tab.Html_itm(); + + byte[] new_text = Get_new_text(tab, null); + Xoae_page new_page = Xoae_page.New(wiki, page.Ttl()); + new_page.Url_(page.Url()); // NOTE: must set Url explicitly, else new_page will not have same url_args as old_page; broken when going to action=edit; DATE:2018-11-25 + new_page.Db().Page().Id_(page.Db().Page().Id()); // NOTE: page_id needed for sqlite (was not needed for xdat) + new_page.Db().Text().Text_bry_(new_text); + wiki.Parser_mgr().Parse(new_page, true); // refresh html + tab.Page_(new_page); new_page.Tab_data().Tab_(tab); // replace old page with new_page; DATE:2014-10-09 + + Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001(); + Xoh_page_wtr_wkr wkr = wiki.Html_mgr().Page_wtr_mgr().Wkr(Xopg_view_mode_.Tid__read); + wkr.Write_body(tmp_bfr, wiki.Parser_mgr().Ctx(), Xoh_wtr_ctx.Basic, new_page); + byte[] new_html = tmp_bfr.To_bry_and_rls(); + new_page.Html_data().Edit_preview_(new_html); + + Invalidate(wiki); + win_itm.Page__mode_(Xopg_view_mode_.Tid__edit); + html_itm.Scroll_page_by_id_gui(Xog_html_itm.Elem_id__first_heading);// NOTE: was originally directly; changed to call on thread; DATE:2014-05-03 + win_itm.Page__async__bgn(tab); // NOTE: needed to show images during preview; DATE:2014-06-21 + } + public static void Rename(Xog_tab_itm tab) { + if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles ctrl+r being pressed + Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win(); + if (Bry_.Eq(page.Ttl().Page_db(), wiki.Props().Main_page())) { + win_itm.Usr_dlg().Warn_many("", "", "The Main Page cannot be renamed"); + win_itm.Kit().Ask_ok("", "", "The Main Page cannot be renamed"); + return; + } + byte[] new_text = Bry_.new_u8(tab.Html_itm().Get_elem_value(Xog_html_itm.Elem_id__xowa_edit_rename_box)); + if (Bry_.Len_eq_0(new_text)) return; // no ttl given; exit + new_text = Xoa_ttl.Replace_spaces(new_text); // ttls cannot have spaces; only underscores + Xoa_ttl new_ttl = Xoa_ttl.Parse(wiki, new_text); + int new_ns_id = new_ttl.Ns().Id(); + if (new_ns_id != Xow_ns_.Tid__main) { + win_itm.Usr_dlg().Warn_many("", "", "The new page name must remain in the same namespace"); + return; + } + wiki.Db_mgr().Save_mgr().Data_rename(page, new_ns_id, new_text); + page.Ttl_(Xoa_ttl.Parse(wiki, Bry_.Add(page.Ttl().Ns().Name_db_w_colon(), new_text))); + win_itm.Page__mode_(Xopg_view_mode_.Tid__read); + win_itm.Usr_dlg().Prog_one("", "", "renamed page to {0}", String_.new_u8(page.Ttl().Full_txt_raw())); + } + public static void Focus(Xog_win_itm win, String elem_focus_id) { + Gfui_html html_box = win.Active_html_box(); + html_box.Focus(); + html_box.Html_js_eval_proc_as_str(Xog_js_procs.Doc__elem_focus, elem_focus_id); + } + public static void Debug(Xog_win_itm win, byte view_tid) { + Xog_tab_itm tab = win.Tab_mgr().Active_tab(); Xoae_page page = tab.Page(); + Xowe_wiki wiki = tab.Wiki(); Xop_ctx ctx = wiki.Parser_mgr().Ctx(); + ctx.Defn_trace().Clear(); // TODO_OLD: move_me + ctx.Defn_trace_(Xot_defn_trace_dbg.Instance); + Xoa_ttl ttl = page.Ttl(); + Xoae_page new_page = Xoae_page.New(wiki, ttl); + new_page.Url_(page.Url()); // NOTE: must set Url explicitly, else new_page will not have same url_args as old_page; broken when going to action=edit; DATE:2018-12-09 + byte[] data = tab.Html_itm().Get_elem_value_for_edit_box_as_bry(); + new_page.Db().Text().Text_bry_(data); + wiki.Parser_mgr().Parse(new_page, true); + Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_m001(); + bfr.Add(new_page.Root().Root_src()); + wiki.Parser_mgr().Ctx().Defn_trace().Print(data, bfr); + new_page.Db().Text().Text_bry_(bfr.To_bry_and_rls()); + byte old = tab.View_mode(); + tab.View_mode_(view_tid); + Xog_tab_itm_read_mgr.Show_page(tab, new_page, false); + tab.History_mgr().Add(new_page); + tab.View_mode_(old); + } + private static void Invalidate(Xowe_wiki wiki) {// invalidate everything on updates; especially needed for page transclusion; {{/my_subpage}} DATE:2014-04-10 + wiki.Parser_mgr().Scrib().Core_term(); + wiki.Cache_mgr().Free_mem__all(); + } + private static byte[] Get_new_text(Xog_tab_itm tab, byte[] orig) { + byte[] rv = tab.Html_itm().Get_elem_value_for_edit_box_as_bry(); + if (orig != null) // orig == null for Preview + rv = tab.Wiki().Parser_mgr().Hdr__section_editable__mgr().Merge_section(tab.Page().Url(), rv, orig); + rv = Bry_.Trim(rv, 0, rv.length, false, true, Bry_.Trim_ary_ws, true); // MW: trim all trailing ws; REF:EditPage.php!safeUnicodeInput; DATE:2014-04-25 + return rv; + } +} diff --git a/400_xowa/src/gplx/xowa/htmls/core/Xow_hdump_mgr__save.java b/400_xowa/src/gplx/xowa/htmls/core/Xow_hdump_mgr__save.java index 32082fcf8..aeb27dc6c 100644 --- a/400_xowa/src/gplx/xowa/htmls/core/Xow_hdump_mgr__save.java +++ b/400_xowa/src/gplx/xowa/htmls/core/Xow_hdump_mgr__save.java @@ -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,74 +13,106 @@ 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.htmls.core; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; -import gplx.xowa.htmls.core.htmls.*; import gplx.xowa.htmls.core.wkrs.*; import gplx.xowa.htmls.core.hzips.*; import gplx.xowa.htmls.heads.*; import gplx.xowa.htmls.core.dbs.*; -import gplx.core.ios.*; import gplx.core.primitives.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.pages.*; -import gplx.xowa.addons.wikis.pages.syncs.core.parsers.*; -public class Xow_hdump_mgr__save { - private final Xow_wiki wiki; private final Xoh_hzip_mgr hzip_mgr; private final Io_stream_zip_mgr zip_mgr; - private final Xoh_page tmp_hpg; private final Xoh_hzip_bfr tmp_bfr = Xoh_hzip_bfr.New_txt(32); private Bool_obj_ref html_db_is_new = Bool_obj_ref.n_(); - private int dflt_zip_tid, dflt_hzip_tid; - public Xow_hdump_mgr__save(Xow_wiki wiki, Xoh_hzip_mgr hzip_mgr, Io_stream_zip_mgr zip_mgr, Xoh_page tmp_hpg) { - this.wiki = wiki; this.hzip_mgr = hzip_mgr; this.zip_mgr = zip_mgr; this.tmp_hpg = tmp_hpg; - } - public void Init_by_db(int dflt_zip_tid, int dflt_hzip_tid, boolean mode_is_b256) { - this.dflt_zip_tid = dflt_zip_tid; this.dflt_hzip_tid = dflt_hzip_tid; tmp_bfr.Mode_is_b256_(mode_is_b256); - } - public byte[] Src_as_hzip() {return src_as_hzip;} private byte[] src_as_hzip; - public int Save(Xoae_page page) { - synchronized (tmp_hpg) { - Bld_hdump(page); - tmp_hpg.Ctor_by_hdiff(tmp_bfr, page, page.Wikie().Msg_mgr().Val_by_id(gplx.xowa.langs.msgs.Xol_msg_itm_.Id_toc)); - Xow_db_file html_db = Get_html_db(wiki, page, html_db_is_new.Val_n_()); - return Save(page, tmp_hpg, html_db.Tbl__html(), html_db_is_new.Val(), true); - } - } - public int Save(Xoae_page page, Xoh_page hpg, Xowd_html_tbl html_tbl, boolean insert, boolean use_hzip_dflt) { - int hzip_tid = use_hzip_dflt ? dflt_hzip_tid : Xoh_hzip_dict_.Hdb__htxt; - byte[] db_body = Write(tmp_bfr, wiki, page, hpg, hzip_mgr, zip_mgr, dflt_zip_tid, hzip_tid, hpg.Db().Html().Html_bry()); - if (insert) html_tbl.Insert(hpg, dflt_zip_tid, dflt_hzip_tid, db_body); - else html_tbl.Update(hpg, dflt_zip_tid, dflt_hzip_tid, db_body); - return db_body.length; - } - public void Bld_hdump(Xoae_page page) { - page.File_queue().Clear(); // need to reset uid to 0, else xowa_file_# will keep incrementing upwards - Xoh_wtr_ctx hctx = Xoh_wtr_ctx.Hdump_by_hzip_tid(dflt_hzip_tid); - wiki.Html__wtr_mgr().Wkr(Xopg_view_mode_.Tid__read).Write_body(tmp_bfr, page.Wikie().Parser_mgr().Ctx(), hctx, page); // save as hdump_fmt - page.Db().Html().Html_bry_(tmp_bfr.To_bry_and_clear()); - } - private byte[] Write(Xoh_hzip_bfr bfr, Xow_wiki wiki, Xoae_page page, Xoh_page hpg, Xoh_hzip_mgr hzip_mgr, Io_stream_zip_mgr zip_mgr, int zip_tid, int hzip_tid, byte[] src) { - switch (hzip_tid) { - case Xoh_hzip_dict_.Hdb__htxt: - break; - case Xoh_hzip_dict_.Hdb__hzip: - src = hzip_mgr.Encode_as_bry((Xoh_hzip_bfr)bfr.Clear(), wiki, hpg, src); - break; - // TOMBSTONE: not used; Xosync_update_mgr calls save directly; unsure if this should be restored for parallelism - // case Xoh_hzip_dict_.Hdb__page_sync: - // src = plain_parser.Parse_hdoc(wiki.Domain_itm(), page.Url_bry_safe(), hpg.Hdump_mgr().Imgs(), src); - // break; - } - src_as_hzip = src; - if (zip_tid > gplx.core.ios.streams.Io_stream_tid_.Tid__raw) - src = zip_mgr.Zip((byte)zip_tid, src); - return src; - } - private static Xow_db_file Get_html_db(Xow_wiki wiki, Xoae_page page, Bool_obj_ref html_db_is_new) { - Xow_db_file rv = Xow_db_file.Null; - Xow_db_mgr core_data_mgr = wiki.Data__core_mgr(); - int html_db_id = page.Db().Page().Html_db_id(); - if (html_db_id == -1) { - html_db_is_new.Val_y_(); - rv = core_data_mgr.Db__html(); - if (rv == null) rv = core_data_mgr.Dbs__make_by_tid(Xow_db_file_.Tid__html_data); - html_db_id = rv.Id(); - page.Db().Page().Html_db_id_(html_db_id); - core_data_mgr.Tbl__page().Update__html_db_id(page.Db().Page().Id(), html_db_id); - } - else { - rv = core_data_mgr.Dbs__get_by_id_or_fail(html_db_id); - } - return rv; - } -} +package gplx.xowa.htmls.core; + +import gplx.core.ios.Io_stream_zip_mgr; +import gplx.core.primitives.Bool_obj_ref; +import gplx.xowa.Xoae_page; +import gplx.xowa.Xow_wiki; +import gplx.xowa.htmls.Xoh_page; +import gplx.xowa.htmls.core.dbs.Xowd_html_tbl; +import gplx.xowa.htmls.core.htmls.Xoh_wtr_ctx; +import gplx.xowa.htmls.core.hzips.Xoh_hzip_dict_; +import gplx.xowa.htmls.core.hzips.Xoh_hzip_mgr; +import gplx.xowa.htmls.core.wkrs.Xoh_hzip_bfr; +import gplx.xowa.wikis.data.Xow_db_file; +import gplx.xowa.wikis.data.Xow_db_file_; +import gplx.xowa.wikis.data.Xow_db_mgr; +import gplx.xowa.wikis.pages.Xopg_view_mode_; +import gplx.xowa.wikis.pages.dbs.Xopg_db_page; + +public class Xow_hdump_mgr__save { + private final Xow_wiki wiki; private final Xoh_hzip_mgr hzip_mgr; private final Io_stream_zip_mgr zip_mgr; + private final Xoh_page tmp_hpg; private final Xoh_hzip_bfr tmp_bfr = Xoh_hzip_bfr.New_txt(32); private Bool_obj_ref html_db_is_new = Bool_obj_ref.n_(); + private int dflt_zip_tid, dflt_hzip_tid; + public Xow_hdump_mgr__save(Xow_wiki wiki, Xoh_hzip_mgr hzip_mgr, Io_stream_zip_mgr zip_mgr, Xoh_page tmp_hpg) { + this.wiki = wiki; this.hzip_mgr = hzip_mgr; this.zip_mgr = zip_mgr; this.tmp_hpg = tmp_hpg; + } + public void Init_by_db(int dflt_zip_tid, int dflt_hzip_tid, boolean mode_is_b256) { + this.dflt_zip_tid = dflt_zip_tid; this.dflt_hzip_tid = dflt_hzip_tid; tmp_bfr.Mode_is_b256_(mode_is_b256); + } + public byte[] Src_as_hzip() {return src_as_hzip;} private byte[] src_as_hzip; + public int Save(Xoae_page page) {return Save(page, false);} + public int Save(Xoae_page page, boolean isEdit) { + synchronized (tmp_hpg) { + Bld_hdump(page); + tmp_hpg.Ctor_by_hdiff(tmp_bfr, page, page.Wikie().Msg_mgr().Val_by_id(gplx.xowa.langs.msgs.Xol_msg_itm_.Id_toc)); + Xow_db_file html_db = Get_html_db(wiki, page, html_db_is_new.Val_n_(), isEdit); + return Save(page, tmp_hpg, html_db.Tbl__html(), html_db_is_new.Val(), true); + } + } + public int Save(Xoae_page page, Xoh_page hpg, Xowd_html_tbl html_tbl, boolean insert, boolean use_hzip_dflt) { + int hzip_tid = use_hzip_dflt ? dflt_hzip_tid : Xoh_hzip_dict_.Hdb__htxt; + byte[] db_body = Write(tmp_bfr, wiki, page, hpg, hzip_mgr, zip_mgr, dflt_zip_tid, hzip_tid, hpg.Db().Html().Html_bry()); + if (insert) html_tbl.Insert(hpg, dflt_zip_tid, dflt_hzip_tid, db_body); + else html_tbl.Update(hpg, dflt_zip_tid, dflt_hzip_tid, db_body); + return db_body.length; + } + public void Bld_hdump(Xoae_page page) { + page.File_queue().Clear(); // need to reset uid to 0, else xowa_file_# will keep incrementing upwards + Xoh_wtr_ctx hctx = Xoh_wtr_ctx.Hdump_by_hzip_tid(dflt_hzip_tid); + wiki.Html__wtr_mgr().Wkr(Xopg_view_mode_.Tid__read).Write_body(tmp_bfr, page.Wikie().Parser_mgr().Ctx(), hctx, page); // save as hdump_fmt + page.Db().Html().Html_bry_(tmp_bfr.To_bry_and_clear()); + } + private byte[] Write(Xoh_hzip_bfr bfr, Xow_wiki wiki, Xoae_page page, Xoh_page hpg, Xoh_hzip_mgr hzip_mgr, Io_stream_zip_mgr zip_mgr, int zip_tid, int hzip_tid, byte[] src) { + switch (hzip_tid) { + case Xoh_hzip_dict_.Hdb__htxt: + break; + case Xoh_hzip_dict_.Hdb__hzip: + src = hzip_mgr.Encode_as_bry((Xoh_hzip_bfr)bfr.Clear(), wiki, hpg, src); + break; + // TOMBSTONE: not used; Xosync_update_mgr calls save directly; unsure if this should be restored for parallelism + // case Xoh_hzip_dict_.Hdb__page_sync: + // src = plain_parser.Parse_hdoc(wiki.Domain_itm(), page.Url_bry_safe(), hpg.Hdump_mgr().Imgs(), src); + // break; + } + src_as_hzip = src; + if (zip_tid > gplx.core.ios.streams.Io_stream_tid_.Tid__raw) + src = zip_mgr.Zip((byte)zip_tid, src); + return src; + } + private static Xow_db_file Get_html_db(Xow_wiki wiki, Xoae_page page, Bool_obj_ref html_db_is_new, boolean isEdit) { + Xow_db_file rv = Xow_db_file.Null; + Xow_db_mgr core_data_mgr = wiki.Data__core_mgr(); + int html_db_id = page.Db().Page().Html_db_id(); + if (html_db_id == Xopg_db_page.HTML_DB_ID_NULL) { + html_db_is_new.Val_y_(); + + // get htmlDbTid; NOTE: probably do not need Tid__html_data b/c xomp_wkr and sync_mgr should be building the databases; ISSUE#:699; DATE:2020-08-06 + byte htmlDbTid = isEdit ? Xow_db_file_.Tid__html_user : Xow_db_file_.Tid__html_data; + + // get htmlDb + if (isEdit) { + rv = core_data_mgr.Dbs__get_by_tid_or_null(htmlDbTid); + } + else { + rv = core_data_mgr.Db__html(); + } + + // make htmlDb if not available + if (rv == null) { + rv = core_data_mgr.Dbs__make_by_tid(htmlDbTid); + Xowd_html_tbl html_tbl = new Xowd_html_tbl(rv.Conn()); + html_tbl.Create_tbl(); + } + + html_db_id = rv.Id(); + page.Db().Page().Html_db_id_(html_db_id); + core_data_mgr.Tbl__page().Update__html_db_id(page.Db().Page().Id(), html_db_id); + } + else { + rv = core_data_mgr.Dbs__get_by_id_or_fail(html_db_id); + } + return rv; + } +} diff --git a/400_xowa/src/gplx/xowa/htmls/hxtns/blobs/Hxtn_blob_tbl.java b/400_xowa/src/gplx/xowa/htmls/hxtns/blobs/Hxtn_blob_tbl.java index 5fea764d2..56bbc8e7d 100644 --- a/400_xowa/src/gplx/xowa/htmls/hxtns/blobs/Hxtn_blob_tbl.java +++ b/400_xowa/src/gplx/xowa/htmls/hxtns/blobs/Hxtn_blob_tbl.java @@ -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,85 +13,111 @@ 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.htmls.hxtns.blobs; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.hxtns.*; -import gplx.dbs.*; -import gplx.core.ios.*; -public class Hxtn_blob_tbl implements Rls_able { - private static final String tbl_name = "hxtn_blob"; private static final Dbmeta_fld_list flds = new Dbmeta_fld_list(); - private static final String - fld_blob_tid = flds.Add_int("blob_tid"), fld_wiki_id = flds.Add_int("wiki_id"), fld_blob_id = flds.Add_int("blob_id") - , fld_zip_tid = flds.Add_byte("zip_tid"), fld_blob_data = flds.Add_bry("blob_data"); - private final Db_conn conn; private Db_stmt stmt_insert; - private final byte zip_tid_default; - private final Io_stream_zip_mgr zip_mgr = new Io_stream_zip_mgr(); - public Hxtn_blob_tbl(Db_conn conn, byte zip_tid_default) { - this.conn = conn; - conn.Rls_reg(this); - this.zip_tid_default = zip_tid_default; - } - public String Tbl_name() {return tbl_name;} - public Db_conn Conn() {return conn;} - public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));} - public void Rls() { - stmt_insert = Db_stmt_.Rls(stmt_insert); - } - public void Stmt_bgn() { - stmt_insert = conn.Stmt_insert(tbl_name, flds); - } - public void Stmt_end() { - this.Rls(); - if (!conn.Meta_idx_exists(tbl_name, "pkey")) - conn.Meta_idx_create(Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "pkey", fld_blob_id, fld_wiki_id, fld_blob_tid)); - } - public void Insert_by_rdr(Db_rdr rdr) { - Db_stmt_.Insert_by_rdr(flds, rdr, stmt_insert); - } - public void Insert_exec(int blob_tid, int wiki_id, int blob_id, byte[] blob_data) { - blob_data = zip_mgr.Zip(zip_tid_default, blob_data); - stmt_insert.Clear() - .Val_int(fld_blob_tid , blob_tid) - .Val_int(fld_wiki_id , wiki_id) - .Val_int(fld_blob_id , blob_id) - .Val_byte(fld_zip_tid , zip_tid_default) - .Val_bry(fld_blob_data , blob_data) - .Exec_insert(); - } - public void Select_to_regy(Bry_bfr temp_bfr, Hash_adp_bry blob_data_hash) { - Db_rdr rdr = conn.Stmt_select(tbl_name, String_.Ary(fld_wiki_id, fld_blob_id, fld_blob_tid)) - .Exec_select__rls_auto(); - try { - while (rdr.Move_next()) { - byte[] key = Make_key(temp_bfr, rdr.Read_int(fld_wiki_id), rdr.Read_int(fld_blob_id), rdr.Read_int(fld_blob_tid)); - blob_data_hash.Add_as_key_and_val(key); - } - } finally { - rdr.Rls(); - } - } - public byte[] Select_text(int blob_tid, int wiki_id, int blob_id) { - Db_rdr rdr = conn.Stmt_select(tbl_name, flds, fld_blob_id, fld_wiki_id, fld_blob_tid) - .Crt_int(fld_blob_id, blob_id) - .Crt_int(fld_wiki_id, wiki_id) - .Crt_int(fld_blob_tid, blob_tid) - .Exec_select__rls_auto(); - try { - if (rdr.Move_next()) { - byte[] rv = rdr.Read_bry(fld_blob_data); - byte zip_type = rdr.Read_byte(fld_zip_tid); - rv = zip_mgr.Unzip(zip_type, rv); - return rv; - } - else { - return null; - } - } finally { - rdr.Rls(); - } - } - - public static byte[] Make_key(Bry_bfr temp_bfr, int blob_id, int wiki_id, int blob_tid) { - return temp_bfr.Add_int_variable(blob_id).Add_byte_pipe().Add_int_variable(wiki_id).Add_byte_pipe().Add_int_variable(blob_tid).To_bry_and_clear(); - } - - public static final int Blob_tid__wtxt = 0, Blob_tid__html = 1; +package gplx.xowa.htmls.hxtns.blobs; + +import gplx.Bry_bfr; +import gplx.Hash_adp_bry; +import gplx.Rls_able; +import gplx.String_; +import gplx.core.ios.Io_stream_zip_mgr; +import gplx.dbs.Db_conn; +import gplx.dbs.Db_rdr; +import gplx.dbs.Db_rdr_; +import gplx.dbs.Db_stmt; +import gplx.dbs.Db_stmt_; +import gplx.dbs.Dbmeta_fld_list; +import gplx.dbs.Dbmeta_idx_itm; +import gplx.dbs.Dbmeta_tbl_itm; + +public class Hxtn_blob_tbl implements Rls_able { + private static final String tbl_name = "hxtn_blob"; private static final Dbmeta_fld_list flds = new Dbmeta_fld_list(); + private static final String + fld_blob_tid = flds.Add_int("blob_tid"), fld_wiki_id = flds.Add_int("wiki_id"), fld_blob_id = flds.Add_int("blob_id") + , fld_zip_tid = flds.Add_byte("zip_tid"), fld_blob_data = flds.Add_bry("blob_data"); + private final Db_conn conn; private Db_stmt stmt_insert; + private final byte zip_tid_default; + private final Io_stream_zip_mgr zip_mgr = new Io_stream_zip_mgr(); + public Hxtn_blob_tbl(Db_conn conn, byte zip_tid_default) { + this.conn = conn; + conn.Rls_reg(this); + this.zip_tid_default = zip_tid_default; + } + public String Tbl_name() {return tbl_name;} + public Db_conn Conn() {return conn;} + public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));} + public void Rls() { + stmt_insert = Db_stmt_.Rls(stmt_insert); + } + public void Stmt_bgn() { + stmt_insert = conn.Stmt_insert(tbl_name, flds); + } + public void Stmt_end() { + this.Rls(); + if (!conn.Meta_idx_exists(tbl_name, "pkey")) + conn.Meta_idx_create(Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "pkey", fld_blob_id, fld_wiki_id, fld_blob_tid)); + } + public void Insert_by_rdr(Db_rdr rdr) { + Db_stmt_.Insert_by_rdr(flds, rdr, stmt_insert); + } + public void Insert_exec(int blob_tid, int wiki_id, int blob_id, byte[] blob_data) { + blob_data = zip_mgr.Zip(zip_tid_default, blob_data); + stmt_insert.Clear() + .Val_int(fld_blob_tid , blob_tid) + .Val_int(fld_wiki_id , wiki_id) + .Val_int(fld_blob_id , blob_id) + .Val_byte(fld_zip_tid , zip_tid_default) + .Val_bry(fld_blob_data , blob_data) + .Exec_insert(); + } + public boolean Exists(int blob_tid, int wiki_id, int blob_id) { + Db_rdr rdr = Db_rdr_.Empty; + try { + rdr = conn.Stmt_select(tbl_name, flds, fld_blob_tid, fld_wiki_id, fld_blob_id) + .Crt_int(fld_blob_tid, blob_tid) + .Crt_int(fld_wiki_id, wiki_id) + .Crt_int(fld_blob_id, blob_id) + .Exec_select__rls_auto(); + return rdr.Move_next(); + } finally { + rdr.Rls(); + } + } + public void Select_to_regy(Bry_bfr temp_bfr, Hash_adp_bry blob_data_hash) { + Db_rdr rdr = conn.Stmt_select(tbl_name, String_.Ary(fld_wiki_id, fld_blob_id, fld_blob_tid)) + .Exec_select__rls_auto(); + try { + while (rdr.Move_next()) { + byte[] key = Make_key(temp_bfr, rdr.Read_int(fld_wiki_id), rdr.Read_int(fld_blob_id), rdr.Read_int(fld_blob_tid)); + blob_data_hash.Add_as_key_and_val(key); + } + } finally { + rdr.Rls(); + } + } + public byte[] Select_text(int blob_tid, int wiki_id, int blob_id) { + Db_rdr rdr = conn.Stmt_select(tbl_name, flds, fld_blob_id, fld_wiki_id, fld_blob_tid) + .Crt_int(fld_blob_id, blob_id) + .Crt_int(fld_wiki_id, wiki_id) + .Crt_int(fld_blob_tid, blob_tid) + .Exec_select__rls_auto(); + try { + if (rdr.Move_next()) { + byte[] rv = rdr.Read_bry(fld_blob_data); + byte zip_type = rdr.Read_byte(fld_zip_tid); + rv = zip_mgr.Unzip(zip_type, rv); + return rv; + } + else { + return null; + } + } finally { + rdr.Rls(); + } + } + + public static byte[] Make_key(Bry_bfr temp_bfr, int blob_id, int wiki_id, int blob_tid) { + return temp_bfr.Add_int_variable(blob_id).Add_byte_pipe().Add_int_variable(wiki_id).Add_byte_pipe().Add_int_variable(blob_tid).To_bry_and_clear(); + } + + public static final int Blob_tid__wtxt = 0, Blob_tid__html = 1; } \ No newline at end of file diff --git a/400_xowa/src/gplx/xowa/htmls/hxtns/pages/Hxtn_page_mgr.java b/400_xowa/src/gplx/xowa/htmls/hxtns/pages/Hxtn_page_mgr.java index 981814ca0..945f48232 100644 --- a/400_xowa/src/gplx/xowa/htmls/hxtns/pages/Hxtn_page_mgr.java +++ b/400_xowa/src/gplx/xowa/htmls/hxtns/pages/Hxtn_page_mgr.java @@ -1,122 +1,124 @@ -/* -XOWA: the XOWA Offline Wiki Application -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. - -You may use XOWA according to either of these licenses as is most appropriate -for your project on a case-by-case basis. - -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.htmls.hxtns.pages; - -import gplx.Bry_bfr; -import gplx.Bry_bfr_; -import gplx.Gfo_usr_dlg_; -import gplx.Hash_adp_bry; -import gplx.Io_mgr; -import gplx.Io_url; -import gplx.List_adp; -import gplx.core.lists.hashs.Hash_adp__int; -import gplx.dbs.Db_conn; -import gplx.dbs.Db_conn_bldr; -import gplx.xowa.Xoa_ttl; -import gplx.xowa.Xow_wiki; -import gplx.xowa.htmls.Xoh_page; -import gplx.xowa.htmls.hxtns.blobs.Hxtn_blob_tbl; -import gplx.xowa.htmls.hxtns.wikis.Hxtn_wiki_mgr; -import gplx.xowa.htmls.hxtns.wkrs.Hxtn_wkr_mgr; -public class Hxtn_page_mgr { - private Hxtn_page_tbl page_tbl; - private Hxtn_blob_tbl blob_tbl; - private Hash_adp_bry blob_hash; - private final Hash_adp__int wkrs = new Hash_adp__int(); - private boolean dbs_missing = true; - private Bry_bfr temp_bfr; - public Hxtn_page_tbl Page_tbl() {return page_tbl;} - public Hxtn_blob_tbl Blob_tbl() {return blob_tbl;} - - public void Init_by_xomp_wkr(Db_conn wkr_db_conn, byte zip_tid) { - // init tbls and other members - this.page_tbl = new Hxtn_page_tbl(wkr_db_conn); - this.blob_tbl = new Hxtn_blob_tbl(wkr_db_conn, zip_tid); - this.blob_hash = Hash_adp_bry.cs(); - this.temp_bfr = Bry_bfr_.New(); - - // if tbl exists, xomp_resume has run; load known blobs to prevent dupes - if (wkr_db_conn.Meta_tbl_exists(page_tbl.Tbl_name())) { - blob_tbl.Select_to_regy(temp_bfr, blob_hash); - } - // else tbl doesn't exist, so create them - else { - page_tbl.Create_tbl(); - blob_tbl.Create_tbl(); - } - } - public void Init_by_wiki(Xow_wiki wiki, boolean is_merge) { - Io_url core_db_url = Make_url(wiki, "-html.hxtn-core.xowa"); - if (!is_merge && !Io_mgr.Instance.ExistsFil(core_db_url)) return; - dbs_missing = false; - Db_conn page_conn = Db_conn_bldr.Instance.Get_or_new(core_db_url).Conn(); - this.page_tbl = new Hxtn_page_tbl(page_conn); - - Io_url blob_db_url = Make_url(wiki, "-html.hxtn-blob.xowa"); - this.blob_tbl = new Hxtn_blob_tbl(Db_conn_bldr.Instance.Get_or_new(blob_db_url).Conn(), gplx.core.ios.streams.Io_stream_tid_.Tid__raw); - - if (is_merge) { - page_tbl.Create_tbl(); - blob_tbl.Create_tbl(); - - Hxtn_wkr_mgr wkr_mgr = new Hxtn_wkr_mgr(); - wkr_mgr.Init_by_xomp_merge(page_conn); - - Hxtn_wiki_mgr wiki_mgr = new Hxtn_wiki_mgr(); - wiki_mgr.Init_by_xomp_merge(page_conn, wiki.Domain_str()); - } - } - public void Insert_bgn(boolean is_merge) { - page_tbl.Stmt_bgn(); - blob_tbl.Stmt_bgn(); - } - public void Insert_end(boolean is_merge) { - page_tbl.Stmt_end(); - blob_tbl.Stmt_end(); - } - public void Page_tbl__insert(int page_id, int wkr_id, int data_id) { - page_tbl.Insert_exec(page_id, wkr_id, data_id); - } - public void Blob_tbl__insert(int blob_tid, int wiki_id, int blob_id, byte[] blob_text) { - byte[] key = Hxtn_blob_tbl.Make_key(temp_bfr, blob_tid, wiki_id, blob_id); - if (!blob_hash.Has(key)) {// multiple pages can refer to same template; only insert if not seen - blob_hash.Add_as_key_and_val(key); - blob_tbl.Insert_exec(blob_tid, wiki_id, blob_id, blob_text); - } - } - public void Reg_wkr(Hxtn_page_wkr wkr) { - wkrs.Add(wkr.Id(), wkr); - } - public void Load_by_page(Xoh_page hpg, Xoa_ttl ttl) { - if (dbs_missing) return; // PERF:do not call SELECT if dbs don't exist - List_adp list = page_tbl.Select_by_page(hpg.Page_id()); - int len = list.Len(); - for (int i = 0; i < len; i++) { - Hxtn_page_itm itm = (Hxtn_page_itm)list.Get_at(i); - Hxtn_page_wkr wkr = (Hxtn_page_wkr)wkrs.Get_by_or_null(itm.Wkr_id()); - if (wkr == null) { // ignore unknown wkrs so other devs can add new xtns; ISSUE#:634; DATE:2020-03-08 - Gfo_usr_dlg_.Instance.Warn_many("", "", "hxtn.unknown wkr: page_id=~{0} wkr_id=~{1}", itm.Page_id(), itm.Wkr_id()); - continue; - } - wkr.Load_by_page(hpg, ttl, itm.Data_id()); - } - } - private static Io_url Make_url(Xow_wiki wiki, String file_name) {return wiki.Fsys_mgr().Root_dir().GenSubFil(wiki.Domain_str() + file_name);} - public static final int - Id__template_styles = 0 - , Id__indicators = 2 - ; -} +/* +XOWA: the XOWA Offline Wiki Application +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. + +You may use XOWA according to either of these licenses as is most appropriate +for your project on a case-by-case basis. + +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.htmls.hxtns.pages; + +import gplx.Bry_bfr; +import gplx.Bry_bfr_; +import gplx.Gfo_usr_dlg_; +import gplx.Hash_adp_bry; +import gplx.Io_mgr; +import gplx.Io_url; +import gplx.List_adp; +import gplx.core.lists.hashs.Hash_adp__int; +import gplx.dbs.Db_conn; +import gplx.dbs.Db_conn_bldr; +import gplx.xowa.Xoa_ttl; +import gplx.xowa.Xow_wiki; +import gplx.xowa.htmls.Xoh_page; +import gplx.xowa.htmls.hxtns.blobs.Hxtn_blob_tbl; +import gplx.xowa.htmls.hxtns.wikis.Hxtn_wiki_mgr; +import gplx.xowa.htmls.hxtns.wkrs.Hxtn_wkr_mgr; + +public class Hxtn_page_mgr { + private Hxtn_page_tbl page_tbl; + private Hxtn_blob_tbl blob_tbl; + private Hash_adp_bry blob_hash = Hash_adp_bry.cs(); + private final Hash_adp__int wkrs = new Hash_adp__int(); + private boolean dbs_missing = true; + private Bry_bfr temp_bfr = Bry_bfr_.New(); + public Hxtn_page_tbl Page_tbl() {return page_tbl;} + public Hxtn_blob_tbl Blob_tbl() {return blob_tbl;} + + public void Init_by_xomp_wkr(Db_conn wkr_db_conn, byte zip_tid) { + // init tbls and other members + this.page_tbl = new Hxtn_page_tbl(wkr_db_conn); + this.blob_tbl = new Hxtn_blob_tbl(wkr_db_conn, zip_tid); + + // if tbl exists, xomp_resume has run; load known blobs to prevent dupes + if (wkr_db_conn.Meta_tbl_exists(page_tbl.Tbl_name())) { + blob_tbl.Select_to_regy(temp_bfr, blob_hash); + } + // else tbl doesn't exist, so create them + else { + page_tbl.Create_tbl(); + blob_tbl.Create_tbl(); + } + } + public void Init_by_wiki(Xow_wiki wiki, boolean is_merge) { + Io_url core_db_url = Make_url(wiki, "-html.hxtn-core.xowa"); + if (!is_merge && !Io_mgr.Instance.ExistsFil(core_db_url)) return; + dbs_missing = false; + Db_conn page_conn = Db_conn_bldr.Instance.Get_or_new(core_db_url).Conn(); + this.page_tbl = new Hxtn_page_tbl(page_conn); + + Io_url blob_db_url = Make_url(wiki, "-html.hxtn-blob.xowa"); + this.blob_tbl = new Hxtn_blob_tbl(Db_conn_bldr.Instance.Get_or_new(blob_db_url).Conn(), gplx.core.ios.streams.Io_stream_tid_.Tid__raw); + + if (is_merge) { + page_tbl.Create_tbl(); + blob_tbl.Create_tbl(); + + Hxtn_wkr_mgr wkr_mgr = new Hxtn_wkr_mgr(); + wkr_mgr.Init_by_xomp_merge(page_conn); + + Hxtn_wiki_mgr wiki_mgr = new Hxtn_wiki_mgr(); + wiki_mgr.Init_by_xomp_merge(page_conn, wiki.Domain_str()); + } + } + public void Insert_bgn(boolean is_merge) { + page_tbl.Stmt_bgn(); + blob_tbl.Stmt_bgn(); + } + public void Insert_end(boolean is_merge) { + page_tbl.Stmt_end(); + blob_tbl.Stmt_end(); + } + public void Page_tbl__insert(int page_id, int wkr_id, int data_id) { + if (!page_tbl.Exists(page_id, wkr_id, data_id)) + page_tbl.Insert_exec(page_id, wkr_id, data_id); + } + public void Blob_tbl__insert(int blob_tid, int wiki_id, int blob_id, byte[] blob_text) { + byte[] key = Hxtn_blob_tbl.Make_key(temp_bfr, blob_tid, wiki_id, blob_id); + if (!blob_hash.Has(key)) {// multiple pages can refer to same template; only insert if not seen + blob_hash.Add_as_key_and_val(key); + if (!blob_tbl.Exists(blob_tid, wiki_id, blob_id)) { + blob_tbl.Insert_exec(blob_tid, wiki_id, blob_id, blob_text); + } + } + } + public void Reg_wkr(Hxtn_page_wkr wkr) { + wkrs.Add(wkr.Id(), wkr); + } + public void Load_by_page(Xoh_page hpg, Xoa_ttl ttl) { + if (dbs_missing) return; // PERF:do not call SELECT if dbs don't exist + List_adp list = page_tbl.Select_by_page(hpg.Page_id()); + int len = list.Len(); + for (int i = 0; i < len; i++) { + Hxtn_page_itm itm = (Hxtn_page_itm)list.Get_at(i); + Hxtn_page_wkr wkr = (Hxtn_page_wkr)wkrs.Get_by_or_null(itm.Wkr_id()); + if (wkr == null) { // ignore unknown wkrs so other devs can add new xtns; ISSUE#:634; DATE:2020-03-08 + Gfo_usr_dlg_.Instance.Warn_many("", "", "hxtn.unknown wkr: page_id=~{0} wkr_id=~{1}", itm.Page_id(), itm.Wkr_id()); + continue; + } + wkr.Load_by_page(hpg, ttl, itm.Data_id()); + } + } + private static Io_url Make_url(Xow_wiki wiki, String file_name) {return wiki.Fsys_mgr().Root_dir().GenSubFil(wiki.Domain_str() + file_name);} + public static final int + Id__template_styles = 0 + , Id__indicators = 2 + ; +} diff --git a/400_xowa/src/gplx/xowa/htmls/hxtns/pages/Hxtn_page_tbl.java b/400_xowa/src/gplx/xowa/htmls/hxtns/pages/Hxtn_page_tbl.java index 7429f737d..c5b093da7 100644 --- a/400_xowa/src/gplx/xowa/htmls/hxtns/pages/Hxtn_page_tbl.java +++ b/400_xowa/src/gplx/xowa/htmls/hxtns/pages/Hxtn_page_tbl.java @@ -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,57 +13,82 @@ 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.htmls.hxtns.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.hxtns.*; -import gplx.dbs.*; -public class Hxtn_page_tbl implements Rls_able { - private static final String tbl_name = "hxtn_page"; private final Dbmeta_fld_list flds = new Dbmeta_fld_list(); - private final String fld_page_id, fld_wkr_id, fld_data_id; - private final Db_conn conn; private Db_stmt stmt_insert; - public Hxtn_page_tbl(Db_conn conn) { - this.conn = conn; - conn.Rls_reg(this); - flds.Add_int_pkey_autonum("id"); - this.fld_page_id = flds.Add_int("page_id"); - this.fld_wkr_id = flds.Add_int("wkr_id"); - this.fld_data_id = flds.Add_int("data_id"); - } - public String Tbl_name() {return tbl_name;} - public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));} - public Db_conn Conn() {return conn;} - public void Rls() { - stmt_insert = Db_stmt_.Rls(stmt_insert); - } - public void Stmt_bgn() { - stmt_insert = conn.Stmt_insert(tbl_name, flds); - } - public void Stmt_end() { - this.Rls(); - if (!conn.Meta_idx_exists(tbl_name, "pkey")) - conn.Meta_idx_create(Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "pkey", fld_page_id, fld_wkr_id, fld_data_id)); - } - public void Insert_by_rdr(Db_rdr rdr) { - Db_stmt_.Insert_by_rdr(flds, rdr, stmt_insert); - } - public void Insert_exec(int page_id, int wkr_id, int data_id) { - stmt_insert.Clear() - .Val_int(fld_page_id , page_id) - .Val_int(fld_wkr_id , wkr_id) - .Val_int(fld_data_id , data_id) - .Exec_insert(); - } - public List_adp Select_by_page(int page_id) { - List_adp rv = List_adp_.New(); - Db_rdr rdr = conn.Stmt_select(tbl_name, flds, fld_page_id) - .Crt_int(fld_page_id, page_id) - .Exec_select__rls_auto(); - try { - while (rdr.Move_next()) { - Hxtn_page_itm itm = new Hxtn_page_itm(rdr.Read_int(fld_page_id), rdr.Read_int(fld_wkr_id), rdr.Read_int(fld_data_id)); - rv.Add(itm); - } - } finally { - rdr.Rls(); - } - return rv; - } -} +package gplx.xowa.htmls.hxtns.pages; + +import gplx.List_adp; +import gplx.List_adp_; +import gplx.Rls_able; +import gplx.dbs.Db_conn; +import gplx.dbs.Db_rdr; +import gplx.dbs.Db_rdr_; +import gplx.dbs.Db_stmt; +import gplx.dbs.Db_stmt_; +import gplx.dbs.Dbmeta_fld_list; +import gplx.dbs.Dbmeta_idx_itm; +import gplx.dbs.Dbmeta_tbl_itm; + +public class Hxtn_page_tbl implements Rls_able { + private static final String tbl_name = "hxtn_page"; private final Dbmeta_fld_list flds = new Dbmeta_fld_list(); + private final String fld_page_id, fld_wkr_id, fld_data_id; + private final Db_conn conn; private Db_stmt stmt_insert; + public Hxtn_page_tbl(Db_conn conn) { + this.conn = conn; + conn.Rls_reg(this); + flds.Add_int_pkey_autonum("id"); + this.fld_page_id = flds.Add_int("page_id"); + this.fld_wkr_id = flds.Add_int("wkr_id"); + this.fld_data_id = flds.Add_int("data_id"); + } + public String Tbl_name() {return tbl_name;} + public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));} + public Db_conn Conn() {return conn;} + public void Rls() { + stmt_insert = Db_stmt_.Rls(stmt_insert); + } + public void Stmt_bgn() { + stmt_insert = conn.Stmt_insert(tbl_name, flds); + } + public void Stmt_end() { + this.Rls(); + if (!conn.Meta_idx_exists(tbl_name, "pkey")) + conn.Meta_idx_create(Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "pkey", fld_page_id, fld_wkr_id, fld_data_id)); + } + public void Insert_by_rdr(Db_rdr rdr) { + Db_stmt_.Insert_by_rdr(flds, rdr, stmt_insert); + } + public void Insert_exec(int page_id, int wkr_id, int data_id) { + stmt_insert.Clear() + .Val_int(fld_page_id , page_id) + .Val_int(fld_wkr_id , wkr_id) + .Val_int(fld_data_id , data_id) + .Exec_insert(); + } + public boolean Exists(int page_id, int wkr_id, int data_id) { + Db_rdr rdr = Db_rdr_.Empty; + try { + rdr = conn.Stmt_select(tbl_name, flds, fld_page_id, fld_wkr_id, fld_data_id) + .Crt_int(fld_page_id, page_id) + .Crt_int(fld_wkr_id, wkr_id) + .Crt_int(fld_data_id, data_id) + .Exec_select__rls_auto(); + return rdr.Move_next(); + } finally { + rdr.Rls(); + } + } + public List_adp Select_by_page(int page_id) { + List_adp rv = List_adp_.New(); + Db_rdr rdr = conn.Stmt_select(tbl_name, flds, fld_page_id) + .Crt_int(fld_page_id, page_id) + .Exec_select__rls_auto(); + try { + while (rdr.Move_next()) { + Hxtn_page_itm itm = new Hxtn_page_itm(rdr.Read_int(fld_page_id), rdr.Read_int(fld_wkr_id), rdr.Read_int(fld_data_id)); + rv.Add(itm); + } + } finally { + rdr.Rls(); + } + return rv; + } +} diff --git a/400_xowa/src/gplx/xowa/wikis/data/Xow_db_file_.java b/400_xowa/src/gplx/xowa/wikis/data/Xow_db_file_.java index b2d8994ff..78dab763e 100644 --- a/400_xowa/src/gplx/xowa/wikis/data/Xow_db_file_.java +++ b/400_xowa/src/gplx/xowa/wikis/data/Xow_db_file_.java @@ -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,49 +13,52 @@ 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.wikis.data; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*; -public class Xow_db_file_ { - public static final int Uid__core = 0; - public static final byte - Tid__core = 1, Tid__text = 2, Tid__cat = 3, Tid__search_core = 4, Tid__wbase = 5 // SERIALIZED:v1 - , Tid__cat_core = 6, Tid__cat_link = 7 // SERIALIZED:v2 - , Tid__wiki_solo = 8, Tid__text_solo = 9 - , Tid__html_solo = 10, Tid__html_data = 11 - , Tid__file_solo = 12, Tid__file_core = 13, Tid__file_data = 14, Tid__file_user = 15 - , Tid__search_link = 16, Tid__random = 17, Tid__css = 18 - , Tid__html_user = 19 - ; - private static final String - Key__core = "core", Key__text = "text", Key__cat = "xtn.category", Key__search_core = "xtn.search.core", Key__wbase = "core.wbase" - , Key__cat_core = "xtn.category.core", Key__cat_link = "xtn.category.link" - , Key__text_solo = "text.solo", Key__wiki_solo = "wiki.solo" - , Key__html_solo = "html.solo", Key__html_data = "html" - , Key__file_solo = "file.solo", Key__file_core = "file.core", Key__file_data = "file.data", Key__file_user = "file.user" - , Key__search_link = "xtn.search.link", Key__random = "xtn.random", Key__css = "xtn.css" - , Key__html_user = "html.user" - ; - public static String To_key(byte v) { - switch (v) { - case Tid__core: return Key__core; - case Tid__text: return Key__text; - case Tid__cat: return Key__cat; - case Tid__search_core: return Key__search_core; - case Tid__wbase: return Key__wbase; - case Tid__cat_core: return Key__cat_core; - case Tid__cat_link: return Key__cat_link; - case Tid__wiki_solo: return Key__wiki_solo; - case Tid__text_solo: return Key__text_solo; - case Tid__html_solo: return Key__html_solo; - case Tid__html_data: return Key__html_data; - case Tid__file_solo: return Key__file_solo; - case Tid__file_core: return Key__file_core; - case Tid__file_data: return Key__file_data; - case Tid__file_user: return Key__file_user; - case Tid__search_link: return Key__search_link; - case Tid__random: return Key__random; - case Tid__css: return Key__css; - case Tid__html_user: return Key__html_user; - default: throw Err_.new_unhandled(v); - } - } -} +package gplx.xowa.wikis.data; + +import gplx.Err_; + +public class Xow_db_file_ { + public static final int Uid__core = 0; + public static final byte + Tid__core = 1, Tid__text = 2, Tid__cat = 3, Tid__search_core = 4, Tid__wbase = 5 // SERIALIZED:v1 + , Tid__cat_core = 6, Tid__cat_link = 7 // SERIALIZED:v2 + , Tid__wiki_solo = 8, Tid__text_solo = 9 + , Tid__html_solo = 10, Tid__html_data = 11 + , Tid__file_solo = 12, Tid__file_core = 13, Tid__file_data = 14, Tid__file_user = 15 + , Tid__search_link = 16, Tid__random = 17, Tid__css = 18 + , Tid__html_user = 19 + ; + private static final String + Key__core = "core", Key__text = "text", Key__cat = "xtn.category", Key__search_core = "xtn.search.core", Key__wbase = "core.wbase" + , Key__cat_core = "xtn.category.core", Key__cat_link = "xtn.category.link" + , Key__text_solo = "text.solo", Key__wiki_solo = "wiki.solo" + , Key__html_solo = "html.solo", Key__html_data = "html" + , Key__file_solo = "file.solo", Key__file_core = "file.core", Key__file_data = "file.data", Key__file_user = "file.user" + , Key__search_link = "xtn.search.link", Key__random = "xtn.random", Key__css = "xtn.css" + , Key__html_user = "html.user" + ; + public static String To_key(byte v) { + switch (v) { + case Tid__core: return Key__core; + case Tid__text: return Key__text; + case Tid__cat: return Key__cat; + case Tid__search_core: return Key__search_core; + case Tid__wbase: return Key__wbase; + case Tid__cat_core: return Key__cat_core; + case Tid__cat_link: return Key__cat_link; + case Tid__wiki_solo: return Key__wiki_solo; + case Tid__text_solo: return Key__text_solo; + case Tid__html_solo: return Key__html_solo; + case Tid__html_data: return Key__html_data; + case Tid__file_solo: return Key__file_solo; + case Tid__file_core: return Key__file_core; + case Tid__file_data: return Key__file_data; + case Tid__file_user: return Key__file_user; + case Tid__search_link: return Key__search_link; + case Tid__random: return Key__random; + case Tid__css: return Key__css; + case Tid__html_user: return Key__html_user; + default: throw Err_.new_unhandled(v); + } + } +} diff --git a/400_xowa/src/gplx/xowa/wikis/data/Xow_db_mgr.java b/400_xowa/src/gplx/xowa/wikis/data/Xow_db_mgr.java index 447d548bc..aa5607907 100644 --- a/400_xowa/src/gplx/xowa/wikis/data/Xow_db_mgr.java +++ b/400_xowa/src/gplx/xowa/wikis/data/Xow_db_mgr.java @@ -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,218 +13,240 @@ 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.wikis.data; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*; -import gplx.dbs.*; import gplx.dbs.cfgs.*; import gplx.core.lists.hashs.*; -import gplx.xowa.wikis.dbs.*; import gplx.xowa.wikis.data.tbls.*; -import gplx.xowa.wikis.domains.*; import gplx.xowa.bldrs.infos.*; import gplx.xowa.wikis.metas.*; -public class Xow_db_mgr { - private final Io_url wiki_root_dir; - private final String domain_str; // needed for generating new files; EX: en.wikipedia.org-text.ns.001.xowa - private final Ordered_hash hash_by_id = Ordered_hash_.New(); private final Xow_db_file_hash hash_by_tids = new Xow_db_file_hash(); - private int db_id_next = 0; - public Xow_db_mgr(Io_url wiki_root_dir, String domain_str) { - this.wiki_root_dir = wiki_root_dir; - this.domain_str = domain_str; - } - public Xowd_core_db_props Props() {return props;} private Xowd_core_db_props props = Xowd_core_db_props.Test; - public Db_cfg_tbl Tbl__cfg() {return db__core.Tbl__cfg();} - public Xowd_page_tbl Tbl__page() {return db__core.Tbl__page();} - public Xow_db_file Db__core() {return db__core;} private Xow_db_file db__core; - public Xow_db_file Db__text() {return db__text;} private Xow_db_file db__text; - public Xow_db_file Db__html() {return db__html;} private Xow_db_file db__html; - public Xow_db_file Db__cat_core() {return db__cat_core;} private Xow_db_file db__cat_core; - public Xow_db_file Db__wbase() {return db__wbase;} private Xow_db_file db__wbase; public void Db__wbase_(Xow_db_file v) {db__wbase = v;} - public void Init_by_load(Io_url core_url) { - // clear lists - hash_by_id.Clear(); - hash_by_tids.Clear(); - - // create core_conn / core_db - Db_conn core_conn = Db_conn_bldr.Instance.Get(core_url); - props = Xowd_core_db_props.Cfg_load(core_conn); // load props to get layout_text - Dbs__set_by_tid(Xow_db_file.Load(props, Xow_db_file_.Uid__core, Xow_db_file__core_.Core_db_tid(props.Layout_text()), core_url, Xob_info_file.Ns_ids_empty, Xob_info_file.Part_id_1st, Guid_adp_.Empty)); - - // load dbs from "xowa_db" tbl - Xow_db_file[] ary = db__core.Tbl__db().Select_all(props, core_url.OwnerDir()); - int len = ary.length; - for (int i = 0; i < len; i++) { - Xow_db_file db = ary[i]; - Dbs__set_by_tid(db); - Dbs__add(db); - } - } - public void Init_by_make(Xowd_core_db_props props, Xob_info_session info_session) { - this.props = props; - - // save data - Xow_db_file core_db = Xow_db_file__core_.Make_core_db(props, info_session, wiki_root_dir, domain_str); - Dbs__set_by_tid(core_db); - Dbs__add_and_save(core_db); - props.Cfg_save(db__core.Tbl__cfg()); // NOTE: must save cfg now, especially zip_tid; latter will be reloaded after import is done; - } - public void Rls() { - int len = hash_by_id.Len(); - for (int i = 0; i < len; i++) { - Xow_db_file db_file = (Xow_db_file)hash_by_id.Get_at(i); - db_file.Rls(); - } - } - - public int Dbs__len() {return hash_by_id.Len();} - public Xow_db_file Dbs__get_at(int i) {return (Xow_db_file)hash_by_id.Get_at(i);} - public Xow_db_file Dbs__get_by_id_or_fail(int id) {return (Xow_db_file)hash_by_id.Get_by_or_fail(id);} - public Xow_db_file Dbs__get_by_id_or_null(int id) {return (Xow_db_file)hash_by_id.Get_by(id);} - public Xow_db_file Dbs__get_by_tid_or_core(byte... tids_ary) {Xow_db_file rv = Dbs__get_by_tid_or_null(tids_ary); return rv == null ? db__core : rv;} - public Xow_db_file Dbs__get_by_tid_or_null(byte... tids_ary) { - int tids_len = tids_ary.length; - for (int i = 0; i < tids_len; ++i) { - byte tid = tids_ary[i]; - Ordered_hash tid_dbs = hash_by_tids.Get_by_tid_or_null(tid); if (tid_dbs == null) continue; - int tid_dbs_len = tid_dbs.Len(); - if (tid_dbs_len != 1) { // NOTE: occurs when multiple search imports fail; DATE:2016-04-04 - Xoa_app_.Usr_dlg().Warn_many("", "", "expecting only 1 db for tid; tid=~{0} len=~{1} db_api=~{2}", tid, tid_dbs.Len(), db__core.Conn().Conn_info().Db_api()); - } - return (Xow_db_file)tid_dbs.Get_at(tid_dbs_len - 1); // get last idx; - } - return null; - } - public Xow_db_file Dbs__assert_by_tid(byte tid) { - Xow_db_file rv = Dbs__get_by_tid_or_null(tid); - if (rv == null) { - rv = Dbs__make_by_tid(tid); - } - return rv; - } - public Ordered_hash Dbs__get_hash_by_tid(int tid) {return hash_by_tids.Get_by_tid_or_null((byte)tid);} - public Xow_db_file Dbs__make_by_tid(byte tid) { - int tid_idx = Get_tid_idx(hash_by_tids, tid); - return Dbs__make_by_tid(tid, Xob_info_file.Ns_ids_empty, tid_idx, Get_tid_name(tid_idx, tid)); - } - public Xow_db_file Dbs__make_by_tid(byte tid, String ns_ids, int part_id, String file_name_suffix) { - return Dbs__make_by_id(db_id_next++, tid, ns_ids, part_id, file_name_suffix); - } - public Xow_db_file Dbs__make_by_id(int id, byte tid, String ns_ids, int part_id, String file_name_suffix) { - Io_url url = wiki_root_dir.GenSubFil(domain_str + file_name_suffix); - Xow_db_file rv = Xow_db_file.Make(db__core.Info_session(), props, id, tid, url, ns_ids, part_id, db__core.Url().NameAndExt(), Db_conn_bldr.Instance.New(url)); - Dbs__add_and_save(rv); - Dbs__set_by_tid(rv); - return rv; - } - public Xow_db_file Dbs__remake_by_tid(byte tid) { - Dbs__delete_by_tid(tid); - return Dbs__make_by_tid(tid); - } - public void Dbs__delete_by_tid(byte... tids) { - int len = hash_by_id.Len(); - for (int i = 0; i < len; ++i) { - Xow_db_file db = (Xow_db_file)hash_by_id.Get_at(i); - if (!Byte_.Match_any(db.Tid(), tids)) continue; - db.Rls(); - Io_mgr.Instance.DeleteFil_args(db.Url()).MissingFails_off().Exec(); - db.Cmd_mode_(Db_cmd_mode.Tid_delete); - } - db__core.Tbl__db().Commit_all(this); - - // call init again to regen list of dbs - this.Init_by_load(db__core.Url()); - } - public Xow_db_file Dbs__get_for_create(byte tid, int ns_id) { - Xow_db_file[] ary = Dbs__get_ary(tid, ns_id); - if (ary.length == 0) throw Err_.new_wo_type("no dbs exist; wiki=~{0} type=~{1}", domain_str, tid); - return ary[ary.length - 1]; - } - public Xow_db_file[] Dbs__get_ary(byte tid, int ns_id) { - List_adp rv = List_adp_.New(); - - // loop all dbs - int len = this.Dbs__len(); - for (int i = 0; i < len; i++) { - boolean add = false; - Xow_db_file db = this.Dbs__get_at(i); - switch (tid) { - // cat_link requested - case Xow_db_file_.Tid__cat_link: - switch (db.Tid()) { - case Xow_db_file_.Tid__core: - add = props.Layout_text().Tid_is_all_or_few(); // cat_link will be in "core" if "all" or "few" (-text, -html, -file) - break; - case Xow_db_file_.Tid__cat_link: - add = true; - break; - } - break; - // text requested - case Xow_db_file_.Tid__text: - switch (db.Tid()) { - case Xow_db_file_.Tid__core: - add = props.Layout_text().Tid_is_all(); // text will be in "core" if "all" - break; - case Xow_db_file_.Tid__text_solo: // EX: "en.wikipedia.org-text.xowa" - add = true; // text will be in db if solo; - break; - case Xow_db_file_.Tid__text: // EX: "en.wikipedia.org-text-ns.000.xowa" - int[] db_ns_ids = Int_ary_.Parse(db.Ns_ids(), "|"); // need to handle both "0" and "0|4" - for (int db_ns_id : db_ns_ids) { - if (db_ns_id == ns_id) { - add = true; // text will be in db if ns matches; EX: en.wikipedia.org-text-ns.014.xowa - break; - } - } - break; - } - break; - } - if (add) - rv.Add(db); - } - - return (Xow_db_file[])rv.To_ary_and_clear(Xow_db_file.class); - } - public void Create_page(Xowd_page_tbl core_tbl, Xowd_text_tbl text_tbl, int page_id, int ns_id, byte[] ttl_wo_ns, boolean redirect, DateAdp modified_on, byte[] text_zip_data, int text_raw_len, int random_int, int text_db_id, int html_db_id) { - core_tbl.Insert_cmd_by_batch(page_id, ns_id, ttl_wo_ns, redirect, modified_on, text_raw_len, random_int, text_db_id, html_db_id, -1); - text_tbl.Insert_cmd_by_batch(page_id, text_zip_data); - } - private void Dbs__set_by_tid(Xow_db_file db) { - switch (db.Tid()) { - case Xow_db_file_.Tid__wiki_solo: - case Xow_db_file_.Tid__text_solo: - case Xow_db_file_.Tid__core : {db__core = db; if (props.Layout_text().Tid_is_all_or_few()) db__cat_core = db__text = db; break;} - case Xow_db_file_.Tid__text : {db__text = db; break;} - case Xow_db_file_.Tid__html_data : {db__html = db; break;} - case Xow_db_file_.Tid__wbase : {if (db__wbase == null) db__wbase = db; break;} - case Xow_db_file_.Tid__cat_core : - case Xow_db_file_.Tid__cat : {if (db__cat_core == null) db__cat_core = db; break;} - } - } - private void Dbs__add(Xow_db_file db_file) { - int db_id = db_file.Id(); - hash_by_id.Add(db_id, db_file); - hash_by_tids.Add_or_new(db_file); - if (db_id >= db_id_next) // always set db_id_next to largest value in given set of dbs; EX: dbs=[0,1,10]; db_id_next should be 11 - db_id_next = db_id + 1; - } - private void Dbs__add_and_save(Xow_db_file db_file) { - Dbs__add(db_file); - - db__core.Tbl__db().Commit_all(this); - db_file.Info_file().Save(db_file.Tbl__cfg()); - db_file.Info_session().Save(db_file.Tbl__cfg()); - } - private int Get_tid_idx(Xow_db_file_hash hash, byte tid) {return hash.Count_of_tid(tid) + Int_.Base1;} - private static String Get_tid_name(int tid_idx, byte tid) { - String tid_name = Xow_db_file_.To_key(tid); - String tid_idx_str = ""; - switch (tid) { - case Xow_db_file_.Tid__cat_core : break; - case Xow_db_file_.Tid__cat_link : tid_idx_str = "-db." + Int_.To_str_pad_bgn_zero(tid_idx, 3); break; - default : tid_idx_str = tid_idx == 1 ? "" : "-db." + Int_.To_str_pad_bgn_zero(tid_idx, 3); break; - } - return String_.Format("-{0}{1}.xowa", tid_name, tid_idx_str); // EX: en.wikipedia.org-text-001.sqlite3 - } - - // helper method for wikis to (a) init db_mgr; (b) load wiki.props; should probably be moved to more generic "wiki.Init_by_db()" - public static void Init_by_load(Xow_wiki wiki, Io_url core_url) { - wiki.Data__core_mgr().Init_by_load(core_url); - wiki.Props().Init_by_load(wiki.App(), wiki.Data__core_mgr().Tbl__cfg()); // load Main_page - } -} +package gplx.xowa.wikis.data; + +import gplx.Byte_; +import gplx.DateAdp; +import gplx.Err_; +import gplx.Guid_adp_; +import gplx.Int_; +import gplx.Int_ary_; +import gplx.Io_mgr; +import gplx.Io_url; +import gplx.List_adp; +import gplx.List_adp_; +import gplx.Ordered_hash; +import gplx.Ordered_hash_; +import gplx.String_; +import gplx.dbs.Db_cmd_mode; +import gplx.dbs.Db_conn; +import gplx.dbs.Db_conn_bldr; +import gplx.dbs.cfgs.Db_cfg_tbl; +import gplx.xowa.Xoa_app_; +import gplx.xowa.Xow_wiki; +import gplx.xowa.bldrs.infos.Xob_info_file; +import gplx.xowa.bldrs.infos.Xob_info_session; +import gplx.xowa.wikis.data.tbls.Xowd_page_tbl; +import gplx.xowa.wikis.data.tbls.Xowd_text_tbl; + +public class Xow_db_mgr { + private final Io_url wiki_root_dir; + private final String domain_str; // needed for generating new files; EX: en.wikipedia.org-text.ns.001.xowa + private final Ordered_hash hash_by_id = Ordered_hash_.New(); private final Xow_db_file_hash hash_by_tids = new Xow_db_file_hash(); + private int db_id_next = 0; + public Xow_db_mgr(Io_url wiki_root_dir, String domain_str) { + this.wiki_root_dir = wiki_root_dir; + this.domain_str = domain_str; + } + public Xowd_core_db_props Props() {return props;} private Xowd_core_db_props props = Xowd_core_db_props.Test; + public Db_cfg_tbl Tbl__cfg() {return db__core.Tbl__cfg();} + public Xowd_page_tbl Tbl__page() {return db__core.Tbl__page();} + public Xow_db_file Db__core() {return db__core;} private Xow_db_file db__core; + public Xow_db_file Db__text() {return db__text;} private Xow_db_file db__text; + public Xow_db_file Db__html() {return db__html;} private Xow_db_file db__html; + public Xow_db_file Db__cat_core() {return db__cat_core;} private Xow_db_file db__cat_core; + public Xow_db_file Db__wbase() {return db__wbase;} private Xow_db_file db__wbase; public void Db__wbase_(Xow_db_file v) {db__wbase = v;} + public void Init_by_load(Io_url core_url) { + // clear lists + hash_by_id.Clear(); + hash_by_tids.Clear(); + + // create core_conn / core_db + Db_conn core_conn = Db_conn_bldr.Instance.Get(core_url); + props = Xowd_core_db_props.Cfg_load(core_conn); // load props to get layout_text + Dbs__set_by_tid(Xow_db_file.Load(props, Xow_db_file_.Uid__core, Xow_db_file__core_.Core_db_tid(props.Layout_text()), core_url, Xob_info_file.Ns_ids_empty, Xob_info_file.Part_id_1st, Guid_adp_.Empty)); + + // load dbs from "xowa_db" tbl + Xow_db_file[] ary = db__core.Tbl__db().Select_all(props, core_url.OwnerDir()); + int len = ary.length; + for (int i = 0; i < len; i++) { + Xow_db_file db = ary[i]; + Dbs__set_by_tid(db); + Dbs__add(db); + } + } + public void Init_by_make(Xowd_core_db_props props, Xob_info_session info_session) { + this.props = props; + + // save data + Xow_db_file core_db = Xow_db_file__core_.Make_core_db(props, info_session, wiki_root_dir, domain_str); + Dbs__set_by_tid(core_db); + Dbs__add_and_save(core_db); + props.Cfg_save(db__core.Tbl__cfg()); // NOTE: must save cfg now, especially zip_tid; latter will be reloaded after import is done; + } + public void Rls() { + int len = hash_by_id.Len(); + for (int i = 0; i < len; i++) { + Xow_db_file db_file = (Xow_db_file)hash_by_id.Get_at(i); + db_file.Rls(); + } + } + + public int Dbs__len() {return hash_by_id.Len();} + public Xow_db_file Dbs__get_at(int i) {return (Xow_db_file)hash_by_id.Get_at(i);} + public Xow_db_file Dbs__get_by_id_or_fail(int id) {return (Xow_db_file)hash_by_id.Get_by_or_fail(id);} + public Xow_db_file Dbs__get_by_id_or_null(int id) {return (Xow_db_file)hash_by_id.Get_by(id);} + public Xow_db_file Dbs__get_by_tid_or_core(byte... tids_ary) {Xow_db_file rv = Dbs__get_by_tid_or_null(tids_ary); return rv == null ? db__core : rv;} + public Xow_db_file Dbs__get_by_tid_or_null(byte... tids_ary) { + int tids_len = tids_ary.length; + for (int i = 0; i < tids_len; ++i) { + byte tid = tids_ary[i]; + Ordered_hash tid_dbs = hash_by_tids.Get_by_tid_or_null(tid); if (tid_dbs == null) continue; + int tid_dbs_len = tid_dbs.Len(); + if (tid_dbs_len != 1) { // NOTE: occurs when multiple search imports fail; DATE:2016-04-04 + Xoa_app_.Usr_dlg().Warn_many("", "", "expecting only 1 db for tid; tid=~{0} len=~{1} db_api=~{2}", tid, tid_dbs.Len(), db__core.Conn().Conn_info().Db_api()); + } + return (Xow_db_file)tid_dbs.Get_at(tid_dbs_len - 1); // get last idx; + } + return null; + } + public Xow_db_file Dbs__assert_by_tid(byte tid) { + Xow_db_file rv = Dbs__get_by_tid_or_null(tid); + if (rv == null) { + rv = Dbs__make_by_tid(tid); + } + return rv; + } + public Ordered_hash Dbs__get_hash_by_tid(int tid) {return hash_by_tids.Get_by_tid_or_null((byte)tid);} + public Xow_db_file Dbs__make_by_tid(byte tid) { + int tid_idx = Get_tid_idx(hash_by_tids, tid); + return Dbs__make_by_tid(tid, Xob_info_file.Ns_ids_empty, tid_idx, Get_tid_name(tid_idx, tid)); + } + public Xow_db_file Dbs__make_by_tid(byte tid, String ns_ids, int part_id, String file_name_suffix) { + return Dbs__make_by_id(db_id_next++, tid, ns_ids, part_id, file_name_suffix); + } + public Xow_db_file Dbs__make_by_id(int id, byte tid, String ns_ids, int part_id, String file_name_suffix) { + Io_url url = wiki_root_dir.GenSubFil(domain_str + file_name_suffix); + Xow_db_file rv = Xow_db_file.Make(db__core.Info_session(), props, id, tid, url, ns_ids, part_id, db__core.Url().NameAndExt(), Db_conn_bldr.Instance.New(url)); + Dbs__add_and_save(rv); + Dbs__set_by_tid(rv); + return rv; + } + public Xow_db_file Dbs__remake_by_tid(byte tid) { + Dbs__delete_by_tid(tid); + return Dbs__make_by_tid(tid); + } + public void Dbs__delete_by_tid(byte... tids) { + int len = hash_by_id.Len(); + for (int i = 0; i < len; ++i) { + Xow_db_file db = (Xow_db_file)hash_by_id.Get_at(i); + if (!Byte_.Match_any(db.Tid(), tids)) continue; + db.Rls(); + Io_mgr.Instance.DeleteFil_args(db.Url()).MissingFails_off().Exec(); + db.Cmd_mode_(Db_cmd_mode.Tid_delete); + } + db__core.Tbl__db().Commit_all(this); + + // call init again to regen list of dbs + this.Init_by_load(db__core.Url()); + } + public Xow_db_file Dbs__get_for_create(byte tid, int ns_id) { + Xow_db_file[] ary = Dbs__get_ary(tid, ns_id); + if (ary.length == 0) throw Err_.new_wo_type("no dbs exist; wiki=~{0} type=~{1}", domain_str, tid); + return ary[ary.length - 1]; + } + public Xow_db_file[] Dbs__get_ary(byte tid, int ns_id) { + List_adp rv = List_adp_.New(); + + // loop all dbs + int len = this.Dbs__len(); + for (int i = 0; i < len; i++) { + boolean add = false; + Xow_db_file db = this.Dbs__get_at(i); + switch (tid) { + // cat_link requested + case Xow_db_file_.Tid__cat_link: + switch (db.Tid()) { + case Xow_db_file_.Tid__core: + add = props.Layout_text().Tid_is_all_or_few(); // cat_link will be in "core" if "all" or "few" (-text, -html, -file) + break; + case Xow_db_file_.Tid__cat_link: + add = true; + break; + } + break; + // text requested + case Xow_db_file_.Tid__text: + switch (db.Tid()) { + case Xow_db_file_.Tid__core: + add = props.Layout_text().Tid_is_all(); // text will be in "core" if "all" + break; + case Xow_db_file_.Tid__text_solo: // EX: "en.wikipedia.org-text.xowa" + add = true; // text will be in db if solo; + break; + case Xow_db_file_.Tid__text: // EX: "en.wikipedia.org-text-ns.000.xowa" + int[] db_ns_ids = Int_ary_.Parse(db.Ns_ids(), "|"); // need to handle both "0" and "0|4" + for (int db_ns_id : db_ns_ids) { + if (db_ns_id == ns_id) { + add = true; // text will be in db if ns matches; EX: en.wikipedia.org-text-ns.014.xowa + break; + } + } + break; + } + break; + } + if (add) + rv.Add(db); + } + + return (Xow_db_file[])rv.To_ary_and_clear(Xow_db_file.class); + } + public void Create_page(Xowd_page_tbl core_tbl, Xowd_text_tbl text_tbl, int page_id, int ns_id, byte[] ttl_wo_ns, boolean redirect, DateAdp modified_on, byte[] text_zip_data, int text_raw_len, int random_int, int text_db_id, int html_db_id) { + core_tbl.Insert_cmd_by_batch(page_id, ns_id, ttl_wo_ns, redirect, modified_on, text_raw_len, random_int, text_db_id, html_db_id, -1); + text_tbl.Insert_cmd_by_batch(page_id, text_zip_data); + } + private void Dbs__set_by_tid(Xow_db_file db) { + switch (db.Tid()) { + case Xow_db_file_.Tid__wiki_solo: + case Xow_db_file_.Tid__text_solo: + case Xow_db_file_.Tid__core : {db__core = db; if (props.Layout_text().Tid_is_all_or_few()) db__cat_core = db__text = db; break;} + case Xow_db_file_.Tid__text : {db__text = db; break;} + case Xow_db_file_.Tid__html_data : {db__html = db; break;} + case Xow_db_file_.Tid__wbase : {if (db__wbase == null) db__wbase = db; break;} + case Xow_db_file_.Tid__cat_core : + case Xow_db_file_.Tid__cat : {if (db__cat_core == null) db__cat_core = db; break;} + } + } + private void Dbs__add(Xow_db_file db_file) { + int db_id = db_file.Id(); + hash_by_id.Add(db_id, db_file); + hash_by_tids.Add_or_new(db_file); + if (db_id >= db_id_next) // always set db_id_next to largest value in given set of dbs; EX: dbs=[0,1,10]; db_id_next should be 11 + db_id_next = db_id + 1; + } + private void Dbs__add_and_save(Xow_db_file db_file) { + Dbs__add(db_file); + + db__core.Tbl__db().Commit_all(this); + db_file.Info_file().Save(db_file.Tbl__cfg()); + db_file.Info_session().Save(db_file.Tbl__cfg()); + } + private int Get_tid_idx(Xow_db_file_hash hash, byte tid) {return hash.Count_of_tid(tid) + Int_.Base1;} + private static String Get_tid_name(int tid_idx, byte tid) { + String tid_name = Xow_db_file_.To_key(tid); + String tid_idx_str = ""; + switch (tid) { + case Xow_db_file_.Tid__cat_core : break; + case Xow_db_file_.Tid__cat_link : tid_idx_str = "-db." + Int_.To_str_pad_bgn_zero(tid_idx, 3); break; + default : tid_idx_str = tid_idx == 1 ? "" : "-db." + Int_.To_str_pad_bgn_zero(tid_idx, 3); break; + } + return String_.Format("-{0}{1}.xowa", tid_name, tid_idx_str); // EX: en.wikipedia.org-text-001.sqlite3 + } + + // helper method for wikis to (a) init db_mgr; (b) load wiki.props; should probably be moved to more generic "wiki.Init_by_db()" + public static void Init_by_load(Xow_wiki wiki, Io_url core_url) { + wiki.Data__core_mgr().Init_by_load(core_url); + wiki.Props().Init_by_load(wiki.App(), wiki.Data__core_mgr().Tbl__cfg()); // load Main_page + } +} diff --git a/400_xowa/src/gplx/xowa/wikis/dbs/Xodb_save_mgr_sql.java b/400_xowa/src/gplx/xowa/wikis/dbs/Xodb_save_mgr_sql.java index 7bb564385..89c4a4dea 100644 --- a/400_xowa/src/gplx/xowa/wikis/dbs/Xodb_save_mgr_sql.java +++ b/400_xowa/src/gplx/xowa/wikis/dbs/Xodb_save_mgr_sql.java @@ -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,66 +13,81 @@ 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.wikis.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*; -import gplx.core.ios.*; import gplx.dbs.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.dbs.qrys.*; -import gplx.xowa.wikis.*; -public class Xodb_save_mgr_sql implements Xodb_save_mgr { - private final Xodb_mgr_sql db_mgr; - public Xodb_save_mgr_sql(Xodb_mgr_sql db_mgr) {this.db_mgr = db_mgr;} - public boolean Create_enabled() {return create_enabled;} public void Create_enabled_(boolean v) {create_enabled = v;} private boolean create_enabled; - public boolean Update_modified_on_enabled() {return update_modified_on_enabled;} public void Update_modified_on_enabled_(boolean v) {update_modified_on_enabled = v;} private boolean update_modified_on_enabled; - public int Page_id_next() {return page_id_next;} public void Page_id_next_(int v) {page_id_next = v;} private int page_id_next; - public int Data_create(Xowe_wiki wiki, Xoa_ttl ttl, byte[] text_raw) { - int ns_id = ttl.Ns().Id(); - Xow_db_file db_file = db_mgr.Core_data_mgr().Db__core(); - int ns_count = db_file.Tbl__ns().Select_ns_count(ns_id) + 1; - int page_id = db_file.Tbl__cfg().Select_int_or(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, -1); - if (page_id == -1) { // HACK: changed for tests; was dbs.qrys.Db_qry_sql.rdr_("SELECT (Max(page_id) + 1) AS max_page_id FROM page;") - Db_rdr rdr = db_mgr.Core_data_mgr().Tbl__page().Conn().Stmt_select(db_file.Tbl__page().Tbl_name(), String_.Ary(db_file.Tbl__page().Fld_page_id()), Dbmeta_fld_itm.Str_ary_empty).Exec_select__rls_auto(); - try { - int max_page_id = -1; - while (rdr.Move_next()) { - int cur_page_id = rdr.Read_int("page_id"); - if (cur_page_id > max_page_id) max_page_id = cur_page_id; - } - page_id = max_page_id + 1; - db_mgr.Core_data_mgr().Tbl__cfg().Upsert_int(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, page_id + 1); - } finally {rdr.Rls();} - } - Xow_db_mgr fsys_mgr = db_mgr.Core_data_mgr(); - Xow_db_file page_text_db = fsys_mgr.Db__text(); - if (page_text_db == null) page_text_db = fsys_mgr.Db__core(); // HACK: needed for create new wiki DATE:2016-10-29 - Xowd_text_tbl page_text_tbl = page_text_db.Tbl__text(); - byte[] text_zip = page_text_tbl.Zip(text_raw); - boolean redirect = wiki.Redirect_mgr().Is_redirect(text_raw, text_raw.length); - Xowd_page_tbl page_core_tbl = db_mgr.Core_data_mgr().Tbl__page(); - page_core_tbl.Insert_bgn(); - page_text_tbl.Insert_bgn(); - try { - db_mgr.Core_data_mgr().Create_page(page_core_tbl, page_text_tbl, page_id, ns_id, ttl.Page_db(), redirect, Datetime_now.Get(), text_zip, text_raw.length, ns_count, page_text_db.Id(), -1); - db_file.Tbl__ns().Update_ns_count(ns_id, ns_count); - db_file.Tbl__cfg().Update_int(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, page_id + 1); - } finally { - page_core_tbl.Insert_end(); - page_text_tbl.Insert_end(); - } - return page_id; - } - public void Data_update(Xoae_page page, byte[] text_raw) { - boolean redirect = page.Wikie().Redirect_mgr().Is_redirect(text_raw, text_raw.length); - DateAdp modified = update_modified_on_enabled ? Datetime_now.Get() : page.Db().Page().Modified_on(); - int page_id = page.Db().Page().Id(); - db_mgr.Core_data_mgr().Tbl__page().Update__redirect__modified(page_id, redirect, modified); - Xowd_page_itm db_page = new Xowd_page_itm(); - db_mgr.Load_mgr().Load_by_id(db_page, page_id); - Xowd_text_tbl text_tbl = db_mgr.Core_data_mgr().Dbs__get_by_id_or_fail(db_page.Text_db_id()).Tbl__text(); - text_tbl.Update(page_id, text_raw); -// int html_db_id = db_page.Html_db_id(); -// if (html_db_id != -1) -// db_mgr.Core_data_mgr().Tbl__page().Update__html_db_id(page_id, -1); // zap html_db_id so that next load will repopulate it - } - public void Data_rename(Xoae_page page, int trg_ns, byte[] trg_ttl) { - db_mgr.Core_data_mgr().Tbl__page().Update__ns__ttl(page.Db().Page().Id(), trg_ns, trg_ttl); - } - public void Clear() {} -} +package gplx.xowa.wikis.dbs; + +import gplx.DateAdp; +import gplx.Datetime_now; +import gplx.String_; +import gplx.dbs.Db_rdr; +import gplx.dbs.Dbmeta_fld_itm; +import gplx.xowa.Xoa_ttl; +import gplx.xowa.Xoae_page; +import gplx.xowa.Xowe_wiki; +import gplx.xowa.wikis.data.Xow_db_file; +import gplx.xowa.wikis.data.Xow_db_mgr; +import gplx.xowa.wikis.data.Xowd_cfg_key_; +import gplx.xowa.wikis.data.tbls.Xowd_page_itm; +import gplx.xowa.wikis.data.tbls.Xowd_page_tbl; +import gplx.xowa.wikis.data.tbls.Xowd_text_tbl; + +public class Xodb_save_mgr_sql implements Xodb_save_mgr { + private final Xodb_mgr_sql db_mgr; + public Xodb_save_mgr_sql(Xodb_mgr_sql db_mgr) {this.db_mgr = db_mgr;} + public boolean Create_enabled() {return create_enabled;} public void Create_enabled_(boolean v) {create_enabled = v;} private boolean create_enabled; + public boolean Update_modified_on_enabled() {return update_modified_on_enabled;} public void Update_modified_on_enabled_(boolean v) {update_modified_on_enabled = v;} private boolean update_modified_on_enabled; + public int Page_id_next() {return page_id_next;} public void Page_id_next_(int v) {page_id_next = v;} private int page_id_next; + public int Data_create(Xowe_wiki wiki, Xoa_ttl ttl, byte[] text_raw) { + int ns_id = ttl.Ns().Id(); + Xow_db_file db_file = db_mgr.Core_data_mgr().Db__core(); + int ns_count = db_file.Tbl__ns().Select_ns_count(ns_id) + 1; + int page_id = db_file.Tbl__cfg().Select_int_or(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, -1); + if (page_id == -1) { // HACK: changed for tests; was dbs.qrys.Db_qry_sql.rdr_("SELECT (Max(page_id) + 1) AS max_page_id FROM page;") + Db_rdr rdr = db_mgr.Core_data_mgr().Tbl__page().Conn().Stmt_select(db_file.Tbl__page().Tbl_name(), String_.Ary(db_file.Tbl__page().Fld_page_id()), Dbmeta_fld_itm.Str_ary_empty).Exec_select__rls_auto(); + try { + int max_page_id = -1; + while (rdr.Move_next()) { + int cur_page_id = rdr.Read_int("page_id"); + if (cur_page_id > max_page_id) max_page_id = cur_page_id; + } + page_id = max_page_id + 1; + db_mgr.Core_data_mgr().Tbl__cfg().Upsert_int(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, page_id + 1); + } finally {rdr.Rls();} + } + Xow_db_mgr fsys_mgr = db_mgr.Core_data_mgr(); + Xow_db_file page_text_db = fsys_mgr.Db__text(); + if (page_text_db == null) page_text_db = fsys_mgr.Db__core(); // HACK: needed for create new wiki DATE:2016-10-29 + Xowd_text_tbl page_text_tbl = page_text_db.Tbl__text(); + byte[] text_zip = page_text_tbl.Zip(text_raw); + boolean redirect = wiki.Redirect_mgr().Is_redirect(text_raw, text_raw.length); + Xowd_page_tbl page_core_tbl = db_mgr.Core_data_mgr().Tbl__page(); + page_core_tbl.Insert_bgn(); + page_text_tbl.Insert_bgn(); + try { + db_mgr.Core_data_mgr().Create_page(page_core_tbl, page_text_tbl, page_id, ns_id, ttl.Page_db(), redirect, Datetime_now.Get(), text_zip, text_raw.length, ns_count, page_text_db.Id(), -1); + db_file.Tbl__ns().Update_ns_count(ns_id, ns_count); + db_file.Tbl__cfg().Update_int(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, page_id + 1); + } finally { + page_core_tbl.Insert_end(); + page_text_tbl.Insert_end(); + } + return page_id; + } + public void Data_update(Xoae_page page, byte[] text_raw) { + boolean redirect = page.Wikie().Redirect_mgr().Is_redirect(text_raw, text_raw.length); + DateAdp modified = update_modified_on_enabled ? Datetime_now.Get() : page.Db().Page().Modified_on(); + int page_id = page.Db().Page().Id(); + db_mgr.Core_data_mgr().Tbl__page().Update__redirect__modified(page_id, redirect, modified); + Xowd_page_itm db_page = new Xowd_page_itm(); + db_mgr.Load_mgr().Load_by_id(db_page, page_id); + Xowd_text_tbl text_tbl = db_mgr.Core_data_mgr().Dbs__get_by_id_or_fail(db_page.Text_db_id()).Tbl__text(); + text_tbl.Update(page_id, text_raw); + + // TOMBSTONE: do not set html_db_id to -1; editing wtxt will now save html; ISSUE#:699; DATE:2020-08-06 + // if (db_page.Html_db_id() != -1) + // db_mgr.Core_data_mgr().Tbl__page().Update__html_db_id(page_id, -1); // zap html_db_id so that next load will repopulate it + } + public void Data_rename(Xoae_page page, int trg_ns, byte[] trg_ttl) { + db_mgr.Core_data_mgr().Tbl__page().Update__ns__ttl(page.Db().Page().Id(), trg_ns, trg_ttl); + } + public void Clear() {} +} diff --git a/400_xowa/src/gplx/xowa/wikis/pages/Xowe_page_mgr.java b/400_xowa/src/gplx/xowa/wikis/pages/Xowe_page_mgr.java index e4e6babd3..9577e84e2 100644 --- a/400_xowa/src/gplx/xowa/wikis/pages/Xowe_page_mgr.java +++ b/400_xowa/src/gplx/xowa/wikis/pages/Xowe_page_mgr.java @@ -1,145 +1,146 @@ -/* -XOWA: the XOWA Offline Wiki Application -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. - -You may use XOWA according to either of these licenses as is most appropriate -for your project on a case-by-case basis. - -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.wikis.pages; - -import gplx.Bry_; -import gplx.Bry_bfr; -import gplx.Bry_bfr_; -import gplx.Err_; -import gplx.Gfo_usr_dlg_; -import gplx.core.net.qargs.Gfo_qarg_itm; -import gplx.core.net.qargs.Gfo_qarg_mgr; -import gplx.xowa.Xoa_app; -import gplx.xowa.Xoa_app_; -import gplx.xowa.Xoa_ttl; -import gplx.xowa.Xoa_url; -import gplx.xowa.Xoa_url_; -import gplx.xowa.Xoae_page; -import gplx.xowa.Xowe_wiki; -import gplx.xowa.Xowe_wiki_; -import gplx.xowa.addons.wikis.pages.syncs.core.Xosync_read_mgr; -import gplx.xowa.guis.views.Xog_tab_itm; -import gplx.xowa.wikis.data.tbls.Xowd_page_itm; - -public class Xowe_page_mgr { - private final Xowe_wiki wiki; - private final Bry_bfr tmp_bfr = Bry_bfr_.New(); - private final Gfo_qarg_mgr tmp_qarg_mgr = new Gfo_qarg_mgr(); - public Xowe_page_mgr(Xowe_wiki wiki) {this.wiki = wiki;} - public Xosync_read_mgr Sync_mgr() {return read_mgr;} private final Xosync_read_mgr read_mgr = new Xosync_read_mgr(); - public void Init_by_wiki(Xowe_wiki wiki) { - read_mgr.Init_by_wiki(wiki); - } - - public Xoae_page Load_page(Xoa_url url, Xoa_ttl ttl, Xog_tab_itm tab) { // NOTE: called by GUI and HTTP_SERVER; not called by MASS_PARSE - Xoa_app_.Usr_dlg().Log_many("", "", "page.load: url=~{0}", url.To_str()); - Wait_for_popups(wiki.App()); - Xowe_wiki_.Rls_mem_if_needed(wiki); - - // handle curid query_arg; EX:en.wikipedia.org/wiki/?curid=303 DATE:2017-02-15 - Gfo_qarg_itm[] qarg_ary = url.Qargs_ary(); - // if qargs exist... - if (qarg_ary.length > 0) { - try { - tmp_qarg_mgr.Init(qarg_ary); - byte[] curid_bry = tmp_qarg_mgr.Read_bry_or(Xoa_url_.Qarg__curid, null); - // if "curid" qarg exists.... - if (curid_bry != null) { - int curid = Bry_.To_int_or(curid_bry, -1); - Xowd_page_itm tmp_page = wiki.Data__core_mgr().Db__core().Tbl__page().Select_by_id_or_null(curid); - // if curid exists in page tbl... - if (tmp_page != null) { - ttl = wiki.Ttl_parse(tmp_page.Ns_id(), tmp_page.Ttl_page_db()); - // handle "home/wiki/?curid=123"; XO automatically changes to "home/wiki/Main_Page?curid=123"; change back to "home/wiki/?curid=123" - if (url.Page_is_main()) { - url.Page_bry_(Bry_.Empty); - } - } - } - } catch (Exception exc) { - Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to handle cur_id; url=~{0} err=~{1}", url.Raw(), Err_.Message_gplx_log(exc)); - } - } - - // load page meta; wait_for_popups - Xoae_page page = wiki.Data_mgr().Load_page_and_parse(url, ttl, wiki.Lang(), tab, false); - ttl = page.Ttl(); // note that Load_page_and_parse can redirect ttl; EX: Special:Random -> A; DATE:2017-01-05 - Wait_for_popups(wiki.App()); - - // auto-update - Xoa_ttl redirect_ttl = read_mgr.Auto_update(wiki, page, ttl); - if (redirect_ttl != null) { - // page-sync occurred; update ttl to handle any redirection; DATE:2017-05-07 - ttl = redirect_ttl; - - // reload metadata, needed to pick up Html_db_id; DATE:2017-03-13 - page = wiki.Data_mgr().Load_page_and_parse(url, ttl, wiki.Lang(), tab, false); - } - - // load from html_db - boolean from_html_db = page.Db().Page().Html_db_id() != -1; - boolean read_from_html_db_preferred = wiki.Html__hdump_mgr().Load_mgr().Read_preferred(); - boolean isCategoryPage = ttl.Ns().Id_is_ctg(); - if (from_html_db) { - if (read_from_html_db_preferred) { - wiki.Html__hdump_mgr().Load_mgr().Load_by_xowe(page, !isCategoryPage); // NOTE: if loading for html_db, do not build page_box; will be built below; ISSUE#:722; DATE:2020-05-17 - int html_len = Bry_.Len(page.Db().Html().Html_bry()); - from_html_db = html_len > 0; // NOTE: archive.org has some wtxt_dbs which included page|html_db_id without actual html_dbs; DATE:2016-06-22 - Gfo_usr_dlg_.Instance.Log_many("", "", "page_load: loaded html; page=~{0} html_len=~{1}", ttl.Full_db(), html_len); - } - else - from_html_db = false; - } - - // load from wtxt_db; occurs if (a) no html_db_id; (b) option says to use wtxt db; (c) html_db_id exists, but no html_db; - if (!from_html_db) { - wiki.Parser_mgr().Parse(page, false); - - // load from html_db if no wtxt found and option just marked as not read_preferred - if ( Bry_.Len_eq_0(page.Db().Text().Text_bry()) // no wtxt found - && !ttl.Ns().Id_is_special() // skip special - && !read_from_html_db_preferred // read preferred not marked - ) { - wiki.Html__hdump_mgr().Load_mgr().Load_by_xowe(page, true); - from_html_db = Bry_.Len_gt_0(page.Db().Html().Html_bry()); - } - else { - Gfo_usr_dlg_.Instance.Log_many("", "", "page_load: loaded wikitext; page=~{0} wikitext_len=~{1}", ttl.Full_db(), page.Db().Text().Text_bry().length); - } - } - page.Html_data().Hdump_exists_(from_html_db); - - // if [[Category]], generate catlinks (subc; page; file) - if (isCategoryPage) { - wiki.Ctg__catpage_mgr().Write_catpage(tmp_bfr, page); - if (from_html_db) { - wiki.Ctg__pagebox_wtr().Write_pagebox(tmp_bfr, page); - page.Db().Html().Html_bry_(Bry_.Add(page.Db().Html().Html_bry(), tmp_bfr.To_bry_and_clear())); - } - else { - page.Html_data().Catpage_data_(tmp_bfr.To_bry_and_clear()); - } - } - - return page; - } - private static void Wait_for_popups(Xoa_app app) {// HACK: wait for popups to finish, else thread errors due to popups and loader mutating cached items - if (app.Mode().Tid_is_http()) return; - int wait_count = 0; - while (gplx.xowa.htmls.modules.popups.Xow_popup_mgr.Running() && ++wait_count < 100) - gplx.core.threads.Thread_adp_.Sleep(10); - } -} +/* +XOWA: the XOWA Offline Wiki Application +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. + +You may use XOWA according to either of these licenses as is most appropriate +for your project on a case-by-case basis. + +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.wikis.pages; + +import gplx.Bry_; +import gplx.Bry_bfr; +import gplx.Bry_bfr_; +import gplx.Err_; +import gplx.Gfo_usr_dlg_; +import gplx.core.net.qargs.Gfo_qarg_itm; +import gplx.core.net.qargs.Gfo_qarg_mgr; +import gplx.xowa.Xoa_app; +import gplx.xowa.Xoa_app_; +import gplx.xowa.Xoa_ttl; +import gplx.xowa.Xoa_url; +import gplx.xowa.Xoa_url_; +import gplx.xowa.Xoae_page; +import gplx.xowa.Xowe_wiki; +import gplx.xowa.Xowe_wiki_; +import gplx.xowa.addons.wikis.pages.syncs.core.Xosync_read_mgr; +import gplx.xowa.guis.views.Xog_tab_itm; +import gplx.xowa.wikis.data.tbls.Xowd_page_itm; +import gplx.xowa.wikis.pages.dbs.Xopg_db_page; + +public class Xowe_page_mgr { + private final Xowe_wiki wiki; + private final Bry_bfr tmp_bfr = Bry_bfr_.New(); + private final Gfo_qarg_mgr tmp_qarg_mgr = new Gfo_qarg_mgr(); + public Xowe_page_mgr(Xowe_wiki wiki) {this.wiki = wiki;} + public Xosync_read_mgr Sync_mgr() {return read_mgr;} private final Xosync_read_mgr read_mgr = new Xosync_read_mgr(); + public void Init_by_wiki(Xowe_wiki wiki) { + read_mgr.Init_by_wiki(wiki); + } + + public Xoae_page Load_page(Xoa_url url, Xoa_ttl ttl, Xog_tab_itm tab) { // NOTE: called by GUI and HTTP_SERVER; not called by MASS_PARSE + Xoa_app_.Usr_dlg().Log_many("", "", "page.load: url=~{0}", url.To_str()); + Wait_for_popups(wiki.App()); + Xowe_wiki_.Rls_mem_if_needed(wiki); + + // handle curid query_arg; EX:en.wikipedia.org/wiki/?curid=303 DATE:2017-02-15 + Gfo_qarg_itm[] qarg_ary = url.Qargs_ary(); + // if qargs exist... + if (qarg_ary.length > 0) { + try { + tmp_qarg_mgr.Init(qarg_ary); + byte[] curid_bry = tmp_qarg_mgr.Read_bry_or(Xoa_url_.Qarg__curid, null); + // if "curid" qarg exists.... + if (curid_bry != null) { + int curid = Bry_.To_int_or(curid_bry, -1); + Xowd_page_itm tmp_page = wiki.Data__core_mgr().Db__core().Tbl__page().Select_by_id_or_null(curid); + // if curid exists in page tbl... + if (tmp_page != null) { + ttl = wiki.Ttl_parse(tmp_page.Ns_id(), tmp_page.Ttl_page_db()); + // handle "home/wiki/?curid=123"; XO automatically changes to "home/wiki/Main_Page?curid=123"; change back to "home/wiki/?curid=123" + if (url.Page_is_main()) { + url.Page_bry_(Bry_.Empty); + } + } + } + } catch (Exception exc) { + Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to handle cur_id; url=~{0} err=~{1}", url.Raw(), Err_.Message_gplx_log(exc)); + } + } + + // load page meta; wait_for_popups + Xoae_page page = wiki.Data_mgr().Load_page_and_parse(url, ttl, wiki.Lang(), tab, false); + ttl = page.Ttl(); // note that Load_page_and_parse can redirect ttl; EX: Special:Random -> A; DATE:2017-01-05 + Wait_for_popups(wiki.App()); + + // auto-update + Xoa_ttl redirect_ttl = read_mgr.Auto_update(wiki, page, ttl); + if (redirect_ttl != null) { + // page-sync occurred; update ttl to handle any redirection; DATE:2017-05-07 + ttl = redirect_ttl; + + // reload metadata, needed to pick up Html_db_id; DATE:2017-03-13 + page = wiki.Data_mgr().Load_page_and_parse(url, ttl, wiki.Lang(), tab, false); + } + + // load from html_db + boolean from_html_db = page.Db().Page().Html_db_id() != Xopg_db_page.HTML_DB_ID_NULL; + boolean read_from_html_db_preferred = wiki.Html__hdump_mgr().Load_mgr().Read_preferred(); + boolean isCategoryPage = ttl.Ns().Id_is_ctg(); + if (from_html_db) { + if (read_from_html_db_preferred) { + wiki.Html__hdump_mgr().Load_mgr().Load_by_xowe(page, !isCategoryPage); // NOTE: if loading for html_db, do not build page_box; will be built below; ISSUE#:722; DATE:2020-05-17 + int html_len = Bry_.Len(page.Db().Html().Html_bry()); + from_html_db = html_len > 0; // NOTE: archive.org has some wtxt_dbs which included page|html_db_id without actual html_dbs; DATE:2016-06-22 + Gfo_usr_dlg_.Instance.Log_many("", "", "page_load: loaded html; page=~{0} html_len=~{1}", ttl.Full_db(), html_len); + } + else + from_html_db = false; + } + + // load from wtxt_db; occurs if (a) no html_db_id; (b) option says to use wtxt db; (c) html_db_id exists, but no html_db; + if (!from_html_db) { + wiki.Parser_mgr().Parse(page, false); + + // load from html_db if no wtxt found and option just marked as not read_preferred + if ( Bry_.Len_eq_0(page.Db().Text().Text_bry()) // no wtxt found + && !ttl.Ns().Id_is_special() // skip special + && !read_from_html_db_preferred // read preferred not marked + ) { + wiki.Html__hdump_mgr().Load_mgr().Load_by_xowe(page, true); + from_html_db = Bry_.Len_gt_0(page.Db().Html().Html_bry()); + } + else { + Gfo_usr_dlg_.Instance.Log_many("", "", "page_load: loaded wikitext; page=~{0} wikitext_len=~{1}", ttl.Full_db(), page.Db().Text().Text_bry().length); + } + } + page.Html_data().Hdump_exists_(from_html_db); + + // if [[Category]], generate catlinks (subc; page; file) + if (isCategoryPage) { + wiki.Ctg__catpage_mgr().Write_catpage(tmp_bfr, page); + if (from_html_db) { + wiki.Ctg__pagebox_wtr().Write_pagebox(tmp_bfr, page); + page.Db().Html().Html_bry_(Bry_.Add(page.Db().Html().Html_bry(), tmp_bfr.To_bry_and_clear())); + } + else { + page.Html_data().Catpage_data_(tmp_bfr.To_bry_and_clear()); + } + } + + return page; + } + private static void Wait_for_popups(Xoa_app app) {// HACK: wait for popups to finish, else thread errors due to popups and loader mutating cached items + if (app.Mode().Tid_is_http()) return; + int wait_count = 0; + while (gplx.xowa.htmls.modules.popups.Xow_popup_mgr.Running() && ++wait_count < 100) + gplx.core.threads.Thread_adp_.Sleep(10); + } +} diff --git a/400_xowa/src/gplx/xowa/wikis/pages/dbs/Xopg_db_page.java b/400_xowa/src/gplx/xowa/wikis/pages/dbs/Xopg_db_page.java index 5cfd9e3a4..1ab2be1c3 100644 --- a/400_xowa/src/gplx/xowa/wikis/pages/dbs/Xopg_db_page.java +++ b/400_xowa/src/gplx/xowa/wikis/pages/dbs/Xopg_db_page.java @@ -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,54 +13,65 @@ 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.wikis.pages.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*; import gplx.xowa.wikis.pages.*; -import gplx.xowa.wikis.nss.*; -public class Xopg_db_page { - public Xopg_db_page() {this.Clear();} - // from page table - public boolean Exists() {return exists;} private boolean exists; - public boolean Exists_n() {return !exists;} - public int Id() {return id;} private int id; - public int Ns_id() {return ns_id;} private int ns_id; - public byte[] Ttl_bry() {return ttl_bry;} private byte[] ttl_bry; - public DateAdp Modified_on() {return modified_on;} private DateAdp modified_on; - public int Text_len() {return text_len;} private int text_len; - public int Text_db_id() {return text_db_id;} private int text_db_id; - public int Html_db_id() {return html_db_id;} private int html_db_id; - public int Redirect_to_id() {return redirect_to_id;} private int redirect_to_id; - public int Score() {return score;} private int score; - - public void Exists_y_() {this.Exists_(Bool_.Y);} - public void Exists_n_() {this.Exists_(Bool_.N);} - public void Exists_(boolean v) {this.exists = v;} - public Xopg_db_page Id_(int v) {this.id = v; return this;} - public Xopg_db_page Score_(int v) {this.score = v; return this;} - public Xopg_db_page Modified_on_(DateAdp v) {this.modified_on = v; return this;} - public Xopg_db_page Html_db_id_(int v) {this.html_db_id = v; return this;} - - // wiki-related - public Xow_ns Ns() {return ns;} private Xow_ns ns; - public Xoa_ttl Ttl() {return ttl;} private Xoa_ttl ttl; - - // init methods - public Xopg_db_page Init_by_db(int id, int ns_id, byte[] ttl_bry, DateAdp modified_on, int text_len, int text_db_id, int html_db_id, int redirect_to_id, int score) { - this.id = id; this.ns_id = ns_id; this.ttl_bry = ttl_bry; this.modified_on = modified_on; - this.text_len = text_len; this.text_db_id = text_db_id; this.html_db_id = html_db_id; this.redirect_to_id = redirect_to_id; this.score = score; - this.ns = null; this.ttl = null; - return this; - } - public Xopg_db_page Init_by_wiki(Xow_wiki wiki) { - this.ns = wiki.Ns_mgr().Ids_get_or_null(ns_id); - this.ttl = wiki.Ttl_parse(ns_id, ttl_bry); - return this; - } - public void Init_by_mp(int id, int score) { - this.id = id; - this.score = score; - } - public void Clear() { - this.exists = true; - this.modified_on = DateAdp_.MinValue; // NOTE: must set to MinValue else some tests will fail - this.html_db_id = -1; // NOTE: must set to -1 b/c code checks for -1 to indicate no html; DATE:2016-07-14 - } -} +package gplx.xowa.wikis.pages.dbs; + +import gplx.Bool_; +import gplx.DateAdp; +import gplx.DateAdp_; +import gplx.xowa.Xoa_ttl; +import gplx.xowa.Xow_wiki; +import gplx.xowa.wikis.nss.Xow_ns; + +public class Xopg_db_page { + public Xopg_db_page() {this.Clear();} + // from page table + public boolean Exists() {return exists;} private boolean exists; + public boolean Exists_n() {return !exists;} + public int Id() {return id;} private int id; + public int Ns_id() {return ns_id;} private int ns_id; + public byte[] Ttl_bry() {return ttl_bry;} private byte[] ttl_bry; + public DateAdp Modified_on() {return modified_on;} private DateAdp modified_on; + public int Text_len() {return text_len;} private int text_len; + public int Text_db_id() {return text_db_id;} private int text_db_id; + public int Html_db_id() {return html_db_id;} private int html_db_id; + public int Redirect_to_id() {return redirect_to_id;} private int redirect_to_id; + public int Score() {return score;} private int score; + + public void Exists_y_() {this.Exists_(Bool_.Y);} + public void Exists_n_() {this.Exists_(Bool_.N);} + public void Exists_(boolean v) {this.exists = v;} + public Xopg_db_page Id_(int v) {this.id = v; return this;} + public Xopg_db_page Score_(int v) {this.score = v; return this;} + public Xopg_db_page Modified_on_(DateAdp v) {this.modified_on = v; return this;} + public Xopg_db_page Html_db_id_(int v) {this.html_db_id = v; return this;} + + // wiki-related + public Xow_ns Ns() {return ns;} private Xow_ns ns; + public Xoa_ttl Ttl() {return ttl;} private Xoa_ttl ttl; + + // init methods + public Xopg_db_page Init_by_db(int id, int ns_id, byte[] ttl_bry, DateAdp modified_on, int text_len, int text_db_id, int html_db_id, int redirect_to_id, int score) { + this.id = id; this.ns_id = ns_id; this.ttl_bry = ttl_bry; this.modified_on = modified_on; + this.text_len = text_len; this.text_db_id = text_db_id; this.html_db_id = html_db_id; this.redirect_to_id = redirect_to_id; this.score = score; + this.ns = null; this.ttl = null; + return this; + } + public Xopg_db_page Init_by_wiki(Xow_wiki wiki) { + this.ns = wiki.Ns_mgr().Ids_get_or_null(ns_id); + this.ttl = wiki.Ttl_parse(ns_id, ttl_bry); + return this; + } + public void Init_by_mp(int id, int score) { + this.id = id; + this.score = score; + } + public void Clear() { + this.exists = true; + this.modified_on = DateAdp_.MinValue; // NOTE: must set to MinValue else some tests will fail + + // NOTE: must set to -1 b/c code checks for -1 to indicate no html; DATE:2016-07-14; + // NOTE: this should probably be removed, but would need to change all the checks; DATE:2020-08-06 + this.html_db_id = Xopg_db_page.HTML_DB_ID_NULL; + } + public static final int HTML_DB_ID_NULL = -1; +}