diff --git a/400_xowa/src/gplx/xowa/Xoae_app.java b/400_xowa/src/gplx/xowa/Xoae_app.java index 89d328ec2..d174320e0 100644 --- a/400_xowa/src/gplx/xowa/Xoae_app.java +++ b/400_xowa/src/gplx/xowa/Xoae_app.java @@ -169,6 +169,7 @@ public class Xoae_app implements Xoa_app, Gfo_invk { if (Launch_done()) return; xwiki_mgr__sitelink_mgr.Init_by_app(); stage = Xoa_stage_.Tid_launch; + gplx.xowa.addons.apps.cfgs.upgrades.Xocfg_upgrade_mgr.Convert(this); Xouc_setup_mgr.Setup_run_check(this); log_bfr.Add("app.upgrade.done"); user.Wiki().Init_assert(); // NOTE: must assert wiki and load langs first, else will be asserted during Portal_mgr().Init(), which will cause IndexOutOfBounds; DATE:2014-10-04 gplx.xowa.addons.users.wikis.regys.Xou_regy_addon.Init(this); diff --git a/400_xowa/src/gplx/xowa/addons/apps/cfgs/Xocfg_mgr.java b/400_xowa/src/gplx/xowa/addons/apps/cfgs/Xocfg_mgr.java index 1e7baf4cc..36af3286b 100644 --- a/400_xowa/src/gplx/xowa/addons/apps/cfgs/Xocfg_mgr.java +++ b/400_xowa/src/gplx/xowa/addons/apps/cfgs/Xocfg_mgr.java @@ -18,10 +18,10 @@ along with this program. If not, see . package gplx.xowa.addons.apps.cfgs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.dbs.*; import gplx.xowa.addons.apps.cfgs.mgrs.caches.*; import gplx.xowa.addons.apps.cfgs.mgrs.dflts.*; import gplx.xowa.addons.apps.cfgs.mgrs.types.*; import gplx.xowa.addons.apps.cfgs.mgrs.execs.*; public class Xocfg_mgr implements Gfo_invk { - private final Xocfg_cache_mgr cache_mgr = new Xocfg_cache_mgr(); public Xocfg_mgr() { this.dflt_mgr = new Xocfg_dflt_mgr(cache_mgr); } + public Xocfg_cache_mgr Cache_mgr() {return cache_mgr;} private final Xocfg_cache_mgr cache_mgr = new Xocfg_cache_mgr(); public Xocfg_type_mgr Type_mgr() {return type_mgr;} private final Xocfg_type_mgr type_mgr = new Xocfg_type_mgr(); public Xocfg_dflt_mgr Dflt_mgr() {return dflt_mgr;} private final Xocfg_dflt_mgr dflt_mgr; public Xocfg_exec_mgr Exec_mgr() {return exec_mgr;} private final Xocfg_exec_mgr exec_mgr = new Xocfg_exec_mgr(); diff --git a/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_grp.java b/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_grp.java index 34f902207..bd012fc27 100644 --- a/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_grp.java +++ b/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_grp.java @@ -16,7 +16,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package gplx.xowa.addons.apps.cfgs.mgrs.caches; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; import gplx.xowa.addons.apps.cfgs.mgrs.*; -class Xocfg_cache_grp { +public class Xocfg_cache_grp { private final Hash_adp vals = Hash_adp_.New(); private final Ordered_hash subs = Ordered_hash_.New(); public Xocfg_cache_grp(String key, String dflt) { diff --git a/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_itm.java b/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_itm.java index 422f46139..7f2176fe6 100644 --- a/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_itm.java +++ b/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_itm.java @@ -16,7 +16,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package gplx.xowa.addons.apps.cfgs.mgrs.caches; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; import gplx.xowa.addons.apps.cfgs.mgrs.*; -class Xocfg_cache_itm { +public class Xocfg_cache_itm { public Xocfg_cache_itm(String ctx, String key, String val) { this.ctx = ctx; this.key = key; diff --git a/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_mgr.java b/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_mgr.java index beb0dfd3b..6f6d056b4 100644 --- a/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_mgr.java +++ b/400_xowa/src/gplx/xowa/addons/apps/cfgs/mgrs/caches/Xocfg_cache_mgr.java @@ -48,7 +48,12 @@ public class Xocfg_cache_mgr { public void Set(boolean save, String ctx, String key, String val) { Xocfg_cache_grp grp = Grps__get_or_load(key); grp.Set(ctx, val); - if (save) db_usr.Set_str(ctx, key, val); + if (save) { + if (String_.Eq(grp.Dflt(), val)) + db_usr.Del(ctx, key); + else + db_usr.Set_str(ctx, key, val); + } grp.Pub(ctx, val); } public void Del(String ctx, String key) { @@ -69,7 +74,7 @@ public class Xocfg_cache_mgr { Xocfg_cache_grp grp = Grps__get_or_load(key); grp.Dflt_(val); } - private Xocfg_cache_grp Grps__get_or_load(String key) { + public Xocfg_cache_grp Grps__get_or_load(String key) { Xocfg_cache_grp grp = (Xocfg_cache_grp)grps.Get_by(key); if (grp == null) { grp = Load_grp(key, ""); diff --git a/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/edits/services/Xocfg_edit_svc.java b/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/edits/services/Xocfg_edit_svc.java index dd9151e24..9dcd06588 100644 --- a/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/edits/services/Xocfg_edit_svc.java +++ b/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/edits/services/Xocfg_edit_svc.java @@ -19,7 +19,7 @@ package gplx.xowa.addons.apps.cfgs.specials.edits.services; import gplx.*; impor import gplx.langs.jsons.*; import gplx.core.gfobjs.*; import gplx.xowa.guis.cbks.*; import gplx.xowa.addons.apps.cfgs.dbs.*; import gplx.xowa.addons.apps.cfgs.specials.edits.objs.*; -import gplx.xowa.addons.apps.cfgs.specials.edits.pages.*; +import gplx.xowa.addons.apps.cfgs.specials.edits.pages.*; import gplx.xowa.addons.apps.cfgs.mgrs.caches.*; public class Xocfg_edit_svc { private final Xoa_app app; private Xocfg_edit_loader edit_loader; @@ -36,7 +36,12 @@ public class Xocfg_edit_svc { val = gplx.xowa.addons.apps.cfgs.enums.Xoitm_gui_binding.To_db_str(val); } app.Cfg().Set_str(ctx, key, val); - app.Gui__cbk_mgr().Send_json(cbk_trg, "xo.cfg_edit.upsert__recv", Gfobj_nde.New().Add_str("key", key)); + + Xocfg_cache_grp grp = app.Cfg().Cache_mgr().Grps__get_or_load(key); + if (String_.Eq(grp.Dflt(), val)) + app.Gui__cbk_mgr().Send_json(cbk_trg, "xo.cfg_edit.revert__recv", Gfobj_nde.New().Add_str("key", key).Add_str("val", val)); + else + app.Gui__cbk_mgr().Send_json(cbk_trg, "xo.cfg_edit.upsert__recv", Gfobj_nde.New().Add_str("key", key)); } public void Revert(Json_nde args) { String ctx = args.Get_as_str("ctx"); diff --git a/400_xowa/src/gplx/xowa/addons/apps/cfgs/upgrades/Xocfg_upgrade_mgr.java b/400_xowa/src/gplx/xowa/addons/apps/cfgs/upgrades/Xocfg_upgrade_mgr.java new file mode 100644 index 000000000..b01cb8f62 --- /dev/null +++ b/400_xowa/src/gplx/xowa/addons/apps/cfgs/upgrades/Xocfg_upgrade_mgr.java @@ -0,0 +1,141 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xowa.addons.apps.cfgs.upgrades; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; +import gplx.dbs.*; +public class Xocfg_upgrade_mgr { + public static void Convert(Xoae_app app) { + // get cfg_fil; if empty, exit + Io_url cfg_fil = app.Fsys_mgr().Root_dir().GenSubFil_nest("user", "anonymous", "app", "data", "cfg", "xowa_user_cfg.gfs"); + byte[] cfg_raw = Io_mgr.Instance.LoadFilBryOrNull(cfg_fil); + if (cfg_raw == null) return; + + // log and rename file + Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:old cfg found; converting"); + Io_mgr.Instance.MoveFil(cfg_fil, cfg_fil.GenNewExt(".bak")); + + // parse, remap, and update + Keyval[] kvs = Parse(cfg_raw); + + // get mappings + Ordered_hash mappings = Ordered_hash_.New(); + Db_conn conn = app.Cfg().Cache_mgr().Db_app().Conn(); + Db_rdr rdr = conn.Stmt_sql("SELECT * FROM cfg_upgrade").Exec_select__rls_auto(); + try { + while (rdr.Move_next()) { + String cfg_old = rdr.Read_str("cfg_old"); + String cfg_new = rdr.Read_str("cfg_new"); + mappings.Add(cfg_old, Keyval_.new_(cfg_old, cfg_new)); + } + } + finally {rdr.Rls();} + + // remap + for (Keyval kv : kvs) { + Keyval mapping = (Keyval)mappings.Get_by(kv.Key()); + if (mapping == null) { + Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:could not find mapping; key=~{0} val=~{1}", kv.Key(), kv.Val()); + kv.Key_(""); + continue; + } + kv.Key_(mapping.Val()); + } + + // apply + for (Keyval kv : kvs) { + if (String_.Eq(kv.Key(), "")) continue; + app.Cfg().Set_str_app(kv.Key(), kv.Val_to_str_or_empty()); + } + } + public static Keyval[] Parse(byte[] src) { + int pos = 0; int len = src.length; + byte[] key_bgn_bry = Bry_.new_a7("app.cfgs.get('"); + byte[] key_end_bry = Bry_.new_a7("', 'app').val = '"); + byte[] val_end_bry = Bry_.new_a7("';\n"); + byte[] apos_2_bry = Bry_.new_a7("''"); + + // main parse + Ordered_hash hash = Ordered_hash_.New(); + while (true) { + // find "app.cfgs.get('" + int key_bgn = Bry_find_.Find_fwd(src, key_bgn_bry, pos, len); + if (key_bgn == Bry_find_.Not_found) break; // no more cfgs; break; + + // update key_bgn; find key_end + key_bgn += key_bgn_bry.length; + int key_end = Bry_find_.Find_fwd(src, key_end_bry, key_bgn, len); + if (key_end == Bry_find_.Not_found) { + Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:could not find key_end; src=~{0}", Bry_.Mid(src, key_bgn, len)); + break; + } + + // look for val_end + int val_bgn = key_end + key_end_bry.length; + int val_end = Bry_find_.Find_fwd(src, val_end_bry, val_bgn, len); + if (val_end == Bry_find_.Not_found) { + Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:could not find val_bgn; src=~{0}", Bry_.Mid(src, val_bgn, len)); + break; + } + + byte[] key = Bry_.Replace(Bry_.Mid(src, key_bgn, key_end), apos_2_bry, Byte_ascii.Apos_bry); + byte[] val = Bry_.Replace(Bry_.Mid(src, val_bgn, val_end), apos_2_bry, Byte_ascii.Apos_bry); + String key_str = String_.new_u8(key); + hash.Add_if_dupe_use_nth(key_str, Keyval_.new_(key_str, String_.new_u8(val))); + pos = val_end + val_end_bry.length; + } + + // consolidate io.cmd + List_adp deleted = List_adp_.New(); + len = hash.Len(); + for (int i = 0; i < len; i++) { + Keyval args_kv = (Keyval)hash.Get_at(i); + String args_kv_key = args_kv.Key(); + String args_kv_val = args_kv.Val_to_str_or_empty(); + if (String_.Has_at_end(args_kv_key, ".args")) { + Keyval cmd_kv = (Keyval)hash.Get_by(String_.Replace(args_kv_key, ".args", ".cmd")); + if (cmd_kv == null) { + Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:could not find cmd; key=~{0} val=~{1}", args_kv_key, args_kv.Val()); + continue; + } + String cmd_kv_val = cmd_kv.Val_to_str_or_empty(); + if (!String_.Has_at_end(cmd_kv_val, "|")) cmd_kv_val += "|"; + cmd_kv.Val_(cmd_kv_val + args_kv_val); + deleted.Add(args_kv_key); + } + else if (String_.Has_at_bgn(args_kv_key, "app.cfg.get.gui.bnds.init('")) { + args_kv_key = String_.Replace(args_kv_key, "app.cfg.get.gui.bnds.init('", ""); + args_kv_key = String_.Replace(args_kv_key, "').src", ""); + args_kv_key = "xowa.gui.shortcuts." + args_kv_key; + args_kv.Key_(args_kv_key); + + args_kv_val = String_.Replace(args_kv_val, "box='", ""); + args_kv_val = String_.Replace(args_kv_val, "';ipt='", "|"); + args_kv_val = String_.Replace(args_kv_val, "';", ""); + args_kv.Val_(args_kv_val); + } + } + + // delete args + len = deleted.Len(); + for (int i = 0; i < len; i++) { + String deleted_key = (String)deleted.Get_at(i); + hash.Del(deleted_key); + } + + return (Keyval[])hash.To_ary_and_clear(Keyval.class); + } +} diff --git a/400_xowa/src/gplx/xowa/addons/apps/cfgs/upgrades/Xocfg_upgrade_mgr__tst.java b/400_xowa/src/gplx/xowa/addons/apps/cfgs/upgrades/Xocfg_upgrade_mgr__tst.java new file mode 100644 index 000000000..6e41d05d1 --- /dev/null +++ b/400_xowa/src/gplx/xowa/addons/apps/cfgs/upgrades/Xocfg_upgrade_mgr__tst.java @@ -0,0 +1,58 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xowa.addons.apps.cfgs.upgrades; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; +import org.junit.*; import gplx.core.tests.*; +public class Xocfg_upgrade_mgr__tst { + private final Xocfg_upgrade_mgr__fxt fxt = new Xocfg_upgrade_mgr__fxt(); + @Test public void Parse__one() { + fxt.Test__parse("app.cfgs.get('k_1', 'app').val = 'v_1';\n", Keyval_.new_("k_1", "v_1")); + } + @Test public void Parse__apos() { + fxt.Test__parse("app.cfgs.get('k_1(''k_1a'')', 'app').val = 'v_1';\n", Keyval_.new_("k_1('k_1a')", "v_1")); + } + @Test public void Parse__many() { + fxt.Test__parse + ( "app.cfgs.get('k_1', 'app').val = 'v_1';\n" + + "app.cfgs.get('k_2', 'app').val = 'v_2';\n" + , Keyval_.new_("k_1", "v_1"), Keyval_.new_("k_2", "v_2")); + } + @Test public void Parse__multi_line() { + fxt.Test__parse + ( "app.cfgs.get('k_1', 'app').val = 'v_1\n" + + "v_2\n" + + "v_3';\n" + , Keyval_.new_("k_1", "v_1\nv_2\nv_3")); + } + @Test public void Parse__io_cmd() { + fxt.Test__parse + ( "app.cfgs.get('a.cmd', 'app').val = 'cmd_1';\n" + + "app.cfgs.get('a.args', 'app').val = 'args_1';\n" + , Keyval_.new_("a.cmd", "cmd_1|args_1")); + } + @Test public void Parse__gui_binding() { + fxt.Test__parse + ( "app.cfgs.get('app.cfg.get.gui.bnds.init('xowa.app.exit-1').src', 'app').val = 'box='browser';ipt='key.none';';\n" + , Keyval_.new_("xowa.gui.shortcuts.xowa.app.exit-1", "browser|key.none")); + } +} +class Xocfg_upgrade_mgr__fxt { + public void Test__parse(String raw, Keyval... expd) { + Keyval[] actl = Xocfg_upgrade_mgr.Parse(Bry_.new_u8(raw)); + Gftest.Eq__str(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl)); + } +} \ No newline at end of file