+*
+*
+* @version $Revision: 1.1 $
+*/
+abstract class BaseHash {
+ /** The canonical name prefix of the hash. */
+ protected String name;
+
+ /** The hash (output) size in bytes. */
+ protected int hashSize;
+
+ /** The hash (inner) block size in bytes. */
+ protected int blockSize;
+
+ /** Number of bytes processed so far. */
+ protected long count;
+
+ /** Temporary input buffer. */
+ protected byte[] buffer;
+
+ // Constructor(s)
+ // -------------------------------------------------------------------------
+
+ /**
+ *
Trivial constructor for use by concrete subclasses.
+ *
+ * @param name the canonical name prefix of this instance.
+ * @param hashSize the block size of the output in bytes.
+ * @param blockSize the block size of the internal transform.
+ */
+ protected BaseHash(String name, int hashSize, int blockSize) {
+ super();
+
+ this.name = name;
+ this.hashSize = hashSize;
+ this.blockSize = blockSize;
+ this.buffer = new byte[blockSize];
+
+ resetContext();
+ }
+
+ // Class methods
+ // -------------------------------------------------------------------------
+
+ // Instance methods
+ // -------------------------------------------------------------------------
+
+ // IMessageDigest interface implementation ---------------------------------
+
+ public String name() {
+ return name;
+ }
+
+ public int hashSize() {
+ return hashSize;
+ }
+
+ public int blockSize() {
+ return blockSize;
+ }
+
+ public void update(byte b) {
+ // compute number of bytes still unhashed; ie. present in buffer
+ int i = (int)(count % blockSize);
+ count++;
+ buffer[i] = b;
+ if (i == (blockSize - 1)) {
+ transform(buffer, 0);
+ }
+ }
+
+ public void update(byte[] b, int offset, int len) {
+ int n = (int)(count % blockSize);
+ count += len;
+ int partLen = blockSize - n;
+ int i = 0;
+
+ if (len >= partLen) {
+ System.arraycopy(b, offset, buffer, n, partLen);
+ transform(buffer, 0);
+ for (i = partLen; i + blockSize - 1 < len; i+= blockSize) {
+ transform(b, offset + i);
+ }
+ n = 0;
+ }
+
+ if (i < len) {
+ System.arraycopy(b, offset + i, buffer, n, len - i);
+ }
+ }
+
+ public byte[] digest() {
+ byte[] tail = padBuffer(); // pad remaining bytes in buffer
+ update(tail, 0, tail.length); // last transform of a message
+ byte[] result = getResult(); // make a result out of context
+
+ reset(); // reset this instance for future re-use
+
+ return result;
+ }
+
+ public void reset() { // reset this instance for future re-use
+ count = 0L;
+ for (int i = 0; i < blockSize; ) {
+ buffer[i++] = 0;
+ }
+
+ resetContext();
+ }
+
+ // methods to be implemented by concrete subclasses ------------------------
+
+ public abstract Object clone();
+
+ /**
+ *
Returns the byte array to use as padding before completing a hash
+ * operation.
+ *
+ * @return the bytes to pad the remaining bytes in the buffer before
+ * completing a hash operation.
+ */
+ protected abstract byte[] padBuffer();
+
+ /**
+ *
Constructs the result from the contents of the current context.
+ *
+ * @return the output of the completed hash operation.
+ */
+ protected abstract byte[] getResult();
+
+ /** Resets the instance for future re-use. */
+ protected abstract void resetContext();
+
+ /**
+ *
The block digest transformation per se.
+ *
+ * @param in the blockSize long block, as an array of bytes to digest.
+ * @param offset the index where the data to digest is located within the
+ * input buffer.
+ */
+ protected abstract void transform(byte[] in, int offset);
+}
+
+//----------------------------------------------------------------------------
+//$Id: BaseHash.java,v 1.8 2002/11/07 17:17:45 raif Exp $
+//
+//Copyright (C) 2001, 2002, Free Software Foundation, Inc.
+//
+//This file is part of GNU Crypto.
+//
+//GNU Crypto is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2, or (at your option)
+//any later version.
+//
+//GNU Crypto 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
+//General Public License for more details.
+//
+//You should have received a copy of the GNU General Public License
+//along with this program; see the file COPYING. If not, write to the
+//
+// Free Software Foundation Inc.,
+// 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307
+// USA
+//
+//Linking this library statically or dynamically with other modules is
+//making a combined work based on this library. Thus, the terms and
+//conditions of the GNU General Public License cover the whole
+//combination.
+//
+//As a special exception, the copyright holders of this library give
+//you permission to link this library with independent modules to
+//produce an executable, regardless of the license terms of these
+//independent modules, and to copy and distribute the resulting
+//executable under terms of your choice, provided that you also meet,
+//for each linked independent module, the terms and conditions of the
+//license of that module. An independent module is a module which is
+//not derived from or based on this library. If you modify this
+//library, you may extend this exception to your version of the
+//library, but you are not obligated to do so. If you do not wish to
+//do so, delete this exception statement from your version.
+//----------------------------------------------------------------------------
+/**
+ *
A base abstract class to facilitate hash implementations.
+ *
+ * @version $Revision: 1.8 $
+ */
diff --git a/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tree_tst.java b/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tree_tst.java
new file mode 100644
index 000000000..c9dac39ed
--- /dev/null
+++ b/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tree_tst.java
@@ -0,0 +1,65 @@
+/*
+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.security; import gplx.*;
+import org.junit.*;
+public class HashAlgo_tth192_tree_tst {
+ @Test public void CalcRecursiveHalves() {
+ tst_CalcRecursiveHalves(129, 128);
+ tst_CalcRecursiveHalves(128, 127);
+ tst_CalcRecursiveHalves(100, 99);
+ tst_CalcRecursiveHalves(20, 19);
+ tst_CalcRecursiveHalves(6, 5);
+ tst_CalcRecursiveHalves(5, 4);
+ tst_CalcRecursiveHalves(4, 3);
+ tst_CalcRecursiveHalves(3, 2);
+ tst_CalcRecursiveHalves(2, 1);
+ tst_CalcRecursiveHalves(1, 0);
+ tst_CalcRecursiveHalves(0, 0);
+ }
+ @Test public void CalcWorkUnits() {
+ tst_CalcWorkUnits(101, 21); // leafs; 10 full, 1 part (+11) -> reduce 11 to 5+1 (+5) -> reduce 6 to 3 (+3) -> reduce 3 to 1+1 (+1) -> reduce 2 to 1 (+1)
+ tst_CalcWorkUnits(100, 19); // leafs; 10 full (+10) -> reduce 10 to 5 (+5) -> reduce 5 to 2+1 (+2) -> reduce 3 to 1+1 (+1) -> reduce 2 to 1 (+1)
+ tst_CalcWorkUnits(30, 5); // leafs; 3 full (+3) -> reduce 3 to 1+1 (+1) -> reduce 2 to 1 (+1)
+ tst_CalcWorkUnits(11, 3); // leafs: 1 full, 1 part (+2) -> reduce 2 to 1 (+1)
+ tst_CalcWorkUnits(10, 1);
+ tst_CalcWorkUnits(9, 1);
+ tst_CalcWorkUnits(1, 1);
+ tst_CalcWorkUnits(0, 1);
+ }
+ void tst_CalcWorkUnits(int length, int expd) {
+ HashAlgo_tth192 algo = HashAlgo_tth192.new_(); algo.BlockSize_set(10);
+ int actl = algo.CalcWorkUnits(length);
+ Tfds.Eq(expd, actl);
+ }
+ void tst_CalcRecursiveHalves(int val, int expd) {
+ int actl = CalcRecursiveHalvesMock(val);
+ Tfds.Eq(expd, actl);
+ }
+ int CalcRecursiveHalvesMock(int val) {
+ if (val <= 1) return 0;
+ int rv = 0;
+ while (true) {
+ int multiple = val / 2;
+ int remainder = val % 2;
+ rv += multiple;
+ val = multiple + remainder;
+ if (val == 1)
+ return remainder == 0 ? rv : ++rv;
+ }
+ }
+}
diff --git a/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tst.java b/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tst.java
new file mode 100644
index 000000000..f65879d89
--- /dev/null
+++ b/100_core/src_160_hash/gplx/security/HashAlgo_tth192_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.security; import gplx.*;
+import org.junit.*; import gplx.ios.*; /*IoStream*/
+public class HashAlgo_tth192_tst {
+ @Test public void Char0000() {tst_CalcBase32FromString("", "LWPNACQDBZRYXW3VHJVCJ64QBZNGHOHHHZWCLNQ");}
+ @Test public void Char0001() {tst_CalcBase32FromString("\0", "VK54ZIEEVTWNAUI5D5RDFIL37LX2IQNSTAXFKSA");}
+ @Test public void Char0002() {tst_CalcBase32FromString("ab", "XQXRSGMB3PSN2VGZYJMNJG6SOOQ3JIGQHD2I6PQ");}
+ @Test public void Char0003() {tst_CalcBase32FromString("abc", "ASD4UJSEH5M47PDYB46KBTSQTSGDKLBHYXOMUIA");}
+ @Test public void Char0004() {tst_CalcBase32FromString("abcd", "SQF2PFTVIFRR5KJSI45IDENXMB43NI7EIXYGHGI");}
+ @Test public void Char0005() {tst_CalcBase32FromString("abcde", "SKGLNP5WV7ZUMF6IUK5CYXBE3PI4C6PHWNVM2YQ");}
+ @Test public void Char0009() {tst_CalcBase32FromString("abcdefghi", "RUIKHZFO4NIY6NNUHJMAC2I26U3U65FZWCO3UFY");}
+ @Test public void Char1024() {tst_CalcBase32FromString(String_.Repeat("A", 1024), "L66Q4YVNAFWVS23X2HJIRA5ZJ7WXR3F26RSASFA");}
+ @Test public void Char1025() {tst_CalcBase32FromString(String_.Repeat("A", 1025), "PZMRYHGY6LTBEH63ZWAHDORHSYTLO4LEFUIKHWY");}
+// @Test // commented out due to time (approx 17.94 seconds)
+ public void Ax2Pow27() { // 134 MB
+ tst_CalcBase32FromString(String_.Repeat("A", (int)Math_.Pow(2, 27)), "QNIJO36QDIQREUT3HWK4MDVKD2T6OENAEKYADTQ");
+ }
+ void tst_CalcBase32FromString(String raw, String expd) {
+ IoStream stream = IoStream_.mem_txt_(Io_url_.Null, raw);
+ String actl = HashAlgo_.Tth192.CalcHash(ConsoleDlg_.Null, stream);
+ Tfds.Eq(expd, actl);
+ }
+}
+/*
+ The empty (zero-length) file:
+ urn:tree:tiger:LWPNACQDBZRYXW3VHJVCJ64QBZNGHOHHHZWCLNQ
+
+ A file with a single zero byte:
+ urn:tree:tiger:VK54ZIEEVTWNAUI5D5RDFIL37LX2IQNSTAXFKSA
+
+ A file with 1024 'A' characters:
+ urn:tree:tiger:L66Q4YVNAFWVS23X2HJIRA5ZJ7WXR3F26RSASFA
+
+ A file with 1025 'A' characters:
+ urn:tree:tiger:PZMRYHGY6LTBEH63ZWAHDORHSYTLO4LEFUIKHWY
+
+ http://open-content.net/specs/draft-jchapweske-thex-02.html
+
+ A file with 134,217,728 'A' characters (2 Pow 27)
+ urn:tree:tiger:QNIJO36QDIQREUT3HWK4MDVKD2T6OENAEKYADTQ
+ queried against DC++ 0.698
+ */
diff --git a/100_core/src_160_hash/gplx/security/HashDlgWtr_tst.java b/100_core/src_160_hash/gplx/security/HashDlgWtr_tst.java
new file mode 100644
index 000000000..6082514e4
--- /dev/null
+++ b/100_core/src_160_hash/gplx/security/HashDlgWtr_tst.java
@@ -0,0 +1,41 @@
+/*
+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.security; import gplx.*;
+import org.junit.*; import gplx.ios.*; /*IoStream*/
+public class HashDlgWtr_tst {
+ @Before public void setup() {
+ HashAlgo_tth192 algo = HashAlgo_tth192.new_();
+ algo.BlockSize_set(10);
+ calc = algo;
+ }
+ @Test public void Basic() {
+ tst_Status(10, stringAry_(" - hash: 100%"));
+ tst_Status(11, stringAry_(" - hash: 66%"));
+ tst_Status(30, stringAry_(" - hash: 40%", " - hash: 60%", " - hash: 100%"));
+ }
+ void tst_Status(int count, String[] expdWritten) {
+ ConsoleDlg_dev dialog = ConsoleDlg_.Dev();
+ String data = String_.Repeat("A", count);
+ IoStream stream = IoStream_.mem_txt_(Io_url_.Null, data);
+ calc.CalcHash(dialog, stream);
+ String[] actlWritten = dialog.Written().XtoStrAry();
+ Tfds.Eq_ary(actlWritten, expdWritten);
+ }
+ String[] stringAry_(String... ary) {return ary;}
+ HashAlgo calc;
+}
diff --git a/100_core/src_200_io/gplx/Io_mgr.java b/100_core/src_200_io/gplx/Io_mgr.java
new file mode 100644
index 000000000..32448f511
--- /dev/null
+++ b/100_core/src_200_io/gplx/Io_mgr.java
@@ -0,0 +1,131 @@
+/*
+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;
+import gplx.ios.*; /*IoItmFil, IoItmDir..*/
+public class Io_mgr { // exists primarily to gather all cmds under gplx namespace; otherwise need to use gplx.ios whenever copying/deleting file
+ public boolean Exists(Io_url url) {return url.Type_dir() ? ExistsDir(url) : ExistsFil(url);}
+ public boolean ExistsFil(Io_url url) {return IoEnginePool._.Fetch(url.Info().EngineKey()).ExistsFil_api(url);}
+ public void ExistsFilOrFail(Io_url url) {if (!ExistsFil(url)) throw Err_.new_("could not find file").Add("url", url);}
+ public void SaveFilStr(String url, String text) {SaveFilStr_args(Io_url_.new_fil_(url), text).Exec();}
+ public void SaveFilStr(Io_url url, String text) {SaveFilStr_args(url, text).Exec();}
+ public IoEngine_xrg_saveFilStr SaveFilStr_args(Io_url url, String text) {return IoEngine_xrg_saveFilStr.new_(url, text);}
+ public void AppendFilStr(String url, String text) {AppendFilStr(Io_url_.new_fil_(url), text);}
+ public void AppendFilStr(Io_url url, String text) {SaveFilStr_args(url, text).Append_(true).Exec();}
+ public void DeleteFil(Io_url url) {DeleteFil_args(url).Exec();}
+ public IoEngine_xrg_deleteFil DeleteFil_args(Io_url url) {return IoEngine_xrg_deleteFil.new_(url);}
+ public void MoveFil(Io_url src, Io_url trg) {IoEngine_xrg_xferFil.move_(src, trg).Exec();}
+ public IoEngine_xrg_xferFil MoveFil_args(Io_url src, Io_url trg, boolean overwrite) {return IoEngine_xrg_xferFil.move_(src, trg).Overwrite_(overwrite);}
+ public void CopyFil(Io_url src, Io_url trg, boolean overwrite) {IoEngine_xrg_xferFil.copy_(src, trg).Overwrite_(overwrite).Exec();}
+ public IoEngine_xrg_xferFil CopyFil_args(Io_url src, Io_url trg, boolean overwrite) {return IoEngine_xrg_xferFil.copy_(src, trg).Overwrite_(overwrite);}
+ public IoRecycleBin RecycleBin() {return recycleBin;} IoRecycleBin recycleBin = IoRecycleBin._;
+
+ public IoStream OpenStreamWrite(Io_url url) {return OpenStreamWrite_args(url).Exec();}
+ public IoEngine_xrg_openWrite OpenStreamWrite_args(Io_url url) {return IoEngine_xrg_openWrite.new_(url);}
+ public IoItmFil QueryFil(Io_url url) {return IoEnginePool._.Fetch(url.Info().EngineKey()).QueryFil(url);}
+ public void UpdateFilAttrib(Io_url url, IoItmAttrib attrib) {IoEnginePool._.Fetch(url.Info().EngineKey()).UpdateFilAttrib(url, attrib);}
+ public void UpdateFilModifiedTime(Io_url url, DateAdp modified) {IoEnginePool._.Fetch(url.Info().EngineKey()).UpdateFilModifiedTime(url, modified);}
+
+ public boolean ExistsDir(Io_url url) {return IoEnginePool._.Fetch(url.Info().EngineKey()).ExistsDir(url);}
+ public void CreateDir(Io_url url) {IoEnginePool._.Fetch(url.Info().EngineKey()).CreateDir(url);}
+ public boolean CreateDirIfAbsent(Io_url url) {
+ boolean exists = ExistsDir(url);
+ if (!exists) {
+ CreateDir(url);
+ return true;
+ }
+ return false;
+ }
+ public Io_url[] QueryDir_fils(Io_url dir) {return QueryDir_args(dir).ExecAsUrlAry();}
+ public IoEngine_xrg_queryDir QueryDir_args(Io_url dir) {return IoEngine_xrg_queryDir.new_(dir);}
+ public void DeleteDirSubs(Io_url url) {IoEngine_xrg_deleteDir.new_(url).Exec();}
+ public IoEngine_xrg_deleteDir DeleteDir_cmd(Io_url url) {return IoEngine_xrg_deleteDir.new_(url);}
+ public void DeleteDirDeep(Io_url url) {IoEngine_xrg_deleteDir.new_(url).Recur_().Exec();}
+ public void DeleteDirDeep_ary(Io_url... urls) {for (Io_url url : urls) IoEngine_xrg_deleteDir.new_(url).Recur_().Exec();}
+ public void MoveDirDeep(Io_url src, Io_url trg) {IoEngine_xrg_xferDir.move_(src, trg).Recur_().Exec();}
+ public IoEngine_xrg_xferDir CopyDir_cmd(Io_url src, Io_url trg) {return IoEngine_xrg_xferDir.copy_(src, trg);}
+ public void CopyDirSubs(Io_url src, Io_url trg) {IoEngine_xrg_xferDir.copy_(src, trg).Exec();}
+ public void CopyDirDeep(Io_url src, Io_url trg) {IoEngine_xrg_xferDir.copy_(src, trg).Recur_().Exec();}
+ public void DeleteDirIfEmpty(Io_url url) {
+ if (Array_.Len(QueryDir_fils(url)) == 0)
+ this.DeleteDirDeep(url);
+ }
+ public void AliasDir_sysEngine(String srcRoot, String trgRoot) {AliasDir(srcRoot, trgRoot, IoEngine_.SysKey);}
+ public void AliasDir(String srcRoot, String trgRoot, String engineKey) {IoUrlInfoRegy._.Reg(IoUrlInfo_.alias_(srcRoot, trgRoot, engineKey));}
+// public IoStream OpenStreamRead2(Io_url url) {return IoEngine_xrg_openRead.new_(url).ExecAsIoStreamOrFail();}
+ public IoStream OpenStreamRead(Io_url url) {return OpenStreamRead_args(url).ExecAsIoStreamOrFail();}
+ public IoEngine_xrg_openRead OpenStreamRead_args(Io_url url) {return IoEngine_xrg_openRead.new_(url);}
+ public String LoadFilStr(String url) {return LoadFilStr_args(Io_url_.new_fil_(url)).Exec();}
+ public String LoadFilStr(Io_url url) {return LoadFilStr_args(url).Exec();}
+ public IoEngine_xrg_loadFilStr LoadFilStr_args(Io_url url) {return IoEngine_xrg_loadFilStr.new_(url);}
+ public byte[] LoadFilBry(String url) {return LoadFilBry_reuse(Io_url_.new_fil_(url), Bry_.Empty, Int_obj_ref.zero_());}
+ public byte[] LoadFilBry(Io_url url) {return LoadFilBry_reuse(url, Bry_.Empty, Int_obj_ref.zero_());}
+ public void LoadFilBryByBfr(Io_url url, Bry_bfr bfr) {
+ Int_obj_ref len = Int_obj_ref.zero_();
+ byte[] bry = LoadFilBry_reuse(url, Bry_.Empty, len);
+ bfr.Bfr_init(bry, len.Val());
+ }
+ public static final byte[] LoadFilBry_fail = Bry_.Empty;
+ public byte[] LoadFilBry_reuse(Io_url url, byte[] ary, Int_obj_ref aryLen) {
+ if (!ExistsFil(url)) {aryLen.Val_(0); return LoadFilBry_fail;}
+ IoStream stream = IoStream_.Null;
+ try {
+ stream = OpenStreamRead(url);
+ int streamLen = (int)stream.Len();
+ aryLen.Val_(streamLen);
+ if (streamLen > ary.length)
+ ary = new byte[streamLen];
+ stream.ReadAry(ary);
+ return ary;
+ }
+ catch (Exception e) {throw Err_.new_("failed to load file").Add("url", url.Xto_api()).Add("e", Err_.Message_lang(e));}
+ finally {stream.Rls();}
+ }
+ public void AppendFilBfr(Io_url url, Bry_bfr bfr) {AppendFilByt(url, bfr.Bfr(), 0, bfr.Len()); bfr.ClearAndReset();}
+ public void AppendFilByt(Io_url url, byte[] val) {AppendFilByt(url, val, 0, val.length);}
+ public void AppendFilByt(Io_url url, byte[] val, int len) {AppendFilByt(url, val, 0, len);}
+ public void AppendFilByt(Io_url url, byte[] val, int bgn, int len) {
+ IoStream stream = IoStream_.Null;
+ try {
+ stream = OpenStreamWrite_args(url).Mode_(IoStream_.Mode_wtr_append).Exec();
+ stream.Write(val, bgn, len);
+ } finally {stream.Rls();}
+ }
+ public void SaveFilBfr(Io_url url, Bry_bfr bfr) {SaveFilBry(url, bfr.Bfr(), bfr.Len()); bfr.Clear();}
+ public void SaveFilBry(String urlStr, byte[] val) {SaveFilBry(Io_url_.new_fil_(urlStr), val);}
+ public void SaveFilBry(Io_url url, byte[] val) {SaveFilBry(url, val, val.length);}
+ public void SaveFilBry(Io_url url, byte[] val, int len) {SaveFilBry(url, val, 0, len);}
+ public void SaveFilBry(Io_url url, byte[] val, int bgn, int len) {
+ IoStream stream = IoStream_.Null;
+ try {
+ stream = OpenStreamWrite(url);
+ stream.Write(val, bgn, len);
+ } finally {stream.Rls();}
+ }
+ public IoEngine InitEngine_mem() {return IoEngine_.Mem_init_();}
+ public IoEngine InitEngine_mem_(String key) {
+ IoEngine engine = IoEngine_.mem_new_(key);
+ IoEnginePool._.AddReplace(engine);
+ IoUrlInfoRegy._.Reg(IoUrlInfo_.mem_(key, key));
+ return engine;
+ }
+ public boolean DownloadFil(String src, Io_url trg) {return IoEngine_xrg_downloadFil.new_(src, trg).Exec();}
+ public IoEngine_xrg_downloadFil DownloadFil_args(String src, Io_url trg) {return IoEngine_xrg_downloadFil.new_(src, trg);}
+ public static final Io_mgr _ = new Io_mgr(); public Io_mgr() {}
+ public static final int Len_kb = 1024, Len_mb = 1048576, Len_gb = 1073741824, Len_gb_2 = 2147483647;
+ public static final long Len_null = -1;
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine.java b/100_core/src_200_io/gplx/ios/IoEngine.java
new file mode 100644
index 000000000..3dfc0feab
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine.java
@@ -0,0 +1,154 @@
+/*
+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.ios; import gplx.*;
+import gplx.criterias.*;
+public interface IoEngine {
+ String Key();
+ boolean ExistsFil_api(Io_url url);
+ void SaveFilText_api(IoEngine_xrg_saveFilStr args);
+ String LoadFilStr(IoEngine_xrg_loadFilStr args);
+ void DeleteFil_api(IoEngine_xrg_deleteFil args);
+ void CopyFil(IoEngine_xrg_xferFil args);
+ void MoveFil(IoEngine_xrg_xferFil args);
+ IoItmFil QueryFil(Io_url url);
+ void UpdateFilAttrib(Io_url url, IoItmAttrib atr); // will fail if file does not exists
+ void UpdateFilModifiedTime(Io_url url, DateAdp modified);
+ IoStream OpenStreamRead(Io_url url);
+ IoStream OpenStreamWrite(IoEngine_xrg_openWrite args);
+ void XferFil(IoEngine_xrg_xferFil args);
+ void RecycleFil(IoEngine_xrg_recycleFil xrg);
+
+ boolean ExistsDir(Io_url url);
+ void CreateDir(Io_url url); // creates all folder levels (EX: C:\a\b\c\ will create C:\a\ and C:\a\b\). will not fail if called on already existing folders.
+ void DeleteDir(Io_url url);
+ void MoveDir(Io_url src, Io_url trg); // will fail if trg exists
+ void CopyDir(Io_url src, Io_url trg);
+ IoItmDir QueryDir(Io_url url);
+
+ void DeleteDirDeep(IoEngine_xrg_deleteDir args);
+ void MoveDirDeep(IoEngine_xrg_xferDir args); // will fail if trg exists
+ IoItmDir QueryDirDeep(IoEngine_xrg_queryDir args);
+ void XferDir(IoEngine_xrg_xferDir args);
+ boolean DownloadFil(IoEngine_xrg_downloadFil xrg);
+ Io_stream_rdr DownloadFil_as_rdr(IoEngine_xrg_downloadFil xrg);
+}
+class IoEngineUtl {
+ public int BufferLength() {return bufferLength;} public void BufferLength_set(int v) {bufferLength = v;} int bufferLength = 4096; // 0x1000
+ public void DeleteRecycleGplx(IoEngine engine, IoEngine_xrg_recycleFil xrg) {
+ Io_url recycleUrl = xrg.RecycleUrl();
+ if (recycleUrl.Type_fil())
+ engine.MoveFil(IoEngine_xrg_xferFil.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true));
+ else
+ engine.MoveDirDeep(IoEngine_xrg_xferDir.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true));
+ }
+ public void DeleteDirDeep(IoEngine engine, Io_url dirUrl, IoEngine_xrg_deleteDir args) {
+ ConsoleDlg usrDlg = args.UsrDlg();
+ IoItmDir dir = engine.QueryDir(dirUrl); if (!dir.Exists()) return;
+ for (Object subDirObj : dir.SubDirs()) {
+ IoItmDir subDir = (IoItmDir)subDirObj;
+ if (!args.SubDirScanCrt().Matches(subDir)) continue;
+ if (args.Recur()) DeleteDirDeep(engine, subDir.Url(), args);
+ }
+ for (Object subFilObj : dir.SubFils()) {
+ IoItmFil subFil = (IoItmFil)subFilObj;
+ if (!args.MatchCrt().Matches(subFil)) continue;
+ Io_url subFilUrl = subFil.Url();
+ try {engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(subFilUrl).ReadOnlyFails_(args.ReadOnlyFails()));}
+ catch (Exception exc) {usrDlg.WriteLineFormat(Err_.Message_lang(exc));}
+ }
+ // all subs deleted; now delete dir
+ if (!args.MatchCrt().Matches(dir)) return;
+ try {engine.DeleteDir(dir.Url());}
+ catch (Exception exc) {usrDlg.WriteLineFormat(Err_.Message_lang(exc));}
+ }
+ public void XferDir(IoEngine srcEngine, Io_url src, IoEngine trgEngine, Io_url trg, IoEngine_xrg_xferDir args) {
+ trgEngine.CreateDir(trg);
+ IoItmDir srcDir = QueryDirDeep(srcEngine, IoEngine_xrg_queryDir.new_(src).Recur_(false));
+ for (Object subSrcObj : srcDir.SubDirs()) {
+ IoItmDir subSrc = (IoItmDir)subSrcObj;
+ if (!args.SubDirScanCrt().Matches(subSrc)) continue;
+ if (!args.MatchCrt().Matches(subSrc)) continue;
+ Io_url subTrg = trg.GenSubDir_nest(subSrc.Url().NameOnly()); //EX: C:\abc\def\ -> C:\123\ + def\
+ if (args.Recur()) XferDir(srcEngine, subSrc.Url(), trgEngine, subTrg, args);
+ }
+ IoItmList srcFils = IoItmList.list_(src.Info().CaseSensitive());
+ for (Object srcFilObj : srcDir.SubFils()) {
+ IoItmFil srcFil = (IoItmFil)srcFilObj;
+ if (args.MatchCrt().Matches(srcFil)) srcFils.Add(srcFil);
+ }
+ for (Object srcFilObj : srcFils) {
+ IoItmFil srcFil = (IoItmFil)srcFilObj;
+ Io_url srcFilPath = srcFil.Url();
+ Io_url trgFilPath = trg.GenSubFil(srcFilPath.NameAndExt()); //EX: C:\abc\fil.txt -> C:\123\ + fil.txt
+ IoEngine_xrg_xferFil xferArgs = args.Type_move() ? IoEngine_xrg_xferFil.move_(srcFilPath, trgFilPath).Overwrite_(args.Overwrite()) : IoEngine_xrg_xferFil.copy_(srcFilPath, trgFilPath).Overwrite_(args.Overwrite());
+ XferFil(srcEngine, xferArgs);
+ }
+ if (args.Type_move()) srcEngine.DeleteDirDeep(IoEngine_xrg_deleteDir.new_(src).Recur_(args.Recur()).ReadOnlyFails_(args.ReadOnlyFails()));// this.DeleteDirDeep(srcEngine, src, IoEngine_xrg_deleteItm.new_(src).Recur_(args.Recur()).ReadOnlyIgnored_(args.ReadOnlyIgnored()));
+ }
+ public void XferFil(IoEngine srcEngine, IoEngine_xrg_xferFil args) {
+ Io_url src = args.Src(), trg = args.Trg();
+ if (String_.Eq(srcEngine.Key(), trg.Info().EngineKey())) {
+ if (args.Type_move())
+ srcEngine.MoveFil(args);
+ else
+ srcEngine.CopyFil(args);
+ }
+ else {
+ TransferStream(src, trg);
+ if (args.Type_move()) srcEngine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(src));
+ }
+ }
+ public IoItmDir QueryDirDeep(IoEngine engine, IoEngine_xrg_queryDir args) {
+ IoItmDir rv = IoItmDir_.top_(args.Url());
+ rv.Exists_set(QueryDirDeepCore(rv, args.Url(), engine, args.Recur(), args.SubDirScanCrt(), args.DirCrt(), args.FilCrt(), args.UsrDlg(), args.DirInclude()));
+ return rv;
+ }
+ static boolean QueryDirDeepCore(IoItmDir ownerDir, Io_url url, IoEngine engine, boolean recur, Criteria subDirScanCrt, Criteria dirCrt, Criteria filCrt, ConsoleDlg usrDlg, boolean dirInclude) {
+ if (usrDlg.CanceledChk()) return false;
+ if (usrDlg.Enabled()) usrDlg.WriteTempText(String_.Concat("scan: ", url.Raw()));
+ IoItmDir scanDir = engine.QueryDir(url);
+ for (Object subDirObj : scanDir.SubDirs()) {
+ IoItmDir subDir = (IoItmDir)subDirObj;
+ if (!subDirScanCrt.Matches(subDir)) continue;
+ if (dirCrt.Matches(subDir)) {
+ ownerDir.SubDirs().Add(subDir); // NOTE: always add subDir; do not use dirCrt here, else its subFils will be added to non-existent subDir
+ }
+ if (recur)
+ QueryDirDeepCore(subDir, subDir.Url(), engine, recur, subDirScanCrt, dirCrt, filCrt, usrDlg, dirInclude);
+ }
+ for (Object subFilObj : scanDir.SubFils()) {
+ IoItmFil subFil = (IoItmFil)subFilObj;
+ if (filCrt.Matches(subFil)) ownerDir.SubFils().Add(subFil);
+ }
+ return scanDir.Exists();
+ }
+ void TransferStream(Io_url src, Io_url trg) {
+ IoStream srcStream = null;
+ IoStream trgStream = null;
+ try {
+ srcStream = IoEnginePool._.Fetch(src.Info().EngineKey()).OpenStreamRead(src);
+ trgStream = IoEngine_xrg_openWrite.new_(trg).Exec();
+ srcStream.Transfer(trgStream, bufferLength);
+ }
+ finally {
+ if (srcStream != null) srcStream.Rls();
+ if (trgStream != null) trgStream.Rls();
+ }
+ }
+ public static IoEngineUtl new_() {return new IoEngineUtl();} IoEngineUtl() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEnginePool.java b/100_core/src_200_io/gplx/ios/IoEnginePool.java
new file mode 100644
index 000000000..513e06a82
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEnginePool.java
@@ -0,0 +1,34 @@
+/*
+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.ios; import gplx.*;
+public class IoEnginePool {
+ public void AddReplace(IoEngine engine) {
+ hash.Del(engine.Key());
+ hash.Add(engine.Key(), engine);
+ }
+ public IoEngine Fetch(String key) {
+ IoEngine rv = (IoEngine)hash.Fetch(key);
+ return rv == null ? IoEngine_.Mem : rv; // rv == null when url is null or empty; return Mem which should be a noop; DATE:2013-06-04
+ }
+ HashAdp hash = HashAdp_.new_();
+ public static final IoEnginePool _ = new IoEnginePool();
+ IoEnginePool() {
+ this.AddReplace(IoEngine_.Sys);
+ this.AddReplace(IoEngine_.Mem);
+ }
+}
\ No newline at end of file
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_.java b/100_core/src_200_io/gplx/ios/IoEngine_.java
new file mode 100644
index 000000000..b57ff377c
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_.java
@@ -0,0 +1,30 @@
+/*
+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.ios; import gplx.*;
+public class IoEngine_ {
+ public static final String SysKey = "sys";
+ public static final String MemKey = "mem";
+
+ public static final IoEngine Sys = IoEngine_system.new_();
+ public static final IoEngine_memory Mem = IoEngine_memory.new_(MemKey);
+ public static IoEngine Mem_init_() {
+ Mem.Clear();
+ return Mem;
+ }
+ public static IoEngine mem_new_(String key) {return IoEngine_memory.new_(key);}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_base.java b/100_core/src_200_io/gplx/ios/IoEngine_base.java
new file mode 100644
index 000000000..f316e7983
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_base.java
@@ -0,0 +1,57 @@
+/*
+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.ios; import gplx.*;
+public abstract class IoEngine_base implements IoEngine {
+ public abstract String Key();
+ public abstract boolean ExistsFil_api(Io_url url);
+ public abstract void SaveFilText_api(IoEngine_xrg_saveFilStr args);
+ public abstract String LoadFilStr(IoEngine_xrg_loadFilStr args);
+ public abstract void DeleteFil_api(IoEngine_xrg_deleteFil args);
+ public abstract void CopyFil(IoEngine_xrg_xferFil args);
+ public abstract void MoveFil(IoEngine_xrg_xferFil args);
+ public abstract IoItmFil QueryFil(Io_url url);
+ public abstract void UpdateFilAttrib(Io_url url, IoItmAttrib atr); // will fail if file does not exists
+ public abstract void UpdateFilModifiedTime(Io_url url, DateAdp modified);
+ public abstract IoStream OpenStreamRead(Io_url url);
+ public abstract IoStream OpenStreamWrite(IoEngine_xrg_openWrite args);
+ public abstract void XferFil(IoEngine_xrg_xferFil args);
+
+ public abstract boolean ExistsDir(Io_url url);
+ public abstract void CreateDir(Io_url url); // creates all folder levels (EX: C:\a\b\c\ will create C:\a\ and C:\a\b\). will not fail if called on already existing folders.
+ public abstract void DeleteDir(Io_url url);
+ public abstract void MoveDir(Io_url src, Io_url trg); // will fail if trg exists
+ public abstract void CopyDir(Io_url src, Io_url trg);
+ public abstract IoItmDir QueryDir(Io_url url);
+
+ public abstract void DeleteDirDeep(IoEngine_xrg_deleteDir args);
+ public abstract void MoveDirDeep(IoEngine_xrg_xferDir args); // will fail if trg exists
+ public abstract IoItmDir QueryDirDeep(IoEngine_xrg_queryDir args);
+ public abstract void XferDir(IoEngine_xrg_xferDir args);
+ public abstract boolean DownloadFil(IoEngine_xrg_downloadFil xrg);
+ public abstract Io_stream_rdr DownloadFil_as_rdr(IoEngine_xrg_downloadFil xrg);
+
+ public void RecycleFil(IoEngine_xrg_recycleFil xrg) {
+ Io_url recycleUrl = xrg.RecycleUrl();
+ if (recycleUrl.Type_fil()) {
+ this.MoveFil(IoEngine_xrg_xferFil.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true).MissingFails_(xrg.MissingFails()));
+ IoRecycleBin._.Regy_add(xrg);
+ }
+ else
+ this.MoveDirDeep(IoEngine_xrg_xferDir.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true));
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_memory.java b/100_core/src_200_io/gplx/ios/IoEngine_memory.java
new file mode 100644
index 000000000..1f2cae2d1
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_memory.java
@@ -0,0 +1,200 @@
+/*
+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.ios; import gplx.*;
+public class IoEngine_memory extends IoEngine_base {
+ @Override public String Key() {return key;} private String key = IoEngine_.MemKey;
+ @Override public boolean ExistsFil_api(Io_url url) {return FetchFil(url) != IoItmFil_mem.Null;}
+ @Override public void DeleteFil_api(IoEngine_xrg_deleteFil args) {
+ Io_url url = args.Url();
+ IoItmDir dir = FetchDir(url.OwnerDir()); if (dir == null) return; // url doesn't exist; just exit
+ IoItmFil fil = IoItmFil_.as_(dir.SubFils().Fetch(url.NameAndExt()));
+ if (fil != null && fil.ReadOnly() && args.ReadOnlyFails()) throw IoErr.FileIsReadOnly(url);
+ dir.SubFils().Del(url);
+ }
+ void DeleteFil(Io_url url) {DeleteFil_api(IoEngine_xrg_deleteFil.new_(url));}
+ @Override public void XferFil(IoEngine_xrg_xferFil args) {utl.XferFil(this, args);}
+ @Override public void MoveFil(IoEngine_xrg_xferFil args) {
+ Io_url src = args.Src(), trg = args.Trg(); boolean overwrite = args.Overwrite();
+ if (String_.Eq(src.Xto_api(), trg.Xto_api())) throw Err_.new_fmt_("move failed; src is same as trg: {0}", src.Raw());
+ CheckTransferArgs("move", src, trg, overwrite);
+ if (overwrite) DeleteFil(trg);
+ IoItmFil_mem curFil = FetchFil(src); curFil.Name_(trg.NameAndExt());
+ AddFilToDir(trg.OwnerDir(), curFil);
+ DeleteFil(src);
+ }
+ @Override public void CopyFil(IoEngine_xrg_xferFil args) {
+ Io_url src = args.Src(), trg = args.Trg(); boolean overwrite = args.Overwrite();
+ CheckTransferArgs("copy", src, trg, overwrite);
+ if (overwrite) DeleteFil(trg);
+ IoItmFil_mem srcFil = FetchFil(src);
+ IoItmFil_mem curFil = srcFil.Clone(); curFil.Name_(trg.NameAndExt());
+ AddFilToDir(trg.OwnerDir(), curFil);
+ }
+ @Override public IoItmDir QueryDirDeep(IoEngine_xrg_queryDir args) {return utl.QueryDirDeep(this, args);}
+ @Override public void UpdateFilAttrib(Io_url url, IoItmAttrib atr) {FetchFil(url).ReadOnly_(atr.ReadOnly());}
+ @Override public void UpdateFilModifiedTime(Io_url url, DateAdp modified) {FetchFil(url).ModifiedTime_(modified);}
+ @Override public IoItmFil QueryFil(Io_url url) {return FetchFil(url);}
+ @Override public void SaveFilText_api(IoEngine_xrg_saveFilStr args) {
+ Io_url url = args.Url();
+ IoItmDir dir = FetchDir(url.OwnerDir());
+ if (dir != null) {
+ IoItmFil fil = IoItmFil_.as_(dir.SubFils().Fetch(url.NameAndExt()));
+ if (fil != null && fil.ReadOnly()) throw IoErr.FileIsReadOnly(url);
+ }
+
+ if (args.Append())
+ AppendFilStr(args);
+ else
+ SaveFilStr(args.Url(), args.Text());
+ }
+ @Override public String LoadFilStr(IoEngine_xrg_loadFilStr args) {
+ return FetchFil(args.Url()).Text();
+ }
+ void SaveFilStr(Io_url url, String text) {
+ DateAdp time = DateAdp_.Now();
+ IoItmFil_mem fil = IoItmFil_mem.new_(url, String_.Len(text), time, text);
+ AddFilToDir(url.OwnerDir(), fil);
+ }
+ void AppendFilStr(IoEngine_xrg_saveFilStr args) {
+ Io_url url = args.Url(); String text = args.Text();
+ if (ExistsFil_api(url)) {
+ IoItmFil_mem fil = FetchFil(url);
+ fil.ModifiedTime_(DateAdp_.Now());
+ fil.Text_set(fil.Text() + text);
+ }
+ else
+ SaveFilStr(args.Url(), args.Text());
+ }
+ @Override public IoStream OpenStreamRead(Io_url url) {
+ IoItmFil_mem fil = FetchFil(url);
+ fil.Stream().Position_set(0);
+ return fil.Stream();
+ }
+ @Override public IoStream OpenStreamWrite(IoEngine_xrg_openWrite args) {
+ Io_url url = args.Url();
+ IoItmFil_mem fil = FetchFil(url);
+ if (fil == IoItmFil_mem.Null) { // file doesn't exist; create new one
+ SaveFilStr(url, "");
+ fil = FetchFil(url);
+ }
+ else {
+ if (args.Mode() == IoStream_.Mode_wtr_create)
+ fil.Text_set(""); // NOTE: clear text b/c it still has pointer to existing stream
+ }
+ return fil.Stream();
+ }
+
+ @Override public boolean ExistsDir(Io_url url) {return FetchDir(url) != null;}
+ @Override public void CreateDir(Io_url url) {
+ IoItmDir dir = FetchDir(url); if (dir != null) return; // dir exists; exit
+ dir = IoItmDir_.top_(url);
+ dirs.Add(dir);
+ IoItmDir ownerDir = FetchDir(url.OwnerDir());
+ if (ownerDir == null && !url.OwnerDir().Eq(Io_url_.Null)) { // no owner dir && not "driveDir" -> create
+ CreateDir(url.OwnerDir()); // recursive
+ ownerDir = FetchDir(url.OwnerDir());
+ }
+ if (ownerDir != null)
+ ownerDir.SubDirs().Add(dir);
+ }
+ @Override public void DeleteDir(Io_url url) {
+ FetchDir(url); // force creation if exists?
+ dirs.Del(url);
+ IoItmDir ownerDir = FetchDir(url.OwnerDir()); if (ownerDir == null) return; // no ownerDir; no need to unregister
+ ownerDir.SubDirs().Del(url);
+ }
+ @Override public void XferDir(IoEngine_xrg_xferDir args) {Io_url trg = args.Trg(); utl.XferDir(this, args.Src(), IoEnginePool._.Fetch(trg.Info().EngineKey()), trg, args);}
+ @Override public void MoveDirDeep(IoEngine_xrg_xferDir args) {Io_url trg = args.Trg(); utl.XferDir(this, args.Src(), IoEnginePool._.Fetch(trg.Info().EngineKey()), trg, args);}
+ @Override public void MoveDir(Io_url src, Io_url trg) {if (ExistsDir(trg)) throw Err_.new_("trg already exists").Add("trg", trg);
+ IoItmDir dir = FetchDir(src); dir.Name_(trg.NameAndExt());
+ for (Object filObj : dir.SubFils()) { // move all subFiles
+ IoItmFil fil = (IoItmFil)filObj;
+ fil.OwnerDir_set(dir);
+ }
+ dirs.Add(dir);
+ DeleteDir(src);
+ }
+ @Override public IoItmDir QueryDir(Io_url url) {
+ IoItmDir dir = FetchDir(url);
+ IoItmDir rv = IoItmDir_.top_(url); // always return copy b/c caller may add/del itms directly
+ if (dir == null) {
+ rv.Exists_set(false);
+ return rv;
+ }
+ for (Object subDirObj : dir.SubDirs()) {
+ IoItmDir subDir = (IoItmDir)subDirObj;
+ rv.SubDirs().Add(IoItmDir_.scan_(subDir.Url()));
+ }
+ for (Object subFilObj : dir.SubFils()) {
+ IoItmFil subFil = (IoItmFil)subFilObj;
+ rv.SubFils().Add(subFil);
+ }
+ return rv;
+ }
+ @Override public void DeleteDirDeep(IoEngine_xrg_deleteDir args) {utl.DeleteDirDeep(this, args.Url(), args);}
+ @Override public void CopyDir(Io_url src, Io_url trg) {
+ IoEngine_xrg_xferDir.copy_(src, trg).Recur_().Exec();
+ }
+ void AddFilToDir(Io_url dirPath, IoItmFil fil) {
+ IoItmDir dir = FetchDir(dirPath);
+ if (dir == null) {
+ CreateDir(dirPath);
+ dir = FetchDir(dirPath);
+ }
+ dir.SubFils().Del(fil.Url());
+ dir.SubFils().Add(fil);
+ }
+ IoItmDir FetchDir(Io_url url) {return IoItmDir_.as_(dirs.Fetch(url));}
+ IoItmFil_mem FetchFil(Io_url url) {
+ IoItmDir ownerDir = FetchDir(url.OwnerDir());
+ if (ownerDir == null) return IoItmFil_mem.Null;
+ IoItmFil_mem rv = IoItmFil_mem.as_(ownerDir.SubFils().Fetch(url.NameAndExt()));
+ if (rv == null) rv = IoItmFil_mem.Null;
+ return rv;
+ }
+ void CheckTransferArgs(String op, Io_url src, Io_url trg, boolean overwrite) {
+ if (!ExistsFil_api(src)) throw Err_.new_("src does not exist").Add("src", src);
+ if (ExistsFil_api(trg) && !overwrite) throw Err_.invalid_op_("trg already exists").Add("op", op).Add("overwrite", false).Add("src", src).Add("trg", trg);
+ }
+ public void Clear() {dirs.Clear();}
+ @Override public boolean DownloadFil(IoEngine_xrg_downloadFil xrg) {
+ Io_url src = Io_url_.mem_fil_(xrg.Src());
+ if (!ExistsFil_api(src)) {
+ xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_file_not_found);
+ return false;
+ }
+ XferFil(IoEngine_xrg_xferFil.copy_(src, xrg.Trg()).Overwrite_());
+ return true;
+ }
+ @Override public Io_stream_rdr DownloadFil_as_rdr(IoEngine_xrg_downloadFil xrg) {
+ Io_url src = Io_url_.mem_fil_(xrg.Src());
+ if (!ExistsFil_api(src)) {
+ xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_file_not_found);
+ return Io_stream_rdr_.Null;
+ }
+ byte[] bry = Bry_.new_utf8_(FetchFil(Io_url_.mem_fil_(xrg.Src())).Text());
+ return Io_stream_rdr_.mem_(bry);
+ }
+ IoItmHash dirs = IoItmHash.new_();
+ IoEngineUtl utl = IoEngineUtl.new_();
+ @gplx.Internal protected static IoEngine_memory new_(String key) {
+ IoEngine_memory rv = new IoEngine_memory();
+ rv.key = key;
+ return rv;
+ } IoEngine_memory() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_system.java b/100_core/src_200_io/gplx/ios/IoEngine_system.java
new file mode 100644
index 000000000..67d06f1bd
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_system.java
@@ -0,0 +1,628 @@
+/*
+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.ios; import gplx.*;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.Date;
+
+import javax.print.FlavorException;
+import javax.tools.JavaCompiler;
+import gplx.criterias.*;
+public class IoEngine_system extends IoEngine_base {
+ @Override public String Key() {return IoEngine_.SysKey;}
+ @Override public void DeleteDirDeep(IoEngine_xrg_deleteDir args) {utl.DeleteDirDeep(this, args.Url(), args);}
+ @Override public void XferDir(IoEngine_xrg_xferDir args) {Io_url trg = args.Trg(); utl.XferDir(this, args.Src(), IoEnginePool._.Fetch(trg.Info().EngineKey()), trg, args);}
+ @Override public void XferFil(IoEngine_xrg_xferFil args) {utl.XferFil(this, args);}
+ @Override public IoItmDir QueryDirDeep(IoEngine_xrg_queryDir args) {return utl.QueryDirDeep(this, args);}
+ @Override public void CopyDir(Io_url src, Io_url trg) {IoEngine_xrg_xferDir.copy_(src, trg).Recur_().Exec();}
+ @Override public void MoveDirDeep(IoEngine_xrg_xferDir args) {Io_url trg = args.Trg(); utl.XferDir(this, args.Src(), IoEnginePool._.Fetch(trg.Info().EngineKey()), trg, args);}
+ @Override public void DeleteFil_api(IoEngine_xrg_deleteFil args) {
+ Io_url url = args.Url();
+ File fil = Fil_(url);
+ if (!Fil_Exists(fil)) {
+ if (args.MissingFails()) throw IoErr.FileNotFound("delete", url);
+ else return;
+ }
+ MarkFileWritable(fil, url, args.ReadOnlyFails(), "DeleteFile");
+ DeleteFil_lang(fil, url);
+ }
+ @Override public boolean ExistsFil_api(Io_url url) {
+ return new File(url.Xto_api()).exists();
+ }
+ @Override public void SaveFilText_api(IoEngine_xrg_saveFilStr mpo) {
+ Io_url url = mpo.Url();
+
+ // encode string
+ byte[] textBytes = null;
+ textBytes = Bry_.new_utf8_(mpo.Text());
+
+ FileChannel fc = null; FileOutputStream fos = null;
+ if (!ExistsDir(url.OwnerDir())) CreateDir(url.OwnerDir());
+ try {
+ // open file
+ try {fos = new FileOutputStream(url.Xto_api(), mpo.Append());}
+ catch (FileNotFoundException e) {throw Err_Fil_NotFound(e, url);}
+ fc = fos.getChannel();
+
+ // write text
+ try {fc.write(ByteBuffer.wrap(textBytes));}
+ catch (IOException e) {
+ Closeable_Close(fc, url, false);
+ Closeable_Close(fos, url, false);
+ throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "write data to file failed").Add("url", url.Xto_api());
+ }
+ if (!Op_sys.Cur().Tid_is_drd()) {
+ File fil = new File(url.Xto_api());
+ IoEngine_system_xtn.SetExecutable(fil, true);
+ }
+ }
+ finally {
+ // cleanup
+ Closeable_Close(fc, url, false);
+ Closeable_Close(fos, url, false);
+ }
+ }
+ @SuppressWarnings("resource")
+ @Override public String LoadFilStr(IoEngine_xrg_loadFilStr args) {
+ Io_url url = args.Url();
+
+ // get reader for file
+ InputStream stream = null;
+ try {stream = new FileInputStream(url.Xto_api());}
+ catch (FileNotFoundException e) {
+ if (args.MissingIgnored()) return "";
+ throw Err_Fil_NotFound(e, url);
+ }
+ InputStreamReader reader = null;
+ try {reader = new InputStreamReader(stream, IoEngineArgs._.LoadFilStr_Encoding);}
+ catch (UnsupportedEncodingException e) {
+ Closeable_Close(stream, url, false);
+ throw Err_Text_UnsupportedEncoding(IoEngineArgs._.LoadFilStr_Encoding, "", url, e);
+ }
+
+ // make other objects
+ char[] readerBuffer = new char[IoEngineArgs._.LoadFilStr_BufferSize];
+ int pos = 0;
+ StringWriter sw = new StringWriter();
+
+ // transfer data
+ while (true) {
+ try {pos = reader.read(readerBuffer);}
+ catch (IOException e) {
+ Closeable_Close(stream, url, false);
+ Closeable_Close(reader, url, false);
+ throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "read data from file failed").Add("url", url.Xto_api()).Add("pos", pos);
+ }
+ if (pos == -1) break;
+ sw.write(readerBuffer, 0, pos);
+ }
+
+ // cleanup
+ Closeable_Close(stream, url, false);
+ Closeable_Close(reader, url, false);
+ return sw.toString();
+ }
+ @Override public boolean ExistsDir(Io_url url) {return new File(url.Xto_api()).exists();}
+ @Override public void CreateDir(Io_url url) {new File(url.Xto_api()).mkdirs();}
+ @Override public void DeleteDir(Io_url url) {
+ File dir = new File(url.Xto_api());
+ if (!dir.exists()) return;
+ boolean rv = dir.delete();
+ if (!rv) throw Err_.new_key_(IoEngineArgs._.Err_IoException, "delete dir failed").Add("url", url.Xto_api());
+ }
+ @Override public IoItmDir QueryDir(Io_url url) {
+ IoItmDir rv = IoItmDir_.scan_(url);
+ File dirInfo = new File(url.Xto_api());
+ if (!dirInfo.exists()) {
+ rv.Exists_set(false);
+ return rv;
+ }
+ IoUrlInfo urlInfo = url.Info();
+ File[] subItmAry = dirInfo.listFiles();
+ if (subItmAry == null) return rv; // directory has no files
+ for (int i = 0; i < subItmAry.length; i++) {
+ File subItm = subItmAry[i];
+ if (subItm.isFile()) {
+ IoItmFil subFil = QueryMkr_fil(urlInfo, subItm);
+ rv.SubFils().Add(subFil);
+ }
+ else {
+ IoItmDir subDir = QueryMkr_dir(urlInfo, subItm);
+ rv.SubDirs().Add(subDir);
+ }
+ }
+ return rv;
+ }
+ IoItmFil QueryMkr_fil(IoUrlInfo urlInfo, File apiFil) {
+ Io_url filUrl = Io_url_.new_inf_(apiFil.getPath(), urlInfo); // NOTE: may throw PathTooLongException when url is > 248 (exception messages states 260)
+ long fil_len = apiFil.exists() ? apiFil.length() : IoItmFil.Size_Invalid; // NOTE: if file doesn't exist, set len to -1; needed for "boolean Exists() {return size != Size_Invalid;}"; DATE:2014-06-21
+ IoItmFil rv = IoItmFil_.new_(filUrl, fil_len, DateAdp_.MinValue, DateAdp_.unixtime_lcl_ms_(apiFil.lastModified()));
+ rv.ReadOnly_(!apiFil.canWrite());
+ return rv;
+ }
+ IoItmDir QueryMkr_dir(IoUrlInfo urlInfo, File apiDir) {
+ Io_url dirUrl = Io_url_.new_inf_(apiDir.getPath() + urlInfo.DirSpr(), urlInfo); // NOTE: may throw PathTooLongException when url is > 248 (exception messages states 260)
+ return IoItmDir_.scan_(dirUrl);
+ }
+ @Override public IoItmFil QueryFil(Io_url url) {
+ File fil = new File(url.Xto_api());
+ return QueryMkr_fil(url.Info(), fil);
+ }
+ @Override public void UpdateFilAttrib(Io_url url, IoItmAttrib atr) {
+ File f = new File(url.Xto_api());
+ boolean rv = true;
+ if (atr.ReadOnly() != Fil_ReadOnly(f)) {
+ if (atr.ReadOnly())
+ rv = f.setReadOnly();
+ else {
+ if (!Op_sys.Cur().Tid_is_drd())
+ IoEngine_system_xtn.SetWritable(f, true);
+ }
+ if (!rv) throw Err_.new_key_(IoEngineArgs._.Err_IoException, "set file attribute failed")
+ .Add("attribute", "readOnly").Add("cur", Fil_ReadOnly(f)).Add("new", atr.ReadOnly()).Add("url", url.Xto_api());
+ }
+ if (atr.Hidden() != f.isHidden()) {
+ //Runtime.getRuntime().exec("attrib +H myHiddenFile.java");
+ }
+ }
+ @Override public void UpdateFilModifiedTime(Io_url url, DateAdp modified) {
+ File f = new File(url.Xto_api());
+ long timeInt = modified.UnderDateTime().getTimeInMillis();
+// if (timeInt < 0) {
+// UsrDlg_._.Notify("{0} {1}", url.Xto_api(), timeInt);
+// return;
+// }
+ if (!f.setLastModified(timeInt)) {
+ if (Fil_ReadOnly(f)) {
+ boolean success = false;
+ try {
+ UpdateFilAttrib(url, IoItmAttrib.normal_());
+ success = f.setLastModified(timeInt);
+ }
+ finally {
+ UpdateFilAttrib(url, IoItmAttrib.readOnly_());
+ }
+ if (!success) throw Err_.new_("could not update file modified time").Add("url", url.Xto_api()).Add("modifiedTime", modified.XtoStr_gplx_long());
+ }
+ }
+ }
+ @Override public IoStream OpenStreamRead(Io_url url) {return IoStream_base.new_(url, IoStream_.Mode_rdr);}
+ @Override public IoStream OpenStreamWrite(IoEngine_xrg_openWrite args) {
+ Io_url url = args.Url();
+ if (!ExistsFil_api(url)) SaveFilText_api(IoEngine_xrg_saveFilStr.new_(url, ""));
+ return IoStream_base.new_(url, args.Mode());
+ }
+ @SuppressWarnings("resource")
+ @Override public void CopyFil(IoEngine_xrg_xferFil args) {
+ // TODO:JAVA6 hidden property ignored; 1.6 does not allow OS-independent way of setting isHidden (wnt only possible through jni)
+ boolean overwrite = args.Overwrite();
+ Io_url srcUrl = args.Src(), trgUrl = args.Trg();
+ File srcFil = new File(srcUrl.Xto_api()), trgFil = new File(trgUrl.Xto_api());
+ if (trgFil.isFile()) { // trgFil exists; check if overwrite set and trgFil is writable
+ Chk_TrgFil_Overwrite(overwrite, trgUrl);
+ MarkFileWritable(trgFil, trgUrl, args.ReadOnlyFails(), "copy");
+ }
+ else { // trgFil doesn't exist; must create file first else fileNotFound exception thrown
+// if (overwrite) throw Err_
+ boolean rv = true; //Exception exc = null;
+ if (!ExistsDir(trgUrl.OwnerDir())) CreateDir(trgUrl.OwnerDir());
+ try {
+ trgFil.createNewFile();
+ if (!Op_sys.Cur().Tid_is_drd())
+ IoEngine_system_xtn.SetExecutable(trgFil, true);
+ }
+ catch (IOException e) {
+// exc = e;
+ rv = false;
+ }
+ if (!rv)
+ throw Err_.new_("create file failed").Add("trg", trgUrl.Xto_api());
+ }
+ FileInputStream srcStream = null; FileOutputStream trgStream = null;
+ FileChannel srcChannel = null, trgChannel = null;
+ try {
+ // make objects
+ try {srcStream = new FileInputStream(srcFil);}
+ catch (FileNotFoundException e) {throw IoErr.FileNotFound("copy", srcUrl);}
+ try {trgStream = new FileOutputStream(trgFil);}
+ catch (FileNotFoundException e) {
+ trgStream = TryToUnHideFile(trgFil, trgUrl);
+ if (trgStream == null)
+ throw IoErr.FileNotFound("copy", trgUrl);
+// else
+// wasHidden = true;
+ }
+ srcChannel = srcStream.getChannel();
+ trgChannel = trgStream.getChannel();
+
+ // transfer data
+ long pos = 0, count = 0, read = 0;
+ try {count = srcChannel.size();}
+ catch (IOException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "size failed").Add("src", srcUrl.Xto_api());}
+ int totalBufferSize = IoEngineArgs._.LoadFilStr_BufferSize;
+ long transferSize = (count > totalBufferSize) ? totalBufferSize : count; // transfer as much as fileSize, but limit to LoadFilStr_BufferSize
+ while (pos < count) {
+ try {read = trgChannel.transferFrom(srcChannel, pos, transferSize);}
+ catch (IOException e) {
+ Closeable_Close(srcChannel, srcUrl, false);
+ Closeable_Close(trgChannel, trgUrl, false);
+ Closeable_Close(srcStream, srcUrl, false);
+ Closeable_Close(trgStream, srcUrl, false);
+ throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "transfer data failed").Add("src", srcUrl.Xto_api()).Add("trg", trgUrl.Xto_api());
+ }
+ if (read == -1) break;
+ pos += read;
+ }
+// if (wasHidden)
+//
+ }
+ finally {
+ // cleanup
+ Closeable_Close(srcChannel, srcUrl, false);
+ Closeable_Close(trgChannel, trgUrl, false);
+ Closeable_Close(srcStream, srcUrl, false);
+ Closeable_Close(trgStream, srcUrl, false);
+ }
+ UpdateFilModifiedTime(trgUrl, QueryFil(srcUrl).ModifiedTime()); // must happen after file is closed
+ }
+ FileOutputStream TryToUnHideFile(File trgFil, Io_url trgUrl) {
+ FileOutputStream trgStream = null;
+ if (trgFil.exists()) { // WORKAROUND: java fails when writing to hidden files; unmark hidden and try again
+ Process p = null;
+ try {
+ String d = "attrib -H \"" + trgUrl.Xto_api() + "\"";
+ p = Runtime.getRuntime().exec(d);
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ }
+ try {
+ p.waitFor();
+ } catch (InterruptedException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ try {trgStream = new FileOutputStream(trgFil);}
+ catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+ return trgStream;
+ }
+ @Override public void MoveFil(IoEngine_xrg_xferFil args) {
+ Io_url srcUrl = args.Src(), trgUrl = args.Trg();
+ String src_api = srcUrl.Xto_api(), trg_api = trgUrl.Xto_api();
+ if (String_.Eq(src_api, trg_api)) return; // ignore command if src and trg is same; EX: C:\a.txt -> C:\a.txt should be noop
+ File srcFil = new File(src_api), trgFil = new File(trg_api);
+
+ // if drive is same, then rename file
+ if (String_.Eq(srcUrl.OwnerRoot().Raw(), trgUrl.OwnerRoot().Raw())) {
+ boolean overwrite = args.Overwrite();
+ if (!srcFil.exists() && args.MissingFails()) throw IoErr.FileNotFound("move", srcUrl);
+ if (trgFil.exists()) {
+ Chk_TrgFil_Overwrite(overwrite, trgUrl);
+ MarkFileWritable(trgFil, trgUrl, args.ReadOnlyFails(), "move");
+ DeleteFil_lang(trgFil, args.Trg()); // overwrite is specified and file is writable -> delete
+ }
+ if (!ExistsDir(trgUrl.OwnerDir())) CreateDir(trgUrl.OwnerDir());
+ srcFil.renameTo(trgFil);
+ }
+ // else copy fil and delete
+ else {
+ if (!srcFil.exists() && !args.MissingFails()) return;
+ CopyFil(args);
+ DeleteFil_lang(srcFil, srcUrl);
+ }
+ }
+ void Chk_TrgFil_Overwrite(boolean overwrite, Io_url trg) {
+ if (!overwrite)
+ throw Err_.invalid_op_("trgFile exists but overwriteFlag not set").Add("trg", trg.Xto_api());
+ }
+ @Override public void MoveDir(Io_url src, Io_url trg) {
+ String srcStr = src.Xto_api(), trgStr = trg.Xto_api();
+ File srcFil = new File(srcStr), trgFil = new File(trgStr);
+ if (trgFil.exists()) {throw Err_.invalid_op_("cannot move dir if trg exists").Add("src", src).Add("trg", trg);}
+ if (String_.Eq(src.OwnerRoot().Raw(), trg.OwnerRoot().Raw())) {
+ srcFil.renameTo(trgFil);
+ }
+ else {
+ XferDir(IoEngine_xrg_xferDir.copy_(src, trg));
+ }
+ }
+ protected static void Closeable_Close(Closeable closeable, Io_url url, boolean throwErr) {
+ if (closeable == null) return;
+ try {closeable.close();}
+ catch (IOException e) {
+ if (throwErr)
+ throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "close object failed").Add("class", ClassAdp_.NameOf_obj(closeable)).Add("url", url.Xto_api());
+// else
+// UsrDlg_._.Finally("failed to close FileChannel", "url", url, "apiErr", Err_.Message_err_arg(e));
+ }
+ }
+
+ File Fil_(Io_url url) {return new File(url.Xto_api());}
+ boolean Fil_Exists(File fil) {return fil.exists();}
+ boolean Fil_ReadOnly(File fil) {return !fil.canWrite();}
+ boolean Fil_Delete(File fil) {return fil.delete();}
+ void Fil_Writable(File fil) {
+ if (!Op_sys.Cur().Tid_is_drd())
+ IoEngine_system_xtn.SetWritable(fil, true);
+ }
+ Err Err_Text_UnsupportedEncoding(String encodingName, String text, Io_url url, Exception e) {
+ return Err_.err_key_(e, "gplx.texts.UnsupportedEncodingException", "text is in unsupported encoding").CallLevel_1_()
+ .Add("encodingName", encodingName)
+ .Add("text", text)
+ .Add("url", url.Xto_api())
+ ;
+ }
+ boolean user_agent_needs_resetting = true;
+ @Override public Io_stream_rdr DownloadFil_as_rdr(IoEngine_xrg_downloadFil xrg) {
+ Io_stream_rdr_http rdr = new Io_stream_rdr_http(xrg);
+ rdr.Open();
+ return rdr;
+ }
+ @Override public boolean DownloadFil(IoEngine_xrg_downloadFil xrg) {
+ IoStream trg_stream = null;
+ java.io.BufferedInputStream src_stream = null;
+ java.net.URL src_url = null;
+ HttpURLConnection src_conn = null;
+ if (user_agent_needs_resetting) {user_agent_needs_resetting = false; System.setProperty("http.agent", "");}
+ boolean exists = Io_mgr._.ExistsDir(xrg.Trg().OwnerDir());
+ Gfo_usr_dlg prog_dlg = null;
+ String src_str = xrg.Src();
+ Io_download_fmt xfer_fmt = xrg.Download_fmt();
+ prog_dlg = xfer_fmt.usr_dlg;
+ if (!Web_access_enabled) {
+ if (session_fil == null) session_fil = prog_dlg.Log_wtr().Session_dir().GenSubFil("internet.txt");
+ if (prog_dlg != null) prog_dlg.Log_wtr().Log_msg_to_url_fmt(session_fil, "download disabled: src='~{0}' trg='~{1}'", xrg.Src(), xrg.Trg().Raw());
+ return false;
+ }
+ try {
+ trg_stream = Io_mgr._.OpenStreamWrite(xrg.Trg());
+ src_url = new java.net.URL(src_str);
+ src_conn = (HttpURLConnection)src_url.openConnection();
+// src_conn.setReadTimeout(5000); // do not set; if file does not exist, will wait 5 seconds before timing out; want to fail immediately
+ String user_agent = xrg.User_agent(); if (user_agent != null) src_conn.setRequestProperty("User-Agent", user_agent);
+ long content_length = Long_.parse_or_(src_conn.getHeaderField("Content-Length"), IoItmFil.Size_Invalid_int);
+ xrg.Src_content_length_(content_length);
+ if (xrg.Src_last_modified_query()) // NOTE: only files will have last modified (api calls will not); if no last_modified, then src_conn will throw get nullRef; avoid nullRef
+ xrg.Src_last_modified_(DateAdp_.unixtime_lcl_ms_(src_conn.getLastModified()));
+ if (xrg.Exec_meta_only()) return true;
+ src_stream = new java.io.BufferedInputStream(src_conn.getInputStream());
+ if (!exists) {
+ Io_mgr._.CreateDir(xrg.Trg().OwnerDir()); // dir must exist for OpenStreamWrite; create dir at last possible moment in case stream does not exist.
+ }
+ byte[] download_bfr = new byte[Download_bfr_len]; // NOTE: download_bfr was originally member variable; DATE:2013-05-03
+ xfer_fmt.Bgn(content_length);
+ int count = 0;
+ while ((count = src_stream.read(download_bfr, 0, Download_bfr_len)) != -1) {
+ if (xrg.Prog_cancel()) {
+ src_stream.close();
+ trg_stream.Rls();
+ Io_mgr._.DeleteFil(xrg.Trg());
+ }
+ xfer_fmt.Prog(count);
+ trg_stream.Write(download_bfr, 0, count);
+ }
+ if (prog_dlg != null) {
+ xfer_fmt.Term();
+ if (session_fil == null) session_fil = prog_dlg.Log_wtr().Session_dir().GenSubFil("internet.txt");
+ prog_dlg.Log_wtr().Log_msg_to_url_fmt(session_fil, "download pass: src='~{0}' trg='~{1}'", src_str, xrg.Trg().Raw());
+ }
+ return true;
+ }
+ catch (Exception exc) {
+ xrg.Rslt_err_(exc);
+ if (ClassAdp_.Eq_typeSafe(exc, java.net.UnknownHostException.class)) xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_host_not_found);
+ else if (ClassAdp_.Eq_typeSafe(exc, java.io.FileNotFoundException.class)) xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_file_not_found);
+ else xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_unknown);
+ if (prog_dlg != null && !xrg.Prog_cancel()) {
+ if (session_fil == null) session_fil = prog_dlg.Log_wtr().Session_dir().GenSubFil("internet.txt");
+ prog_dlg.Log_wtr().Log_msg_to_url_fmt(session_fil, "download fail: src='~{0}' trg='~{1}' error='~{2}'", src_str, xrg.Trg().Raw(), Err_.Message_lang(exc));
+ }
+ if (trg_stream != null) {
+ try {
+ trg_stream.Rls();
+ DeleteFil_api(IoEngine_xrg_deleteFil.new_(xrg.Trg()));
+ }
+ catch (Exception e2) {Err_.Noop(e2);}
+ }
+ return false;
+ }
+ finally {
+ xrg.Prog_running_(false);
+ try {
+ if (src_stream != null) src_stream.close();
+ if (src_conn != null) src_conn.disconnect();
+ } catch (Exception exc) {
+ Err_.Noop(exc);
+ }
+ if (trg_stream != null) trg_stream.Rls();
+ }
+ } Io_url session_fil; Bry_bfr prog_fmt_bfr;
+ byte[] download_bfr; static final int Download_bfr_len = Io_mgr.Len_kb * 128;
+ public static Err Err_Fil_NotFound(Io_url url) {
+ return Err_.new_key_(IoEngineArgs._.Err_FileNotFound, "file not found").Add("url", url.Xto_api()).CallLevel_1_();
+ }
+ public static Err Err_Fil_NotFound(Exception e, Io_url url) {
+ return Err_.err_(e, "file not found").Key_(IoEngineArgs._.Err_FileNotFound).Add("url", url.Xto_api()).CallLevel_1_();
+ }
+ void MarkFileWritable(File fil, Io_url url, boolean readOnlyFails, String op) {
+ if (Fil_ReadOnly(fil)) {
+ if (readOnlyFails) // NOTE: java will always allow final files to be deleted; programmer api is responsible for check
+ throw Err_.new_key_(IoEngineArgs._.Err_ReadonlyFileNotWritable, "writable operation attempted on readOnly file").Add("op", op).Add("url", url.Xto_api()).CallLevel_1_();
+ else
+ Fil_Writable(fil);
+ }
+ }
+ void DeleteFil_lang(File fil, Io_url url) {
+ boolean rv = Fil_Delete(fil);
+ if (!rv)
+ throw Err_.new_key_(IoEngineArgs._.Err_IoException, "file not deleted").Add("url", url.Xto_api());
+ }
+ IoEngineUtl utl = IoEngineUtl.new_();
+ public static IoEngine_system new_() {return new IoEngine_system();} IoEngine_system() {}
+ static final String GRP_KEY = "Io_engine";
+ public static boolean Web_access_enabled = true;
+}
+class IoEngineArgs {
+ public int LoadFilStr_BufferSize = 4096 * 256;
+ public String LoadFilStr_Encoding = "UTF-8";
+ public String Err_ReadonlyFileNotWritable = "gplx.ios.ReadonlyFileNotWritable";
+ public String Err_FileNotFound = "gplx.ios.FileNotFound";
+ public String Err_IoException = "gplx.ios.IoException";
+ public static final IoEngineArgs _ = new IoEngineArgs();
+}
+class IoEngine_system_xtn {
+ // PATCH.DROID:VerifyError if file.setExecutable is referenced directly in IoEngine_system. However, if placed in separate class
+ public static void SetExecutable(java.io.File file, boolean v) {file.setExecutable(v);}
+ public static void SetWritable(java.io.File file, boolean v) {file.setWritable(v);}
+}
+class Io_download_http {
+ public static boolean User_agent_reset_needed = true;
+ public static void User_agent_reset() {
+ User_agent_reset_needed = false;
+ System.setProperty("http.agent", ""); // need to set http.agent to '' in order for "User-agent" to take effect
+ }
+ public static void Save_to_fsys(IoEngine_xrg_downloadFil xrg) {
+ Io_stream_rdr_http rdr = new Io_stream_rdr_http(xrg);
+ IoStream trg_stream = null;
+ try {
+ boolean exists = Io_mgr._.ExistsDir(xrg.Trg().OwnerDir());
+ if (!exists)
+ Io_mgr._.CreateDir(xrg.Trg().OwnerDir()); // dir must exist for OpenStreamWrite; create dir at last possible moment in case stream does not exist.
+ trg_stream = Io_mgr._.OpenStreamWrite(xrg.Trg());
+ byte[] bfr = new byte[Download_bfr_len];
+ rdr.Open();
+ while (rdr.Read(bfr, 0, Download_bfr_len) != Read_done) {
+ }
+ }
+ finally {
+ rdr.Rls();
+ if (trg_stream != null) trg_stream.Rls();
+ }
+ if (xrg.Rslt() != IoEngine_xrg_downloadFil.Rslt_pass)
+ Io_mgr._.DeleteFil_args(xrg.Trg()).MissingFails_off().Exec();
+ }
+ public static final int Read_done = -1;
+ public static final int Download_bfr_len = Io_mgr.Len_kb * 128;
+}
+class Io_stream_rdr_http implements Io_stream_rdr {
+ public Io_stream_rdr_http(IoEngine_xrg_downloadFil xrg) {
+ this.xrg = xrg;
+ } private IoEngine_xrg_downloadFil xrg;
+ public byte Tid() {return Io_stream_.Tid_file;}
+ public Io_url Url() {return url;} public Io_stream_rdr Url_(Io_url v) {url = v; return this;} private Io_url url;
+ public long Len() {return len;} public Io_stream_rdr Len_(long v) {len = v; return this;} private long len = IoItmFil.Size_Invalid; // NOTE: must default size to -1; DATE:2014-06-21
+ private String src_str; private HttpURLConnection src_conn; private java.io.BufferedInputStream src_stream;
+ private Io_download_fmt xfer_fmt; private Gfo_usr_dlg prog_dlg;
+ private boolean read_done = true, read_failed = false;
+ public Io_stream_rdr Open() {
+ if (Io_download_http.User_agent_reset_needed) Io_download_http.User_agent_reset();
+ if (!IoEngine_system.Web_access_enabled) {
+ read_done = read_failed = true;
+ if (prog_dlg != null)
+ prog_dlg.Log_wtr().Log_msg_to_url_fmt(session_fil, "download disabled: src='~{0}' trg='~{1}'", xrg.Src(), xrg.Trg().Raw());
+ return this;
+ }
+ src_str = xrg.Src();
+ xfer_fmt = xrg.Download_fmt(); prog_dlg = xfer_fmt.usr_dlg;
+ try {
+ src_conn = (HttpURLConnection)new java.net.URL(src_str).openConnection();
+ String user_agent = xrg.User_agent();
+ if (user_agent != null)
+ src_conn.setRequestProperty("User-Agent", user_agent);
+// src_conn.setReadTimeout(5000); // do not set; if file does not exist, will wait 5 seconds before timing out; want to fail immediately
+ long content_length = Long_.parse_or_(src_conn.getHeaderField("Content-Length"), IoItmFil.Size_Invalid_int);
+ xrg.Src_content_length_(content_length);
+ this.len = content_length;
+ if (xrg.Src_last_modified_query()) // NOTE: only files will have last modified (api calls will not); if no last_modified, then src_conn will throw get nullRef; avoid nullRef
+ xrg.Src_last_modified_(DateAdp_.unixtime_lcl_ms_(src_conn.getLastModified()));
+ if (xrg.Exec_meta_only()) {
+ read_done = true;
+ return this;
+ }
+ read_done = false;
+ src_stream = new java.io.BufferedInputStream(src_conn.getInputStream());
+ xfer_fmt.Bgn(content_length);
+ }
+ catch (Exception e) {Err_handle(e);}
+ return this;
+ }
+ public void Open_mem(byte[] v) {}
+ public Object Under() {return src_stream;}
+ public int Read(byte[] bry, int bgn, int len) {
+ if (read_done) return Io_download_http.Read_done;
+ if (xrg.Prog_cancel()) {read_failed = true; return Io_download_http.Read_done;}
+ try {
+ int read = src_stream.read(bry, bgn, len);
+ xfer_fmt.Prog(read);
+ return read;
+ }
+ catch (Exception e) {
+ Err_handle(e);
+ return Io_download_http.Read_done;
+ }
+ }
+ private Io_url session_fil = null;
+ private boolean rls_done = false;
+ public long Skip(long len) {return 0;}
+ public void Rls() {
+ if (rls_done) return;
+ try {
+ read_done = true;
+ if (prog_dlg != null) {
+ xfer_fmt.Term();
+ }
+ if (session_fil == null && prog_dlg != null) session_fil = prog_dlg.Log_wtr().Session_dir().GenSubFil("internet.txt");
+ if (read_failed) {
+ }
+ else {
+ prog_dlg.Log_wtr().Log_msg_to_url_fmt(session_fil, "download pass: src='~{0}' trg='~{1}'", src_str, xrg.Trg().Raw());
+ xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_pass);
+ }
+ xrg.Prog_running_(false);
+ }
+ catch (Exception e) {Err_.Noop(e);} // ignore close errors; also Err_handle calls Rls() so it would be circular
+ finally {
+ try {if (src_stream != null) src_stream.close();}
+ catch (Exception e) {Err_.Noop(e);} // ignore failures when cleaning up
+ if (src_conn != null) src_conn.disconnect();
+ src_stream = null;
+ src_conn = null;
+ rls_done = true;
+ }
+ }
+ private void Err_handle(Exception exc) {
+ read_done = read_failed = true;
+ len = -1;
+ xrg.Rslt_err_(exc);
+ if (ClassAdp_.Eq_typeSafe(exc, java.net.UnknownHostException.class)) xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_host_not_found);
+ else if (ClassAdp_.Eq_typeSafe(exc, java.io.FileNotFoundException.class)) xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_file_not_found);
+ else xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_unknown);
+ if (prog_dlg != null && !xrg.Prog_cancel()) {
+ if (session_fil == null) session_fil = prog_dlg.Log_wtr().Session_dir().GenSubFil("internet.txt");
+ prog_dlg.Log_wtr().Log_msg_to_url_fmt(session_fil, "download fail: src='~{0}' trg='~{1}' error='~{2}'", src_str, xrg.Trg().Raw(), Err_.Message_lang(exc));
+ }
+ this.Rls();
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteDir.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteDir.java
new file mode 100644
index 000000000..4a2cd381f
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteDir.java
@@ -0,0 +1,34 @@
+/*
+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.ios; import gplx.*;
+import gplx.criterias.*;
+public class IoEngine_xrg_deleteDir {
+ public Io_url Url() {return url;} public IoEngine_xrg_deleteDir Url_(Io_url val) {url = val; return this;} Io_url url;
+ public boolean Recur() {return recur;} public IoEngine_xrg_deleteDir Recur_() {return Recur_(true);} public IoEngine_xrg_deleteDir Recur_(boolean v) {recur = v; return this;} private boolean recur = false;
+ public boolean ReadOnlyFails() {return readOnlyFails;} public IoEngine_xrg_deleteDir ReadOnlyFails_off() {return ReadOnlyFails_(false);} public IoEngine_xrg_deleteDir ReadOnlyFails_(boolean v) {readOnlyFails = v; return this;} private boolean readOnlyFails = true;
+ public boolean MissingIgnored() {return missingIgnored;} public IoEngine_xrg_deleteDir MissingIgnored_() {return MissingIgnored_(true);} public IoEngine_xrg_deleteDir MissingIgnored_(boolean v) {missingIgnored = v; return this;} private boolean missingIgnored = true;
+ public Criteria MatchCrt() {return matchCrt;} public IoEngine_xrg_deleteDir MatchCrt_(Criteria v) {matchCrt = v; return this;} Criteria matchCrt = Criteria_.All;
+ public Criteria SubDirScanCrt() {return subDirScanCrt;} public IoEngine_xrg_deleteDir SubDirScanCrt_(Criteria v) {subDirScanCrt = v; return this;} Criteria subDirScanCrt = Criteria_.All;
+ public ConsoleDlg UsrDlg() {return usrDlg;} public IoEngine_xrg_deleteDir UsrDlg_(ConsoleDlg v) {usrDlg = v; return this;} ConsoleDlg usrDlg = ConsoleDlg_.Null;
+ public void Exec() {IoEnginePool._.Fetch(url.Info().EngineKey()).DeleteDirDeep(this);}
+ public static IoEngine_xrg_deleteDir new_(Io_url url) {
+ IoEngine_xrg_deleteDir rv = new IoEngine_xrg_deleteDir();
+ rv.url = url;
+ return rv;
+ } IoEngine_xrg_deleteDir() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteFil.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteFil.java
new file mode 100644
index 000000000..9358d3eb2
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteFil.java
@@ -0,0 +1,30 @@
+/*
+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.ios; import gplx.*;
+public class IoEngine_xrg_deleteFil extends IoEngine_xrg_fil_affects1_base {
+ @gplx.New public IoEngine_xrg_deleteFil Url_(Io_url val) {Url_set(val); return this;}
+ public IoEngine_xrg_deleteFil ReadOnlyFails_off() {return ReadOnlyFails_(false);} public IoEngine_xrg_deleteFil ReadOnlyFails_(boolean v) {ReadOnlyFails_set(v); return this;}
+ public IoEngine_xrg_deleteFil MissingFails_off() {return MissingFails_(false);} public IoEngine_xrg_deleteFil MissingFails_(boolean v) {MissingFails_set(v); return this;}
+ @Override public void Exec() {IoEnginePool._.Fetch(this.Url().Info().EngineKey()).DeleteFil_api(this);}
+ public static IoEngine_xrg_deleteFil proto_() {return new IoEngine_xrg_deleteFil();}
+ public static IoEngine_xrg_deleteFil new_(Io_url url) {
+ IoEngine_xrg_deleteFil rv = new IoEngine_xrg_deleteFil();
+ rv.Url_set(url);
+ return rv;
+ } IoEngine_xrg_deleteFil() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_downloadFil.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_downloadFil.java
new file mode 100644
index 000000000..d55cc1821
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_downloadFil.java
@@ -0,0 +1,66 @@
+/*
+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.ios; import gplx.*;
+public class IoEngine_xrg_downloadFil {
+ public String Src() {return src;} public IoEngine_xrg_downloadFil Src_(String v) {src = v; return this;} private String src;
+ public Io_url Trg() {return trg;} public IoEngine_xrg_downloadFil Trg_(Io_url v) {trg = v; return this;} Io_url trg;
+ public byte Rslt() {return rslt;} public IoEngine_xrg_downloadFil Rslt_(byte v) {rslt = v; return this;} private byte rslt = Rslt_pass;
+ public Exception Rslt_err() {return rslt_err;} public IoEngine_xrg_downloadFil Rslt_err_(Exception v) {rslt_err = v; return this;} Exception rslt_err;
+ public String User_agent() {return user_agent;} public IoEngine_xrg_downloadFil User_agent_(String v) {user_agent = v; return this;} private String user_agent;
+ public Gfo_usr_dlg Prog_dlg() {return prog_dlg;} public IoEngine_xrg_downloadFil Prog_dlg_(Gfo_usr_dlg v) {prog_dlg = v; download_fmt.Ctor(prog_dlg); return this;} Gfo_usr_dlg prog_dlg;
+ public Bry_fmtr Prog_fmtr() {return prog_fmtr;} Bry_fmtr prog_fmtr = Bry_fmtr.new_("~{download_header}: ~{download_read} of ~{download_length} kb;", "download_header", "download_url", "download_read", "download_length");
+ public String Prog_fmt_hdr() {return prog_fmt_hdr;} public IoEngine_xrg_downloadFil Prog_fmt_hdr_(String v) {prog_fmt_hdr = v; return this;} private String prog_fmt_hdr = ""; // NOTE: must init to "", else null ref when building String
+ public boolean Prog_cancel() {return prog_cancel;} public IoEngine_xrg_downloadFil Prog_cancel_y_() {prog_cancel = true; return this;} volatile boolean prog_cancel;
+ public boolean Prog_running() {return prog_running;} public IoEngine_xrg_downloadFil Prog_running_(boolean v) {prog_running = v; return this;} private boolean prog_running;
+ public long Src_content_length() {return src_content_length;} public IoEngine_xrg_downloadFil Src_content_length_(long v) {src_content_length = v; return this;} long src_content_length;
+ public DateAdp Src_last_modified() {return src_last_modified;} public IoEngine_xrg_downloadFil Src_last_modified_(DateAdp v) {src_last_modified = v; return this;} DateAdp src_last_modified;
+ public boolean Src_last_modified_query() {return src_last_modified_query;} public IoEngine_xrg_downloadFil Src_last_modified_query_(boolean v) {src_last_modified_query = v; return this;} private boolean src_last_modified_query;
+ public String Trg_engine_key() {return trg_engine_key;} public IoEngine_xrg_downloadFil Trg_engine_key_(String v) {trg_engine_key = v; return this;} private String trg_engine_key = IoEngine_.SysKey;
+ public Io_download_fmt Download_fmt() {return download_fmt;} Io_download_fmt download_fmt = new Io_download_fmt();
+ public boolean Exec() {return IoEnginePool._.Fetch(trg.Info().EngineKey()).DownloadFil(this);}
+ public Io_stream_rdr Exec_as_rdr() {return IoEnginePool._.Fetch(IoEngine_.SysKey).DownloadFil_as_rdr(this);}
+ public boolean Exec_meta_only() {return exec_meta_only;} private boolean exec_meta_only;
+ public byte[] Exec_as_bry(String src) {
+ this.Src_(src); this.Trg_(trg_mem);
+ download_fmt.Init(src, prog_fmt_hdr); // NOTE: must set src else NULL error
+ boolean pass = IoEnginePool._.Fetch(trg_engine_key).DownloadFil(this);
+ return pass ? Io_mgr._.LoadFilBry(trg_mem) : null;
+ } Io_url trg_mem = Io_url_.mem_fil_("mem/download.tmp");
+ public boolean Exec_meta(String src) {
+ this.Src_(src); this.Trg_(trg_mem); // NOTE: set Trg_ else error in download proc
+ download_fmt.Init(src, prog_fmt_hdr); // NOTE: must set src else NULL error
+ exec_meta_only = true;
+ boolean rv = IoEnginePool._.Fetch(trg_engine_key).DownloadFil(this);
+ exec_meta_only = false;
+ return rv;
+ }
+ public void Init(String src, Io_url trg) {
+ this.src = src; this.trg = trg;
+ prog_cancel = false;
+ rslt_err = null;
+ rslt = Rslt_pass;
+ prog_running = true;
+ download_fmt.Init(src, "downloading ~{src_name}: ~{prog_left} left (@ ~{prog_rate}); ~{prog_done} of ~{src_len} (~{prog_pct}%)");
+ }
+ public static IoEngine_xrg_downloadFil new_(String src, Io_url trg) {
+ IoEngine_xrg_downloadFil rv = new IoEngine_xrg_downloadFil();
+ rv.src = src; rv.trg = trg;
+ return rv;
+ } IoEngine_xrg_downloadFil() {}
+ public static final byte Rslt_pass = 0, Rslt_fail_host_not_found = 1, Rslt_fail_file_not_found = 2, Rslt_fail_unknown = 3;
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_fil_affects1_base.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_fil_affects1_base.java
new file mode 100644
index 000000000..0122b645c
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_fil_affects1_base.java
@@ -0,0 +1,25 @@
+/*
+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.ios; import gplx.*;
+public class IoEngine_xrg_fil_affects1_base {
+ public Io_url Url() {return url;} public void Url_set(Io_url v) {url = v;} Io_url url;
+ public IoEngine_xrg_fil_affects1_base Url_(Io_url v) {url = v; return this;}
+ public boolean MissingFails() {return missingFails;} public void MissingFails_set(boolean v) {missingFails = v;} private boolean missingFails = true;
+ public boolean ReadOnlyFails() {return readOnlyFails;} public void ReadOnlyFails_set(boolean v) {readOnlyFails = v;} private boolean readOnlyFails = true;
+ @gplx.Virtual public void Exec() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_loadFilStr.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_loadFilStr.java
new file mode 100644
index 000000000..37b1a57a8
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_loadFilStr.java
@@ -0,0 +1,44 @@
+/*
+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.ios; import gplx.*;
+import gplx.texts.*;
+public class IoEngine_xrg_loadFilStr {
+ public Io_url Url() {return url;} public IoEngine_xrg_loadFilStr Url_(Io_url val) {url = val; return this;} Io_url url;
+ public boolean MissingIgnored() {return missingIgnored;} public IoEngine_xrg_loadFilStr MissingIgnored_() {return MissingIgnored_(true);} public IoEngine_xrg_loadFilStr MissingIgnored_(boolean v) {missingIgnored = v; return this;} private boolean missingIgnored = false;
+ public boolean BomUtf8Convert() {return bomUtf8Convert;} public IoEngine_xrg_loadFilStr BomUtf8Convert_(boolean v) {bomUtf8Convert = v; return this;} private boolean bomUtf8Convert = true;
+ public String Exec() {
+ String s = IoEnginePool._.Fetch(url.Info().EngineKey()).LoadFilStr(this);
+ if (bomUtf8Convert && String_.Len(s) > 0 && String_.CodePointAt(s, 0) == Bom_Utf8) {
+ s = String_.Mid(s, 1);
+ UsrDlg_._.Warn(UsrMsg.new_("UTF8 BOM removed").Add("url", url.Xto_api()));
+ }
+ return s;
+ }
+ public String[] ExecAsStrAry() {return String_.Split(Exec(), String_.CrLf);}
+ public String[] ExecAsStrAryLnx() {
+ String raw = Exec();
+ if (String_.Len(raw) == 0) return String_.Ary_empty;
+ return String_.Split(raw, Op_sys.Dir_spr_char_lnx, false);
+ }
+ int Bom_Utf8 = 65279; // U+FEFF; see http://en.wikipedia.org/wiki/Byte_order_mark
+ public static IoEngine_xrg_loadFilStr new_(Io_url url) {
+ IoEngine_xrg_loadFilStr rv = new IoEngine_xrg_loadFilStr();
+ rv.url = url;
+ return rv;
+ } IoEngine_xrg_loadFilStr() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_openRead.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_openRead.java
new file mode 100644
index 000000000..9ceadffca
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_openRead.java
@@ -0,0 +1,35 @@
+/*
+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.ios; import gplx.*;
+public class IoEngine_xrg_openRead {
+ public Io_url Url() {return url;} Io_url url;
+ public String ErrMsg() {return errMsg;} private String errMsg;
+ public IoStream ExecAsIoStreamOrFail() {return IoEnginePool._.Fetch(url.Info().EngineKey()).OpenStreamRead(url);}
+ public IoStream ExecAsIoStreamOrNull() {
+ try {return IoEnginePool._.Fetch(url.Info().EngineKey()).OpenStreamRead(url);}
+ catch (Exception exc) {
+ errMsg = Err_.Message_lang(exc);
+ return IoStream_.Null;
+ }
+ }
+ public static IoEngine_xrg_openRead new_(Io_url url) {
+ IoEngine_xrg_openRead rv = new IoEngine_xrg_openRead();
+ rv.url = url;
+ return rv;
+ } IoEngine_xrg_openRead() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_openWrite.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_openWrite.java
new file mode 100644
index 000000000..3240012a7
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_openWrite.java
@@ -0,0 +1,31 @@
+/*
+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.ios; import gplx.*;
+public class IoEngine_xrg_openWrite {
+ public Io_url Url() {return url;} public IoEngine_xrg_openWrite Url_(Io_url val) {url = val; return this;} Io_url url;
+ public boolean ReadOnlyIgnored() {return readOnlyIgnored;} public IoEngine_xrg_openWrite ReadOnlyIgnored_() {return ReadOnlyIgnored_(true);} public IoEngine_xrg_openWrite ReadOnlyIgnored_(boolean v) {readOnlyIgnored = v; return this;} private boolean readOnlyIgnored = false;
+ public boolean MissingIgnored() {return missingIgnored;} public IoEngine_xrg_openWrite MissingIgnored_() {return MissingIgnored_(true);} public IoEngine_xrg_openWrite MissingIgnored_(boolean v) {missingIgnored = v; return this;} private boolean missingIgnored = false;
+ public byte Mode() {return mode;} public IoEngine_xrg_openWrite Mode_(byte v) {mode = v; return this;} private byte mode = IoStream_.Mode_wtr_create;
+ public IoEngine_xrg_openWrite Mode_update_() {return Mode_(IoStream_.Mode_wtr_update);}
+ public IoStream Exec() {return IoEnginePool._.Fetch(url.Info().EngineKey()).OpenStreamWrite(this);}
+ public static IoEngine_xrg_openWrite new_(Io_url url) {
+ IoEngine_xrg_openWrite rv = new IoEngine_xrg_openWrite();
+ rv.url = url;
+ return rv;
+ } IoEngine_xrg_openWrite() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_queryDir.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_queryDir.java
new file mode 100644
index 000000000..b3e7357c4
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_queryDir.java
@@ -0,0 +1,55 @@
+/*
+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.ios; import gplx.*;
+import gplx.criterias.*;
+public class IoEngine_xrg_queryDir {
+ public Io_url Url() {return url;} public IoEngine_xrg_queryDir Url_(Io_url val) {url = val; return this;} Io_url url;
+ public boolean Recur() {return recur;} public IoEngine_xrg_queryDir Recur_() {return Recur_(true);} public IoEngine_xrg_queryDir Recur_(boolean val) {recur = val; return this;} private boolean recur = false;
+ public boolean DirInclude() {return dirInclude;} public IoEngine_xrg_queryDir DirInclude_() {return DirInclude_(true);} public IoEngine_xrg_queryDir DirInclude_(boolean val) {dirInclude = val; return this;} private boolean dirInclude = false;
+ public Criteria FilCrt() {return filCrt;} public IoEngine_xrg_queryDir FilCrt_(Criteria val) {filCrt = val; return this;} Criteria filCrt;
+ public Criteria DirCrt() {return dirCrt;} public IoEngine_xrg_queryDir DirCrt_(Criteria val) {dirCrt = val; return this;} Criteria dirCrt;
+ public Criteria SubDirScanCrt() {return subDirScanCrt;} public IoEngine_xrg_queryDir SubDirScanCrt_(Criteria val) {subDirScanCrt = val; return this;} Criteria subDirScanCrt;
+ public IoEngine_xrg_queryDir DirOnly_() {
+ DirInclude_(true);
+ filCrt = Criteria_.None;
+ return this;
+ }
+
+ public ConsoleDlg UsrDlg() {return usrDlg;} public IoEngine_xrg_queryDir UsrDlg_(ConsoleDlg val) {usrDlg = val; return this;} ConsoleDlg usrDlg = ConsoleDlg_.Null;
+ public IoEngine_xrg_queryDir FilPath_(String val) {
+ Criteria_ioMatch crt = Criteria_ioMatch.parse_(true, val, url.Info().CaseSensitive());
+ filCrt = Criteria_wrapper.new_(IoItm_base_.Prop_Path, crt);
+ return this;
+ }
+ public IoItmDir ExecAsDir() {return IoEnginePool._.Fetch(url.Info().EngineKey()).QueryDirDeep(this);}
+ public Io_url[] ExecAsUrlAry() {return ExecAsItmHash().XtoIoUrlAry();}
+ public IoItmHash ExecAsItmHash() {
+ Criteria crt = dirInclude ? Criteria_.All : Criteria_wrapper.new_(IoItm_base_.Prop_Type, Criteria_.eq_(IoItmFil.Type_Fil));
+ IoItmHash list = ExecAsDir().XtoIoItmList(crt);
+ list.SortBy(IoItmBase_comparer_nest._);
+ return list;
+ }
+ public static IoEngine_xrg_queryDir new_(Io_url url) {
+ IoEngine_xrg_queryDir rv = new IoEngine_xrg_queryDir();
+ rv.url = url;
+ rv.filCrt = Criteria_wrapper.new_(IoItm_base_.Prop_Path, Criteria_.All);
+ rv.dirCrt = Criteria_wrapper.new_(IoItm_base_.Prop_Path, Criteria_.All);
+ rv.subDirScanCrt = Criteria_wrapper.new_(IoItm_base_.Prop_Path, Criteria_.All);
+ return rv;
+ } IoEngine_xrg_queryDir() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_recycleFil.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_recycleFil.java
new file mode 100644
index 000000000..c63601983
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_recycleFil.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.ios; import gplx.*;
+public class IoEngine_xrg_recycleFil extends IoEngine_xrg_fil_affects1_base {
+ public IoEngine_xrg_recycleFil MissingFails_off() {return MissingFails_(false);} public IoEngine_xrg_recycleFil MissingFails_(boolean v) {MissingFails_set(v); return this;}
+
+ public int Mode() {return mode;} public IoEngine_xrg_recycleFil Mode_(int v) {mode = v; return this;} int mode;
+ public String AppName() {return appName;} public IoEngine_xrg_recycleFil AppName_(String val) {appName = val; return this;} private String appName = "unknown_app";
+ public UuidAdp Uuid() {return uuid;} public IoEngine_xrg_recycleFil Uuid_(UuidAdp val) {uuid = val; return this;} UuidAdp uuid;
+ public boolean Uuid_include() {return uuid_include;} public IoEngine_xrg_recycleFil Uuid_include_() {uuid_include = true; return this;} private boolean uuid_include;
+ public DateAdp Time() {return time;} public IoEngine_xrg_recycleFil Time_(DateAdp val) {time = val; return this;} DateAdp time;
+ public ListAdp RootDirNames() {return rootDirNames;} public IoEngine_xrg_recycleFil RootDirNames_(ListAdp val) {rootDirNames = val; return this;} ListAdp rootDirNames;
+ public Io_url RecycleUrl() {
+ String dayName = time.XtoStr_fmt("yyyyMMdd"), timeName = time.XtoStr_fmt("hhmmssfff");
+ String rootDirStr = ConcatWith_ary(this.Url().Info().DirSpr(), rootDirNames);
+ Io_url recycleDir = this.Url().OwnerRoot().GenSubDir_nest(rootDirStr, dayName);
+ String uuidStr = uuid_include ? uuid.XtoStr() : "";
+ return recycleDir.GenSubFil_ary(appName, ";", timeName, ";", uuidStr, ";", String_.LimitToFirst(this.Url().NameAndExt(), 128));
+ }
+ String ConcatWith_ary(String separator, ListAdp ary) {
+ String_bldr sb = String_bldr_.new_();
+ int aryLen = ary.Count();
+ for (int i = 0; i < aryLen; i++) {
+ if (i != 0) sb.Add(separator);
+ Object val = ary.FetchAt(i);
+ sb.Add_obj(Object_.XtoStr_OrEmpty(val));
+ }
+ return sb.XtoStr();
+ }
+ @Override public void Exec() {
+ IoEnginePool._.Fetch(this.Url().Info().EngineKey()).RecycleFil(this);
+ }
+ public IoEngine_xrg_recycleFil(int v) {
+ mode = v;
+ time = DateAdp_.Now();
+ uuid = UuidAdp_.random_();
+ rootDirNames = ListAdp_.new_(); rootDirNames.Add("z_trash");
+ }
+ public static IoEngine_xrg_recycleFil sysm_(Io_url url) {return new IoEngine_xrg_recycleFil(SysmConst);}
+ public static IoEngine_xrg_recycleFil gplx_(Io_url url) {IoEngine_xrg_recycleFil rv = new IoEngine_xrg_recycleFil(GplxConst); rv.Url_set(url); return rv;}
+ public static IoEngine_xrg_recycleFil proto_() {return gplx_(Io_url_.Null);}
+ public static final int GplxConst = 0, SysmConst = 1;
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_saveFilStr.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_saveFilStr.java
new file mode 100644
index 000000000..178c722b6
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_saveFilStr.java
@@ -0,0 +1,33 @@
+/*
+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.ios; import gplx.*;
+import gplx.texts.*;
+public class IoEngine_xrg_saveFilStr {
+ public Io_url Url() {return url;} public IoEngine_xrg_saveFilStr Url_(Io_url val) {url = val; return this;} Io_url url;
+ public String Text() {return text;} public IoEngine_xrg_saveFilStr Text_(String val) {text = val; return this;} private String text = "";
+ public boolean Append() {return append;} public IoEngine_xrg_saveFilStr Append_() {return Append_(true);} public IoEngine_xrg_saveFilStr Append_(boolean val) {append = val; return this;} private boolean append = false;
+ public void Exec() {
+ if (String_.Eq(text, "") && append) return; // no change; don't bother writing to disc
+ IoEnginePool._.Fetch(url.Info().EngineKey()).SaveFilText_api(this);
+ }
+ public static IoEngine_xrg_saveFilStr new_(Io_url url, String text) {
+ IoEngine_xrg_saveFilStr rv = new IoEngine_xrg_saveFilStr();
+ rv.url = url; rv.text = text;
+ return rv;
+ } IoEngine_xrg_saveFilStr() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferDir.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferDir.java
new file mode 100644
index 000000000..26df8d6dd
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferDir.java
@@ -0,0 +1,37 @@
+/*
+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.ios; import gplx.*;
+import gplx.criterias.*;
+public class IoEngine_xrg_xferDir {
+ public boolean Type_move() {return move;} public boolean Type_copy() {return !move;} private boolean move = false;
+ public Io_url Src() {return src;} public IoEngine_xrg_xferDir Src_(Io_url val) {src = val; return this;} Io_url src;
+ public Io_url Trg() {return trg;} public IoEngine_xrg_xferDir Trg_(Io_url val) {trg = val; return this;} Io_url trg;
+ public boolean Recur() {return recur;} public IoEngine_xrg_xferDir Recur_() {recur = true; return this;} private boolean recur = false;
+ public boolean Overwrite() {return overwrite;} public IoEngine_xrg_xferDir Overwrite_() {return Overwrite_(true);} public IoEngine_xrg_xferDir Overwrite_(boolean v) {overwrite = v; return this;} private boolean overwrite = false;
+ public boolean ReadOnlyFails() {return readOnlyFails;} public IoEngine_xrg_xferDir ReadOnlyFails_() {return ReadOnlyFails_(true);} public IoEngine_xrg_xferDir ReadOnlyFails_(boolean v) {readOnlyFails = v; return this;} private boolean readOnlyFails = false;
+ public Criteria MatchCrt() {return matchCrt;} public IoEngine_xrg_xferDir MatchCrt_(Criteria v) {matchCrt = v; return this;} Criteria matchCrt = Criteria_.All;
+ public Criteria SubDirScanCrt() {return subDirScanCrt;} public IoEngine_xrg_xferDir SubDirScanCrt_(Criteria v) {subDirScanCrt = v; return this;} Criteria subDirScanCrt = Criteria_.All;
+ public void Exec() {IoEnginePool._.Fetch(src.Info().EngineKey()).XferDir(this);}
+ public static IoEngine_xrg_xferDir move_(Io_url src, Io_url trg) {return new_(src, trg, true);}
+ public static IoEngine_xrg_xferDir copy_(Io_url src, Io_url trg) {return new_(src, trg, false);}
+ static IoEngine_xrg_xferDir new_(Io_url src, Io_url trg, boolean move) {
+ IoEngine_xrg_xferDir rv = new IoEngine_xrg_xferDir();
+ rv.src = src; rv.trg = trg; rv.move = move;
+ return rv;
+ } IoEngine_xrg_xferDir() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferFil.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferFil.java
new file mode 100644
index 000000000..54e7f5c11
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferFil.java
@@ -0,0 +1,34 @@
+/*
+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.ios; import gplx.*;
+public class IoEngine_xrg_xferFil {
+ public boolean Type_move() {return move;} private boolean move = false;
+ public Io_url Src() {return src;} Io_url src;
+ public Io_url Trg() {return trg;} Io_url trg;
+ public boolean Overwrite() {return overwrite;} public IoEngine_xrg_xferFil Overwrite_() {return Overwrite_(true);} public IoEngine_xrg_xferFil Overwrite_(boolean v) {overwrite = v; return this;} private boolean overwrite = false;
+ public boolean ReadOnlyFails() {return readOnlyFails;} public IoEngine_xrg_xferFil ReadOnlyFails_off() {return ReadOnlyFails_(false);} public IoEngine_xrg_xferFil ReadOnlyFails_(boolean v) {readOnlyFails = v; return this;} private boolean readOnlyFails = true;
+ public boolean MissingFails() {return missingFails;} public IoEngine_xrg_xferFil MissingFails_off() {return MissingFails_(false);} public IoEngine_xrg_xferFil MissingFails_(boolean v) {missingFails = v; return this;} private boolean missingFails = true;
+ public void Exec() {IoEnginePool._.Fetch(src.Info().EngineKey()).XferFil(this);}
+ public static IoEngine_xrg_xferFil move_(Io_url src, Io_url trg) {return new_(src, trg, true);}
+ public static IoEngine_xrg_xferFil copy_(Io_url src, Io_url trg) {return new_(src, trg, false);}
+ static IoEngine_xrg_xferFil new_(Io_url src, Io_url trg, boolean move) {
+ IoEngine_xrg_xferFil rv = new IoEngine_xrg_xferFil();
+ rv.src = src; rv.trg = trg; rv.move = move;
+ return rv;
+ } IoEngine_xrg_xferFil() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoErr.java b/100_core/src_200_io/gplx/ios/IoErr.java
new file mode 100644
index 000000000..25310d0db
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoErr.java
@@ -0,0 +1,30 @@
+/*
+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.ios; import gplx.*;
+public class IoErr {
+ public static String Namespace = "gplx.ios.";
+ public static String FileIsReadOnly_key = Namespace + "FileIsReadOnlyError";
+ public static String FileNotFound_key = Namespace + "FileNotFoundError";
+ public static Err FileIsReadOnly(Io_url url) {
+ return Err_.new_key_(FileIsReadOnly_key, "file is read-only").Add("url", url.Xto_api()).CallLevel_1_();
+ }
+ public static Err FileNotFound(String op, Io_url url) {
+ // file is missing -- op='copy' file='C:\a.txt' copyFile_target='D:\a.txt'
+ return Err_.new_key_(FileNotFound_key, "file not found").Add("op", op).Add("file", url.Xto_api());
+ }
+}
\ No newline at end of file
diff --git a/100_core/src_200_io/gplx/ios/IoItmAttrib.java b/100_core/src_200_io/gplx/ios/IoItmAttrib.java
new file mode 100644
index 000000000..1772e57d0
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItmAttrib.java
@@ -0,0 +1,25 @@
+/*
+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.ios; import gplx.*;
+public class IoItmAttrib {
+ public boolean ReadOnly() {return readOnly;} public IoItmAttrib ReadOnly_() {return ReadOnly_(true);} public IoItmAttrib ReadOnly_(boolean val) {readOnly = val; return this;} private boolean readOnly;
+ public boolean Hidden() {return hidden;} public IoItmAttrib Hidden_() {return Hidden_(true);} public IoItmAttrib Hidden_(boolean val) {hidden = val; return this;} private boolean hidden;
+ public static IoItmAttrib readOnly_() {return new IoItmAttrib().ReadOnly_();}
+ public static IoItmAttrib hidden_() {return new IoItmAttrib().Hidden_();}
+ public static IoItmAttrib normal_() {return new IoItmAttrib().ReadOnly_(false).Hidden_(false);}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoItmClassXtn.java b/100_core/src_200_io/gplx/ios/IoItmClassXtn.java
new file mode 100644
index 000000000..7db2abfbf
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItmClassXtn.java
@@ -0,0 +1,32 @@
+/*
+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.ios; import gplx.*;
+public class IoItmClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "ioItemType";
+ @Override public Class> UnderClass() {return int.class;}
+ public Object DefaultValue() {return IoItmDir.Type_Dir;}
+ public boolean Eq(Object lhs, Object rhs) {return ((IoItm_base)lhs).compareTo(rhs) == CompareAble_.Same;}
+ @Override public Object ParseOrNull(String raw) {
+ String rawLower = String_.Lower(raw);
+ if (String_.Eq(rawLower, "dir")) return IoItmDir.Type_Dir;
+ else if (String_.Eq(rawLower, "fil")) return IoItmFil.Type_Fil;
+ else throw Err_.unhandled(raw);
+ }
+ @Override public Object XtoDb(Object obj) {return Int_.cast_(obj);}
+ public static final IoItmClassXtn _ = new IoItmClassXtn(); IoItmClassXtn() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoItmDir.java b/100_core/src_200_io/gplx/ios/IoItmDir.java
new file mode 100644
index 000000000..e76c6c92a
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItmDir.java
@@ -0,0 +1,71 @@
+/*
+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.ios; import gplx.*;
+import gplx.criterias.*;
+public class IoItmDir extends IoItm_base {
+ public boolean Exists() {return exists;} public void Exists_set(boolean v) {exists = v;} private boolean exists = true;
+ @Override public int TypeId() {return Type_Dir;} @Override public boolean Type_dir() {return true;} @Override public boolean Type_fil() {return false;} public static final int Type_Dir = 1;
+ @gplx.New public IoItmDir XtnProps_set(String key, Object val) {return (IoItmDir)super.XtnProps_set(key, val);}
+ public IoItmList SubDirs() {return subDirs;} IoItmList subDirs;
+ public IoItmList SubFils() {return subFils;} IoItmList subFils;
+ public IoItmHash XtoIoItmList(Criteria crt) {
+ IoItmHash rv = IoItmHash.list_(this.Url());
+ XtoItmList_recur(rv, this, crt);
+ return rv;
+ }
+ Io_url[] XtoIoUrlAry() {
+ IoItmHash list = this.XtoIoItmList(Criteria_.All);
+//#plat_wce list.Sort(); // NOTE: on wce, subFils retrieved in unexpected order; createTime vs pathString
+ int count = list.Count();
+ Io_url[] rv = new Io_url[count];
+ for (int i = 0; i < count; i++)
+ rv[i] = list.FetchAt(i).Url();
+ return rv;
+ }
+ public IoItmDir FetchDeepOrNull(Io_url findDirUrl) {
+ String dirSpr = this.Url().Info().DirSpr(); int dirSprLen = String_.Len(dirSpr);
+ String currDirStr = this.Url().Raw();
+ String findDirStr = findDirUrl.Raw();
+ if (!String_.HasAtBgn(findDirStr, currDirStr)) return null; // findUrl must start with currUrl;
+ String findName = String_.DelEnd(currDirStr, dirSprLen); // seed findName for String_.MidByLen below;
+ IoItmDir curDir = this;
+ while (true) {
+ findDirStr = String_.DelBgn(findDirStr, String_.Len(findName) + dirSprLen); // NOTE: findName will never have trailingDirSpr; subDirs.Fetch() takes NameOnly; ex: "dir" not "dir\"
+ int nextDirSprPos = String_.FindFwd(findDirStr, dirSpr); if (nextDirSprPos == String_.Find_none) nextDirSprPos = String_.Len(findDirStr);
+ findName = String_.MidByLen(findDirStr, 0, nextDirSprPos);
+ if (String_.Eq(findDirStr, "")) return curDir; // findDirStr completely removed; all parts match; return curDir
+ curDir = IoItmDir_.as_(curDir.subDirs.Fetch(findName)); // try to find dir
+ if (curDir == null) return null; // dir not found; exit; NOTE: if dir found, loop restarts; with curDir as either findDir, or owner of findDir
+ }
+ }
+ void XtoItmList_recur(IoItmHash list, IoItmDir curDir, Criteria dirCrt) {
+ for (Object subFilObj : curDir.SubFils()) {
+ IoItmFil subFil = (IoItmFil)subFilObj;
+ list.Add(subFil);
+ }
+ for (Object subDirObj : curDir.SubDirs()) {
+ IoItmDir subDir = (IoItmDir)subDirObj;
+ if (dirCrt.Matches(subDir)) list.Add(subDir);
+ XtoItmList_recur(list, subDir, dirCrt);
+ }
+ }
+ @gplx.Internal protected IoItmDir(boolean caseSensitive) {
+ subDirs = IoItmList.new_(this, caseSensitive);
+ subFils = IoItmList.new_(this, caseSensitive);
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/IoItmDir_.java b/100_core/src_200_io/gplx/ios/IoItmDir_.java
new file mode 100644
index 000000000..f9d0b25d3
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItmDir_.java
@@ -0,0 +1,34 @@
+/*
+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.ios; import gplx.*;
+public class IoItmDir_ {
+ public static IoItmDir as_(Object obj) {return obj instanceof IoItmDir ? (IoItmDir)obj : null;}
+ public static final IoItmDir Null = null_();
+ public static IoItmDir top_(Io_url url) {return scan_(url);}
+ public static IoItmDir scan_(Io_url url) {
+ IoItmDir rv = new IoItmDir(url.Info().CaseSensitive());
+ rv.ctor_IoItmBase_url(url);
+ return rv;
+ }
+ static IoItmDir null_() {
+ IoItmDir rv = new IoItmDir(true); // TODO: NULL should be removed
+ rv.ctor_IoItmBase_url(Io_url_.Null);
+ rv.Exists_set(false);
+ return rv;
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/IoItmFil.java b/100_core/src_200_io/gplx/ios/IoItmFil.java
new file mode 100644
index 000000000..38069bbcb
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItmFil.java
@@ -0,0 +1,42 @@
+/*
+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.ios; import gplx.*;
+public class IoItmFil extends IoItm_base {
+ @Override public int TypeId() {return IoItmFil.Type_Fil;} @Override public boolean Type_dir() {return false;} @Override public boolean Type_fil() {return true;} public static final int Type_Fil = 2;
+ public boolean Exists() {return size != Size_Invalid;} // NOTE: questionable logic, but preserved for historical reasons; requires that length be set to -1 if !.exists
+ public DateAdp ModifiedTime() {return modifiedTime;}
+ public IoItmFil ModifiedTime_(DateAdp val) {modifiedTime = val; return this;} DateAdp modifiedTime;
+ public IoItmFil ModifiedTime_(String val) {return ModifiedTime_(DateAdp_.parse_gplx(val));}
+ @gplx.Virtual public long Size() {return size;} public IoItmFil Size_(long val) {size = val; return this;} long size;
+ public IoItmAttrib Attrib() {return attrib;} public IoItmFil Attrib_(IoItmAttrib val) {attrib = val; return this;} IoItmAttrib attrib = IoItmAttrib.normal_();
+ public boolean ReadOnly() {return attrib.ReadOnly();} public IoItmFil ReadOnly_(boolean val) {attrib.ReadOnly_(val); return this;}
+ @gplx.New public IoItmFil XtnProps_set(String key, Object val) {return (IoItmFil)super.XtnProps_set(key, val);}
+
+ @gplx.Internal protected IoItmFil ctor_IoItmFil(Io_url url, long size, DateAdp modifiedTime) {
+ ctor_IoItmBase_url(url); this.size = size; this.modifiedTime = modifiedTime;
+ return this;
+ }
+ @Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, IoItmFil_.Prop_Size)) return size;
+ else if (ctx.Match(k, IoItmFil_.Prop_Modified)) return modifiedTime;
+ else return super.Invk(ctx, ikey, k, m);
+ }
+ @gplx.Internal protected IoItmFil() {}
+ public static final long Size_Invalid = -1;
+ public static final int Size_Invalid_int = -1;
+}
diff --git a/100_core/src_200_io/gplx/ios/IoItmFil_.java b/100_core/src_200_io/gplx/ios/IoItmFil_.java
new file mode 100644
index 000000000..22085ead9
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItmFil_.java
@@ -0,0 +1,25 @@
+/*
+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.ios; import gplx.*;
+public class IoItmFil_ {
+ public static IoItmFil as_(Object obj) {return obj instanceof IoItmFil ? (IoItmFil)obj : null;}
+ public static final String
+ Prop_Size = "size"
+ , Prop_Modified = "modified";
+ public static IoItmFil new_(Io_url url, long size, DateAdp created, DateAdp modified) {return new IoItmFil().ctor_IoItmFil(url, size, modified);}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoItmFil_mem.java b/100_core/src_200_io/gplx/ios/IoItmFil_mem.java
new file mode 100644
index 000000000..57f3423a6
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItmFil_mem.java
@@ -0,0 +1,39 @@
+/*
+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.ios; import gplx.*;
+import gplx.ios.*; /*IoStream_mem*/ import gplx.texts.*; /*Encoding_*/
+class IoItmFil_mem extends IoItmFil { public static IoItmFil_mem as_(Object obj) {return obj instanceof IoItmFil_mem ? (IoItmFil_mem)obj : null;}
+ @gplx.Internal protected IoStream_mem Stream() {return stream;} IoStream_mem stream; // NOTE: using stream instead of Text, b/c no events for IoStream.Dispose; ex: stream.OpenStreamWrite; stream.Write("hi"); stream.Dispose(); "hi" would not be saved if Text is member variable
+ @Override public long Size() {return (int)stream.Len();}
+ public String Text() {return Text_get();} public void Text_set(String v) {stream = IoStream_mem.rdr_txt_(this.Url(), v);}
+ String Text_get() {
+ int len = (int)stream.Len();
+ byte[] buffer = new byte[len];
+ stream.Position_set(0);
+ stream.Read(buffer, 0, len);
+ return String_.new_utf8_(buffer);
+ }
+ public IoItmFil_mem Clone() {return new_(this.Url(), this.Size(), this.ModifiedTime(), this.Text());}
+ public static IoItmFil_mem new_(Io_url filPath, long size, DateAdp modified, String text) {
+ IoItmFil_mem rv = new IoItmFil_mem();
+ rv.ctor_IoItmFil(filPath, size, modified);
+ rv.stream = IoStream_mem.rdr_txt_(filPath, text);
+ return rv;
+ }
+ public static final IoItmFil_mem Null = new_(Io_url_.Null, 0, DateAdp_.MinValue, "");
+}
diff --git a/100_core/src_200_io/gplx/ios/IoItmHash.java b/100_core/src_200_io/gplx/ios/IoItmHash.java
new file mode 100644
index 000000000..e254fb520
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItmHash.java
@@ -0,0 +1,43 @@
+/*
+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.ios; import gplx.*;
+public class IoItmHash extends OrderedHash_base {
+ public Io_url Url() {return url;} Io_url url;
+ public void Add(IoItm_base itm) {Add_base(MakeKey(itm.Url()), itm);}
+ public void Del(Io_url url) {Del(MakeKey(url));}
+ public IoItm_base Fetch(Io_url url) {return IoItm_base_.as_(Fetch_base(MakeKey(url)));}
+ @gplx.New public IoItm_base FetchAt(int i) {return IoItm_base_.as_(FetchAt_base(i));}
+ public Io_url[] XtoIoUrlAry() {
+ int count = this.Count();
+ Io_url[] rv = new Io_url[count];
+ for (int i = 0; i < count; i++)
+ rv[i] = this.FetchAt(i).Url();
+ return rv;
+ }
+ String MakeKey(Io_url url) {return url.XtoCaseNormalized();}
+ public static IoItmHash new_() {
+ IoItmHash rv = new IoItmHash();
+ rv.url = null;//Io_url_.Null;
+ return rv;
+ } IoItmHash() {}
+ public static IoItmHash list_(Io_url url) {
+ IoItmHash rv = new IoItmHash();
+ rv.url = url;
+ return rv;
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/IoItmList.java b/100_core/src_200_io/gplx/ios/IoItmList.java
new file mode 100644
index 000000000..1c001ca43
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItmList.java
@@ -0,0 +1,76 @@
+/*
+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.ios; import gplx.*;
+import gplx.lists.*; /*OrderedHash_base*/
+public class IoItmList extends OrderedHash_base {
+ public boolean Has(Io_url url) {return Has_base(MakeKey(url));}
+ public void Add(IoItm_base itm) {
+ if (ownerDir != null) itm.OwnerDir_set(ownerDir);
+ Add_base(MakeKey(itm.Url()), itm);
+ }
+ public void Del(Io_url url) {
+ String key = MakeKey(url);
+ IoItm_base itm = IoItm_base_.as_(Fetch_base(key)); if (itm == null) return;
+ itm.OwnerDir_set(null);
+ super.Del(key);
+ }
+ public Io_url[] XtoIoUrlAry() {
+ int count = this.Count();
+ Io_url[] rv = new Io_url[count];
+ for (int i = 0; i < count; i++)
+ rv[i] = IoItm_base_.as_(i).Url();
+ return rv;
+ }
+ @Override public void Sort() {SortBy(IoItmBase_comparer_nest._);}
+ @Override protected Object Fetch_base(Object keyObj) {
+ String key = MakeKey((String)keyObj);
+ return super.Fetch_base(key);
+ }
+ @Override public void Del(Object keyObj) {
+ String key = MakeKey((String)keyObj);
+ super.Del(key);
+ }
+ String MakeKey(Io_url url) {
+ String itmName = url.Type_dir() ? url.NameOnly() : url.NameAndExt();
+ return MakeKey(itmName);
+ }
+ String MakeKey(String s) {
+ return caseSensitive ? s : String_.Lower(s);
+ }
+ IoItmDir ownerDir; boolean caseSensitive;
+ @gplx.Internal protected static IoItmList new_(IoItmDir v, boolean caseSensitive) {
+ IoItmList rv = new IoItmList();
+ rv.ownerDir = v; rv.caseSensitive = caseSensitive;
+ return rv;
+ }
+ @gplx.Internal protected static IoItmList list_(boolean caseSensitive) {return new_(null, caseSensitive);}
+}
+class IoItmBase_comparer_nest implements ComparerAble {
+ public int compare(Object lhsObj, Object rhsObj) {
+ IoItm_base lhsItm = (IoItm_base)lhsObj, rhsItm = (IoItm_base)rhsObj;
+ Io_url lhsUrl = lhsItm.Url(), rhsUrl = rhsItm.Url();
+ return String_.Eq(lhsUrl.OwnerDir().Raw(), rhsUrl.OwnerDir().Raw()) // is same dir
+ ? CompareAble_.Compare_obj(lhsUrl.NameAndExt(), rhsUrl.NameAndExt()) // same dir: compare name
+ : CompareAble_.Compare_obj(DepthOf(lhsItm), DepthOf(rhsItm)); // diff dir: compare by depth; ex: c:\fil.txt < c:\dir\fil.txt
+ }
+ int DepthOf(IoItm_base itm) {
+ Io_url url = itm.Url();
+ return String_.Count(url.OwnerDir().Raw(), url.Info().DirSpr()); // use OwnerDir, else dir.Raw will return extra dirSeparator
+ }
+ public static final IoItmBase_comparer_nest _ = new IoItmBase_comparer_nest(); IoItmBase_comparer_nest() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoItm_base.java b/100_core/src_200_io/gplx/ios/IoItm_base.java
new file mode 100644
index 000000000..4f9897758
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItm_base.java
@@ -0,0 +1,54 @@
+/*
+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.ios; import gplx.*;
+public abstract class IoItm_base implements GfoInvkAble, CompareAble {
+ public abstract int TypeId(); public abstract boolean Type_dir(); public abstract boolean Type_fil();
+ public Io_url Url() {return ownerDir == null ? url : ownerDir.Url().GenSubFil(name); /*NOTE: must call .Url*/} Io_url url;
+ public IoItmDir OwnerDir() {return ownerDir;} IoItmDir ownerDir;
+ public void OwnerDir_set(IoItmDir v) {if (v == this) throw Err_.new_("dir cannot be its own owner").Add("url", v.url.Raw());
+ url = v == null && ownerDir != null
+ ? ownerDir.url.GenSubFil(name) // create url, since ownerDir will soon be null; NOTE: must call .url
+ : Io_url_.Null; // delete url, since ownerDir will be avail
+ ownerDir = v;
+ }
+ public String Name() {return name;} private String name;
+ public IoItm_base Name_(String v) {
+ name = v;
+ if (ownerDir == null) url = url.OwnerDir().GenSubFil(name);
+ return this;
+ }
+ public Object XtnProps_get(String key) {return props.Fetch(key);} HashAdp props = HashAdp_.Null;
+ public IoItm_base XtnProps_set(String key, Object val) {
+ if (props == HashAdp_.Null) props = HashAdp_.new_();
+ props.Del(key);
+ props.Add(key, val);
+ return this;
+ }
+ public int compareTo(Object comp) {return url.compareTo(((IoItm_base)comp).url);} // NOTE: needed for comic importer (sort done on IoItmHash which contains IoItm_base)
+// public Object Data_get(String name) {return GfoInvkAble_.InvkCmd(this, name);}
+ @gplx.Virtual public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, IoItm_base_.Prop_Type)) return this.TypeId();
+ else if (ctx.Match(k, IoItm_base_.Prop_Path)) return this.Url();
+ else if (ctx.Match(k, IoItm_base_.Prop_Title)) return this.Url().NameOnly(); // needed for gfio script criteria;
+ else if (ctx.Match(k, IoItm_base_.Prop_Ext)) return this.Url().Ext(); // needed for gfio script criteria; EX: where "ext LIKE '.java'"
+ else return GfoInvkAble_.Rv_unhandled;
+ }
+ @gplx.Internal protected void ctor_IoItmBase_url(Io_url url) {this.url = url; this.name = url.NameAndExt();}
+ @gplx.Internal protected void ctor_IoItmBase_name(String name) {this.name = name;}
+}
+
diff --git a/100_core/src_200_io/gplx/ios/IoItm_base_.java b/100_core/src_200_io/gplx/ios/IoItm_base_.java
new file mode 100644
index 000000000..39d34b5ce
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoItm_base_.java
@@ -0,0 +1,26 @@
+/*
+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.ios; import gplx.*;
+public class IoItm_base_ {
+ public static IoItm_base as_(Object obj) {return obj instanceof IoItm_base ? (IoItm_base)obj : null;}
+ public static final String
+ Prop_Type = "type"
+ , Prop_Path = "url"
+ , Prop_Title = "title"
+ , Prop_Ext = "ext";
+}
diff --git a/100_core/src_200_io/gplx/ios/IoRecycleBin.java b/100_core/src_200_io/gplx/ios/IoRecycleBin.java
new file mode 100644
index 000000000..1a3601919
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoRecycleBin.java
@@ -0,0 +1,59 @@
+/*
+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.ios; import gplx.*;
+public class IoRecycleBin {
+ public void Send(Io_url url) {Send_xrg(url).Exec();}
+ public IoEngine_xrg_recycleFil Send_xrg(Io_url url) {return IoEngine_xrg_recycleFil.gplx_(url);}
+ public void Recover(Io_url url) {
+ String_bldr sb = String_bldr_.new_();
+ ListAdp list = Regy_search(url, sb);
+ int listCount = list.Count(); if (listCount > 1) throw Err_.new_("found more than 1 url").Add("count", list.Count());
+ Io_url trgUrl = (Io_url)list.FetchAt(0);
+ IoEngine_xrg_xferFil.move_(url, trgUrl).ReadOnlyFails_(true).Overwrite_(false).Exec();
+ IoEngine_xrg_saveFilStr.new_(FetchRegistryUrl(url), sb.XtoStr()).Exec();
+ }
+ public void Regy_add(IoEngine_xrg_recycleFil xrg) {
+ Io_url url = xrg.RecycleUrl();
+ Io_url regyUrl = FetchRegistryUrl(url);
+ String text = String_.ConcatWith_any("|", url.NameAndExt_noDirSpr(), xrg.Url().GenRelUrl_orEmpty(url.OwnerRoot()), xrg.Uuid().XtoStr(), xrg.AppName(), xrg.Time());
+ IoEngine_xrg_saveFilStr.new_(regyUrl, text).Append_().Exec();
+ }
+ public ListAdp Regy_search(Io_url url, String_bldr sb) {
+ ListAdp list = ListAdp_.new_();
+ Io_url regyUrl = FetchRegistryUrl(url);
+ String[] lines = IoEngine_xrg_loadFilStr.new_(regyUrl).ExecAsStrAry();
+ int linesLen = Array_.Len(lines);
+ String nameAndExt = url.NameAndExt_noDirSpr() + "|";
+ for (int i = linesLen; i > 0; i--) {
+ String line = lines[i - 1];
+ if (String_.HasAtBgn(line, nameAndExt)) {
+ String[] terms = String_.Split(line, "|");
+ Io_url origUrl = url.OwnerRoot().GenSubFil(terms[1]);
+ list.Add(origUrl);
+ }
+ else
+ sb.Add_str_w_crlf(line);
+ }
+ return list;
+ }
+ Io_url FetchRegistryUrl(Io_url url) {
+ String sourceApp = String_.GetStrBefore(url.NameAndExt_noDirSpr(), ";");
+ return url.OwnerDir().GenSubFil_ary(sourceApp, ".recycle.csv");
+ }
+ public static final IoRecycleBin _ = new IoRecycleBin(); IoRecycleBin() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoStream.java b/100_core/src_200_io/gplx/ios/IoStream.java
new file mode 100644
index 000000000..2cae01fb2
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoStream.java
@@ -0,0 +1,33 @@
+/*
+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.ios; import gplx.*;
+public interface IoStream extends RlsAble {
+ Object UnderRdr();
+ Io_url Url();
+ long Pos();
+ long Len();
+
+ int ReadAry(byte[] array);
+ int Read(byte[] array, int offset, int count);
+ long Seek(long pos);
+ void WriteAry(byte[] ary);
+ void Write(byte[] array, int offset, int count);
+ void Transfer(IoStream trg, int bufferLength);
+ void Flush();
+ void Write_and_flush(byte[] bry, int bgn, int end);
+}
\ No newline at end of file
diff --git a/100_core/src_200_io/gplx/ios/IoStream_.java b/100_core/src_200_io/gplx/ios/IoStream_.java
new file mode 100644
index 000000000..570fd6491
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoStream_.java
@@ -0,0 +1,180 @@
+/*
+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.ios; import gplx.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+public class IoStream_ {
+ public static final IoStream Null = new IoStream_null();
+ public static IoStream mem_txt_(Io_url url, String v) {return IoStream_mem.rdr_txt_(url, v);}
+ public static IoStream ary_(byte[] v) {return IoStream_mem.rdr_ary_(Io_url_.Null, v);}
+ public static final byte Mode_rdr = 0, Mode_wtr_create = 1, Mode_wtr_append = 2, Mode_wtr_update = 3;
+ public static IoStream stream_rdr_() {return new IoStream_stream_rdr();}
+ public static IoStream stream_input_(Io_url url) {return new IoStream_stream_rdr().UnderRdr_(input_stream_(url));}
+ public static Object input_stream_(Io_url url) {
+ try {
+ return new java.io.FileInputStream(url.Raw());
+ } catch (Exception e) {throw Err_.new_fmt_("file not found: {0}", url.Raw());}
+ }
+}
+class IoStream_null implements IoStream {
+ public Object UnderRdr() {return null;}
+ public Io_url Url() {return Io_url_.Null;}
+ public long Pos() {return -1;}
+ public long Len() {return -1;}
+ public int ReadAry(byte[] array) {return -1;}
+ public int Read(byte[] array, int offset, int count) {return -1;}
+ public long Seek(long pos) {return -1;}
+ public void WriteAry(byte[] ary) {}
+ public void Write(byte[] array, int offset, int count) {}
+ public void Transfer(IoStream trg, int bufferLength) {}
+ public void Flush() {}
+ public void Write_and_flush(byte[] bry, int bgn, int end) {}
+ public void Rls() {}
+}
+class IoStream_base implements IoStream {
+ @gplx.Virtual public Io_url Url() {return url;} Io_url url = Io_url_.Null;
+ public void Transfer(IoStream trg, int bufferLength) {
+ byte[] buffer = new byte[bufferLength];
+ int read = -1;
+ while (read != 0) {
+ read = this.Read(buffer, 0, bufferLength);
+ trg.Write(buffer, 0, read);
+ }
+ trg.Flush();
+ }
+ public int ReadAry(byte[] ary) {return this.Read(ary, 0, ary.length);}
+ public void WriteAry(byte[] ary) {this.Write(ary, 0, ary.length);}
+ @gplx.Virtual public Object UnderRdr() {return under;}
+ @gplx.Virtual public void UnderRdr_(Object v) {this.under = (RandomAccessFile)v;}
+ @gplx.Virtual public long Pos() {return pos;} long pos;
+ @gplx.Virtual public long Len() {return length;} long length;
+ @gplx.Virtual public int Read(byte[] array, int offset, int count) {
+ try {
+ int rv = under.read(array, offset, count);
+ return rv == -1 ? 0 : rv; // NOTE: fis returns -1 if nothing read; .NET returned 0; Hash will fail if -1 returned (will try to create array of 0 length)
+ } // NOTE: fis keeps track of offset, only need to pass in array (20110606: this NOTE no longer seems to make sense; deprecate)
+ catch (IOException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "file read failed").Add("url", url);}
+ }
+ public long Seek(long seek_pos) {
+ try {
+ under.seek(seek_pos);
+ pos = under.getFilePointer();
+ return pos;
+ }
+ catch (IOException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "seek failed").Add("url", url);}
+ }
+ @gplx.Virtual public void Write(byte[] array, int offset, int count) {bfr.Add_mid(array, offset, offset + count); this.Flush();} Bry_bfr bfr = Bry_bfr.reset_(16);
+ public void Write_and_flush(byte[] bry, int bgn, int end) {
+// ConsoleAdp._.WriteLine(bry.length +" " + bgn + " " + end);
+ Flush();// flush anything already in buffer
+ int buffer_len = Io_mgr.Len_kb * 16;
+ byte[] buffer = new byte[buffer_len];
+ int buffer_bgn = bgn; boolean loop = true;
+ while (loop) {
+ int buffer_end = buffer_bgn + buffer_len;
+ if (buffer_end > end) {
+ buffer_end = end;
+ buffer_len = end - buffer_bgn;
+ loop = false;
+ }
+ for (int i = 0; i < buffer_len; i++)
+ buffer[i] = bry[i + buffer_bgn];
+ try {under.write(buffer, 0, buffer_len);}
+ catch (IOException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "write failed").Add("url", url);}
+ buffer_bgn = buffer_end;
+ }
+// this.Rls();
+// OutputStream output_stream = null;
+// try {
+// output_stream = new FileOutputStream(url.Xto_api());
+// bry = ByteAry_.Mid(bry, bgn, end);
+// output_stream.write(bry, 0, bry.length);
+// }
+// catch (IOException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "write failed").Add("url", url);}
+// finally {
+// if (output_stream != null) {
+// try {output_stream.close();}
+// catch (IOException ignore) {}
+// }
+// }
+ }
+ @gplx.Virtual public void Flush() {
+ try {
+ if (mode_is_append) under.seek(under.length());
+// else under.seek(0);
+ }
+ catch (IOException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "seek failed").Add("url", url);}
+ try {under.write(bfr.Bfr(), 0, bfr.Len());}
+ catch (IOException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "write failed").Add("url", url);}
+ bfr.Clear();
+ }
+ @gplx.Virtual public void Rls() {
+ IoEngine_system.Closeable_Close(under, url, true);
+ }
+ RandomAccessFile under; boolean mode_is_append; byte mode;
+ public static IoStream_base rdr_wrapper_() {return new IoStream_base();}
+ public static IoStream_base new_(Io_url url, int mode) {
+ IoStream_base rv = new IoStream_base();
+ rv.url = url;
+ rv.mode = (byte)mode;
+ File file = new File(url.Xto_api());
+ String ctor_mode = "";
+ switch (mode) { // mode; SEE:NOTE_1
+ case IoStream_.Mode_wtr_append:
+ rv.mode_is_append = mode == IoStream_.Mode_wtr_append;
+ ctor_mode = "rws";
+ break;
+ case IoStream_.Mode_wtr_create:
+ ctor_mode = "rws";
+ break;
+ case IoStream_.Mode_rdr:
+ ctor_mode = "r";
+ break;
+ }
+ try {rv.under = new RandomAccessFile(file, ctor_mode);}
+ catch (FileNotFoundException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "file open failed").Add("url", url);}
+ if (mode == IoStream_.Mode_wtr_create) {
+ try {rv.under.setLength(0);}
+ catch (IOException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "file truncate failed").Add("url", url);}
+ }
+ rv.length = file.length();
+ return rv;
+ }
+ public static IoStream_base new_(Object stream) {
+ IoStream_base rv = new IoStream_base();
+// rv.stream = (System.IO.Stream)stream;
+ rv.url = Io_url_.Null;
+ return rv;
+ }
+ }
+/*
+NOTE_1:stream mode
+my understanding of mode
+rw: read/write async?
+rws: read/write sync; write content + metadata changes
+rwd: read/write sync; write content
+*/
+//#}
\ No newline at end of file
diff --git a/100_core/src_200_io/gplx/ios/IoStream_mem.java b/100_core/src_200_io/gplx/ios/IoStream_mem.java
new file mode 100644
index 000000000..c1e90da4b
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoStream_mem.java
@@ -0,0 +1,70 @@
+/*
+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.ios; import gplx.*;
+import gplx.texts.*; /*Encoding_*/
+class IoStream_mem extends IoStream_base {
+ @Override public Io_url Url() {return url;} Io_url url;
+ @Override public Object UnderRdr() {throw Err_.not_implemented_();} // NOTE: should not use System.IO.MemoryStream, b/c resized data will not be captured in this instance's buffer
+ @Override public long Len() {return Array_.Len(buffer);}
+ public int Position() {return position;} public void Position_set(int v) {position = v;} int position;
+ public byte[] Buffer() {return buffer;} private byte[] buffer = new byte[0];
+
+ @Override public int Read(byte[] array, int offset, int count) {
+ int read = 0;
+ int len = Array_.Len(buffer);
+ for (int i = 0; i < count; i++) {
+ if (position + i >= len) break;
+ array[offset + i] = buffer[position + i];
+ read++;
+ }
+ position += read;
+ return read;
+ }
+ @Override public void Write(byte[] array, int offset, int count) {
+ // expand buffer if needed; necessary to emulate fileStream writing; ex: FileStream fs = new FileStream(); fs.Write(data); where data may be unknown length
+ int length = (int)position + count + -offset;
+ int bufLen = Array_.Len(buffer);
+ if (bufLen < length) buffer = Bry_.Resize_manual(buffer, length);
+ for (int i = 0; i < count; i++)
+ buffer[position + i] = array[offset + i];
+ position += count +-offset;
+ }
+ @Override public long Pos() {return position;}
+ @Override public long Seek(long pos) {
+ this.position = (int)pos;
+ return pos;
+ }
+
+ @Override public void Flush() {}
+ @Override public void Rls() {}
+
+ public static IoStream_mem rdr_txt_(Io_url url, String v) {return rdr_ary_(url, Bry_.new_utf8_(v));}
+ public static IoStream_mem rdr_ary_(Io_url url, byte[] v) {
+ IoStream_mem rv = new IoStream_mem();
+ rv.buffer = v;
+ rv.url = url;
+ return rv;
+ }
+ public static IoStream_mem wtr_data_(Io_url url, int length) {
+ IoStream_mem rv = new IoStream_mem();
+ rv.buffer = new byte[length];
+ rv.url = url;
+ return rv;
+ }
+ IoStream_mem() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoStream_mem_tst.java b/100_core/src_200_io/gplx/ios/IoStream_mem_tst.java
new file mode 100644
index 000000000..2ad610373
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoStream_mem_tst.java
@@ -0,0 +1,30 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*; //using System.IO; /*Stream*/
+public class IoStream_mem_tst {
+ @Test public void Write() { // confirm that changes written to Stream acquired via .AdpObj are written to IoStream_mem.Buffer
+ IoStream_mem stream = IoStream_mem.wtr_data_(Io_url_.Null, 0);
+ byte[] data = Bry_.ints_(1);
+ stream.Write(data, 0, Array_.Len(data));
+
+ Tfds.Eq(1L , stream.Len());
+ Tfds.Eq((byte)1 , stream.Buffer()[0]);
+ stream.Rls();
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/IoStream_mock.java b/100_core/src_200_io/gplx/ios/IoStream_mock.java
new file mode 100644
index 000000000..b13385451
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoStream_mock.java
@@ -0,0 +1,45 @@
+/*
+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.ios; import gplx.*;
+public class IoStream_mock implements IoStream {
+ public byte[] Data_bry() {return data_bry;} public IoStream_mock Data_bry_(byte[] v) {data_bry = v; data_bry_len = v.length; return this;} private byte[] data_bry; int data_bry_len;
+ public int Data_bry_pos() {return data_bry_pos;} int data_bry_pos;
+ public void Reset() {data_bry_pos = 0;}
+ public IoStream_mock Read_limit_(int v) {read_limit = v; return this;} int read_limit;
+ public int Read(byte[] bfr, int bfr_bgn, int bfr_len) {
+ int bytes_read = bfr_len;
+ if (bytes_read > read_limit) bytes_read = read_limit; // stream may limit maximum read; EX: bfr_len of 16k but only 2k will be filled
+ int bytes_left = data_bry_len - data_bry_pos;
+ if (bytes_read > bytes_left) bytes_read = bytes_left; // not enough bytes left in data_bry; bytes_read = whatever is left
+ Bry_.Copy_by_pos(data_bry, data_bry_pos, data_bry_pos + bytes_read, bfr, bfr_bgn);
+ data_bry_pos += bytes_read;
+ return bytes_read;
+ }
+ public Object UnderRdr() {return null;}
+ public Io_url Url() {return Io_url_.Null;}
+ public long Pos() {return -1;}
+ public long Len() {return -1;}
+ public int ReadAry(byte[] array) {return -1;}
+ public long Seek(long pos) {return -1;}
+ public void WriteAry(byte[] ary) {}
+ public void Write(byte[] array, int offset, int count) {}
+ public void Transfer(IoStream trg, int bufferLength) {}
+ public void Flush() {}
+ public void Write_and_flush(byte[] bry, int bgn, int end) {}
+ public void Rls() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoStream_mock_tst.java b/100_core/src_200_io/gplx/ios/IoStream_mock_tst.java
new file mode 100644
index 000000000..a3cc24136
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoStream_mock_tst.java
@@ -0,0 +1,48 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoStream_mock_tst {
+ @Before public void init() {fxt.Clear();} IoStream_mock_fxt fxt = new IoStream_mock_fxt();
+ @Test public void Basic() {
+ fxt.Init_src_str_("abcde").Init_trg_len_(5).Init_rdr_limit_(2).Init_read_len_(2);
+ fxt.Test_read("ab").Test_read("cd").Test_read("e");
+ }
+ @Test public void Read_limit() {
+ fxt.Init_src_str_("abcde").Init_trg_len_(5).Init_rdr_limit_(2).Init_read_len_(4);
+ fxt.Test_read("ab").Test_read("cd").Test_read("e");
+ }
+}
+class IoStream_mock_fxt {
+ public void Clear() {
+ if (rdr == null)
+ rdr = new IoStream_mock();
+ rdr.Reset();
+ trg_bgn = 0;
+ } IoStream_mock rdr; byte[] trg_bry;
+ public IoStream_mock_fxt Init_src_str_(String v) {rdr.Data_bry_(Bry_.new_ascii_(v)); return this;}
+ public IoStream_mock_fxt Init_trg_len_(int v) {trg_bry = new byte[v]; return this;}
+ public IoStream_mock_fxt Init_read_len_(int v) {read_len = v; return this;} int read_len;
+ public IoStream_mock_fxt Init_rdr_limit_(int v) {rdr.Read_limit_(v); return this;}
+ public IoStream_mock_fxt Test_read(String expd) {
+ int bytes_read = rdr.Read(trg_bry, trg_bgn, read_len);
+ Tfds.Eq(expd, String_.new_ascii_(trg_bry, trg_bgn, trg_bgn + bytes_read));
+ trg_bgn += bytes_read;
+ return this;
+ } int trg_bgn;
+}
diff --git a/100_core/src_200_io/gplx/ios/IoStream_stream_rdr.java b/100_core/src_200_io/gplx/ios/IoStream_stream_rdr.java
new file mode 100644
index 000000000..59d7895f1
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoStream_stream_rdr.java
@@ -0,0 +1,39 @@
+/*
+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.ios; import gplx.*;
+public class IoStream_stream_rdr implements IoStream {
+ public int Read(byte[] bfr, int bfr_bgn, int bfr_len) {
+ try {
+ return stream.read(bfr, bfr_bgn, bfr_len);
+ }
+ catch (Exception e) {throw Err_.err_(e, "failed to read from stream");}
+ }
+ public IoStream UnderRdr_(Object v) {this.stream = (java.io.InputStream)v; return this;} java.io.InputStream stream;
+ public Object UnderRdr() {return stream;}
+ public Io_url Url() {return Io_url_.Null;}
+ public long Pos() {return -1;}
+ public long Len() {return -1;}
+ public int ReadAry(byte[] array) {return -1;}
+ public long Seek(long pos) {return -1;}
+ public void WriteAry(byte[] ary) {}
+ public void Write(byte[] array, int offset, int count) {}
+ public void Transfer(IoStream trg, int bufferLength) {}
+ public void Flush() {}
+ public void Write_and_flush(byte[] bry, int bgn, int end) {}
+ public void Rls() {}
+}
diff --git a/100_core/src_200_io/gplx/ios/IoUrlInfo.java b/100_core/src_200_io/gplx/ios/IoUrlInfo.java
new file mode 100644
index 000000000..a2e229d73
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoUrlInfo.java
@@ -0,0 +1,244 @@
+/*
+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.ios; import gplx.*;
+public interface IoUrlInfo {
+ String Key();
+ byte DirSpr_byte();
+ String DirSpr();
+ boolean CaseSensitive();
+ String EngineKey();
+
+ boolean Match(String raw);
+ boolean IsDir(String raw);
+ String Xto_api(String raw);
+ String OwnerDir(String raw);
+ String OwnerRoot(String raw);
+ String NameAndExt(String raw);
+ String NameOnly(String raw);
+ String Ext(String raw);
+ String XtoRootName(String raw, int rawLen);
+}
+class IoUrlInfo_nil implements IoUrlInfo {
+ public String Key() {return KeyConst;} public static final String KeyConst = String_.Null_mark;
+ public String EngineKey() {return "<>";}
+ public String DirSpr() {return "<>";}
+ public byte DirSpr_byte() {return Byte_ascii.Slash;}
+ public String VolSpr() {return "<>";}
+ public boolean CaseSensitive() {return false;}
+ public boolean Match(String raw) {return false;}
+ public boolean IsDir(String raw) {return false;}
+ public String Xto_api(String raw) {return "";}
+ public String OwnerDir(String raw) {return IoUrlInfo_base.NullString;}
+ public String OwnerRoot(String raw) {return IoUrlInfo_base.NullString;}
+ public String NameAndExt(String raw) {return "";}
+ public String NameOnly(String raw) {return "";}
+ public String Ext(String raw) {return "";}
+ public String XtoRootName(String raw, int rawLen) {return "";}
+ public static final IoUrlInfo_nil _ = new IoUrlInfo_nil(); IoUrlInfo_nil() {}
+}
+abstract class IoUrlInfo_base implements IoUrlInfo {
+ @gplx.Internal protected static final int DirSprLen = 1;
+ @gplx.Internal protected static final String NullString = "", ExtSeparator = ".";
+ public abstract String Key();
+ public abstract byte DirSpr_byte();
+ public abstract String DirSpr();
+ public abstract boolean CaseSensitive();
+ public abstract boolean Match(String raw);
+ public abstract String EngineKey();
+ public boolean IsDir(String raw) {return String_.HasAtEnd(raw, DirSpr());}
+ public abstract String XtoRootName(String raw, int rawLen);
+ @gplx.Virtual public String Xto_api(String raw) {
+ return IsDir(raw)
+ ? String_.DelEnd(raw, IoUrlInfo_base.DirSprLen) // if Dir, remove trailing DirSpr, since most api will not expect it (ex: .Delete will malfunction)
+ : raw;
+ }
+ public String OwnerDir(String raw) {
+ int rawLen = String_.Len(raw);
+ int ownerDirSprPos = OwnerDirPos(raw, rawLen);
+ if (ownerDirSprPos <= OwnerDirPos_hasNoOwner) return IoUrlInfo_base.NullString; // no ownerDir found; return Null; only (a) NullUrls (b) RootUrls ("C:\") (c) relative ("fil.txt")
+ return String_.MidByLen(raw, 0, ownerDirSprPos + 1); // +1 to include backslash
+ }
+ @gplx.Virtual public String OwnerRoot(String raw) {
+ String temp = raw, rv = raw;
+ while (true) {
+ temp = OwnerDir(temp);
+ if (String_.Eq(temp, IoUrlInfo_base.NullString)) break;
+ rv = temp;
+ }
+ return rv;
+ }
+ public String NameAndExt(String raw) { // if Dir, will return \ as last char
+ int rawLen = String_.Len(raw);
+ int ownerDirSprPos = OwnerDirPos(raw, rawLen);
+ if (ownerDirSprPos == OwnerDirPos_isNull) return IoUrlInfo_base.NullString; // NullUrl and RootUrl return Null;
+ return ownerDirSprPos == OwnerDirPos_hasNoOwner || ownerDirSprPos == OwnerDirPos_isRoot
+ ? raw // no PathSeparator b/c (a) RootDir ("C:\"); (b) relative ("fil.txt")
+ : String_.DelBgn(raw, ownerDirSprPos + 1); // +1 to skip backslash
+ }
+ public String NameOnly(String raw) {
+ String nameAndExt = NameAndExt(raw);
+ if (IsDir(raw)) {
+ String rootName = XtoRootName(raw, String_.Len(raw)); // C:\ -> C; / -> root
+ return rootName == null
+ ? String_.DelEnd(nameAndExt, IoUrlInfo_base.DirSprLen)
+ : rootName;
+ }
+ int pos = String_.FindBwd(nameAndExt, IoUrlInfo_base.ExtSeparator);
+ return pos == String_.Find_none
+ ? nameAndExt // Ext not found; return entire NameAndExt
+ : String_.MidByLen(nameAndExt, 0, pos);
+ }
+ public String Ext(String raw) { // if Dir, return DirSpr; if Fil, return . as first char; ex: .txt; .png
+ if (IsDir(raw)) return this.DirSpr();
+ String nameAndExt = NameAndExt(raw);
+ int pos = String_.FindBwd(nameAndExt, IoUrlInfo_base.ExtSeparator);
+ return pos == String_.Find_none ? "" : String_.DelBgn(nameAndExt, pos);
+ }
+ int OwnerDirPos(String raw, int rawLen) {
+ if (rawLen == 0) return OwnerDirPos_isNull;
+ else if (XtoRootName(raw, rawLen) != null) return OwnerDirPos_isRoot;
+ else {// NullUrls and RootUrls have no owners
+ int posAdj = IsDir(raw) ? IoUrlInfo_base.DirSprLen : 0; // Dir ends with DirSpr, adjust lastIndex by DirSprLen
+ return String_.FindBwd(raw, this.DirSpr(), rawLen - 1 - posAdj); // -1 to adjust for LastIdx
+ }
+ }
+ static final int
+ OwnerDirPos_hasNoOwner = -1 // ListAdp_.NotFound
+ , OwnerDirPos_isNull = -2
+ , OwnerDirPos_isRoot = -3;
+}
+class IoUrlInfo_wnt extends IoUrlInfo_base {
+ @Override public String Key() {return "wnt";}
+ @Override public String EngineKey() {return IoEngine_.SysKey;}
+ @Override public String DirSpr() {return Op_sys.Wnt.Fsys_dir_spr_str();}
+ @Override public byte DirSpr_byte() {return Byte_ascii.Backslash;}
+ @Override public boolean CaseSensitive() {return Op_sys.Wnt.Fsys_case_match();}
+ @Override public boolean Match(String raw) {return String_.Len(raw) > 1 && String_.CharAt(raw, 1) == ':';} // 2nd char is :; assumes 1 letter drives
+ @Override public String XtoRootName(String raw, int rawLen) {
+ return rawLen == 3 && String_.CharAt(raw, 1) == ':' // only allow single letter drives; ex: C:\; note, CharAt(raw, 1) to match Match
+ ? Char_.XtoStr(String_.CharAt(raw, 0))
+ : null;
+ }
+ public static final IoUrlInfo_wnt _ = new IoUrlInfo_wnt(); IoUrlInfo_wnt() {}
+}
+class IoUrlInfo_lnx extends IoUrlInfo_base {
+ @Override public String Key() {return "lnx";}
+ @Override public String EngineKey() {return IoEngine_.SysKey;}
+ @Override public String DirSpr() {return DirSprStr;} static final String DirSprStr = Op_sys.Lnx.Fsys_dir_spr_str();
+ @Override public byte DirSpr_byte() {return Byte_ascii.Slash;}
+ @Override public boolean CaseSensitive() {return Op_sys.Lnx.Fsys_case_match();}
+ @Override public boolean Match(String raw) {return String_.HasAtBgn(raw, DirSprStr);} // anything that starts with /
+ @Override public String XtoRootName(String raw, int rawLen) {
+ return rawLen == 1 && String_.Eq(raw, DirSprStr)
+ ? "root"
+ : null;
+ }
+ @Override public String OwnerRoot(String raw) {return DirSprStr;} // drive is always /
+ @Override public String Xto_api(String raw) {
+ return String_.Eq(raw, DirSprStr) // is root
+ ? DirSprStr
+ : super.Xto_api(raw); // NOTE: super.Xto_api will strip off last /
+ }
+ public static final IoUrlInfo_lnx _ = new IoUrlInfo_lnx(); IoUrlInfo_lnx() {}
+}
+class IoUrlInfo_rel extends IoUrlInfo_base {
+ @Override public String Key() {return "rel";}
+ @Override public String EngineKey() {return IoEngine_.SysKey;}
+ @Override public String DirSpr() {return info.DirSpr();}
+ @Override public byte DirSpr_byte() {return info.DirSpr_byte();}
+ @Override public boolean CaseSensitive() {return info.CaseSensitive();}
+ @Override public String XtoRootName(String raw, int rawLen) {return info.XtoRootName(raw, rawLen);}
+ @Override public boolean Match(String raw) {return true;} // relPath is always lastResort; return true
+ IoUrlInfo info;
+ public static IoUrlInfo_rel new_(IoUrlInfo info) {
+ IoUrlInfo_rel rv = new IoUrlInfo_rel();
+ rv.info = info;
+ return rv;
+ } IoUrlInfo_rel() {}
+}
+class IoUrlInfo_mem extends IoUrlInfo_base {
+ @Override public String Key() {return key;} private String key;
+ @Override public String EngineKey() {return engineKey;} private String engineKey;
+ @Override public String DirSpr() {return "/";}
+ @Override public byte DirSpr_byte() {return Byte_ascii.Slash;}
+ @Override public boolean CaseSensitive() {return false;}
+ @Override public String XtoRootName(String raw, int rawLen) {
+ return String_.Eq(raw, key) ? String_.DelEnd(key, 1) : null;
+ }
+ @Override public boolean Match(String raw) {return String_.HasAtBgn(raw, key);}
+ public static IoUrlInfo_mem new_(String key, String engineKey) {
+ IoUrlInfo_mem rv = new IoUrlInfo_mem();
+ rv.key = key; rv.engineKey = engineKey;
+ return rv;
+ } IoUrlInfo_mem() {}
+}
+class IoUrlInfo_alias extends IoUrlInfo_base {
+ @Override public String Key() {return srcDir;}
+ @Override public String EngineKey() {return engineKey;} private String engineKey;
+ @Override public String DirSpr() {return srcDirSpr;}
+ @Override public byte DirSpr_byte() {return srcDirSpr_byte;} private byte srcDirSpr_byte;
+ @Override public boolean CaseSensitive() {return false;}
+ @Override public String XtoRootName(String raw, int rawLen) {
+ return String_.Eq(raw, srcRootDir) ? srcRootName : null;
+ }
+ @Override public boolean Match(String raw) {return String_.HasAtBgn(raw, srcDir);}
+ @Override public String Xto_api(String raw) {
+ String rv = String_.Replace(raw, srcDir, trgDir); // replace src with trg
+ if (!String_.Eq(srcDirSpr, trgDirSpr)) rv = String_.Replace(rv, srcDirSpr, trgDirSpr); // replace dirSprs
+ return IsDir(raw)
+ ? String_.DelEnd(rv, IoUrlInfo_base.DirSprLen) // remove trailingSeparator, else Directory.Delete will not work properly
+ : rv;
+ }
+ void SrcDir_set(String v) {
+ srcDir = v;
+ boolean lnx = DirSpr_lnx(v);
+ if (srcDirSpr == null) {
+ if (lnx) {
+ srcDirSpr = Op_sys.Lnx.Fsys_dir_spr_str();
+ srcDirSpr_byte = Op_sys.Lnx.Fsys_dir_spr_byte();
+ }
+ else {
+ srcDirSpr = Op_sys.Wnt.Fsys_dir_spr_str();
+ srcDirSpr_byte = Op_sys.Wnt.Fsys_dir_spr_byte();
+ }
+ }
+ if (srcRootName == null) srcRootName = lnx ? "root" : String_.Mid(srcDir, 0, String_.FindFwd(srcDir, ":"));
+ if (srcRootDir == null) srcRootDir = lnx ? "/" : srcDir;
+ }
+ void TrgDir_set(String v) {
+ trgDir = v;
+ boolean lnx = DirSpr_lnx(v);
+ if (trgDirSpr == null) trgDirSpr = lnx ? Op_sys.Lnx.Fsys_dir_spr_str() : Op_sys.Wnt.Fsys_dir_spr_str();
+ }
+ boolean DirSpr_lnx(String s) {return String_.Has(s, Op_sys.Lnx.Fsys_dir_spr_str());}
+ void EngineKey_set(String v) {engineKey = v;}
+ String srcDir, trgDir, srcDirSpr, trgDirSpr, srcRootDir, srcRootName;
+ public static IoUrlInfo_alias new_(String srcDir, String trgDir, String engineKey) {
+ IoUrlInfo_alias rv = new IoUrlInfo_alias();
+ rv.SrcDir_set(srcDir);
+ rv.TrgDir_set(trgDir);
+ rv.EngineKey_set(engineKey);
+ return rv;
+ }
+ public static final IoUrlInfo_alias KEYS = new IoUrlInfo_alias();
+ public final String
+ Data_EngineKey = "engineKey"
+ , Data_SrcDir = "srcDir"
+ , Data_TrgDir = "trgDir"
+ ;
+}
diff --git a/100_core/src_200_io/gplx/ios/IoUrlInfoRegy.java b/100_core/src_200_io/gplx/ios/IoUrlInfoRegy.java
new file mode 100644
index 000000000..f82ce7e12
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoUrlInfoRegy.java
@@ -0,0 +1,52 @@
+/*
+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.ios; import gplx.*;
+public class IoUrlInfoRegy implements GfoInvkAble {
+ public void Reg(IoUrlInfo info) {hash.AddReplace(info.Key(), info);}
+ public IoUrlInfo Match(String raw) {
+ if (String_.Len(raw) == 0) return IoUrlInfo_.Nil;
+ for (int i = hash.Count(); i > 0; i--) {
+ IoUrlInfo info = (IoUrlInfo)hash.FetchAt(i - 1);
+ if (info.Match(raw)) return info;
+ }
+ throw Err_.new_("could not match ioPathInfo").Add("raw", raw).Add("count", hash.Count());
+ }
+ public void Reset() {
+ hash.Clear();
+ Reg(IoUrlInfo_rel.new_(Op_sys.Cur().Tid_is_wnt() ? (IoUrlInfo)IoUrlInfo_wnt._ : (IoUrlInfo)IoUrlInfo_lnx._));
+ Reg(IoUrlInfo_.Mem);
+ Reg(IoUrlInfo_lnx._);
+ Reg(IoUrlInfo_wnt._);
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk_Add)) {
+ String srcDirStr = m.ReadStr("srcDir");
+ String trgDirStr = m.ReadStr("trgDir");
+ String engineKey = m.ReadStrOr("engineKey", IoEngine_.SysKey);
+ if (ctx.Deny()) return this;
+ IoUrlInfo_alias alias = IoUrlInfo_alias.new_(srcDirStr, trgDirStr, engineKey);
+ IoUrlInfoRegy._.Reg(alias);
+ }
+ return this;
+ } public static final String Invk_Add = "Add";
+ OrderedHash hash = OrderedHash_.new_();
+ public static final IoUrlInfoRegy _ = new IoUrlInfoRegy();
+ IoUrlInfoRegy() {
+ this.Reset();
+ }
+}
\ No newline at end of file
diff --git a/100_core/src_200_io/gplx/ios/IoUrlInfo_.java b/100_core/src_200_io/gplx/ios/IoUrlInfo_.java
new file mode 100644
index 000000000..897e320fa
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoUrlInfo_.java
@@ -0,0 +1,34 @@
+/*
+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.ios; import gplx.*;
+public class IoUrlInfo_ {
+ public static final IoUrlInfo Nil = IoUrlInfo_nil._;
+ public static final IoUrlInfo Wnt = IoUrlInfo_wnt._;
+ public static final IoUrlInfo Lnx = IoUrlInfo_lnx._;
+ public static final IoUrlInfo Mem = IoUrlInfo_mem.new_("mem", IoEngine_.MemKey);
+
+ public static IoUrlInfo mem_(String key, String engineKey) {return IoUrlInfo_mem.new_(key, engineKey);}
+ public static IoUrlInfo alias_(String srcRoot, String trgRoot, String engineKey) {return IoUrlInfo_alias.new_(srcRoot, trgRoot, engineKey);}
+}
+/*
+wnt C:\dir\fil.txt
+wce \dir\fil.txt
+lnx /dir/fil.txt
+mem mem/dir/fil.txt
+alias app:\dir\fil.txt
+*/
\ No newline at end of file
diff --git a/100_core/src_200_io/gplx/ios/IoUrlTypeRegy.java b/100_core/src_200_io/gplx/ios/IoUrlTypeRegy.java
new file mode 100644
index 000000000..701a12a6c
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoUrlTypeRegy.java
@@ -0,0 +1,75 @@
+/*
+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.ios; import gplx.*;
+public class IoUrlTypeRegy implements GfoInvkAble {
+ public String[] FetchAryOr(String key, String... or) {
+ IoUrlTypeGrp itm = (IoUrlTypeGrp)hash.Fetch(key);
+ return itm == null ? or : itm.AsAry();
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk_Get)) {
+ String key = m.ReadStr(k);
+ if (ctx.Deny()) return this;
+ IoUrlTypeGrp itm = (IoUrlTypeGrp)hash.Fetch(key);
+ if (itm == null) {
+ itm = new IoUrlTypeGrp(key);
+ hash.Add(key, itm);
+ }
+ return itm;
+ }
+ else return GfoInvkAble_.Rv_unhandled;
+// return this;
+ } public static final String Invk_Get = "Get";
+ OrderedHash hash = OrderedHash_.new_();
+ public static final IoUrlTypeRegy _ = new IoUrlTypeRegy(); IoUrlTypeRegy() {}
+}
+class IoUrlTypeGrp implements GfoInvkAble {
+ public String[] AsAry() {
+ String[] rv = new String[list.Count()];
+ for (int i = 0; i < list.Count(); i++)
+ rv[i] = (String)list.FetchAt(i);
+ return rv;
+ }
+ OrderedHash list = OrderedHash_.new_();
+ public IoUrlTypeGrp(String key) {this.key = key;} private String key;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk_AddMany)) {
+ if (ctx.Deny()) return this;
+ for (int i = 0; i < m.Args_count(); i++) {
+ String s = m.ReadStr("v");
+ if (list.Has(s)) {
+ ctx.Write_warn(UsrMsg.new_("itm already has filter").Add("key", key).Add("filter", s).XtoStr());
+ list.Del(s);
+ }
+ list.Add(s, s);
+ }
+ }
+ else if (ctx.Match(k, Invk_Print)) {
+ if (ctx.Deny()) return this;
+ String_bldr sb = String_bldr_.new_();
+ sb.Add(key).Add("{");
+ for (int i = 0; i < list.Count(); i++)
+ sb.Add_spr_unless_first((String)list.FetchAt(i), " ", i);
+ sb.Add("}");
+ return sb.XtoStr();
+ }
+ else if (ctx.Match(k, Invk_Clear)) {if (ctx.Deny()) return this; list.Clear();}
+ else return GfoInvkAble_.Rv_unhandled;
+ return this;
+ } public static final String Invk_AddMany = "AddMany", Invk_Clear = "Clear", Invk_Print = "Print";
+}
diff --git a/100_core/src_200_io/gplx/ios/IoZipWkr.java b/100_core/src_200_io/gplx/ios/IoZipWkr.java
new file mode 100644
index 000000000..f3d015f46
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoZipWkr.java
@@ -0,0 +1,40 @@
+/*
+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.ios; import gplx.*;
+import gplx.stores.*; /*GfoNdeRdr_*/
+public class IoZipWkr {
+ public Io_url ExeUrl() {return (Io_url)GfoRegy._.FetchValOrFail(Regy_ExeUrl);}
+ public String ExeArgFmt() {return (String)GfoRegy._.FetchValOrFail(Regy_ExeArgFmt);}
+ public void Expand(Io_url srcUrl, Io_url trgUrl) {
+ String exeArgs = Expand_genCmdString(srcUrl, trgUrl);
+ process.Exe_url_(this.ExeUrl()).Args_str_(exeArgs);
+ process.Run_wait();
+ }
+ @gplx.Internal protected String Expand_genCmdString(Io_url srcUrl, Io_url trgUrl) {
+ return String_.Format(this.ExeArgFmt(), srcUrl.Xto_api(), trgUrl.Xto_api());
+ }
+ ProcessAdp process = new ProcessAdp();
+ public static IoZipWkr regy_() {return new IoZipWkr();}
+ static final String Regy_ExeUrl = "gplx.ios.IoZipWkr.ExeUrl", Regy_ExeArgFmt = "gplx.ios.IoZipWkr.ExeArgFmt";
+ public static IoZipWkr new_(Io_url exeUrl, String expandArgs) {
+ GfoRegy._.RegObj(Regy_ExeUrl, exeUrl);
+ GfoRegy._.RegObj(Regy_ExeArgFmt, expandArgs);
+ IoZipWkr rv = new IoZipWkr();
+ return rv;
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/IoZipWkr_tst.java b/100_core/src_200_io/gplx/ios/IoZipWkr_tst.java
new file mode 100644
index 000000000..7aa7987e5
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/IoZipWkr_tst.java
@@ -0,0 +1,28 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoZipWkr_tst {
+ @Test public void Basic() {
+ wkr = IoZipWkr.new_(Io_url_.Null, "e \"{0}\" -o\"{1}\" -y");
+ tst_Expand_genCmdString(Io_url_.wnt_fil_("C:\\fil1.zip"), Io_url_.wnt_dir_("D:\\out\\"), "e \"C:\\fil1.zip\" -o\"D:\\out\" -y"); // NOTE: not "D:\out\" because .Xto_api
+ } IoZipWkr wkr;
+ void tst_Expand_genCmdString(Io_url srcUrl, Io_url trgUrl, String expd) {
+ Tfds.Eq(expd, wkr.Expand_genCmdString(srcUrl, trgUrl));
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_download_fmt.java b/100_core/src_200_io/gplx/ios/Io_download_fmt.java
new file mode 100644
index 000000000..db84f5722
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_download_fmt.java
@@ -0,0 +1,92 @@
+/*
+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.ios; import gplx.*;
+import gplx.brys.*;
+public class Io_download_fmt {
+ public long Time_bgn() {return time_bgn;} long time_bgn;
+ public long Time_now() {return time_now;} long time_now;
+ public long Time_dif() {return time_dif;} long time_dif;
+ public long Time_end() {return time_end;} long time_end;
+ public String Src_url() {return src_url;} private String src_url;
+ public String Src_name() {return src_name;} private String src_name;
+ public long Src_len() {return src_len;} long src_len;
+ public long Prog_done() {return prog_done;} long prog_done;
+ public long Prog_rate() {return prog_rate;} long prog_rate;
+ public long Prog_left() {return prog_left;} long prog_left;
+ public long Prog_pct() {return prog_pct;} long prog_pct;
+ public String Prog_msg_hdr() {return prog_msg_hdr;} private String prog_msg_hdr;
+ public int Prog_num_units() {return prog_num_units;} int prog_num_units = Io_mgr.Len_kb;
+ public String Prog_num_fmt() {return prog_num_fmt;} private String prog_num_fmt = "#,##0";
+ public String Prog_msg() {return prog_msg;} private String prog_msg;
+ Io_size_fmtr_arg size_fmtr_arg = new Io_size_fmtr_arg(), rate_fmtr_arg = new Io_size_fmtr_arg().Suffix_(Bry_.new_ascii_("ps"));
+ Bry_fmtr_arg_time prog_left_fmtr_arg = new Bry_fmtr_arg_time(); Bry_fmtr_arg_decimal_int prog_pct_fmtr_arg = new Bry_fmtr_arg_decimal_int().Places_(2);
+ public void Ctor(Gfo_usr_dlg usr_dlg) {
+ this.usr_dlg = usr_dlg;
+ } Gfo_usr_dlg usr_dlg;
+ public void Init(String src_url, String prog_msg_hdr) {
+ this.src_url = src_url;
+ this.src_name = String_.Extract_after_bwd(src_url, "/");
+ this.prog_msg_hdr = prog_msg_hdr;
+ }
+ public void Bgn(long src_len) {
+ this.src_len = src_len;
+ prog_fmtr.Fmt_(prog_msg_hdr).Keys_("src_name", "src_len").Bld_bfr_many_and_set_fmt(src_name, size_fmtr_arg.Val_(src_len));
+ prog_fmtr.Keys_("prog_done", "prog_pct", "prog_rate", "prog_left");
+ prog_done = 0;
+ prog_pct = 0;
+ prog_rate = 0;
+ prog_left = 0;
+ time_bgn = time_prv = Env_.TickCount();
+ time_checkpoint = 0;
+ size_checkpoint = size_checkpoint_interval;
+ }
+ long time_checkpoint_interval = 250;
+ long time_checkpoint = 0;
+ long time_prv = 0;
+ long size_checkpoint = 0;
+ long size_checkpoint_interval = 32 * Io_mgr.Len_kb;
+ public void Prog(int prog_read) {
+ time_now = Env_.TickCount();
+ time_dif = time_now - time_bgn; if (time_dif == 0) time_dif = 1; // avoid div by zero error below
+ prog_done += prog_read;
+ time_checkpoint += time_now - time_prv;
+ time_prv = time_now;
+ if ((time_checkpoint < time_checkpoint_interval)) return; // NOTE: using time_checkpoint instead of size_checkpoint b/c WMF dump servers transfer in spurts (sends 5 packets, and then waits);
+ time_checkpoint = 0;
+ prog_rate = (prog_done * 1000) / (time_dif);
+ prog_pct = (prog_done * 10000) / src_len; // 100 00 to get 2 decimal places; EX: .1234 -> 1234 -> 12.34%
+ prog_left = (1000 * (src_len - prog_done)) / prog_rate;
+ prog_fmtr.Bld_bfr_many(prog_bfr
+ , size_fmtr_arg.Val_(prog_done)
+ , prog_pct_fmtr_arg.Val_((int)prog_pct)
+ , rate_fmtr_arg.Val_(prog_rate)
+ , prog_left_fmtr_arg.Seconds_(prog_left / 1000)
+ );
+ prog_msg = prog_bfr.XtoStrAndClear();
+ if (usr_dlg != null)
+ usr_dlg.Prog_none(GRP_KEY, "prog", prog_msg);
+ } private Bry_bfr prog_bfr = Bry_bfr.new_(); Bry_fmtr prog_fmtr = Bry_fmtr.new_().Fail_when_invalid_escapes_(false); // NOTE: prog_fmtr can be passed file_names with ~ which are not easy to escape; DATE:2013-02-19
+ public void Term() {
+ time_end = Env_.TickCount();
+// prog_rate = (prog_done * 1000) / (time_dif);
+// prog_pct = (prog_done * 10000) / src_len; // 100 00 to get 2 decimal places; EX: .1234 -> 1234 -> 12.34%
+// prog_left = (1000 * (src_len - prog_done)) / prog_rate;
+// if (usr_dlg != null) usr_dlg.Prog_none(GRP_KEY, "clear", "");
+ }
+ static final String GRP_KEY = "gplx.download";
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_download_fmt_tst.java b/100_core/src_200_io/gplx/ios/Io_download_fmt_tst.java
new file mode 100644
index 000000000..5de89cc32
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_download_fmt_tst.java
@@ -0,0 +1,73 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class Io_download_fmt_tst {
+ Io_download_fmt_fxt fxt = new Io_download_fmt_fxt();
+ @Before public void init() {fxt.Clear();}
+ @Test public void Fmt() {
+ fxt.Clear().Ini("downloading ~{src_name}: ~{prog_left} left (@ ~{prog_rate}); ~{prog_done} of ~{src_len} (~{prog_pct}%)", "http://a.org/b.png", Io_mgr.Len_kb * 10);
+ fxt.Now_add_f(1000).Prog_done_(1 * Io_mgr.Len_kb).Prog_pct_(1 * 1000).Prog_rate_(Io_mgr.Len_kb).Prog_left_(9 * 1000)
+ .Prog_msg_("downloading b.png: 09s left (@ 1.000 KBps); 1.000 KB of 10.000 KB (10.00%)")
+ .Download_(Io_mgr.Len_kb);
+ fxt.Now_add_f(1000).Prog_done_(2 * Io_mgr.Len_kb).Prog_pct_(2 * 1000).Prog_rate_(Io_mgr.Len_kb).Prog_left_(8 * 1000)
+ .Prog_msg_("downloading b.png: 08s left (@ 1.000 KBps); 2.000 KB of 10.000 KB (20.00%)")
+ .Download_(Io_mgr.Len_kb)
+ ;
+ fxt.Now_add_f(2000).Prog_done_(3 * Io_mgr.Len_kb).Prog_pct_(3 * 1000).Prog_rate_(768).Prog_left_(9333)
+ .Prog_msg_("downloading b.png: 09s left (@ 768.000 Bps); 3.000 KB of 10.000 KB (30.00%)")
+ .Download_(Io_mgr.Len_kb)
+ ;
+ }
+ @Test public void Tilde() {
+ fxt.Clear().Ini("a~b", "http://a.org/b.png", Io_mgr.Len_kb * 10);
+ }
+}
+class Io_download_fmt_fxt {
+ public Io_download_fmt_fxt Clear() {
+ if (fmt == null) {
+ fmt = new Io_download_fmt();
+ }
+ Env_.TickCount_Test = 0;
+ prog_done = prog_rate = prog_pct = prog_left = -1;
+ prog_msg = null;
+ return this;
+ } Io_download_fmt fmt;
+ public Io_download_fmt_fxt Now_add_f(int v) {Env_.TickCount_Test += v; return this;}
+ public Io_download_fmt_fxt Prog_done_(int v) {prog_done = v; return this;} long prog_done = -1;
+ public Io_download_fmt_fxt Prog_pct_ (int v) {prog_pct = v; return this;} long prog_pct = -1;
+ public Io_download_fmt_fxt Prog_rate_(int v) {prog_rate = v; return this;} long prog_rate = -1;
+ public Io_download_fmt_fxt Prog_left_(int v) {prog_left = v; return this;} long prog_left = -1;
+ public Io_download_fmt_fxt Prog_msg_(String v) {
+ prog_msg = v; return this;
+ } String prog_msg;
+ public Io_download_fmt_fxt Download_(int v) {
+ fmt.Prog(v);
+ if (prog_done != -1) Tfds.Eq(prog_done, fmt.Prog_done(), "prog_done");
+ if (prog_pct != -1) Tfds.Eq(prog_pct , fmt.Prog_pct(), "prog_pct");
+ if (prog_rate != -1) Tfds.Eq(prog_rate, fmt.Prog_rate(), "prog_rate");
+ if (prog_left != -1) Tfds.Eq(prog_left, fmt.Prog_left(), "prog_left");
+ if (prog_msg != null) Tfds.Eq(prog_msg, fmt.Prog_msg(), "prog_msg");
+ return this;
+ }
+ public Io_download_fmt_fxt Ini(String prog_msg_hdr, String src_url, int src_len) {
+ fmt.Init(src_url, prog_msg_hdr);
+ fmt.Bgn(src_len);
+ return this;
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_size_.java b/100_core/src_200_io/gplx/ios/Io_size_.java
new file mode 100644
index 000000000..e3f5260f2
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_size_.java
@@ -0,0 +1,111 @@
+/*
+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.ios; import gplx.*;
+public class Io_size_ {
+ public static String Xto_str(long val) {
+ long cur = val; int pow = 0;
+ while (cur >= 1024) {
+ cur /= 1024;
+ pow++;
+ }
+ long div = (long)Math_.Pow((long)1024, (long)pow);
+ DecimalAdp valDecimal = DecimalAdp_.divide_(val, div);
+ String[] unit = Io_size_.Units[pow];
+ return valDecimal.XtoStr("#,###.000") + " " + String_.PadBgn(unit[0], 2, " ");
+ }
+ public static long parse_or_(String raw, long or) {
+ if (raw == null || raw == String_.Empty) return or;
+ String[] terms = String_.Split(raw, " ");
+ int termsLen = Array_.Len(terms); if (termsLen > 2) return or;
+
+ DecimalAdp val = null;
+ try {val = DecimalAdp_.parse_(terms[0]);} catch (Exception exc) {Err_.Noop(exc); return or;}
+
+ int unitPow = 0;
+ if (termsLen > 1) {
+ String unitStr = String_.Upper(terms[1]);
+ unitPow = parse_unitPow_(unitStr); if (unitPow == -1) return or;
+ }
+ int curPow = unitPow;
+ while (curPow > 0) {
+ val = val.Op_mult(1024);
+ curPow--;
+ }
+ DecimalAdp comp = val.Op_truncate_decimal();
+ if (!val.Eq(comp)) return or;
+ return val.XtoLong();
+ }
+ static int parse_unitPow_(String unitStr) {
+ int unitLen = Array_.Len(Units);
+ int unitPow = -1;
+ for (int i = 0; i < unitLen; i++) {
+ if (String_.Eq(unitStr, String_.Upper(Units[i][0]))) return i;
+ if (String_.Eq(unitStr, String_.Upper(Units[i][1]))) return i;
+ }
+ return unitPow;
+ }
+ static String UnitsXtoStr() {
+ String_bldr sb = String_bldr_.new_();
+ int len = Array_.Len(Units);
+ for (int i = 0; i < len; i++) {
+ String[] eny = Units[i];
+ sb.Add_fmt("{0},{1};", eny[0], eny[1]);
+ }
+ return sb.XtoStr();
+ }
+ static final String[][] Units = new String[][]
+ { String_.Ary("B", "BYTE")
+ , String_.Ary("KB", "KILOBYTE")
+ , String_.Ary("MB", "MEGABYTE")
+ , String_.Ary("GB", "GIGABYTE")
+ , String_.Ary("TB", "TERABYTE")
+ , String_.Ary("PB", "PETABYTE")
+ , String_.Ary("EB", "EXABYTE")
+ };
+ public static final byte[][] Units_bry = new byte[][]
+ { Bry_.new_ascii_("B")
+ , Bry_.new_ascii_("KB")
+ , Bry_.new_ascii_("MB")
+ , Bry_.new_ascii_("GB")
+ , Bry_.new_ascii_("TB")
+ , Bry_.new_ascii_("PB")
+ , Bry_.new_ascii_("EB")
+ };
+ public static int Load_int_(GfoMsg m) {return (int)Load_long_(m);}
+ public static long Load_long_(GfoMsg m) {
+ String v = m.ReadStr("v");
+ long rv = parse_or_(v, Long_.MinValue); if (rv == Long_.MinValue) throw Err_.new_fmt_("invalid val: {0}", v);
+ return rv;
+ }
+}
+class Io_size_fmtr_arg implements Bry_fmtr_arg {
+ public long Val() {return val;} public Io_size_fmtr_arg Val_(long v) {val = v; return this;} long val;
+ public byte[] Suffix() {return suffix;} public Io_size_fmtr_arg Suffix_(byte[] v) {suffix = v; return this;} private byte[] suffix;
+ public void XferAry(Bry_bfr bfr, int idx) {
+ long cur = val; int pow = 0;
+ while (cur >= 1024) {
+ cur /= 1024;
+ pow++;
+ }
+ long div = (long)Math_.Pow((long)1024, (long)pow);
+ DecimalAdp val_decimal = DecimalAdp_.divide_(val, div);
+ bfr.Add_str(val_decimal.XtoStr("#,###.000")).Add_byte(Byte_ascii.Space).Add(gplx.ios.Io_size_.Units_bry[pow]);
+ if (suffix != null)
+ bfr.Add(suffix);
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_size__tst.java b/100_core/src_200_io/gplx/ios/Io_size__tst.java
new file mode 100644
index 000000000..bfd470345
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_size__tst.java
@@ -0,0 +1,56 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class Io_size__tst {
+ @Test public void XtoLong() {
+ tst_XtoLong("1", 1);
+ tst_XtoLong("1 KB", 1024);
+ tst_XtoLong("1 MB", 1024 * 1024);
+ tst_XtoLong("1 GB", 1024 * 1024 * 1024);
+ tst_XtoLong("12 kb", 12 * 1024);
+ tst_XtoLong("1.5 kb", 1024 + 512); // 1536
+ tst_XtoLong("1.5 mb", (long)(1024 * 1024 * 1.5));
+ tst_XtoLong("-1", -1); // NOTE: negative bytes allowed
+
+ tst_XtoLongFail("1 kilobite");
+ tst_XtoLongFail("1 BB");
+ tst_XtoLongFail("1.1");
+ tst_XtoLongFail("1.51 kb");
+ }
+ void tst_XtoLong(String raw, long expd) {Tfds.Eq(expd, Io_size_.parse_or_(raw, Long_.MinValue));}
+ void tst_XtoLongFail(String raw) {
+ long val = Io_size_.parse_or_(raw, Long_.MinValue);
+ if (val != Long_.MinValue) Tfds.Fail("expd parse failure; raw=" + raw);
+ }
+ @Test public void XtoStr() {
+ tst_XtoStr(1, "1.000 B");
+ tst_XtoStr(1024, "1.000 KB");
+ tst_XtoStr(1536, "1.500 KB");
+ tst_XtoStr(1024 * 1024, "1.000 MB");
+ tst_XtoStr(1016, "1,016.000 B"); // NOTE: 1016 is not 1.016 KB
+ } void tst_XtoStr(long val, String expd) {Tfds.Eq(expd, Io_size_.Xto_str(val));}
+ @Test public void EqualsTest() {
+ tst_Equals("1", "1");
+ tst_Equals("1 kb", "1 kb");
+ tst_Equals("1024", "1 kb");
+ tst_Equals("1048576", "1 mb");
+ tst_Equals("1024 kb", "1 mb");
+ tst_Equals("1.5 kb", "1536 b");
+ } void tst_Equals(String lhs, String rhs) {Tfds.Eq(Io_size_.parse_or_(lhs, Long_.MinValue), Io_size_.parse_or_(rhs, Long_.MinValue));}
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_stream_.java b/100_core/src_200_io/gplx/ios/Io_stream_.java
new file mode 100644
index 000000000..d9006d71c
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_stream_.java
@@ -0,0 +1,22 @@
+/*
+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.ios; import gplx.*;
+public class Io_stream_ { // SERIALIZED
+ public static final byte Tid_null = 0, Tid_file = 1, Tid_zip = 2, Tid_gzip = 3, Tid_bzip2 = 4;
+ public static final String Ext_zip = ".zip", Ext_gz = ".gz", Ext_bz2 = ".bz2";
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_stream_rdr.java b/100_core/src_200_io/gplx/ios/Io_stream_rdr.java
new file mode 100644
index 000000000..46884a7c9
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_stream_rdr.java
@@ -0,0 +1,29 @@
+/*
+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.ios; import gplx.*;
+public interface Io_stream_rdr extends RlsAble {
+ byte Tid();
+ Io_url Url(); Io_stream_rdr Url_(Io_url v);
+ long Len(); Io_stream_rdr Len_(long v);
+ Io_stream_rdr Open();
+ void Open_mem(byte[] v);
+ Object Under();
+
+ int Read(byte[] bry, int bgn, int len);
+ long Skip(long len);
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_stream_rdr_.java b/100_core/src_200_io/gplx/ios/Io_stream_rdr_.java
new file mode 100644
index 000000000..31d880a08
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_stream_rdr_.java
@@ -0,0 +1,266 @@
+/*
+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.ios; import gplx.*;
+public class Io_stream_rdr_ {
+ public static Io_stream_rdr file_(Io_url url) {return new Io_stream_rdr_file().Url_(url);}
+ public static Io_stream_rdr file_(java.io.InputStream strm) {return new Io_stream_rdr_file().Under_(strm);}
+ public static Io_stream_rdr zip_(Io_url url) {return new Io_stream_rdr_zip().Url_(url);}
+ public static Io_stream_rdr gzip_(Io_url url) {return new Io_stream_rdr_gzip().Url_(url);}
+ public static Io_stream_rdr bzip2_(Io_url url) {return new Io_stream_rdr_bzip2().Url_(url);}
+ public static Io_stream_rdr new_by_url_(Io_url url) {
+ String ext = url.Ext();
+ if (String_.Eq(ext, Io_stream_.Ext_zip)) return gplx.ios.Io_stream_rdr_.zip_(url);
+ else if (String_.Eq(ext, Io_stream_.Ext_gz)) return gplx.ios.Io_stream_rdr_.gzip_(url);
+ else if (String_.Eq(ext, Io_stream_.Ext_bz2)) return gplx.ios.Io_stream_rdr_.bzip2_(url);
+ else return gplx.ios.Io_stream_rdr_.file_(url);
+ }
+ public static Io_stream_rdr new_by_tid_(byte tid) {
+ switch (tid) {
+ case Io_stream_.Tid_file: return new Io_stream_rdr_file();
+ case Io_stream_.Tid_zip: return new Io_stream_rdr_zip();
+ case Io_stream_.Tid_gzip: return new Io_stream_rdr_gzip();
+ case Io_stream_.Tid_bzip2: return new Io_stream_rdr_bzip2();
+ default: throw Err_.unhandled(tid);
+ }
+ }
+ public static byte[] Load_all(Io_url url) {
+ Io_stream_rdr rdr = new_by_url_(url);
+ Bry_bfr rv = Bry_bfr.new_();
+ try {
+ rdr.Open();
+ return Load_all_as_bry(rv, rdr);
+ }
+ finally {rdr.Rls();}
+ }
+ public static String Load_all_as_str(Io_stream_rdr rdr) {return String_.new_utf8_(Load_all_as_bry(rdr));}
+ public static byte[] Load_all_as_bry(Io_stream_rdr rdr) {return Load_all_as_bry(Bry_bfr.new_(), rdr);}
+ public static byte[] Load_all_as_bry(Bry_bfr rv, Io_stream_rdr rdr) {
+ Load_all_to_bfr(rv, rdr);
+ return rv.XtoAryAndClear();
+ }
+ public static void Load_all_to_bfr(Bry_bfr rv, Io_stream_rdr rdr) {
+ try {
+ byte[] bry = new byte[4096];
+ while (true) {
+ int read = rdr.Read(bry, 0, 4096);
+ if (read < gplx.ios.Io_stream_rdr_.Read_done_compare) break;
+ rv.Add_mid(bry, 0, read);
+ }
+ } finally {rdr.Rls();}
+ }
+ public static final Io_stream_rdr Null = new Io_stream_rdr_null();
+ public static Io_stream_rdr mem_(String v) {return mem_(Bry_.new_utf8_(v));}
+ public static Io_stream_rdr mem_(byte[] v) {
+ Io_stream_rdr rv = new Io_stream_rdr_adp(Stream_new_mem(v));
+ rv.Len_(v.length);
+ return rv;
+ }
+ public static java.io.InputStream Stream_new_mem(byte[] v) {
+ return new java.io.ByteArrayInputStream(v);
+ }
+ public static boolean Stream_close(java.io.InputStream stream) {
+ try {
+ if (stream != null)
+ stream.close();
+ return true;
+ } catch (Exception e) {Err_.Noop(e); return false;}
+ }
+ public static int Stream_read_by_parts(java.io.InputStream stream, int part_len, byte[] bry, int bgn, int len) {
+ /*
+ NOTE: BZip2CompressorInputStream will fail if large len is used
+ Instead, make smaller requests and fill bry
+ */
+ try {
+ int rv = 0;
+ int end = bgn + len;
+ int cur = bgn;
+ while (true) {
+ int bry_len = part_len; // read in increments of part_len
+ if (cur + bry_len > end) // if cur + 8 kb > bry_len, trim to end; EX: 9 kb bry passed; 1st pass is 8kb, 2nd pass should be 1kb, not 8 kb;
+ bry_len = end - cur;
+ if (cur == end) break; // no more bytes needed; break; EX: 8 kb bry passed; 1st pass is 8kb; 2nd pass is 0 and cur == end
+ int read = stream.read(bry, cur, bry_len);
+ if (read == gplx.ios.Io_stream_rdr_.Read_done) // read done; end
+ break;
+ rv += read;
+ cur += read;
+ }
+ return rv;
+ }
+ catch (Exception exc) {
+ throw Err_.new_fmt_("read failed: bgn={0} len={1} exc={2}", bgn, len, Err_.Message_gplx(exc));
+ }
+ }
+ public static final int Read_done = -1;
+ public static final int Read_done_compare = 1;
+}
+class Io_stream_rdr_null implements Io_stream_rdr {
+ public Object Under() {return null;}
+ public byte Tid() {return Io_stream_.Tid_null;}
+ public Io_url Url() {return Io_url_.Null;} public Io_stream_rdr Url_(Io_url v) {return this;}
+ public long Len() {return Io_mgr.Len_null;} public Io_stream_rdr Len_(long v) {return this;}
+ public void Open_mem(byte[] v) {}
+ public Io_stream_rdr Open() {return this;}
+ public int Read(byte[] bry, int bgn, int len) {return Io_stream_rdr_.Read_done;}
+ public long Skip(long len) {return Io_stream_rdr_.Read_done;}
+ public void Rls() {}
+}
+class Io_stream_rdr_adp implements Io_stream_rdr {
+ private java.io.InputStream strm;
+ public Io_stream_rdr_adp(java.io.InputStream strm) {this.strm = strm;}
+ public Object Under() {return strm;}
+ public byte Tid() {return Io_stream_.Tid_file;}
+ public Io_url Url() {return url;} public Io_stream_rdr Url_(Io_url v) {this.url = v; return this;} private Io_url url;
+ public long Len() {return len;} public Io_stream_rdr Len_(long v) {len = v; return this;} private long len = Io_mgr.Len_null;
+ public void Open_mem(byte[] v) {}
+ public Io_stream_rdr Open() {return this;}
+ public int Read(byte[] bry, int bgn, int len) {
+ try {return strm.read(bry, bgn, len);}
+ catch (Exception exc) {Err_.Noop(exc); throw Err_.new_fmt_("read failed: bgn={0} len={1}", bgn, len);}
+ }
+ public long Skip(long len) {
+ try {return strm.skip(len);}
+ catch (Exception exc) {Err_.Noop(exc); throw Err_.new_fmt_("skip failed: len={0}", len);}
+ }
+ public void Rls() {
+ try {strm.close();}
+ catch (Exception exc) {Err_.Noop(exc); throw Err_.new_fmt_("close failed: url={0}", url.Xto_api());}
+ }
+}
+abstract class Io_stream_rdr_base implements Io_stream_rdr {
+ public abstract byte Tid();
+ public Object Under() {return stream;} public Io_stream_rdr Under_(java.io.InputStream v) {this.stream = v; return this;} protected java.io.InputStream stream;
+ public Io_url Url() {return url;} public Io_stream_rdr Url_(Io_url v) {this.url = v; return this;} protected Io_url url;
+ public long Len() {return len;} public Io_stream_rdr Len_(long v) {len = v; return this;} private long len = Io_mgr.Len_null;
+ public void Open_mem(byte[] v) {
+ stream = Wrap_stream(new java.io.ByteArrayInputStream(v));
+ }
+ public Io_stream_rdr Open() {
+ try {stream = Wrap_stream(new java.io.FileInputStream(url.Xto_api()));}
+ catch (Exception exc) {throw Err_.new_fmt_("open failed: url={0}", url.Xto_api());}
+ return this;
+ }
+ public int Read(byte[] bry, int bgn, int len) {
+ try {return stream.read(bry, bgn, len);}
+ catch (Exception exc) {throw Err_.new_fmt_("read failed: bgn={0} len={1}", bgn, len);}
+ }
+ public long Skip(long len) {
+ try {return stream.skip(len);}
+ catch (Exception exc) {throw Err_.new_fmt_("skip failed: len={0}", len);}
+ }
+ public void Rls() {
+ try {stream.close();}
+ catch (Exception e) {
+ throw Err_.new_fmt_("close failed: url={0}", url.Xto_api());
+ }
+ }
+ public abstract java.io.InputStream Wrap_stream(java.io.InputStream stream);
+}
+class Io_stream_rdr_file extends Io_stream_rdr_base {
+ @Override public byte Tid() {return Io_stream_.Tid_file;}
+ public Io_stream_rdr Open() {
+ try {
+ if (!Io_mgr._.Exists(url))
+ stream = Wrap_stream(new java.io.ByteArrayInputStream(Bry_.Empty));
+ else {
+ if (url.Info().EngineKey() == gplx.ios.IoEngine_.MemKey)
+ stream = Wrap_stream(new java.io.ByteArrayInputStream(Io_mgr._.LoadFilBry(url.Xto_api())));
+ else
+ stream = Wrap_stream(new java.io.FileInputStream(url.Xto_api()));
+ }
+ }
+ catch (Exception exc) {throw Err_.new_fmt_("open failed: url={0}", url.Xto_api());}
+ return this;
+ }
+ @Override public java.io.InputStream Wrap_stream(java.io.InputStream stream) {return stream;}
+}
+class Io_stream_rdr_zip implements Io_stream_rdr {
+ @Override public byte Tid() {return Io_stream_.Tid_zip;}
+ public Io_url Url() {return url;} public Io_stream_rdr Url_(Io_url v) {this.url = v; return this;} Io_url url;
+ public long Len() {return len;} public Io_stream_rdr Len_(long v) {len = v; return this;} private long len = Io_mgr.Len_null;
+ public Object Under() {return zip_stream;} private java.util.zip.ZipInputStream zip_stream;
+ public void Src_bfr_(Bry_bfr v) {this.src_bfr = v;} Bry_bfr src_bfr;
+ public void Open_mem(byte[] v) {
+ Wrap_stream(new java.io.ByteArrayInputStream(v));
+ }
+ public Io_stream_rdr Open() {
+ try {Wrap_stream(new java.io.FileInputStream(url.Xto_api()));}
+ catch (Exception exc) {throw Err_.new_fmt_("open failed: url={0}", url.Xto_api());}
+ return this;
+ }
+ void Wrap_stream(java.io.InputStream input_stream) {zip_stream = new java.util.zip.ZipInputStream(input_stream);}
+ public int Read(byte[] bry, int bgn, int len) {
+ try {
+ while (true){
+ int read = zip_stream.read(bry, bgn, len);
+ if (read == gplx.ios.Io_stream_rdr_.Read_done) {
+ if (zip_stream.getNextEntry() == null)
+ return gplx.ios.Io_stream_rdr_.Read_done;
+ }
+ else
+ return read;
+ }
+ }
+ catch (Exception exc) {throw Err_.new_fmt_("read failed: bgn={0} len={1}", bgn, len);}
+ }
+ public long Skip(long len) {
+ try {return zip_stream.skip(len);}
+ catch (Exception exc) {throw Err_.new_fmt_("skip failed: len={0}", len);}
+ }
+ public void Rls() {
+ try {zip_stream.close();}
+ catch (Exception e) {
+ throw Err_.new_fmt_("close failed: url={0}", url.Xto_api());
+ }
+ }
+}
+class Io_stream_rdr_gzip extends Io_stream_rdr_base {
+ @Override public byte Tid() {return Io_stream_.Tid_gzip;}
+ @Override public int Read(byte[] bry, int bgn, int len) {
+ try {
+ int total_read = 0;
+ while (true) { // NOTE: the gz stream reads partially; (request 100; only get back 10); keep reading until entire bfr is full or -1
+ int read = stream.read(bry, bgn, len);
+ if (read == gplx.ios.Io_stream_rdr_.Read_done) break;
+ total_read += read;
+ if (total_read >= len) break; // entire bfr full; stop
+ bgn += read; // increase bgn by amount read
+ len -= read; // decrease len by amount read
+ }
+ return total_read == 0 ? gplx.ios.Io_stream_rdr_.Read_done : total_read; // gzip seems to allow 0 bytes read (bz2 and zip return -1 instead); normalize return to -1;
+ }
+ catch (Exception exc) {
+ throw Err_.new_fmt_("read failed: bgn={0} len={1}", bgn, len);
+ }
+ }
+ @Override public java.io.InputStream Wrap_stream(java.io.InputStream stream) {
+ try {return new java.util.zip.GZIPInputStream(stream);}
+ catch (Exception exc) {throw Err_.new_fmt_("failed to open gz stream");}
+ }
+}
+class Io_stream_rdr_bzip2 extends Io_stream_rdr_base {
+ @Override public byte Tid() {return Io_stream_.Tid_bzip2;}
+ @Override public java.io.InputStream Wrap_stream(java.io.InputStream stream) {
+ try {return new org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream(stream, true);}
+ catch (Exception exc) {throw Err_.new_fmt_("failed to open bzip2 stream");}
+ }
+ @Override public int Read(byte[] bry, int bgn, int len) {
+ return Io_stream_rdr_.Stream_read_by_parts(stream, Read_len, bry, bgn, len);
+ }
+ private static final int Read_len = Io_mgr.Len_mb * 128;
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_stream_rdr_tst.java b/100_core/src_200_io/gplx/ios/Io_stream_rdr_tst.java
new file mode 100644
index 000000000..a34d6c25e
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_stream_rdr_tst.java
@@ -0,0 +1,56 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class Io_stream_rdr_tst {
+ @Before public void init() {fxt.Clear();} private Io_stream_rdr_fxt fxt = new Io_stream_rdr_fxt();
+ @After public void term() {fxt.Rls();}
+ @Test public void Bz2_read() {
+ fxt .Init_stream("abcd") // read everything at once
+ .Expd_bytes_read(4).Test_read(0, 4, "abcd");
+ fxt .Init_stream("abcd") // read in steps
+ .Expd_bytes_read(1).Test_read(0, 1, "a")
+ .Expd_bytes_read(2).Test_read(1, 2, "bc")
+ .Expd_bytes_read(1).Test_read(3, 1, "d")
+ ;
+ }
+}
+class Io_stream_rdr_fxt {
+ private java.io.InputStream stream;
+ private int stream_bry_len;
+ public void Clear() {
+ expd_bytes_read = Int_.MinValue;
+ }
+ public Io_stream_rdr_fxt Expd_bytes_read(int v) {expd_bytes_read = v; return this;} private int expd_bytes_read = Int_.MinValue;
+ public Io_stream_rdr_fxt Init_stream(String v) {
+ byte[] stream_bry = Bry_.new_ascii_(v);
+ stream_bry_len = stream_bry.length;
+ stream = Io_stream_rdr_.Stream_new_mem(stream_bry);
+ return this;
+ }
+ public Io_stream_rdr_fxt Test_read(int bgn, int len, String expd_str) {
+ byte[] bfr = new byte[stream_bry_len]; // allocate whole stream; may not use it all
+ int actl_bytes_read = Io_stream_rdr_.Stream_read_by_parts(stream, 8, bfr, bgn, len);
+ Tfds.Eq(expd_bytes_read, actl_bytes_read, "bytes_read");
+ Tfds.Eq(expd_str, String_.new_utf8_(bfr, bgn, bgn + actl_bytes_read), "str");
+ return this;
+ }
+ public void Rls() {
+ Io_stream_rdr_.Stream_close(stream);
+ }
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_stream_wtr.java b/100_core/src_200_io/gplx/ios/Io_stream_wtr.java
new file mode 100644
index 000000000..c4c432487
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_stream_wtr.java
@@ -0,0 +1,28 @@
+/*
+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.ios; import gplx.*;
+public interface Io_stream_wtr extends RlsAble {
+ byte Tid();
+ Io_url Url(); Io_stream_wtr Url_(Io_url v);
+ void Trg_bfr_(Bry_bfr v);
+ Io_stream_wtr Open();
+ byte[] Xto_ary_and_clear();
+
+ void Write(byte[] bry, int bgn, int len);
+ void Flush();
+}
diff --git a/100_core/src_200_io/gplx/ios/Io_stream_wtr_.java b/100_core/src_200_io/gplx/ios/Io_stream_wtr_.java
new file mode 100644
index 000000000..0907706c2
--- /dev/null
+++ b/100_core/src_200_io/gplx/ios/Io_stream_wtr_.java
@@ -0,0 +1,208 @@
+/*
+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.ios; import gplx.*;
+public class Io_stream_wtr_ {
+ public static Io_stream_wtr bzip2_(Io_url url) {return new Io_stream_wtr_bzip2().Url_(url);}
+ public static Io_stream_wtr gzip_(Io_url url) {return new Io_stream_wtr_gzip().Url_(url);}
+ public static Io_stream_wtr zip_(Io_url url) {return new Io_stream_wtr_zip().Url_(url);}
+ public static Io_stream_wtr file_(Io_url url) {return new Io_stream_wtr_file().Url_(url);}
+ public static Io_stream_wtr new_by_url_(Io_url url) {
+ String ext = url.Ext();
+ if (String_.Eq(ext, Io_stream_.Ext_zip)) return gplx.ios.Io_stream_wtr_.zip_(url);
+ else if (String_.Eq(ext, Io_stream_.Ext_gz)) return gplx.ios.Io_stream_wtr_.gzip_(url);
+ else if (String_.Eq(ext, Io_stream_.Ext_bz2)) return gplx.ios.Io_stream_wtr_.bzip2_(url);
+ else return gplx.ios.Io_stream_wtr_.file_(url);
+ }
+ public static Io_stream_wtr new_by_mem(Bry_bfr bfr, byte tid) {
+ Io_stream_wtr wtr = new_by_tid_(tid).Url_(Io_url_.Null);
+ wtr.Trg_bfr_(bfr);
+ return wtr;
+ }
+ public static Io_stream_wtr new_by_tid_(byte v) {
+ switch (v) {
+ case gplx.ios.Io_stream_.Tid_file : return new Io_stream_wtr_file();
+ case gplx.ios.Io_stream_.Tid_zip : return new Io_stream_wtr_zip();
+ case gplx.ios.Io_stream_.Tid_gzip : return new Io_stream_wtr_gzip();
+ case gplx.ios.Io_stream_.Tid_bzip2 : return new Io_stream_wtr_bzip2();
+ default : throw Err_.unhandled(v);
+ }
+ }
+ public static void Save_all(Io_url url, byte[] bry, int bgn, int end) {
+ Io_stream_wtr wtr = new_by_url_(url);
+ try {
+ wtr.Open();
+ wtr.Write(bry, bgn, end);
+ wtr.Flush();
+ }
+ finally {wtr.Rls();}
+ }
+ public static void Save_rdr(Io_url url, Io_stream_rdr rdr) {
+ byte[] bry = new byte[4096];
+ Io_stream_wtr wtr = new_by_url_(url);
+ try {
+ wtr.Open();
+ while (true) {
+ int read = rdr.Read(bry, 0, 4096);
+ if (read < gplx.ios.Io_stream_rdr_.Read_done_compare) break;
+ wtr.Write(bry, 0, read);
+ }
+ wtr.Flush();
+ }
+ finally {wtr.Rls(); rdr.Rls();}
+ }
+}
+abstract class Io_stream_wtr_base implements Io_stream_wtr {
+ java.io.OutputStream zip_stream;
+ public Io_url Url() {return url;} public Io_stream_wtr Url_(Io_url v) {url = v; trg_bfr = null; return this;} Io_url url;
+ public void Trg_bfr_(Bry_bfr v) {trg_bfr = v;} Bry_bfr trg_bfr; java.io.ByteArrayOutputStream mem_stream;
+ public byte[] Xto_ary_and_clear() {return trg_bfr.XtoAryAndClear();}
+ @SuppressWarnings("resource") // rely on OutputStream to close bry_stream
+ public Io_stream_wtr Open() {
+ java.io.OutputStream bry_stream = null;
+ if (trg_bfr == null) {
+ if (!Io_mgr._.ExistsFil(url)) Io_mgr._.SaveFilStr(url, "");
+ try {bry_stream = new java.io.FileOutputStream(url.Raw());}
+ catch (Exception exc) {throw Err_.new_fmt_("open failed: url={0}", url.Raw());}
+ }
+ else {
+ mem_stream = new java.io.ByteArrayOutputStream();
+ bry_stream = mem_stream;
+ }
+ zip_stream = Wrap_stream(bry_stream);
+ return this;
+ }
+ public void Write(byte[] bry, int bgn, int len) {
+ try {zip_stream.write(bry, bgn, len);}
+ catch (Exception exc) {throw Err_.new_fmt_("write failed: bgn={0} len={1}", bgn, len);}
+ }
+ public void Flush() {
+ if (trg_bfr != null) {
+ try {zip_stream.close();} catch (Exception exc) {throw Err_.new_fmt_("flush failed");} // must close zip_stream to flush all bytes
+ trg_bfr.Add(mem_stream.toByteArray());
+ }
+ }
+ public void Rls() {
+ try {
+ if (zip_stream != null) zip_stream.close();
+ if (mem_stream != null) mem_stream.close();
+ }
+ catch (Exception e) {throw Err_.new_fmt_("close failed: url={0}", url.Raw());}
+ }
+ public abstract java.io.OutputStream Wrap_stream(java.io.OutputStream stream);
+}
+class Io_stream_wtr_bzip2 extends Io_stream_wtr_base {
+ @Override public byte Tid() {return Io_stream_.Tid_bzip2;}
+ @Override public java.io.OutputStream Wrap_stream(java.io.OutputStream stream) {
+ try {return new org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream(stream);}
+ catch (Exception exc) {throw Err_.new_fmt_("failed to open bzip2 stream");}
+ }
+ static final byte[] Bz2_header = new byte[] {Byte_ascii.Ltr_B, Byte_ascii.Ltr_Z};
+}
+class Io_stream_wtr_gzip extends Io_stream_wtr_base {
+ @Override public byte Tid() {return Io_stream_.Tid_gzip;}
+ @Override public java.io.OutputStream Wrap_stream(java.io.OutputStream stream) {
+ try {return new java.util.zip.GZIPOutputStream(stream);}
+ catch (Exception exc) {throw Err_.new_fmt_("failed to open gz stream");}
+ }
+}
+class Io_stream_wtr_zip implements Io_stream_wtr {
+ private java.util.zip.ZipOutputStream zip_stream;
+ @Override public byte Tid() {return Io_stream_.Tid_zip;}
+ public Io_url Url() {return url;} public Io_stream_wtr Url_(Io_url v) {url = v; trg_bfr = null; return this;} private Io_url url = Io_url_.Null;
+ public void Trg_bfr_(Bry_bfr v) {trg_bfr = v;} private Bry_bfr trg_bfr; private java.io.ByteArrayOutputStream mem_stream;
+ @SuppressWarnings("resource") // rely on zip_stream to close bry_stream
+ public Io_stream_wtr Open() {
+ java.io.OutputStream bry_stream;
+ if (trg_bfr == null) {
+ if (!Io_mgr._.ExistsFil(url)) Io_mgr._.SaveFilStr(url, ""); // create file if it doesn't exist
+ try {bry_stream = new java.io.FileOutputStream(url.Xto_api());}
+ catch (Exception exc) {throw Err_.new_fmt_("open failed: url={0}", url.Raw());}
+ }
+ else {
+ mem_stream = new java.io.ByteArrayOutputStream();
+ bry_stream = mem_stream;
+ }
+ zip_stream = new java.util.zip.ZipOutputStream(bry_stream);
+ java.util.zip.ZipEntry entry = new java.util.zip.ZipEntry("file");
+ try {zip_stream.putNextEntry(entry);}
+ catch (Exception exc) {throw Err_.new_fmt_("open failed: url={0}", url.Raw());}
+ return this;
+ }
+ public void Write(byte[] bry, int bgn, int len) {
+ try {zip_stream.write(bry, bgn, len);}
+ catch (Exception exc) {throw Err_.new_fmt_("write failed: url={0} bgn={1} len={2}", url.Raw(), bgn, len);}
+ }
+ public void Flush() {// fixed as of DATE:2014-04-15
+ try {
+ zip_stream.closeEntry();
+ zip_stream.close();
+ if (trg_bfr != null)
+ trg_bfr.Add(mem_stream.toByteArray());
+ zip_stream.flush();
+ }
+ catch (Exception e) {throw Err_.new_fmt_("flush failed: url={0}", url.Raw());}
+ }
+ public void Rls() {
+ try {
+ if (zip_stream != null) zip_stream.close();
+ if (mem_stream != null) mem_stream.close();
+ }
+ catch (Exception e) {throw Err_.new_fmt_("close failed: url={0}", url.Raw());}
+ }
+ public byte[] Xto_ary_and_clear() {
+ byte[] rv = trg_bfr.XtoAryAndClear();
+ this.Rls();
+ return rv;
+ }
+}
+class Io_stream_wtr_file implements Io_stream_wtr {
+ IoStream bry_stream;
+ @Override public byte Tid() {return Io_stream_.Tid_file;}
+ public Io_url Url() {return url;} public Io_stream_wtr Url_(Io_url v) {url = v; return this;} Io_url url;
+ public void Trg_bfr_(Bry_bfr v) {trg_bfr = v;} private Bry_bfr trg_bfr; java.io.ByteArrayOutputStream mem_stream;
+ public Io_stream_wtr Open() {
+ try {
+ if (trg_bfr == null)
+ bry_stream = Io_mgr._.OpenStreamWrite(url);
+ }
+ catch (Exception exc) {throw Err_.new_fmt_("open failed: url={0}", url.Raw());}
+ return this;
+ }
+ public void Write(byte[] bry, int bgn, int len) {
+ if (trg_bfr == null) {
+ try {bry_stream.Write(bry, bgn, len);}
+ catch (Exception exc) {throw Err_.new_fmt_("write failed: url={0} bgn={1} len={2}", url.Raw(), bgn, len);}
+ }
+ else
+ trg_bfr.Add_mid(bry, bgn, bgn + len);
+ }
+ public byte[] Xto_ary_and_clear() {
+ return trg_bfr == null ? Io_mgr._.LoadFilBry(url) : trg_bfr.XtoAryAndClear();
+ }
+ public void Flush() {
+ if (trg_bfr == null)
+ bry_stream.Flush();
+ }
+ public void Rls() {
+ try {
+ if (trg_bfr == null)
+ bry_stream.Rls();
+ }
+ catch (Exception e) {throw Err_.new_fmt_("close failed: url={0}", url.Raw());}
+ }
+}
diff --git a/100_core/src_210_env/gplx/ClassAdp_.java b/100_core/src_210_env/gplx/ClassAdp_.java
new file mode 100644
index 000000000..ead2e4b12
--- /dev/null
+++ b/100_core/src_210_env/gplx/ClassAdp_.java
@@ -0,0 +1,45 @@
+/*
+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;
+public class ClassAdp_ {
+ public static boolean Eq(Class> lhs, Class> rhs) {
+ if (lhs == null && rhs == null) return true;
+ else if (lhs == null || rhs == null) return false;
+ else return lhs.equals(rhs);
+ }
+ public static boolean Eq_typeSafe(Object o, Class> expd) {if (o == null) return false;
+ Class> actl = o.getClass();
+ return Object_.Eq(expd, actl);
+ }
+ public static boolean IsAssignableFrom(Class> lhs, Class> rhs) {return lhs.isAssignableFrom(rhs);}
+ public static boolean Is_array(Class> t) {return t.isArray();}
+ public static Class> ClassOf_obj(Object o) {return o.getClass();}
+ public static Class> ClassOf_primitive(Object o) {
+ Class> rv = o.getClass();
+ if (rv == Integer.class) rv = int.class;
+ else if (rv == Long.class) rv = long.class;
+ else if (rv == Byte.class) rv = byte.class;
+ else if (rv == Short.class) rv = short.class;
+ return rv;
+ }
+ public static String FullNameOf_obj(Object o) {return FullNameOf_type(o.getClass());}
+ public static String FullNameOf_type(Class> type) {return type.getCanonicalName();}
+ public static String NameOf_type(Class> type) {return type.getName();}
+ public static String NameOf_obj(Object obj) {return obj == null ? String_.Null_mark : obj.getClass().getName();}
+ public static final byte Tid_bool = 1, Tid_byte = 2, Tid_int = 3, Tid_long = 4, Tid_float = 5, Tid_double = 6, Tid_char = 7, Tid_str = 8, Tid_date = 9, Tid_decimal = 10;
+}
diff --git a/100_core/src_210_env/gplx/Env_.java b/100_core/src_210_env/gplx/Env_.java
new file mode 100644
index 000000000..3a83c408b
--- /dev/null
+++ b/100_core/src_210_env/gplx/Env_.java
@@ -0,0 +1,96 @@
+/*
+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;
+import gplx.threads.*;
+public class Env_ {
+ public static void Init(String[] args, String appNameAndExt, Class> type) {
+ mode_testing = false;
+ mode_debug = String_.In("GPLX_DEBUG_MODE_ENABLED", args);
+ appArgs = args;
+ appUrl = JarAdp_.Url_type(type).OwnerDir().GenSubFil(appNameAndExt);
+ }
+ public static void Init_swt(String[] args, Class> type) { // DATE:2014-06-23
+ mode_testing = false;
+ mode_debug = String_.In("GPLX_DEBUG_MODE_ENABLED", args);
+ appArgs = args;
+ appUrl = JarAdp_.Url_type(type);
+ }
+ public static void Init_drd(String[] args, Io_url url) {
+ mode_testing = mode_debug = false;
+ appArgs = args;
+ appUrl = url;
+ }
+ public static void Init_testing() {mode_testing = true;}
+ public static boolean Mode_testing() {return mode_testing;} static boolean mode_testing = true;
+ public static boolean Mode_debug() {return mode_debug;} static boolean mode_debug = false;
+ public static String[] AppArgs() {return appArgs;} static String[] appArgs;
+ public static Io_url AppUrl() {
+ if (mode_testing) return Io_url_.mem_fil_("mem/testing.jar");
+ if (appUrl == Io_url_.Null) throw Err_.new_("Env_.Init was not called");
+ return appUrl;
+ } static Io_url appUrl = Io_url_.Null;
+ public static void Exit() {Exit_code(0);}
+ public static void Exit_code(int code) {System.exit(code);}
+ public static String UserName() {return System.getProperty("user.name");}
+ public static void GarbageCollect() {if (mode_testing) return; System.gc();}
+ public static long TickCount() {return TickCount_Test >= 0 ? TickCount_Test : System.currentTimeMillis();}
+ public static int TickCount_elapsed_in_sec(long time_bgn) {return (int)(Env_.TickCount() - time_bgn) / 1000;}
+ public static int TickCount_elapsed_in_frac(long time_bgn) {return (int)(Env_.TickCount() - time_bgn);}
+ public static long TickCount_Test = -1; // in milliseconds
+ public static void TickCount_normal() {TickCount_Test = -1;}
+ public static long System_memory_free() {return Runtime.getRuntime().freeMemory();}
+ public static final String LocalHost = "127.0.0.1";
+ public static String NewLine_lang() {return mode_testing ? "\n" : "\n";}
+ public static String GenHdr(boolean forSourceCode, String programName, String hdr_bgn, String hdr_end) {
+ String newLine = Op_sys.Lnx.Nl_str();
+ String lineEnd = Op_sys.Lnx.Nl_str();
+ String codeBgn = forSourceCode ? "/*" + newLine : "";
+ String codeEnd = forSourceCode ? "*/" + newLine : "";
+ String codeHdr = forSourceCode ? "This file is part of {0}." + newLine + newLine : "";
+ String fmt = String_.Concat
+ ( codeBgn
+ , codeHdr
+ , hdr_bgn
+ , "Copyright (c) 2012 gnosygnu@gmail.com", newLine
+ , newLine
+ , "This program is free software: you can redistribute it and/or modify", lineEnd
+ , "it under the terms of the GNU Affero General Public License as", lineEnd
+ , "published by the Free Software Foundation, either version 3 of the", lineEnd
+ , "License, or (at your option) any later version.", newLine
+ , newLine
+ , "This program is distributed in the hope that it will be useful,", lineEnd
+ , "but WITHOUT ANY WARRANTY; without even the implied warranty of", lineEnd
+ , "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", lineEnd
+ , "GNU Affero General Public License for more details.", newLine
+ , newLine
+ , "You should have received a copy of the GNU Affero General Public License", lineEnd
+ , "along with this program. If not, see .", newLine
+ , codeEnd
+ , hdr_end
+ );
+ return String_.Format(fmt, programName);
+ }
+ public static String Env_prop__user_language() {return Env_prop(Env_prop_key__user_language);}
+ public static String Env_prop(String key) {
+ return System.getProperty(key);
+ } static final String Env_prop_key__user_language = "user.language";
+ public static void Term_add(GfoInvkAble invk, String cmd) {
+ ThreadAdp thread = ThreadAdp_.invk_(invk, cmd);
+ Runtime.getRuntime().addShutdownHook(thread.Under_thread());
+ }
+}
diff --git a/100_core/src_210_env/gplx/JarAdp_.java b/100_core/src_210_env/gplx/JarAdp_.java
new file mode 100644
index 000000000..1c2134215
--- /dev/null
+++ b/100_core/src_210_env/gplx/JarAdp_.java
@@ -0,0 +1,33 @@
+/*
+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;
+public class JarAdp_ {
+ public static DateAdp ModifiedTime_type(Class> type) {if (type == null) throw Err_.null_("type");
+ Io_url url = Url_type(type);
+ return Io_mgr._.QueryFil(url).ModifiedTime();
+ }
+ public static Io_url Url_type(Class> type) {if (type == null) throw Err_.null_("type");
+ String codeBase = type.getProtectionDomain().getCodeSource().getLocation().getPath();
+ if (Op_sys.Cur().Tid_is_wnt())
+ codeBase = String_.Mid(codeBase, 1); // codebase always starts with /; remove for wnt
+ codeBase = String_.Replace(codeBase, "/", Op_sys.Cur().Fsys_dir_spr_str()); // java always returns DirSpr as /; change to Env_.DirSpr to handle windows
+ try {codeBase = java.net.URLDecoder.decode(codeBase, "UTF-8");}
+ catch (java.io.UnsupportedEncodingException e) {Err_.Noop(e);}
+ return Io_url_.new_fil_(codeBase);
+ }
+}
diff --git a/100_core/src_210_env/gplx/Op_sys.java b/100_core/src_210_env/gplx/Op_sys.java
new file mode 100644
index 000000000..69d997aea
--- /dev/null
+++ b/100_core/src_210_env/gplx/Op_sys.java
@@ -0,0 +1,79 @@
+/*
+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;
+public class Op_sys {
+ Op_sys(byte tid, byte sub_tid, String os_name, byte bitness, String nl_str, byte fsys_dir_spr_byte, boolean fsys_case_match, byte[] fsys_invalid_chars) {this.tid = tid; this.sub_tid = sub_tid; this.os_name = os_name; this.bitness = bitness; this.nl_str = nl_str; this.fsys_dir_spr_byte = fsys_dir_spr_byte; this.fsys_dir_spr_str = Char_.XtoStr((char)fsys_dir_spr_byte); this.fsys_case_match = fsys_case_match; this.fsys_invalid_chars = fsys_invalid_chars;}
+ public byte Tid() {return tid;} final byte tid;
+ public byte Sub_tid() {return sub_tid;} final byte sub_tid;
+ public String Os_name() {return os_name;} private String os_name;
+ public byte Bitness() {return bitness;} final byte bitness;
+ public String Nl_str() {return nl_str;} final String nl_str;
+ public String Fsys_dir_spr_str() {return fsys_dir_spr_str;} final String fsys_dir_spr_str;
+ public byte Fsys_dir_spr_byte() {return fsys_dir_spr_byte;} final byte fsys_dir_spr_byte;
+ public String Fsys_http_frag_to_url_str(String raw) {return fsys_dir_spr_byte == Byte_ascii.Slash ? raw : String_.Replace(raw, Lnx.Fsys_dir_spr_str(), fsys_dir_spr_str);}
+ public boolean Fsys_case_match() {return fsys_case_match;} final boolean fsys_case_match;
+ public byte[] Fsys_invalid_chars() {return fsys_invalid_chars;} final byte[] fsys_invalid_chars;
+ public String Fsys_case_match_str(String s) {return String_.CaseNormalize(fsys_case_match, s);}
+ public boolean Tid_is_wnt() {return tid == Tid_wnt;}
+ public boolean Tid_is_lnx() {return tid == Tid_lnx;}
+ public boolean Tid_is_osx() {return tid == Tid_osx;}
+ public boolean Tid_is_drd() {return tid == Tid_drd;}
+ public String Xto_str() {return os_name + (bitness == Bitness_32 ? "32" : "64");}
+
+ public static final byte Tid_nil = 0, Tid_wnt = 1, Tid_lnx = 2, Tid_osx = 3, Tid_drd = 4;
+ public static final byte Sub_tid_unknown = 0, Sub_tid_win_xp = 1, Sub_tid_win_7 = 2, Sub_tid_win_8 = 3;
+ public static final byte Bitness_32 = 1, Bitness_64 = 2;
+ public static final char Dir_spr_char_lnx = '\n';
+
+ public static final Op_sys Lnx = new_unx_flavor_(Tid_lnx, "linux", Bitness_32);
+ public static final Op_sys Osx = new_unx_flavor_(Tid_osx, "macosx", Bitness_32);
+ public static final Op_sys Drd = new_unx_flavor_(Tid_drd, "windows", Bitness_32);
+ public static final Op_sys Wnt = new_wnt_(Sub_tid_unknown, Bitness_32);
+ public static Op_sys Cur() {return cur_op_sys;} static Op_sys cur_op_sys = new_auto_identify_();
+ static Op_sys new_wnt_(byte bitness, byte sub_tid) {return new Op_sys(Tid_wnt , sub_tid , "windows", bitness, "\r\n", Byte_ascii.Backslash , Bool_.N, new byte[] {Byte_ascii.Slash, Byte_ascii.Backslash, Byte_ascii.Lt, Byte_ascii.Gt, Byte_ascii.Colon, Byte_ascii.Pipe, Byte_ascii.Question, Byte_ascii.Asterisk, Byte_ascii.Quote});}
+ static Op_sys new_unx_flavor_(byte tid, String os_name, byte bitness) {return new Op_sys(tid , Sub_tid_unknown , os_name , bitness, "\n" , Byte_ascii.Slash , Bool_.Y, new byte[] {Byte_ascii.Slash});}
+ static final String GRP_KEY = "gplx.op_sys";
+// public static Op_sys Cur_() {cur_op_sys = new_auto_identify_(); return cur_op_sys;}
+ static Op_sys new_auto_identify_() {
+ String os_name = "";
+ try {
+ String bitness_str = System.getProperty("sun.arch.data.model"); if (bitness_str == null) return Drd;
+ bitness_str = bitness_str.toLowerCase();
+ byte bitness_byte = Bitness_32;
+ if (String_.Eq(bitness_str, "32")) bitness_byte = Bitness_32;
+ else if (String_.Eq(bitness_str, "64")) bitness_byte = Bitness_64;
+ else throw Err_mgr._.fmt_(GRP_KEY, "unknown_bitness", "unknown bitness; expecting 32 or 64; System.getProperty(\"bit.level\") yielded ~{0}", bitness_str);
+
+ os_name = System.getProperty("os.name").toLowerCase();
+ if (String_.HasAtBgn(os_name, "win")) {
+ String os_version = System.getProperty("os.version").toLowerCase();// "Windows 7".equals(osName) && "6.1".equals(osVersion);
+ byte sub_tid = Sub_tid_unknown;
+ if (String_.Eq(os_name, "windows xp") && String_.Eq(os_version, "5.1")) sub_tid = Sub_tid_win_xp;
+ else if (String_.Eq(os_name, "windows 7") && String_.Eq(os_version, "6.1")) sub_tid = Sub_tid_win_7;
+ else if (String_.Eq(os_name, "windows 8")) sub_tid = Sub_tid_win_8;
+ return new_wnt_(bitness_byte, sub_tid);
+ }
+ else if (String_.Eq(os_name, "linux")) return new_unx_flavor_(Tid_lnx, os_name, bitness_byte);
+ else if (String_.HasAtBgn(os_name, "mac")) return new_unx_flavor_(Tid_osx, os_name, bitness_byte); // EX:Mac OS X
+ else throw Err_mgr._.fmt_(GRP_KEY, "unknown_os_name", "unknown os_name; expecting windows, linux, mac; System.getProperty(\"os.name\") yielded ~{0}", os_name);
+ } catch (Exception exc) {Drd.os_name = os_name; return Drd;}
+ }
+ public static void OpSysIsDroid() {
+ cur_op_sys = Drd;
+ }
+ }
diff --git a/100_core/src_210_env/gplx/ProcessAdp.java b/100_core/src_210_env/gplx/ProcessAdp.java
new file mode 100644
index 000000000..5bf9cfd76
--- /dev/null
+++ b/100_core/src_210_env/gplx/ProcessAdp.java
@@ -0,0 +1,344 @@
+/*
+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;
+import gplx.threads.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import javax.management.RuntimeErrorException;
+public class ProcessAdp implements GfoInvkAble, RlsAble {
+ public boolean Enabled() {return enabled;} public ProcessAdp Enabled_(boolean v) {enabled = v; return this;} private boolean enabled = true;
+ public byte Exe_exists() {return exe_exists;} public ProcessAdp Exe_exists_(byte v) {exe_exists = v; return this;} private byte exe_exists = Bool_.__byte;
+ public Io_url Exe_url() {return exe_url;} public ProcessAdp Exe_url_(Io_url val) {exe_url = val; exe_exists = Bool_.__byte; return this;} Io_url exe_url;
+ public String Args_str() {return args_str;} public ProcessAdp Args_str_(String val) {args_str = val; return this;} private String args_str = "";
+ public Bry_fmtr Args_fmtr() {return args_fmtr;} Bry_fmtr args_fmtr = Bry_fmtr.new_("");
+ public byte Run_mode() {return run_mode;} public ProcessAdp Run_mode_(byte v) {run_mode = v; return this;} private byte run_mode = Run_mode_sync_block;
+ public static final byte Run_mode_async = 0, Run_mode_sync_block = 1, Run_mode_sync_timeout = 2;
+ public int Exit_code() {return exit_code;} int exit_code;
+ public boolean Exit_code_pass() {return exit_code == Exit_pass;}
+ public String Rslt_out() {return rslt_out;} private String rslt_out;
+ public Io_url Working_dir() {return working_dir;} public ProcessAdp Working_dir_(Io_url v) {working_dir = v; return this;} Io_url working_dir;
+ public ProcessAdp Cmd_args(String cmd, String args) {this.Exe_url_(Io_url_.new_fil_(cmd)); this.args_fmtr.Fmt_(args); return this;}
+ public ProcessAdp WhenBgn_add(GfoInvkAbleCmd cmd) {whenBgnList.Add(cmd); return this;}
+ public ProcessAdp WhenBgn_del(GfoInvkAbleCmd cmd) {whenBgnList.Del(cmd); return this;}
+ public int Thread_timeout() {return thread_timeout;} public ProcessAdp Thread_timeout_seconds_(int v) {thread_timeout = v * 1000; return this;} int thread_timeout = 0;
+ public int Thread_interval() {return thread_interval;} public ProcessAdp Thread_interval_(int v) {thread_interval = v; return this;} int thread_interval = 20;
+ public String Thread_kill_name() {return thread_kill_name;} public ProcessAdp Thread_kill_name_(String v) {thread_kill_name = v; return this;} private String thread_kill_name = "";
+ public Io_url Tmp_dir() {return tmp_dir;} @gplx.Virtual public ProcessAdp Tmp_dir_(Io_url v) {tmp_dir = v; return this;} Io_url tmp_dir;
+ private ProcessAdp WhenBgn_run() {return Invk_cmds(whenBgnList);} ListAdp whenBgnList = ListAdp_.new_();
+ public ProcessAdp WhenEnd_add(GfoInvkAbleCmd cmd) {whenEndList.Add(cmd); return this;}
+ public ProcessAdp WhenEnd_del(GfoInvkAbleCmd cmd) {whenEndList.Del(cmd); return this;}
+ public Gfo_usr_dlg Prog_dlg() {return prog_dlg;} public ProcessAdp Prog_dlg_(Gfo_usr_dlg v) {prog_dlg = v; return this;} Gfo_usr_dlg prog_dlg;
+ public String Prog_fmt() {return prog_fmt;} public ProcessAdp Prog_fmt_(String v) {prog_fmt = v; return this;} private String prog_fmt = ""; // NOTE: set to "", else cmds that do not set prog_fmt will fail on fmtr.Fmt(null)
+ private GfoInvkAble owner;
+ private ProcessAdp WhenEnd_run() {return Invk_cmds(whenEndList);} ListAdp whenEndList = ListAdp_.new_();
+ private ProcessAdp Invk_cmds(ListAdp list) {
+ for (Object o : list)
+ ((GfoInvkAbleCmd)o).Invk();
+ return this;
+ }
+ public ProcessAdp Run(Object... args) {
+ if (String_.Len_eq_0(exe_url.Raw())) return this; // noop if exe_url is "";
+ if (!args_fmtr.Fmt_null()) {
+ Bry_bfr tmp_bfr = Bry_bfr.new_();
+ args_fmtr.Bld_bfr_many(tmp_bfr, args);
+ args_str = tmp_bfr.XtoStrAndClear();
+ }
+ prog_dlg.Log_many(GRP_KEY, "run", "running process: ~{0} ~{1}", exe_url.Raw(), args_str);
+ exit_code = Exit_init;
+ switch (run_mode) {
+ case Run_mode_async: return Run_async();
+ case Run_mode_sync_timeout: return Run_wait();
+ case Run_mode_sync_block: return Run_wait_sync();
+ default: throw Err_mgr._.unhandled_(run_mode);
+ }
+ }
+ public String[] X_to_process_bldr_args(String... args) {
+ String args_str = args_fmtr.Bld_str_many(args);
+ return X_to_process_bldr_args_utl(exe_url, args_str);
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk_enabled)) return enabled;
+ else if (ctx.Match(k, Invk_enabled_)) enabled = m.ReadBool("v");
+ else if (ctx.Match(k, Invk_cmd)) return exe_url.Raw();
+ else if (ctx.Match(k, Invk_cmd_)) this.Exe_url_(Bry_fmtr_eval_mgr_.Eval_url(cmd_url_eval, m.ReadBry("cmd")));
+ else if (ctx.Match(k, Invk_args)) return String_.new_utf8_(args_fmtr.Fmt());
+ else if (ctx.Match(k, Invk_args_)) args_fmtr.Fmt_(m.ReadBry("v"));
+ else if (ctx.Match(k, Invk_cmd_args_)) {this.Exe_url_(Bry_fmtr_eval_mgr_.Eval_url(cmd_url_eval, m.ReadBry("cmd"))); args_fmtr.Fmt_(m.ReadBry("args"));}
+ else if (ctx.Match(k, Invk_mode_)) run_mode = m.ReadByte("v");
+ else if (ctx.Match(k, Invk_timeout_)) thread_timeout = m.ReadInt("v");
+ else if (ctx.Match(k, Invk_tmp_dir_)) tmp_dir = m.ReadIoUrl("v");
+ else if (ctx.Match(k, Invk_owner)) return owner;
+ else return GfoInvkAble_.Rv_unhandled;
+ return this;
+ }
+ static final String Invk_cmd = "cmd", Invk_cmd_ = "cmd_", Invk_args = "args", Invk_args_ = "args_", Invk_cmd_args_ = "cmd_args_", Invk_enabled = "enabled", Invk_enabled_ = "enabled_", Invk_mode_ = "mode_", Invk_timeout_ = "timeout_", Invk_tmp_dir_ = "tmp_dir_", Invk_owner = "owner";
+ Bry_fmtr_eval_mgr cmd_url_eval;
+ public static ProcessAdp ini_(GfoInvkAble owner, Gfo_usr_dlg gui_wtr, ProcessAdp process, Bry_fmtr_eval_mgr cmd_url_eval, byte run_mode, int timeout, String cmd_url_fmt, String args_fmt, String... args_keys) {
+ process.Run_mode_(run_mode).Thread_timeout_seconds_(timeout);
+ process.cmd_url_eval = cmd_url_eval;
+ Io_url cmd_url = Bry_fmtr_eval_mgr_.Eval_url(cmd_url_eval, Bry_.new_utf8_(cmd_url_fmt));
+ process.Exe_url_(cmd_url).Tmp_dir_(cmd_url.OwnerDir());
+ process.Args_fmtr().Fmt_(args_fmt).Keys_(args_keys);
+ process.owner = owner;
+ process.Prog_dlg_(gui_wtr);
+ return process; // return process for chaining
+ }
+ public static String Escape_ampersands_if_process_is_cmd(boolean os_is_wnt, String exe_url, String exe_args) {
+ return ( os_is_wnt
+ && String_.Eq(exe_url, "cmd"))
+ ? String_.Replace(exe_args, "&", "^&") // escape ampersands
+ : exe_args
+ ;
+ }
+ private Bry_fmtr notify_fmtr = Bry_fmtr.new_("", "process_exe_name", "process_exe_args", "process_seconds"); Bry_bfr notify_bfr = Bry_bfr.reset_(255);
+ public Process UnderProcess() {return process;} Process process;
+ public void Rls() {if (process != null) process.destroy();}
+ public ProcessAdp Run_wait_sync() {
+ if (Env_.Mode_testing()) return Test_runs_add();
+ Process_bgn();
+ Process_start();
+ Process_run_and_end();
+ return this;
+ }
+ public ProcessAdp Run_start() {
+ if (Env_.Mode_testing()) return Test_runs_add();
+ Process_bgn();
+ Process_start();
+ return this;
+ }
+ public ProcessAdp Run_async() {
+ if (Env_.Mode_testing()) return Test_runs_add();
+ Process_bgn();
+ Thread_ProcessAdp_async thread = new Thread_ProcessAdp_async(this);
+ thread.start();
+ return this;
+ }
+ public ProcessAdp Run_wait() {
+ if (Env_.Mode_testing()) return Test_runs_add();
+ int notify_interval = 100; int notify_checkpoint = notify_interval;
+ int elapsed = 0;
+ try {
+ Process_bgn();
+ Thread_ProcessAdp_sync thread = new Thread_ProcessAdp_sync(this);
+ thread.start();
+ // thread_timeout = 15000;
+ boolean thread_run = false;
+ notify_fmtr.Fmt_(prog_fmt);
+ while (thread.isAlive()) {
+ thread_run = true;
+ long prv = Env_.TickCount();
+ ThreadAdp_.Sleep(thread_interval);
+// try {thread.join(thread_interval);}
+// catch (InterruptedException e) {throw Err_.err_key_(e, "gplx.ProcessAdp", "thread interrupted at join");}
+ long cur = Env_.TickCount();
+ int dif = (int)(cur - prv);
+ elapsed += dif;
+ if (prog_dlg != null) {
+ if (elapsed > notify_checkpoint) {
+ elapsed = notify_checkpoint;
+ notify_checkpoint += notify_interval;
+ notify_fmtr.Bld_bfr_many(notify_bfr, exe_url.NameAndExt(), args_str, elapsed / 1000);
+ prog_dlg.Prog_none(GRP_KEY, "notify.prog", notify_bfr.XtoStrAndClear());
+ }
+ }
+ if (thread_timeout == 0) break;
+ if (elapsed > thread_timeout) {
+ thread.interrupt();
+ thread.Cancel();
+ try {thread.join();}
+ catch (InterruptedException e) {throw Err_.err_key_(e, "gplx.ProcessAdp", "thread interrupted at timeout");}
+ break;
+ }
+ }
+ if (!thread_run) {
+ try {thread.join();}
+ catch (InterruptedException e) {throw Err_.err_key_(e, "gplx.ProcessAdp", "thread interrupted at join 2");}
+ }
+ } catch (Exception exc) {
+ Tfds.Write(Err_.Message_gplx_brief(exc));
+ }
+ if (elapsed != notify_checkpoint) {
+ notify_fmtr.Bld_bfr_many(notify_bfr, exe_url.NameAndExt(), args_str, elapsed / 1000);
+ if (prog_dlg != null) prog_dlg.Prog_none(GRP_KEY, "notify.prog", notify_bfr.XtoStrAndClear());
+ }
+ return this;
+ }
+ public synchronized void Process_post(String result) {
+ exit_code = process.exitValue();
+ rslt_out = result;
+ WhenEnd_run();
+ process.destroy();
+ }
+ String Kill() {
+ if (thread_kill_name == String_.Empty) return "";
+// Runtime rt = Runtime.getRuntime();
+ String kill_exe = "", kill_args = "";
+ if (Op_sys.Cur().Tid_is_wnt()) {
+ kill_exe = "taskkill";
+ kill_args = "/F /IM ";
+ }
+ else {
+ kill_exe = "kill";
+ kill_args = "-9 ";
+ }
+ kill_args += thread_kill_name;
+ ProcessAdp kill_process = new ProcessAdp().Exe_url_(Io_url_.new_fil_(kill_exe)).Args_str_(kill_args).Thread_kill_name_("");
+ boolean pass = kill_process.Run_wait().Exit_code_pass();
+ return "killed|" + kill_exe + "|" + kill_args + "|" + pass + "|" + exe_url.Raw() + "|" + args_str;
+ }
+ synchronized void Process_bgn() {
+ exit_code = Exit_init;
+ rslt_out = "";
+ WhenBgn_run();
+ pb = new ProcessBuilder(X_to_process_bldr_args_utl(exe_url, args_str));
+ pb.redirectErrorStream(true); // NOTE: need to redirectErrorStream or rdr.readLine() will hang; see inkscape and Ostfriesland Verkehr-de.svg
+ if (working_dir != null)
+ pb.directory(new File(working_dir.Xto_api()));
+ else if (!exe_url.OwnerDir().EqNull()) // only set workingDir if ownerDir is not null; NOTE: workingDir necessary for AdvMame; probably not a bad thing to do
+ pb.directory(new File(exe_url.OwnerDir().Xto_api()));
+ } ProcessBuilder pb;
+ Process Process_start() {
+ try {process = pb.start();}
+ catch (IOException e) {throw Err_.err_key_(e, "gplx.ProcessAdp", "thread start failed");}
+ return process;
+ }
+ void Process_run_and_end() {
+ String_bldr sb = String_bldr_.new_();
+ BufferedReader rdr = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ try {
+ String line = "";
+ while ((line = rdr.readLine()) != null)
+ sb.Add_str_w_crlf(line);
+ process.waitFor();
+ }
+ catch (InterruptedException e) {throw Err_.err_key_(e, "gplx.ProcessAdp", "thread interrupted at wait_for").Add("exe_url", exe_url.Xto_api()).Add("exeArgs", args_str);}
+ catch (IOException e) {throw Err_.err_key_(e, "gplx.ProcessAdp", "io error").Add("exe_url", exe_url.Xto_api()).Add("exeArgs", args_str);}
+ exit_code = process.exitValue();
+ WhenEnd_run();
+ process.destroy();
+ rslt_out = sb.XtoStrAndClear();
+ }
+ public void Process_term() {
+ try {
+ process.getInputStream().close();
+ process.getErrorStream().close();
+ } catch (IOException e) {}
+ process.destroy();
+ }
+ public static void run_wait_(Io_url url) {
+ ProcessAdp process = new ProcessAdp().Exe_url_(url);
+ process.Run_start();
+ process.Process_run_and_end();
+ return;
+ }
+ public static final ListAdp Test_runs = ListAdp_.new_();
+ private ProcessAdp Test_runs_add() {Test_runs.Add(exe_url.Raw() + " " + args_str); exit_code = Exit_pass; return this;}
+ public static int run_wait_arg_(Io_url url, String arg) {
+ ProcessAdp process = new ProcessAdp();
+ process.Exe_url_(url).Args_str_(arg).Run_wait();
+ return process.Exit_code();
+ }
+ private static final String GRP_KEY = "gplx.process";
+ public static final int Exit_pass = 0, Exit_init = -1;
+ public static String[] X_to_process_bldr_args_utl(Io_url exe_url, String args_str) {
+ ListAdp list = ListAdp_.new_();
+ list.Add(exe_url.Xto_api());
+ String_bldr sb = String_bldr_.new_();
+ int len = String_.Len(args_str);
+ boolean in_quotes = false;
+ for (int i = 0; i < len; i++) {
+ char c = String_.CharAt(args_str, i);
+ if (c == ' ' && !in_quotes) { // space encountered; assume arg done
+ list.Add(sb.XtoStr());
+ sb.Clear();
+ }
+ else if (c == '"') // NOTE: ProcessBuilder seems to have issues with quotes; do not call sb.Add()
+ in_quotes = !in_quotes;
+ else
+ sb.Add(c);
+ }
+ if (sb.Has_some()) list.Add(sb.XtoStr());
+ return list.XtoStrAry();
+ }
+}
+class Thread_ProcessAdp_async extends Thread {
+ public Thread_ProcessAdp_async(ProcessAdp process_adp) {this.process_adp = process_adp;} ProcessAdp process_adp;
+ public boolean Done() {return done;} boolean done = false;
+ public void Cancel() {process_adp.UnderProcess().destroy();}
+ public void run() {
+ process_adp.Run_wait();
+ }
+}
+class Thread_ProcessAdp_sync extends Thread {
+ public Thread_ProcessAdp_sync(ProcessAdp process_adp) {this.process_adp = process_adp;} ProcessAdp process_adp;
+ public boolean Done() {return done;} boolean done = false;
+ public void Cancel() {
+ process_adp.UnderProcess().destroy();
+ }
+ public synchronized void run() {
+ done = false;
+ Process process = process_adp.Process_start();
+ StreamGobbler input_gobbler = new StreamGobbler("input", process.getInputStream());
+ StreamGobbler error_gobbler = new StreamGobbler("error", process.getErrorStream());
+ input_gobbler.start();
+ error_gobbler.start();
+ try {process.waitFor();}
+ catch (InterruptedException e) {
+ this.Cancel();
+ String kill_rslt = process_adp.Kill();
+ process_adp.Process_post(kill_rslt);
+ done = false;
+ return;
+ }
+ while (input_gobbler.isAlive()) {
+ try {input_gobbler.join(50);}
+ catch (InterruptedException e) {throw Err_.err_key_(e, "gplx.ProcessAdp", "thread interrupted at input gobbler");}
+ }
+ while (error_gobbler.isAlive()) {
+ try {error_gobbler.join(50);}
+ catch (InterruptedException e) {throw Err_.err_key_(e, "gplx.ProcessAdp", "thread interrupted at error gobbler");}
+ }
+ String result = input_gobbler.Rslt() + "\n" + error_gobbler.Rslt();
+ process_adp.Process_post(result);
+ done = true;
+ }
+}
+class StreamGobbler extends Thread {
+ String name; InputStream stream;
+ public StreamGobbler (String name, InputStream stream) {this.name = name; this.stream = stream;}
+ public String Rslt() {return rslt;} String rslt;
+ public void run () {
+ try {
+ String_bldr sb = String_bldr_.new_();
+ InputStreamReader isr = new InputStreamReader(stream);
+ BufferedReader br = new BufferedReader(isr);
+ while (true) {
+ String s = br.readLine ();
+ if (s == null) break;
+ sb.Add(s);
+ }
+ stream.close();
+ rslt = sb.XtoStrAndClear();
+ }
+ catch (Exception ex) {throw Err_.new_fmt_("failed reading stream; name={0} ex={1}", name, Err_.Message_lang(ex));}
+ }
+}
diff --git a/100_core/src_210_env/gplx/ProcessAdp_tst.java b/100_core/src_210_env/gplx/ProcessAdp_tst.java
new file mode 100644
index 000000000..b3d28f380
--- /dev/null
+++ b/100_core/src_210_env/gplx/ProcessAdp_tst.java
@@ -0,0 +1,32 @@
+/*
+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;
+import org.junit.*;
+public class ProcessAdp_tst {
+ private ProcessAdp_fxt fxt = new ProcessAdp_fxt();
+ @Test public void Escape_ampersands_if_process_is_cmd() {
+ fxt.Test_Escape_ampersands_if_process_is_cmd(Bool_.Y, "cmd" , "/c \"http://a.org?b=c&d=e\"", "/c \"http://a.org?b=c^&d=e\"");
+ fxt.Test_Escape_ampersands_if_process_is_cmd(Bool_.Y, "cmd1", "/c \"http://a.org?b=c&d=e\"", "/c \"http://a.org?b=c&d=e\"");
+ fxt.Test_Escape_ampersands_if_process_is_cmd(Bool_.N, "cmd" , "/c \"http://a.org?b=c&d=e\"", "/c \"http://a.org?b=c&d=e\"");
+ }
+}
+class ProcessAdp_fxt {
+ public void Test_Escape_ampersands_if_process_is_cmd(boolean os_is_wnt, String exe_url, String exe_args, String expd) {
+ Tfds.Eq(expd, ProcessAdp.Escape_ampersands_if_process_is_cmd(os_is_wnt, exe_url, exe_args));
+ }
+}
diff --git a/100_core/src_210_env/gplx/threads/ThreadAdp.java b/100_core/src_210_env/gplx/threads/ThreadAdp.java
new file mode 100644
index 000000000..1c8c13f27
--- /dev/null
+++ b/100_core/src_210_env/gplx/threads/ThreadAdp.java
@@ -0,0 +1,49 @@
+/*
+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.threads; import gplx.*;
+import java.lang.*;
+public class ThreadAdp implements Runnable {
+ private String name; private GfoInvkAble invk; private String cmd; private GfoMsg msg;
+ @gplx.Internal protected ThreadAdp(String name, GfoInvkAble invk, String cmd, GfoMsg msg) {
+ this.name = name; this.invk = invk; this.cmd = cmd; this.msg = msg;
+ this.ctor_ThreadAdp();
+ }
+ public ThreadAdp Start() {thread.start(); return this;}
+ public void Interrupt() {thread.interrupt();}
+ public void Join() {
+ try {
+ thread.join();
+ }
+ catch (Exception e) {
+ Err_.Noop(e);
+ }
+ }
+// public void Stop() {thread.stop();}
+ public boolean IsAlive() {return thread.isAlive();}
+ void ctor_ThreadAdp() {
+ if (name == null)
+ thread = new Thread(this);
+ else
+ thread = new Thread(this, name);
+ }
+ @Override public void run() {
+ invk.Invk(GfsCtx._, 0, cmd, msg);
+ }
+ public Thread Under_thread() {return thread;} private Thread thread;
+ public static final ThreadAdp Null = new ThreadAdp(ThreadAdp_.Name_null, GfoInvkAble_.Null, "", GfoMsg_.Null);
+}
diff --git a/100_core/src_210_env/gplx/threads/ThreadAdp_.java b/100_core/src_210_env/gplx/threads/ThreadAdp_.java
new file mode 100644
index 000000000..6d4719e6d
--- /dev/null
+++ b/100_core/src_210_env/gplx/threads/ThreadAdp_.java
@@ -0,0 +1,31 @@
+/*
+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.threads; import gplx.*;
+public class ThreadAdp_ {
+ public static void Sleep(int milliseconds) {
+ try {Thread.sleep(milliseconds);} catch (InterruptedException e) {throw Err_.err_key_(e, "gplx.Thread", "thread interrupted").Add("milliseconds", milliseconds);}
+ }
+ public static ThreadAdp invk_(GfoInvkAble invk, String cmd) {return invk_(Name_null, invk, cmd);}
+ public static ThreadAdp invk_(String name, GfoInvkAble invk, String cmd) {return new ThreadAdp(name, invk, cmd, GfoMsg_.Null);}
+ public static ThreadAdp invk_msg_(GfoInvkAble invk, GfoMsg msg) {return invk_msg_(Name_null, invk, msg);}
+ public static ThreadAdp invk_msg_(String name, GfoInvkAble invk, GfoMsg msg) {return new ThreadAdp(name, invk, msg.Key(), msg);}
+ public static void Run_invk_msg(String name, GfoInvkAble invk, GfoMsg m) {
+ ThreadAdp_.invk_msg_(name, invk, m).Start();
+ }
+ public static final String Name_null = null;
+}
diff --git a/100_core/src_220_console/gplx/ConsoleAdp.java b/100_core/src_220_console/gplx/ConsoleAdp.java
new file mode 100644
index 000000000..4b8b0a912
--- /dev/null
+++ b/100_core/src_220_console/gplx/ConsoleAdp.java
@@ -0,0 +1,68 @@
+/*
+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;
+public class ConsoleAdp implements GfoInvkAble, ConsoleDlg {
+ public boolean Enabled() {return true;}
+ public boolean Canceled() {return canceled;} public void Canceled_set(boolean v) {canceled = v;} private boolean canceled = false;
+ public boolean CanceledChk() {if (canceled) throw Err_.op_canceled_usr_(); return canceled;}
+ public int CharsPerLineMax() {return chars_per_line_max;} public void CharsPerLineMax_set(int v) {chars_per_line_max = v;} int chars_per_line_max = 80;
+ public boolean Backspace_by_bytes() {return backspace_by_bytes;} public ConsoleAdp Backspace_by_bytes_(boolean v) {backspace_by_bytes = v; return this;} private boolean backspace_by_bytes;
+ public void WriteText(String s) {ClearTempText(); WriteText_lang(s);}
+ public void WriteLine(String s) {ClearTempText(); WriteLine_lang(s);}
+ public void WriteLineOnly() {ClearTempText(); WriteLine("");}
+ public void WriteLineFormat(String format, Object... args) {ClearTempText(); WriteLine_lang(String_.Format(format, args));}
+ public char ReadKey(String m) {WriteText(m); return ReadKey_lang();}
+ public String ReadLine(String m) {WriteText(m); return ReadLine_lang();}
+ public void WriteTempText(String s) {
+ ClearTempText();
+ if (String_.Has(s, "\r")) s = String_.Replace(s, "\r", " ");
+ if (String_.Has(s, "\n")) s = String_.Replace(s, "\n", " ");
+ if (String_.Len(s) >= chars_per_line_max) s = String_.Mid(s, 0, chars_per_line_max - String_.Len("...") - 1) + "..."; // NOTE: >= and -1 needed b/c line needs to be 1 less than max; ex: default cmd is 80 width, but writing 80 chars will automatically create lineBreak
+ tempText = s;
+ WriteText_lang(s);
+ } String tempText;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;}
+ void ClearTempText() {
+ if (tempText == null) return;
+ if (Env_.Mode_debug()) {WriteText_lang(String_.CrLf); return;}
+ int count = backspace_by_bytes ? Bry_.new_utf8_(tempText).length : String_.Len(tempText);
+ String moveBack = String_.Repeat("\b", count);
+ this.WriteText_lang(moveBack); // move cursor back to beginning of line
+ this.WriteText_lang(String_.Repeat(" ", count)); // overwrite tempText with space
+ this.WriteText_lang(moveBack); // move cursor back to beginning of line (so next Write will start at beginning)
+ tempText = null;
+ }
+ void WriteText_lang(String s) {System.out.print(s);}
+ void WriteLine_lang(String s) {System.out.println(s);}
+ String ReadLine_lang() {return System.console() == null ? "" : System.console().readLine();}
+ char ReadKey_lang() {
+ String text = ReadLine_lang();
+ return String_.Len(text) == 0 ? '\0' : String_.CharAt(text, 0);
+ }
+ public void WriteLine_utf8(String s) {
+ java.io.PrintStream ps;
+ try {ps = new java.io.PrintStream(System.out, true, "UTF-8");}
+ catch (java.io.UnsupportedEncodingException e) {throw Err_.new_("unsupported exception");}
+ ps.println(s);
+ }
+ public static final ConsoleAdp _ = new ConsoleAdp();
+ public ConsoleAdp() {
+ if (Op_sys.Cur().Tid_is_lnx())
+ backspace_by_bytes = true; // bash shows UTF8 by default; backspace in bytes, else multi-byte characters don't show; DATE:2014-03-04
+ }
+}
diff --git a/100_core/src_220_console/gplx/ConsoleDlg.java b/100_core/src_220_console/gplx/ConsoleDlg.java
new file mode 100644
index 000000000..74a79d3ea
--- /dev/null
+++ b/100_core/src_220_console/gplx/ConsoleDlg.java
@@ -0,0 +1,28 @@
+/*
+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;
+public interface ConsoleDlg {
+ boolean Enabled(); // optimization; allows Write to be skipped (since Write may Concat strings or generate arrays)
+ boolean CanceledChk();
+ int CharsPerLineMax(); void CharsPerLineMax_set(int v);
+ void WriteText(String s);
+ void WriteLineFormat(String s, Object... args);
+ void WriteTempText(String s);
+ char ReadKey(String msg);
+ String ReadLine(String msg);
+}
diff --git a/100_core/src_220_console/gplx/ConsoleDlg_.java b/100_core/src_220_console/gplx/ConsoleDlg_.java
new file mode 100644
index 000000000..39db2eaad
--- /dev/null
+++ b/100_core/src_220_console/gplx/ConsoleDlg_.java
@@ -0,0 +1,32 @@
+/*
+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;
+public class ConsoleDlg_ {
+ public static final ConsoleDlg Null = new ConsoleDlg_null();
+ public static ConsoleDlg_dev Dev() {return new ConsoleDlg_dev();}
+}
+class ConsoleDlg_null implements ConsoleDlg {
+ public boolean Enabled() {return false;}
+ public boolean CanceledChk() {return false;}
+ public int CharsPerLineMax() {return 80;} public void CharsPerLineMax_set(int v) {}
+ public void WriteText(String s) {}
+ public void WriteLineFormat(String s, Object... args) {}
+ public void WriteTempText(String s) {}
+ public char ReadKey(String msg) {return '\0';}
+ public String ReadLine(String msg) {return "";}
+}
diff --git a/100_core/src_220_console/gplx/ConsoleDlg_dev.java b/100_core/src_220_console/gplx/ConsoleDlg_dev.java
new file mode 100644
index 000000000..5c5405321
--- /dev/null
+++ b/100_core/src_220_console/gplx/ConsoleDlg_dev.java
@@ -0,0 +1,49 @@
+/*
+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;
+public class ConsoleDlg_dev implements ConsoleDlg {
+ public boolean Enabled() {return true;}
+ public boolean CanceledChk() {return false;}
+ public int CharsPerLineMax() {return 80;} public void CharsPerLineMax_set(int v) {}
+ public ConsoleDlg_dev Ignore_add(String s) {ignored.AddKeyVal(s); return this;}
+ public void WriteText(String s) {WriteString(s);}
+ public void WriteLineFormat(String s, Object... args) {WriteString(String_.Format(s, args) + String_.CrLf);}
+ public void WriteTempText(String s) {WriteString(s);}
+ public String ReadLine(String msg) {return "";}
+ public char ReadKey(String msg) {return '\0';}
+ public ConsoleDlg_dev CancelWhenTextWritten(String val) {
+ cancelVal = val;
+ return this;
+ }
+ void WriteString(String s) {
+ if (ignored.Has(s)) return;
+ written.Add(s);
+ if (cancelVal != null && String_.Has(s, cancelVal)) throw Err_.new_("canceled " + s + " " + cancelVal);
+ }
+ String cancelVal;
+
+ public ListAdp Written() {return written;}
+ public void tst_WrittenStr(String... expd) {
+ String[] actl = new String[written.Count()];
+ int actlLength = Array_.Len(actl);
+ for (int i = 0; i < actlLength; i++)
+ actl[i] = written.FetchAt(i).toString();
+ Tfds.Eq_ary(actl, expd);
+ }
+ ListAdp written = ListAdp_.new_(), erased = ListAdp_.new_(); HashAdp ignored = HashAdp_.new_();
+}
diff --git a/100_core/src_300_classXtn/gplx/BoolClassXtn.java b/100_core/src_300_classXtn/gplx/BoolClassXtn.java
new file mode 100644
index 000000000..f1136fc78
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/BoolClassXtn.java
@@ -0,0 +1,41 @@
+/*
+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;
+public class BoolClassXtn extends ClassXtn_base implements ClassXtn {
+ public static final String Key_const = "bo" + "ol";
+ public String Key() {return Key_const;}
+ @Override public Class> UnderClass() {return boolean.class;}
+ public Object DefaultValue() {return false;}
+ public boolean Eq(Object lhs, Object rhs) {try {return Bool_.cast_(lhs) == Bool_.cast_(rhs);} catch (Exception e) {Err_.Noop(e); return false;}}
+ @Override public Object ParseOrNull(String raw) {
+ if ( String_.Eq(raw, "true")
+ || String_.Eq(raw, "True") // needed for Store_Wtr() {boolVal.toString();}
+ || String_.Eq(raw, "1") // needed for db; gplx field for boolean is int; need simple way to convert from dbInt to langBool
+ )
+ return true;
+ else if
+ ( String_.Eq(raw, "false")
+ || String_.Eq(raw, "False")
+ || String_.Eq(raw, "0")
+ )
+ return false;
+ throw Err_.parse_type_(boolean.class, raw);
+ }
+ @Override public Object XtoDb(Object obj) {return obj;}
+ public static final BoolClassXtn _ = new BoolClassXtn(); BoolClassXtn() {} // added to ClassXtnPool by default
+}
\ No newline at end of file
diff --git a/100_core/src_300_classXtn/gplx/ByteClassXtn.java b/100_core/src_300_classXtn/gplx/ByteClassXtn.java
new file mode 100644
index 000000000..e3d48b4fe
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/ByteClassXtn.java
@@ -0,0 +1,28 @@
+/*
+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;
+public class ByteClassXtn extends ClassXtn_base implements ClassXtn {
+ public static final String Key_const = "byte";
+ public String Key() {return Key_const;}
+ @Override public Class> UnderClass() {return byte.class;}
+ public Object DefaultValue() {return 0;}
+ public boolean Eq(Object lhs, Object rhs) {try {return Byte_.cast_(lhs) == Byte_.cast_(rhs);} catch (Exception e) {Err_.Noop(e); return false;}}
+ @Override public Object ParseOrNull(String raw) {return raw == null ? (Object)null : Byte_.parse_(raw);}
+ @Override public Object XtoDb(Object obj) {return Byte_.cast_(obj);}
+ public static final ByteClassXtn _ = new ByteClassXtn(); ByteClassXtn() {} // added to ClassXtnPool by default
+}
\ No newline at end of file
diff --git a/100_core/src_300_classXtn/gplx/ClassXtn.java b/100_core/src_300_classXtn/gplx/ClassXtn.java
new file mode 100644
index 000000000..3732eb6e6
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/ClassXtn.java
@@ -0,0 +1,29 @@
+/*
+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;
+public interface ClassXtn {
+ String Key();
+ Class> UnderClass();
+ Object DefaultValue();
+ Object ParseOrNull(String raw);
+ Object XtoDb(Object obj);
+ String XtoUi(Object obj, String fmt);
+ boolean MatchesClass(Object obj);
+ boolean Eq(Object lhs, Object rhs);
+ int compareTo(Object lhs, Object rhs);
+}
diff --git a/100_core/src_300_classXtn/gplx/ClassXtnPool.java b/100_core/src_300_classXtn/gplx/ClassXtnPool.java
new file mode 100644
index 000000000..bd3584d4b
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/ClassXtnPool.java
@@ -0,0 +1,39 @@
+/*
+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;
+import gplx.lists.*;
+public class ClassXtnPool extends HashAdp_base {
+ public void Add(ClassXtn typx) {Add_base(typx.Key(), typx);}
+ public ClassXtn FetchOrFail(String key) {return (ClassXtn)FetchOrFail_base(key);}
+
+ public static final ClassXtnPool _ = new ClassXtnPool();
+ public static final String Format_null = "";
+ public static ClassXtnPool new_() {return new ClassXtnPool();}
+ ClassXtnPool() {
+ Add(ObjectClassXtn._);
+ Add(StringClassXtn._);
+ Add(IntClassXtn._);
+ Add(BoolClassXtn._);
+ Add(ByteClassXtn._);
+ Add(DateAdpClassXtn._);
+ Add(TimeSpanAdpClassXtn._);
+ Add(IoUrlClassXtn._);
+ Add(DecimalAdpClassXtn._);
+ Add(FloatClassXtn._);
+ }
+}
diff --git a/100_core/src_300_classXtn/gplx/ClassXtn_base.java b/100_core/src_300_classXtn/gplx/ClassXtn_base.java
new file mode 100644
index 000000000..2835d4355
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/ClassXtn_base.java
@@ -0,0 +1,28 @@
+/*
+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;
+public abstract class ClassXtn_base {
+ public abstract Class> UnderClass();
+ public abstract Object ParseOrNull(String raw);
+ @gplx.Virtual public Object XtoDb(Object obj) {return obj;}
+ @gplx.Virtual public String XtoUi(Object obj, String fmt) {return Object_.XtoStr_OrNullStr(obj);}
+ @gplx.Virtual public boolean MatchesClass(Object obj) {if (obj == null) throw Err_.null_("obj");
+ return ClassAdp_.Eq_typeSafe(obj, UnderClass());
+ }
+ @gplx.Virtual public int compareTo(Object lhs, Object rhs) {return CompareAble_.Compare_obj(lhs, rhs);}
+}
diff --git a/100_core/src_300_classXtn/gplx/DateAdpClassXtn.java b/100_core/src_300_classXtn/gplx/DateAdpClassXtn.java
new file mode 100644
index 000000000..dfadd0e85
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/DateAdpClassXtn.java
@@ -0,0 +1,28 @@
+/*
+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;
+public class DateAdpClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "datetime";
+ public boolean Eq(Object lhs, Object rhs) {try {return DateAdp_.cast_(lhs).Eq(DateAdp_.cast_(rhs));} catch (Exception e) {Err_.Noop(e); return false;}}
+ @Override public Class> UnderClass() {return DateAdp.class;}
+ public Object DefaultValue() {return DateAdp_.MinValue;}
+ @Override public Object ParseOrNull(String raw) {return DateAdp_.parse_gplx(raw);}
+ @Override public Object XtoDb(Object obj) {return DateAdp_.cast_(obj).XtoStr_gplx_long();}
+ @Override public String XtoUi(Object obj, String fmt) {return DateAdp_.cast_(obj).XtoStr_fmt(fmt);}
+ public static final DateAdpClassXtn _ = new DateAdpClassXtn(); DateAdpClassXtn() {} // added to ClassXtnPool by default
+}
diff --git a/100_core/src_300_classXtn/gplx/DateAdpClassXtn_tst.java b/100_core/src_300_classXtn/gplx/DateAdpClassXtn_tst.java
new file mode 100644
index 000000000..53204409e
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/DateAdpClassXtn_tst.java
@@ -0,0 +1,28 @@
+/*
+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;
+import org.junit.*;
+public class DateAdpClassXtn_tst {
+ @Test public void XtoDb() {
+ tst_XtoDb("20091115 220102.999", "2009-11-15 22:01:02.999");
+ }
+ void tst_XtoDb(String val, String expdRaw) {
+ String actlRaw = (String)DateAdpClassXtn._.XtoDb(DateAdp_.parse_gplx(val));
+ Tfds.Eq(expdRaw, actlRaw);
+ }
+}
diff --git a/100_core/src_300_classXtn/gplx/DecimalAdpClassXtn.java b/100_core/src_300_classXtn/gplx/DecimalAdpClassXtn.java
new file mode 100644
index 000000000..909846dc4
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/DecimalAdpClassXtn.java
@@ -0,0 +1,27 @@
+/*
+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;
+public class DecimalAdpClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "decimal"; // current dsv files reference "decimal"
+ @Override public Class> UnderClass() {return DecimalAdp.class;}
+ public Object DefaultValue() {return 0;}
+ public boolean Eq(Object lhs, Object rhs) {try {return DecimalAdp_.cast_(lhs).Eq(DecimalAdp_.cast_(rhs));} catch (Exception e) {Err_.Noop(e); return false;}}
+ @Override public Object ParseOrNull(String raw) {return DecimalAdp_.parse_(raw);}
+ @Override public String XtoUi(Object obj, String fmt) {return DecimalAdp_.cast_(obj).XtoStr();}
+ public static final DecimalAdpClassXtn _ = new DecimalAdpClassXtn(); DecimalAdpClassXtn() {} // added to ClassXtnPool by default
+}
diff --git a/100_core/src_300_classXtn/gplx/DoubleClassXtn.java b/100_core/src_300_classXtn/gplx/DoubleClassXtn.java
new file mode 100644
index 000000000..0bcc42366
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/DoubleClassXtn.java
@@ -0,0 +1,26 @@
+/*
+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;
+public class DoubleClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "double";
+ @Override public Class> UnderClass() {return double.class;}
+ public Object DefaultValue() {return 0;}
+ public boolean Eq(Object lhs, Object rhs) {try {return Double_.cast_(lhs) == Double_.cast_(rhs);} catch (Exception e) {Err_.Noop(e); return false;}}
+ @Override public Object ParseOrNull(String raw) {return Double_.parse_(raw);}
+ public static final DoubleClassXtn _ = new DoubleClassXtn(); DoubleClassXtn() {} // added to ClassXtnPool by default
+}
\ No newline at end of file
diff --git a/100_core/src_300_classXtn/gplx/FloatClassXtn.java b/100_core/src_300_classXtn/gplx/FloatClassXtn.java
new file mode 100644
index 000000000..094b193e6
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/FloatClassXtn.java
@@ -0,0 +1,26 @@
+/*
+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;
+public class FloatClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "float";
+ @Override public Class> UnderClass() {return float.class;}
+ public Object DefaultValue() {return 0;}
+ public boolean Eq(Object lhs, Object rhs) {try {return Float_.cast_(lhs) == Float_.cast_(rhs);} catch (Exception e) {Err_.Noop(e); return false;}}
+ @Override public Object ParseOrNull(String raw) {return Float_.parse_(raw);}
+ public static final FloatClassXtn _ = new FloatClassXtn(); FloatClassXtn() {} // added to ClassXtnPool by default
+}
\ No newline at end of file
diff --git a/100_core/src_300_classXtn/gplx/IntClassXtn.java b/100_core/src_300_classXtn/gplx/IntClassXtn.java
new file mode 100644
index 000000000..565241c55
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/IntClassXtn.java
@@ -0,0 +1,28 @@
+/*
+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;
+public class IntClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "int";
+ @Override public Class> UnderClass() {return Integer.class;}
+ public Object DefaultValue() {return 0;}
+ @Override public Object ParseOrNull(String raw) {return raw == null ? (Object)null : Int_.parse_(raw);}
+ public boolean Eq(Object lhs, Object rhs) {try {return Int_.cast_(lhs) == Int_.cast_(rhs);} catch (Exception e) {Err_.Noop(e); return false;}}
+ @Override public Object XtoDb(Object obj) {return Int_.cast_(obj);} // necessary for enums
+
+ public static final IntClassXtn _ = new IntClassXtn(); IntClassXtn() {} // added to ClassXtnPool by default
+}
diff --git a/100_core/src_300_classXtn/gplx/IoUrlClassXtn.java b/100_core/src_300_classXtn/gplx/IoUrlClassXtn.java
new file mode 100644
index 000000000..280d41786
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/IoUrlClassXtn.java
@@ -0,0 +1,29 @@
+/*
+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;
+public class IoUrlClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "ioPath";
+ @Override public Class> UnderClass() {return Io_url.class;}
+ public Object DefaultValue() {return Io_url_.Null;}
+ @Override public Object ParseOrNull(String raw) {return Io_url_.new_any_(raw);}
+ @Override public Object XtoDb(Object obj) {return Io_url_.cast_(obj).Raw();}
+ @Override public String XtoUi(Object obj, String fmt) {return Io_url_.cast_(obj).Raw();}
+ @Override public boolean MatchesClass(Object obj) {return Io_url_.as_(obj) != null;}
+ public boolean Eq(Object lhs, Object rhs) {try {return Io_url_.cast_(lhs).Eq(Io_url_.cast_(rhs));} catch (Exception e) {Err_.Noop(e); return false;}}
+ public static final IoUrlClassXtn _ = new IoUrlClassXtn(); IoUrlClassXtn() {} // added to ClassXtnPool by default
+}
diff --git a/100_core/src_300_classXtn/gplx/LongClassXtn.java b/100_core/src_300_classXtn/gplx/LongClassXtn.java
new file mode 100644
index 000000000..5981cd311
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/LongClassXtn.java
@@ -0,0 +1,27 @@
+/*
+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;
+public class LongClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "long";
+ @Override public Class> UnderClass() {return long.class;}
+ public Object DefaultValue() {return 0;}
+ public boolean Eq(Object lhs, Object rhs) {try {return Long_.cast_(lhs) == Long_.cast_(rhs);} catch (Exception e) {Err_.Noop(e); return false;}}
+ @Override public Object ParseOrNull(String raw) {return raw == null ? (Object)null : Long_.parse_(raw);}
+ @Override public Object XtoDb(Object obj) {return Long_.cast_(obj);} // necessary for enums
+ public static final LongClassXtn _ = new LongClassXtn(); LongClassXtn() {} // added to ClassXtnPool by default
+}
\ No newline at end of file
diff --git a/100_core/src_300_classXtn/gplx/ObjectClassXtn.java b/100_core/src_300_classXtn/gplx/ObjectClassXtn.java
new file mode 100644
index 000000000..878c16adc
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/ObjectClassXtn.java
@@ -0,0 +1,27 @@
+/*
+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;
+public class ObjectClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "Object";
+ @Override public Class> UnderClass() {return Object.class;}
+ public Object DefaultValue() {return null;}
+ @Override public Object ParseOrNull(String raw) {throw Err_.not_implemented_();}
+ @Override public Object XtoDb(Object obj) {throw Err_.not_implemented_();}
+ public boolean Eq(Object lhs, Object rhs) {return lhs == rhs;}
+ public static final ObjectClassXtn _ = new ObjectClassXtn(); ObjectClassXtn() {} // added to ClassXtnPool by default
+}
diff --git a/100_core/src_300_classXtn/gplx/StringClassXtn.java b/100_core/src_300_classXtn/gplx/StringClassXtn.java
new file mode 100644
index 000000000..03e9aca95
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/StringClassXtn.java
@@ -0,0 +1,28 @@
+/*
+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;
+public class StringClassXtn extends ClassXtn_base implements ClassXtn {
+ public static final String Key_const = "string";
+ public String Key() {return Key_const;}
+ @Override public Class> UnderClass() {return String.class;}
+ public Object DefaultValue() {return "";}
+ @Override public Object ParseOrNull(String raw) {return raw;}
+ @Override public String XtoUi(Object obj, String fmt) {return String_.as_(obj);}
+ public boolean Eq(Object lhs, Object rhs) {try {return String_.Eq(String_.cast_(lhs), String_.cast_(rhs));} catch (Exception e) {Err_.Noop(e); return false;}}
+ public static final StringClassXtn _ = new StringClassXtn(); StringClassXtn() {} // added to ClassXtnPool by default
+}
\ No newline at end of file
diff --git a/100_core/src_300_classXtn/gplx/TimeSpanAdpClassXtn.java b/100_core/src_300_classXtn/gplx/TimeSpanAdpClassXtn.java
new file mode 100644
index 000000000..014aa7a6d
--- /dev/null
+++ b/100_core/src_300_classXtn/gplx/TimeSpanAdpClassXtn.java
@@ -0,0 +1,28 @@
+/*
+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;
+public class TimeSpanAdpClassXtn extends ClassXtn_base implements ClassXtn {
+ public String Key() {return Key_const;} public static final String Key_const = "timeSpan";
+ @Override public Class> UnderClass() {return TimeSpanAdp.class;}
+ public Object DefaultValue() {return TimeSpanAdp_.Zero;}
+ @Override public Object ParseOrNull(String raw) {return TimeSpanAdp_.parse_(raw);}
+ @Override public Object XtoDb(Object obj) {return TimeSpanAdp_.cast_(obj).TotalSecs();}
+ @Override public String XtoUi(Object obj, String fmt) {return TimeSpanAdp_.cast_(obj).XtoStr(fmt);}
+ public boolean Eq(Object lhs, Object rhs) {try {return TimeSpanAdp_.cast_(lhs).Eq(rhs);} catch (Exception e) {Err_.Noop(e); return false;}}
+ public static final TimeSpanAdpClassXtn _ = new TimeSpanAdpClassXtn(); TimeSpanAdpClassXtn() {} // added to ClassXtnPool by default
+}
\ No newline at end of file
diff --git a/100_core/src_310_gfoNde/gplx/GfoFld.java b/100_core/src_310_gfoNde/gplx/GfoFld.java
new file mode 100644
index 000000000..74c808609
--- /dev/null
+++ b/100_core/src_310_gfoNde/gplx/GfoFld.java
@@ -0,0 +1,28 @@
+/*
+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;
+public class GfoFld {
+ public String Key() {return key;} private String key;
+ public ClassXtn Type() {return type;} ClassXtn type;
+ public static final GfoFld Null = new_(String_.Null_mark, ObjectClassXtn._);
+ public static GfoFld new_(String key, ClassXtn c) {
+ GfoFld rv = new GfoFld();
+ rv.key = key; rv.type = c;
+ return rv;
+ }
+}
diff --git a/100_core/src_310_gfoNde/gplx/GfoFldList.java b/100_core/src_310_gfoNde/gplx/GfoFldList.java
new file mode 100644
index 000000000..f38f6b6d5
--- /dev/null
+++ b/100_core/src_310_gfoNde/gplx/GfoFldList.java
@@ -0,0 +1,27 @@
+/*
+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;
+public interface GfoFldList {
+ int Count();
+ boolean Has(String key);
+ int IndexOf(String key);
+ GfoFld FetchAt(int i);
+ GfoFld FetchOrNull(String key);
+ GfoFldList Add(String key, ClassXtn c);
+ String XtoStr();
+}
diff --git a/100_core/src_310_gfoNde/gplx/GfoFldList_.java b/100_core/src_310_gfoNde/gplx/GfoFldList_.java
new file mode 100644
index 000000000..c66de4efc
--- /dev/null
+++ b/100_core/src_310_gfoNde/gplx/GfoFldList_.java
@@ -0,0 +1,62 @@
+/*
+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;
+public class GfoFldList_ {
+ public static final GfoFldList Null = new GfoFldList_null();
+ public static GfoFldList new_() {return new GfoFldList_base();}
+ public static GfoFldList str_(String... names) {
+ GfoFldList rv = new GfoFldList_base();
+ for (String name : names)
+ rv.Add(name, StringClassXtn._);
+ return rv;
+ }
+}
+class GfoFldList_base implements GfoFldList {
+ public int Count() {return hash.Count();}
+ public boolean Has(String key) {return hash.Has(key);}
+ public int IndexOf(String key) {
+ Object rv = idxs.Fetch(key);
+ return rv == null ? ListAdp_.NotFound : Int_.cast_(rv);
+ }
+ public GfoFld FetchAt(int i) {return (GfoFld)hash.FetchAt(i);}
+ public GfoFld FetchOrNull(String key) {return (GfoFld)hash.Fetch(key);}
+ public GfoFldList Add(String key, ClassXtn c) {
+ GfoFld fld = GfoFld.new_(key, c);
+ hash.Add(key, fld);
+ idxs.Add(key, idxs.Count());
+ return this;
+ }
+ public String XtoStr() {
+ String_bldr sb = String_bldr_.new_();
+ for (int i = 0; i < hash.Count(); i++) {
+ GfoFld fld = this.FetchAt(i);
+ sb.Add(fld.Key()).Add("|");
+ }
+ return sb.XtoStr();
+ }
+ OrderedHash hash = OrderedHash_.new_(); HashAdp idxs = HashAdp_.new_(); // PERF: idxs used for IndexOf; need to recalc if Del ever added
+}
+class GfoFldList_null implements GfoFldList {
+ public int Count() {return 0;}
+ public boolean Has(String key) {return false;}
+ public int IndexOf(String key) {return ListAdp_.NotFound;}
+ public GfoFld FetchAt(int i) {return GfoFld.Null;}
+ public GfoFld FetchOrNull(String key) {return null;}
+ public GfoFldList Add(String key, ClassXtn typx) {return this;}
+ public String XtoStr() {return "<>";}
+}
\ No newline at end of file
diff --git a/100_core/src_310_gfoNde/gplx/GfoNde.java b/100_core/src_310_gfoNde/gplx/GfoNde.java
new file mode 100644
index 000000000..672da927f
--- /dev/null
+++ b/100_core/src_310_gfoNde/gplx/GfoNde.java
@@ -0,0 +1,71 @@
+/*
+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;
+public class GfoNde implements GfoInvkAble {
+ public GfoFldList Flds() {return flds;} GfoFldList flds;
+ public HashAdp EnvVars() {return envVars;} HashAdp envVars = HashAdp_.new_();
+ public String Name() {return name;} public GfoNde Name_(String v) {name = v; return this;} private String name;
+ public Object ReadAt(int i) {ChkIdx(i); return ary[i];}
+ public void WriteAt(int i, Object val) {ChkIdx(i); ary[i] = val;}
+ public Object Read(String key) {int i = IndexOfOrFail(key); return ary[i];}
+ public void Write(String key, Object val) {int i = IndexOfOrFail(key); ary[i] = val;}
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return Read(k);}
+
+ public GfoNdeList Subs() {return subs;} GfoNdeList subs = GfoNdeList_.new_();
+ public GfoFldList SubFlds() {return subFlds;} GfoFldList subFlds = GfoFldList_.new_();
+ public void XtoStr_wtr(DataWtr wtr) {XtoStr_wtr(this, wtr);}// TEST
+ public String XtoStr() {
+ String_bldr sb = String_bldr_.new_();
+ for (int i = 0; i < aryLen; i++) {
+ String key = i >= flds.Count() ? "<< NULL " + i + " >>" : flds.FetchAt(i).Key();
+ String val = i >= aryLen ? "<< NULL " + i + " >>" : Object_.XtoStr_OrNullStr(ary[i]);
+ sb.Add(key).Add("=").Add(val);
+ }
+ return sb.XtoStr();
+ }
+ int IndexOfOrFail(String key) {
+ int i = flds.IndexOf(key);
+ if ((i < 0 || i >= aryLen)) throw Err_.new_("field name not found").Add("name", key).Add("index", i).Add("count", this.Flds().Count());
+ return i;
+ }
+ boolean ChkIdx(int i) {if (i < 0 || i >= aryLen) throw Err_.missing_idx_(i, aryLen); return true;}
+ Object[] ary; int type; int aryLen;
+ @gplx.Internal protected GfoNde(int type, String name, GfoFldList flds, Object[] ary, GfoFldList subFlds, GfoNde[] subAry) {
+ this.type = type; this.name = name; this.flds = flds; this.ary = ary; aryLen = Array_.Len(ary); this.subFlds = subFlds;
+ for (GfoNde sub : subAry)
+ subs.Add(sub);
+ }
+ static void XtoStr_wtr(GfoNde nde, DataWtr wtr) {
+ if (nde.type == GfoNde_.Type_Leaf) {
+ wtr.WriteLeafBgn("flds");
+ for (int i = 0; i < nde.ary.length; i++)
+ wtr.WriteData(nde.Flds().FetchAt(i).Key(), nde.ReadAt(i));
+ wtr.WriteLeafEnd();
+ }
+ else {
+ if (nde.type == GfoNde_.Type_Node) // never write node info for root
+ wtr.WriteTableBgn(nde.Name(), nde.SubFlds());
+ for (int i = 0; i < nde.Subs().Count(); i++) {
+ GfoNde sub = nde.Subs().FetchAt_asGfoNde(i);
+ XtoStr_wtr(sub, wtr);
+ }
+ if (nde.type == GfoNde_.Type_Node)
+ wtr.WriteNodeEnd();
+ }
+ }
+}
diff --git a/100_core/src_310_gfoNde/gplx/GfoNdeFxt.java b/100_core/src_310_gfoNde/gplx/GfoNdeFxt.java
new file mode 100644
index 000000000..d0cdb9300
--- /dev/null
+++ b/100_core/src_310_gfoNde/gplx/GfoNdeFxt.java
@@ -0,0 +1,35 @@
+/*
+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;
+public class GfoNdeFxt {
+ public GfoNde root_(GfoNde... subs) {return GfoNde_.root_(subs);}
+ public GfoNde tbl_(String name, GfoNde... rows) {return GfoNde_.tbl_(name, GfoFldList_.Null, rows);}
+ public GfoNde nde_(String name, GfoFldList flds, GfoNde... subs) {return GfoNde_.tbl_(name, flds, subs);}
+ public GfoNde row_(GfoFldList flds, Object... vals) {return GfoNde_.vals_(flds, vals);}
+ public GfoNde row_vals_(Object... vals) {return GfoNde_.vals_(GfoFldList_by_count_(vals.length), vals);}
+ public GfoNde csv_dat_(GfoNde... rows) {return GfoNde_.tbl_("", GfoFldList_.Null, rows);}
+ public GfoNde csv_hdr_(GfoFldList flds, GfoNde... rows) {return GfoNde_.tbl_("", flds, rows);}
+ public static GfoNdeFxt new_() {return new GfoNdeFxt();}
+
+ static GfoFldList GfoFldList_by_count_(int count) {
+ GfoFldList rv = GfoFldList_.new_();
+ for (int i = 0; i < count; i++)
+ rv.Add("fld" + Int_.XtoStr(i), StringClassXtn._);
+ return rv;
+ }
+}
diff --git a/100_core/src_310_gfoNde/gplx/GfoNdeList.java b/100_core/src_310_gfoNde/gplx/GfoNdeList.java
new file mode 100644
index 000000000..a23f6760c
--- /dev/null
+++ b/100_core/src_310_gfoNde/gplx/GfoNdeList.java
@@ -0,0 +1,27 @@
+/*
+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;
+import gplx.lists.*; /*ComparerAble*/
+public interface GfoNdeList {
+ int Count();
+ GfoNde FetchAt_asGfoNde(int index);
+ void Add(GfoNde rcd);
+ void Del(GfoNde rcd);
+ void Clear();
+ void SortBy(ComparerAble comparer);
+}
diff --git a/100_core/src_310_gfoNde/gplx/GfoNdeList_.java b/100_core/src_310_gfoNde/gplx/GfoNdeList_.java
new file mode 100644
index 000000000..6b73aa6b3
--- /dev/null
+++ b/100_core/src_310_gfoNde/gplx/GfoNdeList_.java
@@ -0,0 +1,40 @@
+/*
+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;
+import gplx.lists.*; /*ComparerAble*/
+public class GfoNdeList_ {
+ public static final GfoNdeList Null = new GfoNdeList_null();
+ public static GfoNdeList new_() {return new GfoNdeList_base();}
+}
+class GfoNdeList_base implements GfoNdeList {
+ public int Count() {return list.Count();}
+ public GfoNde FetchAt_asGfoNde(int i) {return (GfoNde)list.FetchAt(i);}
+ public void Add(GfoNde rcd) {list.Add(rcd);}
+ public void Del(GfoNde rcd) {list.Del(rcd);}
+ public void Clear() {list.Clear();}
+ public void SortBy(ComparerAble comparer) {list.SortBy(comparer);}
+ ListAdp list = ListAdp_.new_();
+}
+class GfoNdeList_null implements GfoNdeList {
+ public int Count() {return 0;}
+ public GfoNde FetchAt_asGfoNde(int index) {return null;}
+ public void Add(GfoNde rcd) {}
+ public void Del(GfoNde rcd) {}
+ public void Clear() {}
+ public void SortBy(ComparerAble comparer) {}
+}
diff --git a/100_core/src_310_gfoNde/gplx/GfoNde_.java b/100_core/src_310_gfoNde/gplx/GfoNde_.java
new file mode 100644
index 000000000..b9b256390
--- /dev/null
+++ b/100_core/src_310_gfoNde/gplx/GfoNde_.java
@@ -0,0 +1,46 @@
+/*
+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;
+public class GfoNde_ {
+ public static final GfoNde[] Ary_empty = new GfoNde[0];
+ public static GfoNde[] ary_(GfoNde... ary) {return ary;}
+ public static GfoNde as_(Object obj) {return obj instanceof GfoNde ? (GfoNde)obj : null;}
+ public static GfoNde root_(GfoNde... subs) {return new GfoNde(GfoNde_.Type_Root, "RootName", GfoFldList_.Null, Object_.Ary_empty, GfoFldList_.Null, subs);}
+ public static GfoNde tbl_(String name, GfoFldList flds, GfoNde... rows) {return new GfoNde(GfoNde_.Type_Node, name, flds, Object_.Ary_empty, flds, rows);}
+ public static GfoNde vals_(GfoFldList flds, Object[] ary) {return new GfoNde(GfoNde_.Type_Leaf, "row", flds, ary, GfoFldList_.Null, Ary_empty);}
+ public static GfoNde vals_params_(GfoFldList flds, Object... ary) {return new GfoNde(GfoNde_.Type_Leaf, "row", flds, ary, GfoFldList_.Null, Ary_empty);}
+ public static GfoNde nde_(String name, Object[] ary, GfoNde... subs) {return new GfoNde(GfoNde_.Type_Node, name, GfoFldList_.Null, ary, GfoFldList_.Null, subs);}
+ public static GfoNde rdr_(DataRdr rdr) {
+ try {
+ ListAdp rows = ListAdp_.new_();
+ GfoFldList flds = GfoFldList_.new_();
+ int fldLen = rdr.FieldCount();
+ for (int i = 0; i < fldLen; i++)
+ flds.Add(rdr.KeyAt(i), ObjectClassXtn._);
+ while (rdr.MoveNextPeer()) {
+ Object[] valAry = new Object[fldLen];
+ for (int i = 0; i < fldLen; i++)
+ valAry[i] = rdr.ReadAt(i);
+ rows.Add(GfoNde_.vals_(flds, valAry));
+ }
+ return GfoNde_.tbl_("", flds, (GfoNde[])rows.XtoAry(GfoNde.class));
+ }
+ finally {rdr.Rls();}
+ }
+ @gplx.Internal protected static final int Type_Leaf = 1, Type_Node = 2, Type_Root = 3;
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoEvMgr.java b/100_core/src_311_gfoObj/gplx/GfoEvMgr.java
new file mode 100644
index 000000000..3a1aa7fc3
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoEvMgr.java
@@ -0,0 +1,131 @@
+/*
+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;
+import gplx.lists.*;
+public class GfoEvMgr {
+ @gplx.Internal protected void AddSub(GfoEvMgrOwner pub, String pubEvt, GfoEvObj sub, String subPrc) {
+ GfoEvLnk lnk = new GfoEvLnk(pub, pubEvt, sub, subPrc);
+ if (subsRegy == null) subsRegy = OrderedHash_.new_();
+ AddInList(subsRegy, pubEvt, lnk);
+ sub.EvMgr().AddPub(pubEvt, lnk);
+ }
+ @gplx.Internal protected void Lnk(GfoEvMgrOwner pub) {
+ if (pub.EvMgr().lnks == null) pub.EvMgr().lnks = ListAdp_.new_();
+ pub.EvMgr().lnks.Add(this);
+ } ListAdp lnks;
+ void AddInList(OrderedHash regy, String key, GfoEvLnk lnk) {
+ GfoEvLnkList list = (GfoEvLnkList)regy.Fetch(key);
+ if (list == null) {
+ list = new GfoEvLnkList(key);
+ regy.Add(key, list);
+ }
+ list.Add(lnk);
+ }
+ @gplx.Internal protected void AddPub(String pubEvt, GfoEvLnk lnk) {
+ if (pubsRegy == null) pubsRegy = OrderedHash_.new_();
+ AddInList(pubsRegy, pubEvt, lnk);
+ }
+ @gplx.Internal protected void Pub(GfsCtx ctx, String evt, GfoMsg m) {
+ ctx.MsgSrc_(sender);
+ GfoEvLnkList subs = subsRegy == null ? null : (GfoEvLnkList)subsRegy.Fetch(evt);
+ if (subs != null) {
+ for (int i = 0; i < subs.Count(); i++) {
+ GfoEvLnk lnk = (GfoEvLnk)subs.FetchAt(i);
+ lnk.Sub().Invk(ctx, 0, lnk.SubPrc(), m); // NOTE: itm.Key() needed for Subscribe_diff()
+ }
+ }
+ if (lnks != null) {
+ for (int i = 0; i < lnks.Count(); i++) {
+ GfoEvMgr lnk = (GfoEvMgr)lnks.FetchAt(i);
+ lnk.Pub(ctx, evt, m);
+ }
+ }
+ }
+ @gplx.Internal protected void RlsSub(GfoEvMgrOwner eobj) {
+ RlsRegyObj(pubsRegy, eobj, true);
+ RlsRegyObj(subsRegy, eobj, false);
+ }
+ @gplx.Internal protected void RlsPub(GfoEvMgrOwner eobj) {
+ RlsRegyObj(pubsRegy, eobj, true);
+ RlsRegyObj(subsRegy, eobj, false);
+ }
+ @gplx.Internal protected void RlsRegyObj(OrderedHash regy, GfoEvMgrOwner eobj, boolean pub) {
+ if (regy == null) return;
+ ListAdp delList = ListAdp_.new_();
+ for (int i = 0; i < regy.Count(); i++) {
+ GfoEvLnkList pubsList = (GfoEvLnkList)regy.FetchAt(i);
+ delList.Clear();
+ for (int j = 0; j < pubsList.Count(); j++) {
+ GfoEvLnk lnk = (GfoEvLnk)pubsList.FetchAt(j);
+ if (lnk.End(!pub) == eobj) delList.Add(lnk);
+ }
+ for (int j = 0; j < delList.Count(); j++) {
+ GfoEvLnk del = (GfoEvLnk)delList.FetchAt(j);
+ del.End(pub).EvMgr().RlsLnk(!pub, pubsList.Key(), del.End(!pub));
+ pubsList.Del(del);
+ }
+ }
+ }
+ @gplx.Internal protected void RlsLnk(boolean pubEnd, String key, GfoEvMgrOwner endObj) {
+ OrderedHash regy = pubEnd ? pubsRegy : subsRegy;
+ GfoEvLnkList list = (GfoEvLnkList)regy.Fetch(key);
+ ListAdp delList = ListAdp_.new_();
+ for (int i = 0; i < list.Count(); i++) {
+ GfoEvLnk lnk = (GfoEvLnk)list.FetchAt(i);
+ if (lnk.End(pubEnd) == endObj) delList.Add(lnk);
+ }
+ for (int i = 0; i < delList.Count(); i++) {
+ GfoEvLnk lnk = (GfoEvLnk)delList.FetchAt(i);
+ list.Del(lnk);
+ }
+ delList.Clear();
+ }
+
+ Object sender; OrderedHash subsRegy, pubsRegy;
+ public static GfoEvMgr new_(Object sender) {
+ GfoEvMgr rv = new GfoEvMgr();
+ rv.sender = sender;
+ return rv;
+ } GfoEvMgr() {}
+}
+class GfoEvLnkList {
+ public String Key() {return key;} private String key;
+ public int Count() {return list.Count();}
+ public void Add(GfoEvLnk lnk) {list.Add(lnk);}
+ public void Del(GfoEvLnk lnk) {list.Del(lnk);}
+ public GfoEvLnk FetchAt(int i) {return (GfoEvLnk)list.FetchAt(i);}
+ public GfoEvLnkList(String key) {this.key = key;}
+ ListAdp list = ListAdp_.new_();
+}
+class GfoEvLnk {
+ public GfoEvMgrOwner Pub() {return pub;} GfoEvMgrOwner pub;
+ public String PubEvt() {return pubEvt;} private String pubEvt;
+ public GfoEvObj Sub() {return sub;} GfoEvObj sub;
+ public String SubPrc() {return subPrc;} private String subPrc;
+ public GfoEvMgrOwner End(boolean pubEnd) {return pubEnd ? pub : sub;}
+ public GfoEvLnk(GfoEvMgrOwner pub, String pubEvt, GfoEvObj sub, String subPrc) {this.pub = pub; this.pubEvt = pubEvt; this.sub = sub; this.subPrc = subPrc;}
+}
+class GfoEvItm {
+ public String Key() {return key;} private String key;
+ public GfoInvkAble InvkAble() {return invkAble;} GfoInvkAble invkAble;
+ public static GfoEvItm new_(GfoInvkAble invkAble, String key) {
+ GfoEvItm rv = new GfoEvItm();
+ rv.invkAble = invkAble; rv.key = key;
+ return rv;
+ }
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoEvMgrOwner.java b/100_core/src_311_gfoObj/gplx/GfoEvMgrOwner.java
new file mode 100644
index 000000000..d2cb940a2
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoEvMgrOwner.java
@@ -0,0 +1,21 @@
+/*
+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;
+public interface GfoEvMgrOwner {
+ GfoEvMgr EvMgr();
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoEvMgr_.java b/100_core/src_311_gfoObj/gplx/GfoEvMgr_.java
new file mode 100644
index 000000000..512584222
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoEvMgr_.java
@@ -0,0 +1,45 @@
+/*
+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;
+public class GfoEvMgr_ {
+ public static void Sub(GfoEvMgrOwner pub, String pubEvt, GfoEvObj sub, String subEvt) {pub.EvMgr().AddSub(pub, pubEvt, sub, subEvt);}
+ public static void SubSame(GfoEvMgrOwner pub, String evt, GfoEvObj sub) {pub.EvMgr().AddSub(pub, evt, sub, evt);}
+ public static void SubSame_many(GfoEvMgrOwner pub, GfoEvObj sub, String... evts) {
+ int len = evts.length;
+ for (int i = 0; i < len; i++) {
+ String evt = evts[i];
+ pub.EvMgr().AddSub(pub, evt, sub, evt);
+ }
+ }
+ public static void Pub(GfoEvMgrOwner pub, String pubEvt) {pub.EvMgr().Pub(GfsCtx.new_(), pubEvt, GfoMsg_.new_cast_(pubEvt));}
+ public static void PubObj(GfoEvMgrOwner pub, String pubEvt, String key, Object v) {pub.EvMgr().Pub(GfsCtx.new_(), pubEvt, msg_(pubEvt, KeyVal_.new_(key, v)));}
+ public static void PubVal(GfoEvMgrOwner pub, String pubEvt, Object v) {pub.EvMgr().Pub(GfsCtx.new_(), pubEvt, msg_(pubEvt, KeyVal_.new_("v", v)));}
+ public static void PubVals(GfoEvMgrOwner pub, String pubEvt, KeyVal... ary) {pub.EvMgr().Pub(GfsCtx.new_(), pubEvt, msg_(pubEvt, ary));}
+ public static void PubMsg(GfoEvMgrOwner pub, GfsCtx ctx, String pubEvt, GfoMsg m) {pub.EvMgr().Pub(ctx, pubEvt, m);}
+ public static void Lnk(GfoEvMgrOwner pub, GfoEvMgrOwner sub) {sub.EvMgr().Lnk(pub);}
+ public static void RlsPub(GfoEvMgrOwner pub) {pub.EvMgr().RlsPub(pub);}
+ public static void RlsSub(GfoEvMgrOwner sub) {sub.EvMgr().RlsSub(sub);}
+ static GfoMsg msg_(String evt, KeyVal... kvAry) {
+ GfoMsg m = GfoMsg_.new_cast_(evt);
+ for (int i = 0; i < kvAry.length; i++) {
+ KeyVal kv = kvAry[i];
+ m.Add(kv.Key(), kv.Val());
+ }
+ return m;
+ }
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoEvMgr_tst.java b/100_core/src_311_gfoObj/gplx/GfoEvMgr_tst.java
new file mode 100644
index 000000000..0763b0024
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoEvMgr_tst.java
@@ -0,0 +1,69 @@
+/*
+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;
+import org.junit.*;
+public class GfoEvMgr_tst {
+ @Before public void setup() {
+ pub = make_(); sub = make_();
+ } MockEvObj pub, sub;
+ @Test public void Basic() {
+ GfoEvMgr_.SubSame(pub, "ev1", sub);
+ GfoEvMgr_.PubVal(pub, "ev1", "val1");
+ sub.tst_Handled("val1");
+ }
+ @Test public void None() {// make sure no subscribers does not cause exception
+ GfoEvMgr_.SubSame(pub, "ev1", sub);
+ GfoEvMgr_.PubVal(pub, "ev2", "val1"); //ev2 does not exist
+ sub.tst_Handled();
+ }
+ @Test public void Lnk() {
+ MockEvObj mid = make_();
+ mid.EvMgr().Lnk(pub);
+ GfoEvMgr_.SubSame(mid, "ev1", sub);
+ GfoEvMgr_.PubVal(pub, "ev1", "val1");
+ sub.tst_Handled("val1");
+ }
+ @Test public void RlsSub() {
+ this.Basic();
+
+ GfoEvMgr_.RlsSub(sub);
+ GfoEvMgr_.PubVal(pub, "ev1", "val1");
+ sub.tst_Handled();
+ }
+ @Test public void RlsPub() {
+ this.Basic();
+
+ GfoEvMgr_.RlsSub(pub);
+ GfoEvMgr_.PubVal(pub, "ev1", "val1");
+ sub.tst_Handled();
+ }
+ MockEvObj make_() {return new MockEvObj();}
+}
+class MockEvObj implements GfoEvObj {
+ public GfoEvMgr EvMgr() {return eventMgr;} GfoEvMgr eventMgr;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ handled.Add(m.ReadStr("v"));
+ return this;
+ }
+ ListAdp handled = ListAdp_.new_();
+ public void tst_Handled(String... expd) {
+ Tfds.Eq_ary_str(expd, handled.XtoStrAry());
+ handled.Clear();
+ }
+ public MockEvObj(){eventMgr = GfoEvMgr.new_(this);}
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoEvObj.java b/100_core/src_311_gfoObj/gplx/GfoEvObj.java
new file mode 100644
index 000000000..2efe9ba3d
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoEvObj.java
@@ -0,0 +1,19 @@
+/*
+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;
+public interface GfoEvObj extends GfoInvkAble, GfoEvMgrOwner {}
diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkAble.java b/100_core/src_311_gfoObj/gplx/GfoInvkAble.java
new file mode 100644
index 000000000..5b734be57
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoInvkAble.java
@@ -0,0 +1,28 @@
+/*
+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;
+public interface GfoInvkAble {
+ Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m);
+}
+/*
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk_set)) {}
+ else return GfoInvkAble_.Rv_unhandled;
+ return this;
+ } private static final String Invk_set = "set";
+*/
diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkAbleCmd.java b/100_core/src_311_gfoObj/gplx/GfoInvkAbleCmd.java
new file mode 100644
index 000000000..fb85e50a2
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoInvkAbleCmd.java
@@ -0,0 +1,37 @@
+/*
+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;
+public class GfoInvkAbleCmd {
+ public GfoInvkAble InvkAble() {return invkAble;} GfoInvkAble invkAble;
+ public String Cmd() {return cmd;} private String cmd;
+ public Object Arg() {return arg;} Object arg;
+ public Object Invk() {
+ if (this == null) return GfoInvkAble_.Rv_unhandled;
+ return invkAble.Invk(GfsCtx._, 0, cmd, m);
+ }
+ GfoMsg m;
+
+ public static final GfoInvkAbleCmd Null = new GfoInvkAbleCmd();
+ public static GfoInvkAbleCmd new_(GfoInvkAble invkAble, String cmd) {return arg_(invkAble, cmd, null);}
+ public static GfoInvkAbleCmd arg_(GfoInvkAble invkAble, String cmd, Object arg) {
+ GfoInvkAbleCmd rv = new GfoInvkAbleCmd();
+ rv.invkAble = invkAble; rv.cmd = cmd; rv.arg = arg;
+ rv.m = (arg == null) ? GfoMsg_.Null : GfoMsg_.new_parse_(cmd).Add("v", arg);
+ return rv;
+ } GfoInvkAbleCmd() {}
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkAble_.java b/100_core/src_311_gfoObj/gplx/GfoInvkAble_.java
new file mode 100644
index 000000000..03cbf3893
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoInvkAble_.java
@@ -0,0 +1,36 @@
+/*
+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;
+public class GfoInvkAble_ {
+ public static GfoInvkAble as_(Object obj) {return obj instanceof GfoInvkAble ? (GfoInvkAble)obj : null;}
+ public static GfoInvkAble cast_(Object obj) {try {return (GfoInvkAble)obj;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, GfoInvkAble.class, obj);}}
+ public static final String_obj_val Rv_unhandled = String_obj_val.new_("Unhandled"), Rv_handled = String_obj_val.new_("Handled"), Rv_host = String_obj_val.new_("Host")
+ , Rv_cancel = String_obj_val.new_("Cancel"), Rv_error = String_obj_val.new_("Error");
+
+ public static Object InvkCmd(GfoInvkAble invk, String k) {return InvkCmd_msg(invk, k, GfoMsg_.Null);}
+ public static Object InvkCmd_val(GfoInvkAble invk, String k, Object v) {return InvkCmd_msg(invk, k, GfoMsg_.new_cast_(k).Add("v", v));}
+ public static Object InvkCmd_msg(GfoInvkAble invk, String k, GfoMsg m) {
+ Object rv = invk.Invk(GfsCtx._, 0, k, m);
+ if (rv == GfoInvkAble_.Rv_unhandled) throw Err_.new_("invkable did not handle message").Add("key", k);
+ return rv;
+ }
+ public static final GfoInvkAble Null = new GfoInvkAble_null();
+}
+class GfoInvkAble_null implements GfoInvkAble {
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;}
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgr.java b/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgr.java
new file mode 100644
index 000000000..88a27ff79
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgr.java
@@ -0,0 +1,67 @@
+/*
+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;
+public class GfoInvkCmdMgr {
+ public GfoInvkCmdMgr Add_cmd_many(GfoInvkAble invk, String... keys) {
+ for (String key : keys)
+ list.Add(GfoInvkCmdItm.new_(key, invk));
+ return this;
+ }
+ public GfoInvkCmdMgr Add_cmd(String key, GfoInvkAble invk) {
+ list.Add(GfoInvkCmdItm.new_(key, invk));
+ return this;
+ }
+ public GfoInvkCmdMgr Add_mgr(String key, GfoInvkAble invk) {
+ list.Add(GfoInvkCmdItm.new_(key, invk).Type_isMgr_(true));
+ return this;
+ }
+ public GfoInvkCmdMgr Add_xtn(GfoInvkAble xtn) {
+ list.Add(GfoInvkCmdItm.new_("xtn", xtn).Type_isXtn_(true));
+ return this;
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m, Object host) {
+ for (int i = 0; i < list.Count(); i++) {
+ GfoInvkCmdItm itm = (GfoInvkCmdItm)list.FetchAt(i);
+ if (itm.Type_isXtn()) {
+ Object invkVal = itm.Invk().Invk(ctx, ikey, k, m);
+ if (invkVal != GfoInvkAble_.Rv_unhandled) return invkVal;
+ }
+ if (!ctx.Match(k, itm.Key())) continue;
+ if (itm.Type_isMgr()) return itm.Invk();
+ Object rv = null;
+ m.Add("host", host);
+ rv = itm.Invk().Invk(ctx, ikey, k, m);
+ return rv == GfoInvkAble_.Rv_host ? host : rv; // if returning "this" return host
+ }
+ return Unhandled;
+ }
+ public static final String_obj_val Unhandled = String_obj_val.new_("GfoInvkCmdMgr Unhandled");
+ ListAdp list = ListAdp_.new_();
+ public static GfoInvkCmdMgr new_() {return new GfoInvkCmdMgr();} GfoInvkCmdMgr() {}
+}
+class GfoInvkCmdItm {
+ public String Key() {return key;} private String key;
+ public GfoInvkAble Invk() {return invk;} GfoInvkAble invk;
+ public boolean Type_isMgr() {return type_isMgr;} public GfoInvkCmdItm Type_isMgr_(boolean v) {type_isMgr = v; return this;} private boolean type_isMgr;
+ public boolean Type_isXtn() {return type_isXtn;} public GfoInvkCmdItm Type_isXtn_(boolean v) {type_isXtn = v; return this;} private boolean type_isXtn;
+ public static GfoInvkCmdItm new_(String key, GfoInvkAble invk) {
+ GfoInvkCmdItm rv = new GfoInvkCmdItm();
+ rv.key = key; rv.invk = invk;
+ return rv;
+ } GfoInvkCmdItm() {}
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgrOwner.java b/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgrOwner.java
new file mode 100644
index 000000000..37cbb9acc
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgrOwner.java
@@ -0,0 +1,21 @@
+/*
+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;
+public interface GfoInvkCmdMgrOwner {
+ GfoInvkCmdMgr InvkMgr();
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkRootWkr.java b/100_core/src_311_gfoObj/gplx/GfoInvkRootWkr.java
new file mode 100644
index 000000000..2c2189ce1
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoInvkRootWkr.java
@@ -0,0 +1,21 @@
+/*
+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;
+public interface GfoInvkRootWkr {
+ Object Run_str_for(GfoInvkAble invk, GfoMsg msg);
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkXtoStr.java b/100_core/src_311_gfoObj/gplx/GfoInvkXtoStr.java
new file mode 100644
index 000000000..e1985edf5
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoInvkXtoStr.java
@@ -0,0 +1,43 @@
+/*
+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;
+public class GfoInvkXtoStr {
+ public static GfoMsg ReadMsg(GfoInvkAble invk, String k) {
+ GfsCtx ctx = GfsCtx.wtr_();
+ GfoMsg m = GfoMsg_.rdr_(k);
+ invk.Invk(ctx, 0, k, m);
+ String invkKey = GfsCore._.FetchKey(invk);
+ GfoMsg root = GfoMsg_.new_cast_(invkKey);
+ root.Subs_add(m);
+ return root;
+ }
+ public static GfoMsg WriteMsg(GfoInvkAble invk, String k, Object... ary) {return WriteMsg(GfsCore._.FetchKey(invk), invk, k, ary);}
+ public static GfoMsg WriteMsg(String invkKey, GfoInvkAble invk, String k, Object... ary) {
+ GfsCtx ctx = GfsCtx.wtr_();
+ GfoMsg m = GfoMsg_.wtr_();
+ invk.Invk(ctx, 0, k, m);
+ GfoMsg rv = GfoMsg_.new_cast_(k);
+ for (int i = 0; i < m.Args_count(); i++) {
+ KeyVal kv = m.Args_getAt(i);
+ rv.Add(kv.Key(), ary[i]);
+ }
+ GfoMsg root = GfoMsg_.new_cast_(invkKey);
+ root.Subs_add(rv);
+ return root;
+ }
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoMsg.java b/100_core/src_311_gfoObj/gplx/GfoMsg.java
new file mode 100644
index 000000000..8263bf1f9
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoMsg.java
@@ -0,0 +1,70 @@
+/*
+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;
+public interface GfoMsg {
+ String Key();
+ GfoMsg CloneNew();
+ String XtoStr();
+ GfoMsg Clear();
+ GfoMsg Parse_(boolean v);
+
+ int Args_count();
+ KeyVal Args_getAt(int i);
+ GfoMsg Args_ovr(String k, Object v);
+ void Args_reset();
+ GfoMsg Add(String k, Object v);
+ int Subs_count();
+ GfoMsg Subs_getAt(int i);
+ GfoMsg Subs_add(GfoMsg m);
+ GfoMsg Subs_(GfoMsg... ary);
+
+ boolean ReadBool(String k);
+ boolean ReadBoolOr(String k, boolean or);
+ boolean ReadBoolOrFalse(String k);
+ boolean ReadBoolOrTrue(String k);
+ int ReadInt(String k);
+ int ReadIntOr(String k, int or);
+ long ReadLong(String k);
+ long ReadLongOr(String k, long or);
+ float ReadFloat(String k);
+ float ReadFloatOr(String k, float or);
+ double ReadDouble(String k);
+ double ReadDoubleOr(String k, double or);
+ DateAdp ReadDate(String k);
+ DateAdp ReadDateOr(String k, DateAdp or);
+ DecimalAdp ReadDecimal(String k);
+ DecimalAdp ReadDecimalOr(String k, DecimalAdp or);
+ String ReadStr(String k);
+ String ReadStrOr(String k, String or);
+ Io_url ReadIoUrl(String k);
+ Io_url ReadIoUrlOr(String k, Io_url url);
+ boolean ReadYn(String k);
+ boolean ReadYn_toggle(String k, boolean cur);
+ boolean ReadYnOrY(String k);
+ byte ReadByte(String k);
+ byte[] ReadBry(String k);
+ byte[] ReadBryOr(String k, byte[] or);
+ Object ReadObj(String k);
+ Object ReadObj(String k, ParseAble parseAble);
+ Object ReadObjOr(String k, ParseAble parseAble, Object or);
+ String[]ReadStrAry(String k, String spr);
+ String[]ReadStrAryIgnore(String k, String spr, String ignore);
+ Object ReadValAt(int i);
+ Object CastObj(String k);
+ Object CastObjOr(String k, Object or);
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoMsgUtl.java b/100_core/src_311_gfoObj/gplx/GfoMsgUtl.java
new file mode 100644
index 000000000..0e5e65dec
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoMsgUtl.java
@@ -0,0 +1,25 @@
+/*
+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;
+public class GfoMsgUtl {
+ public static int SetInt(GfsCtx ctx, GfoMsg m, int cur) {return ctx.Deny() ? cur : m.ReadIntOr("v", cur);}
+ public static boolean SetBool(GfsCtx ctx, GfoMsg m, boolean cur) {return ctx.Deny() ? cur : m.ReadBoolOr("v", cur);}
+ public static String SetStr(GfsCtx ctx, GfoMsg m, String cur) {return ctx.Deny() ? cur : m.ReadStrOr("v", cur);}
+ public static Io_url SetIoUrl(GfsCtx ctx, GfoMsg m, Io_url cur) {return ctx.Deny() ? cur : m.ReadIoUrlOr("v", cur);}
+ public static DecimalAdp SetDecimal(GfsCtx ctx, GfoMsg m, DecimalAdp cur) {return ctx.Deny() ? cur : m.ReadDecimalOr("v", cur);}
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoMsg_.java b/100_core/src_311_gfoObj/gplx/GfoMsg_.java
new file mode 100644
index 000000000..7752dbe9a
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoMsg_.java
@@ -0,0 +1,268 @@
+/*
+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;
+public class GfoMsg_ {
+ public static GfoMsg as_(Object obj) {return obj instanceof GfoMsg ? (GfoMsg)obj : null;}
+ public static final GfoMsg Null = new GfoMsg_base().ctor_("<>", false);
+ public static GfoMsg new_parse_(String key) {return new GfoMsg_base().ctor_(key, true);}
+ public static GfoMsg new_cast_(String key) {return new GfoMsg_base().ctor_(key, false);}
+ public static GfoMsg srl_(GfoMsg owner, String key) {
+ GfoMsg rv = new_parse_(key);
+ owner.Subs_add(rv);
+ return rv;
+ }
+ public static GfoMsg root_(String... ary) {return root_leafArgs_(ary);}
+ public static GfoMsg root_leafArgs_(String[] ary, KeyVal... kvAry) {
+ int len = Array_.Len(ary); if (len == 0) throw Err_arg.cannotBe_("== 0", "@len", len);
+ GfoMsg root = new GfoMsg_base().ctor_(ary[0], false);
+ GfoMsg owner = root;
+ for (int i = 1; i < len; i++) {
+ String key = ary[i];
+ GfoMsg cur = new GfoMsg_base().ctor_(key, false);
+ owner.Subs_add(cur);
+ owner = cur;
+ }
+ for (int i = 0; i < kvAry.length; i++) {
+ KeyVal kv = kvAry[i];
+ owner.Add(kv.Key(), kv.Val());
+ }
+ return root;
+ }
+ public static GfoMsg chain_(GfoMsg owner, String key) {
+ GfoMsg sub = owner;
+ ListAdp list = ListAdp_.new_();
+ list.Add(sub.Key());
+ while (sub != null) {
+ if (sub.Subs_count() == 0) break;
+ sub = (GfoMsg)sub.Subs_getAt(0);
+ list.Add(sub.Key());
+ }
+ list.Add(key);
+
+ GfoMsg root = GfoMsg_.new_parse_((String)list.FetchAt(0));
+ GfoMsg cur = root;
+ for (int i = 1; i < list.Count(); i++) {
+ String k = (String)list.FetchAt(i);
+ GfoMsg mm = GfoMsg_.new_parse_(k);
+ cur.Subs_add(mm);
+ cur = mm;
+ }
+ return root;
+ }
+ public static GfoMsg wtr_() {return new GfoMsg_wtr().ctor_("", false);}
+ public static GfoMsg rdr_(String cmd) {return new GfoMsg_rdr().ctor_(cmd, false);}
+ public static GfoMsg basic_(String cmd, Object... vals) {
+ GfoMsg rv = new_cast_(cmd);
+ int len = vals.length;
+ for (int i = 0; i < len; i++)
+ rv.Add("", vals[i]);
+ return rv;
+ }
+}
+class GfoMsg_wtr extends GfoMsg_base {
+ @Override protected Object ReadOr(String k, Object defaultOr) {
+ if (args == null) args = ListAdp_.new_();
+ args.Add(KeyVal_.new_(k, null));
+ return defaultOr;
+ }
+}
+class GfoMsg_rdr extends GfoMsg_base {
+ @Override protected Object ReadOr(String k, Object defaultOr) {
+ if (args == null) args = ListAdp_.new_();
+ args.Add(KeyVal_.new_(k, defaultOr));
+ return defaultOr;
+ }
+}
+class GfoMsg_base implements GfoMsg {
+ public String Key() {return key;} private String key;
+ public int Subs_count() {return subs == null ? 0 : subs.Count();}
+ public GfoMsg Subs_getAt(int i) {return subs == null ? null : (GfoMsg)subs.FetchAt(i);}
+ public GfoMsg Subs_add(GfoMsg m) {if (subs == null) subs = ListAdp_.new_(); subs.Add(m); return this;}
+ public GfoMsg Subs_(GfoMsg... ary) {for (GfoMsg m : ary) Subs_add(m); return this;}
+ public int Args_count() {return args == null ? 0 : args.Count();}
+ public void Args_reset() {
+ counter = 0;
+ Args_reset(this);
+ }
+ public GfoMsg Clear() {
+ this.Args_reset();
+ if (subs != null) subs.Clear();
+ if (args != null) args.Clear();
+ return this;
+ }
+ static void Args_reset(GfoMsg owner) {
+ int len = owner.Subs_count();
+ for (int i = 0; i < len; i++) {
+ GfoMsg sub = owner.Subs_getAt(i);
+ sub.Args_reset();
+ }
+ }
+ public KeyVal Args_getAt(int i) {return args == null ? null : (KeyVal)args.FetchAt(i);}
+ public GfoMsg Args_ovr(String k, Object v) {
+ if (args == null) args = ListAdp_.new_();
+ for (int i = 0; i < args.Count(); i++) {
+ KeyVal kv = (KeyVal)args.FetchAt(i);
+ if (String_.Eq(k, kv.Key())) {
+ kv.Val_(v);
+ return this;
+ }
+ }
+ args.Add(new KeyVal(KeyVal_.Key_tid_str, k, v));
+ return this;
+ }
+ public GfoMsg Parse_(boolean v) {parse = v; return this;}
+ public GfoMsg Add(String k, Object v) {
+ if (args == null) args = ListAdp_.new_();
+ args.Add(new KeyVal(KeyVal_.Key_tid_str, k, v));
+ return this;
+ }
+ public boolean ReadBool(String k) {Object rv = ReadOr(k,false); if (rv == Nil) ThrowNotFound(k); return parse ? Yn.parse_or_((String)rv, false) : Bool_.cast_(rv);}
+ public int ReadInt(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Int_.parse_((String)rv) : Int_.cast_(rv);}
+ public byte ReadByte(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Byte_.parse_((String)rv) : Byte_.cast_(rv);}
+ public long ReadLong(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Long_.parse_((String)rv) : Long_.cast_(rv);}
+ public float ReadFloat(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Float_.parse_((String)rv) : Float_.cast_(rv);}
+ public double ReadDouble(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Double_.parse_((String)rv) : Double_.cast_(rv);}
+ public DecimalAdp ReadDecimal(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? DecimalAdp_.parse_((String)rv) : DecimalAdp_.cast_(rv);}
+ public String ReadStr(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return (String)rv;}
+ public DateAdp ReadDate(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return parse ? DateAdp_.parse_gplx((String)rv) : DateAdp_.cast_(rv);}
+ public Io_url ReadIoUrl(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return parse ? Io_url_.new_any_((String)rv) : Io_url_.cast_(rv);}
+ public Object CastObj(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return rv;}
+ public boolean ReadBoolOr(String k, boolean or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Yn.parse_or_((String)rv, or) : Bool_.cast_(rv);}
+ public int ReadIntOr(String k, int or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Int_.parse_((String)rv) : Int_.cast_(rv);}
+ public long ReadLongOr(String k, long or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Long_.parse_((String)rv) : Long_.cast_(rv);}
+ public float ReadFloatOr(String k, float or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Float_.parse_((String)rv) : Float_.cast_(rv);}
+ public double ReadDoubleOr(String k,double or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Double_.parse_((String)rv) : Double_.cast_(rv);}
+ public DecimalAdp ReadDecimalOr(String k,DecimalAdp or) {Object rv = ReadOr(k, or); if (rv == Nil) return or ; return parse ? DecimalAdp_.parse_((String)rv) : DecimalAdp_.cast_(rv);}
+ public String ReadStrOr(String k, String or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return (String)rv;}
+ public DateAdp ReadDateOr(String k, DateAdp or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? DateAdp_.parse_gplx((String)rv) : DateAdp_.cast_(rv);}
+ public Io_url ReadIoUrlOr(String k, Io_url or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Io_url_.new_any_((String)rv) : Io_url_.cast_(rv);}
+ public boolean ReadBoolOrFalse(String k) {Object rv = ReadOr(k,false); if (rv == Nil) return false ; return parse ? Yn.parse_or_((String)rv, false) : Bool_.cast_(rv);}
+ public boolean ReadBoolOrTrue(String k) {Object rv = ReadOr(k, true); if (rv == Nil) return true ; return parse ? Yn.parse_or_((String)rv, true) : Bool_.cast_(rv);}
+ public boolean ReadYnOrY(String k) {Object rv = ReadOr(k, true); if (rv == Nil) return true ; return parse ? Yn.parse_or_((String)rv, true) : Bool_.cast_(rv);}
+ public boolean ReadYn(String k) {Object rv = ReadOr(k,false); if (rv == Nil) ThrowNotFound(k); return parse ? Yn.parse_or_((String)rv, false) : Yn.coerce_(rv);}
+ public boolean ReadYn_toggle(String k, boolean cur) {
+ Object rv = ReadOr(k, "!");
+ if (rv == Nil) ThrowNotFound(k);
+ if (!parse) throw Err_.new_("only parse supported");
+ String rv_str = (String)rv;
+ return (String_.Eq(rv_str, "!")) ? !cur : Yn.parse_(rv_str);
+ }
+ public byte[] ReadBry(String k) {Object rv = ReadOr(k,false); if (rv == Nil) ThrowNotFound(k); return parse ? Bry_.new_utf8_((String)rv) : (byte[])rv;}
+ public byte[] ReadBryOr(String k, byte[] or) {Object rv = ReadOr(k, or); if (rv == Nil) return or; return parse ? Bry_.new_utf8_((String)rv) : (byte[])rv;}
+ public Object CastObjOr(String k, Object or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return rv;}
+ public Object ReadObj(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return rv;}
+ public Object ReadObj(String k, ParseAble parseAble) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return parse ? parseAble.ParseAsObj((String)rv) : rv;}
+ public Object ReadObjOr(String k, ParseAble parseAble, Object or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? parseAble.ParseAsObj((String)rv) : rv;}
+ public String[] ReadStrAry(String k, String spr) {return String_.Split(ReadStr(k), spr);}
+ public String[] ReadStrAryIgnore(String k, String spr, String ignore) {return String_.Split(String_.Replace(ReadStr(k), ignore, ""), spr);}
+ public Object ReadValAt(int i) {return Args_getAt(i).Val();}
+ @gplx.Virtual protected Object ReadOr(String k, Object defaultOr) {
+ if (args == null) return Nil; // WORKAROUND.gfui: args null for DataBndr_whenEvt_execCmd
+ if (!String_.Eq(k, "")) {
+ for (int i = 0; i < args.Count(); i++) {
+ KeyVal kv = (KeyVal)args.FetchAt(i);
+ if (String_.Eq(k, kv.Key())) return kv.Val();
+ }
+ }
+ if (counter >= args.Count()) return Nil;
+ for (int i = 0; i < args.Count(); i++) {
+ KeyVal kv = (KeyVal)args.FetchAt(i);
+ if (String_.Eq(kv.Key(), "") && i >= counter) {
+ counter++;
+ return kv.Val();
+ }
+ }
+ return Nil;
+ } int counter = 0;
+ void ThrowNotFound(String k) {throw Err_.new_("arg not found in msg").Add("k", k).Add("counter", counter).Add("args", args);}
+ String ArgsXtoStr() {
+ if (this.Args_count() == 0) return "<>";
+ String_bldr sb = String_bldr_.new_();
+ for (int i = 0; i < this.Args_count(); i++) {
+ KeyVal rv = (KeyVal)this.Args_getAt(i);
+ sb.Add_fmt("{0};", rv.Key());
+ }
+ return sb.XtoStr();
+ }
+ public GfoMsg CloneNew() {
+ GfoMsg_base rv = new GfoMsg_base().ctor_(key, parse);
+ if (args != null) {
+ rv.args = ListAdp_.new_();
+ for (int i = 0; i < args.Count(); i++)
+ rv.args.Add(args.FetchAt(i));
+ }
+ if (subs != null) {
+ rv.subs = ListAdp_.new_();
+ for (int i = 0; i < args.Count(); i++) {
+ GfoMsg sub = (GfoMsg)args.FetchAt(i);
+ rv.subs.Add(sub.CloneNew()); // NOTE: recursion
+ }
+ }
+ return rv;
+ }
+
+ protected ListAdp args;
+ ListAdp subs;
+ public String XtoStr() {
+ String_bldr sb = String_bldr_.new_();
+ XtoStr(sb, new XtoStrWkr_gplx(), this);
+ return sb.XtoStrAndClear();
+ }
+ void XtoStr(String_bldr sb, XtoStrWkr wkr, GfoMsg m) {
+ sb.Add(m.Key());
+ if (m.Subs_count() == 0) {
+ sb.Add(":");
+ boolean first = true;
+ for (int i = 0; i < m.Args_count(); i++) {
+ KeyVal kv = m.Args_getAt(i);
+ if (kv.Val() == null) continue;
+ if (!first) sb.Add(" ");
+ sb.Add(kv.Key());
+ sb.Add("='");
+ sb.Add(wkr.XtoStr(kv.Val()));
+ sb.Add("'");
+ first = false;
+ }
+ sb.Add(";");
+ }
+ else {
+ sb.Add(".");
+ XtoStr(sb, wkr, m.Subs_getAt(0));
+ }
+ }
+
+ public GfoMsg_base ctor_(String key, boolean parse) {this.key = key; this.parse = parse; return this;} private boolean parse;
+ @gplx.Internal protected GfoMsg_base(){}
+ static final String_obj_val Nil = String_obj_val.new_("<>");
+}
+interface XtoStrWkr {
+ String XtoStr(Object o);
+}
+class XtoStrWkr_gplx implements XtoStrWkr {
+ public String XtoStr(Object o) {
+ if (o == null) return "<>";
+ Class> type = ClassAdp_.ClassOf_obj(o);
+ String rv = null;
+ if (type == String.class) rv = String_.cast_(o);
+ else if (Int_.TypeMatch(type)) return Int_.XtoStr(Int_.cast_(o));
+ else if (Bool_.TypeMatch(type)) return Yn.X_to_str(Bool_.cast_(o));
+ else if (type == DateAdp.class) return DateAdp_.cast_(o).XtoStr_gplx();
+ else rv = Object_.XtoStr_OrEmpty(o);
+ return String_.Replace(rv, "'", "''");
+ }
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoMsg_tst.java b/100_core/src_311_gfoObj/gplx/GfoMsg_tst.java
new file mode 100644
index 000000000..060679301
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoMsg_tst.java
@@ -0,0 +1,51 @@
+/*
+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;
+import org.junit.*;
+public class GfoMsg_tst {
+ @Before public void setup() {
+ GfsCore._.AddObj(new Mok(), "Mok");
+ }
+ @Test public void Write1() {
+ GfoMsg m = GfoMsg_.root_leafArgs_(String_.Ary("a", "b"), KeyVal_.new_("int0", 1));
+ tst_Msg(m, "a.b:int0='1';");
+ }
+ @Test public void Write() {
+ Mok mok = new Mok();
+ tst_Msg(GfoInvkXtoStr.WriteMsg(mok, Mok.Invk_Cmd0, true, 1, "a"), "Mok.Cmd0:bool0='y' int0='1' str0='a';");
+ mok.Int0 = 2;
+ mok.Bool0 = true;
+ mok.Str0 = "b";
+ tst_Msg(GfoInvkXtoStr.ReadMsg(mok, Mok.Invk_Cmd0), "Mok.Cmd0:bool0='y' int0='2' str0='b';");
+ }
+ void tst_Msg(GfoMsg m, String expd) {Tfds.Eq(expd, m.XtoStr());}
+ class Mok implements GfoInvkAble {
+ public boolean Bool0;
+ public int Int0;
+ public String Str0;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk_Cmd0)) {
+ Bool0 = m.ReadBoolOr("bool0", Bool0);
+ Int0 = m.ReadIntOr("int0", Int0);
+ Str0 = m.ReadStrOr("str0", Str0);
+ if (ctx.Deny()) return this;
+ }
+ return this;
+ } public static final String Invk_Cmd0 = "Cmd0";
+ }
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoTemplate.java b/100_core/src_311_gfoObj/gplx/GfoTemplate.java
new file mode 100644
index 000000000..fb301e880
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoTemplate.java
@@ -0,0 +1,21 @@
+/*
+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;
+public interface GfoTemplate {
+ Object NewCopy(GfoTemplate template);
+}
diff --git a/100_core/src_311_gfoObj/gplx/GfoTemplateFactory.java b/100_core/src_311_gfoObj/gplx/GfoTemplateFactory.java
new file mode 100644
index 000000000..3841966a9
--- /dev/null
+++ b/100_core/src_311_gfoObj/gplx/GfoTemplateFactory.java
@@ -0,0 +1,32 @@
+/*
+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;
+public class GfoTemplateFactory implements GfoInvkAble {
+ public void Reg(String key, GfoTemplate template) {hash.Add(key, template);}
+ public Object Make(String key) {
+ GfoTemplate template = (GfoTemplate)hash.Fetch(key);
+ return template.NewCopy(template);
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ ctx.Match(k, k);
+ Object o = hash.Fetch(k);
+ return o == null ? GfoInvkAble_.Rv_unhandled : o;
+ }
+ public static final GfoTemplateFactory _ = new GfoTemplateFactory(); GfoTemplateFactory() {}
+ HashAdp hash = HashAdp_.new_();
+}
diff --git a/100_core/src_330_store/gplx/DataRdr.java b/100_core/src_330_store/gplx/DataRdr.java
new file mode 100644
index 000000000..6f626581c
--- /dev/null
+++ b/100_core/src_330_store/gplx/DataRdr.java
@@ -0,0 +1,50 @@
+/*
+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;
+public interface DataRdr extends SrlMgr, RlsAble {
+ String NameOfNode(); String XtoStr();
+ Io_url Uri(); void Uri_set(Io_url s);
+ HashAdp EnvVars();
+ boolean Parse(); void Parse_set(boolean v);
+
+ int FieldCount();
+ String KeyAt(int i);
+ Object ReadAt(int i);
+ KeyVal KeyValAt(int i);
+
+ Object Read(String key);
+ String ReadStr(String key); String ReadStrOr(String key, String or);
+ byte[] ReadBryByStr(String key); byte[] ReadBryByStrOr(String key, byte[] or);
+ byte[] ReadBry(String key); byte[] ReadBryOr(String key, byte[] or);
+ char ReadChar(String key); char ReadCharOr(String key, char or);
+ int ReadInt(String key); int ReadIntOr(String key, int or);
+ boolean ReadBool(String key); boolean ReadBoolOr(String key, boolean or);
+ long ReadLong(String key); long ReadLongOr(String key, long or);
+ double ReadDouble(String key); double ReadDoubleOr(String key, double or);
+ float ReadFloat(String key); float ReadFloatOr(String key, float or);
+ byte ReadByte(String key); byte ReadByteOr(String key, byte or);
+ DecimalAdp ReadDecimal(String key); DecimalAdp ReadDecimalOr(String key, DecimalAdp or);
+ DateAdp ReadDate(String key); DateAdp ReadDateOr(String key, DateAdp or);
+ gplx.ios.Io_stream_rdr ReadRdr(String key);
+
+ boolean MoveNextPeer();
+ DataRdr Subs();
+ DataRdr Subs_byName(String name);
+ DataRdr Subs_byName_moveFirst(String name);
+ void XtoStr_gfml(String_bldr sb);
+}
diff --git a/100_core/src_330_store/gplx/DataRdr_.java b/100_core/src_330_store/gplx/DataRdr_.java
new file mode 100644
index 000000000..70a7d155c
--- /dev/null
+++ b/100_core/src_330_store/gplx/DataRdr_.java
@@ -0,0 +1,67 @@
+/*
+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;
+public class DataRdr_ {
+ public static final DataRdr Null = new DataRdr_null();
+ public static DataRdr as_(Object obj) {return obj instanceof DataRdr ? (DataRdr)obj : null;}
+ public static DataRdr cast_(Object obj) {try {return (DataRdr)obj;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, DataRdr.class, obj);}}
+}
+class DataRdr_null implements DataRdr {
+ public String NameOfNode() {return XtoStr();} public String XtoStr() {return "<< NULL READER >>";}
+ public boolean Type_rdr() {return true;}
+ public HashAdp EnvVars() {return HashAdp_.Null;}
+ public Io_url Uri() {return Io_url_.Null;} public void Uri_set(Io_url s) {}
+ public boolean Parse() {return parse;} public void Parse_set(boolean v) {parse = v;} private boolean parse;
+ public int FieldCount() {return 0;}
+ public String KeyAt(int i) {return XtoStr();}
+ public Object ReadAt(int i) {return null;}
+ public KeyVal KeyValAt(int i) {return KeyVal_.new_(this.KeyAt(i), this.ReadAt(i));}
+ public Object Read(String name) {return null;}
+ public String ReadStr(String key) {return String_.Empty;} public String ReadStrOr(String key, String or) {return or;}
+ public byte[] ReadBryByStr(String key) {return Bry_.Empty;} public byte[] ReadBryByStrOr(String key, byte[] or) {return or;}
+ public byte[] ReadBry(String key) {return Bry_.Empty;} public byte[] ReadBryOr(String key, byte[] or) {return or;}
+ public char ReadChar(String key) {return Char_.Null;} public char ReadCharOr(String key, char or) {return or;}
+ public int ReadInt(String key) {return Int_.MinValue;} public int ReadIntOr(String key, int or) {return or;}
+ public boolean ReadBool(String key) {return false;} public boolean ReadBoolOr(String key, boolean or) {return or;}
+ public long ReadLong(String key) {return Long_.MinValue;} public long ReadLongOr(String key, long or) {return or;}
+ public double ReadDouble(String key) {return Double_.NaN;} public double ReadDoubleOr(String key, double or) {return or;}
+ public float ReadFloat(String key) {return Float_.NaN;} public float ReadFloatOr(String key, float or) {return or;}
+ public byte ReadByte(String key) {return Byte_.MinValue;} public byte ReadByteOr(String key, byte or) {return or;}
+ public DecimalAdp ReadDecimal(String key) {return DecimalAdp_.Zero;}public DecimalAdp ReadDecimalOr(String key, DecimalAdp or) {return or;}
+ public DateAdp ReadDate(String key) {return DateAdp_.MinValue;} public DateAdp ReadDateOr(String key, DateAdp or) {return or;}
+ public gplx.ios.Io_stream_rdr ReadRdr(String key) {return gplx.ios.Io_stream_rdr_.Null;}
+ public boolean MoveNextPeer() {return false;}
+ public DataRdr Subs() {return this;}
+ public DataRdr Subs_byName(String name) {return this;}
+ public DataRdr Subs_byName_moveFirst(String name) {return this;}
+ public Object StoreRoot(SrlObj root, String key) {return null;}
+ public boolean SrlBoolOr(String key, boolean v) {return v;}
+ public byte SrlByteOr(String key, byte v) {return v;}
+ public int SrlIntOr(String key, int or) {return or;}
+ public long SrlLongOr(String key, long or) {return or;}
+ public String SrlStrOr(String key, String or) {return or;}
+ public DateAdp SrlDateOr(String key, DateAdp or) {return or;}
+ public DecimalAdp SrlDecimalOr(String key, DecimalAdp or) {return or;}
+ public double SrlDoubleOr(String key, double or) {return or;}
+ public Object SrlObjOr(String key, Object or) {return or;}
+ public void SrlList(String key, ListAdp list, SrlObj proto, String itmKey) {}
+ public void TypeKey_(String v) {}
+ public void XtoStr_gfml(String_bldr sb) {sb.Add_str_w_crlf("NULL:;");}
+ public SrlMgr SrlMgr_new(Object o) {return this;}
+ public void Rls() {}
+}
diff --git a/100_core/src_330_store/gplx/DataWtr.java b/100_core/src_330_store/gplx/DataWtr.java
new file mode 100644
index 000000000..dd829febd
--- /dev/null
+++ b/100_core/src_330_store/gplx/DataWtr.java
@@ -0,0 +1,32 @@
+/*
+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;
+public interface DataWtr extends SrlMgr {
+ HashAdp EnvVars();
+
+ void InitWtr(String key, Object val);
+ void WriteTableBgn(String name, GfoFldList fields);
+ void WriteNodeBgn(String nodeName);
+ void WriteLeafBgn(String leafName);
+ void WriteData(String name, Object val);
+ void WriteNodeEnd();
+ void WriteLeafEnd();
+
+ void Clear();
+ String XtoStr();
+}
diff --git a/100_core/src_330_store/gplx/DataWtr_.java b/100_core/src_330_store/gplx/DataWtr_.java
new file mode 100644
index 000000000..cc6e543c5
--- /dev/null
+++ b/100_core/src_330_store/gplx/DataWtr_.java
@@ -0,0 +1,48 @@
+/*
+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;
+import gplx.stores.*; /*DsvDataWtr_*/
+public class DataWtr_ {
+ public static final DataWtr Null = new DataWtr_null();
+}
+class DataWtr_null implements DataWtr {
+ public boolean Type_rdr() {return false;}
+ public HashAdp EnvVars() {return envVars;} HashAdp envVars = HashAdp_.new_();
+ public void InitWtr(String key, Object val) {}
+ public void WriteTableBgn(String name, GfoFldList fields) {}
+ public void WriteNodeBgn(String nodeName) {}
+ public void WriteLeafBgn(String leafName) {}
+ public void WriteData(String name, Object val) {}
+ public void WriteNodeEnd() {}
+ public void WriteLeafEnd() {}
+ public void Clear() {}
+ public String XtoStr() {return "";}
+ public Object StoreRoot(SrlObj root, String key) {return null;}
+ public boolean SrlBoolOr(String key, boolean v) {return v;}
+ public byte SrlByteOr(String key, byte v) {return v;}
+ public int SrlIntOr(String key, int or) {return or;}
+ public long SrlLongOr(String key, long or) {return or;}
+ public String SrlStrOr(String key, String or) {return or;}
+ public DateAdp SrlDateOr(String key, DateAdp or) {return or;}
+ public DecimalAdp SrlDecimalOr(String key, DecimalAdp or) {return or;}
+ public double SrlDoubleOr(String key, double or) {return or;}
+ public Object SrlObjOr(String key, Object or) {return or;}
+ public void SrlList(String key, ListAdp list, SrlObj proto, String itmKey) {}
+ public void TypeKey_(String v) {}
+ public SrlMgr SrlMgr_new(Object o) {return this;}
+}
diff --git a/100_core/src_330_store/gplx/DataWtr_base.java b/100_core/src_330_store/gplx/DataWtr_base.java
new file mode 100644
index 000000000..341f93eba
--- /dev/null
+++ b/100_core/src_330_store/gplx/DataWtr_base.java
@@ -0,0 +1,52 @@
+/*
+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;
+public abstract class DataWtr_base implements SrlMgr {
+ @gplx.Virtual public HashAdp EnvVars() {return envVars;} HashAdp envVars = HashAdp_.new_();
+ public boolean Type_rdr() {return false;}
+ public abstract void WriteData(String key, Object o);
+ public abstract void WriteNodeBgn(String nodeName);
+ public abstract void WriteNodeEnd();
+ @gplx.Virtual public void SrlList(String key, ListAdp list, SrlObj proto, String itmKey) {
+ this.WriteNodeBgn(key);
+ for (Object itmObj : list) {
+ SrlObj itm = (SrlObj)itmObj;
+ this.WriteNodeBgn(itmKey);
+ itm.SrlObj_Srl(this);
+ this.WriteNodeEnd();
+ }
+ this.WriteNodeEnd();
+ }
+ @gplx.Virtual public Object StoreRoot(SrlObj root, String key) {
+ this.WriteNodeBgn(key);
+ root.SrlObj_Srl(this);
+ this.WriteNodeEnd();
+ return root;
+ }
+ public boolean SrlBoolOr(String key, boolean v) {WriteData(key, v); return v;}
+ public byte SrlByteOr(String key, byte v) {WriteData(key, v); return v;}
+ public int SrlIntOr(String key, int or) {WriteData(key, or); return or;}
+ public long SrlLongOr(String key, long or) {WriteData(key, or); return or;}
+ public String SrlStrOr(String key, String or) {WriteData(key, or); return or;}
+ public DateAdp SrlDateOr(String key, DateAdp or) {WriteData(key, or.XtoStr_gplx()); return or;}
+ public DecimalAdp SrlDecimalOr(String key, DecimalAdp or) {WriteData(key, or.XtoDecimal()); return or;}
+ public double SrlDoubleOr(String key, double or) {WriteData(key, or); return or;}
+ public Object SrlObjOr(String key, Object or) {throw Err_.not_implemented_();}
+ public void TypeKey_(String v) {}
+ public abstract SrlMgr SrlMgr_new(Object o);
+}
diff --git a/100_core/src_330_store/gplx/SrlMgr.java b/100_core/src_330_store/gplx/SrlMgr.java
new file mode 100644
index 000000000..bb87432a8
--- /dev/null
+++ b/100_core/src_330_store/gplx/SrlMgr.java
@@ -0,0 +1,35 @@
+/*
+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;
+public interface SrlMgr {
+ boolean Type_rdr();
+ Object StoreRoot(SrlObj root, String key);
+
+ boolean SrlBoolOr(String key, boolean v);
+ byte SrlByteOr(String key, byte v);
+ int SrlIntOr(String key, int v);
+ long SrlLongOr(String key, long v);
+ String SrlStrOr(String key, String v);
+ double SrlDoubleOr(String key, double v);
+ DecimalAdp SrlDecimalOr(String key, DecimalAdp v);
+ DateAdp SrlDateOr(String key, DateAdp v);
+ Object SrlObjOr(String key, Object v);
+ void SrlList(String key, ListAdp list, SrlObj proto, String itmKey);
+ void TypeKey_(String v);
+ SrlMgr SrlMgr_new(Object o);
+}
diff --git a/100_core/src_330_store/gplx/SrlObj.java b/100_core/src_330_store/gplx/SrlObj.java
new file mode 100644
index 000000000..a2297a79d
--- /dev/null
+++ b/100_core/src_330_store/gplx/SrlObj.java
@@ -0,0 +1,22 @@
+/*
+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;
+public interface SrlObj {
+ SrlObj SrlObj_New(Object o);
+ void SrlObj_Srl(SrlMgr mgr);
+}
diff --git a/100_core/src_330_store/gplx/stores/DataRdr_base.java b/100_core/src_330_store/gplx/stores/DataRdr_base.java
new file mode 100644
index 000000000..eb8cd19ef
--- /dev/null
+++ b/100_core/src_330_store/gplx/stores/DataRdr_base.java
@@ -0,0 +1,213 @@
+/*
+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.stores; import gplx.*;
+public abstract class DataRdr_base implements SrlMgr {
+ public boolean Parse() {return parse;} public void Parse_set(boolean v) {parse = v;} private boolean parse;
+ public Io_url Uri() {return uri;} public void Uri_set(Io_url s) {uri = s;} Io_url uri = Io_url_.Null;
+ public abstract String NameOfNode();
+ public boolean Type_rdr() {return true;}
+ public HashAdp EnvVars() {return envVars;} HashAdp envVars = HashAdp_.new_();
+ public abstract Object Read(String key);
+ public abstract int FieldCount();
+ public abstract String KeyAt(int i);
+ public abstract Object ReadAt(int i);
+ @gplx.Virtual public KeyVal KeyValAt(int idx) {return KeyVal_.new_(this.KeyAt(idx), ReadAt(idx));}
+ public String ReadStr(String key) {
+ Object val = Read(key);
+ try {return (String)val;}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(String.class, key, val, exc);}
+ }
+ public String ReadStrOr(String key, String or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return (String)val;}
+ catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, String.class, key, val, or); return or;}
+ }
+ public byte[] ReadBryByStr(String key) {return Bry_.new_utf8_(ReadStr(key));}
+ public byte[] ReadBryByStrOr(String key, byte[] or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return Bry_.new_utf8_((String)val);}
+ catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, byte[].class, key, val, or); return or;}
+ }
+ @gplx.Virtual public void SrlList(String key, ListAdp list, SrlObj proto, String itmKey) {
+ list.Clear();
+ DataRdr subRdr = this.Subs_byName_moveFirst(key); // collection node
+ subRdr = subRdr.Subs();
+ while (subRdr.MoveNextPeer()) {
+ SrlObj itm = proto.SrlObj_New(null);
+ itm.SrlObj_Srl(subRdr);
+ list.Add(itm);
+ }
+ }
+ @gplx.Virtual public Object StoreRoot(SrlObj root, String key) {
+ SrlObj clone = root.SrlObj_New(null);
+ clone.SrlObj_Srl(this);
+ return clone;
+ }
+ public abstract DataRdr Subs_byName_moveFirst(String name);
+
+ public int ReadInt(String key) {
+ Object val = Read(key);
+ try {return (parse) ? Int_.parse_(String_.as_(val)) : Int_.cast_(val);}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(int.class, key, val, exc);}
+ }
+ public int ReadIntOr(String key, int or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return (parse) ? Int_.parse_(String_.as_(val)) : Int_.cast_(val);}
+ catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, int.class, key, val, or); return or;}
+ }
+ public long ReadLongOr(String key, long or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return (parse) ? Long_.parse_(String_.as_(val)) : Long_.cast_(val);}
+ catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, long.class, key, val, or); return or;}
+ }
+ @gplx.Virtual public boolean ReadBool(String key) {
+ Object val = Read(key);
+ try {return (parse) ? Bool_.cast_(BoolClassXtn._.ParseOrNull(String_.as_(val))) : Bool_.cast_(val);}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(boolean.class, key, val, exc);}
+ }
+ @gplx.Virtual public boolean ReadBoolOr(String key, boolean or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return (parse) ? Bool_.parse_(String_.as_(val)) : Bool_.cast_(val);}
+ catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, boolean.class, key, val, or); return or;}
+ }
+ public long ReadLong(String key) {
+ Object val = Read(key);
+ try {return (parse) ? Long_.parse_(String_.as_(val)) : Long_.cast_(val);}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(long.class, key, val, exc);}
+ }
+ public float ReadFloat(String key) {
+ Object val = Read(key);
+ try {return (parse) ? Float_.parse_(String_.as_(val)) : Float_.cast_(val);}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(float.class, key, val, exc);}
+ }
+ public float ReadFloatOr(String key, float or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return (parse) ? Float_.parse_(String_.as_(val)) : Float_.cast_(val);}
+ catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, float.class, key, val, or); return or;}
+ }
+ public double ReadDouble(String key) {
+ Object val = Read(key);
+ try {return (parse) ? Double_.parse_(String_.as_(val)) : Double_.cast_(val);}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(double.class, key, val, exc);}
+ }
+ public double ReadDoubleOr(String key, double or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return (parse) ? Double_.parse_(String_.as_(val)) : Double_.cast_(val);}
+ catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, double.class, key, val, or); return or;}
+ }
+ @gplx.Virtual public byte ReadByte(String key) {
+ Object val = Read(key);
+ try {return (parse) ? Byte_.parse_(String_.as_(val)) : Byte_.cast_(val);}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(byte.class, key, val, exc);}
+ }
+ @gplx.Virtual public byte ReadByteOr(String key, byte or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return (parse) ? Byte_.parse_(String_.as_(val)) : Byte_.cast_(val);}
+ catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, byte.class, key, val, or); return or;}
+ }
+ @gplx.Virtual public DateAdp ReadDate(String key) {
+ Object val = Read(key);
+ try {return (parse) ? DateAdp_.parse_gplx(String_.as_(val)) : (DateAdp)val;}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(DateAdp.class, key, val, exc);}
+ }
+ @gplx.Virtual public DateAdp ReadDateOr(String key, DateAdp or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return (parse) ? DateAdp_.parse_gplx(String_.as_(val)) : (DateAdp)val;}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(DateAdp.class, key, val, exc);}
+ }
+ @gplx.Virtual public DecimalAdp ReadDecimal(String key) {
+ Object val = Read(key);
+ try {
+ if (parse) return DecimalAdp_.parse_(String_.as_(val));
+ DecimalAdp rv = DecimalAdp_.as_(val);
+ return (rv == null)
+ ? DecimalAdp_.db_(val) // HACK: GfoNde_.rdr_ will call ReadAt(int i) on Db_data_rdr; since no Db_data_rdr knows about DecimalAdp, it will always return decimalType
+ : rv;
+ }
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(DecimalAdp.class, key, val, exc);}
+ }
+ @gplx.Virtual public DecimalAdp ReadDecimalOr(String key, DecimalAdp or) {
+ Object val = Read(key); if (val == null) return or;
+ try {
+ if (parse) return DecimalAdp_.parse_(String_.as_(val));
+ DecimalAdp rv = DecimalAdp_.as_(val);
+ return (rv == null)
+ ? DecimalAdp_.db_(val) // HACK: GfoNde_.rdr_ will call ReadAt(int i) on Db_data_rdr; since no Db_data_rdr knows about DecimalAdp, it will always return decimalType
+ : rv;
+ }
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(DecimalAdp.class, key, val, exc);}
+ }
+ public char ReadChar(String key) {
+ Object val = Read(key);
+ try {
+ if (parse) return Char_.parse_(String_.as_(val));
+ return Char_.cast_(val);
+ }
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(char.class, key, val, exc);}
+ }
+ public char ReadCharOr(String key, char or) {
+ Object val = Read(key); if (val == null) return or;
+ try {
+ if (parse) return Char_.parse_(String_.as_(val));
+ return Char_.cast_(val);
+ }
+ catch (Exception exc) {Err_.Noop(exc); return or;}
+ }
+ public byte[] ReadBry(String key) {
+ Object val = Read(key);
+ try {return (byte[])val;}
+ catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(byte[].class, key, val, exc);}
+ }
+ public byte[] ReadBryOr(String key, byte[] or) {
+ Object val = Read(key); if (val == null) return or;
+ try {return (byte[])val;}
+ catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, byte[].class, key, val, or); return or;}
+ }
+ public gplx.ios.Io_stream_rdr ReadRdr(String key) {return gplx.ios.Io_stream_rdr_.Null;}
+ public boolean SrlBoolOr(String key, boolean or) {return ReadBoolOr(key, or);}
+ public byte SrlByteOr(String key, byte or) {return ReadByteOr(key, or);}
+ public int SrlIntOr(String key, int or) {return ReadIntOr(key, or);}
+ public long SrlLongOr(String key, long or) {return ReadLongOr(key, or);}
+ public String SrlStrOr(String key, String or) {return ReadStrOr(key, or);}
+ public DateAdp SrlDateOr(String key, DateAdp or) {return ReadDateOr(key, or);}
+ public DecimalAdp SrlDecimalOr(String key, DecimalAdp or) {return ReadDecimalOr(key, or);}
+ public double SrlDoubleOr(String key, double or) {return ReadDoubleOr(key, or);}
+ public Object SrlObjOr(String key, Object or) {throw Err_.not_implemented_();}
+ public void XtoStr_gfml(String_bldr sb) {
+ sb.Add(this.NameOfNode()).Add(":");
+ for (int i = 0; i < this.FieldCount(); i++) {
+ KeyVal kv = this.KeyValAt(i);
+ if (i != 0) sb.Add(" ");
+ sb.Add_fmt("{0}='{1}'", kv.Key(), String_.Replace(kv.Val_to_str_or_empty(), "'", "\""));
+ }
+ sb.Add(";");
+ }
+ public abstract DataRdr Subs();
+ public void TypeKey_(String v) {}
+ public abstract SrlMgr SrlMgr_new(Object o);
+ static Err Err_dataRdr_ReadFailed_err(Class> type, String key, Object val, Exception inner) {
+ String innerMsg = inner == null ? "" : Err_.Message_lang(inner);
+ return Err_.new_key_("DataRdr_ReadFailed", "failed to read data").Add("key", key).Add("val", val).Add("type", type).Add("innerMsg", innerMsg);
+ }
+ static void Err_dataRdr_ReadFailed_useOr(Class> type, String key, Object val, Object or) {
+ UsrDlg_._.Warn(UsrMsg.new_("failed to read data; substituting default").Add("key", key).Add("val", val).Add("default", or).Add("type", type));
+ }
+ static void Err_dataRdr_ReadFailed_useOr(Exception exc, Class> type, String key, Object val, Object or) {
+ UsrDlg_._.Warn(UsrMsg.new_("failed to read data; substituting default").Add("key", key).Add("val", val).Add("default", or).Add("type", type));
+ }
+}
diff --git a/100_core/src_330_store/gplx/stores/DataRdr_mem.java b/100_core/src_330_store/gplx/stores/DataRdr_mem.java
new file mode 100644
index 000000000..7439b2814
--- /dev/null
+++ b/100_core/src_330_store/gplx/stores/DataRdr_mem.java
@@ -0,0 +1,78 @@
+/*
+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.stores; import gplx.*;
+public class DataRdr_mem extends DataRdr_base implements GfoNdeRdr {
+ @Override public String NameOfNode() {return cur.Name();}
+ public GfoNde UnderNde() {return cur;}
+ @Override public int FieldCount() {return flds.Count();}
+ @Override public String KeyAt(int i) {return flds.FetchAt(i).Key();}
+ @Override public Object ReadAt(int i) {return cur.ReadAt(i);}
+ @Override public Object Read(String key) {
+ int i = flds.IndexOf(key); if (i == ListAdp_.NotFound) return null;
+ return cur.ReadAt(i);
+ }
+ public boolean MoveNextPeer() {
+ if (++peerPos >= peerList.Count()) {
+ cur = null;
+ return false;
+ }
+ cur = peerList.FetchAt_asGfoNde(peerPos);
+ return true;
+ }
+ @Override public DataRdr Subs() {
+ if (cur == null && peerList.Count() == 0) return DataRdr_.Null;
+ return GfoNdeRdr_.peers_(Peers_get(), this.Parse());
+ }
+ public DataRdr Subs_byName(String name) {
+ if (cur == null && peerList.Count() == 0) return DataRdr_.Null;
+ String[] names = String_.Split(name, "/");
+ GfoNdeList list = GfoNdeList_.new_();
+ Subs_byName(list, names, 0, Peers_get());
+ return GfoNdeRdr_.peers_(list, this.Parse());
+ }
+ @Override public DataRdr Subs_byName_moveFirst(String name) {
+ DataRdr subRdr = Subs_byName(name);
+ boolean hasFirst = subRdr.MoveNextPeer();
+ return (hasFirst) ? subRdr : DataRdr_.Null;
+ }
+ public String XtoStr() {return cur.XtoStr();}
+ public void Rls() {this.cur = null; this.peerList = null;}
+ @Override public SrlMgr SrlMgr_new(Object o) {return new DataRdr_mem();}
+ GfoNdeList Peers_get() {
+ boolean initialized = cur == null && peerPos == -1 && peerList.Count() > 0; // initialized = no current, at bof, subs available
+ return initialized ? peerList.FetchAt_asGfoNde(0).Subs() : cur.Subs();
+ }
+ void Subs_byName(GfoNdeList list, String[] names, int depth, GfoNdeList peers) {
+ String name = names[depth];
+ for (int i = 0; i < peers.Count(); i++) {
+ GfoNde sub = peers.FetchAt_asGfoNde(i); if (sub == null) continue;
+ if (!String_.Eq(name, sub.Name())) continue;
+ if (depth == names.length - 1)
+ list.Add(sub);
+ else
+ Subs_byName(list, names, depth + 1, sub.Subs());
+ }
+ }
+
+ GfoNde cur; GfoNdeList peerList; int peerPos = -1; GfoFldList flds;
+ public static DataRdr_mem new_(GfoNde cur, GfoFldList flds, GfoNdeList peerList) {
+ DataRdr_mem rv = new DataRdr_mem();
+ rv.cur = cur; rv.peerList = peerList; rv.flds = flds;
+ return rv;
+ } @gplx.Internal protected DataRdr_mem() {}
+}
diff --git a/100_core/src_330_store/gplx/stores/GfoNdeRdr.java b/100_core/src_330_store/gplx/stores/GfoNdeRdr.java
new file mode 100644
index 000000000..e0547a337
--- /dev/null
+++ b/100_core/src_330_store/gplx/stores/GfoNdeRdr.java
@@ -0,0 +1,21 @@
+/*
+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.stores; import gplx.*;
+public interface GfoNdeRdr extends DataRdr {
+ GfoNde UnderNde();
+}
diff --git a/100_core/src_330_store/gplx/stores/GfoNdeRdr_.java b/100_core/src_330_store/gplx/stores/GfoNdeRdr_.java
new file mode 100644
index 000000000..3143ede58
--- /dev/null
+++ b/100_core/src_330_store/gplx/stores/GfoNdeRdr_.java
@@ -0,0 +1,48 @@
+/*
+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.stores; import gplx.*;
+public class GfoNdeRdr_ {
+ public static GfoNdeRdr kvs_(KeyValList kvList) {
+ GfoFldList flds = GfoFldList_.new_();
+ int pairsLen = kvList.Count();
+ Object[] vals = new Object[pairsLen];
+ for (int i = 0; i < pairsLen; i++) {
+ KeyVal pair = kvList.GetAt(i);
+ flds.Add(pair.Key(), StringClassXtn._);
+ vals[i] = pair.Val_to_str_or_empty();
+ }
+ GfoNde nde = GfoNde_.vals_(flds, vals);
+ return root_(nde, true);
+ }
+ public static GfoNdeRdr root_parseNot_(GfoNde root) {return root_(root, true);}
+ public static GfoNdeRdr root_(GfoNde root, boolean parse) {
+ DataRdr_mem rv = DataRdr_mem.new_(root, root.Flds(), root.Subs()); rv.Parse_set(parse);
+ return rv;
+ }
+ public static GfoNdeRdr leaf_(GfoNde cur, boolean parse) {
+ DataRdr_mem rv = DataRdr_mem.new_(cur, cur.Flds(), GfoNdeList_.Null); rv.Parse_set(parse);
+ return rv;
+ }
+ public static GfoNdeRdr peers_(GfoNdeList peers, boolean parse) {
+ GfoFldList flds = peers.Count() == 0 ? GfoFldList_.Null : peers.FetchAt_asGfoNde(0).Flds();
+ DataRdr_mem rv = DataRdr_mem.new_(null, flds, peers); rv.Parse_set(parse);
+ return rv;
+ }
+ public static GfoNdeRdr as_(Object obj) {return obj instanceof GfoNdeRdr ? (GfoNdeRdr)obj : null;}
+ public static GfoNdeRdr cast_(Object obj) {try {return (GfoNdeRdr)obj;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, GfoNdeRdr.class, obj);}}
+}
diff --git a/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr.java b/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr.java
new file mode 100644
index 000000000..ff92fb689
--- /dev/null
+++ b/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr.java
@@ -0,0 +1,77 @@
+/*
+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.stores.xmls; import gplx.*; import gplx.stores.*;
+import gplx.xmls.*; /*Xpath_*/
+public class XmlDataRdr extends DataRdr_base implements DataRdr {
+ @Override public String NameOfNode() {return nde.Name();} public String XtoStr() {return nde.Xml_outer();}
+ @Override public int FieldCount() {return nde.Atrs() == null ? 0 : nde.Atrs().Count();} // nde.Attributes == null when nde is XmlText; ex: val
+ @Override public String KeyAt(int i) {return nde.Atrs().FetchAt(i).Name();}
+ @Override public Object ReadAt(int i) {
+ XmlAtr attrib = nde.Atrs().FetchAt(i);
+ return (attrib == null) ? null : attrib.Value();
+ }
+ @Override public Object Read(String key) {
+ return nde.Atrs().FetchValOr(key, null);
+ }
+ public boolean MoveNextPeer() {
+ if (++pos >= peerList.Count()){ // moved out Of range
+ nde = null;
+ return false;
+ }
+ nde = peerList.FetchAt(pos);
+ return true;
+ }
+ @Override public DataRdr Subs() {
+ XmlNdeList list = Xpath_.SelectElements(nde);
+ XmlDataRdr rv = new XmlDataRdr();
+ rv.ctor_(list, null);
+ return rv;
+ }
+ @Override public DataRdr Subs_byName_moveFirst(String name) {
+ DataRdr subRdr = Subs_byName(name);
+ boolean hasFirst = subRdr.MoveNextPeer();
+ return (hasFirst) ? subRdr : DataRdr_.Null;
+ }
+ public DataRdr Subs_byName(String name) {
+ XmlNdeList list = Xpath_.SelectAll(nde, name);
+ XmlDataRdr rv = new XmlDataRdr();
+ rv.ctor_(list, null);
+ return rv;
+ }
+ public void Rls() {nde = null; peerList = null;}
+ public String NodeValue_get() {
+ if (nde.SubNdes().Count() != 1) return "";
+ XmlNde sub = nde.SubNdes().FetchAt(0);
+ return (sub.NdeType_textOrEntityReference()) ? sub.Text_inner() : "";
+ }
+ public String Node_OuterXml() {return nde.Xml_outer();}
+ @Override public SrlMgr SrlMgr_new(Object o) {return new XmlDataRdr();}
+ void LoadString(String raw) {
+ XmlDoc xdoc = XmlDoc_.parse_(raw);
+ XmlNdeList list = Xpath_.SelectElements(xdoc.Root());
+ ctor_(list, xdoc.Root());
+ }
+ void ctor_(XmlNdeList peerList, XmlNde nde) {
+ this.peerList = peerList; this.nde = nde; pos = -1;
+ }
+
+ XmlNde nde = null;
+ XmlNdeList peerList = null; int pos = -1;
+ @gplx.Internal protected XmlDataRdr(String raw) {this.LoadString(raw); this.Parse_set(true);}
+ XmlDataRdr() {this.Parse_set(true);}
+}
diff --git a/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr_.java b/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr_.java
new file mode 100644
index 000000000..ddcfad373
--- /dev/null
+++ b/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr_.java
@@ -0,0 +1,25 @@
+/*
+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.stores.xmls; import gplx.*; import gplx.stores.*;
+public class XmlDataRdr_ {
+ public static XmlDataRdr file_(Io_url url) {
+ String text = Io_mgr._.LoadFilStr(url);
+ return new XmlDataRdr(text);
+ }
+ public static XmlDataRdr text_(String text) {return new XmlDataRdr(text);}
+}
diff --git a/100_core/src_330_store/gplx/stores/xmls/XmlDataWtr_.java b/100_core/src_330_store/gplx/stores/xmls/XmlDataWtr_.java
new file mode 100644
index 000000000..1674e8b2e
--- /dev/null
+++ b/100_core/src_330_store/gplx/stores/xmls/XmlDataWtr_.java
@@ -0,0 +1,112 @@
+/*
+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.stores.xmls; import gplx.*; import gplx.stores.*;
+public class XmlDataWtr_ {
+ public static DataWtr new_() {return XmlDataWtr.new_();}
+}
+class XmlDataWtr extends DataWtr_base implements DataWtr {
+ public void InitWtr(String key, Object val) {}
+ @Override public void WriteData(String name, Object val) {
+// if (val == null) return;
+ String valString = Object_.XtoStr_OrEmpty(val);
+ int valStringLen = String_.Len(valString);
+ sb.Add(" ").Add(name).Add("=\"");
+ for (int i = 0; i < valStringLen; i++) {
+ char c = String_.CharAt(valString, i);
+ if (c == '<') sb.Add("<");
+ else if (c == '>') sb.Add(">");
+ else if (c == '&') sb.Add("&");
+ else if (c == '\"') sb.Add(""e;");
+ else sb.Add(c);
+ }
+ sb.Add("\"");
+// XmlAttribute atr = doc.CreateAttribute(name);
+// atr.Value = (val == null) ? String_.Empty : val.toString();
+// nde.Attributes.Append(atr);
+ }
+ public void WriteLeafBgn(String leafName) {this.WriteXmlNodeBegin(leafName);}
+ public void WriteLeafEnd() {}
+ public void WriteTableBgn(String name, GfoFldList fields) {this.WriteXmlNodeBegin(name);}
+ @Override public void WriteNodeBgn(String nodeName) {this.WriteXmlNodeBegin(nodeName);}
+ @Override public void WriteNodeEnd() {this.WriteXmlNodeEnd();}
+ public String XtoStr() {
+ while (names.Count() > 0) {
+ WriteXmlNodeEnd();
+ }
+ return sb.XtoStr();
+// while (nde.ParentNode != null)
+// WriteXmlNodeEnd(); // close all open ndes automatically
+// return doc.OuterXml;
+ }
+ public void WriteComment(String comment) {
+ sb.Add("");
+// XmlComment xmlComment = doc.CreateComment(comment);
+// nde.AppendChild(xmlComment);
+ }
+ public void Clear() {
+ sb.Clear();
+// doc = new XmlDocument();
+ }
+ void WriteXmlNodeBegin(String name) {
+ if (ndeOpened) {
+ sb.Add(">" + String_.CrLf);
+ }
+ ndeOpened = true;
+ names.Add(name);
+ sb.Add("<" + name);
+// XmlNode owner = nde;
+// nde = doc.CreateElement(name);
+// if (owner == null) // first call to WriteXmlNodeBegin(); append child to doc
+// doc.AppendChild(nde);
+// else {
+// WriteLineFeedIfNeeded(doc, owner);
+// owner.AppendChild(nde);
+// }
+ }
+ void WriteXmlNodeEnd() {
+ if (ndeOpened) {
+ sb.Add(" />" + String_.CrLf);
+ ndeOpened = false;
+ }
+ else {
+ String name = (String)names.FetchAtLast();
+ sb.Add("" + name + ">" + String_.CrLf);
+ }
+ names.DelAt(names.Count() - 1);
+ // if (nde.ParentNode == null) throw Err_.new_("WriteXmlNodeEnd() called on root node");
+// nde = nde.ParentNode;
+// WriteLineFeed(doc, nde);
+ }
+// void WriteLineFeed(XmlDocument doc, XmlNode owner) {
+// XmlSignificantWhitespace crlf = doc.CreateSignificantWhitespace(String_.CrLf);
+// owner.AppendChild(crlf);
+// }
+// void WriteLineFeedIfNeeded(XmlDocument doc, XmlNode owner) {
+// XmlSignificantWhitespace lastSubNode = owner.ChildNodes[owner.ChildNodes.Count - 1] as XmlSignificantWhitespace;
+// if (lastSubNode == null)
+// WriteLineFeed(doc, owner); // write LineFeed for consecutive WriteXmlNodeBegin calls; ex:
+// }
+ @Override public SrlMgr SrlMgr_new(Object o) {return new XmlDataWtr();}
+ boolean ndeOpened = false;
+// int atrCount = 0;
+// int ndeState = -1; static final int NdeState0_Opened = 0, NdeState0_H = 1;
+// XmlDocument doc = new XmlDocument(); XmlNode nde;
+ ListAdp names = ListAdp_.new_();
+ String_bldr sb = String_bldr_.new_();
+ public static XmlDataWtr new_() {return new XmlDataWtr();} XmlDataWtr() {}
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdrOpts.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdrOpts.java
new file mode 100644
index 000000000..3205f8c9e
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdrOpts.java
@@ -0,0 +1,25 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+public class DsvDataRdrOpts {
+ public boolean HasHeader() {return hasHeader;} public DsvDataRdrOpts HasHeader_(boolean val) {hasHeader = val; return this;} private boolean hasHeader = false;
+ public String NewLineSep() {return newLineSep;} public DsvDataRdrOpts NewLineSep_(String val) {newLineSep = val; return this;} private String newLineSep = String_.CrLf;
+ public String FldSep() {return fldSep;} public DsvDataRdrOpts FldSep_(String val) {fldSep = val; return this;} private String fldSep = ",";
+ public GfoFldList Flds() {return flds;} public DsvDataRdrOpts Flds_(GfoFldList val) {flds = val; return this;} GfoFldList flds = GfoFldList_.Null;
+ public static DsvDataRdrOpts new_() {return new DsvDataRdrOpts();} DsvDataRdrOpts() {}
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_.java
new file mode 100644
index 000000000..d613c1e00
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_.java
@@ -0,0 +1,247 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+import gplx.texts.*; /*CharStream*/
+public class DsvDataRdr_ {
+ public static DataRdr dsv_(String text) {return DsvParser.dsv_().ParseAsRdr(text);}
+ public static DataRdr csv_hdr_(String text) {return csv_opts_(text, DsvDataRdrOpts.new_().HasHeader_(true));}
+ public static DataRdr csv_dat_(String text) {return csv_opts_(text, DsvDataRdrOpts.new_());}
+ public static DataRdr csv_dat_with_flds_(String text, String... flds) {return csv_opts_(text, DsvDataRdrOpts.new_().Flds_(GfoFldList_.str_(flds)));}
+ public static DataRdr csv_opts_(String text, DsvDataRdrOpts opts) {
+ DsvParser parser = DsvParser.csv_(opts.HasHeader(), opts.Flds()); // NOTE: this sets up the bldr; do not call .Init after this
+ parser.Symbols().RowSep_(opts.NewLineSep()).FldSep_(opts.FldSep());
+
+ DataRdr root = parser.ParseAsRdr(text); // don't return root; callers expect csv to return rdr for rows
+ DataRdr csvTable = root.Subs();
+ return csvTable.Subs();
+ }
+}
+class DsvParser {
+ @gplx.Internal protected DsvSymbols Symbols() {return sym;} DsvSymbols sym = DsvSymbols.default_();
+ @gplx.Internal protected void Init() {sb.Clear(); bldr.Init(); qteOn = false;}
+ @gplx.Internal protected DataRdr ParseAsRdr(String raw) {return GfoNdeRdr_.root_(ParseAsNde(raw), csvOn);} // NOTE: csvOn means parse; assume manual typed flds not passed in (ex: id,Int)
+ @gplx.Internal protected GfoNde ParseAsNde(String raw) {
+ if (String_.Eq(raw, "")) return bldr.BldRoot();
+ CharStream strm = CharStream.pos0_(raw);
+ while (true) {
+ if (strm.AtEnd()) {
+ ProcessLine(strm, true);
+ break;
+ }
+ if (qteOn)
+ ReadStreamInQte(strm);
+ else if (strm.MatchAndMove(sym.QteDlm()))
+ qteOn = true;
+ else if (strm.MatchAndMove(sym.FldSep()))
+ ProcessFld(strm);
+ else if (strm.MatchAndMove(sym.RowSep()))
+ ProcessLine(strm, false);
+ else {
+ sb.Add(strm.Cur());
+ strm.MoveNext();
+ }
+ }
+ return bldr.BldRoot();
+ }
+ void ReadStreamInQte(CharStream strm) {
+ if (strm.MatchAndMove(sym.QteDlm())) { // is quote
+ if (strm.MatchAndMove(sym.QteDlm())) // double quote -> quote; "a""
+ sb.Add(sym.QteDlm());
+ else if (strm.MatchAndMove(sym.FldSep())) { // closing quote before field; "a",
+ ProcessFld(strm);
+ qteOn = false;
+ }
+ else if (strm.MatchAndMove(sym.RowSep()) || strm.AtEnd()) { // closing quote before record; "a"\r\n
+ ProcessLine(strm, false);
+ qteOn = false;
+ }
+ else
+ throw Err_.new_("invalid quote in quoted field; quote must be followed by quote, fieldSpr, or recordSpr").Add("sym", strm.Cur()).Add("text", strm.XtoStrByPos(strm.Pos() - 10, strm.Pos() + 10));
+ }
+ else { // regular char; append and continue
+ sb.Add(strm.Cur());
+ strm.MoveNext();
+ }
+ }
+ void ProcessFld(CharStream strm) {
+ String val = sb.XtoStrAndClear();
+ if (cmdSeqOn) {
+ cmdSeqOn = false;
+ if (String_.Eq(val, sym.CmdDlm()) && qteOn) { // 2 cmdDlms in a row; cmdSeq encountered; next fld must be cmdName
+ nextValType = ValType_CmdName;
+ return;
+ }
+ tkns.Add(sym.CmdDlm()); // curTkn is not cmdDlm; prevTkn happened to be cmdDlm; add prev to tkns and continue; ex: a, ,b
+ }
+ if (String_.Eq(val, sym.CmdDlm())) // val is cmdDlm; do not add now; wait til next fld to decide
+ cmdSeqOn = true;
+ else if (nextValType == ValType_Data) {
+ if (String_.Len(val) == 0) val = qteOn ? "" : null; // differentiate between null and emptyString; ,, vs ,"",
+ tkns.Add(val);
+ }
+ else if (nextValType == ValType_CmdName) {
+ if (String_.Eq(val, sym.TblNameSym())) lineMode = LineType_TblBgn; // #
+ else if (String_.Eq(val, sym.FldNamesSym())) lineMode = LineType_FldNames; // @
+ else if (String_.Eq(val, sym.FldTypesSym())) lineMode = LineType_FldTypes; // $
+ else if (String_.Eq(val, sym.CommentSym())) lineMode = LineType_Comment; // '
+ else throw Err_.new_("unknown dsv cmd").Add("cmd", val);
+ }
+ else
+ throw Err_.new_("unable to process field value").Add("value", val);
+ }
+ void ProcessLine(CharStream strm, boolean cleanup) {
+ if (sb.Count() == 0 && tkns.Count() == 0)
+ if (csvOn) { // csvOn b/c csvMode allows blank lines as empty data
+ if (cleanup) // cleanup b/c blankLine should not be added when called by cleanup, else will always add extra row at end
+ return; // cleanup, so no further action needed; return;
+ else
+ ProcessFld(strm);
+ }
+ else
+ lineMode = LineType_BlankLine;
+ else
+ ProcessFld(strm); // always process fld; either (1) chars waiting in sb "a,b"; or (2) last char was fldSep "a,"
+ if (cmdSeqOn) { // only happens if last fld is comma space (, ); do not let cmds span lines
+ cmdSeqOn = false;
+ tkns.Add(sym.CmdDlm());
+ }
+ if (lineMode == LineType_TblBgn) bldr.MakeTblBgn(tkns);
+ else if (lineMode == LineType_FldNames) bldr.MakeFldNames(tkns);
+ else if (lineMode == LineType_FldTypes) bldr.MakeFldTypes(tkns);
+ else if (lineMode == LineType_Comment) bldr.MakeComment(tkns);
+ else if (lineMode == LineType_BlankLine) bldr.MakeBlankLine();
+ else bldr.MakeVals(tkns);
+ nextValType = ValType_Data;
+ lineMode = LineType_Data;
+ }
+ String_bldr sb = String_bldr_.new_(); ListAdp tkns = ListAdp_.new_(); DsvTblBldr bldr = DsvTblBldr.new_();
+ boolean cmdSeqOn = false, qteOn = false, csvOn = false;
+ int nextValType = ValType_Data, lineMode = LineType_Data;
+ @gplx.Internal protected static DsvParser dsv_() {return new DsvParser();}
+ @gplx.Internal protected static DsvParser csv_(boolean hasHdr, GfoFldList flds) {
+ DsvParser rv = new DsvParser();
+ rv.csvOn = true;
+ rv.lineMode = hasHdr ? LineType_FldNames : LineType_Data;
+ ListAdp names = ListAdp_.new_(), types = ListAdp_.new_();
+ for (int i = 0; i < flds.Count(); i++) {
+ GfoFld fld = flds.FetchAt(i);
+ names.Add(fld.Key()); types.Add(fld.Type().Key());
+ }
+ rv.bldr.MakeFldNames(names); rv.bldr.MakeFldTypes(types);
+ return rv;
+ }
+ static final int ValType_Data = 0, ValType_CmdName = 1;
+ static final int LineType_Data = 0, LineType_Comment = 1, LineType_TblBgn = 2, LineType_FldNames = 3, LineType_FldTypes = 4, LineType_BlankLine = 5;
+}
+class DsvTblBldr {
+ public void Init() {
+ root = GfoNde_.root_(); tbl = GfoNde_.tbl_(NullTblName, GfoFldList_.new_());
+ fldNames.Clear(); fldTypes.Clear();
+ stage = Stage_Init;
+ }
+ public GfoNde BldRoot() {
+ if (stage != Stage_Init) CreateTbl(); // CreateTbl if HDR or ROW is in progress
+ return root;
+ }
+ public void MakeTblBgn(ListAdp tkns) {
+ if (stage != Stage_Init) CreateTbl(); // CreateTbl if HDR or ROW is in progress
+ tbl.Name_((String)tkns.FetchAt(0));
+ layout.HeaderList().Add_TableName();
+ stage = Stage_Hdr; tkns.Clear();
+ }
+ public void MakeFldNames(ListAdp tkns) {
+ if (stage == Stage_Row) CreateTbl(); // CreateTbl if ROW is in progress; NOTE: exclude HDR, as first HDR would have called CreateTbl
+ fldNames.Clear();
+ for (Object fldNameObj : tkns)
+ fldNames.Add(fldNameObj);
+ layout.HeaderList().Add_LeafNames();
+ stage = Stage_Hdr; tkns.Clear();
+ }
+ public void MakeFldTypes(ListAdp tkns) {
+ if (stage == Stage_Row) CreateTbl(); // CreateTbl if ROW is in progress; NOTE: exclude HDR, as first HDR would have called CreateTbl
+ fldTypes.Clear();
+ for (Object fldTypeObj : tkns) {
+ ClassXtn type = ClassXtnPool._.FetchOrFail((String)fldTypeObj);
+ fldTypes.Add(type);
+ }
+ layout.HeaderList().Add_LeafTypes();
+ stage = Stage_Hdr; tkns.Clear();
+ }
+ public void MakeComment(ListAdp tkns) {
+ if (stage == Stage_Row) // comments in ROW; ignore; NOTE: tkns.Clear() could be merged, but this seems clearer
+ tkns.Clear();
+ else { // comments in HDR
+ String_bldr sb = String_bldr_.new_();
+ for (int i = 0; i < tkns.Count(); i++)
+ sb.Add((String)tkns.FetchAt(i));
+ layout.HeaderList().Add_Comment(sb.XtoStr());
+ tkns.Clear();
+ }
+ }
+ public void MakeBlankLine() {
+ if (stage != Stage_Init) CreateTbl(); // CreateTbl if HDR or ROW is in progress;
+ layout.HeaderList().Add_BlankLine();
+ stage = Stage_Init; // NOTE: mark stage as INIT;
+ }
+ public void MakeVals(ListAdp tkns) {
+ if (stage != Stage_Row) CreateFlds(tkns.Count()); // stage != Stage_Row means if (noRowsCreated)
+ GfoNde row = GfoNde_.vals_(tbl.SubFlds(), MakeValsAry(tkns));
+ tbl.Subs().Add(row);
+ stage = Stage_Row; tkns.Clear();
+ }
+ Object[] MakeValsAry(ListAdp tkns) {
+ GfoFldList subFlds = tbl.SubFlds(); int subFldsCount = subFlds.Count();
+ if (tkns.Count() > subFldsCount) throw Err_.new_("values.Count cannot be greater than fields.Count").Add("values.Count", tkns.Count()).Add("fields.Count", subFldsCount);
+ Object[] rv = new Object[subFldsCount];
+ for (int i = 0; i < subFldsCount; i++) {
+ ClassXtn typx = subFlds.FetchAt(i).Type();
+ String val = i < tkns.Count() ? (String)tkns.FetchAt(i) : null;
+ rv[i] = typx.ParseOrNull(val);
+ }
+ return rv;
+ }
+ void CreateTbl() {
+ if (tbl.SubFlds().Count() == 0) CreateFlds(0); // this check occurs when tbl has no ROW; (TOMB: tdb test fails)
+ tbl.EnvVars().Add(DsvStoreLayout.Key_const, layout);
+ root.Subs().Add(tbl); // add pending table
+ layout = DsvStoreLayout.dsv_brief_();
+ tbl = GfoNde_.tbl_(NullTblName, GfoFldList_.new_());
+ stage = Stage_Hdr;
+ }
+ void CreateFlds(int valCount) {
+ int fldNamesCount = fldNames.Count(), fldTypesCount = fldTypes.Count();
+ if (fldNamesCount == 0 && fldTypesCount == 0) { // csv tbls where no names or types, just values
+ for (int i = 0; i < valCount; i++)
+ tbl.SubFlds().Add("fld" + i, StringClassXtn._);
+ }
+ else { // all else, where either names or types is defined
+ int maxCount = fldNamesCount > fldTypesCount ? fldNamesCount : fldTypesCount;
+ for (int i = 0; i < maxCount; i++) {
+ String name = i < fldNamesCount ? (String)fldNames.FetchAt(i) : "fld" + i;
+ ClassXtn typx = i < fldTypesCount ? (ClassXtn)fldTypes.FetchAt(i) : StringClassXtn._;
+ tbl.SubFlds().Add(name, typx);
+ }
+ }
+ }
+ GfoNde root; GfoNde tbl; DsvStoreLayout layout = DsvStoreLayout.dsv_brief_();
+ ListAdp fldNames = ListAdp_.new_(); ListAdp fldTypes = ListAdp_.new_();
+ int stage = Stage_Init;
+ public static DsvTblBldr new_() {return new DsvTblBldr();} DsvTblBldr() {this.Init();}
+ @gplx.Internal protected static final String NullTblName = "";
+ static final int Stage_Init = 0, Stage_Hdr = 1, Stage_Row = 2;
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_csv_dat_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_csv_dat_tst.java
new file mode 100644
index 000000000..e733061f7
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_csv_dat_tst.java
@@ -0,0 +1,213 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+import org.junit.*;
+public class DsvDataRdr_csv_dat_tst {
+ @Before public void setup() {
+ fx.Parser_(DsvParser.csv_(false, GfoFldList_.Null));
+ fx.Clear();
+ } DsvDataRdr_fxt fx = DsvDataRdr_fxt.new_();
+ @Test public void Empty() {
+ fx.run_parse_("");
+ fx.tst_DatNull();
+ }
+ @Test public void Fld_0() {
+ fx.run_parse_("a");
+ fx.tst_DatCsv(fx.ary_("a"));
+ }
+ @Test public void Fld_N() {
+ fx.run_parse_("a,b,c");
+ fx.tst_FldListCsv("fld0", "fld1", "fld2");
+ fx.tst_DatCsv(fx.ary_("a", "b", "c"));
+ }
+ @Test public void Row_N() {
+ fx.run_parse_
+ ( "a,b,c", String_.CrLf
+ , "1,2,3"
+ );
+ fx.tst_DatCsv
+ ( fx.ary_("a", "b", "c")
+ , fx.ary_("1", "2", "3")
+ );
+ }
+ @Test public void Escape_WhiteSpace() {
+ fx.run_parse_("a,\" \t\",c");
+ fx.tst_DatCsv(fx.ary_("a", " \t", "c"));
+ }
+ @Test public void Escape_FldSep() {
+ fx.run_parse_("a,\",\",c");
+ fx.tst_DatCsv(fx.ary_("a", ",", "c"));
+ }
+ @Test public void Escape_RowSep() {
+ fx.run_parse_("a,\"" + String_.CrLf + "\",c");
+ fx.tst_DatCsv(fx.ary_("a", String_.CrLf, "c"));
+ }
+ @Test public void Escape_Quote() {
+ fx.run_parse_("a,\"\"\"\",c");
+ fx.tst_DatCsv(fx.ary_("a", "\"", "c"));
+ }
+ @Test public void Blank_Null() {
+ fx.run_parse_("a,,c");
+ fx.tst_DatCsv(fx.ary_("a", null, "c"));
+ }
+ @Test public void Blank_EmptyString() {
+ fx.run_parse_("a,\"\",c");
+ fx.tst_DatCsv(fx.ary_("a", "", "c"));
+ }
+ @Test public void Blank_Null_Multiple() {
+ fx.run_parse_(",,");
+ fx.tst_DatCsv(fx.ary_(null, null, null));
+ }
+ @Test public void TrailingNull() {
+ fx.run_parse_("a,");
+ fx.tst_DatCsv(fx.ary_("a", null));
+ }
+ @Test public void TrailingEmpty() {
+ fx.run_parse_("a,\"\"");
+ fx.tst_DatCsv(fx.ary_("a", ""));
+ }
+ @Test public void Quote_Error() {
+ try {fx.run_parse_("a,\"\" ,c"); Tfds.Fail_expdError();}
+ catch (Err exc) {
+ Tfds.Eq_true(String_.Has(Err_.Message_lang(exc), "invalid quote in quoted field"));
+ }
+ }
+ @Test public void Misc_AllowValsLessThanFields() {
+ // assume null when vals.Count < fields.Count; PURPOSE: MsExcel will not save trailing commas for csvExport; ex: a, -> a
+ fx.run_parse_
+ ( "a0,a1", String_.CrLf
+ , "b0"
+ );
+ fx.tst_DatCsv
+ ( fx.ary_("a0", "a1")
+ , fx.ary_("b0", null)
+ );
+ }
+ @Test public void Misc_NewLineValidForSingleColumnTables() {
+ fx.run_parse_
+ ( "a", String_.CrLf
+ , String_.CrLf
+ , "c" , String_.CrLf
+ , String_.CrLf
+ );
+ fx.tst_DatCsv
+ ( fx.ary_("a")
+ , fx.ary_null_()
+ , fx.ary_("c")
+ , fx.ary_null_()
+ );
+ }
+ @Test public void Misc_NewLineValidForSingleColumnTables_FirstLine() {
+ fx.run_parse_
+ ( String_.CrLf
+ , "b", String_.CrLf
+ , "c"
+ );
+ fx.tst_DatCsv
+ ( fx.ary_null_()
+ , fx.ary_("b")
+ , fx.ary_("c")
+ );
+ }
+ @Test public void Hdr_Basic() {
+ fx.Parser_(DsvParser.csv_(true, GfoFldList_.Null));
+ fx.run_parse_
+ ( "id,name", String_.CrLf
+ , "0,me"
+ );
+ fx.tst_FldListCsv("id", "name");
+ fx.tst_DatCsv(fx.ary_("0", "me"));
+ }
+// @Test public void Hdr_Manual() {
+// fx.Parser_(DsvParser.csv_(false, GfoFldList_.new_().Add("id", IntClassXtn._).Add("name", StringClassXtn._), true));
+// fx.run_parse_("0,me");
+// fx.tst_DatCsv(fx.ary_(0, "me")); // NOTE: testing auto-parsing of id to int b/c id fld is IntClassXtn._;
+// }
+}
+class DsvDataRdr_fxt {
+ public Object[] ary_(Object... ary) {return ary;}
+ public Object[] ary_null_() {return new Object[] {null};}
+ public void Clear() {parser.Init(); root = null;}
+ public DsvParser Parser() {return parser;} public DsvDataRdr_fxt Parser_(DsvParser val) {parser = val; return this;} DsvParser parser = DsvParser.dsv_();
+ public GfoNde Root() {return root;} GfoNde root;
+ public void run_parse_(String... ary) {root = parser.ParseAsNde(String_.Concat(ary));}
+ public void run_parse_lines_(String... ary) {root = parser.ParseAsNde(String_.Concat_lines_crlf(ary));}
+ public DsvDataRdr_fxt tst_FldListCsv(String... names) {return tst_Flds(TblIdx0, GfoFldList_.str_(names));}
+ public DsvDataRdr_fxt tst_Flds(int tblIdx, GfoFldList expdFlds) {
+ GfoNde tbl = root.Subs().FetchAt_asGfoNde(tblIdx);
+ ListAdp expdList = ListAdp_.new_(), actlList = ListAdp_.new_();
+ String_bldr sb = String_bldr_.new_();
+ GfoFldList_BldDbgList(expdFlds, expdList, sb);
+ GfoFldList_BldDbgList(tbl.SubFlds(), actlList, sb);
+ Tfds.Eq_list(expdList, actlList);
+ return this;
+ }
+ void GfoFldList_BldDbgList(GfoFldList flds, ListAdp list, String_bldr sb) {
+ for (int i = 0; i < flds.Count(); i++) {
+ GfoFld fld = flds.FetchAt(i);
+ sb.Add(fld.Key()).Add(",").Add(fld.Type().Key());
+ list.Add(sb.XtoStrAndClear());
+ }
+ }
+ public DsvDataRdr_fxt tst_Tbls(String... expdNames) {
+ ListAdp actlList = ListAdp_.new_();
+ for (int i = 0; i < root.Subs().Count(); i++) {
+ GfoNde tbl = root.Subs().FetchAt_asGfoNde(i);
+ actlList.Add(tbl.Name());
+ }
+ Tfds.Eq_ary(expdNames, actlList.XtoStrAry());
+ return this;
+ }
+ public DsvDataRdr_fxt tst_DatNull() {
+ Tfds.Eq(0, root.Subs().Count());
+ return this;
+ }
+ public DsvDataRdr_fxt tst_DatCsv(Object[]... expdRows) {return tst_Dat(0, expdRows);}
+ public DsvDataRdr_fxt tst_Dat(int tblIdx, Object[]... expdRows) {
+ GfoNde tbl = root.Subs().FetchAt_asGfoNde(tblIdx);
+ if (expdRows.length == 0) {
+ Tfds.Eq(0, tbl.Subs().Count());
+ return this;
+ }
+ ListAdp expdList = ListAdp_.new_(), actlList = ListAdp_.new_();
+ String_bldr sb = String_bldr_.new_();
+ for (int i = 0; i < tbl.Subs().Count(); i++) {
+ GfoNde row = tbl.Subs().FetchAt_asGfoNde(i);
+ for (int j = 0; j < row.Flds().Count(); j++) {
+ if (j != 0) sb.Add("~");
+ sb.Add_obj(Object_.XtoStr_OrNullStr(row.ReadAt(j)));
+ }
+ expdList.Add(sb.XtoStrAndClear());
+ }
+ for (Object[] expdRow : expdRows) {
+ if (expdRow == null) {
+ actlList.Add("");
+ continue;
+ }
+ for (int j = 0; j < expdRow.length; j++) {
+ if (j != 0) sb.Add("~");
+ sb.Add_obj(Object_.XtoStr_OrNullStr(expdRow[j]));
+ }
+ actlList.Add(sb.XtoStrAndClear());
+ }
+ Tfds.Eq_list(expdList, actlList);
+ return this;
+ }
+ public static DsvDataRdr_fxt new_() {return new DsvDataRdr_fxt();}
+ static final int TblIdx0 = 0;
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_dat_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_dat_tst.java
new file mode 100644
index 000000000..c599a674d
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_dat_tst.java
@@ -0,0 +1,70 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+import org.junit.*;
+public class DsvDataRdr_dsv_dat_tst {
+ @Before public void setup() {fx.Clear();} DsvDataRdr_fxt fx = DsvDataRdr_fxt.new_();
+ @Test public void NameOnly() {
+ fx.run_parse_("tableName, ,\" \",#");
+ fx.tst_Tbls("tableName");
+ fx.tst_Dat(0);
+ }
+ @Test public void Rows_N() {
+ fx.run_parse_lines_
+ ( "numbers, ,\" \",#"
+ , "1,2,3"
+ , "4,5,6"
+ );
+ fx.tst_Tbls("numbers");
+ fx.tst_Dat(0
+ , fx.ary_("1", "2", "3")
+ , fx.ary_("4", "5", "6")
+ );
+ }
+ @Test public void Tbls_N() {
+ fx.run_parse_lines_
+ ( "letters, ,\" \",#"
+ , "a,b,c"
+ , "numbers, ,\" \",#"
+ , "1,2,3"
+ , "4,5,6"
+ );
+ fx.tst_Tbls("letters", "numbers");
+ fx.tst_Dat(0, fx.ary_("a", "b", "c"));
+ fx.tst_Dat(1, fx.ary_("1", "2", "3"), fx.ary_("4", "5", "6"));
+ }
+ @Test public void IgnoreTrailingBlankRow() {
+ fx.run_parse_lines_
+ ( "letters, ,\" \",#"
+ , "a,b,c"
+ , "" // ignored
+ );
+ fx.tst_Tbls("letters");
+ fx.tst_Dat(0, fx.ary_("a", "b", "c"));
+ }
+ @Test public void AllowCommentsDuringData() {
+ fx.run_parse_lines_
+ ( "letters, ,\" \",#"
+ , "a,b,c"
+ , "// letters omitted, ,\" \",//" // these comments are not preserved
+ , "x,y,z"
+ );
+ fx.tst_Tbls("letters");
+ fx.tst_Dat(0, fx.ary_("a", "b", "c"), fx.ary_("x", "y", "z"));
+ }
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_hdr_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_hdr_tst.java
new file mode 100644
index 000000000..b97471cc2
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_hdr_tst.java
@@ -0,0 +1,82 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+import org.junit.*;
+public class DsvDataRdr_dsv_hdr_tst {
+ @Before public void setup() {fx.Clear();} DsvDataRdr_fxt fx = DsvDataRdr_fxt.new_();
+ @Test public void Names() {
+ fx.run_parse_lines_
+ ( "id,name, ,\" \",@"
+ , "0,me"
+ , "1,you"
+ );
+ fx.tst_Flds(0, GfoFldList_.str_("id", "name"));
+ fx.tst_Tbls(DsvTblBldr.NullTblName);
+ fx.tst_Dat(0
+ , fx.ary_("0", "me")
+ , fx.ary_("1", "you")
+ );
+ }
+ @Test public void Types() {
+ fx.run_parse_lines_
+ ( "int," + StringClassXtn.Key_const + ", ,\" \",$"
+ , "0,me"
+ , "1,you"
+ );
+ fx.tst_Flds(0, GfoFldList_.new_().Add("fld0", IntClassXtn._).Add("fld1", StringClassXtn._));
+ fx.tst_Dat(0
+ , fx.ary_(0, "me")
+ , fx.ary_(1, "you")
+ );
+ }
+ @Test public void NamesAndTypes() {
+ fx.run_parse_lines_
+ ( "id,name, ,\" \",@"
+ , "int," + StringClassXtn.Key_const + ", ,\" \",$"
+ , "0,me"
+ , "1,you"
+ );
+ fx.tst_Flds(0, GfoFldList_.new_().Add("id", IntClassXtn._).Add("name", StringClassXtn._));
+ fx.tst_Dat(0
+ , fx.ary_(0, "me")
+ , fx.ary_(1, "you")
+ );
+ }
+ @Test public void MultipleTables_NoData() {
+ fx.run_parse_lines_
+ ( "persons, ,\" \",#"
+ , "id,name, ,\" \",@"
+ , "things, ,\" \",#"
+ , "id,data, ,\" \",@"
+ );
+ fx.tst_Tbls("persons", "things");
+ fx.tst_Flds(0, GfoFldList_.str_("id", "name"));
+ fx.tst_Flds(1, GfoFldList_.str_("id", "data"));
+ fx.tst_Dat(0);
+ fx.tst_Dat(1);
+ }
+ @Test public void Comment() {
+ fx.run_parse_lines_
+ ( "--------------------, ,\" \",//"
+ , "tbl0, ,\" \",#"
+ , "a0,a1"
+ );
+ fx.tst_Tbls("tbl0");
+ fx.tst_Dat(0, fx.ary_("a0", "a1"));
+ }
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_misc_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_misc_tst.java
new file mode 100644
index 000000000..680827565
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_misc_tst.java
@@ -0,0 +1,76 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+import org.junit.*;
+public class DsvDataRdr_dsv_misc_tst {
+ @Before public void setup() {fx.Clear();} DsvDataRdr_fxt fx = DsvDataRdr_fxt.new_();
+ @Test public void CmdDlm_NearMatches() {
+ fx.run_parse_("a, ,b");
+ fx.tst_DatCsv(fx.ary_("a", " ", "b"));
+ fx.Clear();
+
+ fx.run_parse_("a,\" \",b");
+ fx.tst_DatCsv(fx.ary_("a", " ", "b"));
+ fx.Clear();
+
+ fx.run_parse_("a, ,b,\" \",c");
+ fx.tst_DatCsv(fx.ary_("a", " ", "b", " ", "c"));
+ fx.Clear();
+ }
+ @Test public void CmdDlm_DoNotSpanLines() {
+ fx.run_parse_lines_
+ ( "a, "
+ , "\" \",b"
+ );
+ fx.tst_DatCsv
+ ( fx.ary_("a", " ")
+ , fx.ary_(" ", "b")
+ );
+ }
+ @Test public void CmdDlm_SecondFldMustBeQuoted() {
+ fx.run_parse_lines_("a, , ,b"); // will fail with "invalid command: b", if second , , is interpreted as command delimiter
+ fx.tst_DatCsv(fx.ary_("a", " ", " ", "b"));
+ }
+ @Test public void Null_Int() {
+ fx.run_parse_ // not using run_parse_lines_ b/c (a) will have extra lineBreak; (b) test will look funny;
+ ( "int," + StringClassXtn.Key_const + ", ,\" \",$", String_.CrLf
+ , ",val1"
+ );
+ fx.tst_Tbls(DsvTblBldr.NullTblName);
+ fx.tst_Flds(0, GfoFldList_.new_().Add("fld0", IntClassXtn._).Add("fld1", StringClassXtn._));
+ fx.tst_Dat(0, fx.ary_(null, "val1"));
+ }
+ @Test public void Null_String() {
+ fx.run_parse_ // not using run_parse_lines_ b/c (a) will have extra lineBreak; (b) test will look funny;
+ ( StringClassXtn.Key_const + "," + StringClassXtn.Key_const + ", ,\" \",$", String_.CrLf
+ , ",val1"
+ );
+ fx.tst_Tbls(DsvTblBldr.NullTblName);
+ fx.tst_Flds(0, GfoFldList_.new_().Add("fld0", StringClassXtn._).Add("fld1", StringClassXtn._));
+ fx.tst_Dat(0, fx.ary_(null, "val1"));
+ }
+ @Test public void EmptyString() {
+ fx.run_parse_ // not using run_parse_lines_ b/c (a) will have extra lineBreak; (b) test will look funny;
+ ( StringClassXtn.Key_const + "," + StringClassXtn.Key_const + ", ,\" \",$", String_.CrLf
+ , "\"\",val1"
+ );
+ fx.tst_Tbls(DsvTblBldr.NullTblName);
+ fx.tst_Flds(0, GfoFldList_.new_().Add("fld0", StringClassXtn._).Add("fld1", StringClassXtn._));
+ fx.tst_Dat(0, fx.ary_("", "val1"));
+ }
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_layout_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_layout_tst.java
new file mode 100644
index 000000000..8e5353eb5
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_layout_tst.java
@@ -0,0 +1,131 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+import org.junit.*;
+public class DsvDataRdr_layout_tst {
+ @Test public void TableName() {
+ run_parse_lines("table0, ,\" \",#");
+ tst_Layout(0, DsvHeaderItm.Id_TableName);
+ }
+ @Test public void Comment() {
+ run_parse_lines("-------------, ,\" \",//", "data"); // need dataLine or parser will throw away standalone header
+ tst_Layout(0, DsvHeaderItm.Id_Comment);
+ }
+ @Test public void BlankLine() {
+ run_parse_lines("", "data"); // need dataLine or parser will throw away standalone header
+ tst_Layout(0, DsvHeaderItm.Id_BlankLine);
+ }
+ @Test public void LeafNames() {
+ run_parse_lines("id,name, ,\" \",@");
+ tst_Layout(0, DsvHeaderItm.Id_LeafNames);
+ }
+ @Test public void LeafTypes() {
+ run_parse_lines("int," + StringClassXtn.Key_const + ", ,\" \",$");
+ tst_Layout(0, DsvHeaderItm.Id_LeafTypes);
+ }
+ @Test public void Combined() {
+ run_parse_lines
+ ( ""
+ , "-------------, ,\" \",//"
+ , "table0, ,\" \",#"
+ , "int," + StringClassXtn.Key_const + ", ,\" \",$"
+ , "id,name, ,\" \",@"
+ , "-------------, ,\" \",//"
+ , "0,me"
+ );
+ tst_Layout(0
+ , DsvHeaderItm.Id_BlankLine
+ , DsvHeaderItm.Id_Comment
+ , DsvHeaderItm.Id_TableName
+ , DsvHeaderItm.Id_LeafTypes
+ , DsvHeaderItm.Id_LeafNames
+ , DsvHeaderItm.Id_Comment
+ );
+ }
+ @Test public void Tbl_N() {
+ run_parse_lines
+ ( ""
+ , "*************, ,\" \",//"
+ , "table0, ,\" \",#"
+ , "-------------, ,\" \",//"
+ , "0,me"
+ , ""
+ , "*************, ,\" \",//"
+ , "table1, ,\" \",#"
+ , " extended data, ,\" \",//"
+ , "-------------, ,\" \",//"
+ , "1,you,more"
+ );
+ tst_Layout(0
+ , DsvHeaderItm.Id_BlankLine
+ , DsvHeaderItm.Id_Comment
+ , DsvHeaderItm.Id_TableName
+ , DsvHeaderItm.Id_Comment
+ );
+ tst_Layout(1
+ , DsvHeaderItm.Id_BlankLine
+ , DsvHeaderItm.Id_Comment
+ , DsvHeaderItm.Id_TableName
+ , DsvHeaderItm.Id_Comment
+ , DsvHeaderItm.Id_Comment
+ );
+ }
+ @Test public void Tbl_N_FirstIsEmpty() {
+ run_parse_lines
+ ( ""
+ , "*************, ,\" \",//"
+ , "table0, ,\" \",#"
+ , "-------------, ,\" \",//"
+ , ""
+ , ""
+ , "*************, ,\" \",//"
+ , "table1, ,\" \",#"
+ , " extended data, ,\" \",//"
+ , "-------------, ,\" \",//"
+ , "1,you,more"
+ );
+ tst_Layout(0
+ , DsvHeaderItm.Id_BlankLine
+ , DsvHeaderItm.Id_Comment
+ , DsvHeaderItm.Id_TableName
+ , DsvHeaderItm.Id_Comment
+ );
+ tst_Layout(1
+ , DsvHeaderItm.Id_BlankLine
+ , DsvHeaderItm.Id_BlankLine
+ , DsvHeaderItm.Id_Comment
+ , DsvHeaderItm.Id_TableName
+ , DsvHeaderItm.Id_Comment
+ , DsvHeaderItm.Id_Comment
+ );
+ }
+ void run_parse_lines(String... ary) {
+ String raw = String_.Concat_lines_crlf(ary);
+ DsvParser parser = DsvParser.dsv_();
+ root = parser.ParseAsNde(raw);
+ }
+ void tst_Layout(int subIdx, int... expd) {
+ GfoNde tbl = root.Subs().FetchAt_asGfoNde(subIdx);
+ DsvStoreLayout layout = (DsvStoreLayout)tbl.EnvVars().Fetch(DsvStoreLayout.Key_const);
+ int[] actl = new int[layout.HeaderList().Count()];
+ for (int i = 0; i < actl.length; i++)
+ actl[i] = layout.HeaderList().FetchAt(i).Id();
+ Tfds.Eq_ary(expd, actl);
+ }
+ GfoNde root;
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr.java
new file mode 100644
index 000000000..b4b2e7d8d
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr.java
@@ -0,0 +1,114 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+public class DsvDataWtr extends DataWtr_base implements DataWtr {
+ public void InitWtr(String key, Object val) {
+ if (key == DsvStoreLayout.Key_const) layout = (DsvStoreLayout)val;
+ }
+ @Override public void WriteData(String name, Object val) {sb.WriteFld(val == null ? null : val.toString());}
+ public void WriteLeafBgn(String leafName) {}
+ public void WriteLeafEnd() {sb.WriteRowSep();}
+ @Override public void WriteNodeBgn(String name) {WriteTableBgn(name, GfoFldList_.Null);}
+ public void WriteTableBgn(String name, GfoFldList flds) {
+ for (int i = 0; i < layout.HeaderList().Count(); i++) {
+ DsvHeaderItm data = layout.HeaderList().FetchAt(i);
+ int id = data.Id();
+ if (id == DsvHeaderItm.Id_TableName) WriteTableName(name);
+ else if (id == DsvHeaderItm.Id_LeafNames) WriteMeta(flds, true, sym.FldNamesSym());
+ else if (id == DsvHeaderItm.Id_LeafTypes) WriteMeta(flds, false, sym.FldTypesSym());
+ else if (id == DsvHeaderItm.Id_BlankLine) sb.WriteRowSep();
+ else if (id == DsvHeaderItm.Id_Comment) WriteComment(data.Val().toString());
+ }
+ }
+ @Override public void WriteNodeEnd() {}
+ public void Clear() {sb.Clear();}
+ public String XtoStr() {return sb.XtoStr();}
+ void WriteTableName(String tableName) {
+ sb.WriteFld(tableName);
+ sb.WriteCmd(sym.TblNameSym());
+ sb.WriteRowSep();
+ }
+ void WriteMeta(GfoFldList flds, boolean isName, String cmd) {
+ for (int i = 0; i < flds.Count(); i++) {
+ GfoFld fld = flds.FetchAt(i);
+ String val = isName ? fld.Key(): fld.Type().Key();
+ sb.WriteFld(val);
+ }
+ if (layout.WriteCmdSequence()) sb.WriteCmd(cmd);
+ sb.WriteRowSep();
+ }
+ void WriteComment(String comment) {
+ sb.WriteFld(comment);
+ sb.WriteCmd(sym.CommentSym());
+ sb.WriteRowSep();
+ }
+ @Override public SrlMgr SrlMgr_new(Object o) {return new DsvDataWtr();}
+ DsvStringBldr sb; DsvSymbols sym = DsvSymbols.default_(); DsvStoreLayout layout = DsvStoreLayout.csv_dat_();
+ @gplx.Internal protected DsvDataWtr() {sb = DsvStringBldr.new_(sym);}
+}
+class DsvStringBldr {
+ public void Clear() {sb.Clear();}
+ public String XtoStr() {return sb.XtoStr();}
+ public void WriteCmd(String cmd) {
+ WriteFld(sym.CmdSequence(), true);
+ WriteFld(cmd);
+ }
+ public void WriteFldSep() {sb.Add(sym.FldSep());}
+ public void WriteRowSep() {
+ sb.Add(sym.RowSep());
+ isNewRow = true;
+ }
+ public void WriteFld(String val) {WriteFld(val, false);}
+ void WriteFld(String val, boolean writeRaw) {
+ if (isNewRow) // if isNewRow, then fld is first, and no fldSpr needed (RowSep serves as fldSpr)
+ isNewRow = false;
+ else
+ sb.Add(sym.FldSep());
+
+ if (val == null) {} // null -> append nothing
+ else if (String_.Eq(val, String_.Empty))// "" -> append ""
+ sb.Add("\"\"");
+ else if (writeRaw) // only cmds should be writeRaw (will append ," ")
+ sb.Add(val);
+ else { // escape as necessary; ex: "the quote "" char"; "the comma , char"
+ boolean quoteField = false;
+ if (String_.Has(val, sym.QteDlm())) {
+ val = String_.Replace(val, "\"", "\"\"");
+ quoteField = true;
+ }
+ else if (String_.Has(val, sym.FldSep()))
+ quoteField = true;
+ else if (sym.RowSepIsNewLine()
+ && (String_.Has(val, "\n") || String_.Has(val, "\r")))
+ quoteField = true;
+ else if (String_.Has(val, sym.RowSep()))
+ quoteField = true;
+
+ if (quoteField) sb.Add(sym.QteDlm());
+ sb.Add(val);
+ if (quoteField) sb.Add(sym.QteDlm());
+ }
+ }
+
+ String_bldr sb = String_bldr_.new_(); DsvSymbols sym; boolean isNewRow = true;
+ public static DsvStringBldr new_(DsvSymbols sym) {
+ DsvStringBldr rv = new DsvStringBldr();
+ rv.sym = sym;
+ return rv;
+ } DsvStringBldr() {}
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_.java
new file mode 100644
index 000000000..f13b4b8f3
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_.java
@@ -0,0 +1,31 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+public class DsvDataWtr_ {
+ public static DsvDataWtr csv_hdr_() {
+ DsvDataWtr rv = new DsvDataWtr();
+ rv.InitWtr(DsvStoreLayout.Key_const, DsvStoreLayout.csv_hdr_());
+ return rv;
+ }
+ public static DsvDataWtr csv_dat_() {
+ DsvDataWtr rv = new DsvDataWtr();
+ rv.InitWtr(DsvStoreLayout.Key_const, DsvStoreLayout.csv_dat_());
+ return rv;
+ }
+ public static DsvDataWtr new_() {return new DsvDataWtr();}
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_csv_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_csv_tst.java
new file mode 100644
index 000000000..1954777e6
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_csv_tst.java
@@ -0,0 +1,100 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+import org.junit.*;
+public class DsvDataWtr_csv_tst {
+ @Test public void Dat_Val_0() {
+ root = fx_nde.csv_dat_(); this.AddCsvRow(root);
+ expd = String_.Concat_lines_crlf("");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Dat_Val_1() {
+ root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a");
+ expd = String_.Concat_lines_crlf("a");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Dat_Val_N() {
+ root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", "b", "c");
+ expd = String_.Concat_lines_crlf("a,b,c");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Dat_Row_N() {
+ root = fx_nde.csv_dat_();
+ this.AddCsvRow(root, "a", "b", "c");
+ this.AddCsvRow(root, "d", "e", "f");
+ expd = String_.Concat_lines_crlf
+ ( "a,b,c"
+ , "d,e,f"
+ );
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Dat_Escape_FldSpr() { // ,
+ root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", ",", "c");
+ expd = String_.Concat_lines_crlf("a,\",\",c");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Dat_Escape_RcdSpr() { // NewLine
+ root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", String_.CrLf, "c");
+ expd = String_.Concat_lines_crlf("a,\"" + String_.CrLf + "\",c");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Dat_Escape_Quote() { // " -> ""
+ root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", "\"", "c");
+ expd = String_.Concat_lines_crlf("a,\"\"\"\",c");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Dat_Whitespace() {
+ root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", " b\t", "c");
+ expd = String_.Concat_lines_crlf("a, b\t,c");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Dat_Null() {
+ root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", null, "c");
+ expd = String_.Concat_lines_crlf("a,,c");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Dat_EmptyString() {
+ root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", "", "c");
+ expd = String_.Concat_lines_crlf("a,\"\",c");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Hdr_Flds() {
+ wtr = DsvDataWtr_.csv_hdr_();
+ GfoFldList flds = GfoFldList_.new_().Add("id", StringClassXtn._).Add("name", StringClassXtn._);
+ root = fx_nde.csv_hdr_(flds); this.AddCsvRow(root, "0", "me");
+ expd = String_.Concat_lines_crlf
+ ( "id,name"
+ , "0,me"
+ );
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ void AddCsvRow(GfoNde root, String... ary) {
+ GfoNde sub = GfoNde_.vals_(root.SubFlds(), ary);
+ root.Subs().Add(sub);
+ }
+ GfoNde root; String expd; DsvDataWtr wtr = DsvDataWtr_.csv_dat_(); DsvDataWtr_fxt fx = DsvDataWtr_fxt.new_(); GfoNdeFxt fx_nde = GfoNdeFxt.new_();
+}
+class DsvDataWtr_fxt {
+ public void tst_XtoStr(DsvDataWtr wtr, GfoNde root, String expd) {
+ wtr.Clear();
+ root.XtoStr_wtr(wtr);
+ String actl = wtr.XtoStr();
+ Tfds.Eq(expd, actl);
+ }
+ public static DsvDataWtr_fxt new_() {return new DsvDataWtr_fxt();} DsvDataWtr_fxt() {}
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_tbls_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_tbls_tst.java
new file mode 100644
index 000000000..981de747a
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_tbls_tst.java
@@ -0,0 +1,73 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+import org.junit.*;
+public class DsvDataWtr_tbls_tst {
+ @Before public void setup() {
+ DsvStoreLayout layout = DsvStoreLayout.dsv_brief_();
+ layout.HeaderList().Add_TableName();
+ wtr.InitWtr(DsvStoreLayout.Key_const, layout);
+ }
+ @Test public void Rows_0() {
+ root = fx_nde.tbl_("tbl0");
+ expd = String_.Concat_lines_crlf( "tbl0, ,\" \",#");
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Rows_N() {
+ root = fx_nde.tbl_
+ ( "numbers"
+ , fx_nde.row_vals_(1, 2, 3)
+ , fx_nde.row_vals_(4, 5, 6)
+ );
+ expd = String_.Concat_lines_crlf
+ ( "numbers, ,\" \",#"
+ , "1,2,3"
+ , "4,5,6"
+ );
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Tbls_N_Empty() {
+ root = fx_nde.root_
+ ( fx_nde.tbl_("tbl0")
+ , fx_nde.tbl_("tbl1")
+ );
+ expd = String_.Concat_lines_crlf
+ ( "tbl0, ,\" \",#"
+ , "tbl1, ,\" \",#"
+ );
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ @Test public void Tbls_N() {
+ root = fx_nde.root_
+ ( fx_nde.tbl_("letters"
+ , fx_nde.row_vals_("a", "b", "c"))
+ , fx_nde.tbl_("numbers"
+ , fx_nde.row_vals_(1, 2, 3)
+ , fx_nde.row_vals_(4, 5, 6)
+ ));
+ expd = String_.Concat_lines_crlf
+ ( "letters, ,\" \",#"
+ , "a,b,c"
+ , "numbers, ,\" \",#"
+ , "1,2,3"
+ , "4,5,6"
+ );
+ fx.tst_XtoStr(wtr, root, expd);
+ }
+ GfoNde root; String expd; DsvDataWtr wtr = DsvDataWtr_.csv_dat_(); DsvDataWtr_fxt fx = DsvDataWtr_fxt.new_(); GfoNdeFxt fx_nde = GfoNdeFxt.new_();
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvHeaderList.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvHeaderList.java
new file mode 100644
index 000000000..9448c7677
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvHeaderList.java
@@ -0,0 +1,44 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+public class DsvHeaderList {
+ @gplx.Internal protected int Count() {return list.Count();}
+ @gplx.Internal protected DsvHeaderItm FetchAt(int i) {return (DsvHeaderItm)list.FetchAt(i);}
+ public DsvHeaderList Add_LeafTypes() {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_LeafTypes, null)); return this;}
+ public DsvHeaderList Add_LeafNames() {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_LeafNames, null)); return this;}
+ public DsvHeaderList Add_TableName() {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_TableName, null)); return this;}
+ public DsvHeaderList Add_BlankLine() {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_BlankLine, null)); return this;}
+ public DsvHeaderList Add_Comment(String comment) {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_Comment, comment)); return this;}
+ void Add(DsvHeaderItm data) {list.Add(data);}
+
+ ListAdp list = ListAdp_.new_();
+ public static DsvHeaderList new_() {return new DsvHeaderList();} DsvHeaderList() {}
+}
+class DsvHeaderItm {
+ public int Id() {return id;} int id;
+ public Object Val() {return val;} Object val;
+ @gplx.Internal protected DsvHeaderItm(int id, Object val) {this.id = id; this.val = val;}
+
+ public static final int
+ Id_Comment = 1
+ , Id_TableName = 2
+ , Id_BlankLine = 3
+ , Id_LeafTypes = 4
+ , Id_LeafNames = 5
+ ;
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvStoreLayout.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvStoreLayout.java
new file mode 100644
index 000000000..495d52e17
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvStoreLayout.java
@@ -0,0 +1,51 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+public class DsvStoreLayout {
+ public DsvHeaderList HeaderList() {return headerList;} DsvHeaderList headerList = DsvHeaderList.new_();
+ @gplx.Internal protected boolean WriteCmdSequence() {return writeCmdSequence;} @gplx.Internal protected DsvStoreLayout WriteCmdSequence_(boolean val) {writeCmdSequence = val; return this;} private boolean writeCmdSequence;
+
+ static DsvStoreLayout new_() {return new DsvStoreLayout();}
+ public static DsvStoreLayout csv_dat_() {return new_();}
+ public static DsvStoreLayout csv_hdr_() {
+ DsvStoreLayout rv = new_();
+ rv.HeaderList().Add_LeafNames();
+ return rv;
+ }
+ public static DsvStoreLayout dsv_brief_() {
+ DsvStoreLayout rv = new_();
+ rv.writeCmdSequence = true;
+ return rv;
+ }
+ public static DsvStoreLayout dsv_full_() {
+ DsvStoreLayout rv = DsvStoreLayout.new_();
+ rv.writeCmdSequence = true;
+ rv.HeaderList().Add_BlankLine();
+ rv.HeaderList().Add_BlankLine();
+ rv.HeaderList().Add_Comment("================================");
+ rv.HeaderList().Add_TableName();
+ rv.HeaderList().Add_Comment("================================");
+ rv.HeaderList().Add_LeafTypes();
+ rv.HeaderList().Add_LeafNames();
+ rv.HeaderList().Add_Comment("================================");
+ return rv;
+ }
+ public static DsvStoreLayout as_(Object obj) {return obj instanceof DsvStoreLayout ? (DsvStoreLayout)obj : null;}
+ public static DsvStoreLayout cast_(Object obj) {try {return (DsvStoreLayout)obj;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, DsvStoreLayout.class, obj);}}
+ public static final String Key_const = "StoreLayoutWtr";
+}
diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvSymbols.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvSymbols.java
new file mode 100644
index 000000000..2e2e5f9ed
--- /dev/null
+++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvSymbols.java
@@ -0,0 +1,52 @@
+/*
+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.stores.dsvs; import gplx.*; import gplx.stores.*;
+class DsvSymbols {
+ public String FldSep() {return fldSep;} public DsvSymbols FldSep_(String v) {fldSep = v; CmdSequence_set(); return this;} private String fldSep;
+ public String RowSep() {return rowSep;}
+ public DsvSymbols RowSep_(String v) {
+ rowSep = v;
+ rowSepIsNewLine = String_.Has(v, "\n") || String_.Has(v, "\r");
+ return this;
+ } String rowSep;
+ public String QteDlm() {return qteDlm;} public void QteDlm_set(String v) {qteDlm = v; CmdSequence_set();} private String qteDlm;
+ public String CmdDlm() {return cmdDlm;} public void CmdDlm_set(String v) {cmdDlm = v; CmdSequence_set();} private String cmdDlm;
+ public String CmdSequence() {return cmdSequence;} private String cmdSequence;
+ public String CommentSym() {return commentSym;} public void CommentSym_set(String v) {commentSym = v;} private String commentSym;
+ public String TblNameSym() {return tblNameSym;} public void TblNamesSym_set(String v) {tblNameSym = v;} private String tblNameSym;
+ public String FldNamesSym() {return fldNamesSym;} public void FldNamesSym_set(String v) {fldNamesSym = v;} private String fldNamesSym;
+ public String FldTypesSym() {return fldTypesSym;} public void FldTypesSym_set(String v) {fldTypesSym = v;} private String fldTypesSym;
+ public boolean RowSepIsNewLine() {return rowSepIsNewLine;} private boolean rowSepIsNewLine;
+ public void Reset() {
+ fldSep = ",";
+ RowSep_ ("\r\n");
+
+ qteDlm = "\"";
+ cmdDlm = " ";
+ CmdSequence_set();
+
+ commentSym = "//";
+ tblNameSym = "#";
+ fldNamesSym = "@";
+ fldTypesSym = "$";
+ }
+ void CmdSequence_set() { // commandDelimiters are repeated; once without quotes and once with quotes; ex: , ," ",
+ cmdSequence = String_.Concat(cmdDlm, fldSep, qteDlm, cmdDlm, qteDlm);
+ }
+ public static DsvSymbols default_() {return new DsvSymbols();} DsvSymbols() {this.Reset();}
+}
diff --git a/100_core/src_400_gfs/gplx/GfsCore.java b/100_core/src_400_gfs/gplx/GfsCore.java
new file mode 100644
index 000000000..a7c301314
--- /dev/null
+++ b/100_core/src_400_gfs/gplx/GfsCore.java
@@ -0,0 +1,167 @@
+/*
+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;
+public class GfsCore implements GfoInvkAble {
+ public GfoInvkAble Root() {return root;}
+ @gplx.Internal protected GfsRegy Root_as_regy() {return root;} GfsRegy root = GfsRegy.new_();
+ public void Clear() {root.Clear();}
+ public GfoMsgParser MsgParser() {return msgParser;} public GfsCore MsgParser_(GfoMsgParser v) {msgParser = v; return this;} GfoMsgParser msgParser;
+ public void Del(String key) {root.Del(key);}
+ public void AddLib(GfsLibIni... ary) {for (GfsLibIni itm : ary) itm.Ini(this);}
+ public void AddCmd(GfoInvkAble invk, String key) {root.AddCmd(invk, key);}
+ public void AddObj(GfoInvkAble invk, String key) {root.AddObj(invk, key);}
+ public void AddDeep(GfoInvkAble invk, String... ary) {
+ GfoInvkCmdMgrOwner cur = (GfoInvkCmdMgrOwner)((GfsRegyItm)root.Fetch(ary[0])).InvkAble();
+ for (int i = 1; i < ary.length - 1; i++)
+ cur = (GfoInvkCmdMgrOwner)cur.InvkMgr().Invk(GfsCtx._, 0, ary[i], GfoMsg_.Null, cur);
+ cur.InvkMgr().Add_cmd(ary[ary.length - 1], invk);
+ }
+ public String FetchKey(GfoInvkAble invk) {return root.FetchByType(invk).Key();}
+ public Object ExecOne(GfsCtx ctx, GfoMsg msg) {return GfsCore_.Exec(ctx, root, msg, null, 0);}
+ public Object ExecOne_to(GfsCtx ctx, GfoInvkAble invk, GfoMsg msg) {return GfsCore_.Exec(ctx, invk, msg, null, 0);}
+ public Object ExecMany(GfsCtx ctx, GfoMsg rootMsg) {
+ Object rv = null;
+ for (int i = 0; i < rootMsg.Subs_count(); i++) {
+ GfoMsg subMsg = (GfoMsg)rootMsg.Subs_getAt(i);
+ rv = GfsCore_.Exec(ctx, root, subMsg, null, 0);
+ }
+ return rv;
+ }
+ public void ExecRegy(String key) {
+ GfoRegyItm itm = GfoRegy._.FetchOrNull(key);
+ if (itm == null) {UsrDlg_._.Warn(UsrMsg.new_("could not find script for key").Add("key", key)); return;}
+ Io_url url = itm.Url();
+ if (!Io_mgr._.ExistsFil(url)) {
+ UsrDlg_._.Warn(UsrMsg.new_("script url does not exist").Add("key", key).Add("url", url));
+ return;
+ }
+ this.ExecText(Io_mgr._.LoadFilStr(url));
+ }
+ public Object ExecFile_ignoreMissing(Io_url url) {if (!Io_mgr._.ExistsFil(url)) return null; return ExecText(Io_mgr._.LoadFilStr(url));}
+ public Object ExecFile(Io_url url) {return ExecText(Io_mgr._.LoadFilStr(url));}
+ public Object ExecFile_ignoreMissing(GfoInvkAble root, Io_url url) {
+ if (!Io_mgr._.ExistsFil(url)) return null;
+ if (msgParser == null) throw Err_.new_("msgParser is null");
+ return Exec_bry(Io_mgr._.LoadFilBry(url), root);
+ }
+ public Object Exec_bry(byte[] bry) {return Exec_bry(bry, root);}
+ public Object Exec_bry(byte[] bry, GfoInvkAble root) {
+ GfoMsg rootMsg = msgParser.ParseToMsg(String_.new_utf8_(bry));
+ Object rv = null;
+ GfsCtx ctx = GfsCtx.new_();
+ for (int i = 0; i < rootMsg.Subs_count(); i++) {
+ GfoMsg subMsg = (GfoMsg)rootMsg.Subs_getAt(i);
+ rv = GfsCore_.Exec(ctx, root, subMsg, null, 0);
+ }
+ return rv;
+ }
+ public Object ExecText(String text) {
+ if (msgParser == null) throw Err_.new_("msgParser is null");
+ GfsCtx ctx = GfsCtx.new_();
+ return ExecMany(ctx, msgParser.ParseToMsg(text));
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk_ExecFil)) {
+ Io_url url = m.ReadIoUrl("url");
+ if (ctx.Deny()) return this;
+ return ExecFile(url);
+ }
+ else return GfoInvkAble_.Rv_unhandled;
+// return this;
+ } public static final String Invk_ExecFil = "ExecFil";
+ public static final GfsCore _ = new GfsCore();
+ @gplx.Internal protected static GfsCore new_() {return new GfsCore();}
+}
+class GfsCore_ {
+ public static final String Arg_primitive = "v";
+ public static Object Exec(GfsCtx ctx, GfoInvkAble ownerInvk, GfoMsg ownerMsg, Object ownerPrimitive, int depth) {
+ if (ownerMsg.Args_count() == 0 && ownerMsg.Subs_count() == 0 && String_.Eq(ownerMsg.Key(), "")) {UsrDlg_._.Warn("empty msg"); return GfoInvkAble_.Rv_unhandled;}
+ if (ownerPrimitive != null) ownerMsg.Parse_(false).Add(GfsCore_.Arg_primitive, ownerPrimitive);
+ Object rv = ownerInvk.Invk(ctx, 0, ownerMsg.Key(), ownerMsg);
+ if (rv == GfoInvkAble_.Rv_cancel) return rv;
+ else if (rv == GfoInvkAble_.Rv_unhandled) {
+ if (ctx.Fail_if_unhandled())
+ throw Err_.new_("Object does not support key").Add("key", ownerMsg.Key()).Add("ownerType", ClassAdp_.FullNameOf_obj(ownerInvk));
+ else {
+ Gfo_usr_dlg usr_dlg = ctx.Usr_dlg();
+ if (usr_dlg != null) usr_dlg.Warn_many(GRP_KEY, "unhandled_key", "Object does not support key: key=~{0} ownerType=~{1}", ownerMsg.Key(), ClassAdp_.FullNameOf_obj(ownerInvk));
+ return GfoInvkAble_.Null;
+ }
+ }
+ if (ownerMsg.Subs_count() == 0) { // msg is leaf
+ GfsRegyItm regyItm = GfsRegyItm.as_(rv);
+ if (regyItm == null) return rv; // rv is primitive or other non-regy Object
+ if (regyItm.IsCmd()) // rv is cmd; invk cmd
+ return regyItm.InvkAble().Invk(ctx, 0, ownerMsg.Key(), ownerMsg);
+ else // rv is host
+ return regyItm.InvkAble();
+ }
+ else { // intermediate; cast to invk and call Exec
+ GfoInvkAble invk = GfoInvkAble_.as_(rv);
+ Object primitive = null;
+ if (invk == null) { // rv is primitive; find appropriate mgr
+ Class> type = rv.getClass();
+ if (type == String.class) invk = String_.Gfs;
+ else if (Int_.TypeMatch(type)) invk = Int_.Gfs;
+ else if (Bool_.TypeMatch(type)) invk = Bool_.Gfs;
+ else throw Err_.new_("unknown primitive").Add("type", ClassAdp_.NameOf_type(type)).Add("obj", Object_.XtoStr_OrNullStr(rv));
+ primitive = rv;
+ }
+ Object exec_rv = null;
+ int len = ownerMsg.Subs_count();
+ for (int i = 0; i < len; i++) // iterate over subs; needed for a{b;c;d;}
+ exec_rv = Exec(ctx, invk, ownerMsg.Subs_getAt(i), primitive, depth + 1);
+ return exec_rv;
+ }
+ }
+ static final String GRP_KEY = "gplx.gfs_core";
+}
+// class GfsRegyMgr : GfoInvkAble {
+// public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+// if (ctx.Match(k, Invk_Add)) {
+// String libKey = m.ReadStr("libKey"), regKey = m.ReadStr("regKey");
+// if (ctx.Deny()) return this;
+// GfsRegyItm itm = regy.Fetch(libKey);
+// if (regy.Has(regKey)) {ctx.Write_warn("'{0}' already exists", regKey); return this;}
+// regy.Add(regKey, itm.InvkAble(), itm.Type_cmd());
+// ctx.Write_note("added '{0}' as '{1}'", regKey, libKey);
+// }
+// else if (ctx.Match(k, Invk_Del)) {
+// String regKey = m.ReadStr("regKey");
+// if (ctx.Deny()) return this;
+// if (!regy.Has(regKey)) {ctx.Write_warn("{0} does not exist", regKey); return this;}
+// regy.Del(regKey);
+// ctx.Write_note("removed '{0}'", regKey);
+// }
+// else if (ctx.Match(k, Invk_Load)) {
+// Io_url url = (Io_url)m.ReadObj("url", Io_url_.Parser);
+// if (ctx.Deny()) return this;
+// String loadText = Io_mgr._.LoadFilStr(url);
+// GfoMsg loadMsg = core.MsgParser().ParseToMsg(loadText);
+// return core.Exec(ctx, loadMsg);
+// }
+// else return GfoInvkAble_.Rv_unhandled;
+// return this;
+// } public static final String Invk_Add = "Add", Invk_Del = "Del", Invk_Load = "Load";
+// GfsCore core; GfsRegy regy;
+// public static GfsRegyMgr new_(GfsCore core, GfsRegy regy) {
+// GfsRegyMgr rv = new GfsRegyMgr();
+// rv.core = core; rv.regy = regy;
+// return rv;
+// } GfsRegyMgr() {}
+// }
diff --git a/100_core/src_400_gfs/gplx/GfsCoreHelp.java b/100_core/src_400_gfs/gplx/GfsCoreHelp.java
new file mode 100644
index 000000000..668d89e3d
--- /dev/null
+++ b/100_core/src_400_gfs/gplx/GfsCoreHelp.java
@@ -0,0 +1,72 @@
+/*
+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;
+class GfsCoreHelp implements GfoInvkAble {
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ String path = m.ReadStrOr("path", "");
+ if (String_.Eq(path, "")) {
+ String_bldr sb = String_bldr_.new_();
+ for (int i = 0; i < core.Root_as_regy().Count(); i++) {
+ GfsRegyItm itm = (GfsRegyItm)core.Root_as_regy().FetchAt(i);
+ sb.Add_spr_unless_first(itm.Key(), String_.CrLf, i);
+ }
+ return sb.XtoStr();
+ }
+ else return Exec(ctx, core.Root_as_regy(), path);
+ }
+ public static Err Err_Unhandled(String objPath, String key) {return Err_.new_("obj does not handle msgKey").Add("objPath", objPath).Add("key", key);}
+ static Err Err_Unhandled(String[] itmAry, int i) {
+ String_bldr sb = String_bldr_.new_();
+ for (int j = 0; j < i; j++)
+ sb.Add_spr_unless_first(itmAry[j], ".", j);
+ return Err_Unhandled(sb.XtoStr(), itmAry[i]);
+ }
+ static Object Exec(GfsCtx rootCtx, GfoInvkAble rootInvk, String path) {
+ String[] itmAry = String_.Split(path, ".");
+ GfoInvkAble invk = rootInvk;
+ GfsCtx ctx = GfsCtx.new_();
+ Object curRv = null;
+ for (int i = 0; i < itmAry.length; i++) {
+ String itm = itmAry[i];
+ curRv = invk.Invk(ctx, 0, itm, GfoMsg_.Null);
+ if (curRv == GfoInvkAble_.Rv_unhandled) throw Err_Unhandled(itmAry, i);
+ invk = GfoInvkAble_.as_(curRv);
+ }
+ GfsCoreHelp helpData = GfsCoreHelp.as_(curRv);
+ if (helpData != null) { // last itm is actually Method
+ return "";
+ }
+ else {
+ ctx = GfsCtx.new_().Help_browseMode_(true);
+ invk.Invk(ctx, 0, "", GfoMsg_.Null);
+ String_bldr sb = String_bldr_.new_();
+ for (int i = 0; i < ctx.Help_browseList().Count(); i++) {
+ String s = (String)ctx.Help_browseList().FetchAt(i);
+ sb.Add_spr_unless_first(s, String_.CrLf, i);
+ }
+ return sb.XtoStr();
+ }
+ }
+ public static GfsCoreHelp as_(Object obj) {return obj instanceof GfsCoreHelp ? (GfsCoreHelp)obj : null;}
+ public static GfsCoreHelp new_(GfsCore core) {
+ GfsCoreHelp rv = new GfsCoreHelp();
+ rv.core = core;
+ return rv;
+ } GfsCoreHelp() {}
+ GfsCore core;
+}
diff --git a/100_core/src_400_gfs/gplx/GfsCore_tst.java b/100_core/src_400_gfs/gplx/GfsCore_tst.java
new file mode 100644
index 000000000..7a1316bef
--- /dev/null
+++ b/100_core/src_400_gfs/gplx/GfsCore_tst.java
@@ -0,0 +1,113 @@
+/*
+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;
+import org.junit.*;
+public class GfsCore_tst {
+ @Before public void setup() {
+ core = GfsCore.new_();
+ core.AddObj(String_.Gfs, "String_");
+ core.AddObj(Int_.Gfs, "Int_");
+ } GfsCore core;
+ @Test public void Basic() { // String_.Len('abc') >> 3
+ tst_Msg
+ ( msg_("String_").Subs_
+ ( msg_("Len").Add("v", "abc"))
+ , 3);
+ }
+ @Test public void PrimitiveConversion() { // String_.Len('abc').Add(-3) >> 0
+ tst_Msg
+ ( msg_("String_").Subs_
+ ( msg_("Len").Add("v", "abc").Subs_
+ ( msg_("Add").Add("operand", -3))
+ )
+ , 0);
+ }
+// @Test public void Fail_notFound() { // String_.DoesNotExists
+// tst_Err
+// ( msg_("help").Add("", "String_.DoesNotExist")
+// , GfsHelp.Err_Unhandled("String_", "DoesNotExist"));
+// }
+ @Test public void Cmd() { // cmd
+ core.AddCmd(new GfsTest_cmd(), "testCmd");
+ tst_Msg
+ ( msg_("testCmd").Add("s", "pass")
+ , "pass");
+ }
+ @Test public void EmptyMsg() {
+ tst_Msg
+ ( msg_("")
+ , GfoInvkAble_.Rv_unhandled);
+ }
+// @Test public void Fail_argMissing() { // String_.Len()
+// tst_String__Len_Err(msg_("Len"), GfsCtx.Err_KeyNotFound("v", "<>"));
+// }
+// @Test public void Fail_argWrongKey() { // String_.Len(badKey='abc')
+// tst_String__Len_Err(msg_("Len").Add("badKey", "abc"), GfsCtx.Err_KeyNotFound("v", "badKey;"));
+// }
+// @Test public void Fail_argExtraKey() { // String_.Len(v='abc' extraKey=1)
+// tst_String__Len_Err(msg_("Len").Add("v", "abc").Add("extraKey", 1), GfsCtx.Err_KeyNotFound("v", "badKey;"));
+// }
+ @Test public void Add_obj_deep() { // String_.Len(badKey='abc')
+ GfsCore_tst_nest obj1 = GfsCore_tst_nest.new_("1", "val1");
+ GfsCore_tst_nest obj1_1 = GfsCore_tst_nest.new_("1_1", "val2");
+ core.AddObj(obj1, "1");
+ core.AddDeep(obj1_1, "1", "1_1");
+
+ GfoMsg root = GfoMsg_.root_("1", "1_1", GfsCore_tst_nest.Prop2);
+ Object actl = core.ExecOne(GfsCtx._, root);
+ Tfds.Eq("val2", actl);
+ }
+ void tst_String__Len_Err(GfoMsg m, Err expd) {
+ tst_Err(msg_("String_").Subs_(m), expd);
+ }
+ void tst_Err(GfoMsg msg, Err expd) {
+ GfoMsg root = msg;
+ GfsCtx ctx = GfsCtx.new_();
+ try {
+ core.ExecOne(ctx, root);
+ Tfds.Fail_expdError();
+ }
+ catch (Exception e) {
+ Tfds.Eq_err(expd, e);
+ }
+ }
+ GfoMsg msg_(String k) {return GfoMsg_.new_cast_(k);}
+ void tst_Msg(GfoMsg msg, Object expd) {
+ GfsCtx ctx = GfsCtx.new_();
+ Object actl = core.ExecOne(ctx, msg);
+ Tfds.Eq(expd, actl);
+ }
+}
+class GfsCore_tst_nest implements GfoInvkAble, GfoInvkCmdMgrOwner {
+ public GfoInvkCmdMgr InvkMgr() {return invkMgr;} GfoInvkCmdMgr invkMgr = GfoInvkCmdMgr.new_();
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Prop1)) {return prop1;}
+ else if (ctx.Match(k, Prop2)) {return prop2;}
+ else if (ctx.Match(k, prop1)) {return this;}
+ else return invkMgr.Invk(ctx, ikey, k, m, this);
+ } public static final String Prop1 = "Prop1", Prop2 = "Prop2";
+ String prop1, prop2;
+ public static GfsCore_tst_nest new_(String prop1, String prop2) {
+ GfsCore_tst_nest rv = new GfsCore_tst_nest();
+ rv.prop1 = prop1; rv.prop2 = prop2;
+ return rv;
+ } GfsCore_tst_nest() {}
+}
+class GfsTest_cmd implements GfoInvkAble {
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return m.ReadStr("s");}
+}
diff --git a/100_core/src_400_gfs/gplx/GfsCtx.java b/100_core/src_400_gfs/gplx/GfsCtx.java
new file mode 100644
index 000000000..b3fedf647
--- /dev/null
+++ b/100_core/src_400_gfs/gplx/GfsCtx.java
@@ -0,0 +1,65 @@
+/*
+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;
+public class GfsCtx {
+ public OrderedHash Vars() {return vars;} OrderedHash vars = OrderedHash_.new_();
+ public boolean Fail_if_unhandled() {return fail_if_unhandled;} public GfsCtx Fail_if_unhandled_(boolean v) {fail_if_unhandled = v; return this;} private boolean fail_if_unhandled;
+ public Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public GfsCtx Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v; return this;} Gfo_usr_dlg usr_dlg;
+ public boolean Help_browseMode() {return help_browseMode;} public GfsCtx Help_browseMode_(boolean v) {help_browseMode = v; return this;} private boolean help_browseMode;
+ @gplx.Internal protected ListAdp Help_browseList() {return help_browseList;} ListAdp help_browseList = ListAdp_.new_();
+ public Object MsgSrc() {return msgSrc;} public GfsCtx MsgSrc_(Object v) {msgSrc = v; return this;} Object msgSrc;
+ public boolean Match(String k, String match) {
+ if (help_browseMode) {
+ help_browseList.Add(match);
+ return false;
+ }
+ else
+ return String_.Eq(k, match);
+ }
+ public boolean MatchPriv(String k, String match) {return help_browseMode ? false : String_.Eq(k, match);}
+ public boolean MatchIn(String k, String... match) {
+ if (help_browseMode) {
+ for (String i : match)
+ help_browseList.Add(i);
+ return false;
+ }
+ return String_.In(k, match);
+ }
+ public boolean Write_note(String fmt, Object... ary) {UsrDlg_._.Note(fmt, ary); return false;}
+ public boolean Write_warn(String fmt, Object... ary) {UsrDlg_._.Note("! " + fmt, ary); return false;}
+ public boolean Write_stop(UsrMsg umsg) {UsrDlg_._.Note("* " + umsg.XtoStr()); return false;}
+ public boolean Write_stop(String fmt, Object... ary) {UsrDlg_._.Note("* " + fmt, ary); return false;}
+ public boolean Deny() {return deny;} private boolean deny;
+ public static final GfsCtx _ = new GfsCtx();
+ public static GfsCtx new_() {return new GfsCtx();} GfsCtx() {}
+ public static GfsCtx rdr_() {
+ GfsCtx rv = new GfsCtx();
+ rv.deny = true;
+ rv.mode = "read";
+ return rv;
+ }
+ public static GfsCtx wtr_() {
+ GfsCtx rv = new GfsCtx();
+ rv.deny = true;
+ rv.mode = Mode_write;
+ return rv;
+ }
+ public String Mode() {return mode;} public GfsCtx Mode_(String v) {mode = v; return this;} private String mode = "regular";
+ public static final String Mode_write = "write";
+ public static final int Ikey_null = -1;
+}
diff --git a/100_core/src_400_gfs/gplx/GfsLibIni.java b/100_core/src_400_gfs/gplx/GfsLibIni.java
new file mode 100644
index 000000000..da359de29
--- /dev/null
+++ b/100_core/src_400_gfs/gplx/GfsLibIni.java
@@ -0,0 +1,21 @@
+/*
+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;
+public interface GfsLibIni {
+ void Ini(GfsCore core);
+}
diff --git a/100_core/src_400_gfs/gplx/GfsLibIni_core.java b/100_core/src_400_gfs/gplx/GfsLibIni_core.java
new file mode 100644
index 000000000..2b1e241a7
--- /dev/null
+++ b/100_core/src_400_gfs/gplx/GfsLibIni_core.java
@@ -0,0 +1,35 @@
+/*
+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;
+public class GfsLibIni_core implements GfsLibIni {
+ public void Ini(GfsCore core) {
+ core.AddCmd(GfsCoreHelp.new_(core), "help");
+ core.AddObj(String_.Gfs, "String_");
+ core.AddObj(Int_.Gfs, "Int_");
+ core.AddObj(DateAdp_.Gfs, "Date_");
+ core.AddObj(RandomAdp_.Gfs, "RandomAdp_");
+ core.AddObj(GfoTemplateFactory._, "factory");
+ core.AddObj(GfoRegy._, "GfoRegy_");
+ core.AddObj(GfsCore._, "GfsCore_");
+ core.AddObj(gplx.ios.IoUrlInfoRegy._, "IoUrlInfoRegy_");
+ core.AddObj(gplx.ios.IoUrlTypeRegy._, "IoUrlTypeRegy_");
+
+ GfoRegy._.Parsers().Add("Io_url", Io_url_.Parser);
+ }
+ public static final GfsLibIni_core _ = new GfsLibIni_core(); GfsLibIni_core() {}
+}
diff --git a/100_core/src_400_gfs/gplx/GfsRegy.java b/100_core/src_400_gfs/gplx/GfsRegy.java
new file mode 100644
index 000000000..0391449dc
--- /dev/null
+++ b/100_core/src_400_gfs/gplx/GfsRegy.java
@@ -0,0 +1,54 @@
+/*
+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;
+class GfsRegy implements GfoInvkAble {
+ public int Count() {return hash.Count();}
+ public void Clear() {hash.Clear(); typeHash.Clear();}
+ public boolean Has(String k) {return hash.Has(k);}
+ public GfsRegyItm FetchAt(int i) {return (GfsRegyItm)hash.FetchAt(i);}
+ public GfsRegyItm Fetch(String key) {return (GfsRegyItm)hash.Fetch(key);}
+ public GfsRegyItm FetchByType(GfoInvkAble invk) {return (GfsRegyItm)typeHash.Fetch(ClassAdp_.FullNameOf_obj(invk));}
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ Object rv = (GfsRegyItm)hash.Fetch(k); if (rv == null) throw Err_.missing_key_(k);
+ return rv;
+ }
+ public void AddObj(GfoInvkAble invk, String key) {Add(key, invk, false);}
+ public void AddCmd(GfoInvkAble invk, String key) {Add(key, invk, true);}
+ public void Add(String key, GfoInvkAble invk, boolean typeCmd) {
+ if (hash.Has(key)) return;
+ GfsRegyItm regyItm = new GfsRegyItm().Key_(key).InvkAble_(invk).IsCmd_(typeCmd).TypeKey_(ClassAdp_.FullNameOf_obj(invk));
+ hash.Add(key, regyItm);
+ typeHash.Add_if_new(regyItm.TypeKey(), regyItm); // NOTE: changed to allow same Object to be added under different aliases (app, xowa) DATE:2014-06-09;
+ }
+ public void Del(String k) {
+ GfsRegyItm itm =(GfsRegyItm)hash.Fetch(k);
+ if (itm != null) typeHash.Del(itm.TypeKey());
+ hash.Del(k);
+ }
+ HashAdp typeHash = HashAdp_.new_();
+ OrderedHash hash = OrderedHash_.new_();
+ public static GfsRegy new_() {return new GfsRegy();} GfsRegy() {}
+}
+class GfsRegyItm implements GfoInvkAble {
+ public String Key() {return key;} public GfsRegyItm Key_(String v) {key = v; return this;} private String key;
+ public String TypeKey() {return typeKey;} public GfsRegyItm TypeKey_(String v) {typeKey = v; return this;} private String typeKey;
+ public boolean IsCmd() {return isCmd;} public GfsRegyItm IsCmd_(boolean v) {isCmd = v; return this;} private boolean isCmd;
+ public GfoInvkAble InvkAble() {return invkAble;} public GfsRegyItm InvkAble_(GfoInvkAble v) {invkAble = v; return this;} GfoInvkAble invkAble;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return invkAble.Invk(ctx, ikey, k, m);}
+ public static GfsRegyItm as_(Object obj) {return obj instanceof GfsRegyItm ? (GfsRegyItm)obj : null;}
+}
diff --git a/100_core/src_400_gfs/gplx/GfsTypeNames.java b/100_core/src_400_gfs/gplx/GfsTypeNames.java
new file mode 100644
index 000000000..70c581f50
--- /dev/null
+++ b/100_core/src_400_gfs/gplx/GfsTypeNames.java
@@ -0,0 +1,28 @@
+/*
+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;
+public class GfsTypeNames {
+ public static final String
+ String = "string"
+ , Int = "int"
+ , Bool = "bool"
+ , Float = "float"
+ , YesNo = "yn"
+ , Date = "date"
+ ;
+}
diff --git a/100_core/src_400_gfs/gplx/Gfs_Date_tst.java b/100_core/src_400_gfs/gplx/Gfs_Date_tst.java
new file mode 100644
index 000000000..5ddeaa0a7
--- /dev/null
+++ b/100_core/src_400_gfs/gplx/Gfs_Date_tst.java
@@ -0,0 +1,42 @@
+/*
+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;
+import org.junit.*;
+public class Gfs_Date_tst {
+ @Before public void setup() {
+ fx = new GfsCoreFxt();
+ fx.AddObj(DateAdp_.Gfs, "Date_");
+ Tfds.Now_enabled_y_();
+ } GfsCoreFxt fx;
+ @Test public void Now() {
+ fx.tst_MsgStr(fx.msg_(String_.Ary("Date_", "Now")), DateAdp_.parse_gplx("2001-01-01 00:00:00.000"));
+ }
+ @Test public void Add_day() {
+ fx.tst_MsgStr(fx.msg_(String_.Ary("Date_", "Now", "Add_day"), KeyVal_.new_("days", 1)), DateAdp_.parse_gplx("2001-01-02 00:00:00.000"));
+ }
+}
+class GfsCoreFxt {
+ public GfsCore Core() {return core;} GfsCore core = GfsCore.new_();
+ public GfoMsg msg_(String[] ary, KeyVal... kvAry) {return GfoMsg_.root_leafArgs_(ary, kvAry);}
+ public void AddObj(GfoInvkAble invk, String s) {core.AddObj(invk, s);}
+ public void tst_MsgStr(GfoMsg msg, Object expd) {
+ GfsCtx ctx = GfsCtx.new_();
+ Object actl = core.ExecOne(ctx, msg);
+ Tfds.Eq(Object_.XtoStr_OrNullStr(expd), Object_.XtoStr_OrNullStr(actl));
+ }
+}
diff --git a/100_core/src_410_gfoCfg/gplx/GfoMsgParser.java b/100_core/src_410_gfoCfg/gplx/GfoMsgParser.java
new file mode 100644
index 000000000..a149505f1
--- /dev/null
+++ b/100_core/src_410_gfoCfg/gplx/GfoMsgParser.java
@@ -0,0 +1,21 @@
+/*
+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;
+public interface GfoMsgParser {
+ GfoMsg ParseToMsg(String s);
+}
diff --git a/100_core/src_410_gfoCfg/gplx/GfoRegy.java b/100_core/src_410_gfoCfg/gplx/GfoRegy.java
new file mode 100644
index 000000000..fb108b186
--- /dev/null
+++ b/100_core/src_410_gfoCfg/gplx/GfoRegy.java
@@ -0,0 +1,94 @@
+/*
+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;
+public class GfoRegy implements GfoInvkAble {
+ public int Count() {return hash.Count();}
+ public HashAdp Parsers() {return parsers;} HashAdp parsers = HashAdp_.new_();
+ public GfoRegyItm FetchOrNull(String key) {return (GfoRegyItm)hash.Fetch(key);}
+ public Object FetchValOrFail(String key) {
+ GfoRegyItm rv = (GfoRegyItm)hash.Fetch(key); if (rv == null) throw Err_.new_("regy does not have key").Add("key", key);
+ return rv.Val();
+ }
+ public Object FetchValOrNull(String key) {return FetchValOr(key, null);}
+ public Object FetchValOr(String key, Object or) {
+ GfoRegyItm itm = FetchOrNull(key);
+ return itm == null ? or : itm.Val();
+ }
+ public void Del(String key) {hash.Del(key);}
+ public void RegObj(String key, Object val) {RegItm(key, val, GfoRegyItm.ValType_Obj, Io_url_.Null);}
+ public void RegDir(Io_url dirUrl, String match, boolean recur, String chopBgn, String chopEnd) {
+ Io_url[] filUrls = Io_mgr._.QueryDir_args(dirUrl).FilPath_(match).Recur_(recur).ExecAsUrlAry();
+ if (filUrls.length == 0 && !Io_mgr._.ExistsDir(dirUrl)) {UsrDlg_._.Stop(UsrMsg.new_("dirUrl does not exist").Add("dirUrl", dirUrl.Xto_api())); return;}
+ for (Io_url filUrl : filUrls) {
+ String key = filUrl.NameAndExt();
+ int pos = String_.Find_none;
+ if (String_.EqNot(chopBgn, "")) {
+ pos = String_.FindFwd(key, chopBgn);
+ if (pos == String_.Len(key) - 1)
+ throw Err_.new_(Err_ChopBgn).Add("key", key).Add("chopBgn", chopBgn);
+ else if (pos != String_.Find_none)
+ key = String_.Mid(key, pos + 1);
+ }
+ if (String_.EqNot(chopEnd, "")) {
+ pos = String_.FindBwd(key, chopEnd);
+ if (pos == 0)
+ throw Err_.new_(Err_ChopEnd).Add("key", key).Add("chopEnd", chopEnd);
+ else if (pos != String_.Find_none)
+ key = String_.MidByLen(key, 0, pos);
+ }
+ if (hash.Has(key)) throw Err_.new_(Err_Dupe).Add("key", key).Add("filUrl", filUrl);
+ RegItm(key, null, GfoRegyItm.ValType_Url, filUrl);
+ }
+ }
+ public void RegObjByType(String key, String val, String type) {
+ Object o = val;
+ if (String_.EqNot(type, StringClassXtn.Key_const)) {
+ ParseAble parser = (ParseAble)parsers.Fetch(type);
+ if (parser == null) throw Err_.new_("could not find parser").Add("type", type).Add("key", key).Add("val", val);
+ o = parser.ParseAsObj(val);
+ }
+ RegItm(key, o, GfoRegyItm.ValType_Obj, Io_url_.Null);
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk_RegDir)) {
+ Io_url dir = m.ReadIoUrl("dir");
+ String match = m.ReadStrOr("match", "*.*");
+ boolean recur = m.ReadBoolOr("recur", false);
+ String chopBgn = m.ReadStrOr("chopBgn", "");
+ String chopEnd = m.ReadStrOr("chopEnd", ".");
+ if (ctx.Deny()) return this;
+ RegDir(dir, match, recur, chopBgn, chopEnd);
+ }
+ else if (ctx.Match(k, Invk_RegObj)) {
+ String key = m.ReadStr("key");
+ String val = m.ReadStr("val");
+ String type = m.ReadStrOr("type", StringClassXtn.Key_const);
+ if (ctx.Deny()) return this;
+ RegObjByType(key, val, type);
+ }
+ else return GfoInvkAble_.Rv_unhandled;
+ return this;
+ } public static final String Invk_RegDir = "RegDir", Invk_RegObj = "RegObj";
+ void RegItm(String key, Object val, int valType, Io_url url) {
+ hash.AddReplace(key, new GfoRegyItm(key, val, valType, url));
+ }
+ HashAdp hash = HashAdp_.new_();
+ public static final String Err_ChopBgn = "chopBgn results in null key", Err_ChopEnd = "chopEnd results in null key", Err_Dupe = "key already registered";
+ public static final GfoRegy _ = new GfoRegy(); GfoRegy() {}
+ @gplx.Internal protected static GfoRegy new_() {return new GfoRegy();}
+}
diff --git a/100_core/src_410_gfoCfg/gplx/GfoRegyItm.java b/100_core/src_410_gfoCfg/gplx/GfoRegyItm.java
new file mode 100644
index 000000000..afada9f7c
--- /dev/null
+++ b/100_core/src_410_gfoCfg/gplx/GfoRegyItm.java
@@ -0,0 +1,31 @@
+/*
+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;
+public class GfoRegyItm {
+ public String Key() {return key;} private String key;
+ public Object Val() {return val;} Object val;
+ public Io_url Url() {return url;} Io_url url;
+ public int ValType() {return valType;} int valType;
+ public GfoRegyItm(String key, Object val, int valType, Io_url url) {this.key = key; this.val = val; this.valType = valType; this.url = url;}
+
+ public static final int
+ ValType_Obj = 1
+ , ValType_Url = 2
+ , ValType_B64 = 3
+ ;
+}
diff --git a/100_core/src_410_gfoCfg/gplx/GfoRegy_RegDir_tst.java b/100_core/src_410_gfoCfg/gplx/GfoRegy_RegDir_tst.java
new file mode 100644
index 000000000..88a5bc0cd
--- /dev/null
+++ b/100_core/src_410_gfoCfg/gplx/GfoRegy_RegDir_tst.java
@@ -0,0 +1,61 @@
+/*
+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;
+import org.junit.*;
+public class GfoRegy_RegDir_tst {
+ @Before public void setup() {
+ regy = GfoRegy.new_();
+ Io_mgr._.InitEngine_mem();
+ root = Io_url_.mem_dir_("mem/root");
+ } GfoRegy regy; Io_url root;
+ @Test public void Basic() {
+ ini_fil("101_tsta.txt");
+ ini_fil("102_tstb.txt");
+ ini_fil("103_tstc.png");
+ ini_fil("dir1", "104_tstd.txt");
+ regy.RegDir(root, "*.txt", false, "_", ".");
+ tst_Count(2);
+ tst_Exists("tsta");
+ tst_Exists("tstb");
+ }
+ @Test public void Err_dupe() {
+ ini_fil("101_tsta.txt");
+ ini_fil("102_tsta.txt");
+ try {regy.RegDir(root, "*.txt", false, "_", ".");}
+ catch (Exception e) {Tfds.Err_has(e, GfoRegy.Err_Dupe); return;}
+ Tfds.Fail_expdError();
+ }
+ @Test public void Err_chopBgn() {
+ ini_fil("123_");
+ try {regy.RegDir(root, "*", false, "_", ".");}
+ catch (Exception e) {Tfds.Err_has(e, GfoRegy.Err_ChopBgn); return;}
+ Tfds.Fail_expdError();
+ }
+ @Test public void Err_chopEnd() {
+ ini_fil(".txt");
+ try {regy.RegDir(root, "*.txt", false, "_", ".");}
+ catch (Exception e) {Tfds.Err_has(e, GfoRegy.Err_ChopEnd); return;}
+ Tfds.Fail_expdError();
+ }
+ void tst_Count(int expd) {Tfds.Eq(expd, regy.Count());}
+ void tst_Exists(String expd) {
+ GfoRegyItm itm = regy.FetchOrNull(expd);
+ Tfds.Eq_nullNot(itm);
+ }
+ void ini_fil(String... nest) {Io_mgr._.SaveFilStr(root.GenSubFil_nest(nest), "");}
+}
diff --git a/100_core/src_410_gfoCfg/gplx/GfoRegy_basic_tst.java b/100_core/src_410_gfoCfg/gplx/GfoRegy_basic_tst.java
new file mode 100644
index 000000000..b11c05ae9
--- /dev/null
+++ b/100_core/src_410_gfoCfg/gplx/GfoRegy_basic_tst.java
@@ -0,0 +1,31 @@
+/*
+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;
+import org.junit.*;
+public class GfoRegy_basic_tst {
+ @Before public void setup() {
+ regy = GfoRegy.new_();
+ } GfoRegy regy;
+ @Test public void RegObjByType() {
+ regy.Parsers().Add("Io_url", Io_url_.Parser);
+ Io_url expd = Io_url_.new_any_("C:\\fil.txt");
+ regy.RegObjByType("test", expd.Xto_api(), "Io_url");
+ Io_url actl = (Io_url)regy.FetchValOr("test", Io_url_.Null);
+ Tfds.Eq(expd.Xto_api(), actl.Xto_api());
+ }
+}
diff --git a/100_core/src_420_usrMsg/gplx/Gfo_log_bfr.java b/100_core/src_420_usrMsg/gplx/Gfo_log_bfr.java
new file mode 100644
index 000000000..6ab5589e2
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/Gfo_log_bfr.java
@@ -0,0 +1,29 @@
+/*
+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;
+public class Gfo_log_bfr {
+ private Bry_bfr bfr = Bry_bfr.reset_(255);
+ public Gfo_log_bfr Add(String s) {
+ bfr.Add_str(DateAdp_.Now().XtoUtc().XtoStr_fmt_yyyyMMdd_HHmmss_fff());
+ bfr.Add_byte_space();
+ bfr.Add_str(s);
+ bfr.Add_byte_nl();
+ return this;
+ }
+ public String Xto_str() {return bfr.XtoStrAndClear();}
+}
diff --git a/100_core/src_420_usrMsg/gplx/Gfo_log_wtr.java b/100_core/src_420_usrMsg/gplx/Gfo_log_wtr.java
new file mode 100644
index 000000000..946a283e5
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/Gfo_log_wtr.java
@@ -0,0 +1,32 @@
+/*
+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;
+public interface Gfo_log_wtr extends GfoInvkAble {
+ Io_url Session_dir();
+ Io_url Log_dir(); void Log_dir_(Io_url v);
+ Io_url Session_fil();
+ boolean Enabled(); void Enabled_(boolean v);
+ boolean Queue_enabled(); void Queue_enabled_(boolean v);
+ void Log_msg_to_url_fmt(Io_url url, String fmt, Object... args);
+ void Log_msg_to_session(String txt);
+ void Log_msg_to_session_fmt(String fmt, Object... args);
+ void Log_msg_to_session_direct(String txt);
+ void Log_err(String txt);
+ void Init();
+ void Term();
+}
diff --git a/100_core/src_420_usrMsg/gplx/Gfo_log_wtr_.java b/100_core/src_420_usrMsg/gplx/Gfo_log_wtr_.java
new file mode 100644
index 000000000..65892cf1b
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/Gfo_log_wtr_.java
@@ -0,0 +1,36 @@
+/*
+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;
+public class Gfo_log_wtr_ {
+ public static final Gfo_log_wtr Null = new Gfo_log_wtr_null();
+}
+class Gfo_log_wtr_null implements Gfo_log_wtr {
+ public Io_url Session_fil() {return Io_url_.Null;}
+ public Io_url Session_dir() {return Io_url_.Null;}
+ public Io_url Log_dir() {return Io_url_.Null;} public void Log_dir_(Io_url v) {}
+ public boolean Enabled() {return enabled;} public void Enabled_(boolean v) {enabled = v;} private boolean enabled;
+ public boolean Queue_enabled() {return queue_enabled;} public void Queue_enabled_(boolean v) {queue_enabled = v;} private boolean queue_enabled;
+ public void Log_msg_to_url_fmt(Io_url url, String fmt, Object... args) {}
+ public void Log_msg_to_session_fmt(String fmt, Object... args) {}
+ public void Log_msg_to_session(String txt) {}
+ public void Log_msg_to_session_direct(String txt) {}
+ public void Log_err(String txt) {}
+ public void Init() {}
+ public void Term() {}
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;}
+}
diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg.java
new file mode 100644
index 000000000..b1a0b6849
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg.java
@@ -0,0 +1,35 @@
+/*
+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;
+public interface Gfo_usr_dlg extends GfoInvkAble, Cancelable {
+ void Canceled_y_(); void Canceled_n_();
+ void Clear();
+ Gfo_usr_dlg_ui Ui_wkr(); void Ui_wkr_(Gfo_usr_dlg_ui v);
+ Gfo_log_wtr Log_wtr(); void Log_wtr_(Gfo_log_wtr v);
+ String Log_many(String grp_key, String msg_key, String fmt, Object... args);
+ String Warn_many(String grp_key, String msg_key, String fmt, Object... args);
+ Err Fail_many(String grp_key, String msg_key, String fmt, Object... args);
+ String Prog_many(String grp_key, String msg_key, String fmt, Object... args);
+ String Prog_none(String grp_key, String msg_key, String fmt);
+ String Note_many(String grp_key, String msg_key, String fmt, Object... args);
+ String Note_none(String grp_key, String msg_key, String fmt);
+ String Note_gui_none(String grp_key, String msg_key, String fmt);
+ String Prog_one(String grp_key, String msg_key, String fmt, Object arg);
+ String Prog_direct(String msg);
+ String Log_direct(String msg);
+}
diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_.java
new file mode 100644
index 000000000..385fcda98
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_.java
@@ -0,0 +1,42 @@
+/*
+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;
+public class Gfo_usr_dlg_ {
+ public static Gfo_usr_dlg _ = Gfo_usr_dlg_null._;
+ public static final Gfo_usr_dlg Null = Gfo_usr_dlg_null._;
+}
+class Gfo_usr_dlg_null implements Gfo_usr_dlg {
+ public boolean Canceled() {return false;} public void Canceled_y_() {} public void Canceled_n_() {}
+ public void Cancel() {} public void Cancel_reset() {}
+ public void Clear() {}
+ public Gfo_usr_dlg_ui Ui_wkr() {throw Err_.not_implemented_();} public void Ui_wkr_(Gfo_usr_dlg_ui v) {}
+ public Gfo_log_wtr Log_wtr() {throw Err_.not_implemented_();} public void Log_wtr_(Gfo_log_wtr v) {}
+ public String Log_many(String grp_key, String msg_key, String fmt, Object... args) {return "";}
+ public String Warn_many(String grp_key, String msg_key, String fmt, Object... args) {return "";}
+ public Err Fail_many(String grp_key, String msg_key, String fmt, Object... args) {return Err_.new_(fmt);}
+ public String Prog_many(String grp_key, String msg_key, String fmt, Object... args) {return "";}
+ public String Prog_none(String grp_key, String msg_key, String fmt) {return "";}
+ public String Note_many(String grp_key, String msg_key, String fmt, Object... args) {return "";}
+ public String Note_none(String grp_key, String msg_key, String fmt) {return "";}
+ public String Note_gui_none(String grp_key, String msg_key, String fmt) {return "";}
+ public String Prog_one(String grp_key, String msg_key, String fmt, Object arg) {return "";}
+ public String Prog_direct(String msg) {return "";}
+ public String Log_direct(String msg) {return "";}
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;}
+ public static final Gfo_usr_dlg_null _ = new Gfo_usr_dlg_null(); Gfo_usr_dlg_null() {}
+}
diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_ui.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_ui.java
new file mode 100644
index 000000000..01fe7eb6a
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_ui.java
@@ -0,0 +1,26 @@
+/*
+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;
+public interface Gfo_usr_dlg_ui {
+ void Clear();
+ String_ring Prog_msgs();
+ void Write_prog(String text);
+ void Write_note(String text);
+ void Write_warn(String text);
+ void Write_stop(String text);
+}
diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_ui_.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_ui_.java
new file mode 100644
index 000000000..8105c41b4
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_ui_.java
@@ -0,0 +1,40 @@
+/*
+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;
+public class Gfo_usr_dlg_ui_ {
+ public static final Gfo_usr_dlg_ui Null = new Gfo_usr_dlg_ui_null();
+ public static final Gfo_usr_dlg_ui Console = new Gfo_usr_dlg_ui_console();
+ public static final Gfo_usr_dlg_ui Test = new Gfo_usr_dlg_ui_test();
+}
+class Gfo_usr_dlg_ui_null implements Gfo_usr_dlg_ui {
+ public void Clear() {}
+ public String_ring Prog_msgs() {return ring;} String_ring ring = new String_ring().Max_(0);
+ public void Write_prog(String text) {}
+ public void Write_note(String text) {}
+ public void Write_warn(String text) {}
+ public void Write_stop(String text) {}
+}
+class Gfo_usr_dlg_ui_console implements Gfo_usr_dlg_ui {
+ public void Clear() {}
+ public String_ring Prog_msgs() {return ring;} String_ring ring = new String_ring().Max_(0);
+ public void Write_prog(String text) {console.WriteTempText(text);}
+ public void Write_note(String text) {console.WriteLine(text);}
+ public void Write_warn(String text) {console.WriteLine(text);}
+ public void Write_stop(String text) {console.WriteLine(text);}
+ ConsoleAdp console = ConsoleAdp._;
+}
diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_ui_test.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_ui_test.java
new file mode 100644
index 000000000..1dc21391d
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_ui_test.java
@@ -0,0 +1,28 @@
+/*
+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;
+public class Gfo_usr_dlg_ui_test implements Gfo_usr_dlg_ui {
+ public String[] Xto_str_ary() {return msgs.XtoStrAry();}
+ public ListAdp Warns() {return warns;}
+ public String_ring Prog_msgs() {return ring;} String_ring ring = new String_ring().Max_(0);
+ public void Clear() {msgs.Clear(); warns.Clear();}
+ public void Write_prog(String text) {msgs.Add(text);} ListAdp msgs = ListAdp_.new_();
+ public void Write_note(String text) {msgs.Add(text);}
+ public void Write_warn(String text) {warns.Add(text);} ListAdp warns = ListAdp_.new_();
+ public void Write_stop(String text) {msgs.Add(text);}
+}
diff --git a/100_core/src_420_usrMsg/gplx/UsrDlg.java b/100_core/src_420_usrMsg/gplx/UsrDlg.java
new file mode 100644
index 000000000..70298a840
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/UsrDlg.java
@@ -0,0 +1,51 @@
+/*
+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;
+public class UsrDlg {
+ public int Verbosity() {return verbosity;} public UsrDlg Verbosity_(int v) {verbosity = v; return this;} int verbosity = UsrMsgWkr_.Type_Note;
+ public void Note(String text, Object... ary) {Exec(text, ary, noteWkrs);}
+ public void Warn(String text, Object... ary) {Exec(text, ary, warnWkrs);}
+ public void Stop(String text, Object... ary) {Exec(text, ary, stopWkrs);}
+ public void Note(UsrMsg msg) {Exec(UsrMsgWkr_.Type_Note, msg);}
+ public void Warn(UsrMsg msg) {Exec(UsrMsgWkr_.Type_Warn, msg);}
+ public void Stop(UsrMsg msg) {Exec(UsrMsgWkr_.Type_Stop, msg);}
+ public void Exec(int type, UsrMsg umsg) {
+ UsrMsgWkrList list = GetList(type);
+ list.Exec(umsg);
+ }
+ void Exec(String text, Object[] ary, UsrMsgWkrList list) {
+ String msg = String_.Format(text, ary);
+ list.Exec(UsrMsg.new_(msg));
+ }
+ public void Reg(int type, UsrMsgWkr wkr) {
+ UsrMsgWkrList list = GetList(type);
+ list.Add(wkr);
+ }
+ public void RegOff(int type, UsrMsgWkr wkr) {
+ UsrMsgWkrList list = GetList(type);
+ list.Del(wkr);
+ }
+ UsrMsgWkrList GetList(int type) {
+ if (type == UsrMsgWkr_.Type_Note) return noteWkrs;
+ else if (type == UsrMsgWkr_.Type_Warn) return warnWkrs;
+ else if (type == UsrMsgWkr_.Type_Stop) return stopWkrs;
+ else throw Err_.unhandled(type);
+ }
+ UsrMsgWkrList noteWkrs = new UsrMsgWkrList(UsrMsgWkr_.Type_Note), warnWkrs = new UsrMsgWkrList(UsrMsgWkr_.Type_Warn), stopWkrs = new UsrMsgWkrList(UsrMsgWkr_.Type_Stop);
+ public static UsrDlg new_() {return new UsrDlg();}
+}
diff --git a/100_core/src_420_usrMsg/gplx/UsrDlg_.java b/100_core/src_420_usrMsg/gplx/UsrDlg_.java
new file mode 100644
index 000000000..72fb054e4
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/UsrDlg_.java
@@ -0,0 +1,21 @@
+/*
+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;
+public class UsrDlg_ {
+ public static final UsrDlg _ = UsrDlg.new_();
+}
diff --git a/100_core/src_420_usrMsg/gplx/UsrMsg.java b/100_core/src_420_usrMsg/gplx/UsrMsg.java
new file mode 100644
index 000000000..d56d07362
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/UsrMsg.java
@@ -0,0 +1,67 @@
+/*
+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;
+public class UsrMsg {
+ public int VisibilityDuration() {return visibilityDuration;} public UsrMsg VisibilityDuration_(int v) {visibilityDuration = v; return this;} int visibilityDuration = 3000;
+ public String Hdr() {return hdr;} public UsrMsg Hdr_(String val) {hdr = val; return this;} private String hdr;
+ public OrderedHash Args() {return args;} OrderedHash args = OrderedHash_.new_();
+ public UsrMsg Add(String k, Object v) {
+ args.Add(k, KeyVal_.new_(k, v));
+ return this;
+ }
+ public UsrMsg AddReplace(String k, Object v) {
+ args.AddReplace(k, KeyVal_.new_(k, v));
+ return this;
+ }
+ public String XtoStrSingleLine() {return XtoStr(" ");}
+ public String XtoStr() {return XtoStr(Op_sys.Cur().Nl_str());}
+ String XtoStr(String spr) {
+ if (hdr == null) {
+ GfoMsg m = GfoMsg_.new_cast_(cmd);
+ for (int i = 0; i < args.Count(); i++) {
+ KeyVal kv = (KeyVal)args.FetchAt(i);
+ m.Add(kv.Key(), kv.Val());
+ }
+ return Object_.XtoStr_OrNullStr(invk.Invk(GfsCtx._, 0, cmd, m));
+ }
+ String_bldr sb = String_bldr_.new_();
+ sb.Add(hdr).Add(spr);
+ for (int i = 0; i < args.Count(); i++) {
+ KeyVal kv = (KeyVal)args.FetchAt(i);
+ sb.Add_spr_unless_first("", " ", i);
+ sb.Add_fmt("{0}={1}", kv.Key(), kv.Val(), spr);
+ }
+ return sb.XtoStr();
+ }
+ public static UsrMsg fmt_(String hdr, Object... ary) {
+ UsrMsg rv = new UsrMsg();
+ rv.hdr = String_.Format(hdr, ary);
+ return rv;
+ } UsrMsg() {}
+ public static UsrMsg new_(String hdr) {
+ UsrMsg rv = new UsrMsg();
+ rv.hdr = hdr;
+ return rv;
+ }
+ public static UsrMsg invk_(GfoInvkAble invk, String cmd) {
+ UsrMsg rv = new UsrMsg();
+ rv.invk = invk;
+ rv.cmd = cmd;
+ return rv;
+ } GfoInvkAble invk; String cmd;
+}
diff --git a/100_core/src_420_usrMsg/gplx/UsrMsgWkr.java b/100_core/src_420_usrMsg/gplx/UsrMsgWkr.java
new file mode 100644
index 000000000..cedbef815
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/UsrMsgWkr.java
@@ -0,0 +1,50 @@
+/*
+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;
+public interface UsrMsgWkr {
+ void ExecUsrMsg(int type, UsrMsg umsg);
+}
+class UsrMsgWkrList {
+ public void Add(UsrMsgWkr v) {
+ if (wkr == null && list == null)
+ wkr = v;
+ else {
+ if (list == null) {
+ list = ListAdp_.new_();
+ list.Add(wkr);
+ wkr = null;
+ }
+ list.Add(v);
+ }
+ }
+ public void Del(UsrMsgWkr v) {
+// list.Del(v);
+ }
+ public void Exec(UsrMsg umsg) {
+ if (wkr != null)
+ wkr.ExecUsrMsg(type, umsg);
+ else if (list != null) {
+ for (Object lObj : list) {
+ UsrMsgWkr l = (UsrMsgWkr)lObj;
+ l.ExecUsrMsg(type, umsg);
+ }
+ }
+ }
+ ListAdp list; UsrMsgWkr wkr; int type;
+ public UsrMsgWkrList(int type) {this.type = type;}
+}
diff --git a/100_core/src_420_usrMsg/gplx/UsrMsgWkr_.java b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_.java
new file mode 100644
index 000000000..2bedb2294
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_.java
@@ -0,0 +1,27 @@
+/*
+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;
+public class UsrMsgWkr_ {
+ public static final int
+ Type_None = 0
+ , Type_Stop = 1
+ , Type_Warn = 2
+ , Type_Note = 4
+ , Type_Log = 8
+ ;
+}
diff --git a/100_core/src_420_usrMsg/gplx/UsrMsgWkr_console.java b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_console.java
new file mode 100644
index 000000000..7ba18b027
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_console.java
@@ -0,0 +1,34 @@
+/*
+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;
+public class UsrMsgWkr_console implements UsrMsgWkr {
+ public void ExecUsrMsg(int type, UsrMsg umsg) {
+ String text = umsg.XtoStr();
+ if (type == UsrMsgWkr_.Type_Warn)
+ text = "!!!!" + text;
+ else if (type == UsrMsgWkr_.Type_Stop)
+ text = "****" + text;
+ ConsoleAdp._.WriteText(text);
+ }
+ public static void RegAll(UsrDlg dlg) {
+ UsrMsgWkr wkr = new UsrMsgWkr_console();
+ dlg.Reg(UsrMsgWkr_.Type_Note, wkr);
+ dlg.Reg(UsrMsgWkr_.Type_Stop, wkr);
+ dlg.Reg(UsrMsgWkr_.Type_Warn, wkr);
+ }
+}
diff --git a/100_core/src_420_usrMsg/gplx/UsrMsgWkr_test.java b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_test.java
new file mode 100644
index 000000000..e7d215982
--- /dev/null
+++ b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_test.java
@@ -0,0 +1,38 @@
+/*
+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;
+public class UsrMsgWkr_test implements UsrMsgWkr {
+ public void ExecUsrMsg(int type, UsrMsg m) {
+ msgs.Add(m);
+ }
+ public boolean HasWarn(UsrMsg um) {
+ for (int i = 0; i < msgs.Count(); i++) {
+ UsrMsg found = (UsrMsg)msgs.FetchAt(i);
+ if (String_.Eq(um.XtoStr(), found.XtoStr())) return true;
+ }
+ return false;
+ }
+ public static UsrMsgWkr_test RegAll(UsrDlg dlg) {
+ UsrMsgWkr_test wkr = new UsrMsgWkr_test();
+ dlg.Reg(UsrMsgWkr_.Type_Note, wkr);
+ dlg.Reg(UsrMsgWkr_.Type_Stop, wkr);
+ dlg.Reg(UsrMsgWkr_.Type_Warn, wkr);
+ return wkr;
+ }
+ ListAdp msgs = ListAdp_.new_();
+}
diff --git a/100_core/src_800_tst/gplx/PerfLogMgr_fxt.java b/100_core/src_800_tst/gplx/PerfLogMgr_fxt.java
new file mode 100644
index 000000000..552d368ca
--- /dev/null
+++ b/100_core/src_800_tst/gplx/PerfLogMgr_fxt.java
@@ -0,0 +1,65 @@
+/*
+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;
+public class PerfLogMgr_fxt {
+ public void Init(Io_url url, String text) {
+ this.url = url;
+ entries.ResizeBounds(1000);
+ entries.Add(new PerfLogItm(0, text + "|" + DateAdp_.Now().XtoStr_gplx()));
+ tmr.Bgn();
+ }
+ public void Write(String text) {
+ long milliseconds = tmr.ElapsedMilliseconds();
+ entries.Add(new PerfLogItm(milliseconds, text));
+ tmr.Bgn();
+ }
+ public void WriteFormat(String fmt, Object... ary) {
+ long milliseconds = tmr.ElapsedMilliseconds();
+ String text = String_.Format(fmt, ary);
+ entries.Add(new PerfLogItm(milliseconds, text));
+ tmr.Bgn();
+ }
+ public void Flush() {
+ String_bldr sb = String_bldr_.new_();
+ for (Object itmObj : entries) {
+ PerfLogItm itm = (PerfLogItm)itmObj;
+ sb.Add(itm.XtoStr()).Add_char_crlf();
+ }
+ Io_mgr._.AppendFilStr(url, sb.XtoStr());
+ entries.Clear();
+ }
+ ListAdp entries = ListAdp_.new_(); PerfLogTmr tmr = PerfLogTmr.new_(); Io_url url = Io_url_.Null;
+ public static final PerfLogMgr_fxt _ = new PerfLogMgr_fxt(); PerfLogMgr_fxt() {}
+ class PerfLogItm {
+ public String XtoStr() {
+ String secondsStr = TimeSpanAdp_.XtoStr(milliseconds, TimeSpanAdp_.Fmt_Default);
+ secondsStr = String_.PadBgn(secondsStr, 7, "0"); // 7=000.000; left-aligns all times
+ return String_.Concat(secondsStr, "|", text);
+ }
+ long milliseconds; String text;
+ @gplx.Internal protected PerfLogItm(long milliseconds, String text) {
+ this.milliseconds = milliseconds; this.text = text;
+ }
+ }
+
+}
+class PerfLogTmr {
+ public void Bgn() {bgn = Env_.TickCount();} long bgn;
+ public long ElapsedMilliseconds() {return Env_.TickCount() - bgn; }
+ public static PerfLogTmr new_() {return new PerfLogTmr();} PerfLogTmr() {}
+}
diff --git a/100_core/src_800_tst/gplx/Tfds.java b/100_core/src_800_tst/gplx/Tfds.java
new file mode 100644
index 000000000..0eb8532bd
--- /dev/null
+++ b/100_core/src_800_tst/gplx/Tfds.java
@@ -0,0 +1,244 @@
+/*
+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;
+public class Tfds { // URL:doc/gplx.tfds/Tfds.txt
+ public static boolean SkipDb = false;
+ public static void Eq(Object expd, Object actl) {Eq_wkr(expd, actl, true, EmptyStr);}
+ public static void Eq_able(EqAble expd, EqAble actl) {Eq_able_wkr(expd, actl, true, EmptyStr);}
+ public static void Eq_able(EqAble expd, EqAble actl, String fmt, Object... args) {Eq_able_wkr(expd, actl, true, String_.Format(fmt, args));}
+ public static void Eq_byte(byte expd, byte actl) {Eq_wkr(expd, actl, true, EmptyStr);}
+ public static void Eq_long(long expd, long actl) {Eq_wkr(expd, actl, true, EmptyStr);}
+ public static void Eq_float(float expd, float actl) {Eq_wkr(expd, actl, true, EmptyStr);}
+ public static void Eq_decimal(DecimalAdp expd, DecimalAdp actl) {Eq_wkr(expd.XtoDouble(), actl.XtoDouble(), true, EmptyStr);}
+ public static void Eq_date(DateAdp expd, DateAdp actl) {Eq_wkr(expd.XtoStr_gplx(), actl.XtoStr_gplx(), true, EmptyStr);}
+ public static void Eq_date(DateAdp expd, DateAdp actl, String fmt, Object... args){Eq_wkr(expd.XtoStr_gplx(), actl.XtoStr_gplx(), true, String_.Format(fmt, args));}
+ public static void Eq_url(Io_url expd, Io_url actl) {Eq_wkr(expd.Raw(), actl.Raw(), true, EmptyStr);}
+ public static void Eq_bry(String expd, byte[] actl) {Eq_wkr(expd, String_.new_utf8_(actl), true, EmptyStr);}
+ public static void Eq_bry(byte[] expd, byte[] actl) {Eq_wkr(String_.new_utf8_(expd), String_.new_utf8_(actl), true, EmptyStr);}
+ public static void Eq_str(XtoStrAble expd, XtoStrAble actl, String msg) {Eq_wkr(expd.XtoStr(), actl.XtoStr(), true, msg);}
+ public static void Eq_str(XtoStrAble expd, XtoStrAble actl) {Eq_wkr(expd.XtoStr(), actl.XtoStr(), true, String_.Empty);}
+ public static void Eq_str_lines(String lhs, String rhs) {Eq_str_lines(lhs, rhs, EmptyStr);}
+ public static void Eq_str_lines(String lhs, String rhs, String note) {
+ if (lhs == null && rhs == null) return; // true
+ else if (lhs == null) throw Err_.new_("lhs is null" + note);
+ else if (rhs == null) throw Err_.new_("rhs is null" + note);
+ else Eq_ary_wkr(String_.Split(lhs, Char_.NewLine), String_.Split(rhs, Char_.NewLine), false, note);
+ }
+ public static void Eq(Object expd, Object actl, String fmt, Object... args) {Eq_wkr(expd, actl, true, String_.Format(fmt, args));}
+ public static void Eq_rev(Object actl, Object expd) {Eq_wkr(expd, actl, true, EmptyStr);}
+ public static void Eq_rev(Object actl, Object expd, String fmt, Object... args) {Eq_wkr(expd, actl, true, String_.Format(fmt, args));}
+ public static void Eq_true(Object actl) {Eq_wkr(true, actl, true, EmptyStr);}
+ public static void Eq_true(Object actl, String fmt, Object... args) {Eq_wkr(true, actl, true, String_.Format(fmt, args));}
+ public static void Eq_false(Object actl) {Eq_wkr(false, actl, true, EmptyStr);}
+ public static void Eq_false(Object actl, String fmt, Object... args) {Eq_wkr(false, actl, true, String_.Format(fmt, args));}
+ public static void Eq_null(Object actl) {Eq_wkr(null, actl, true, EmptyStr);}
+ public static void Eq_null(Object actl, String fmt, Object... args) {Eq_wkr(null, actl, true, String_.Format(fmt, args));}
+ public static void Eq_nullNot(Object actl) {Eq_wkr(null, actl, false, EmptyStr);}
+ public static void Eq_nullNot(Object actl, String fmt, Object... args) {Eq_wkr(null, actl, false, String_.Format(fmt, args));}
+ public static void Fail_expdError() {Eq_wkr(true, false, true, "fail expd error");}
+ public static void Fail(String fmt, Object... args) {Eq_wkr(true, false, true, String_.Format(fmt, args));}
+ public static void Eq_ary(Object lhs, Object rhs) {Eq_ary_wkr(lhs, rhs, true, EmptyStr);}
+ public static void Eq_ary(Object lhs, Object rhs, String fmt, Object... args){Eq_ary_wkr(lhs, rhs, true, String_.Format(fmt, args));}
+ public static void Eq_ary_str(Object lhs, Object rhs, String note) {Eq_ary_wkr(lhs, rhs, false, note);}
+ public static void Eq_ary_str(Object lhs, Object rhs) {Eq_ary_wkr(lhs, rhs, false, EmptyStr);}
+ public static void Eq_list(ListAdp lhs, ListAdp rhs) {Eq_list_wkr(lhs, rhs, TfdsEqListItmStr_cls_default._, EmptyStr);}
+ public static void Eq_list(ListAdp lhs, ListAdp rhs, TfdsEqListItmStr xtoStr) {Eq_list_wkr(lhs, rhs, xtoStr, EmptyStr);}
+ static void Eq_able_wkr(EqAble lhs, EqAble rhs, boolean expd, String customMsg) {
+ boolean actl = false;
+ if (lhs == null && rhs != null) actl = false;
+ else if (lhs != null && rhs == null) actl = false;
+ else actl = lhs.Eq(rhs);
+ if (expd == actl) return;
+ String msg = msgBldr.Eq_xtoStr(lhs, rhs, customMsg);
+ throw Err_.new_(msg);
+ }
+ static void Eq_wkr(Object lhs, Object rhs, boolean expd, String customMsg) {
+ boolean actl = Object_.Eq(lhs, rhs);
+ if (expd == actl) return;
+ String msg = msgBldr.Eq_xtoStr(lhs, rhs, customMsg);
+ throw Err_.new_(msg);
+ }
+ static void Eq_ary_wkr(Object lhsAry, Object rhsAry, boolean compareUsingEquals, String customMsg) {
+ ListAdp list = ListAdp_.new_(); boolean pass = true;
+ int lhsLen = Array_.Len(lhsAry), rhsLen = Array_.Len(rhsAry);
+ for (int i = 0; i < lhsLen; i++) {
+ Object lhs = Array_.FetchAt(lhsAry, i);
+ Object rhs = i >= rhsLen ? "<>" : Array_.FetchAt(rhsAry, i);
+ String lhsString = msgBldr.Obj_xtoStr(lhs); String rhsString = msgBldr.Obj_xtoStr(rhs); // even if compareUsingEquals, method does ToStr on each itm for failMsg
+ boolean isEq = compareUsingEquals
+ ? Object_.Eq(lhs, rhs)
+ : Object_.Eq(lhsString, rhsString);
+ Eq_ary_wkr_addItm(list, i, isEq, lhsString, rhsString);
+ if (!isEq) pass = false;
+ }
+ for (int i = lhsLen; i < rhsLen; i++) {
+ String lhsString = "<>";
+ String rhsString = msgBldr.Obj_xtoStr(Array_.FetchAt(rhsAry, i));
+ Eq_ary_wkr_addItm(list, i, false, lhsString, rhsString);
+ pass = false;
+ }
+ if (pass) return;
+ String msg = msgBldr.Eq_ary_xtoStr(list, lhsLen, rhsLen, customMsg);
+ throw Err_.new_(msg);
+ }
+ static void Eq_list_wkr(ListAdp lhsList, ListAdp rhsList, TfdsEqListItmStr xtoStr, String customMsg) {
+ ListAdp list = ListAdp_.new_(); boolean pass = true;
+ int lhsLen = lhsList.Count(), rhsLen = rhsList.Count();
+ for (int i = 0; i < lhsLen; i++) {
+ Object lhs = lhsList.FetchAt(i);
+ Object rhs = i >= rhsLen ? null : rhsList.FetchAt(i);
+ String lhsStr = xtoStr.XtoStr(lhs, lhs);
+ String rhsStr = rhs == null ? "<>" : xtoStr.XtoStr(rhs, lhs);
+ boolean isEq = Object_.Eq(lhsStr, rhsStr); if (!isEq) pass = false;
+ Eq_ary_wkr_addItm(list, i, isEq, lhsStr, rhsStr);
+ }
+ for (int i = lhsLen; i < rhsLen; i++) {
+ String lhsStr = "<>";
+ Object rhs = rhsList.FetchAt(i);
+ String rhsStr = xtoStr.XtoStr(rhs, null);
+ Eq_ary_wkr_addItm(list, i, false, lhsStr, rhsStr);
+ pass = false;
+ }
+ if (pass) return;
+ String msg = msgBldr.Eq_ary_xtoStr(list, lhsLen, rhsLen, customMsg);
+ throw Err_.new_(msg);
+ }
+ static void Eq_ary_wkr_addItm(ListAdp list, int i, boolean isEq, String lhsString, String rhsString) {
+ TfdsEqAryItm itm = new TfdsEqAryItm().Idx_(i).Eq_(isEq).Lhs_(lhsString).Rhs_(rhsString);
+ list.Add(itm);
+ }
+ public static void Err_classMatch(Exception exc, Class> type) {
+ boolean match = ClassAdp_.Eq_typeSafe(exc, type);
+ if (!match) throw Err_.new_key_("Tfds", "error types do not match").Add("expdType", ClassAdp_.FullNameOf_type(type)).Add("actlType", ClassAdp_.NameOf_obj(exc)).Add("actlMsg", Err_.Message_lang(exc));
+ }
+ public static void Eq_err(Err expd, Exception actlExc) {
+ Tfds.Eq(XtoStr_Err(expd), XtoStr_Err(actlExc));
+ }
+ public static void Err_has(Exception e, String hdr) {
+ Tfds.Eq_true(String_.Has(Err_.Message_gplx_brief(e), hdr), "could not find '{0}' in '{1}'", hdr, Err_.Message_gplx_brief(e));
+ }
+ static String XtoStr_Err(Exception e) {
+ Err err = Err_.as_(e); if (err == null) return Err_.Message_lang(e);
+ String_bldr sb = String_bldr_.new_();
+ sb.Add(err.Hdr()).Add(":");
+ for (Object kvo : err.Args()) {
+ KeyVal kv = (KeyVal)kvo;
+ if (sb.Count() != 0) sb.Add(" ");
+ sb.Add_fmt("{0}={1}", kv.Key(), kv.Val());
+ }
+ return sb.XtoStr();
+ }
+ static final String EmptyStr = TfdsMsgBldr.EmptyStr;
+ static TfdsMsgBldr msgBldr = TfdsMsgBldr.new_();
+ public static final Io_url RscDir = Io_url_.Usr().GenSubDir_nest("xowa", "dev", "tst");
+ public static DateAdp Now_time0_add_min(int minutes) {return time0.Add_minute(minutes);}
+ @gplx.Internal protected static boolean Now_enabled() {return now_enabled;} static boolean now_enabled;
+ public static void Now_enabled_n_() {now_enabled = false;}
+ public static void Now_set(DateAdp date) {now_enabled = true; nowTime = date;}
+ public static void Now_enabled_y_() {now_enabled = true; nowTime = time0;}
+ @gplx.Internal protected static DateAdp Now() {
+ DateAdp rv = nowTime;
+ nowTime = rv.Add_minute(1);
+ return rv;
+ }
+ private static final DateAdp time0 = DateAdp_.parse_gplx("2001-01-01 00:00:00.000");
+ private static DateAdp nowTime; // NOTE: cannot set to time0 due to static initialization;
+ public static void WriteText(String text) {ConsoleAdp._.WriteText(text);}
+ public static void Write_bry(byte[] ary) {Write(String_.new_utf8_(ary));}
+ public static void Write() {Write("tmp");}
+ public static void Write(Object... ary) {
+ String_bldr sb = String_bldr_.new_();
+ int aryLen = Array_.Len(ary);
+ for (int i = 0; i < aryLen; i++)
+ sb.Add_many("'", Object_.XtoStr_OrNullStr(ary[i]), "'", " ");
+ WriteText(sb.XtoStr() + String_.CrLf);
+ }
+}
+class TfdsEqListItmStr_cls_default implements TfdsEqListItmStr {
+ public String XtoStr(Object cur, Object actl) {
+ return Object_.XtoStr_OrNullStr(cur);
+ }
+ public static final TfdsEqListItmStr_cls_default _ = new TfdsEqListItmStr_cls_default(); TfdsEqListItmStr_cls_default() {}
+}
+class TfdsEqAryItm {
+ public int Idx() {return idx;} public TfdsEqAryItm Idx_(int v) {idx = v; return this;} int idx;
+ public String Lhs() {return lhs;} public TfdsEqAryItm Lhs_(String v) {lhs = v; return this;} private String lhs;
+ public String Rhs() {return rhs;} public TfdsEqAryItm Rhs_(String v) {rhs = v; return this;} private String rhs;
+ public boolean Eq() {return eq;} public TfdsEqAryItm Eq_(boolean v) {eq = v; return this;} private boolean eq;
+}
+class TfdsMsgBldr {
+ public String Eq_xtoStr(Object expd, Object actl, String customMsg) {
+ String expdString = Obj_xtoStr(expd); String actlString = Obj_xtoStr(actl);
+ String detail = String_.Concat
+ ( CustomMsg_xtoStr(customMsg)
+ , "\t\t", "expd: ", expdString, String_.CrLf
+ , "\t\t", "actl: ", actlString, String_.CrLf
+ );
+ return WrapMsg(detail);
+ }
+ public String Eq_ary_xtoStr(ListAdp list, int lhsAryLen, int rhsAryLen, String customMsg) {
+ String_bldr sb = String_bldr_.new_();
+ sb.Add(CustomMsg_xtoStr(customMsg));
+ if (lhsAryLen != rhsAryLen)
+ sb.Add_fmt_line("{0}element counts differ: {1} {2}", "\t\t", lhsAryLen, rhsAryLen);
+ int lhsLenMax = 0, rhsLenMax = 0;
+ for (int i = 0; i < list.Count(); i++) {
+ TfdsEqAryItm itm = (TfdsEqAryItm)list.FetchAt(i);
+ int lhsLen = String_.Len(itm.Lhs()), rhsLen = String_.Len(itm.Rhs());
+ if (lhsLen > lhsLenMax) lhsLenMax = lhsLen;
+ if (rhsLen > rhsLenMax) rhsLenMax = rhsLen;
+ }
+ for (int i = 0; i < list.Count(); i++) {
+ TfdsEqAryItm itm = (TfdsEqAryItm)list.FetchAt(i);
+ sb.Add_fmt_line("{0}: {1} {2} {3}"
+ , Int_.XtoStr_PadBgn(itm.Idx(), 4)
+ , String_.PadBgn(itm.Lhs(), lhsLenMax, " ")
+ , itm.Eq() ? "==" : "!="
+ , String_.PadBgn(itm.Rhs(), rhsLenMax, " ")
+ );
+ }
+// String compSym = isEq ? " " : "!=";
+// String result = String_.Format("{0}: {1}{2} {3} {4}", Int_.XtoStr_PadBgn(i, 4), lhsString, String_.CrLf + "\t\t", compSym, rhsString);
+// foreach (Object obj in list) {
+// String itmComparison = (String)obj;
+// sb.Add_fmt_line("{0}{1}", "\t\t", itmComparison);
+// }
+ return WrapMsg(sb.XtoStr());
+ }
+ String CustomMsg_xtoStr(String customMsg) {
+ return (customMsg == EmptyStr)
+ ? ""
+ : String_.Concat(customMsg, String_.CrLf);
+ }
+ public String Obj_xtoStr(Object obj) {
+ String s = String_.as_(obj);
+ if (s != null) return String_.Concat("'", s, "'"); // if Object is String, put quotes around it for legibility
+ XtoStrAble xtoStrAble = XtoStrAble_.as_(obj);
+ if (xtoStrAble != null) return xtoStrAble.XtoStr();
+ return Object_.XtoStr_OrNullStr(obj);
+ }
+ String WrapMsg(String text) {
+ return String_.Concat(String_.CrLf
+ , "************************************************************************************************", String_.CrLf
+ , text
+ , "________________________________________________________________________________________________"
+ );
+ }
+ public static TfdsMsgBldr new_() {return new TfdsMsgBldr();} TfdsMsgBldr() {}
+ public static final String EmptyStr = "";
+}
diff --git a/100_core/src_800_tst/gplx/TfdsEqListItmStr.java b/100_core/src_800_tst/gplx/TfdsEqListItmStr.java
new file mode 100644
index 000000000..92d98f50e
--- /dev/null
+++ b/100_core/src_800_tst/gplx/TfdsEqListItmStr.java
@@ -0,0 +1,21 @@
+/*
+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;
+public interface TfdsEqListItmStr {
+ String XtoStr(Object cur, Object actl);
+}
diff --git a/100_core/src_900_xml/gplx/Base85_utl.java b/100_core/src_900_xml/gplx/Base85_utl.java
new file mode 100644
index 000000000..df08a034a
--- /dev/null
+++ b/100_core/src_900_xml/gplx/Base85_utl.java
@@ -0,0 +1,66 @@
+/*
+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;
+public class Base85_utl {
+ public static String XtoStr(int val, int minLen) {return String_.new_utf8_(XtoStrByAry(val, null, 0, minLen));}
+ public static byte[] XtoStrByAry(int val, int minLen) {return XtoStrByAry(val, null, 0, minLen);}
+ public static byte[] XtoStrByAry(int val, byte[] ary, int aryPos, int minLen) {
+ int strLen = DigitCount(val);
+ int aryLen = strLen, padLen = 0;
+ boolean pad = aryLen < minLen;
+ if (pad) {
+ padLen = minLen - aryLen;
+ aryLen = minLen;
+ }
+ if (ary == null) ary = new byte[aryLen];
+ if (pad) {
+ for (int i = 0; i < padLen; i++) // fill ary with padLen
+ ary[i + aryPos] = AsciiOffset;
+ }
+ for (int i = aryLen - padLen; i > 0; i--) {
+ int div = Pow85[i - 1];
+ byte tmp = (byte)(val / div);
+ ary[aryPos + aryLen - i] = (byte)(tmp + AsciiOffset);
+ val -= tmp * div;
+ }
+ return ary;
+ }
+ public static byte XtoByteChar(int v) {return (byte)(v + AsciiOffset);}
+ public static int XtoInt(byte v) {return v - AsciiOffset;}
+ public static int XtoIntByStr(String s) {
+ byte[] ary = Bry_.new_utf8_(s);
+ return XtoIntByAry(ary, 0, ary.length - 1);
+ }
+ public static int XtoIntByAry(byte[] ary, int bgn, int end) {
+ int rv = 0, factor = 1;
+ for (int i = end; i >= bgn; i--) {
+ rv += (ary[i] - AsciiOffset) * factor;
+ factor *= Radix;
+ }
+ return rv;
+ }
+ public static int DigitCount(int v) {
+ if (v == 0) return 1;
+ for (int i = Pow85Last; i > -1; i--)
+ if (v >= Pow85[i]) return i + 1;
+ throw Err_.new_("neg number not allowed").Add("v", v);
+ }
+ static int[] Pow85 = new int[]{1, 85, 7225, 614125, 52200625}; // NOTE: ary constructed to match index to exponent; Pow85[1] = 85^1
+ static final int Pow85Last = 4, Radix = 85; static final byte AsciiOffset = 33;
+ public static final int Len_int = 5;
+}
diff --git a/100_core/src_900_xml/gplx/Base85_utl_tst.java b/100_core/src_900_xml/gplx/Base85_utl_tst.java
new file mode 100644
index 000000000..1b4668c0d
--- /dev/null
+++ b/100_core/src_900_xml/gplx/Base85_utl_tst.java
@@ -0,0 +1,56 @@
+/*
+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;
+import org.junit.*;
+public class Base85_utl_tst {
+ @Test public void Log() {
+ tst_Log( 0, 1);
+ tst_Log( 84, 1);
+ tst_Log( 85, 2);
+ tst_Log( 7224, 2);
+ tst_Log( 7225, 3);
+ tst_Log( 614124, 3);
+ tst_Log( 614125, 4);
+ tst_Log( 52200624, 4);
+ tst_Log( 52200625, 5);
+ tst_Log(Int_.MaxValue, 5);
+ } void tst_Log(int val, int expd) {Tfds.Eq(expd, Base85_utl.DigitCount(val));}
+ @Test public void XtoStr() {
+ tst_XtoStr( 0, "!");
+ tst_XtoStr( 84, "u");
+ tst_XtoStr( 85, "\"!");
+ tst_XtoStr( 7224, "uu");
+ tst_XtoStr( 7225, "\"!!");
+ tst_XtoStr( 614124, "uuu");
+ tst_XtoStr( 614125, "\"!!!");
+ tst_XtoStr( 52200624, "uuuu");
+ tst_XtoStr( 52200625, "\"!!!!");
+ }
+ void tst_XtoStr(int val, String expd) {
+ String actl = Base85_utl.XtoStr(val, 0);
+ Tfds.Eq(expd, actl);
+ Tfds.Eq(val, Base85_utl.XtoIntByStr(expd));
+ }
+ @Test public void XtoStrAry() {
+ byte[] ary = new byte[9];
+ run_XtoStr(ary, 0, 2); // !!#
+ run_XtoStr(ary, 3, 173); // !#$
+ run_XtoStr(ary, 6, 14709); // #$%
+ Tfds.Eq("!!#!#$#$%", String_.new_utf8_(ary));
+ } void run_XtoStr(byte[] ary, int aryPos, int val) {Base85_utl.XtoStrByAry(val, ary, aryPos, 3);}
+}
diff --git a/100_core/src_900_xml/gplx/HierStrBldr.java b/100_core/src_900_xml/gplx/HierStrBldr.java
new file mode 100644
index 000000000..cb83b09aa
--- /dev/null
+++ b/100_core/src_900_xml/gplx/HierStrBldr.java
@@ -0,0 +1,55 @@
+/*
+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;
+public class HierStrBldr {
+ public String Root() {return root;} public HierStrBldr Root_(String v) {root = v; return this;} private String root;
+ public Io_url RootAsIoUrl() {return Io_url_.new_dir_(root);}
+ public String DirFmt() {return dirFmt;} private String dirFmt;
+ public String DirSpr() {return dirSpr;} private String dirSpr = Op_sys.Cur().Fsys_dir_spr_str();
+ public String FilFmt() {return filFmt;} private String filFmt;
+ public String NumFmt() {return numFmt;} private String numFmt;
+ public int[] FilCountMaxs() {return filCountMaxs;} int[] filCountMaxs;
+ public Io_url GenStrIdxOnlyAsoUrl(int idx) {return Io_url_.new_fil_(GenStrIdxOnly(idx));}
+ public String GenStrIdxOnly(int idx) {return GenStr(String_.Ary_empty, idx);}
+ public Io_url GenStrAsIoUrl(String[] subDirs, int idx) {
+ return Io_url_.new_fil_(GenStr(subDirs, idx));
+ }
+ String GenStr(String[] subDirs, int idx) {
+ String_bldr sb = String_bldr_.new_();
+ sb.Add(root);
+ for (String subDir : subDirs)
+ sb.Add(subDir).Add(dirSpr);
+ int multiple = 1;
+ int[] multipleAry = new int[filCountMaxs.length];
+ for (int i = filCountMaxs.length - 1; i >= 0; i--) {
+ multiple *= filCountMaxs[i];
+ multipleAry[i] = (idx / multiple) * multiple; // NOTE: rounds down to multiple; EX: 11 -> 10
+ }
+ for (int i = 0; i < multipleAry.length; i++)
+ sb.Add_fmt(dirFmt, Int_.XtoStr_fmt(multipleAry[i], numFmt));
+ sb.Add_fmt(filFmt, Int_.XtoStr_fmt(idx, numFmt));
+ return sb.XtoStr();
+ }
+ public HierStrBldr Ctor_io(Io_url root, String dirFmt, String filFmt, String numFmt, int... filCountMaxs) {
+ this.Ctor(root.Raw(), dirFmt + dirSpr, filFmt, numFmt, filCountMaxs);
+ return this;
+ }
+ public void Ctor(String root, String dirFmt, String filFmt, String numFmt, int... filCountMaxs) {
+ this.root = root; this.dirFmt = dirFmt; this.filFmt = filFmt; this.numFmt = numFmt; this.filCountMaxs = filCountMaxs;
+ }
+}
diff --git a/100_core/src_900_xml/gplx/HierStrBldr_tst.java b/100_core/src_900_xml/gplx/HierStrBldr_tst.java
new file mode 100644
index 000000000..e330dfbdc
--- /dev/null
+++ b/100_core/src_900_xml/gplx/HierStrBldr_tst.java
@@ -0,0 +1,47 @@
+/*
+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;
+import org.junit.*;
+import gplx.ios.*; import gplx.texts.*;
+public class HierStrBldr_tst {
+ @Before public void setup() {bldr = new HierStrBldr();} HierStrBldr bldr;
+ @Test public void Hier0() {
+ bldr.Ctor("/root/", "dir_{0}/", "idx_{0}.csv", "000");
+ tst_MakeName( 0, "/root/idx_000.csv");
+ tst_MakeName( 1, "/root/idx_001.csv");
+ tst_MakeName(10, "/root/idx_010.csv");
+ }
+ @Test public void Hier1() {
+ bldr.Ctor("/root/", "dir_{0}/", "idx_{0}.csv", "000", 10);
+ tst_MakeName( 0, "/root/dir_000/idx_000.csv");
+ tst_MakeName( 1, "/root/dir_000/idx_001.csv");
+ tst_MakeName(10, "/root/dir_010/idx_010.csv");
+ }
+ @Test public void Hier2() {
+ bldr.Ctor("/root/", "dir_{0}/", "idx_{0}.csv", "000", 5, 10);
+ tst_MakeName( 0, "/root/dir_000/dir_000/idx_000.csv");
+ tst_MakeName( 1, "/root/dir_000/dir_000/idx_001.csv");
+ tst_MakeName( 10, "/root/dir_000/dir_010/idx_010.csv");
+ tst_MakeName( 49, "/root/dir_000/dir_040/idx_049.csv");
+ tst_MakeName( 50, "/root/dir_050/dir_050/idx_050.csv");
+ tst_MakeName( 99, "/root/dir_050/dir_090/idx_099.csv");
+ tst_MakeName(100, "/root/dir_100/dir_100/idx_100.csv");
+ tst_MakeName(110, "/root/dir_100/dir_110/idx_110.csv");
+ }
+ void tst_MakeName(int val, String expd) {Tfds.Eq(expd, bldr.GenStrIdxOnly(val));}
+}
diff --git a/100_core/src_900_xml/gplx/xmls/XmlAtr.java b/100_core/src_900_xml/gplx/xmls/XmlAtr.java
new file mode 100644
index 000000000..d99b1b427
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlAtr.java
@@ -0,0 +1,24 @@
+/*
+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.xmls; import gplx.*;
+import org.w3c.dom.Node;
+public class XmlAtr {
+ public String Name() {return xatr.getNodeName();}
+ public String Value() {return xatr.getNodeValue();}
+ @gplx.Internal protected XmlAtr(Node xatr) {this.xatr = xatr;} Node xatr;
+}
diff --git a/100_core/src_900_xml/gplx/xmls/XmlAtrList.java b/100_core/src_900_xml/gplx/xmls/XmlAtrList.java
new file mode 100644
index 000000000..c4267d824
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlAtrList.java
@@ -0,0 +1,37 @@
+/*
+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.xmls; import gplx.*;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+public class XmlAtrList {
+ public int Count() {return list == null ? 0 : list.getLength();}
+ public String FetchValOr(String key, String or) {
+ Node xatr = list.getNamedItem(key);
+ return (xatr == null) ? or : xatr.getNodeValue();
+ }
+ public XmlAtr Fetch(String key) {
+ Node xatr = list.getNamedItem(key); if (xatr == null) throw Err_arg.notFound_key_("key", key);
+ return new XmlAtr(xatr);
+ }
+ public XmlAtr Fetch_or_null(String key) {
+ Node xatr = list.getNamedItem(key); if (xatr == null) return null;
+ return new XmlAtr(xatr);
+ }
+ public XmlAtr FetchAt(int i) {return list == null ? null : new XmlAtr(list.item(i));}
+ @gplx.Internal protected XmlAtrList(NamedNodeMap list) {this.list = list;} NamedNodeMap list;
+}
diff --git a/100_core/src_900_xml/gplx/xmls/XmlDoc.java b/100_core/src_900_xml/gplx/xmls/XmlDoc.java
new file mode 100644
index 000000000..7c2df540a
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlDoc.java
@@ -0,0 +1,24 @@
+/*
+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.xmls; import gplx.*;
+import org.w3c.dom.Document;
+public class XmlDoc {
+ public XmlNde Root() {return new XmlNde(xdoc.getDocumentElement());}
+ @gplx.Internal protected XmlDoc(Document xdoc) {this.xdoc = xdoc;} Document xdoc;
+}
+//#}
\ No newline at end of file
diff --git a/100_core/src_900_xml/gplx/xmls/XmlDoc_.java b/100_core/src_900_xml/gplx/xmls/XmlDoc_.java
new file mode 100644
index 000000000..17866ed17
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlDoc_.java
@@ -0,0 +1,53 @@
+/*
+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.xmls; import gplx.*;
+import gplx.Io_url;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+public class XmlDoc_ {
+ public static XmlDoc parse_(String raw) {return new XmlDoc(doc_(raw));}
+ static Document doc_(String raw) {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder bldr = null;
+ try {bldr = factory.newDocumentBuilder();}
+ catch (ParserConfigurationException e) {throw Err_.err_key_(e, XmlDoc_.Err_XmlException, "failed to create newDocumentBuilder");}
+ StringReader reader = new StringReader(raw);
+ InputSource source = new InputSource(reader);
+ Document doc = null;
+ try {doc = bldr.parse(source);}
+ catch (SAXException e) {throw Err_.err_key_(e, XmlDoc_.Err_XmlException, "failed to parse xml").Add("raw", raw);}
+ catch (IOException e) {throw Err_.err_key_(e, XmlDoc_.Err_XmlException, "failed to parse xml").Add("raw", raw);}
+ return doc;
+ }
+ public static final String Err_XmlException = "gplx.xmls.XmlException";
+}
+//#}
\ No newline at end of file
diff --git a/100_core/src_900_xml/gplx/xmls/XmlDoc_tst.java b/100_core/src_900_xml/gplx/xmls/XmlDoc_tst.java
new file mode 100644
index 000000000..49a65e7b7
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlDoc_tst.java
@@ -0,0 +1,71 @@
+/*
+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.xmls; import gplx.*;
+import org.junit.*;
+public class XmlDoc_tst {
+ String xml; XmlDoc xdoc; XmlNde xnde;
+ @Test public void parse_() {
+ xml = String_.Concat("");
+ xdoc = XmlDoc_.parse_(xml);
+ Tfds.Eq("root", xdoc.Root().Name());
+ Tfds.Eq(true, xdoc.Root().NdeType_element());
+ }
+ @Test public void Xml_outer() {
+ xml = String_.Concat
+ ( ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , ""
+ );
+ xdoc = XmlDoc_.parse_(xml);
+ xnde = xdoc.Root().SubNdes().FetchAt(0);
+ Tfds.Eq("a", xnde.Name());
+ Tfds.Eq("", xnde.Xml_outer());
+ }
+ @Test public void Text_inner() {
+ xml = String_.Concat
+ ( ""
+ , ""
+ , "test me"
+ , ""
+ , ""
+ );
+ xdoc = XmlDoc_.parse_(xml);
+ xnde = xdoc.Root().SubNdes().FetchAt(0);
+ Tfds.Eq("a", xnde.Name());
+ Tfds.Eq("test me", xnde.Text_inner());
+ }
+ @Test public void Atrs() {
+ xml = String_.Concat
+ ( ""
+ , ""
+ );
+ xdoc = XmlDoc_.parse_(xml);
+ XmlAtrList atrs = xdoc.Root().Atrs();
+ XmlAtr atr = atrs.FetchAt(1);
+ tst_Atr(atr, "atr1", "1");
+ atr = atrs.FetchAt(1);
+ tst_Atr(atr, "atr1", "1");
+ }
+ void tst_Atr(XmlAtr atr, String expdName, String expdVal) {
+ Tfds.Eq(expdName, atr.Name());
+ Tfds.Eq(expdVal, atr.Value());
+ }
+}
diff --git a/100_core/src_900_xml/gplx/xmls/XmlFileSplitter.java b/100_core/src_900_xml/gplx/xmls/XmlFileSplitter.java
new file mode 100644
index 000000000..cd50ee171
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlFileSplitter.java
@@ -0,0 +1,140 @@
+/*
+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.xmls; import gplx.*;
+import gplx.ios.*;
+import gplx.texts.*;
+public class XmlFileSplitter {
+ public XmlFileSplitterOpts Opts() {return opts;} XmlFileSplitterOpts opts = new XmlFileSplitterOpts();
+ public byte[] Hdr() {return hdr;} private byte[] hdr;
+ public void Clear() {hdr = null;}
+ public void Split(Io_url xmlUrl) {
+ Io_url partDir = opts.PartDir();
+ byte[] xmlEndTagAry = Bry_.new_utf8_(opts.XmlEnd());
+ byte[][] nameAry = XtoByteAry(opts.XmlNames());
+ int partIdx = 0;
+
+ // bgn reading file
+ XmlSplitRdr rdr = new XmlSplitRdr().Init_(xmlUrl, opts.FileSizeMax());
+
+ // split hdr: includes , xmlNamespaces, and any DTD headers; will be prepended to each partFile
+ rdr.Read();
+ int findPos = FindMatchPos(rdr.CurAry(), nameAry); if (findPos == String_.Find_none) throw Err_.new_("could not find any names in first segment");
+ byte[] dataAry = SplitHdr(rdr.CurAry(), findPos);
+ if (opts.XmlBgn() != null)
+ hdr = Bry_.new_utf8_(opts.XmlBgn());
+ byte[] tempAry = new byte[0];
+ int newFindPos = FindMatchPosRev(dataAry, nameAry);
+ findPos = (newFindPos <= findPos) ? String_.Find_none : newFindPos;
+ boolean first = true;
+
+ // split files
+ XmlSplitWtr partWtr = new XmlSplitWtr().Init_(partDir, hdr, opts);
+ while (true) {
+ partWtr.Bgn(partIdx++);
+ if (opts.StatusFmt() != null) ConsoleAdp._.WriteLine(String_.Format(opts.StatusFmt(), partWtr.Url().NameOnly()));
+ partWtr.Write(tempAry);
+ if (!first) {
+ rdr.Read();
+ dataAry = rdr.CurAry();
+ findPos = FindMatchPosRev(dataAry, nameAry);
+ }
+ else
+ first = false;
+
+ // find last closing node
+ while (findPos == String_.Find_none) {
+ if (rdr.Done()) {
+ findPos = rdr.CurRead();
+ break;
+ }
+ else {
+ partWtr.Write(dataAry);
+ rdr.Read();
+ dataAry = rdr.CurAry();
+ findPos = FindMatchPosRev(dataAry, nameAry);
+ }
+ }
+
+ byte[][] rv = SplitRest(dataAry, findPos);
+ partWtr.Write(rv[0]);
+ tempAry = rv[1];
+ boolean done = rdr.Done() && tempAry.length == 0;
+ if (!done)
+ partWtr.Write(xmlEndTagAry);
+ partWtr.Rls();
+ if (done) break;
+ }
+ rdr.Rls();
+ }
+ public byte[] SplitHdr(byte[] src, int findPos) {
+ hdr = new byte[findPos];
+ Array_.CopyTo(src, 0, hdr, 0, findPos);
+ byte[] rv = new byte[src.length - findPos];
+ Array_.CopyTo(src, findPos, rv, 0, rv.length);
+ return rv;
+ }
+ public byte[][] SplitRest(byte[] src, int findPos) {
+ byte[][] rv = new byte[2][];
+ rv[0] = new byte[findPos];
+ Array_.CopyTo(src, 0, rv[0], 0, findPos);
+ rv[1] = new byte[src.length - findPos];
+ Array_.CopyTo(src, findPos, rv[1], 0, rv[1].length);
+ return rv;
+ }
+ public int FindMatchPos(byte[] src, byte[][] wordAry) {return FindMatchPos(src, wordAry, true);}
+ public int FindMatchPosRev(byte[] src, byte[][] wordAry) {return FindMatchPos(src, wordAry, false);}
+ int FindMatchPos(byte[] src, byte[][] wordAry, boolean fwd) {
+ int[] findAry = new int[wordAry.length];
+ for (int i = 0; i < findAry.length; i++)
+ findAry[i] = fwd ? -1 : Int_.MaxValue;
+ for (int i = 0; i < wordAry.length; i++) { // look at each word in wordAry
+ int srcLen = src.length, srcPos, srcEnd, srcDif;
+ if (fwd) {srcPos = 0; srcEnd = srcLen; srcDif = 1;}
+ else {srcPos = srcLen - 1; srcEnd = -1; srcDif = -1;}
+ while (srcPos != srcEnd) { // look at each byte in src
+ byte[] ary = wordAry[i];
+ int aryLen = ary.length, aryPos, aryEnd, aryDif;
+ if (fwd) {aryPos = 0; aryEnd = aryLen; aryDif = 1;}
+ else {aryPos = aryLen - 1; aryEnd = -1; aryDif = -1;}
+ boolean found = true;
+ while (aryPos != aryEnd) { // look at each byte in word
+ int lkpPos = srcPos + aryPos;
+ if (lkpPos >= srcLen) {found = false; break;} // outside bounds; exit
+ if (ary[aryPos] != src[lkpPos]) {found = false; break;} // srcByte doesn't match wordByte; exit
+ aryPos += aryDif;
+ }
+ if (found) {findAry[i] = srcPos; break;} // result found; stop now and keep "best" result
+ srcPos += srcDif;
+ }
+ }
+ int best = fwd ? -1 : Int_.MaxValue;
+ for (int find : findAry) {
+ if ((fwd && find > best)
+ || (!fwd && find < best))
+ best = find;
+ }
+ if (best == Int_.MaxValue) best = -1;
+ return best;
+ }
+ byte[][] XtoByteAry(String[] names) {
+ byte[][] rv = new byte[names.length][];
+ for (int i = 0; i < names.length; i++)
+ rv[i] = Bry_.new_utf8_(names[i]);
+ return rv;
+ }
+}
diff --git a/100_core/src_900_xml/gplx/xmls/XmlFileSplitterOpts.java b/100_core/src_900_xml/gplx/xmls/XmlFileSplitterOpts.java
new file mode 100644
index 000000000..39825f2d8
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlFileSplitterOpts.java
@@ -0,0 +1,27 @@
+/*
+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.xmls; import gplx.*;
+public class XmlFileSplitterOpts {
+ public int FileSizeMax() {return fileSizeMax;} public XmlFileSplitterOpts FileSizeMax_(int v) {fileSizeMax = v; return this;} int fileSizeMax = 1024 * 1024;
+ public String[] XmlNames() {return xmlNames;} public XmlFileSplitterOpts XmlNames_(String... v) {xmlNames = v; return this;} private String[] xmlNames;
+ public String XmlBgn() {return xmlBgn;} public XmlFileSplitterOpts XmlBgn_(String v) {xmlBgn = v; return this;} private String xmlBgn;
+ public String XmlEnd() {return xmlEnd;} public XmlFileSplitterOpts XmlEnd_(String v) {xmlEnd = v; return this;} private String xmlEnd;
+ public Io_url PartDir() {return partDir;} public XmlFileSplitterOpts PartDir_(Io_url v) {partDir = v; return this;} Io_url partDir;
+ public String StatusFmt() {return statusFmt;} public XmlFileSplitterOpts StatusFmt_(String v) {statusFmt = v; return this;} private String statusFmt = "splitting {0}";
+ public HierStrBldr Namer() {return namer;} HierStrBldr namer = new HierStrBldr();
+}
diff --git a/100_core/src_900_xml/gplx/xmls/XmlFileSplitter_tst.java b/100_core/src_900_xml/gplx/xmls/XmlFileSplitter_tst.java
new file mode 100644
index 000000000..824a9147f
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlFileSplitter_tst.java
@@ -0,0 +1,88 @@
+/*
+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.xmls; import gplx.*;
+import org.junit.*;
+import gplx.ios.*; import gplx.texts.*;
+public class XmlFileSplitter_tst {
+ @Before public void setup() {
+ splitter = new XmlFileSplitter();
+ Io_mgr._.InitEngine_mem();
+ } XmlFileSplitter splitter;
+ @Test public void FindMatchPos() {
+ tst_FindMatchPos("abcde", "a", 0);
+ tst_FindMatchPos("abcde", "b", 1);
+ tst_FindMatchPos("abcde", "cd", 2);
+ tst_FindMatchPos("abcde", "f", -1);
+ tst_FindMatchPos("abcde", "fg", -1);
+ } void tst_FindMatchPos(String src, String find, int expd) {Tfds.Eq(expd, splitter.FindMatchPos(byte_(src), byteAry_(find)));}
+ @Test public void FindMatchPosRev() {
+ tst_FindMatchPosRev("abcde", "a", 0);
+ tst_FindMatchPosRev("abcde", "b", 1);
+ tst_FindMatchPosRev("abcde", "cd", 2);
+ tst_FindMatchPosRev("abcde", "f", -1);
+ tst_FindMatchPosRev("abcde", "ef", -1);
+ tst_FindMatchPosRev("abcde", "za", -1);
+ tst_FindMatchPosRev("dbcde", "d", 3);
+ } void tst_FindMatchPosRev(String src, String find, int expd) {Tfds.Eq(expd, splitter.FindMatchPosRev(byte_(src), byteAry_(find)));}
+ @Test public void ExtractHdr() {
+ tst_ExtractHdr("", "", "");
+ }
+ @Test public void Split() {
+ splitter.Opts().FileSizeMax_(30).XmlNames_("");
+ tst_Split
+ ( ""
+ , ""
+ , ""
+ , ""
+ );
+ tst_Split
+ ( ""
+ , ""
+ , ""
+ );
+ }
+ void tst_Split(String txt, String... expd) {
+ Io_url xmlFil = Io_url_.mem_fil_("mem/800_misc/txt.xml");
+ Io_url tmpDir = xmlFil.OwnerDir().GenSubDir("temp_xml");
+ Io_mgr._.DeleteDirDeep(tmpDir);
+ splitter.Opts().StatusFmt_(null).PartDir_(tmpDir);
+ splitter.Opts().Namer().Ctor_io(tmpDir, "", "fil_{0}.xml", "000");
+ Io_mgr._.SaveFilStr(xmlFil, txt);
+ splitter.Split(xmlFil);
+ Io_url[] tmpFilAry = Io_mgr._.QueryDir_fils(tmpDir);
+ Tfds.Eq(expd.length, tmpFilAry.length);
+ for (int i = 0; i < tmpFilAry.length; i++) {
+ Io_url tmpFil = tmpFilAry[i];
+ Tfds.Eq(expd[i], Io_mgr._.LoadFilStr(tmpFil));
+ }
+ }
+ byte[] byte_(String s) {return Bry_.new_utf8_(s);}
+ byte[][] byteAry_(String s) {
+ byte[][] rv = new byte[1][];
+ rv[0] = Bry_.new_utf8_(s);
+ return rv;
+ }
+ void tst_ExtractHdr(String src, String find, String expdHdr, String expdSrc) {
+ splitter.Clear();
+ byte[] srcAry = byte_(src);
+ int findPos = splitter.FindMatchPos(srcAry, byteAry_(find));
+ srcAry = splitter.SplitHdr(srcAry, findPos);
+ Tfds.Eq(String_.new_utf8_(splitter.Hdr()), expdHdr);
+ Tfds.Eq(String_.new_utf8_(srcAry), expdSrc);
+ }
+}
diff --git a/100_core/src_900_xml/gplx/xmls/XmlNde.java b/100_core/src_900_xml/gplx/xmls/XmlNde.java
new file mode 100644
index 000000000..7eb5b5e7f
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlNde.java
@@ -0,0 +1,51 @@
+/*
+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.xmls; import gplx.*;
+import java.io.StringWriter;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.w3c.dom.Node;
+public class XmlNde {
+ public XmlAtrList Atrs() {return new XmlAtrList(xnde.getAttributes());}
+ public XmlNdeList SubNdes() {return new XmlNdeList_cls_xml(xnde.getChildNodes());}
+ public String Name() {return xnde.getNodeName();}
+ public String Xml_outer() {
+ Transformer transformer = transformer_();
+ StringWriter writer = new StringWriter();
+ try {transformer.transform(new DOMSource(xnde), new StreamResult(writer));}
+ catch (TransformerException e) {throw Err_.err_key_(e, XmlDoc_.Err_XmlException, "failed to get xml string");}
+ return writer.toString();
+ }
+ public String Text_inner() {return xnde.getTextContent();}
+ public boolean NdeType_element() {return xnde.getNodeType() == Node.ELEMENT_NODE;}
+ public boolean NdeType_textOrEntityReference() {return xnde.getNodeType() == Node.TEXT_NODE || xnde.getNodeType() == Node.ENTITY_REFERENCE_NODE;}
+ @gplx.Internal protected XmlNde(Node xnde) {this.xnde = xnde;} Node xnde;
+ static Transformer transformer_() {
+ TransformerFactory transformerfactory = TransformerFactory.newInstance();
+ Transformer transformer = null;
+ try {transformer = transformerfactory.newTransformer();}
+ catch (TransformerConfigurationException e) {throw Err_.err_key_(e, XmlDoc_.Err_XmlException, "failed to get create transformer");}
+ transformer.setOutputProperty("omit-xml-declaration", "yes");
+ return transformer;
+ }
+ }
diff --git a/100_core/src_900_xml/gplx/xmls/XmlNdeList.java b/100_core/src_900_xml/gplx/xmls/XmlNdeList.java
new file mode 100644
index 000000000..bbd657766
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlNdeList.java
@@ -0,0 +1,35 @@
+/*
+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.xmls; import gplx.*;
+import org.w3c.dom.NodeList;
+public interface XmlNdeList {
+ int Count();
+ XmlNde FetchAt(int i);
+}
+class XmlNdeList_cls_xml implements XmlNdeList {
+ public int Count() {return list.getLength();}
+ public XmlNde FetchAt(int i) {return new XmlNde(list.item(i));}
+ @gplx.Internal protected XmlNdeList_cls_xml(NodeList list) {this.list = list;} NodeList list;
+}
+class XmlNdeList_cls_list implements XmlNdeList {
+ public int Count() {return list.Count();}
+ public XmlNde FetchAt(int i) {return (XmlNde)list.FetchAt(i);}
+ public void Add(XmlNde xnde) {list.Add(xnde);}
+ @gplx.Internal protected XmlNdeList_cls_list(int count) {list = ListAdp_.new_(); list.ResizeBounds(count);} ListAdp list;
+}
+//#}
\ No newline at end of file
diff --git a/100_core/src_900_xml/gplx/xmls/XmlSplitRdr.java b/100_core/src_900_xml/gplx/xmls/XmlSplitRdr.java
new file mode 100644
index 000000000..947f81822
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlSplitRdr.java
@@ -0,0 +1,51 @@
+/*
+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.xmls; import gplx.*;
+import gplx.ios.*;
+public class XmlSplitRdr {
+ public byte[] CurAry() {return curAry;} private byte[] curAry;
+ public long CurSum() {return curSum;} long curSum;
+ public int CurRead() {return curRead;} int curRead;
+ public boolean Done() {return done;} private boolean done;
+ public XmlSplitRdr InitAll_(Io_url url) {
+ stream = Io_mgr._.OpenStreamRead(url);
+ curLen = stream.Len();
+ curAry = new byte[(int)curLen];
+ curSum = 0;
+ curRead = 0;
+ done = false;
+ return this;
+ }
+ public XmlSplitRdr Init_(Io_url url, int curArySize) {
+ stream = Io_mgr._.OpenStreamRead(url);
+ curLen = Io_mgr._.QueryFil(url).Size();
+ curAry = new byte[curArySize];
+ curSum = 0;
+ curRead = 0;
+ done = false;
+ return this;
+ } IoStream stream; long curLen;
+ public void Read() {
+ curRead = stream.ReadAry(curAry);
+ curSum += curRead;
+ done = curSum == curLen;
+ if (done && curRead != curAry.length) // on last pass, readAry may have garbage at end, remove
+ curAry = (byte[])Bry_.Resize_manual(curAry, curRead);
+ }
+ public void Rls() {stream.Rls();}
+}
diff --git a/100_core/src_900_xml/gplx/xmls/XmlSplitWtr.java b/100_core/src_900_xml/gplx/xmls/XmlSplitWtr.java
new file mode 100644
index 000000000..a4ca7afd1
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/XmlSplitWtr.java
@@ -0,0 +1,40 @@
+/*
+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.xmls; import gplx.*;
+import gplx.ios.*;
+public class XmlSplitWtr {
+ public Io_url Url() {return url;} Io_url url;
+ public XmlSplitWtr Init_(Io_url partDir, byte[] hdr, XmlFileSplitterOpts opts) {
+ this.partDir = partDir; this.hdr = hdr; this.opts = opts;
+ return this;
+ }
+ public void Bgn(int partIdx) {
+ String partStr = opts.Namer().GenStrIdxOnly(partIdx);
+ url = Io_url_.mem_fil_(partStr);
+ stream = Io_mgr._.OpenStreamWrite(url);
+ init = true;
+ } boolean init = true; byte[] hdr; XmlFileSplitterOpts opts; Io_url partDir; IoStream stream;
+ public void Write(byte[] ary) {
+ if (init) {
+ stream.WriteAry(hdr);
+ init = false;
+ }
+ stream.WriteAry(ary);
+ }
+ public void Rls() {stream.Rls();}
+}
diff --git a/100_core/src_900_xml/gplx/xmls/Xpath_.java b/100_core/src_900_xml/gplx/xmls/Xpath_.java
new file mode 100644
index 000000000..6c4398250
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/Xpath_.java
@@ -0,0 +1,105 @@
+/*
+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.xmls; import gplx.*;
+public class Xpath_ {
+ public static XmlNdeList SelectAll(XmlNde owner, String xpath) {return Select(owner, xpath, Xpath_Args.all_());}
+ public static XmlNde SelectFirst(XmlNde owner, String xpath) {
+ XmlNdeList rv = Select(owner, xpath, Xpath_Args.first_());
+ return rv.Count() == 0 ? null : rv.FetchAt(0); // selects first
+ }
+ public static XmlNdeList SelectElements(XmlNde owner) {
+ XmlNdeList subNdes = owner.SubNdes(); int count = subNdes.Count();
+ XmlNdeList_cls_list list = new XmlNdeList_cls_list(count);
+ for (int i = 0; i < count; i++) {
+ XmlNde sub = subNdes.FetchAt(i);
+ if (sub.NdeType_element())
+ list.Add(sub);
+ }
+ return list;
+ }
+ static XmlNdeList Select(XmlNde owner, String xpath, Xpath_Args args) {
+ XmlNdeList_cls_list rv = new XmlNdeList_cls_list(ListAdp_.Capacity_initial);
+ String[] parts = String_.Split(xpath, "/");
+ TraverseSubs(owner, parts, 0, rv, args);
+ return rv;
+ }
+ static void TraverseSubs(XmlNde owner, String[] parts, int depth, XmlNdeList_cls_list results, Xpath_Args args) {
+ int partsLen = Array_.Len(parts);
+ if (depth == partsLen) return;
+ String name = parts[depth];
+ XmlNdeList subNdes = owner.SubNdes(); int count = subNdes.Count();
+ for (int i = 0; i < count; i++) {
+ XmlNde sub = subNdes.FetchAt(i);
+ if (args.Cancel) return;
+ if (!String_.Eq(name, sub.Name())) continue;
+ if (depth == partsLen - 1) {
+ results.Add(sub);
+ if (args.SelectFirst) args.Cancel = true;
+ }
+ else
+ TraverseSubs(sub, parts, depth + 1, results, args);
+ }
+ }
+ public static final String InnetTextKey = "&innerText";
+ public static KeyValHash ExtractKeyVals(String xml, Int_obj_ref posRef, String nodeName) {
+ int pos = posRef.Val();
+ Err xmlErr = Err_.new_("error parsing xml").Add("xml", xml).Add("pos", pos);
+ String headBgnFind = "<" + nodeName + " "; int headBgnFindLen = String_.Len(headBgnFind);
+ int headBgn = String_.FindFwd(xml, headBgnFind, pos); if (headBgn == String_.Find_none) return null;
+ int headEnd = String_.FindFwd(xml, ">", headBgn + headBgnFindLen); if (headEnd == String_.Find_none) throw xmlErr;
+ String atrXml = String_.Mid(xml, headBgn, headEnd);
+ KeyValHash rv = ExtractNodeVals(atrXml, xmlErr);
+ boolean noInnerText = String_.CharAt(xml, headEnd - 1) == '/'; // if />, then no inner text
+ if (!noInnerText) {
+ int tail = String_.FindFwd(xml, "" + nodeName + ">", headBgn); if (tail == String_.Find_none) throw xmlErr.Hdr_("could not find tailPos").Add("headBgn", headBgn);
+ String innerText = String_.Mid(xml, headEnd + 1, tail);
+ rv.Add(InnetTextKey, innerText);
+ }
+ posRef.Val_(headEnd);
+ return rv;
+ }
+ static KeyValHash ExtractNodeVals(String xml, Err xmlErr) {
+ KeyValHash rv = KeyValHash.new_();
+ int pos = 0;
+ while (true) {
+ int eqPos = String_.FindFwd(xml, "=", pos); if (eqPos == String_.Find_none) break;
+ int q0Pos = String_.FindFwd(xml, "\"", eqPos + 1); if (q0Pos == String_.Find_none) throw xmlErr.Add("eqPos", eqPos);
+ int q1Pos = String_.FindFwd(xml, "\"", q0Pos + 1); if (q1Pos == String_.Find_none) throw xmlErr.Add("q1Pos", q1Pos);
+ int spPos = eqPos - 1;
+ while (spPos > -1) {
+ char c = String_.CharAt(xml, spPos);
+ if (Char_.IsWhitespace(c)) break;
+ spPos--;
+ }
+ if (spPos == String_.Find_none) throw xmlErr.Hdr_("could not find hdr").Add("eqPos", eqPos);
+ String key = String_.Mid(xml, spPos + 1, eqPos);
+ String val = String_.Mid(xml, q0Pos + 1, q1Pos);
+ rv.Add(key, val);
+ pos = q1Pos;
+ }
+ return rv;
+ }
+}
+class Xpath_Args {
+ public boolean SelectFirst; // false=SelectAll
+ public boolean Cancel;
+ public static Xpath_Args all_() {return new Xpath_Args(false);}
+ public static Xpath_Args first_() {return new Xpath_Args(true);}
+ Xpath_Args(boolean selectFirst) {this.SelectFirst = selectFirst;}
+}
+enum Xpath_SelectMode {All, First}
diff --git a/100_core/src_900_xml/gplx/xmls/Xpath__tst.java b/100_core/src_900_xml/gplx/xmls/Xpath__tst.java
new file mode 100644
index 000000000..e83f1fec7
--- /dev/null
+++ b/100_core/src_900_xml/gplx/xmls/Xpath__tst.java
@@ -0,0 +1,44 @@
+/*
+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.xmls; import gplx.*;
+import org.junit.*;
+public class Xpath__tst {
+ @Test public void Select_all() {
+ String xml = String_.Concat
+ ( ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , ""
+ );
+ tst_SelectAll(xml, "a", 2);
+ tst_SelectAll(xml, "b", 1);
+ tst_SelectAll(xml, "b/c", 3);
+ }
+ void tst_SelectAll(String raw, String xpath, int expdCount) {
+ XmlDoc xdoc = XmlDoc_.parse_(raw);
+ XmlNdeList xndeList = Xpath_.SelectAll(xdoc.Root(), xpath);
+ Tfds.Eq(expdCount, xndeList.Count());
+ }
+}
diff --git a/100_core/tst/gplx/EnmParser_tst.java b/100_core/tst/gplx/EnmParser_tst.java
new file mode 100644
index 000000000..5fbc879db
--- /dev/null
+++ b/100_core/tst/gplx/EnmParser_tst.java
@@ -0,0 +1,60 @@
+/*
+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;
+import org.junit.*;
+public class EnmParser_tst {
+ @Before public void setup() {
+ parser = EnmMgr.new_();
+ }
+ @Test public void Basic() { // 1,2,4,8
+ parser.BitRngEnd_(8);
+ run_Reg(0, "zero");
+ run_Reg(1, "one");
+ run_Reg(2, "two");
+ run_Reg(4, "four");
+ run_Reg(8, "eight");
+
+ tst_Convert("zero", 0);
+ tst_Convert("one", 1);
+ tst_Convert("eight", 8);
+ tst_Convert("one+eight", 9);
+ }
+ @Test public void Keys() {
+ parser.BitRngBgn_(65536).BitRngEnd_(262144);
+ run_Reg( 65, "a");
+ run_Reg( 65536, "shift");
+ run_Reg(131072, "ctrl");
+ run_Reg(262144, "alt");
+ tst_Convert("a", 65);
+ tst_Convert("shift+a", 65 + 65536);
+ tst_Convert("ctrl+a", 65 + 131072);
+ tst_Convert("shift+ctrl+a", 65 + 65536 + 131072);
+ }
+ @Test public void Prefix() {
+ parser.Prefix_("key.").BitRngBgn_(128).BitRngEnd_(128);
+ run_Reg(65, "a");
+ tst_Convert("key.a", 65);
+ }
+ void run_Reg(int i, String s) {parser.RegObj(i, s, "NULL");}
+ void tst_Convert(String raw, int val) {
+ int actlVal = parser.GetVal(raw);
+ Tfds.Eq(val, actlVal);
+ Tfds.Eq(raw, parser.GetStr(val));
+ }
+ EnmMgr parser;
+}
diff --git a/100_core/tst/gplx/ErrMock_tst.java b/100_core/tst/gplx/ErrMock_tst.java
new file mode 100644
index 000000000..f292e2543
--- /dev/null
+++ b/100_core/tst/gplx/ErrMock_tst.java
@@ -0,0 +1,62 @@
+/*
+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;
+import org.junit.*;
+public class ErrMock_tst { // NOTE: ErrMock_tst name important b/c gplx java code will ignore all stacks with gplx.Err_
+ @Before public void setup() {} Err err = null;
+ @Test public void Basic() {
+ err = Err_.new_key_("gplx.MockFail", "mock fail");
+ try {throw err;} catch (Exception e) {err = Err.convert_(e);}
+ tst_Key("gplx.MockFail").tst_Msg("mock fail").tst_ProcName("gplx.ErrMock_tst.Basic");
+ }
+ @Test public void Args() {
+ err = Err_.new_key_("gplx.MockFail", "mock fail").Add("a", 1).Add("b", 2);
+ try {throw err;} catch (Exception e) {err = Err.convert_(e);}
+ tst_Arg(0, "a", 1).tst_Arg(1, "b", 2);
+ }
+// @Test public void PrintAll() {
+// String actl = "";
+// try {FailedMethod();}
+// catch (Exception e) {
+// actl = Err_.Message_gplx(e);
+// }
+// Tfds.Eq_ary_str(String_.Split(String_.Concat_lines_crlf(
+// // " mock fail "
+// ," @a 1"
+// ," @b 2"
+// ," gplx.ErrMock_tst.FailedMethod()"
+// ,"-----------------------------------"
+// ," gplx.ErrMock_tst.PrintAll()"
+// ," c:\\000\\200.dev\\100.gplx\\100.framework\\100.core\\gplx\\tst\\gplx\\errmock_tst.cs(18,0)"
+// ," gplx.ErrMock_tst.FailedMethod()"
+// ," c:\\000\\200.dev\\100.gplx\\100.framework\\100.core\\gplx\\tst\\gplx\\errmock_tst.cs(37,0)"), String_.NewLine),
+// // String_.Split(actl, String_.CrLf));
+// }
+ void FailedMethod() {
+ throw Err_.new_key_("gplx.MockFail", "mock fail").Add("a", 1).Add("b", 2);
+ }
+
+ ErrMock_tst tst_Key(String expd) {Tfds.Eq(expd, err.Key()); return this;}
+ ErrMock_tst tst_Msg(String expd) {Tfds.Eq(expd, err.Hdr()); return this;}
+ ErrMock_tst tst_ProcName(String expd) {Tfds.Eq(expd, err.Proc().SignatureRaw()); return this;}
+ ErrMock_tst tst_Arg(int i, String expdKey, Object expdVal) {
+ KeyVal actl = (KeyVal)err.Args().FetchAt(i);
+ KeyVal expd = KeyVal_.new_(expdKey, expdVal);
+ Tfds.Eq(expd.XtoStr(), actl.XtoStr()); return this;
+ }
+}
diff --git a/100_core/tst/gplx/ErrMsgWtr_tst.java b/100_core/tst/gplx/ErrMsgWtr_tst.java
new file mode 100644
index 000000000..41c04d259
--- /dev/null
+++ b/100_core/tst/gplx/ErrMsgWtr_tst.java
@@ -0,0 +1,72 @@
+/*
+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;
+import org.junit.*;
+public class ErrMsgWtr_tst {
+ @Test public void Rethrow() {
+ tst(new RethrowExample()
+ , "0 failed run "
+ , " gplx.ErrMsgWtr_tst$RethrowExample.Run"
+ , "1 failed proc2 "
+ , " gplx.ErrMsgWtr_tst$RethrowExample.Proc1"
+ , "2 failed proc1; key=key val=123:0 "
+ , " gplx.ErrMsgWtr_tst$RethrowExample.Proc2"
+ , "-----------------------------------"
+ , " gplx.ErrMsgWtr_tst.Rethrow(ErrMsgWtr_tst.java:5)"
+ , " gplx.ErrMsgWtr_tst.tst(ErrMsgWtr_tst.java:24)"
+ , "0 gplx.ErrMsgWtr_tst$RethrowExample.Run(ErrMsgWtr_tst.java:35)"
+ , "1 gplx.ErrMsgWtr_tst$RethrowExample.Proc1(ErrMsgWtr_tst.java:36)"
+ , "2 gplx.ErrMsgWtr_tst$RethrowExample.Proc2(ErrMsgWtr_tst.java:37)"
+ , ""
+ );
+ }
+ void tst(ErrExample o, String... expdAry) {
+// try {o.Run();}
+// catch (Exception exc) {
+// String actlMsg = ErrMsgWtr._.Message_gplx(exc);
+// String[] actlAry = String_.Split(actlMsg, String_.CrLf);
+// Tfds.Eq_ary_str(expdAry, actlAry); //Tfds.Write(String_.CrLf + actlMsg);
+// return;
+// }
+// Tfds.Fail_expdError();
+ }
+ interface ErrExample {void Run();}
+ class RethrowExample implements ErrExample {
+ public void Run() {try {Proc1();} catch(Exception exc) {throw Err_.err_(exc, "failed run");} }
+ public void Proc1() {try {Proc2();} catch(Exception exc) {throw Err_.err_(exc, "failed proc2");} }
+ public void Proc2() {throw Err_.new_key_("gplx.parse", "failed proc1");}
+ }
+ @Test public void Deep() {
+ tst(new DeepExample()
+ , "0 failed proc1; key=key val=123:0 "
+ , " gplx.ErrMsgWtr_tst$DeepExample.Proc2"
+ , "-----------------------------------"
+ , " gplx.ErrMsgWtr_tst.Deep(ErrMsgWtr_tst.java:40)"
+ , " gplx.ErrMsgWtr_tst.tst(ErrMsgWtr_tst.java:24)"
+ , " gplx.ErrMsgWtr_tst$DeepExample.Run(ErrMsgWtr_tst.java:55)"
+ , " gplx.ErrMsgWtr_tst$DeepExample.Proc1(ErrMsgWtr_tst.java:56)"
+ , "0 gplx.ErrMsgWtr_tst$DeepExample.Proc2(ErrMsgWtr_tst.java:57)"
+ , ""
+ );
+ }
+ class DeepExample implements ErrExample {
+ public void Run() {Proc1();}
+ public void Proc1() {Proc2();}
+ public void Proc2() {throw Err_.new_key_("gplx.parse", "failed proc1");}
+ }
+}
diff --git a/100_core/tst/gplx/GfoMsg_rdr_tst.java b/100_core/tst/gplx/GfoMsg_rdr_tst.java
new file mode 100644
index 000000000..edd5c6c7f
--- /dev/null
+++ b/100_core/tst/gplx/GfoMsg_rdr_tst.java
@@ -0,0 +1,57 @@
+/*
+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;
+import org.junit.*;
+public class GfoMsg_rdr_tst {
+ @Before public void setup() {
+ msg = msg_().Add("a", "1").Add("b", "2").Add("c", "3");
+ ctx.Match("init", "init");
+ } GfoMsg msg; GfsCtx ctx = GfsCtx.new_();
+ @Test public void Key() {
+ tst_Msg(msg, "a", "1");
+ tst_Msg(msg, "b", "2");
+ tst_Msg(msg, "c", "3");
+ tst_Msg(msg, "d", null);
+ }
+ @Test public void Pos() {
+ msg = msg_().Add("", "1").Add("", "2").Add("", "3");
+ tst_Msg(msg, "", "1");
+ tst_Msg(msg, "", "2");
+ tst_Msg(msg, "", "3");
+ tst_Msg(msg, "", null);
+ }
+ @Test public void OutOfOrder() {
+ tst_Msg(msg, "c", "3");
+ tst_Msg(msg, "b", "2");
+ tst_Msg(msg, "a", "1");
+ }
+ @Test public void Key3_Pos1_Pos2() {
+ msg = msg_().Add("", "1").Add("", "2").Add("c", "3");
+ tst_Msg(msg, "c", "3");
+ tst_Msg(msg, "", "1");
+ tst_Msg(msg, "", "2");
+ }
+ @Test public void MultipleEmpty() {
+ msg = msg_().Add("", "1").Add("", "2").Add("", "3");
+ tst_Msg(msg, "", "1");
+ tst_Msg(msg, "", "2");
+ tst_Msg(msg, "", "3");
+ }
+ GfoMsg msg_() {return GfoMsg_.new_parse_("test");}
+ void tst_Msg(GfoMsg m, String k, String expd) {Tfds.Eq(expd, m.ReadStrOr(k, null));}
+}
diff --git a/100_core/tst/gplx/GfoTreeBldr_fxt.java b/100_core/tst/gplx/GfoTreeBldr_fxt.java
new file mode 100644
index 000000000..6fdd61dd3
--- /dev/null
+++ b/100_core/tst/gplx/GfoTreeBldr_fxt.java
@@ -0,0 +1,32 @@
+/*
+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;
+public class GfoTreeBldr_fxt {
+ public ListAdp Atrs() {return atrs;} ListAdp atrs = ListAdp_.new_();
+ public ListAdp Subs() {return subs;} ListAdp subs = ListAdp_.new_();
+ public GfoTreeBldr_fxt atr_(Object key, Object val) {
+ atrs.Add(new Object[] {key, val});
+ return this;
+ }
+ public GfoTreeBldr_fxt sub_(GfoTreeBldr_fxt... ary) {
+ for (GfoTreeBldr_fxt sub : ary)
+ subs.Add(sub);
+ return this;
+ }
+ public static GfoTreeBldr_fxt new_() {return new GfoTreeBldr_fxt();} GfoTreeBldr_fxt() {}
+}
diff --git a/100_core/tst/gplx/TfdsTstr_fxt.java b/100_core/tst/gplx/TfdsTstr_fxt.java
new file mode 100644
index 000000000..835116cbe
--- /dev/null
+++ b/100_core/tst/gplx/TfdsTstr_fxt.java
@@ -0,0 +1,98 @@
+/*
+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;
+import gplx.lists.*;
+public class TfdsTstr_fxt {
+ public TfdsTstr_fxt Eq_str(Object expd, Object actl, String name) {
+ int nameLen = String_.Len(name); if (nameLen > nameLenMax) nameLenMax = nameLen;
+ TfdsTstrItm itm = TfdsTstrItm.new_().Expd_(expd).Actl_(actl).Name_(name);
+ list.Add(itm);
+ return this;
+ }
+ public void SubName_push(String s) {
+ stack.Push(s);
+ TfdsTstrItm itm = TfdsTstrItm.new_();
+ itm.SubName_make(stack);
+ itm.TypeOf = 1;
+ list.Add(itm);
+ } StackAdp stack = StackAdp_.new_();
+ public void Fail() {
+ manualFail = true;
+ }boolean manualFail = false;
+ public int List_Max(ListAdp expd, ListAdp actl) {return Math_.Max(expd.Count(), actl.Count());}
+ public int List_Max(String[] expd, String[] actl) {return Math_.Max(expd.length, actl.length);}
+ public Object List_FetchAtOrNull(ListAdp l, int i) {return (i >= l.Count()) ? null : l.FetchAt(i);}
+
+ public void SubName_pop() {stack.Pop();}
+ int nameLenMax = 0;
+ public void tst_Equal(String hdr) {
+ boolean pass = true;
+ for (int i = 0; i < list.Count(); i++) {
+ TfdsTstrItm itm = (TfdsTstrItm)list.FetchAt(i);
+ if (!itm.Compare()) pass = false; // don't break early; Compare all vals
+ }
+ if (pass && !manualFail) return;
+ String_bldr sb = String_bldr_.new_();
+ sb.Add_char_crlf();
+ sb.Add_str_w_crlf(hdr);
+ for (int i = 0; i < list.Count(); i++) {
+ TfdsTstrItm itm = (TfdsTstrItm)list.FetchAt(i);
+ if (itm.TypeOf == 1) {
+ sb.Add_fmt_line(" /{0}", itm.SubName());
+ continue;
+ }
+ boolean hasError = itm.CompareResult() != TfdsTstrItm.CompareResult_eq;
+ String errorKey = hasError ? "*" : " ";
+ sb.Add_fmt_line("{0}{1} {2}", errorKey, String_.PadEnd(itm.Name(), nameLenMax, " "), itm.Expd());
+ if (hasError)
+ sb.Add_fmt_line("{0}{1} {2}", errorKey, String_.PadEnd("", nameLenMax, " "), itm.Actl());
+ }
+ sb.Add(String_.Repeat("_", 80));
+ throw Err_.new_(sb.XtoStr());
+ }
+ ListAdp list = ListAdp_.new_();
+ public static TfdsTstr_fxt new_() {return new TfdsTstr_fxt();} TfdsTstr_fxt() {}
+}
+class TfdsTstrItm {
+ public String Name() {return name;} public TfdsTstrItm Name_(String val) {name = val; return this;} private String name;
+ public Object Expd() {return expd;} public TfdsTstrItm Expd_(Object val) {expd = val; return this;} Object expd;
+ public Object Actl() {return actl;} public TfdsTstrItm Actl_(Object val) {actl = val; return this;} Object actl;
+ public String SubName() {return subName;} private String subName = "";
+ public int TypeOf;
+ public void SubName_make(StackAdp stack) {
+ if (stack.Count() == 0) return;
+ ListAdp list = stack.XtoList();
+ String_bldr sb = String_bldr_.new_();
+ for (int i = 0; i < list.Count(); i++) {
+ if (i != 0) sb.Add(".");
+ sb.Add((String)list.FetchAt(i));
+ }
+ subName = sb.XtoStr();
+ }
+ public int CompareResult() {return compareResult;} public TfdsTstrItm CompareResult_(int val) {compareResult = val; return this;} int compareResult;
+ public boolean Compare() {
+ boolean eq = Object_.Eq(expd, actl);
+ compareResult = eq ? 1 : 0;
+ return eq;
+ }
+ public String CompareSym() {
+ return compareResult == 1 ? "==" : "!=";
+ }
+ public static TfdsTstrItm new_() {return new TfdsTstrItm();} TfdsTstrItm() {}
+ public static final int CompareResult_none = 0, CompareResult_eq = 1, CompareResult_eqn = 2;
+}
diff --git a/100_core/tst/gplx/ios/IoEngineFxt.java b/100_core/tst/gplx/ios/IoEngineFxt.java
new file mode 100644
index 000000000..42cfa6924
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngineFxt.java
@@ -0,0 +1,54 @@
+/*
+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.ios; import gplx.*;
+public class IoEngineFxt {
+ IoEngine EngineOf(Io_url url) {return IoEnginePool._.Fetch(url.Info().EngineKey());}
+ public void tst_ExistsPaths(boolean expd, Io_url... ary) {
+ for (Io_url fil : ary) {
+ if (fil.Type_dir())
+ Tfds.Eq(expd, EngineOf(fil).ExistsDir(fil), "ExistsDir failed; dir={0}", fil);
+ else
+ Tfds.Eq(expd, EngineOf(fil).ExistsFil_api(fil), "ExistsFil failed; fil={0}", fil);
+ }
+ }
+ public void tst_LoadFilStr(Io_url fil, String expd) {Tfds.Eq(expd, EngineOf(fil).LoadFilStr(IoEngine_xrg_loadFilStr.new_(fil)));}
+ public void run_SaveFilText(Io_url fil, String expd) {EngineOf(fil).SaveFilText_api(IoEngine_xrg_saveFilStr.new_(fil, expd));}
+ public void run_UpdateFilModifiedTime(Io_url fil, DateAdp modifiedTime) {EngineOf(fil).UpdateFilModifiedTime(fil, modifiedTime);}
+ public void tst_QueryFilReadOnly(Io_url fil, boolean expd) {Tfds.Eq(expd, EngineOf(fil).QueryFil(fil).ReadOnly());}
+ public IoEngineFxt tst_QueryFil_size(Io_url fil, long expd) {Tfds.Eq(expd, EngineOf(fil).QueryFil(fil).Size()); return this;}
+ public IoEngineFxt tst_QueryFil_modifiedTime(Io_url fil, DateAdp expd) {Tfds.Eq_date(expd, EngineOf(fil).QueryFil(fil).ModifiedTime()); return this;}
+ public IoItmDir tst_ScanDir(Io_url dir, Io_url... expd) {
+ IoItmDir dirItem = EngineOf(dir).QueryDir(dir);
+ Io_url[] actl = new Io_url[dirItem.SubDirs().Count() + dirItem.SubFils().Count()];
+ for (int i = 0; i < dirItem.SubDirs().Count(); i++) {
+ IoItmDir subDir = IoItmDir_.as_(dirItem.SubDirs().FetchAt(i));
+ actl[i] = subDir.Url();
+ }
+ for (int i = 0; i < dirItem.SubFils().Count(); i++) {
+ IoItmFil subFil = IoItmFil_.as_(dirItem.SubFils().FetchAt(i));
+ actl[i + dirItem.SubDirs().Count()] = subFil.Url();
+ }
+ Tfds.Eq_ary_str(expd, actl);
+ return dirItem;
+ }
+ public static IoEngineFxt new_() {
+ IoEngineFxt rv = new IoEngineFxt();
+ return rv;
+ }
+ public IoEngineFxt() {}
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_dir_basic_base.java b/100_core/tst/gplx/ios/IoEngine_dir_basic_base.java
new file mode 100644
index 000000000..c80d93e92
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_dir_basic_base.java
@@ -0,0 +1,79 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public abstract class IoEngine_dir_basic_base {
+ @Before public void setup() {
+ engine = engine_();
+ fx = IoEngineFxt.new_();
+ setup_hook();
+ } protected IoEngine engine; @gplx.Internal protected IoEngineFxt fx; protected Io_url fil, root;
+ protected abstract IoEngine engine_();
+ protected abstract void setup_hook();
+ @Test @gplx.Virtual public void CreateDir() {
+ fx.tst_ExistsPaths(false, root);
+
+ engine.CreateDir(root);
+ fx.tst_ExistsPaths(true, root);
+ }
+ @Test public void DeleteDir() {
+ engine.CreateDir(root);
+ fx.tst_ExistsPaths(true, root);
+
+ engine.DeleteDir(root);
+ fx.tst_ExistsPaths(false, root);
+ }
+ @Test public void CreateDir_createAllOwners() {
+ Io_url subDir = root.GenSubDir_nest("sub1");
+ fx.tst_ExistsPaths(false, subDir, subDir.OwnerDir());
+
+ engine.CreateDir(subDir);
+ fx.tst_ExistsPaths(true, subDir, subDir.OwnerDir());
+ }
+// @Test public void DeleteDir_missing_fail() {
+// try {engine.DeleteDir(root);}
+// catch {return;}
+// Tfds.Fail_expdError();
+// }
+ @Test public void DeleteDir_missing_pass() {
+ engine.DeleteDir(root);
+ }
+ @Test @gplx.Virtual public void ScanDir() {
+ Io_url fil = root.GenSubFil("fil1.txt"); fx.run_SaveFilText(fil, "test");
+ Io_url dir1 = root.GenSubDir_nest("dir1"); engine.CreateDir(dir1);
+ Io_url dir1_1 = dir1.GenSubDir_nest("dir1_1"); engine.CreateDir(dir1_1); // NOTE: QueryDir should not recurse by default; dir1_1 should not be returned below
+
+ fx.tst_ScanDir(root, dir1, fil);
+ }
+ @Test public void MoveDir() {
+ Io_url src = root.GenSubDir_nest("src"), trg = root.GenSubDir_nest("trg");
+ engine.CreateDir(src);
+ fx.tst_ExistsPaths(true, src); fx.tst_ExistsPaths(false, trg);
+
+ engine.MoveDir(src, trg);
+ fx.tst_ExistsPaths(false, src); fx.tst_ExistsPaths(true, trg);
+}
+@Test @gplx.Virtual public void CopyDir() {
+ Io_url src = root.GenSubDir_nest("src"), trg = root.GenSubDir_nest("trg");
+ engine.CreateDir(src);
+ fx.tst_ExistsPaths(true, src); fx.tst_ExistsPaths(false, trg);
+
+ engine.CopyDir(src, trg);
+ fx.tst_ExistsPaths(true, src, trg);
+}
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_dir_basic_memory_tst.java b/100_core/tst/gplx/ios/IoEngine_dir_basic_memory_tst.java
new file mode 100644
index 000000000..d11cae4f3
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_dir_basic_memory_tst.java
@@ -0,0 +1,24 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_dir_basic_memory_tst extends IoEngine_dir_basic_base {
+ @Override protected void setup_hook() {
+ root = Io_url_.mem_dir_("mem");
+ } @Override protected IoEngine engine_() {return IoEngine_.Mem_init_();}
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_dir_basic_system_tst.java b/100_core/tst/gplx/ios/IoEngine_dir_basic_system_tst.java
new file mode 100644
index 000000000..dcb87fe90
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_dir_basic_system_tst.java
@@ -0,0 +1,28 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_dir_basic_system_tst extends IoEngine_dir_basic_base {
+ @Override protected void setup_hook() {
+ root = Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp");
+ IoEngine_xrg_deleteDir.new_(root).Recur_().ReadOnlyFails_off().Exec();
+ } @Override protected IoEngine engine_() {return IoEngine_system.new_();}
+ @Test @Override public void ScanDir() {
+ super.ScanDir();
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_dir_deep_base.java b/100_core/tst/gplx/ios/IoEngine_dir_deep_base.java
new file mode 100644
index 000000000..ed5057826
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_dir_deep_base.java
@@ -0,0 +1,126 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public abstract class IoEngine_dir_deep_base {
+ @Before public void setup() {
+ engine = engine_();
+ fx = IoEngineFxt.new_();
+ setup_hook();
+ setup_paths();
+ setup_objs();
+ } protected IoEngine engine; protected Io_url fil, root; @gplx.Internal protected IoEngineFxt fx;
+ protected abstract IoEngine engine_();
+ protected abstract void setup_hook();
+ @Test @gplx.Virtual public void SearchDir() {
+ Io_url[] expd = paths_(src_dir0a, src_fil0a, src_dir0a_dir0a, src_dir0a_fil0a);
+ Io_url[] actl = IoEngine_xrg_queryDir.new_(src).Recur_().DirInclude_().ExecAsUrlAry();
+ Tfds.Eq_ary(expd, actl);
+ }
+ @Test @gplx.Virtual public void MoveDirDeep() {
+ fx.tst_ExistsPaths(true, srcTree); fx.tst_ExistsPaths(false, trgTree);
+
+ engine.MoveDirDeep(IoEngine_xrg_xferDir.move_(src, trg).Recur_());
+ fx.tst_ExistsPaths(false, srcTree);
+ fx.tst_ExistsPaths(true, trgTree);
+ }
+ @Test @gplx.Virtual public void CopyDir() {
+ fx.tst_ExistsPaths(true, srcTree); fx.tst_ExistsPaths(false, trgTree);
+
+ engine.CopyDir(src, trg);
+ fx.tst_ExistsPaths(true, srcTree);
+ fx.tst_ExistsPaths(true, trgTree);
+ }
+ @Test @gplx.Virtual public void DeleteDir() {
+ fx.tst_ExistsPaths(true, srcTree);
+
+ engine.DeleteDirDeep(IoEngine_xrg_deleteDir.new_(src).Recur_());
+ fx.tst_ExistsPaths(false, srcTree);
+ }
+// @Test public virtual void CopyDir_IgnoreExisting() {
+// fx.tst_ExistsPaths(true, srcTree); fx.tst_ExistsPaths(false, trgTree);
+// engine.SaveFilStr(trg_dir0a_fil0a, "x"); // NOTE: this file is different than src counterpart; should be overwritten by Copy
+// fx.tst_ExistsPaths(true, trg_dir0a, trg_dir0a_fil0a);
+//
+// engine.CopyDir(src, trg);
+// fx.tst_ExistsPaths(true, srcTree);
+// fx.tst_ExistsPaths(true, trgTree);
+// }
+// @Test public virtual void CopyDir_IgnoreExistingReadOnlyFile() {
+// fx.tst_ExistsPaths(true, srcTree); fx.tst_ExistsPaths(false, trgTree);
+// engine.SaveFilStr(trg_fil0a, "x"); // NOTE: this file is different than src counterpart; should be overwritten by Copy
+// fx.tst_ExistsPaths(true, trg_fil0a);
+// engine.UpdateFilAttrib(trg_fil0a, IoItmAttrib.ReadOnlyFile);
+//
+// engine.CopyDir(src, trg);
+// fx.tst_ExistsPaths(true, srcTree);
+// fx.tst_ExistsPaths(true, trgTree);
+// }
+// @Test public void MoveDir_IgnoreExisting() {
+// fx.tst_ExistsPaths(true, srcTree);
+// fx.tst_ExistsPaths(false, trgTree);
+// engine.SaveFilStr(trg_dir0a_fil0a, @"x"); // NOTE: this file is different than src counterpart; should be overwritten by Copy
+// fx.tst_ExistsPaths(true, trg_dir0a, trg_dir0a_fil0a);
+//
+// engine.MoveDir(src, trg);
+//
+// fx.tst_ExistsPaths(true, srcTree);
+// fx.tst_ExistsPaths(true, trgTree);
+// }
+// @Test public virtual void ProgressUi() {
+// ConsoleDlg_dev dialog = ConsoleDlg_dev.new_();
+// engine.SearchDir(src).Recur_().Prog_(dialog).ExecAsDir();
+//
+// Tfds.Eq(dialog.Written.Count, 3); // 3 levels
+// tst_(dialog, 0, "scan", src);
+// tst_(dialog, 1, "scan", src_dir0a);
+// tst_(dialog, 2, "scan", src_dir0a_dir0a);
+// }
+// void tst_(ConsoleDlg_dev dialog, int i, String s, Io_url root) {
+// Object o = dialog.Written.FetchAt(i);
+// IoStatusArgs args = (IoStatusArgs)o;
+// Tfds.Eq(s, args.Op);
+// Tfds.Eq(root, args.Path);
+// }
+ protected Io_url src, src_dir0a, src_dir0a_dir0a;
+ Io_url src_fil0a, src_dir0a_fil0a;
+ protected Io_url trg, trg_dir0a, trg_dir0a_dir0a;
+ Io_url trg_fil0a, trg_dir0a_fil0a;
+ Io_url[] srcTree, trgTree;
+ Io_url[] paths_(Io_url... ary) {return ary;}
+ protected void setup_paths() {
+ src = root.GenSubDir_nest("src");
+ src_dir0a = root.GenSubDir_nest("src", "dir0a");
+ src_dir0a_dir0a = root.GenSubDir_nest("src", "dir0a", "dir0a");
+ src_fil0a = root.GenSubFil_nest("src", "fil0a.txt");
+ src_dir0a_fil0a = root.GenSubFil_nest("src", "dir0a", "fil0a.txt");
+ trg = root.GenSubDir_nest("trg");
+ trg_dir0a = root.GenSubDir_nest("trg", "dir0a");
+ trg_dir0a_dir0a = root.GenSubDir_nest("trg", "dir0a", "dir0a");
+ trg_fil0a = root.GenSubFil_nest("trg", "fil0a.txt");
+ trg_dir0a_fil0a = root.GenSubFil_nest("trg", "dir0a", "fil0a.txt");
+ srcTree = new Io_url[] {src, src_dir0a, src_dir0a_dir0a, src_fil0a, src_dir0a_fil0a};
+ trgTree = new Io_url[] {trg, trg_dir0a, trg_dir0a_dir0a, trg_fil0a, trg_dir0a_fil0a};
+ }
+ void setup_objs() {
+ fx.run_SaveFilText(src_fil0a, "src_fil0a"); // NOTE: automatically creates src
+ fx.run_SaveFilText(src_dir0a_fil0a, "src_dir0a_fil0a"); // NOTE: automatically creates src_dir0a_dir0a
+ fx.tst_ExistsPaths(true, src_fil0a);
+ engine.CreateDir(src_dir0a_dir0a);
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_dir_deep_memory_tst.java b/100_core/tst/gplx/ios/IoEngine_dir_deep_memory_tst.java
new file mode 100644
index 000000000..d2f75c244
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_dir_deep_memory_tst.java
@@ -0,0 +1,36 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_dir_deep_memory_tst extends IoEngine_dir_deep_base {
+ @Override protected void setup_hook() {
+ root = Io_url_.mem_dir_("mem/root");
+ } @Override protected IoEngine engine_() {return IoEngine_.Mem_init_();}
+ @Test @Override public void SearchDir() {
+ super.SearchDir();
+ }
+ @Test @Override public void MoveDirDeep() {
+ super.MoveDirDeep();
+ }
+ @Test @Override public void CopyDir() {
+ super.CopyDir();
+ }
+ @Test @Override public void DeleteDir() {
+ super.DeleteDir();
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_dir_deep_system_tst.java b/100_core/tst/gplx/ios/IoEngine_dir_deep_system_tst.java
new file mode 100644
index 000000000..79672c36f
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_dir_deep_system_tst.java
@@ -0,0 +1,25 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_dir_deep_system_tst extends IoEngine_dir_deep_base {
+ @Override protected void setup_hook() {
+ root = Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp");
+ IoEngine_xrg_deleteDir.new_(root).Recur_().ReadOnlyFails_off().Exec();
+ } @Override protected IoEngine engine_() {return IoEngine_.Sys;}
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_fil_basic_base.java b/100_core/tst/gplx/ios/IoEngine_fil_basic_base.java
new file mode 100644
index 000000000..98d1e6039
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_fil_basic_base.java
@@ -0,0 +1,176 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*; import gplx.texts.*;/*EncodingAdp_*/
+public abstract class IoEngine_fil_basic_base {
+ @Before public void setup() {
+ engine = engine_();
+ fx = IoEngineFxt.new_();
+ setup_hook();
+ } protected IoEngine engine; protected IoEngineFxt fx; protected Io_url fil, root;
+ protected abstract IoEngine engine_();
+ protected abstract void setup_hook();
+ @Test @gplx.Virtual public void ExistsFil() {
+ fx.tst_ExistsPaths(false, fil);
+ }
+ @Test @gplx.Virtual public void ExistsFil_deep() {
+ fx.tst_ExistsPaths(false, root.GenSubFil_nest("dir1", "dir2", "fil1.txt"));
+ }
+ @Test @gplx.Virtual public void SaveFilStr() {
+ fx.tst_ExistsPaths(false, fil, fil.OwnerDir());
+
+ fx.run_SaveFilText(fil, "text");
+ fx.tst_ExistsPaths(true, fil, fil.OwnerDir());
+ }
+ @Test @gplx.Virtual public void SaveFilText_autoCreateOwnerDir() {
+ fil = fil.OwnerDir().GenSubFil_nest("sub1", "fil1.txt");
+ fx.tst_ExistsPaths(false, fil, fil.OwnerDir());
+
+ fx.run_SaveFilText(fil, "text");
+ fx.tst_ExistsPaths(true, fil, fil.OwnerDir());
+ }
+ @Test @gplx.Virtual public void SaveFilText_overwrite() {
+ fx.run_SaveFilText(fil, "text");
+ fx.tst_ExistsPaths(true, fil);
+
+ fx.run_SaveFilText(fil, "changed");
+ fx.tst_LoadFilStr(fil, "changed");
+ }
+ @Test @gplx.Virtual public void SaveFilText_append() {
+ fx.run_SaveFilText(fil, "text");
+
+ engine.SaveFilText_api(IoEngine_xrg_saveFilStr.new_(fil, "appended").Append_());
+ fx.tst_LoadFilStr(fil, "text" + "appended");
+ }
+ @Test @gplx.Virtual public void SaveFilText_caseInsensitive() {
+ if (root.Info().CaseSensitive()) return;
+ Io_url lcase = root.GenSubFil_nest("dir", "fil.txt");
+ Io_url ucase = root.GenSubFil_nest("DIR", "FIL.TXT");
+ fx.run_SaveFilText(lcase, "text");
+
+ fx.tst_ExistsPaths(true, lcase, ucase);
+ fx.tst_LoadFilStr(lcase, "text");
+ fx.tst_LoadFilStr(ucase, "text");
+ }
+ @Test @gplx.Virtual public void SaveFilText_readOnlyFails() {
+ fx.run_SaveFilText(fil, "text");
+ engine.UpdateFilAttrib(fil, IoItmAttrib.readOnly_());
+
+ try {fx.run_SaveFilText(fil, "changed");}
+ catch (Exception exc) {
+ fx.tst_LoadFilStr(fil, "text");
+ Err_.Noop(exc);
+ return;
+ }
+ Tfds.Fail_expdError();
+ }
+ @Test @gplx.Virtual public void LoadFilStr() {
+ fx.run_SaveFilText(fil, "text");
+ fx.tst_LoadFilStr(fil, "text");
+ }
+ @Test @gplx.Virtual public void LoadFilStr_missingIgnored() {
+ Tfds.Eq("", engine.LoadFilStr(IoEngine_xrg_loadFilStr.new_(fil).MissingIgnored_()));
+ }
+ @Test @gplx.Virtual public void UpdateFilAttrib() {
+ fx.run_SaveFilText(fil, "text");
+ fx.tst_QueryFilReadOnly(fil, false);
+
+ engine.UpdateFilAttrib(fil, IoItmAttrib.readOnly_());
+ fx.tst_QueryFilReadOnly(fil, true);
+ }
+ @Test @gplx.Virtual public void DeleteFil() {
+ fx.run_SaveFilText(fil, "text");
+ fx.tst_ExistsPaths(true, fil);
+
+ engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(fil));
+ fx.tst_ExistsPaths(false, fil);
+ }
+ @Test @gplx.Virtual public void DeleteFil_missing_pass() {
+ fil = root.GenSubFil("fileThatDoesntExist.txt");
+
+ engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(fil).MissingFails_off());
+ fx.tst_ExistsPaths(false, fil);
+ }
+ @Test @gplx.Virtual public void DeleteFil_readOnly_fail() {
+ fx.run_SaveFilText(fil, "text");
+
+ engine.UpdateFilAttrib(fil, IoItmAttrib.readOnly_());
+ try {engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(fil));}
+ catch (Exception exc) {Err_.Noop(exc);
+ fx.tst_ExistsPaths(true, fil);
+ return;
+ }
+ Tfds.Fail_expdError();
+ }
+ @Test @gplx.Virtual public void DeleteFil_readOnly_pass() {
+ fx.run_SaveFilText(fil, "text");
+ engine.UpdateFilAttrib(fil, IoItmAttrib.readOnly_());
+
+ engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(fil).ReadOnlyFails_off());
+ fx.tst_ExistsPaths(false, fil);
+ }
+ @Test @gplx.Virtual public void QueryFil_size() {
+ fx.run_SaveFilText(fil, "text");
+
+ fx.tst_QueryFil_size(fil, String_.Len("text"));
+ }
+ @Test @gplx.Virtual public void UpdateFilModifiedTime() {
+ fx.run_SaveFilText(fil, "text");
+
+ DateAdp time = Tfds.Now_time0_add_min(10);
+ engine.UpdateFilModifiedTime(fil, time);
+ fx.tst_QueryFil_modifiedTime(fil, time);
+ }
+ @Test @gplx.Virtual public void OpenStreamRead() {
+ fx.run_SaveFilText(fil, "text");
+
+ int textLen = String_.Len("text");
+ byte[] buffer = new byte[textLen];
+ IoStream stream = IoStream_.Null;
+ try {
+ stream = engine.OpenStreamRead(fil);
+ stream.Read(buffer, 0, textLen);
+ }
+ finally {stream.Rls();}
+ String actl = String_.new_utf8_(buffer);
+ Tfds.Eq("text", actl);
+ }
+ @Test @gplx.Virtual public void OpenStreamWrite() {
+ IoStream stream = IoEngine_xrg_openWrite.new_(fil).Exec();
+ byte[] buffer = Bry_.new_utf8_("text");
+ int textLen = String_.Len("text");
+ stream.Write(buffer, 0, textLen);
+ stream.Rls();
+
+ fx.tst_LoadFilStr(fil, "text");
+ }
+// @Test public virtual void OpenStreamWrite_in_place() {
+// byte[] buffer = Bry_.new_utf8_("a|b|c");
+// IoStream stream = IoEngine_xrg_openWrite.new_(fil).Exec();
+// stream.Write(buffer, 0, buffer.length);
+// stream.Rls();
+//
+// buffer = Bry_.new_utf8_("B");
+// stream = IoEngine_xrg_openWrite.new_(fil).Exec();
+// stream.Seek(2);
+// stream.Write(buffer, 0, buffer.length);
+// stream.Rls();
+//
+// fx.tst_LoadFilStr(fil, "a|B|c");
+// }
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_fil_basic_memory_tst.java b/100_core/tst/gplx/ios/IoEngine_fil_basic_memory_tst.java
new file mode 100644
index 000000000..1706c4f15
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_fil_basic_memory_tst.java
@@ -0,0 +1,57 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_fil_basic_memory_tst extends IoEngine_fil_basic_base {
+ @Override protected IoEngine engine_() {return IoEngine_.Mem_init_();}
+ @Override protected void setup_hook() {
+ root = Io_url_.mem_dir_("mem");
+ fil = root.GenSubFil_nest("root", "fil.txt");
+ }
+ @Test @Override public void OpenStreamRead() {
+ super.OpenStreamRead ();
+ }
+ @Test @Override public void SaveFilText_overwrite() {
+ super.SaveFilText_overwrite();
+
+ // bugfix: verify changed file in ownerDir's hash
+ IoItmDir dirItm = fx.tst_ScanDir(fil.OwnerDir(), fil);
+ IoItmFil_mem filItm = (IoItmFil_mem)dirItm.SubFils().FetchAt(0);
+ Tfds.Eq(filItm.Text(), "changed");
+ }
+ @Test public void RecycleFil() {
+ fx.run_SaveFilText(fil, "text");
+ fx.tst_ExistsPaths(true, fil);
+
+ IoRecycleBin bin = IoRecycleBin._;
+ ListAdp list = Tfds.RscDir.XtoNames();
+// foreach (String s in list)
+// Tfds.Write(s);
+ list.DelAt(0); // remove drive
+ IoEngine_xrg_recycleFil recycleXrg = bin.Send_xrg(fil)
+ .RootDirNames_(list)
+ .AppName_("gplx.test").Time_(DateAdp_.parse_gplx("20100102_115559123")).Uuid_(UuidAdp_.parse_("467ffb41-cdfe-402f-b22b-be855425784b"));
+ recycleXrg.Exec();
+ fx.tst_ExistsPaths(false, fil);
+ fx.tst_ExistsPaths(true, recycleXrg.RecycleUrl());
+
+ bin.Recover(recycleXrg.RecycleUrl());
+ fx.tst_ExistsPaths(true, fil);
+ fx.tst_ExistsPaths(false, recycleXrg.RecycleUrl());
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_fil_basic_system_tst.java b/100_core/tst/gplx/ios/IoEngine_fil_basic_system_tst.java
new file mode 100644
index 000000000..493d4bc48
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_fil_basic_system_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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_fil_basic_system_tst extends IoEngine_fil_basic_base {
+ @Override protected void setup_hook() {
+ root = Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp");
+ fil = root.GenSubFil("fil.txt");
+ IoEngine_xrg_deleteDir.new_(fil.OwnerDir()).Recur_().ReadOnlyFails_off().Exec();
+ } @Override protected IoEngine engine_() {return IoEngine_system.new_();}
+ @Test public void ExistsFil_IgnoreDifferentCasing() {
+ if (root.Info().CaseSensitive()) return;
+ fx.run_SaveFilText(fil, "text");
+ fx.tst_ExistsPaths(true, fil);
+ fx.tst_ExistsPaths(true, fil.OwnerDir().GenSubFil("FIL.txt"));
+ }
+ @Test @gplx.Virtual public void RecycleFil() {
+ fx.run_SaveFilText(fil, "text");
+ fx.tst_ExistsPaths(true, fil);
+
+ IoRecycleBin bin = IoRecycleBin._;
+ ListAdp list = root.XtoNames(); list.DelAt(0); // remove drive
+ IoEngine_xrg_recycleFil recycleXrg = bin.Send_xrg(fil)
+ .RootDirNames_(list)
+ .AppName_("gplx.test").Time_(DateAdp_.parse_gplx("20100102_115559123")).Uuid_(UuidAdp_.parse_("467ffb41-cdfe-402f-b22b-be855425784b"));
+ recycleXrg.Exec();
+ fx.tst_ExistsPaths(false, fil);
+ fx.tst_ExistsPaths(true, recycleXrg.RecycleUrl());
+
+ bin.Recover(recycleXrg.RecycleUrl());
+ fx.tst_ExistsPaths(true, fil);
+ fx.tst_ExistsPaths(false, recycleXrg.RecycleUrl());
+ }
+ @Test @Override public void DeleteFil_missing_pass() {
+ super.DeleteFil_missing_pass();
+ }
+ @Test @Override public void DeleteFil_readOnly_pass() {
+ super.DeleteFil_readOnly_pass ();
+ }
+ @Test @Override public void SaveFilText_readOnlyFails() {
+ super.SaveFilText_readOnlyFails();
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_fil_xfer_base.java b/100_core/tst/gplx/ios/IoEngine_fil_xfer_base.java
new file mode 100644
index 000000000..8729f870a
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_fil_xfer_base.java
@@ -0,0 +1,106 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public abstract class IoEngine_fil_xfer_base {
+ @Before public void setup() {
+ engine = engine_();
+ fx = IoEngineFxt.new_();
+ setup_hook();
+ src = root.GenSubFil("src.txt"); trg = root.GenSubFil("trg.txt");
+ } protected IoEngine engine; @gplx.Internal protected IoEngineFxt fx; protected Io_url src, trg, root;
+ DateAdp srcModifiedTime = DateAdp_.parse_gplx("2010.04.12 20.26.01.000"), trgModifiedTime = DateAdp_.parse_gplx("2010.04.01 01.01.01.000");
+ protected abstract IoEngine engine_();
+ protected abstract void setup_hook();
+ protected abstract Io_url AltRoot();
+ @Test @gplx.Virtual public void CopyFil() {
+ fx.run_SaveFilText(src, "src"); fx.run_UpdateFilModifiedTime(src, srcModifiedTime);
+ fx.tst_ExistsPaths(true, src);
+ fx.tst_ExistsPaths(false, trg);
+
+ IoEngine_xrg_xferFil.copy_(src, trg).Exec();
+ fx.tst_ExistsPaths(true, src, trg);
+ fx.tst_LoadFilStr(trg, "src");
+ fx.tst_QueryFil_modifiedTime(trg, srcModifiedTime);
+ }
+ @Test @gplx.Virtual public void CopyFil_overwrite_fail() {
+ fx.run_SaveFilText(src, "src");
+ fx.run_SaveFilText(trg, "trg");
+
+ try {IoEngine_xrg_xferFil.copy_(src, trg).Exec();}
+ catch (Exception exc) {Err_.Noop(exc);
+ fx.tst_ExistsPaths(true, src, trg);
+ fx.tst_LoadFilStr(trg, "trg");
+ return;
+ }
+ Tfds.Fail_expdError();
+ }
+ @Test @gplx.Virtual public void CopyFil_overwrite_pass() {
+ fx.run_SaveFilText(src, "src"); fx.run_UpdateFilModifiedTime(src, srcModifiedTime);
+ fx.run_SaveFilText(trg, "trg"); fx.run_UpdateFilModifiedTime(trg, trgModifiedTime);
+
+ IoEngine_xrg_xferFil.copy_(src, trg).Overwrite_().Exec();
+ fx.tst_ExistsPaths(true, src, trg);
+ fx.tst_LoadFilStr(trg, "src");
+ fx.tst_QueryFil_modifiedTime(trg, srcModifiedTime);
+ }
+ @Test @gplx.Virtual public void MoveFil() {
+ fx.run_SaveFilText(src, "src");
+ fx.tst_ExistsPaths(true, src);
+ fx.tst_ExistsPaths(false, trg);
+
+ IoEngine_xrg_xferFil.move_(src, trg).Exec();
+ fx.tst_ExistsPaths(false, src);
+ fx.tst_ExistsPaths(true, trg);
+ }
+ @Test @gplx.Virtual public void MoveFil_overwrite_fail() {
+ fx.run_SaveFilText(src, "src");
+ fx.run_SaveFilText(trg, "trg");
+
+ try {IoEngine_xrg_xferFil.move_(src, trg).Exec();}
+ catch (Exception exc) {Err_.Noop(exc);
+ fx.tst_ExistsPaths(true, src);
+ fx.tst_ExistsPaths(true, trg);
+ fx.tst_LoadFilStr(trg, "trg");
+ return;
+ }
+ Tfds.Fail_expdError();
+ }
+ @Test @gplx.Virtual public void MoveFil_overwrite_pass() {
+ fx.run_SaveFilText(src, "src"); fx.run_UpdateFilModifiedTime(src, srcModifiedTime);
+ fx.run_SaveFilText(trg, "trg"); fx.run_UpdateFilModifiedTime(trg, trgModifiedTime);
+
+ IoEngine_xrg_xferFil.move_(src, trg).Overwrite_().Exec();
+ fx.tst_ExistsPaths(false, src);
+ fx.tst_ExistsPaths(true, trg);
+ fx.tst_LoadFilStr(trg, "src");
+ fx.tst_QueryFil_modifiedTime(trg, srcModifiedTime);
+ }
+ @Test @gplx.Virtual public void MoveFil_betweenDrives() {
+ IoEngine_xrg_deleteDir.new_(AltRoot()).Recur_().ReadOnlyFails_off().Exec();
+ src = root.GenSubFil_nest("dir", "fil1a.txt");
+ trg = AltRoot().GenSubFil_nest("dir", "fil1b.txt");
+ fx.run_SaveFilText(src, "src");
+ fx.tst_ExistsPaths(true, src);
+ fx.tst_ExistsPaths(false, trg);
+
+ IoEngine_xrg_xferFil.move_(src, trg).Exec();
+ fx.tst_ExistsPaths(false, src);
+ fx.tst_ExistsPaths(true, trg);
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_fil_xfer_memory_tst.java b/100_core/tst/gplx/ios/IoEngine_fil_xfer_memory_tst.java
new file mode 100644
index 000000000..dff6bbec1
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_fil_xfer_memory_tst.java
@@ -0,0 +1,28 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_fil_xfer_memory_tst extends IoEngine_fil_xfer_base {
+ @Override protected void setup_hook() {
+ root = Io_url_.mem_dir_("mem");
+ } @Override protected IoEngine engine_() {return IoEngine_.Mem_init_();}
+ @Override protected Io_url AltRoot() {
+ Io_mgr._.InitEngine_mem_("mem2");
+ return Io_url_.mem_dir_("mem2");
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_fil_xfer_system_tst.java b/100_core/tst/gplx/ios/IoEngine_fil_xfer_system_tst.java
new file mode 100644
index 000000000..793de5756
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_fil_xfer_system_tst.java
@@ -0,0 +1,28 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_fil_xfer_system_tst extends IoEngine_fil_xfer_base {
+ @Override protected void setup_hook() {
+ root = Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp");
+ IoEngine_xrg_deleteDir.new_(root.OwnerDir()).Recur_().ReadOnlyFails_off().Exec();
+ } @Override protected IoEngine engine_() {return IoEngine_system.new_();}
+ @Override protected Io_url AltRoot() {
+ return Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp");
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_stream_xfer_tst.java b/100_core/tst/gplx/ios/IoEngine_stream_xfer_tst.java
new file mode 100644
index 000000000..08dd8d4bb
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_stream_xfer_tst.java
@@ -0,0 +1,49 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_stream_xfer_tst {
+ @Before public void setup() {
+ srcEngine = IoEngine_memory.new_("mock1");
+ trgEngine = IoEngine_memory.new_("mock2");
+ IoEnginePool._.AddReplace(srcEngine); IoEnginePool._.AddReplace(trgEngine);
+ IoUrlInfoRegy._.Reg(IoUrlInfo_.mem_("mem1/", srcEngine.Key()));
+ IoUrlInfoRegy._.Reg(IoUrlInfo_.mem_("mem2/", trgEngine.Key()));
+ srcDir = Io_url_.mem_dir_("mem1/dir"); trgDir = Io_url_.mem_dir_("mem2/dir");
+ }
+ @Test public void TransferBetween() {
+ Io_url srcPath = srcDir.GenSubFil("fil.txt");
+ Io_url trgPath = trgDir.GenSubFil("fil.txt");
+ tst_TransferStreams(srcEngine, srcPath, trgEngine, trgPath);
+ }
+ void tst_TransferStreams(IoEngine srcEngine, Io_url srcPath, IoEngine trgEngine, Io_url trgPath) {
+ srcEngine.SaveFilText_api(IoEngine_xrg_saveFilStr.new_(srcPath, "test1"));
+ trgEngine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(trgPath)); // make sure file is deleted
+ fx.tst_ExistsPaths(true, srcPath);
+ fx.tst_ExistsPaths(false, trgPath);
+
+ IoEngineUtl utl = IoEngineUtl.new_();
+ utl.BufferLength_set(4);
+ utl.XferFil(srcEngine, IoEngine_xrg_xferFil.copy_(srcPath, trgPath));
+ fx.tst_ExistsPaths(true, srcPath, trgPath);
+ fx.tst_LoadFilStr(trgPath, "test1");
+ }
+ IoEngineFxt fx = IoEngineFxt.new_();
+ Io_url srcDir, trgDir;
+ IoEngine srcEngine, trgEngine;
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_xrg_queryDir_tst.java b/100_core/tst/gplx/ios/IoEngine_xrg_queryDir_tst.java
new file mode 100644
index 000000000..2b06f5207
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_xrg_queryDir_tst.java
@@ -0,0 +1,65 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_xrg_queryDir_tst {
+ @Before public void setup() {
+ engine = IoEngine_.Mem_init_();
+ } IoEngine engine; Io_url[] ary;
+ @Test public void Basic() {
+ ary = save_text_(fil_("fil1.txt"));
+
+ tst_ExecPathAry(finder_(), ary);
+ }
+ @Test public void FilPath() {
+ ary = save_text_(fil_("fil1.txt"), fil_("fil2.jpg"), fil_("fil3.txt"));
+
+ tst_ExecPathAry(finder_(), ary); // default: all files
+ tst_ExecPathAry(finder_().FilPath_("*.txt") // findPattern of *.txt
+ , fil_("fil1.txt"), fil_("fil3.txt"));
+ }
+ @Test public void Recur() {
+ ary = save_text_(fil_("fil1.txt"), fil_("dirA", "fil1A.jpg"));
+
+ tst_ExecPathAry(finder_(), fil_("fil1.txt")); // default: no recursion
+ tst_ExecPathAry(finder_().Recur_(), ary); // recurse
+ }
+ @Test public void DirPattern() {
+ save_text_(fil_("fil1.txt"), fil_("dirA", "fil1A.jpg"));
+
+ tst_ExecPathAry(finder_(), fil_("fil1.txt")); // default: files only
+ tst_ExecPathAry(finder_().DirInclude_() // include dirs; NOTE: fil1A not returned b/c Recur_ is not true
+ , dir_("dirA"), fil_("fil1.txt"));
+ }
+ @Test public void SortBy() {
+ save_text_(fil_("fil2a.txt"), fil_("fil1.txt"));
+
+ tst_ExecPathAry(finder_() // default: sortByAscOrder
+ , fil_("fil1.txt"), fil_("fil2a.txt"));
+ }
+ IoEngine_xrg_queryDir finder_() {return IoEngine_xrg_queryDir.new_(Io_url_.mem_dir_("mem/root"));}// NOTE: not in setup b/c finder must be newed several times inside test method
+ Io_url fil_(String... ary) {return Io_url_.mem_dir_("mem/root").GenSubFil_nest(ary);}
+ Io_url dir_(String... ary) {return Io_url_.mem_dir_("mem/root").GenSubDir_nest(ary);}
+
+ Io_url[] save_text_(Io_url... ary) {
+ for (Io_url url : ary)
+ Io_mgr._.SaveFilStr(url, url.Raw());
+ return ary;
+ }
+ void tst_ExecPathAry(IoEngine_xrg_queryDir finder, Io_url... expd) {Tfds.Eq_ary(expd, finder.ExecAsUrlAry());}
+}
diff --git a/100_core/tst/gplx/ios/IoEngine_xrg_recycleFil_tst.java b/100_core/tst/gplx/ios/IoEngine_xrg_recycleFil_tst.java
new file mode 100644
index 000000000..5525f7efa
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoEngine_xrg_recycleFil_tst.java
@@ -0,0 +1,32 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoEngine_xrg_recycleFil_tst {
+ @Before public void setup() {
+ IoEngine_.Mem_init_();
+ }
+ @Test public void GenRecycleUrl() {
+ tst_GenRecycleUrl(recycle_(), Io_url_.mem_fil_("mem/z_trash/20100102/gplx.images;115559123;;fil.txt"));
+ tst_GenRecycleUrl(recycle_().Uuid_include_(), Io_url_.mem_fil_("mem/z_trash/20100102/gplx.images;115559123;467ffb41-cdfe-402f-b22b-be855425784b;fil.txt"));
+ }
+ IoEngine_xrg_recycleFil recycle_() {return IoEngine_xrg_recycleFil.gplx_(Io_url_.mem_fil_("mem/dir/fil.txt")).AppName_("gplx.images").Uuid_(UuidAdp_.parse_("467ffb41-cdfe-402f-b22b-be855425784b")).Time_(DateAdp_.parse_gplx("20100102_115559123"));}
+ void tst_GenRecycleUrl(IoEngine_xrg_recycleFil xrg, Io_url expd) {
+ Tfds.Eq(expd, xrg.RecycleUrl());
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoItmDir_FetchDeepOrNull_tst.java b/100_core/tst/gplx/ios/IoItmDir_FetchDeepOrNull_tst.java
new file mode 100644
index 000000000..0ef1c9315
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoItmDir_FetchDeepOrNull_tst.java
@@ -0,0 +1,40 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoItmDir_FetchDeepOrNull_tst {
+ @Before public void setup() {
+ drive = Io_url_.mem_dir_("mem");
+ rootDir = bldr.dir_(drive, bldr.dir_(drive.GenSubDir("sub1")));
+ } IoItm_fxt bldr = IoItm_fxt.new_(); Io_url drive; IoItmDir rootDir;
+ @Test public void FetchDeepOrNull() {
+ tst_FetchDeepOrNull(rootDir, drive.GenSubDir("sub1"), true);
+ tst_FetchDeepOrNull(rootDir, drive.GenSubDir("sub2"), false);
+ tst_FetchDeepOrNull(rootDir.SubDirs().FetchAt(0), drive.GenSubDir("sub1"), true);
+ tst_FetchDeepOrNull(rootDir.SubDirs().FetchAt(0), drive.GenSubDir("sub2"), false);
+ }
+ void tst_FetchDeepOrNull(Object rootDirObj, Io_url find, boolean expdFound) {
+ IoItmDir rootDir = IoItmDir_.as_(rootDirObj);
+ IoItmDir actlDir = rootDir.FetchDeepOrNull(find);
+ if (actlDir == null) {
+ if (expdFound) Tfds.Fail("actlDir is null, but expd dir to be found");
+ else return; // actlDir is null but expdFound was false; return;
+ }
+ Tfds.Eq(find.Raw(), actlDir.Url().Raw());
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoItm_fxt.java b/100_core/tst/gplx/ios/IoItm_fxt.java
new file mode 100644
index 000000000..c11ba52fc
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoItm_fxt.java
@@ -0,0 +1,34 @@
+/*
+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.ios; import gplx.*;
+public class IoItm_fxt {
+ public IoItmFil fil_wnt_(String s) {return fil_(Io_url_.wnt_fil_(s));}
+ public IoItmFil fil_(Io_url url) {return IoItmFil_.new_(url, 1, DateAdp_.parse_gplx("2001-01-01"), DateAdp_.parse_gplx("2001-01-01"));}
+ public IoItmDir dir_wnt_(String s) {return dir_(Io_url_.wnt_dir_(s));}
+ public IoItmDir dir_(Io_url url, IoItm_base... ary) {
+ IoItmDir rv = IoItmDir_.top_(url);
+ for (IoItm_base itm : ary) {
+ if (itm.Type_dir())
+ rv.SubDirs().Add(itm);
+ else
+ rv.SubFils().Add(itm);
+ }
+ return rv;
+ }
+ public static IoItm_fxt new_() {return new IoItm_fxt();} IoItm_fxt() {}
+}
diff --git a/100_core/tst/gplx/ios/IoUrlInfo_alias_tst.java b/100_core/tst/gplx/ios/IoUrlInfo_alias_tst.java
new file mode 100644
index 000000000..424a7302f
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoUrlInfo_alias_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.ios; import gplx.*;
+import org.junit.*;
+public class IoUrlInfo_alias_tst {
+ IoUrlInfo_alias alias;
+ @Test public void MapWntToWnt() {
+ Make("usr:\\", "D:\\usr\\");
+ tst_Xto_api("usr:\\dir\\fil.txt", "D:\\usr\\dir\\fil.txt");
+ tst_OwnerDir("usr:\\dir\\", "usr:\\");
+ tst_OwnerDir("usr:\\", "");
+ tst_NameOnly("usr:\\", "usr");
+ }
+ @Test public void MapToLnx() {
+ Make("usr:\\", "/home/");
+ tst_Xto_api("usr:\\dir\\fil.txt", "/home/dir/fil.txt");
+ }
+ @Test public void MapLnxToWnt() {
+ Make("usr:/", "C:\\usr\\");
+ tst_Xto_api("usr:/dir/fil.txt", "C:\\usr\\dir\\fil.txt");
+ }
+ @Test public void WntToWnt() {
+ Make("C:\\", "X:\\");
+ tst_Xto_api("C:\\dir\\fil.txt", "X:\\dir\\fil.txt");
+ tst_NameOnly("C:\\", "C");
+ }
+ @Test public void WntToLnx() {
+ Make("C:\\", "/home/");
+ tst_Xto_api("C:\\dir\\fil.txt", "/home/dir/fil.txt");
+ }
+ @Test public void LnxToWnt() {
+ Make("/home/", "C:\\");
+ tst_Xto_api("/home/dir/fil.txt", "C:\\dir\\fil.txt");
+ tst_NameOnly("/home/", "home");
+ tst_NameOnly("/", "root");
+ }
+ void tst_Xto_api(String raw, String expd) {Tfds.Eq(expd, alias.Xto_api(raw));}
+ void tst_OwnerDir(String raw, String expd) {Tfds.Eq(expd, alias.OwnerDir(raw));}
+ void tst_NameOnly(String raw, String expd) {Tfds.Eq(expd, alias.NameOnly(raw));}
+ void Make(String srcDir, String trgDir) {
+ alias = IoUrlInfo_alias.new_(srcDir, trgDir, IoEngine_.SysKey);
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoUrl_lnx_tst.java b/100_core/tst/gplx/ios/IoUrl_lnx_tst.java
new file mode 100644
index 000000000..250fe8a5a
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoUrl_lnx_tst.java
@@ -0,0 +1,55 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoUrl_lnx_tst {
+ IoUrlFxt fx = IoUrlFxt.new_();
+ @Test public void Raw() {
+ fx.tst_Xto_gplx(Io_url_.lnx_dir_("/home/"), "/home/");
+ fx.tst_Xto_gplx(Io_url_.lnx_dir_("/home"), "/home/"); // add /
+ fx.tst_Xto_gplx(Io_url_.lnx_dir_("/"), "/");
+ fx.tst_Xto_gplx(Io_url_.lnx_fil_("/home/fil.txt"), "/home/fil.txt");
+ }
+ @Test public void Xto_api() {
+ fx.tst_Xto_api(Io_url_.lnx_fil_("/home/fil.txt"), "/home/fil.txt");
+ fx.tst_Xto_api(Io_url_.lnx_dir_("/home/"), "/home"); // del /
+ fx.tst_Xto_api(Io_url_.lnx_dir_("/"), "/");
+ }
+ @Test public void OwnerRoot() {
+ fx.tst_OwnerRoot(Io_url_.lnx_dir_("/home/fil.txt"), "/");
+ fx.tst_OwnerRoot(Io_url_.lnx_dir_("/home"), "/");
+ fx.tst_OwnerRoot(Io_url_.lnx_dir_("root"), "/");
+ }
+ @Test public void XtoNames() {
+ fx.tst_XtoNames(Io_url_.lnx_dir_("/home/fil.txt"), fx.ary_("root", "home", "fil.txt"));
+ fx.tst_XtoNames(Io_url_.lnx_dir_("/home"), fx.ary_("root", "home"));
+ }
+ @Test public void IsDir() {
+ fx.tst_IsDir(Io_url_.lnx_dir_("/home"), true);
+ fx.tst_IsDir(Io_url_.lnx_fil_("/home/file.txt"), false);
+ }
+ @Test public void OwnerDir() {
+ fx.tst_OwnerDir(Io_url_.lnx_dir_("/home/lnxusr"), Io_url_.lnx_dir_("/home"));
+ fx.tst_OwnerDir(Io_url_.lnx_dir_("/fil.txt"), Io_url_.lnx_dir_("/"));
+ fx.tst_OwnerDir(Io_url_.lnx_dir_("/"), Io_url_.Null);
+ }
+ @Test public void NameAndExt() {
+ fx.tst_NameAndExt(Io_url_.lnx_fil_("/fil.txt"), "fil.txt");
+ fx.tst_NameAndExt(Io_url_.lnx_dir_("/dir"), "dir/");
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoUrl_map_tst.java b/100_core/tst/gplx/ios/IoUrl_map_tst.java
new file mode 100644
index 000000000..2b2a094e3
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoUrl_map_tst.java
@@ -0,0 +1,31 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoUrl_map_tst {
+ IoUrlFxt fx = IoUrlFxt.new_();
+ @Test public void Xto_api() {
+ IoUrlInfo inf = IoUrlInfo_.alias_("tst:\\", "C:\\tst\\", IoEngine_.SysKey);
+ fx.tst_Xto_api(Io_url_.new_inf_("tst:\\dir\\fil.txt", inf), "C:\\tst\\dir\\fil.txt");
+ fx.tst_Xto_api(Io_url_.new_inf_("tst:\\dir\\", inf), "C:\\tst\\dir"); // no trailing \
+ }
+ @Test public void Xto_api_wce() {
+ IoUrlInfo inf = IoUrlInfo_.alias_("wce:\\", "\\SD Card\\", IoEngine_.SysKey);
+ fx.tst_Xto_api(Io_url_.new_inf_("wce:\\dir\\", inf), "\\SD Card\\dir");
+ }
+}
diff --git a/100_core/tst/gplx/ios/IoUrl_wnt_tst.java b/100_core/tst/gplx/ios/IoUrl_wnt_tst.java
new file mode 100644
index 000000000..341b47af2
--- /dev/null
+++ b/100_core/tst/gplx/ios/IoUrl_wnt_tst.java
@@ -0,0 +1,98 @@
+/*
+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.ios; import gplx.*;
+import org.junit.*;
+public class IoUrl_wnt_tst {
+ IoUrlFxt fx = IoUrlFxt.new_();
+ @Test public void Raw() {
+ fx.tst_Xto_gplx(Io_url_.wnt_fil_("C:\\dir\\fil.txt"), "C:\\dir\\fil.txt");
+ fx.tst_Xto_gplx(Io_url_.wnt_dir_("C:\\dir\\"), "C:\\dir\\");
+ fx.tst_Xto_gplx(Io_url_.wnt_dir_("C:\\dir") , "C:\\dir\\"); // add \
+ }
+ @Test public void Xto_api() {
+ fx.tst_Xto_api(Io_url_.wnt_fil_("C:\\fil.txt"), "C:\\fil.txt");
+ fx.tst_Xto_api(Io_url_.wnt_dir_("C:\\dir\\"), "C:\\dir"); // del \
+ fx.tst_Xto_api(Io_url_.wnt_dir_("C:"), "C:");
+ }
+ @Test public void OwnerRoot() {
+ fx.tst_OwnerRoot(Io_url_.wnt_dir_("C:\\dir") , "C:\\");
+ fx.tst_OwnerRoot(Io_url_.wnt_dir_("C:\\fil.png") , "C:\\");
+ fx.tst_OwnerRoot(Io_url_.wnt_dir_("C:") , "C:\\");
+ }
+ @Test public void IsDir() {
+ fx.tst_IsDir(Io_url_.wnt_dir_("C:\\dir\\"), true);
+ fx.tst_IsDir(Io_url_.wnt_fil_("C:\\dir"), false);
+ fx.tst_IsDir(Io_url_.wnt_fil_("C:\\fil.txt"), false);
+ }
+ @Test public void OwnerDir() {
+ fx.tst_OwnerDir(Io_url_.wnt_dir_("C:\\dir\\sub1"), Io_url_.wnt_dir_("C:\\dir"));
+ fx.tst_OwnerDir(Io_url_.wnt_fil_("C:\\fil.txt"), Io_url_.wnt_dir_("C:"));
+ fx.tst_OwnerDir(Io_url_.wnt_dir_("C:"), Io_url_.Null);
+// fx.tst_OwnerDir(Io_url_.wnt_fil_("press enter to select this folder"), Io_url_.Null);
+ }
+ @Test public void NameAndExt() {
+ fx.tst_NameAndExt(Io_url_.wnt_fil_("C:\\fil.txt"), "fil.txt");
+ fx.tst_NameAndExt(Io_url_.wnt_dir_("C:\\dir"), "dir\\");
+ }
+ @Test public void NameOnly() {
+ fx.tst_NameOnly(Io_url_.wnt_fil_("C:\\fil.txt"), "fil");
+ fx.tst_NameOnly(Io_url_.wnt_dir_("C:\\dir"), "dir");
+ fx.tst_NameOnly(Io_url_.wnt_dir_("C:"), "C");
+ }
+ @Test public void Ext() {
+ fx.tst_Ext(Io_url_.wnt_fil_("C:\\fil.txt"), ".txt"); // fil
+ fx.tst_Ext(Io_url_.wnt_fil_("C:\\fil.multiple.txt"), ".txt"); // multiple ext
+ fx.tst_Ext(Io_url_.wnt_fil_("C:\\fil"), ""); // no ext
+ fx.tst_Ext(Io_url_.wnt_dir_("C:\\dir"), "\\"); // dir
+ }
+ @Test public void GenSubDir_nest() {
+ fx.tst_GenSubDir_nest(Io_url_.wnt_dir_("C:"), fx.ary_("dir1", "sub1"), Io_url_.wnt_dir_("C:\\dir1\\sub1"));
+ }
+ @Test public void GenNewExt() {
+ fx.tst_GenNewExt(Io_url_.wnt_fil_("C:\\fil.gif"), ".png", Io_url_.wnt_fil_("C:\\fil.png")); // basic
+ fx.tst_GenNewExt(Io_url_.wnt_fil_("C:\\fil.tst.gif"), ".png", Io_url_.wnt_fil_("C:\\fil.tst.png")); // last in multiple dotted
+ }
+ @Test public void GenRelUrl_orEmpty() {
+ fx.tst_GenRelUrl_orEmpty(Io_url_.wnt_fil_("C:\\root\\fil.txt") , Io_url_.wnt_dir_("C:\\root") , "fil.txt"); // fil
+ fx.tst_GenRelUrl_orEmpty(Io_url_.wnt_dir_("C:\\root\\dir") , Io_url_.wnt_dir_("C:\\root") , "dir\\"); // dir
+ fx.tst_GenRelUrl_orEmpty(Io_url_.wnt_fil_("C:\\root\\dir\\fil.txt") , Io_url_.wnt_dir_("C:\\root") , "dir\\fil.txt"); // fil: nested1
+ fx.tst_GenRelUrl_orEmpty(Io_url_.wnt_fil_("C:\\root\\dir\\fil.txt") , Io_url_.wnt_dir_("C:") , "root\\dir\\fil.txt"); // fil: nested2
+ }
+ @Test public void GenParallel() {
+ fx.tst_GenParallel(Io_url_.wnt_fil_("C:\\root1\\fil.txt"), Io_url_.wnt_dir_("C:\\root1"), Io_url_.wnt_dir_("D:\\root2"), Io_url_.wnt_fil_("D:\\root2\\fil.txt"));
+ fx.tst_GenParallel(Io_url_.wnt_dir_("C:\\root1\\dir") , Io_url_.wnt_dir_("C:\\root1"), Io_url_.wnt_dir_("D:\\root2"), Io_url_.wnt_dir_("D:\\root2\\dir"));
+ }
+}
+class IoUrlFxt {
+ public void tst_Xto_api(Io_url url, String expd) {Tfds.Eq(expd, url.Xto_api());}
+ public void tst_OwnerRoot(Io_url url, String expd) {Tfds.Eq(expd, url.OwnerRoot().Raw());}
+ public void tst_XtoNames(Io_url url, String... expdAry) {Tfds.Eq_ary(expdAry, url.XtoNames().XtoStrAry());}
+ public void tst_NameAndExt(Io_url url, String expd) {Tfds.Eq(expd, url.NameAndExt());}
+ public void tst_Xto_gplx(Io_url url, String expd) {Tfds.Eq(expd, url.Raw());}
+ public void tst_IsDir(Io_url url, boolean expd) {Tfds.Eq(expd, url.Type_dir());}
+ public void tst_OwnerDir(Io_url url, Io_url expd) {Tfds.Eq_url(expd, url.OwnerDir());}
+ public void tst_NameOnly(Io_url url, String expd) {Tfds.Eq(expd, url.NameOnly());}
+ public void tst_Ext(Io_url url, String expd) {Tfds.Eq(expd, url.Ext());}
+ public void tst_GenSubDir_nest(Io_url rootDir, String[] parts, Io_url expd) {Tfds.Eq(expd, rootDir.GenSubDir_nest(parts));}
+ public void tst_GenNewExt(Io_url url, String ext, Io_url expd) {Tfds.Eq_url(expd, url.GenNewExt(ext));}
+ public void tst_GenRelUrl_orEmpty(Io_url url, Io_url rootDir, String expd) {Tfds.Eq(expd, url.GenRelUrl_orEmpty(rootDir));}
+ public void tst_GenParallel(Io_url url, Io_url oldRoot, Io_url newRoot, Io_url expd) {Tfds.Eq_url(expd, url.GenParallel(oldRoot, newRoot));}
+
+ public String[] ary_(String... ary) {return String_.Ary(ary);}
+ public static IoUrlFxt new_() {return new IoUrlFxt();} IoUrlFxt() {}
+}
diff --git a/100_core/tst/gplx/stores/GfoNdeRdr_read_tst.java b/100_core/tst/gplx/stores/GfoNdeRdr_read_tst.java
new file mode 100644
index 000000000..4154669b3
--- /dev/null
+++ b/100_core/tst/gplx/stores/GfoNdeRdr_read_tst.java
@@ -0,0 +1,48 @@
+/*
+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.stores; import gplx.*;
+import org.junit.*;
+public class GfoNdeRdr_read_tst {
+ @Test public void ReadInt() {
+ rdr = rdr_(IntClassXtn._, "id", 1);
+ Tfds.Eq(rdr.ReadInt("id"), 1);
+ }
+ @Test public void ReadIntOr() {
+ rdr = rdr_(IntClassXtn._, "id", 1);
+ Tfds.Eq(rdr.ReadIntOr("id", -1), 1);
+ }
+ @Test public void ReadIntElse_minus1() {
+ rdr = rdr_(IntClassXtn._, "id", null);
+ Tfds.Eq(rdr.ReadIntOr("id", -1), -1);
+ }
+ @Test public void ReadInt_parse() {
+ rdr = rdr_(StringClassXtn._, "id", "1");
+ Tfds.Eq(rdr.ReadInt("id"), 1);
+ }
+ @Test public void ReadIntElse_parse() {
+ rdr = rdr_(StringClassXtn._, "id", "2");
+ Tfds.Eq(rdr.ReadIntOr("id", -1), 2);
+ }
+ GfoNdeRdr rdr_(ClassXtn type, String key, Object val) { // makes rdr with one row and one val
+ GfoFldList flds = GfoFldList_.new_().Add(key, type);
+ GfoNde row = GfoNde_.vals_(flds, new Object[] {val});
+ boolean parse = type == StringClassXtn._; // assumes type is either StringClassXtn or IntClassXtn
+ return GfoNdeRdr_.leaf_(row, parse);
+ }
+ GfoNdeRdr rdr;
+}
diff --git a/100_core/tst/gplx/stores/GfoNdeRdr_tst.java b/100_core/tst/gplx/stores/GfoNdeRdr_tst.java
new file mode 100644
index 000000000..fa3a9d4d7
--- /dev/null
+++ b/100_core/tst/gplx/stores/GfoNdeRdr_tst.java
@@ -0,0 +1,189 @@
+/*
+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.stores; import gplx.*;
+import org.junit.*;
+public class GfoNdeRdr_tst {
+ @Test public void Subs_leafs() {
+ root =
+ fx.root_
+ ( fx.row_vals_(0)
+ , fx.row_vals_(1)
+ , fx.row_vals_(2)
+ );
+ tst_NdeVals(root, 0, 1, 2);
+ }
+ @Test public void Subs_ndes() {
+ root =
+ fx.root_
+ ( leaf_("", 0)
+ , leaf_("", 1)
+ , leaf_("", 2)
+ );
+ tst_NdeVals(root, 0, 1, 2);
+ }
+ @Test public void Subs_mix() {
+ root =
+ fx.root_
+ ( leaf_("", 0)
+ , fx.row_vals_(1)
+ , fx.row_vals_(2)
+ );
+ tst_NdeVals(root, 0, 1, 2);
+ }
+ @Test public void Subs_rdr() {
+ root =
+ fx.root_
+ ( fx.row_vals_(0)
+ );
+ rootRdr = GfoNdeRdr_.root_parseNot_(root);
+ DataRdr rdr = rootRdr.Subs();
+ Tfds.Eq_true(rdr.MoveNextPeer());
+ Tfds.Eq(0, rdr.ReadAt(0));
+ Tfds.Eq_false(rdr.MoveNextPeer());
+ }
+ @Test public void MoveNextPeer_implicit() {
+ root =
+ fx.root_
+ ( fx.csv_dat_
+ ( fx.row_vals_(0)
+ , fx.row_vals_(1)
+ , fx.row_vals_(2)
+ )
+ );
+ GfoNdeRdr rootRdr = GfoNdeRdr_.root_parseNot_(root);
+ DataRdr subsRdr = rootRdr.Subs(); // pos=-1; bof
+ DataRdr subRdr = subsRdr.Subs(); // MoveNextPeer not needed; implicitly moves to pos=0
+ tst_RdrVals(subRdr, Object_.Ary(0, 1, 2));
+ }
+ @Test public void MoveNextPeer_explicit() {
+ root =
+ fx.root_
+ ( fx.csv_dat_
+ ( fx.row_vals_(0)
+ , fx.row_vals_(1)
+ , fx.row_vals_(2)
+ )
+ );
+ GfoNdeRdr rootRdr = GfoNdeRdr_.root_parseNot_(root);
+ DataRdr subsRdr = rootRdr.Subs(); // pos=-1; bof
+ Tfds.Eq_true(subsRdr.MoveNextPeer()); // explicitly moves to pos=0
+ DataRdr subRdr = subsRdr.Subs();
+ tst_RdrVals(subRdr, Object_.Ary(0, 1, 2));
+ }
+ @Test public void Xpath_basic() {
+ root = fx.root_
+ ( leaf_("root", 0)
+ , leaf_("root", 1)
+ , leaf_("root", 2)
+ );
+ tst_Xpath_all(root, "root", 0, 1, 2);
+ }
+ @Test public void Xpath_nested() {
+ root = fx.root_
+ ( fx.tbl_("owner"
+ , leaf_("root", 0)
+ , leaf_("root", 1)
+ , leaf_("root", 2)
+ ));
+ tst_Xpath_all(root, "owner/root", 0, 1, 2);
+ }
+ @Test public void Xpath_null() {
+ root = fx.root_
+ ( leaf_("match", 0)
+ );
+ rootRdr = GfoNdeRdr_.root_parseNot_(root);
+ DataRdr sub = rootRdr.Subs_byName("no_match");
+ Tfds.Eq_false(sub.MoveNextPeer());
+ }
+ @Test public void Xpath_moveFirst_basic() {
+ root = fx.root_
+ ( leaf_("nde0", 0)
+ );
+ tst_Xpath_first(root, "nde0", 0);
+ }
+ @Test public void Xpath_moveFirst_shallow() {
+ root = fx.root_
+ ( leaf_("nde0", 0)
+ , leaf_("nde1", 1)
+ , leaf_("nde2", 2)
+ );
+ tst_Xpath_first(root, "nde2", 2);
+ }
+ @Test public void Xpath_moveFirst_nested() {
+ root = fx.root_
+ ( node_("nde0", Object_.Ary("0")
+ , leaf_("nde00", "00")
+ ));
+ tst_Xpath_first(root, "nde0", "0");
+ tst_Xpath_first(root, "nde0/nde00", "00");
+ }
+ @Test public void Xpath_moveFirst_nested_similarName() {
+ root = fx.root_
+ ( node_("nde0", Object_.Ary("0")
+ , leaf_("nde00", "00")
+ )
+ , node_("nde1", Object_.Ary("1")
+ , leaf_("nde00", "10")
+ ));
+ tst_Xpath_first(root, "nde1/nde00", "10");
+ }
+ @Test public void Xpath_moveFirst_many() {
+ root = fx.root_
+ ( leaf_("root", 0)
+ , leaf_("root", 1)
+ , leaf_("root", 2)
+ );
+ tst_Xpath_first(root, "root", 0); // returns first
+ }
+ @Test public void Xpath_moveFirst_null() {
+ root = fx.root_
+ ( leaf_("nde0", 0)
+ , leaf_("nde1", 1)
+ , leaf_("nde2", 2)
+ );
+ rootRdr = GfoNdeRdr_.root_parseNot_(root);
+ DataRdr rdr = rootRdr.Subs_byName("nde3");
+ Tfds.Eq_false(rdr.MoveNextPeer());
+ }
+
+ GfoNde leaf_(String name, Object... vals) {return GfoNde_.nde_(name, vals, GfoNde_.Ary_empty);}
+ GfoNde node_(String name, Object[] vals, GfoNde... subs) {return GfoNde_.nde_(name, vals, subs);}
+ void tst_NdeVals(GfoNde nde, Object... exptVals) {
+ DataRdr rdr = GfoNdeRdr_.root_parseNot_(nde);
+ tst_RdrVals(rdr.Subs(), exptVals);
+ }
+ void tst_RdrVals(DataRdr rdr, Object[] exptVals) {
+ int count = 0;
+ while (rdr.MoveNextPeer()) {
+ Object actl = rdr.ReadAt(0);
+ Tfds.Eq(actl, exptVals[count++]);
+ }
+ Tfds.Eq(count, exptVals.length);
+ }
+ void tst_Xpath_first(GfoNde root, String xpath, Object expt) {
+ DataRdr rdr = GfoNdeRdr_.root_parseNot_(root);
+ DataRdr sel = rdr.Subs_byName_moveFirst(xpath);
+ Object actl = sel.ReadAt(0);
+ Tfds.Eq(actl, expt);
+ }
+ void tst_Xpath_all(GfoNde root, String xpath, Object... exptVals) {
+ DataRdr rdr = GfoNdeRdr_.root_parseNot_(root);
+ tst_RdrVals(rdr.Subs_byName(xpath), exptVals);
+ }
+ GfoNde root; DataRdr rootRdr; GfoNdeFxt fx = GfoNdeFxt.new_();
+}
diff --git a/100_core/tst/gplx/stores/xmls/XmlDataRdr_tst.java b/100_core/tst/gplx/stores/xmls/XmlDataRdr_tst.java
new file mode 100644
index 000000000..511b8115b
--- /dev/null
+++ b/100_core/tst/gplx/stores/xmls/XmlDataRdr_tst.java
@@ -0,0 +1,102 @@
+/*
+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.stores.xmls; import gplx.*; import gplx.stores.*;
+import org.junit.*;
+public class XmlDataRdr_tst {
+ @Test public void Read() {
+ DataRdr rdr = fx.rdr_("");
+ Tfds.Eq(rdr.NameOfNode(), "title");
+ Tfds.Eq(rdr.ReadStr("name"), "first");
+ Tfds.Eq(rdr.ReadInt("id"), 1);
+ Tfds.Eq(rdr.ReadBool("profiled"), false);
+ }
+ @Test public void None() {
+ DataRdr rdr = fx.rdr_
+ ( ""
+ , ""
+ , ""
+ );
+ fx.tst_Subs_ByName(rdr, "no_nde", "no_atr");
+ }
+ @Test public void One() {
+ DataRdr rdr = fx.rdr_
+ ( ""
+ , ""
+ , ""
+ );
+ fx.tst_Subs_ByName(rdr, "find", "id", "f0");
+ }
+ @Test public void One_IgnoreOthers() {
+ DataRdr rdr = fx.rdr_
+ ( ""
+ , ""
+ , ""
+ , ""
+ );
+ fx.tst_Subs_ByName(rdr, "find", "id", "f0");
+ }
+ @Test public void Many() {
+ DataRdr rdr = fx.rdr_
+ ( ""
+ , ""
+ , ""
+ , ""
+ );
+ fx.tst_Subs_ByName(rdr, "find", "id", "f0", "f1");
+ }
+ @Test public void Nested() {
+ DataRdr rdr = fx.rdr_
+ ( ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , ""
+ );
+ fx.tst_Subs_ByName(rdr, "sub1/find", "id", "f0", "f1");
+ }
+ @Test public void Nested_IgnoreOthers() {
+ DataRdr rdr = fx.rdr_
+ ( ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , ""
+ , "" // NOTE: find across ndes
+ , ""
+ , ""
+ , ""
+ );
+ fx.tst_Subs_ByName(rdr, "sub1/find", "id", "f0", "f1");
+ }
+ XmlDataRdr_fxt fx = XmlDataRdr_fxt.new_();
+}
+class XmlDataRdr_fxt {
+ public DataRdr rdr_(String... ary) {return XmlDataRdr_.text_(String_.Concat(ary));}
+ public void tst_Subs_ByName(DataRdr rdr, String xpath, String key, String... expdAry) {
+ DataRdr subRdr = rdr.Subs_byName(xpath);
+ ListAdp list = ListAdp_.new_();
+ while (subRdr.MoveNextPeer())
+ list.Add(subRdr.Read(key));
+
+ String[] actlAry = list.XtoStrAry();
+ Tfds.Eq_ary(actlAry, expdAry);
+ }
+ public static XmlDataRdr_fxt new_() {return new XmlDataRdr_fxt();} XmlDataRdr_fxt() {}
+}
diff --git a/100_core/tst/gplx/stores/xmls/XmlDataWtr_tst.java b/100_core/tst/gplx/stores/xmls/XmlDataWtr_tst.java
new file mode 100644
index 000000000..d2bbde0c2
--- /dev/null
+++ b/100_core/tst/gplx/stores/xmls/XmlDataWtr_tst.java
@@ -0,0 +1,95 @@
+/*
+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.stores.xmls; import gplx.*; import gplx.stores.*;
+import org.junit.*;
+public class XmlDataWtr_tst {
+ @Before public void setup() {
+ wtr = XmlDataWtr.new_();
+ }
+ @Test public void WriteNodeBgn() {
+ wtr.WriteNodeBgn("chapter");
+ tst_XStr(wtr, "", String_.CrLf);
+ }
+ @Test public void Attributes() {
+ wtr.WriteNodeBgn("chapter");
+ wtr.WriteData("id", 1);
+ wtr.WriteData("name", "first");
+ tst_XStr(wtr, "", String_.CrLf);
+ }
+ @Test public void Subs() {
+ wtr.WriteNodeBgn("title");
+ wtr.WriteNodeBgn("chapters");
+ wtr.WriteNodeBgn("chapter");
+ tst_XStr(wtr
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ );
+ }
+ @Test public void Subs_Iterate() {
+ wtr.WriteNodeBgn("titles");
+ for (int title = 1; title <= 2; title++) {
+ wtr.WriteNodeBgn("title");
+ wtr.WriteData("id", title);
+ wtr.WriteNodeBgn("chapters");
+ wtr.WriteNodeEnd(); // chapters
+ wtr.WriteNodeEnd(); // title
+ }
+ wtr.WriteNodeEnd(); //titles
+ tst_XStr(wtr
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ );
+ }
+ @Test public void Peers() {
+ wtr.WriteNodeBgn("title");
+ wtr.WriteNodeBgn("chapters");
+ wtr.WriteNodeEnd();
+ wtr.WriteNodeBgn("audioStreams");
+ tst_XStr(wtr
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ );
+ }
+ @Test public void AtrsWithNesting() {
+ wtr.WriteNodeBgn("title");
+ wtr.WriteData("id", 1);
+ wtr.WriteData("name", "first");
+ wtr.WriteNodeBgn("chapters");
+ tst_XStr(wtr
+ , "", String_.CrLf
+ , "", String_.CrLf
+ , "", String_.CrLf
+ );
+ }
+ void tst_XStr(XmlDataWtr wtr, String... parts) {
+ String expd = String_.Concat(parts);
+ Tfds.Eq(expd, wtr.XtoStr());
+ }
+ XmlDataWtr wtr;
+}
diff --git a/100_core/xtn/gplx/Internal.java b/100_core/xtn/gplx/Internal.java
new file mode 100644
index 000000000..eb976259b
--- /dev/null
+++ b/100_core/xtn/gplx/Internal.java
@@ -0,0 +1,20 @@
+/*
+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;
+public @interface Internal {}
+
diff --git a/100_core/xtn/gplx/MainClass.java b/100_core/xtn/gplx/MainClass.java
new file mode 100644
index 000000000..f50b9e082
--- /dev/null
+++ b/100_core/xtn/gplx/MainClass.java
@@ -0,0 +1,22 @@
+/*
+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;
+public class MainClass {
+ public static void main(String s[]) {
+ }
+}
diff --git a/100_core/xtn/gplx/New.java b/100_core/xtn/gplx/New.java
new file mode 100644
index 000000000..4c0e76d55
--- /dev/null
+++ b/100_core/xtn/gplx/New.java
@@ -0,0 +1,20 @@
+/*
+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;
+public @interface New {}
+
diff --git a/100_core/xtn/gplx/Virtual.java b/100_core/xtn/gplx/Virtual.java
new file mode 100644
index 000000000..6f019ddee
--- /dev/null
+++ b/100_core/xtn/gplx/Virtual.java
@@ -0,0 +1,20 @@
+/*
+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;
+public @interface Virtual {}
+
diff --git a/110_gfml/.classpath b/110_gfml/.classpath
new file mode 100644
index 000000000..813419156
--- /dev/null
+++ b/110_gfml/.classpath
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/110_gfml/.project b/110_gfml/.project
new file mode 100644
index 000000000..2ccedcf3e
--- /dev/null
+++ b/110_gfml/.project
@@ -0,0 +1,17 @@
+
+
+ 110_gfml
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr.java
new file mode 100644
index 000000000..7025efd28
--- /dev/null
+++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr.java
@@ -0,0 +1,34 @@
+/*
+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.gfml; import gplx.*;
+import gplx.texts.*; /*CharStream*/
+public interface GfmlLxr extends GfoEvObj {
+ String Key();
+ String[] Hooks();
+ GfmlTkn CmdTkn();
+ void CmdTkn_set(GfmlTkn val); // needed for lxr pragma
+ GfmlTkn MakeTkn(CharStream stream, int hookLength);
+ GfmlLxr SubLxr();
+ void SubLxr_Add(GfmlLxr... lexer);
+}
+class GfmlLxrRegy {
+ public int Count() {return hash.Count();}
+ public void Add(GfmlLxr lxr) {hash.Add(lxr.Key(), lxr);}
+ public GfmlLxr Fetch(String key) {return (GfmlLxr)hash.Fetch(key);}
+ HashAdp hash = HashAdp_.new_();
+}
diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr_.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr_.java
new file mode 100644
index 000000000..1ca74847d
--- /dev/null
+++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr_.java
@@ -0,0 +1,216 @@
+/*
+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.gfml; import gplx.*;
+import gplx.texts.*; /*CharStream*/
+public class GfmlLxr_ {
+ public static GfmlLxr general_(String key, GfmlTkn protoTkn) {return GfmlLxr_general.new_(key, protoTkn);}
+ public static GfmlLxr solo_(String key, GfmlTkn singletonTkn) {return GfmlLxr_singleton.new_(key, singletonTkn.Raw(), singletonTkn);}
+ public static GfmlLxr range_(String key, String[] ary, GfmlTkn protoTkn, boolean ignoreOutput) {return GfmlLxr_group.new_(key, ary, protoTkn, ignoreOutput);}
+
+ @gplx.Internal protected static GfmlLxr symbol_(String key, String raw, String val, GfmlBldrCmd cmd) {
+ GfmlTkn tkn = GfmlTkn_.singleton_(key, raw, val, cmd);
+ return GfmlLxr_.solo_(key, tkn);
+ }
+ @gplx.Internal protected static GfmlLxr frame_(String key, GfmlFrame frame, String bgn, String end) {return GfmlLxr_frame.new_(key, frame, bgn, end, GfmlBldrCmd_pendingTkns_add._, GfmlBldrCmd_frameEnd.data_());}
+ public static final GfmlLxr Null = new GfmlLxr_null();
+ public static final String CmdTknChanged_evt = "Changed";
+ public static GfmlLxr as_(Object obj) {return obj instanceof GfmlLxr ? (GfmlLxr)obj : null;}
+ public static GfmlLxr cast_(Object obj) {try {return (GfmlLxr)obj;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, GfmlLxr.class, obj);}}
+}
+class GfmlLxr_null implements GfmlLxr {
+ public String Key() {return "gfml.nullLxr";}
+ public GfoEvMgr EvMgr() {if (evMgr == null) evMgr = GfoEvMgr.new_(this); return evMgr;} GfoEvMgr evMgr;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return GfoInvkAble_.Rv_unhandled;}
+ public GfmlTkn CmdTkn() {return GfmlTkn_.Null;} public void CmdTkn_set(GfmlTkn val) {}
+ public String[] Hooks() {return String_.Ary_empty;}
+ public GfmlTkn MakeTkn(CharStream stream, int hookLength) {return GfmlTkn_.Null;}
+ public void SubLxr_Add(GfmlLxr... lexer) {}
+ public GfmlLxr SubLxr() {return this;}
+}
+class GfmlLxr_singleton implements GfmlLxr, GfoEvObj {
+ public GfoEvMgr EvMgr() {if (evMgr == null) evMgr = GfoEvMgr.new_(this); return evMgr;} GfoEvMgr evMgr;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return GfoInvkAble_.Rv_unhandled;}
+ public String Key() {return key;} private String key;
+ public GfmlTkn CmdTkn() {return singletonTkn;} GfmlTkn singletonTkn;
+ public void CmdTkn_set(GfmlTkn val) {
+ String oldRaw = singletonTkn.Raw();
+ singletonTkn = val;
+ hooks = String_.Ary(val.Raw());
+ GfoEvMgr_.PubVals(this, GfmlLxr_.CmdTknChanged_evt, KeyVal_.new_("old", oldRaw), KeyVal_.new_("new", val.Raw()), KeyVal_.new_("lxr", this));
+ }
+ public String[] Hooks() {return hooks;} private String[] hooks;
+ public GfmlTkn MakeTkn(CharStream stream, int hookLength) {
+ stream.MoveNextBy(hookLength);
+ return singletonTkn;
+ }
+ public GfmlLxr SubLxr() {return subLxr;} GfmlLxr subLxr;
+ public void SubLxr_Add(GfmlLxr... lexer) {subLxr.SubLxr_Add(lexer);}
+ public static GfmlLxr_singleton new_(String key, String hook, GfmlTkn singletonTkn) {
+ GfmlLxr_singleton rv = new GfmlLxr_singleton();
+ rv.ctor_(key, hook, singletonTkn, GfmlLxr_.Null);
+ return rv;
+ } protected GfmlLxr_singleton() {}
+ @gplx.Internal protected void ctor_(String key, String hook, GfmlTkn singletonTkn, GfmlLxr subLxr) {
+ this.key = key;
+ this.hooks = String_.Ary(hook);
+ this.subLxr = subLxr;
+ this.singletonTkn = singletonTkn;
+ }
+}
+class GfmlLxr_group implements GfmlLxr {
+ public String Key() {return key;} private String key;
+ public GfoEvMgr EvMgr() {if (evMgr == null) evMgr = GfoEvMgr.new_(this); return evMgr;} GfoEvMgr evMgr;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return GfoInvkAble_.Rv_unhandled;}
+ public GfmlTkn CmdTkn() {return outputTkn;} public void CmdTkn_set(GfmlTkn val) {} GfmlTkn outputTkn;
+ public String[] Hooks() {return trie.Symbols();}
+ public GfmlTkn MakeTkn(CharStream stream, int hookLength) {
+ while (stream.AtMid()) {
+ if (!ignoreOutput)
+ sb.Add_mid(stream.Ary(), stream.Pos(), hookLength);
+ stream.MoveNextBy(hookLength);
+
+ String found = String_.cast_(trie.FindMatch(stream));
+ if (found == null) break;
+ hookLength = trie.LastMatchCount;
+ }
+ if (ignoreOutput) return GfmlTkn_.IgnoreOutput;
+ String raw = sb.XtoStrAndClear();
+ return outputTkn.MakeNew(raw, raw);
+ }
+ public GfmlLxr SubLxr() {throw Err_sublxr();}
+ public void SubLxr_Add(GfmlLxr... lexer) {throw Err_sublxr();}
+ Err Err_sublxr() {return Err_.not_implemented_msg_("group lxr does not have subLxrs").Add("key", key).Add("outputTkn", outputTkn.Raw());}
+ GfmlTrie trie = GfmlTrie.new_(); String_bldr sb = String_bldr_.new_(); boolean ignoreOutput;
+ public static GfmlLxr_group new_(String key, String[] hooks, GfmlTkn outputTkn, boolean ignoreOutput) {
+ GfmlLxr_group rv = new GfmlLxr_group();
+ rv.key = key;
+ for (String hook : hooks)
+ rv.trie.Add(hook, hook);
+ rv.outputTkn = outputTkn; rv.ignoreOutput = ignoreOutput;
+ return rv;
+ } GfmlLxr_group() {}
+}
+class GfmlLxr_general implements GfmlLxr, GfoInvkAble {
+ public GfoEvMgr EvMgr() {if (evMgr == null) evMgr = GfoEvMgr.new_(this); return evMgr;} GfoEvMgr evMgr;
+ public String Key() {return key;} private String key;
+ public GfmlTkn CmdTkn() {return txtTkn;} public void CmdTkn_set(GfmlTkn val) {} GfmlTkn txtTkn;
+ public String[] Hooks() {return symTrie.Symbols();}
+ public GfmlTkn MakeTkn(CharStream stream, int firstTknLength) {
+ GfmlTkn rv = null;
+ if (symLxr != null) { // symLxr has something; produce
+ rv = MakeTkn_symLxr(stream);
+ if (rv != GfmlTkn_.IgnoreOutput) return rv;
+ }
+ while (stream.AtMid()) { // keep moving til (a) symChar or (b) endOfStream
+ Object result = symTrie.FindMatch(stream);
+ symTknLen = symTrie.LastMatchCount;
+ if (result == null) { // no match; must be txtChar;
+ txtBfr.Add(stream);
+ stream.MoveNext();
+ }
+ else { // symChar
+ symLxr = (GfmlLxr)result; // set symLxr for next pass
+ if (txtBfr.Has()) // txtBfr has something: gen txtTkn
+ rv = txtBfr.MakeTkn(stream, txtTkn);
+ else { // txtBfr empty: gen symbol
+ rv = MakeTkn_symLxr(stream);
+ if (rv == GfmlTkn_.IgnoreOutput) continue;
+ }
+ return rv;
+ }
+ }
+ if (txtBfr.Has()) // endOfStream, but txtBfr has chars
+ return txtBfr.MakeTkn(stream, txtTkn);
+ return GfmlTkn_.EndOfStream;
+ }
+ public void SubLxr_Add(GfmlLxr... lxrs) {
+ for (GfmlLxr lxr : lxrs) {
+ for (String hook : lxr.Hooks())
+ symTrie.Add(hook, lxr);
+ GfoEvMgr_.SubSame(lxr, GfmlLxr_.CmdTknChanged_evt, this);
+ }
+ }
+ public GfmlLxr SubLxr() {return this;}
+ GfmlTkn MakeTkn_symLxr(CharStream stream) {
+ GfmlLxr lexer = symLxr; symLxr = null;
+ int length = symTknLen; symTknLen = 0;
+ return lexer.MakeTkn(stream, length);
+ }
+ GfmlLxr_general_txtBfr txtBfr = new GfmlLxr_general_txtBfr(); GfmlTrie symTrie = GfmlTrie.new_(); GfmlLxr symLxr; int symTknLen;
+ @gplx.Internal protected static GfmlLxr_general new_(String key, GfmlTkn txtTkn) {
+ GfmlLxr_general rv = new GfmlLxr_general();
+ rv.key = key; rv.txtTkn = txtTkn;
+ return rv;
+ } protected GfmlLxr_general() {}
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, GfmlLxr_.CmdTknChanged_evt)) {
+ symTrie.Del(m.ReadStr("old"));
+ symTrie.Add(m.ReadStr("new"), m.CastObj("lxr"));
+ }
+ else return GfoInvkAble_.Rv_unhandled;
+ return this;
+ }
+}
+class GfmlLxr_general_txtBfr {
+ public int Bgn = NullPos;
+ public int Len;
+ public boolean Has() {return Bgn != NullPos;}
+ public void Add(CharStream stream) {
+ if (Bgn == NullPos) Bgn = stream.Pos();
+ Len++;
+ } static final int NullPos = -1;
+ public GfmlTkn MakeTkn(CharStream stream, GfmlTkn textTkn) {
+ String raw = String_.new_charAry_(stream.Ary(), Bgn, Len);
+ Bgn = -1; Len = 0;
+ return textTkn.MakeNew(raw, raw);
+ }
+}
+class GfmlLxr_frame extends GfmlLxr_singleton { GfmlFrame frame; GfmlLxr endLxr, txtLxr;
+ public void BgnRaw_set(String val) {// needed for lxr pragma
+ GfmlBldrCmd_frameBgn bgnCmd = GfmlBldrCmd_frameBgn.new_(frame, txtLxr);
+ GfmlTkn bgnTkn = GfmlTkn_.singleton_(this.Key() + "_bgn", val, GfmlTkn_.NullVal, bgnCmd);
+ this.CmdTkn_set(bgnTkn);
+ }
+ public void EndRaw_set(String val) {// needed for lxr pragma
+ GfmlBldrCmd_frameEnd endCmd = GfmlBldrCmd_frameEnd.data_();
+ GfmlTkn endTkn = GfmlTkn_.singleton_(this.Key() + "_end", val, GfmlTkn_.NullVal, endCmd);
+ endLxr.CmdTkn_set(endTkn);
+ }
+ public static GfmlLxr new_(String key, GfmlFrame frame, String bgn, String end, GfmlBldrCmd txtCmd, GfmlBldrCmd endCmd) {
+ GfmlLxr_frame rv = new GfmlLxr_frame();
+ GfmlTkn txtTkn = frame.FrameType() == GfmlFrame_.Type_comment
+ ? GfmlTkn_.valConst_(key + "_txt", GfmlTkn_.NullVal, txtCmd)
+ : GfmlTkn_.cmd_(key + "_txt", txtCmd)
+ ;
+ GfmlLxr txtLxr = GfmlLxr_.general_(key + "_txt", txtTkn);
+
+ GfmlTkn bgnTkn = GfmlTkn_.singleton_(key + "_bgn", bgn, GfmlTkn_.NullVal, GfmlBldrCmd_frameBgn.new_(frame, txtLxr));
+ rv.ctor_(key, bgn, bgnTkn, txtLxr);
+
+ GfmlTkn endTkn = GfmlTkn_.singleton_(key + "_end", end, GfmlTkn_.NullVal, endCmd);
+ GfmlLxr endLxr = GfmlLxr_.solo_(key + "_end", endTkn);
+ rv.SubLxr_Add(endLxr);
+
+ rv.frame = frame;
+ rv.endLxr = endLxr;
+ rv.txtLxr = txtLxr;
+ return rv;
+ } GfmlLxr_frame() {}
+ public static GfmlLxr_frame as_(Object obj) {return obj instanceof GfmlLxr_frame ? (GfmlLxr_frame)obj : null;}
+ public static GfmlLxr_frame cast_(Object obj) {try {return (GfmlLxr_frame)obj;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, GfmlLxr_frame.class, obj);}}
+}
diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlObj.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlObj.java
new file mode 100644
index 000000000..d9a19a05e
--- /dev/null
+++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlObj.java
@@ -0,0 +1,29 @@
+/*
+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.gfml; import gplx.*;
+public interface GfmlObj {
+ int ObjType();
+}
+class GfmlObj_ {
+ public static final int
+ Type_tkn = 1
+ , Type_atr = 2
+ , Type_nde = 3
+ , Type_prg = 4
+ ;
+}
diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlObjList.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlObjList.java
new file mode 100644
index 000000000..f3ec78286
--- /dev/null
+++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlObjList.java
@@ -0,0 +1,25 @@
+/*
+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.gfml; import gplx.*;
+public class GfmlObjList extends ListAdp_base {
+ @gplx.New public GfmlObj FetchAt(int idx) {return (GfmlObj)FetchAt_base(idx);}
+ public void Add(GfmlObj tkn) {Add_base(tkn);}
+ public void AddAt(GfmlObj tkn, int idx) {super.AddAt_base(idx, tkn);}
+ public void Del(GfmlObj tkn) {Del_base(tkn);}
+ public static GfmlObjList new_() {return new GfmlObjList();} GfmlObjList() {}
+}
diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn.java
new file mode 100644
index 000000000..60a65feb8
--- /dev/null
+++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn.java
@@ -0,0 +1,45 @@
+/*
+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.gfml; import gplx.*;
+public interface GfmlTkn extends GfmlObj {
+ String TknType();
+ String Raw();
+ String Val();
+ GfmlTkn[] SubTkns();
+ GfmlBldrCmd Cmd_of_Tkn();
+ GfmlTkn MakeNew(String raw, String val);
+}
+class GfmlTknAry_ {
+ public static final GfmlTkn[] Empty = new GfmlTkn[0];
+ public static GfmlTkn[] ary_(GfmlTkn... ary) {return ary;}
+ @gplx.Internal protected static String XtoRaw(GfmlTkn[] ary) {
+ String_bldr sb = String_bldr_.new_();
+ for (GfmlTkn tkn : ary)
+ sb.Add(tkn.Raw());
+ return sb.XtoStr();
+ }
+ @gplx.Internal protected static String XtoVal(GfmlTkn[] ary) {return XtoVal(ary, 0, ary.length);}
+ static String XtoVal(GfmlTkn[] ary, int bgn, int end) {
+ String_bldr sb = String_bldr_.new_();
+ for (int i = bgn; i < end; i++) {
+ GfmlTkn tkn = ary[i];
+ sb.Add(tkn.Val());
+ }
+ return sb.XtoStr();
+ }
+}
diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn_.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn_.java
new file mode 100644
index 000000000..40ce14008
--- /dev/null
+++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn_.java
@@ -0,0 +1,65 @@
+/*
+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.gfml; import gplx.*;
+public class GfmlTkn_ {
+ @gplx.Internal protected static final String NullRaw = "", NullVal = ""; static final String Type_base = "gfml.baseTkn";
+ @gplx.Internal protected static final GfmlTkn
+ Null = new GfmlTkn_base().ctor_GfmlTkn_base("gfml.nullTkn", NullRaw, NullVal, GfmlBldrCmd_.Null)
+ , EndOfStream = GfmlTkn_.raw_("<>")
+ , IgnoreOutput = GfmlTkn_.raw_("<>");
+ public static GfmlTkn as_(Object obj) {return obj instanceof GfmlTkn ? (GfmlTkn)obj : null;}
+ @gplx.Internal protected static GfmlTkn new_(String raw, String val) {return new GfmlTkn_base().ctor_GfmlTkn_base(Type_base, raw, val, GfmlBldrCmd_.Null);}
+ public static GfmlTkn raw_(String raw) {return new GfmlTkn_base().ctor_GfmlTkn_base(Type_base, raw, raw, GfmlBldrCmd_.Null);}
+ @gplx.Internal protected static GfmlTkn val_(String val) {return new GfmlTkn_base().ctor_GfmlTkn_base(Type_base, NullRaw, val, GfmlBldrCmd_.Null);}
+ @gplx.Internal protected static GfmlTkn cmd_(String tknType, GfmlBldrCmd cmd) {return new GfmlTkn_base().ctor_GfmlTkn_base(tknType, NullRaw, NullVal, cmd);}
+ @gplx.Internal protected static GfmlTkn valConst_(String tknType, String val, GfmlBldrCmd cmd) {return new GfmlTkn_valConst().ctor_GfmlTkn_base(tknType, GfmlTkn_.NullRaw, val, cmd);}
+ @gplx.Internal protected static GfmlTkn singleton_(String tknType, String raw, String val, GfmlBldrCmd cmd) {return new GfmlTkn_singleton().ctor_GfmlTkn_base(tknType, raw, val, cmd);}
+ @gplx.Internal protected static GfmlTkn composite_(String tknType, GfmlTkn[] ary) {return new GfmlTkn_composite(tknType, ary);}
+ @gplx.Internal protected static GfmlTkn composite_list_(String tknType, GfmlObjList list) {
+ GfmlTkn[] ary = new GfmlTkn[list.Count()];
+ for (int i = 0; i < list.Count(); i++)
+ ary[i] = (GfmlTkn)list.FetchAt(i);
+ return GfmlTkn_.composite_(tknType, ary);
+ }
+}
+class GfmlTkn_base implements GfmlTkn {
+ public int ObjType() {return GfmlObj_.Type_tkn;}
+ public String TknType() {return tknType;} private String tknType;
+ public String Raw() {return raw;} private String raw;
+ public String Val() {return val;} private String val;
+ public GfmlBldrCmd Cmd_of_Tkn() {return cmd;} GfmlBldrCmd cmd;
+ public GfmlTkn[] SubTkns() {return GfmlTknAry_.Empty;}
+ @gplx.Virtual public GfmlTkn MakeNew(String rawNew, String valNew) {return new GfmlTkn_base().ctor_GfmlTkn_base(tknType, rawNew, valNew, cmd);}
+ @gplx.Internal protected GfmlTkn_base ctor_GfmlTkn_base(String tknType, String raw, String val, GfmlBldrCmd cmd) {this.tknType = tknType; this.raw = raw; this.val = val; this.cmd = cmd; return this;}
+}
+class GfmlTkn_valConst extends GfmlTkn_base {
+ @Override public GfmlTkn MakeNew(String rawNew, String valNew) {return new GfmlTkn_base().ctor_GfmlTkn_base(this.TknType(), rawNew, this.Val(), this.Cmd_of_Tkn());}
+}
+class GfmlTkn_singleton extends GfmlTkn_base {
+ @Override public GfmlTkn MakeNew(String rawNew, String valNew) {return this;}
+}
+class GfmlTkn_composite implements GfmlTkn {
+ public int ObjType() {return GfmlObj_.Type_tkn;}
+ public String TknType() {return tknType;} private String tknType;
+ public String Raw() {return GfmlTknAry_.XtoRaw(ary);}
+ public String Val() {return GfmlTknAry_.XtoVal(ary);}
+ public GfmlBldrCmd Cmd_of_Tkn() {return GfmlBldrCmd_.Null;}
+ public GfmlTkn[] SubTkns() {return ary;} GfmlTkn[] ary;
+ public GfmlTkn MakeNew(String rawNew, String valNew) {throw Err_.not_implemented_msg_(".MakeNew cannot be invoked on GfmlTkn_composite (raw is available, but not val)").Add("tknType", tknType).Add("rawNew", rawNew).Add("valNew", valNew);}
+ @gplx.Internal protected GfmlTkn_composite(String tknType, GfmlTkn[] ary) {this.tknType = tknType; this.ary = ary;}
+}
diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlTrie.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlTrie.java
new file mode 100644
index 000000000..d6e40d7f8
--- /dev/null
+++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlTrie.java
@@ -0,0 +1,114 @@
+/*
+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.gfml; import gplx.*;
+import gplx.texts.*; /*CharStream*/
+public class GfmlTrie {
+ public String[] Symbols() {
+ String[] rv = new String[symbols.Count()];
+ for (int i = 0; i < rv.length; i++)
+ rv[i] = String_.cast_(symbols.FetchAt(i));
+ return rv;
+ } OrderedHash symbols = OrderedHash_.new_();
+ public int LastMatchCount; // PERF: prop is faster than method
+ public Object FindMatch(CharStream stream) {
+ Object result = null; int moveCount = 0; LastMatchCount = 0;
+ IntObjHash_base link = rootLink;
+ while (stream.AtMid()) {
+ Object found = link.Fetch(stream.Cur());
+ if (found == null) break; // found is null; can happen for false matches; ex: .
+*/
+package gplx.gfui; import gplx.*;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.io.File;
+import java.io.IOException;
+import javax.imageio.ImageIO;
+public class ImageAdp_base implements ImageAdp, RlsAble {
+ @gplx.Internal protected ImageAdp_base(Image img) {this.under = img;}
+ public Gfui_kit Kit() {return kit;} public void Kit_(Gfui_kit v) {this.kit = v;} Gfui_kit kit;
+ public SizeAdp Size() {
+ if (this == ImageAdp_.Null) return SizeAdp_.Null;
+ if (size == null) {
+ size = SizeAdp_.new_(this.Width(), this.Height());
+ }
+ return size;
+ } SizeAdp size = null;
+ public int Width() {return under.getWidth(null);}
+ public int Height() {return under.getHeight(null);}
+ public Io_url Url() {return url;} public ImageAdp Url_(Io_url v) {url = v; return this;} Io_url url = Io_url_.Null;
+ public Object Under() {return under;} Image under;
+ public boolean Disposed() {return disposed;} private boolean disposed = false;
+
+ public void Rls() {disposed = true; under.flush();}
+ public void SaveAsBmp(Io_url url) {SaveAs(url, "bmp");}
+ public void SaveAsPng(Io_url url) {SaveAs(url, "png");}
+ void SaveAs(Io_url url, String fmtStr) {
+ Io_mgr._.CreateDirIfAbsent(url.OwnerDir());
+ File fil = new File(url.Xto_api());
+// String[] formatNames = ImageIO.getWriterFormatNames();
+// for (String s : formatNames)
+// Tfds.Write(s);
+ boolean success = false;
+ try {success = ImageIO.write((BufferedImage)under, fmtStr, fil);}
+ catch (IOException e) {}
+ if (!success) throw Err_.new_key_("gplx.gfui.imgs.SaveImageFailed", "save image failed").Add("srcUrl", url.Xto_api()).Add("trgFil", fil).Add("fmt", fmtStr);
+ //#@endif
+ }
+ public ImageAdp Extract_image(RectAdp src_rect, SizeAdp trg_size) {return Extract_image(src_rect.X(), src_rect.Y(), src_rect.Width(), src_rect.Height(), trg_size.Width(), trg_size.Height());}
+ public ImageAdp Extract_image(int src_x, int src_y, int src_w, int src_h, int trg_w, int trg_h) {
+ if (this == ImageAdp_.Null) return ImageAdp_.Null; // TODO: create ImageAdpNull class (along with ImageAdp interface)
+ if (disposed) return ImageAdp_.new_(1, 1);
+ ImageAdp rv = ImageAdp_.new_(trg_w, trg_h);
+ GfxAdp gfx = GfxAdp_.image_(rv);
+ gfx.DrawImage(this, 0, 0, trg_w, trg_h, src_x, src_y, src_w, src_h);
+ gfx.Rls();
+ return rv;
+ }
+ public ImageAdp Resize(int width, int height) {return Extract_image(0, 0, this.Width(), this.Height(), width, height);}
+}
diff --git a/150_gfui/src_600_adp/gplx/gfui/ImageAdp_null.java b/150_gfui/src_600_adp/gplx/gfui/ImageAdp_null.java
new file mode 100644
index 000000000..0a93effd5
--- /dev/null
+++ b/150_gfui/src_600_adp/gplx/gfui/ImageAdp_null.java
@@ -0,0 +1,34 @@
+/*
+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.gfui; import gplx.*;
+public class ImageAdp_null implements ImageAdp {
+ public Gfui_kit Kit() {return Gfui_kit_.Mem();}
+ public SizeAdp Size() {return SizeAdp_.Zero;}
+ public int Width() {return 0;}
+ public int Height() {return 0;}
+ public Io_url Url() {return Io_url_.Null;} public ImageAdp Url_(Io_url v) {return this;}
+ public Object Under() {return null;}
+ public boolean Disposed() {return disposed;} private boolean disposed = false;
+ public void Rls() {disposed = true;}
+ public void SaveAsBmp(Io_url url) {}
+ public void SaveAsPng(Io_url url) {}
+ public ImageAdp Extract_image(RectAdp src_rect, SizeAdp trg_size) {return Extract_image(src_rect.X(), src_rect.Y(), src_rect.Width(), src_rect.Height(), trg_size.Width(), trg_size.Height());}
+ public ImageAdp Extract_image(int src_x, int src_y, int src_w, int src_h, int trg_w, int trg_h) {return this;}
+ public ImageAdp Resize(int width, int height) {return this;}
+ public static final ImageAdp_null _ = new ImageAdp_null(); ImageAdp_null() {}
+}
diff --git a/150_gfui/src_600_adp/gplx/gfui/ScreenAdp.java b/150_gfui/src_600_adp/gplx/gfui/ScreenAdp.java
new file mode 100644
index 000000000..3cdfdc00e
--- /dev/null
+++ b/150_gfui/src_600_adp/gplx/gfui/ScreenAdp.java
@@ -0,0 +1,32 @@
+/*
+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.gfui; import gplx.*;
+public class ScreenAdp {
+ public int Index() {return index;} int index;
+ public RectAdp Rect() {return bounds;} RectAdp bounds = RectAdp_.Zero;
+ public SizeAdp Size() {return bounds.Size();}
+ public int Width() {return bounds.Width();}
+ public int Height() {return bounds.Height();}
+ public PointAdp Pos() {return bounds.Pos();}
+ public int X() {return bounds.X();}
+ public int Y() {return bounds.Y();}
+
+ @gplx.Internal protected ScreenAdp(int index, RectAdp bounds) {
+ this.index = index; this.bounds = bounds;
+ }
+}
diff --git a/150_gfui/src_600_adp/gplx/gfui/ScreenAdp_.java b/150_gfui/src_600_adp/gplx/gfui/ScreenAdp_.java
new file mode 100644
index 000000000..ac22ed9a7
--- /dev/null
+++ b/150_gfui/src_600_adp/gplx/gfui/ScreenAdp_.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.gfui; import gplx.*;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
+public class ScreenAdp_ {
+ public static final ScreenAdp Primary = screen_(0);
+ public static ScreenAdp as_(Object obj) {return obj instanceof ScreenAdp ? (ScreenAdp)obj : null;}
+ public static ScreenAdp cast_(Object obj) {try {return (ScreenAdp)obj;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, ScreenAdp.class, obj);}}
+ public static ScreenAdp parse_(String raw) { // ex: {screen{1}
+ try {
+ raw = String_.Replace(raw, "{screen{", "");
+ raw = String_.Replace(raw, "}", "");
+ return ScreenAdp_.screen_(Int_.parse_(raw));
+ } catch(Exception exc) {throw Err_.parse_type_exc_(exc, ScreenAdp.class, raw);}
+ }
+ public static ScreenAdp from_point_(PointAdp pos) {// NOTE: not using FromPoint b/c of plat_wce
+ if (ScreenAdp_.Count() == 1) return Primary;
+ ScreenAdp screen0 = screen_(0), screen1 = screen_(1);
+ return pos.X() < screen1.X() ? screen0 : screen1;
+ }
+ public static ScreenAdp opposite_(int idx) {
+ if (ScreenAdp_.Count() == 1) return Primary;
+ int opposite = idx == 0 ? 1 : 0; // will ignore all screens with index > 1
+ return screen_(opposite);
+ }
+ public static int Count() {
+ return GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices().length;
+// return 1;//Screen.AllScreens.Length;
+ }
+ public static ScreenAdp screen_(int index) {
+ if (index >= ScreenAdp_.Count()) throw Err_.missing_idx_(index, ScreenAdp_.Count());
+ GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice[] devs = env.getScreenDevices();
+ GraphicsConfiguration conf = devs[index].getDefaultConfiguration();
+ ScreenAdp sd = new ScreenAdp(index, GxwCore_lang.XtoRectAdp(conf.getBounds()));
+ return sd;
+ }
+//#@endif
+ static ScreenAdp new_(int index, RectAdp rect) {return new ScreenAdp(index, rect);}
+}
diff --git a/150_gfui/src_600_adp/gplx/gfui/TimerAdp.java b/150_gfui/src_600_adp/gplx/gfui/TimerAdp.java
new file mode 100644
index 000000000..6fc7e9bdd
--- /dev/null
+++ b/150_gfui/src_600_adp/gplx/gfui/TimerAdp.java
@@ -0,0 +1,53 @@
+/*
+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.gfui; import gplx.*;
+import javax.swing.Timer;
+import java.awt.event.ActionListener;
+public class TimerAdp implements RlsAble {
+ public TimerAdp Interval_(int interval) {
+ underTimer.setInitialDelay(interval);
+ underTimer.setDelay(interval);
+ return this;
+ }
+ public TimerAdp Enabled_on() {return Enabled_(true);} public TimerAdp Enabled_off() {return Enabled_(false);}
+ public TimerAdp Enabled_(boolean val) {
+ if (!Env_.Mode_testing()) {
+ if (val) underTimer.start();
+ else underTimer.stop();
+ }
+ return this;
+ }
+ public void Rls() {underTimer.stop();}
+
+ Timer underTimer;
+ public static TimerAdp new_(GfoInvkAble invk, String msgKey, int interval, boolean enabled) {
+ TimerAdp rv = new TimerAdp();
+ rv.underTimer = new Timer(interval, new TimerActionListener(invk, msgKey));
+ rv.Interval_(interval).Enabled_(enabled);
+ return rv;
+ }
+ }
+class TimerActionListener implements ActionListener {
+ public void actionPerformed(java.awt.event.ActionEvent arg0) {
+ GfoInvkAble_.InvkCmd(invk, key);
+ }
+ GfoInvkAble invk; String key;
+ public TimerActionListener(GfoInvkAble invk, String key) {
+ this.invk = invk; this.key = key;
+ }
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/GfoFactory_gfui.java b/150_gfui/src_700_env/gplx/gfui/GfoFactory_gfui.java
new file mode 100644
index 000000000..f543e2215
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/GfoFactory_gfui.java
@@ -0,0 +1,39 @@
+/*
+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.gfui; import gplx.*;
+public class GfoFactory_gfui {
+ public static void Btn_MinWin(GfuiElem owner, GfoMsg appWinMsg) {
+ GfuiBtn_.msg_("minWin", owner, GfoMsg_.chain_(appWinMsg, GfuiWin.Invk_Minimize)).Text_("_").TipText_("minmize window").Width_(20);
+ }
+ public static void Btn_MinWin2(GfuiElem owner) {
+ GfuiBtn_.msg_("minWin", owner, GfoMsg_.root_(".", GfuiElemBase.Invk_OwnerWin_cmd, GfuiWin.Invk_Minimize)).Text_("_").TipText_("minmize window").Width_(20);
+ }
+ public static void Btn_MoveBox(GfuiElem owner, GfuiElem target) {
+ GfuiElem rv = GfuiBtn_.new_("moveBox").Owner_(owner).Text_("*").TipText_("move box").Width_(20);
+ GfuiMoveElemBnd bnd = GfuiMoveElemBnd.new_();
+ bnd.TargetElem_set(target);
+ rv.Inject_(bnd);
+ }
+ public static GfuiBtn Btn_QuitWin3(GfuiElem owner) {
+ return (GfuiBtn)GfuiBtn_.msg_("quitWin", owner, GfoMsg_.root_(".", GfuiElemBase.Invk_OwnerWin_cmd, GfuiWin.Invk_Quit)).Text_("X").TipText_("quit win").Width_(20);
+ }
+ public static void Btn_QuitWin2(GfuiElem owner, GfoMsg quitMsg) {
+ GfuiBtn_.msg_("quitWin", owner, quitMsg).Text_("X").TipText_("quit win").Width_(20);
+ }
+ public static final GfoFactory_gfui _ = new GfoFactory_gfui(); GfoFactory_gfui() {}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/GfsLibIni_gfui.java b/150_gfui/src_700_env/gplx/gfui/GfsLibIni_gfui.java
new file mode 100644
index 000000000..7d666b3e5
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/GfsLibIni_gfui.java
@@ -0,0 +1,24 @@
+/*
+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.gfui; import gplx.*;
+public class GfsLibIni_gfui implements GfsLibIni {
+ public void Ini(GfsCore core) {
+ core.AddCmd(IptCfgRegy._, "IptBndMgr_");
+ }
+ public static final GfsLibIni_gfui _ = new GfsLibIni_gfui(); GfsLibIni_gfui() {}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/GfuiEnv_.java b/150_gfui/src_700_env/gplx/gfui/GfuiEnv_.java
new file mode 100644
index 000000000..478091eba
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/GfuiEnv_.java
@@ -0,0 +1,109 @@
+/*
+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.gfui; import gplx.*;
+import gplx.gfml.*;
+import gplx.threads.*;
+import java.awt.AWTKeyStroke;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.KeyboardFocusManager;
+import java.awt.event.KeyEvent;
+import java.awt.image.BufferedImage;
+import java.util.HashSet;
+import java.util.Set;
+import javax.swing.JOptionPane;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+public class GfuiEnv_ {
+ static FontAdp system_font;
+ public static void Exit() {if (!Env_.Mode_testing()) System.exit(0);}
+ public static void Init(String[] args, String appNameAndExt, Class> type) {Init(args, appNameAndExt, type, true);}
+ public static void Init(String[] args, String appNameAndExt, Class> type, boolean swingHack) {
+ Env_.Init(args, appNameAndExt, type);
+ if (swingHack) { // TODO: move to kit dependent functionality; WHEN: swing kit
+ if (Op_sys.Cur().Tid_is_wnt()) {
+ try {UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");}
+ catch (ClassNotFoundException e) {e.printStackTrace();}
+ catch (InstantiationException e) {e.printStackTrace();}
+ catch (IllegalAccessException e) {e.printStackTrace();}
+ catch (UnsupportedLookAndFeelException e) {e.printStackTrace();}
+ }
+ Set fwdSet = new HashSet(); fwdSet.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
+ Set bwdSet = new HashSet(); bwdSet.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, java.awt.event.InputEvent.SHIFT_DOWN_MASK ));
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, fwdSet);
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, bwdSet);
+ }
+ if (!Op_sys.Cur().Tid_is_drd())
+ GxwElemFactory_.winForms_();
+
+ // reg interruptLnr
+ if (swingHack) { // TODO: move to kit dependent functionality; WHEN: swing kit
+ UsrDlg_._.Reg(UsrMsgWkr_.Type_Warn, GfoConsoleWin._);
+ UsrDlg_._.Reg(UsrMsgWkr_.Type_Stop, GfuiInterruptLnr.new_());
+ }
+ IptBndMgr_win = IptCfg_.new_("gplx.gfui.GfuiWin");
+
+ // alias default dirs
+ Io_mgr._.AliasDir_sysEngine("app:\\", Env_.AppUrl().OwnerDir().Raw());
+
+ GfsCore._.MsgParser_(GfoMsgParser_gfml._);
+ GfsCore._.AddLib(GfsLibIni_core._);
+ GfsCore._.AddLib(GfsLibIni_gfui._);
+ Io_url iniFile = Env_.AppUrl().GenSubFil(".gfs");
+ if (Io_mgr._.ExistsFil(iniFile))
+ GfsCore._.ExecFile(iniFile);
+ }
+ public static void Init_swt(String[] args, Class> type) {
+ Env_.Init_swt(args, type);
+ if (!Op_sys.Cur().Tid_is_drd()) GxwElemFactory_.winForms_();
+ GfsCore._.MsgParser_(GfoMsgParser_gfml._);
+ }
+ public static void Gfs_init() {GfsCore._.MsgParser_(GfoMsgParser_gfml._);}
+ public static IptCfg IptBndMgr_win;
+ public static void DoEvents() {;}
+ public static void ShowMsg(String message) {javax.swing.JOptionPane.showMessageDialog(null, message, "", javax.swing.JOptionPane.INFORMATION_MESSAGE, null);}
+ public static void BringToFront(ProcessAdp process) {}
+ public static void DoEvents(int milliseconds) {
+ ThreadAdp_.Sleep(milliseconds);
+ }
+ public static void Run(GfuiWin form) {javax.swing.SwingUtilities.invokeLater(new GfuiFormRunner(form));}
+ public static FontAdp System_font() {
+ try {
+ if (system_font == null) {
+ Font label_font = (Font)UIManager.get("Label.font");
+ system_font = FontAdp.new_(label_font.getFamily(), label_font.getSize(), FontStyleAdp_.Plain);
+ }
+ return system_font;
+ } catch (Exception e) {return FontAdp.new_("Arial", 8, FontStyleAdp_.Plain);}
+ }
+ public static final String Quit_commit_evt = "quit_commit_evt", Quit_notify_evt = "quit_notify_evt";
+ public static final String Err_GfuiException = "gplx.dbs.GfuiException"; // TODO: used in JAVA. move
+}
+class GfuiInterruptLnr implements UsrMsgWkr {
+ public void ExecUsrMsg(int type, UsrMsg umsg) {GfuiEnv_.ShowMsg(umsg.XtoStr());}
+ public static GfuiInterruptLnr new_() {return new GfuiInterruptLnr();} GfuiInterruptLnr() {}
+}
+class GfuiFormRunner implements Runnable {
+ public GfuiFormRunner(GfuiWin form) {this.form = form;} GfuiWin form;
+ public void run() {
+ form.Show();
+ }
+}
+//#}
\ No newline at end of file
diff --git a/150_gfui/src_700_env/gplx/gfui/GfuiInvkCmd.java b/150_gfui/src_700_env/gplx/gfui/GfuiInvkCmd.java
new file mode 100644
index 000000000..e83dbf103
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/GfuiInvkCmd.java
@@ -0,0 +1,23 @@
+/*
+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.gfui; import gplx.*;
+public interface GfuiInvkCmd extends GfoInvkAble, RlsAble {
+}
+class GfuiInvkCmd_ {
+ public static final String Invk_sync = "Sync";
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_clipboard.java b/150_gfui/src_700_env/gplx/gfui/Gfui_clipboard.java
new file mode 100644
index 000000000..2362b71bd
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_clipboard.java
@@ -0,0 +1,27 @@
+/*
+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.gfui; import gplx.*;
+public interface Gfui_clipboard extends GfoInvkAble, RlsAble {
+ void Copy(String s);
+}
+class Gfui_clipboard_null implements Gfui_clipboard {
+ public void Copy(String s) {}
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;}
+ public void Rls() {}
+ public static final Gfui_clipboard_null Null = new Gfui_clipboard_null(); Gfui_clipboard_null() {}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_clipboard_.java b/150_gfui/src_700_env/gplx/gfui/Gfui_clipboard_.java
new file mode 100644
index 000000000..ccdd78340
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_clipboard_.java
@@ -0,0 +1,21 @@
+/*
+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.gfui; import gplx.*;
+public class Gfui_clipboard_ {
+ public static final String Invk_copy = "copy", Invk_select_all = "select_all";
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_dlg_file.java b/150_gfui/src_700_env/gplx/gfui/Gfui_dlg_file.java
new file mode 100644
index 000000000..bdef62e86
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_dlg_file.java
@@ -0,0 +1,33 @@
+/*
+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.gfui; import gplx.*;
+public interface Gfui_dlg_file {
+ Gfui_dlg_file Init_msg_(String v);
+ Gfui_dlg_file Init_file_(String v);
+ Gfui_dlg_file Init_dir_(Io_url v);
+ Gfui_dlg_file Init_exts_(String... v);
+ String Ask();
+}
+class Gfui_dlg_file_null implements Gfui_dlg_file {
+ public Gfui_dlg_file Init_msg_(String v) {return this;}
+ public Gfui_dlg_file Init_file_(String v) {return this;}
+ public Gfui_dlg_file Init_dir_(Io_url v) {return this;}
+ public Gfui_dlg_file Init_exts_(String... v) {return this;}
+ public String Ask() {return "";}
+ public static final Gfui_dlg_file_null _ = new Gfui_dlg_file_null(); Gfui_dlg_file_null() {}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_dlg_msg.java b/150_gfui/src_700_env/gplx/gfui/Gfui_dlg_msg.java
new file mode 100644
index 000000000..9eed1b308
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_dlg_msg.java
@@ -0,0 +1,33 @@
+/*
+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.gfui; import gplx.*;
+public interface Gfui_dlg_msg {
+ Gfui_dlg_msg Init_msg_(String v);
+ Gfui_dlg_msg Init_ico_(int v);
+ Gfui_dlg_msg Init_btns_(int... ary);
+ int Ask();
+ boolean Ask(int expd);
+}
+class Gfui_dlg_msg_null implements Gfui_dlg_msg {
+ public Gfui_dlg_msg Init_msg_(String v) {return this;}
+ public Gfui_dlg_msg Init_ico_(int v) {return this;}
+ public Gfui_dlg_msg Init_btns_(int... ary) {return this;}
+ public boolean Ask(int expd) {return false;}
+ public int Ask() {return Int_.MinValue;}
+ public static final Gfui_dlg_msg_null _ = new Gfui_dlg_msg_null(); Gfui_dlg_msg_null() {}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_dlg_msg_.java b/150_gfui/src_700_env/gplx/gfui/Gfui_dlg_msg_.java
new file mode 100644
index 000000000..ab112941e
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_dlg_msg_.java
@@ -0,0 +1,22 @@
+/*
+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.gfui; import gplx.*;
+public class Gfui_dlg_msg_ {
+ public static final int Ico_error = 0, Ico_information = 1, Ico_question = 2, Ico_warning = 3, Ico_working = 4;
+ public static final int Btn_ok = 0, Btn_cancel = 1, Btn_yes = 2, Btn_no = 3, Retry = 4, Btn_abort = 5, Btn_ignore = 6;
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_kit.java b/150_gfui/src_700_env/gplx/gfui/Gfui_kit.java
new file mode 100644
index 000000000..cbaf67d19
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_kit.java
@@ -0,0 +1,49 @@
+/*
+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.gfui; import gplx.*;
+public interface Gfui_kit extends GfoInvkAble {
+ byte Tid();
+ String Key();
+ void Cfg_set(String type, String key, Object val);
+ boolean Kit_init_done();
+ void Kit_init(Gfo_usr_dlg gui_wtr);
+ void Kit_run();
+ void Kit_term();
+ void Kit_term_cbk_(GfoInvkAbleCmd cmd);
+ Gfui_clipboard Clipboard();
+ void Ask_ok(String grp_key, String msg_key, String fmt, Object... args);
+ boolean Ask_yes_no(String grp_key, String msg_key, String fmt, Object... args);
+ boolean Ask_ok_cancel(String grp_key, String msg_key, String fmt, Object... args);
+ int Ask_yes_no_cancel(String grp_key, String msg_key, String fmt, Object... args);
+ GfuiInvkCmd New_cmd_sync(GfoInvkAble invk);
+ GfuiInvkCmd New_cmd_async(GfoInvkAble invk);
+ GfuiWin New_win_app(String key, KeyVal... args);
+ GfuiWin New_win_utl(String key, GfuiWin owner, KeyVal... args);
+ Gfui_html New_html(String key, GfuiElem owner, KeyVal... args);
+ Gfui_tab_mgr New_tab_mgr(String key, GfuiElem owner, KeyVal... args);
+ GfuiTextBox New_text_box(String key, GfuiElem owner, KeyVal... args);
+ GfuiBtn New_btn(String key, GfuiElem owner, KeyVal... args);
+ Gfui_dlg_file New_dlg_file(byte type, String msg);
+ Gfui_dlg_msg New_dlg_msg(String msg);
+ ImageAdp New_img_load(Io_url path);
+ Object New_color(int a, int r, int g, int b);
+ Gfui_mnu_grp New_mnu_popup(String key, GfuiElem owner);
+ Gfui_mnu_grp New_mnu_bar(String key, GfuiWin owner);
+ void Set_mnu_popup(GfuiElem owner, Gfui_mnu_grp grp);
+ float Calc_font_height(GfuiElem elem, String s);
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_kit_.java b/150_gfui/src_700_env/gplx/gfui/Gfui_kit_.java
new file mode 100644
index 000000000..6cd3bb63d
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_kit_.java
@@ -0,0 +1,32 @@
+/*
+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.gfui; import gplx.*;
+public class Gfui_kit_ {
+ public static final byte Mem_tid = 0, Swing_tid = 1, Swt_tid = 2, Android_tid = 3;
+ public static Gfui_kit Mem() {return mem_kit;} private static final Gfui_kit mem_kit = Mem_kit._;
+ public static Gfui_kit Swt() {if (swt_kit == null) swt_kit = Swt_kit._; return swt_kit;} private static Gfui_kit swt_kit; // NOTE: late-binding else swing apps will fail (since swt jar is not deployed)
+ public static Gfui_kit Swing() {if (swing_kit == null) swing_kit = Swing_kit._; return swing_kit;} private static Gfui_kit swing_kit;
+ public static Gfui_kit Get_by_key(String key) {
+ if (String_.Eq(key, Mem().Key())) return Mem();
+ else if (String_.Eq(key, Swt().Key())) return Swt();
+ else if (String_.Eq(key, Swing().Key())) return Swing();
+ else throw Err_.unhandled(key);
+ }
+ public static final String Cfg_HtmlBox = "HtmlBox";
+ public static final byte File_dlg_type_open = 0, File_dlg_type_save = 1;
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_kit_base.java b/150_gfui/src_700_env/gplx/gfui/Gfui_kit_base.java
new file mode 100644
index 000000000..46454b22d
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_kit_base.java
@@ -0,0 +1,104 @@
+/*
+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.gfui; import gplx.*;
+public abstract class Gfui_kit_base implements Gfui_kit {
+ private KeyValHash ctor_args = KeyValHash.new_();
+ public abstract byte Tid();
+ public abstract String Key();
+ public abstract GxwElemFactory_base Factory();
+ public GfuiWin Main_win() {return main_win;} public Gfui_kit Main_win_(GfuiWin v) {main_win = v; return this;} private GfuiWin main_win;
+ public Gfui_clipboard Clipboard() {return Gfui_clipboard_null.Null;}
+ public GfoInvkAbleCmd Kit_term_cbk() {return kit_term_cbk;} public void Kit_term_cbk_(GfoInvkAbleCmd v) {kit_term_cbk = v;} private GfoInvkAbleCmd kit_term_cbk;
+ public void Cfg_set(String type, String key, Object val) {}
+ public boolean Kit_init_done() {return true;}
+ public void Kit_init(Gfo_usr_dlg gui_wtr) {}
+ @gplx.Virtual public void Kit_run() {}
+ @gplx.Virtual public void Kit_term() {kit_term_cbk.Invk();}
+ @gplx.Virtual public void Ask_ok(String grp_key, String msg_key, String fmt, Object... args) {}
+ public boolean Ask_yes_no(String grp_key, String msg_key, String fmt, Object... args) {return false;}
+ public int Ask_yes_no_cancel(String grp_key, String msg_key, String fmt, Object... args) {return Gfui_dlg_msg_.Btn_cancel;}
+ public boolean Ask_ok_cancel(String grp_key, String msg_key, String fmt, Object... args) {return false;}
+ public void Btn_img_(GfuiBtn btn, IconAdp v) {}
+ public GfuiInvkCmd New_cmd_sync(GfoInvkAble invk) {return new Gfui_kit_cmd_sync(invk);}
+ public GfuiInvkCmd New_cmd_async(GfoInvkAble invk) {return new Gfui_kit_cmd_async(invk);}
+ public GfuiWin New_win_app(String key, KeyVal... args) {
+ GfuiWin rv = GfuiWin_.kit_(this, key, this.Factory().win_app_(), ctor_args);
+ main_win = rv;
+ return rv;
+ }
+ public GfuiWin New_win_utl(String key, GfuiWin owner, KeyVal... args) {return GfuiWin_.kit_(this, key, this.Factory().win_tool_(ctor_args), ctor_args);}
+ @gplx.Virtual public Gfui_html New_html(String key, GfuiElem owner, KeyVal... args) {
+ Gfui_html rv = Gfui_html.kit_(this, key, this.New_html_impl(), ctor_args);
+ owner.SubElems().Add(rv);
+ return rv;
+ }
+ public Gfui_tab_mgr New_tab_mgr(String key, GfuiElem owner, KeyVal... args) {
+ Gfui_tab_mgr rv = Gfui_tab_mgr.kit_(this, key, this.New_tab_mgr_impl(), ctor_args);
+ owner.SubElems().Add(rv);
+ return rv;
+ }
+ public Gfui_tab_itm New_tab_itm(String key, Gfui_tab_mgr owner, KeyVal... args) {
+ Gfui_tab_itm rv = Gfui_tab_itm.kit_(this, key, this.New_tab_itm_impl(), ctor_args);
+ owner.SubElems().Add(rv);
+ return rv;
+ }
+ public GfuiTextBox New_text_box(String key, GfuiElem owner, KeyVal... args) {
+ GfuiTextBox rv = GfuiTextBox_.kit_(this, key, this.Factory().text_fld_(), ctor_args);
+ owner.SubElems().Add(rv);
+ return rv;
+ }
+ @gplx.Virtual public GfuiBtn New_btn(String key, GfuiElem owner, KeyVal... args) {
+ GfuiBtn rv = GfuiBtn_.kit_(this, key, New_btn_impl(), ctor_args);
+ owner.SubElems().Add(rv);
+ return rv;
+ }
+ @gplx.Virtual public GfuiStatusBox New_status_box(String key, GfuiElem owner, KeyVal... args) {
+ GfuiStatusBox rv = GfuiStatusBox_.kit_(this, key, this.Factory().text_memo_());
+ owner.SubElems().Add(rv);
+ return rv;
+ }
+ public void Set_mnu_popup(GfuiElem owner, Gfui_mnu_grp grp) {}
+ protected abstract Gxw_html New_html_impl();
+ protected abstract Gxw_tab_mgr New_tab_mgr_impl();
+ protected abstract Gxw_tab_itm New_tab_itm_impl();
+ protected abstract GxwElem New_btn_impl();
+ @gplx.Virtual public Gfui_dlg_file New_dlg_file(byte type, String msg) {return Gfui_dlg_file_null._;}
+ @gplx.Virtual public Gfui_dlg_msg New_dlg_msg(String msg) {return Gfui_dlg_msg_null._;}
+ @gplx.Virtual public Gfui_mnu_grp New_mnu_popup(String key, GfuiElem owner) {return Gfui_mnu_grp_null.Null;}
+ @gplx.Virtual public Gfui_mnu_grp New_mnu_bar(String key, GfuiWin owner) {return Gfui_mnu_grp_null.Null;}
+ public abstract ImageAdp New_img_load(Io_url url);
+ public Object New_color(int a, int r, int g, int b) {return null;}
+ public float Calc_font_height(GfuiElem elem, String s) {return 13;}
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ return this;
+ }
+}
+class Gfui_kit_cmd_sync implements GfuiInvkCmd {
+ public Gfui_kit_cmd_sync(GfoInvkAble target) {this.target = target;} private GfoInvkAble target;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ return target.Invk(ctx, ikey, k, m);
+ }
+ public void Rls() {target = null;}
+}
+class Gfui_kit_cmd_async implements GfuiInvkCmd {
+ public Gfui_kit_cmd_async(GfoInvkAble target) {this.target = target;} private GfoInvkAble target;
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ return target.Invk(ctx, ikey, k, m);
+ }
+ public void Rls() {target = null;}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_mnu_grp.java b/150_gfui/src_700_env/gplx/gfui/Gfui_mnu_grp.java
new file mode 100644
index 000000000..adacabb5e
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_mnu_grp.java
@@ -0,0 +1,46 @@
+/*
+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.gfui; import gplx.*;
+public interface Gfui_mnu_grp extends Gfui_mnu_itm {
+ String Root_key();
+ void Itms_clear();
+ Gfui_mnu_itm Itms_add_btn_cmd (String txt, ImageAdp img, GfoInvkAble invk, String invk_cmd);
+ Gfui_mnu_itm Itms_add_btn_msg (String txt, ImageAdp img, GfoInvkAble invk, GfoInvkRootWkr root_wkr, GfoMsg msg);
+ Gfui_mnu_itm Itms_add_chk_msg (String txt, ImageAdp img, GfoInvkAble invk, GfoInvkRootWkr root_wkr, GfoMsg msg_n, GfoMsg msg_y);
+ Gfui_mnu_itm Itms_add_rdo_msg (String txt, ImageAdp img, GfoInvkAble invk, GfoInvkRootWkr root_wkr, GfoMsg msg);
+ Gfui_mnu_grp Itms_add_grp (String txt, ImageAdp img);
+ Gfui_mnu_itm Itms_add_separator();
+}
+class Gfui_mnu_grp_null implements Gfui_mnu_grp {
+ public String Uid() {return "";}
+ public int Tid() {return Gfui_mnu_itm_.Tid_grp;}
+ public boolean Enabled() {return true;} public void Enabled_(boolean v) {}
+ public String Text() {return null;} public void Text_(String v) {}
+ public ImageAdp Img() {return null;} public void Img_(ImageAdp v) {}
+ public boolean Selected() {return true;} public void Selected_(boolean v) {}
+ public String Root_key() {return "null";}
+ public Object Under() {return null;}
+ public void Itms_clear() {}
+ public Gfui_mnu_itm Itms_add_btn_cmd (String txt, ImageAdp img, GfoInvkAble invk, String invk_cmd) {return Gfui_mnu_itm_null.Null;}
+ public Gfui_mnu_itm Itms_add_btn_msg (String txt, ImageAdp img, GfoInvkAble invk, GfoInvkRootWkr root_wkr, GfoMsg invk_msg) {return Gfui_mnu_itm_null.Null;}
+ public Gfui_mnu_itm Itms_add_chk_msg (String txt, ImageAdp img, GfoInvkAble invk, GfoInvkRootWkr root_wkr, GfoMsg msg_n, GfoMsg msg_y) {return Gfui_mnu_itm_null.Null;}
+ public Gfui_mnu_itm Itms_add_rdo_msg (String txt, ImageAdp img, GfoInvkAble invk, GfoInvkRootWkr root_wkr, GfoMsg msg) {return Gfui_mnu_itm_null.Null;}
+ public Gfui_mnu_grp Itms_add_grp(String txt, ImageAdp img) {return Gfui_mnu_grp_null.Null;}
+ public Gfui_mnu_itm Itms_add_separator() {return Gfui_mnu_itm_null.Null;}
+ public static final Gfui_mnu_grp_null Null = new Gfui_mnu_grp_null(); Gfui_mnu_grp_null() {}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_mnu_itm.java b/150_gfui/src_700_env/gplx/gfui/Gfui_mnu_itm.java
new file mode 100644
index 000000000..9b4e8e8e6
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_mnu_itm.java
@@ -0,0 +1,37 @@
+/*
+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.gfui; import gplx.*;
+public interface Gfui_mnu_itm {
+ int Tid();
+ String Uid();
+ boolean Enabled(); void Enabled_(boolean v);
+ String Text(); void Text_(String v);
+ ImageAdp Img(); void Img_(ImageAdp v);
+ boolean Selected(); void Selected_(boolean v);
+ Object Under();
+}
+class Gfui_mnu_itm_null implements Gfui_mnu_itm {
+ public String Uid() {return "";}
+ public int Tid() {return Gfui_mnu_itm_.Tid_btn;}
+ public boolean Enabled() {return true;} public void Enabled_(boolean v) {}
+ public String Text() {return text;} public void Text_(String v) {text = v;} private String text;
+ public ImageAdp Img() {return img;} public void Img_(ImageAdp v) {img = v;} private ImageAdp img;
+ public boolean Selected() {return true;} public void Selected_(boolean v) {}
+ public Object Under() {return null;}
+ public static final Gfui_mnu_itm_null Null = new Gfui_mnu_itm_null(); Gfui_mnu_itm_null() {}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Gfui_mnu_itm_.java b/150_gfui/src_700_env/gplx/gfui/Gfui_mnu_itm_.java
new file mode 100644
index 000000000..49c75e69d
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Gfui_mnu_itm_.java
@@ -0,0 +1,22 @@
+/*
+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.gfui; import gplx.*;
+public class Gfui_mnu_itm_ {
+ public static String Gen_uid() {return "mnu_" + Int_.XtoStr(++uid_next);} private static int uid_next = 0;
+ public static final int Tid_nil = 0, Tid_grp = 1, Tid_spr = 2, Tid_btn = 3, Tid_chk = 4, Tid_rdo = 5;
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Mem_html.java b/150_gfui/src_700_env/gplx/gfui/Mem_html.java
new file mode 100644
index 000000000..4322552b5
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Mem_html.java
@@ -0,0 +1,138 @@
+/*
+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.gfui; import gplx.*;
+class Mem_html extends GxwTextMemo_lang implements Gxw_html { public String Html_doc_html() {
+ return String_.Replace(this.TextVal(), "\r\n", "\n");
+ }
+ public String Html_doc_selected_get_sub_atr(String tag, String sub_tag, int sub_idx, String sub_atr) {return "";}
+ public String Html_doc_selected_get(String host, String page) {return "";}
+ public String Html_doc_selected_get_text_or_href() {return "";}
+ public String Html_doc_selected_get_href_or_text() {return "";}
+ public String Html_doc_selected_get_src_or_empty() {return "";}
+ public boolean Html_window_print_preview() {return false;}
+ public void Html_invk_src_(GfoEvObj v) {}
+ public String Html_elem_atr_get_str(String elem_id, String atr_key) {
+ if (String_.Eq(atr_key, Gfui_html.Atr_value)) return String_.Replace(this.TextVal(), "\r\n", "\n");
+ else throw Err_.unhandled(atr_key);
+ }
+ public Object Html_elem_atr_get_obj(String elem_id, String atr_key) {
+ if (String_.Eq(atr_key, Gfui_html.Atr_value)) return String_.Replace(this.TextVal(), "\r\n", "\n");
+ else throw Err_.unhandled(atr_key);
+ }
+ public boolean Html_elem_atr_get_bool(String elem_id, String atr_key) {
+ if (String_.Eq(atr_key, Gfui_html.Atr_value)) return Bool_.parse_(String_.Replace(this.TextVal(), "\r\n", "\n"));
+ else throw Err_.unhandled(atr_key);
+ }
+ public boolean Html_elem_atr_set(String elem_id, String atr_key, String v) {
+ if (String_.Eq(atr_key, Gfui_html.Atr_value)) this.TextVal_set(v);
+ else throw Err_.unhandled(atr_key);
+ return true;
+ }
+ public boolean Html_elem_atr_set_append(String elem_id, String atr_key, String append) {
+ if (String_.Eq(atr_key, Gfui_html.Atr_value)) this.TextVal_set(this.TextVal() + append);
+ else throw Err_.unhandled(atr_key);
+ return true;
+ }
+ public void Html_doc_html_(String s) {
+// this.Core().ForeColor_set(plainText ? ColorAdp_.Black : ColorAdp_.Gray);
+ s = String_.Replace(s, "\r", "");
+ s = String_.Replace(s, "\n", "\r\n");
+ this.TextVal_set(s);
+ this.SelBgn_set(0);
+ }
+ public String Html_active_atr_get_str(String atrKey, String or) { // NOTE: fuzzy way of finding current href; EX: b
+ String txt = this.TextVal();
+ int pos = this.SelBgn();
+ String rv = ExtractAtr(atrKey, txt, pos);
+ return rv == null ? or : rv;
+ }
+ public void Html_doc_body_focus() {}
+ public String Html_window_vpos() {return "";}
+ public boolean Html_window_vpos_(String v) {return true;}
+ public boolean Html_elem_focus(String v) {return true;}
+ public boolean Html_elem_img_update(String elem_id, String elem_src, int elem_width, int elem_height) {return true;}
+ public boolean Html_elem_delete(String elem_id) {return true;}
+ public boolean Html_elem_replace_html(String id, String html) {return true;}
+ public boolean Html_gallery_packed_exec() {return true;}
+ public String Html_js_eval_script(String script) {return "";}
+ String ExtractAtr(String key, String txt, int pos) {
+ int key_pos = String_.FindBwd(txt, key, pos); if (key_pos == String_.Find_none) return null;
+ int q0 = String_.FindFwd(txt, "\"", key_pos); if (q0 == String_.Find_none) return null;
+ int q1 = String_.FindFwd(txt, "\"", q0 + 1); if (q1 == String_.Find_none) return null;
+ if (!Int_.Between(pos, q0, q1)) return null; // current pos is not between nearest quotes
+ return String_.Mid(txt, q0 + 1, q1);
+ }
+ public boolean Html_doc_find(String elem_id, String find, boolean dir_fwd, boolean case_match, boolean wrap_find) {
+// String txt = this.TextVal();
+// int pos = this.SelBgn();
+// int bgn = String_.FindFwd(txt, find, pos); if (bgn == String_.Find_none) return false;
+// if (bgn == pos) {
+// bgn = String_.FindFwd(txt, find, pos + 1);
+// if (bgn == String_.Find_none) {
+// bgn = String_.FindFwd(txt, find, 0);
+// if (bgn == String_.Find_none) return false;
+// }
+// }
+// this.SelBgn_set(bgn);
+// this.SelLen_set(String_.Len(find));
+// this.ScrollTillSelectionStartIsFirstLine();
+ txtFindMgr.Text_(this.TextVal());
+ int cur = this.SelBgn();
+ int[] ary = txtFindMgr.FindByUi(find, this.SelBgn(), this.SelLen(), false);
+ if (ary[0] != cur) {
+ this.SelBgn_set(ary[0]);
+ this.SelLen_set(ary[1]);
+ this.ScrollTillCaretIsVisible();
+ }
+ else {
+ ary = txtFindMgr.FindByUi(find, this.SelBgn() + 1, 0, false);
+ if (ary[0] != 0) {
+ this.SelBgn_set(ary[0]);
+ this.SelLen_set(ary[1]);
+ this.ScrollTillCaretIsVisible();
+// this.ScrollTillSelectionStartIsFirstLine();
+ }
+ }
+ return true;
+ }
+ public boolean Html_elem_scroll_into_view(String id) {return false;}
+ public void Html_js_enabled_(boolean v) {}
+ public void Html_js_eval_proc(String proc, String... args) {}
+ public void Html_js_cbks_add(String js_func_name, GfoInvkAble invk) {}
+ private TxtFindMgr txtFindMgr = new TxtFindMgr();
+ public Mem_html() {
+ this.ctor_MsTextBoxMultiline_();
+ }
+}
+class Mem_tab_mgr extends GxwElem_mock_base implements Gxw_tab_mgr { public ColorAdp Btns_selected_color() {return btns_selected_color;} public void Btns_selected_color_(ColorAdp v) {btns_selected_color = v;} private ColorAdp btns_selected_color;
+ public ColorAdp Btns_unselected_color() {return btns_unselected_color;} public void Btns_unselected_color_(ColorAdp v) {btns_unselected_color = v;} private ColorAdp btns_unselected_color;
+ public Gxw_tab_itm Tabs_add(Gfui_tab_itm_data tab_data) {return new Mem_tab_itm();}
+ public void Tabs_select_by_idx(int i) {}
+ public void Tabs_close_by_idx(int i) {}
+ public void Tabs_switch(int src, int trg) {}
+ public int Btns_height() {return 0;} public void Btns_height_(int v) {}
+ public boolean Btns_place_on_top() {return false;} public void Btns_place_on_top_(boolean v) {}
+ public boolean Btns_curved() {return false;} public void Btns_curved_(boolean v) {}
+ public boolean Btns_close_visible() {return false;} public void Btns_close_visible_(boolean v) {}
+ public boolean Btns_unselected_close_visible() {return false;} public void Btns_unselected_close_visible_(boolean v) {}
+}
+class Mem_tab_itm extends GxwElem_mock_base implements Gxw_tab_itm { public void Subs_add(GfuiElem sub) {}
+ public Gfui_tab_itm_data Tab_data() {return tab_data;} private Gfui_tab_itm_data tab_data = new Gfui_tab_itm_data("null", -1);
+ public String Tab_name() {return tab_name;} public void Tab_name_(String v) {tab_name = v;} private String tab_name;
+ public String Tab_tip_text() {return tab_tip_text;} public void Tab_tip_text_(String v) {tab_tip_text = v;} private String tab_tip_text;
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Mem_kit.java b/150_gfui/src_700_env/gplx/gfui/Mem_kit.java
new file mode 100644
index 000000000..9431a54bd
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Mem_kit.java
@@ -0,0 +1,38 @@
+/*
+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.gfui; import gplx.*;
+public class Mem_kit extends Gfui_kit_base {
+ @Override public byte Tid() {return Gfui_kit_.Mem_tid;}
+ @Override public String Key() {return "mem";}
+ @Override public GxwElemFactory_base Factory() {return factory;} private GxwElemFactory_cls_mock factory = new GxwElemFactory_cls_mock();
+ public void New_html_impl_prototype_(Gxw_html v) {html_impl_prototype = v;} private Gxw_html html_impl_prototype;
+ @Override public Gfui_html New_html(String key, GfuiElem owner, KeyVal... args) {
+ if (html_impl_prototype == null)
+ return super.New_html(key, owner, args);
+ else {
+ Gfui_html rv = Gfui_html.mem_(key, html_impl_prototype);
+ return rv;
+ }
+ }
+ @Override protected Gxw_html New_html_impl() {return html_impl_prototype == null ? new Mem_html(): html_impl_prototype;}
+ @Override protected Gxw_tab_mgr New_tab_mgr_impl() {return new Mem_tab_mgr();}
+ @Override protected Gxw_tab_itm New_tab_itm_impl() {return new Mem_tab_itm();}
+ @Override protected GxwElem New_btn_impl() {return factory.control_();}
+ @Override public ImageAdp New_img_load(Io_url url) {return ImageAdp_null._;}
+ public static final Mem_kit _ = new Mem_kit(); Mem_kit() {}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Swing_kit.java b/150_gfui/src_700_env/gplx/gfui/Swing_kit.java
new file mode 100644
index 000000000..a671c8932
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Swing_kit.java
@@ -0,0 +1,33 @@
+/*
+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.gfui; import gplx.*;
+public class Swing_kit extends Gfui_kit_base {
+ private Bry_fmtr ask_fmtr = Bry_fmtr.new_(); private Bry_bfr ask_bfr = Bry_bfr.new_();
+ @Override public byte Tid() {return Gfui_kit_.Swing_tid;}
+ @Override public String Key() {return "swing";}
+ @Override public GxwElemFactory_base Factory() {return factory;} private GxwElemFactory_cls_lang factory = new GxwElemFactory_cls_lang();
+ @Override public void Ask_ok(String grp_key, String msg_key, String fmt, Object... args) {GfuiEnv_.ShowMsg(ask_fmtr.Bld_str_many(ask_bfr, fmt, args));}
+ @Override public void Kit_run() {GfuiEnv_.Run(this.Main_win());}
+ @Override public void Kit_term() {this.Kit_term_cbk().Invk(); GfuiEnv_.Exit();}
+ @Override public ImageAdp New_img_load(Io_url url) {return ImageAdp_.file_(url);}
+ @Override protected Gxw_html New_html_impl() {return new Mem_html();}
+ @Override protected Gxw_tab_mgr New_tab_mgr_impl() {return new Mem_tab_mgr();}
+ @Override protected Gxw_tab_itm New_tab_itm_impl() {return new Mem_tab_itm();}
+ @Override protected GxwElem New_btn_impl() {return factory.control_();}
+ public static final Swing_kit _ = new Swing_kit(); Swing_kit() {}
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/Swt_kit.java b/150_gfui/src_700_env/gplx/gfui/Swt_kit.java
new file mode 100644
index 000000000..46d904901
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/Swt_kit.java
@@ -0,0 +1,280 @@
+/*
+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.gfui; import gplx.*;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Button;
+public class Swt_kit implements Gfui_kit {
+ private String xulRunnerPath = null;
+ private KeyValHash ctor_args = KeyValHash.new_(); private HashAdp kit_args = HashAdp_.new_();
+ private KeyValHash nullArgs = KeyValHash.new_();
+ public byte Tid() {return Gfui_kit_.Swt_tid;}
+ public String Key() {return "swt";}
+ public Gfui_clipboard Clipboard() {return clipboard;} private Swt_clipboard clipboard;
+ public Display Swt_display() {return display;} private Display display;
+ public boolean Mode_is_shutdown() {return mode_is_shutdown;} private boolean mode_is_shutdown = false;
+ public Gfui_html_cfg Html_cfg() {return html_cfg;} private Gfui_html_cfg html_cfg = new Gfui_html_cfg();
+ public void Cfg_set(String type, String key, Object val) {
+ if (String_.Eq(type, Gfui_kit_.Cfg_HtmlBox)) {
+ if (String_.Eq(key, "XulRunnerPath")) {
+ xulRunnerPath = (String)val;
+ return;
+ }
+ }
+ KeyValHash typeCfg = (KeyValHash)kit_args.Fetch(type);
+ if (typeCfg == null) {
+ typeCfg = KeyValHash.new_();
+ kit_args.Add(type, typeCfg);
+ }
+ typeCfg.AddReplace(key, val);
+ }
+ public boolean Kit_init_done() {return kit_init_done;} private boolean kit_init_done;
+ public void Kit_init(Gfo_usr_dlg gui_wtr) {
+ this.gui_wtr = gui_wtr;
+ usrMsgWkr_Stop = new Swt_UsrMsgWkr_Stop(this, gui_wtr);
+ display = new Display();
+ UsrDlg_._.Reg(UsrMsgWkr_.Type_Warn, GfoConsoleWin._);
+ UsrDlg_._.Reg(UsrMsgWkr_.Type_Stop, usrMsgWkr_Stop);
+ clipboard = new Swt_clipboard(display);
+ if (xulRunnerPath != null) System.setProperty("org.eclipse.swt.browser.XULRunnerPath", xulRunnerPath);
+ kit_init_done = true;
+ gui_wtr.Log_many("", "", "swt.kit.init.done");
+ } private Gfo_usr_dlg gui_wtr;
+ public void Kit_term_cbk_(GfoInvkAbleCmd v) {this.term_cbk = v;} GfoInvkAbleCmd term_cbk = GfoInvkAbleCmd.Null;
+ public void Kit_run() {
+ shell.addListener(SWT.Close, new Swt_lnr_shell_close(this));
+ shell.open();
+ Cursor cursor = new Cursor(display, SWT.CURSOR_ARROW);
+ shell.setCursor(cursor); // set cursor to hand else cursor defaults to Hourglass until mouse is moved; DATE: 2014-01-31
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ cursor.dispose();
+ Kit_term();
+ }
+ public void Kit_term() {
+ mode_is_shutdown = true; // NOTE: must mark kit as shutting down, else writing to status.bar will create stack overflow exception; DATE:2014-05-05
+ usrMsgWkr_Stop.Rls();
+ clipboard.Rls();
+ display.dispose();
+ } private Swt_UsrMsgWkr_Stop usrMsgWkr_Stop;
+ public boolean Ask_yes_no(String grp_key, String msg_key, String fmt, Object... args) {
+ Swt_dlg_msg dlg = (Swt_dlg_msg)New_dlg_msg(ask_fmtr.Bld_str_many(ask_bfr, fmt, args)).Init_btns_(Gfui_dlg_msg_.Btn_yes, Gfui_dlg_msg_.Btn_no).Init_ico_(Gfui_dlg_msg_.Ico_question);
+ display.syncExec(dlg);
+ return dlg.Ask_rslt == Gfui_dlg_msg_.Btn_yes;
+ }
+ public boolean Ask_ok_cancel(String grp_key, String msg_key, String fmt, Object... args) {
+ Swt_dlg_msg dlg = (Swt_dlg_msg)New_dlg_msg(ask_fmtr.Bld_str_many(ask_bfr, fmt, args)).Init_btns_(Gfui_dlg_msg_.Btn_ok, Gfui_dlg_msg_.Btn_cancel).Init_ico_(Gfui_dlg_msg_.Ico_question);
+ display.syncExec(dlg);
+ return dlg.Ask_rslt == Gfui_dlg_msg_.Btn_ok;
+ } Bry_fmtr ask_fmtr = Bry_fmtr.new_().Fail_when_invalid_escapes_(false); Bry_bfr ask_bfr = Bry_bfr.new_();
+ public int Ask_yes_no_cancel(String grp_key, String msg_key, String fmt, Object... args) {
+ Swt_dlg_msg dlg = (Swt_dlg_msg)New_dlg_msg(ask_fmtr.Bld_str_many(ask_bfr, fmt, args)).Init_btns_(Gfui_dlg_msg_.Btn_yes, Gfui_dlg_msg_.Btn_no, Gfui_dlg_msg_.Btn_cancel).Init_ico_(Gfui_dlg_msg_.Ico_question);
+ display.syncExec(dlg);
+ return dlg.Ask_rslt;
+ }
+ public void Ask_ok(String grp_key, String msg_key, String fmt, Object... args) {
+ Swt_dlg_msg dlg = (Swt_dlg_msg)New_dlg_msg(ask_fmtr.Bld_str_many(ask_bfr, fmt, args)).Init_btns_(Gfui_dlg_msg_.Btn_ok).Init_ico_(Gfui_dlg_msg_.Ico_information);
+ display.syncExec(dlg);
+ }
+ public GfuiInvkCmd New_cmd_sync(GfoInvkAble invk) {return new Swt_gui_cmd(this, gui_wtr, display, invk, Bool_.N);}
+ public GfuiInvkCmd New_cmd_async(GfoInvkAble invk) {return new Swt_gui_cmd(this, gui_wtr, display, invk, Bool_.Y);}
+ public GfuiWin New_win_utl(String key, GfuiWin owner, KeyVal... args) {return GfuiWin_.kit_(this, key, new Swt_win(shell), nullArgs); }
+ public GfuiWin New_win_app(String key, KeyVal... args) {
+ Swt_win win = new Swt_win(display);
+ this.shell = win.UnderShell();
+ shell.setLayout(null);
+ GfuiWin rv = GfuiWin_.kit_(this, key, win, nullArgs);
+ main_win = rv;
+ return rv;
+ } Shell shell; GfuiWin main_win;
+ public GfuiBtn New_btn(String key, GfuiElem owner, KeyVal... args) {
+ GfuiBtn rv = GfuiBtn_.kit_(this, key, new Swt_btn_no_border(Swt_control_.cast_or_fail(owner), ctor_args), ctor_args);
+ owner.SubElems().Add(rv);
+ return rv;
+ }
+ public Gfui_html New_html(String key, GfuiElem owner, KeyVal... args) {
+ ctor_args.Clear();
+ Object htmlBox_args_obj = kit_args.Fetch(Gfui_kit_.Cfg_HtmlBox);
+ if (htmlBox_args_obj != null) {
+ KeyValHash htmlBox_args = (KeyValHash)htmlBox_args_obj;
+ KeyVal browser_type = htmlBox_args.FetchOrNull(Cfg_Html_BrowserType);
+ if (browser_type != null) ctor_args.Add(browser_type);
+ }
+ Gfui_html rv = Gfui_html.kit_(this, key, new Swt_html(this, Swt_control_.cast_or_fail(owner), ctor_args), ctor_args);
+ ((Swt_html)rv.UnderElem()).Under_control().addMenuDetectListener(new Swt_lnr__menu_detect(rv));
+ rv.Owner_(owner);
+ return rv;
+ }
+ public Gfui_tab_mgr New_tab_mgr(String key, GfuiElem owner, KeyVal... args) {
+ ctor_args.Clear();
+ Swt_tab_mgr rv_swt = new Swt_tab_mgr(this, Swt_control_.cast_or_fail(owner), ctor_args);
+ Gfui_tab_mgr rv = Gfui_tab_mgr.kit_(this, key, rv_swt, ctor_args);
+ rv.Owner_(owner);
+ rv_swt.EvMgr_(rv.EvMgr());
+ return rv;
+ }
+ public GfuiTextBox New_text_box(String key, GfuiElem owner, KeyVal... args) {
+ ctor_args.Clear();
+ int args_len = args.length;
+ for (int i = 0; i < args_len; i++)
+ ctor_args.Add(args[i]);
+ boolean border_on = Bool_.cast_(ctor_args.FetchValOr(GfuiTextBox.CFG_border_on_, true));
+ GxwTextFld under = new Swt_text_w_border(Swt_control_.cast_or_fail(owner), New_color(border_on ? ColorAdp_.LightGray : ColorAdp_.White), ctor_args);
+ GfuiTextBox rv = GfuiTextBox_.kit_(this, key, under, ctor_args);
+ rv.Owner_(owner);
+ ctor_args.Clear();
+ return rv;
+ }
+ public GfuiStatusBox New_status_box(String key, GfuiElem owner, KeyVal... args) {
+ ctor_args.Clear();
+ GfuiStatusBox rv = GfuiStatusBox_.kit_(this, key, new Swt_text(Swt_control_.cast_or_fail(owner), ctor_args));
+ rv.Owner_(owner);
+ return rv;
+ }
+ public Gfui_dlg_file New_dlg_file(byte type, String msg) {return new Swt_dlg_file(type, shell).Init_msg_(msg);}
+ public Gfui_dlg_msg New_dlg_msg(String msg) {return new Swt_dlg_msg(shell).Init_msg_(msg);}
+ public ImageAdp New_img_load(Io_url url) {
+ if (url == Io_url_.Null) return ImageAdp_.Null;
+ Image img = new Image(display, url.Raw());
+ Rectangle rect = img.getBounds();
+ return new Swt_img(this, img, rect.width, rect.height).Url_(url);
+ }
+ public Color New_color(ColorAdp v) {return (Color)New_color(v.Alpha(), v.Red(), v.Green(), v.Blue());}
+ public Object New_color(int a, int r, int g, int b) {return new Color(display, r, g, b);}
+ public Gfui_mnu_grp New_mnu_popup(String key, GfuiElem owner) {return Swt_popup_grp.new_popup(key, owner);}
+ public Gfui_mnu_grp New_mnu_bar(String key, GfuiWin owner) {return Swt_popup_grp.new_bar(key, owner);}
+ public float Calc_font_height(GfuiElem elem, String s) {
+ if (String_.Len_eq_0(s)) return 8;
+ String old_text = elem.Text();
+ elem.Text_(s);
+ float rv = ((Swt_text_w_border)(elem.UnderElem())).Under_text().getFont().getFontData()[0].height;
+ shell.setText(old_text);
+ return rv;
+ }
+ public void Set_mnu_popup(GfuiElem owner, Gfui_mnu_grp grp) {
+ Control control = Swt_control_.cast_or_fail(owner).Under_menu_control();
+ Swt_popup_grp popup = (Swt_popup_grp)grp;
+ control.setMenu(popup.Under_menu());
+ }
+ public static final Swt_kit _ = new Swt_kit(); private Swt_kit() {} // singleton b/c of following line "In particular, some platforms which SWT supports will not allow more than one active display" (http://help.eclipse.org/indigo/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/Display.html)
+ public static final String Cfg_Html_BrowserType = "BrowserType";
+ public static int Cfg_Html_BrowserType_parse(String v) {
+ if (String_.Eq(v, "mozilla")) return Swt_html.Browser_tid_mozilla;
+ else return Swt_html.Browser_tid_none;
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (String_.Eq(k, Invk_Cfg_add)) {
+ String type = m.ReadStrOr("type", "");
+ String key = m.ReadStrOr("key", "");
+ String val = m.ReadStrOr("val", "");
+ if (ctx.Deny()) return this;
+ if (String_.Eq(type, Gfui_kit_.Cfg_HtmlBox)) {
+ if (String_.Eq(key, "XulRunnerPath"))
+ xulRunnerPath = val;
+ else if (String_.Eq(key, Swt_kit.Cfg_Html_BrowserType))
+ Cfg_set(type, Swt_kit.Cfg_Html_BrowserType, Cfg_Html_BrowserType_parse(val));
+ }
+ }
+ else if (String_.Eq(k, Invk_HtmlBox)) {return html_cfg;}
+ else if (String_.Eq(k, Invk_ask_file)) return this.New_dlg_file(Gfui_kit_.File_dlg_type_open, m.Args_getAt(0).Val_to_str_or_empty()).Ask();
+ return this;
+ } public static final String Invk_Cfg_add = "Cfg_add", Invk_HtmlBox = "HtmlBox", Invk_ask_file = "ask_file";
+ public static boolean Html_box_focus_automatically = false;
+ public static FontAdp Control_font_get(Font font, GxwCore_base owner) {
+ FontData fontData = font.getFontData()[0];
+ FontAdp rv = FontAdp.new_(fontData.getName(), fontData.getHeight(), FontStyleAdp_.lang_(fontData.getStyle())); // NOTE: swt style constants match swing
+ rv.OwnerGxwCore_(owner);
+ return rv;
+ }
+ public static void Control_font_set(FontAdp font, GxwCore_base owner, Control control) {
+ font.OwnerGxwCore_(owner);
+ FontData fontData = new FontData(font.Name(), (int)font.size, font.Style().Val());
+ Font rv = new Font(control.getDisplay(), fontData);
+ control.setFont(rv);
+ }
+}
+class Swt_lnr_shell_close implements Listener {
+ public Swt_lnr_shell_close(Swt_kit kit) {this.kit = kit;} private Swt_kit kit;
+ @Override public void handleEvent(Event event) {
+ if (kit.term_cbk.Cmd() == null) return; // close_cmd not defined
+ boolean rslt = Bool_.cast_(kit.term_cbk.Invk());
+ if (!rslt)
+ event.doit = false;
+ }
+}
+class Swt_UsrMsgWkr_Stop implements UsrMsgWkr, RlsAble {
+ public Swt_UsrMsgWkr_Stop(Swt_kit kit, Gfo_usr_dlg gui_wtr) {this.kit = kit; this.gui_wtr = gui_wtr;} Swt_kit kit; Gfo_usr_dlg gui_wtr;
+ @Override public void Rls() {this.kit = null;}
+ public void ExecUsrMsg(int type, UsrMsg umsg) {
+ String msg = umsg.XtoStr();
+ kit.Ask_ok("xowa.gui", "stop", msg);
+ gui_wtr.Log_many("", "", msg);
+ }
+}
+class Swt_gui_cmd implements GfuiInvkCmd, Runnable {
+ private Swt_kit kit; private Gfo_usr_dlg usr_dlg; private GfoInvkAble target; private Display display; private boolean async;
+ private GfsCtx invk_ctx; private int invk_ikey; private String invk_key; private GfoMsg invk_msg;
+ public Swt_gui_cmd(Swt_kit kit, Gfo_usr_dlg usr_dlg, Display display, GfoInvkAble target, boolean async) {
+ this.kit = kit; this.usr_dlg = usr_dlg; this.display = display; this.target = target; this.async = async;
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ this.invk_ctx = ctx; this.invk_ikey = ikey ; this.invk_key = k; this.invk_msg = m;
+ if (async)
+ display.asyncExec(this);
+ else
+ display.syncExec(this);
+ return this;
+ }
+ @Override public void run() {
+ try {
+ target.Invk(invk_ctx, invk_ikey, invk_key, invk_msg);
+ }
+ catch (Exception e) {
+ if (kit.Mode_is_shutdown()) return; // NOTE: if shutting down, don't warn; warn will try to write to status.bar, which will fail b/c SWT is shutting down; failures will try to write to status.bar again, causing StackOverflow exception; DATE:2014-05-04
+ usr_dlg.Warn_many("", "", "fatal error while running; key=~{0} err=~{1}", invk_key, Err_.Message_gplx_brief(e));
+ }
+ }
+ public void Rls() {
+ usr_dlg = null; target = null; display = null;
+ invk_ctx = null; invk_key = null; invk_msg = null;
+ }
+}
diff --git a/150_gfui/src_700_env/gplx/gfui/TxtFindMgr.java b/150_gfui/src_700_env/gplx/gfui/TxtFindMgr.java
new file mode 100644
index 000000000..e0dfc7cbe
--- /dev/null
+++ b/150_gfui/src_700_env/gplx/gfui/TxtFindMgr.java
@@ -0,0 +1,48 @@
+/*
+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.gfui; import gplx.*;
+public class TxtFindMgr {
+ public String Text() {return text;}
+ public TxtFindMgr Text_(String v) {
+ if (!caseSensitive) v = String_.Lower(v);
+ text = v;
+ return this;
+ } String text;
+ public boolean CaseSensitive() {return caseSensitive;} public TxtFindMgr CaseSensitive_(boolean v) {caseSensitive = v; return this;} private boolean caseSensitive = false;
+ public int[] FindByUi(String findText, int selBgn, int selLen, boolean keyIsEnter) {
+ int[] rv = new int[2];
+ if (String_.Eq(findText, "")) return rv; // make newSel = 0 b/c all text deleted; else, find will continue from last selBgn; easy way to "reset"
+ rv[0] = selBgn; rv[1] = selLen; // make newSel = curSel
+ int adj = keyIsEnter ? 1 : 0; // if enter, search next, else search from cur; else will add to selLen if at match; ex: ab->c at abc will keep same selBgn, but increase selLen to 3
+ int findPos = FindNext(findText, selBgn + adj);
+ if (findPos == String_.Find_none) { // nothing found; set selLen to 0 and return
+ rv[1] = 0;
+ return rv;
+ }
+ rv[0] = findPos;
+ rv[1] = String_.Len(findText);
+ return rv;
+ }
+ public int FindNext(String find, int guiPos) {
+ if (!caseSensitive) find = String_.Lower(find);
+ int findPos = String_.FindFwd(text, find, guiPos);
+ if (findPos == String_.Find_none && guiPos != 0)
+ findPos = String_.FindFwd(text, find, 0);
+ return findPos;
+ }
+}
diff --git a/150_gfui/tst/gplx/gfui/ClipboardAdp__tst.java b/150_gfui/tst/gplx/gfui/ClipboardAdp__tst.java
new file mode 100644
index 000000000..24ff8a4cb
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/ClipboardAdp__tst.java
@@ -0,0 +1,26 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class ClipboardAdp__tst {
+ @Test public void Basic() {
+ ClipboardAdp_.SetText("test");
+ Tfds.Eq(true, ClipboardAdp_.IsText());
+ Tfds.Eq("test", ClipboardAdp_.GetText());
+ }
+}
diff --git a/150_gfui/tst/gplx/gfui/GfuiBorderMgr_tst.java b/150_gfui/tst/gplx/gfui/GfuiBorderMgr_tst.java
new file mode 100644
index 000000000..fe699713e
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfuiBorderMgr_tst.java
@@ -0,0 +1,53 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class GfuiBorderMgr_tst {
+ @Before public void setup() {
+ borderMgr = GfuiBorderMgr.new_();
+ }
+ @Test public void NullToEdge() { // all null -> one edge
+ tst_Eq(borderMgr, null, null, null, null, null);
+
+ borderMgr.Top_(red);
+ tst_Eq(borderMgr, null, red, null, null, null);
+ }
+ @Test public void EdgeToAll() { // one edge -> all edge
+ borderMgr.Top_(red);
+ tst_Eq(borderMgr, null, red, null, null, null);
+
+ borderMgr.All_(black);
+ tst_Eq(borderMgr, black, null, null, null, null);
+ }
+ @Test public void AllToEdge() { // all edge -> one new; three old
+ borderMgr.All_(red);
+ tst_Eq(borderMgr, red, null, null, null, null);
+
+ borderMgr.Top_(black);
+ tst_Eq(borderMgr, null, black, red, red, red);
+ }
+ void tst_Eq(GfuiBorderMgr borderMgr, PenAdp all, PenAdp top, PenAdp left, PenAdp right, PenAdp bottom) {
+ Tfds.Eq(borderMgr.All(), all);
+ Tfds.Eq(borderMgr.Top(), top);
+ Tfds.Eq(borderMgr.Left(), left);
+ Tfds.Eq(borderMgr.Right(), right);
+ Tfds.Eq(borderMgr.Bot(), bottom);
+ }
+ GfuiBorderMgr borderMgr;
+ PenAdp black = PenAdp_.black_(), red = PenAdp_.new_(ColorAdp_.Red, 1);
+}
diff --git a/150_gfui/tst/gplx/gfui/GfuiClickKeyMgr_tst.java b/150_gfui/tst/gplx/gfui/GfuiClickKeyMgr_tst.java
new file mode 100644
index 000000000..9b8d37b92
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfuiClickKeyMgr_tst.java
@@ -0,0 +1,31 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class GfuiClickKeyMgr_tst {
+ @Test public void ExtractKeyFromText() {
+ tst_ExtractKey("&click", IptKey_.C);
+ tst_ExtractKey("&", IptKey_.None);
+ tst_ExtractKey("trailing &", IptKey_.None);
+ tst_ExtractKey("me & you", IptKey_.None);
+ }
+ void tst_ExtractKey(String text, IptKey expd) {
+ IptKey actl = GfuiWinKeyCmdMgr.ExtractKeyFromText(text);
+ Tfds.Eq(expd, actl);
+ }
+}
diff --git a/150_gfui/tst/gplx/gfui/GfuiFocusOrderer_tst.java b/150_gfui/tst/gplx/gfui/GfuiFocusOrderer_tst.java
new file mode 100644
index 000000000..6b05257dc
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfuiFocusOrderer_tst.java
@@ -0,0 +1,87 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class GfuiFocusOrderer_tst {
+ @Before public void setup() {
+ owner = GfuiElem_.new_();
+ list = ListAdp_.new_(); // list of all controls
+ }
+ @Test public void Horizontal() {
+ ini_Subs(owner, list, xy_(40, 0), xy_(20, 0), xy_(0, 0));
+ tst_FocusIndxs(owner, list, 0, 1, 2);
+
+ GfuiFocusOrderer.OrderByX(owner);
+ tst_FocusIndxs(owner, list, 2, 1, 0);
+ }
+ @Test public void Vertical() {
+ ini_Subs(owner, list, xy_(0, 40), xy_(0, 20), xy_(0, 0));
+ tst_FocusIndxs(owner, list, 0, 1, 2);
+
+ GfuiFocusOrderer.OrderByY(owner);
+ tst_FocusIndxs(owner, list, 2, 1, 0);
+ }
+ @Test public void Grid() {
+ ini_Subs(owner, list, xy_(20, 20), xy_(0, 20), xy_(20, 0), xy_(0, 0));
+ tst_FocusIndxs(owner, list, 0, 1, 2, 3);
+
+ GfuiFocusOrderer.OrderByX(owner);
+ tst_FocusIndxs(owner, list, 3, 2, 1, 0);
+ }
+ @Test public void Deep() {
+ ini_Subs(owner, list, xy_(20, 0), xy_(0, 0));
+ GfuiElem sub0 = sub_(owner, 0), sub1 = sub_(owner, 1);
+ ini_Subs(sub0, list, xy_(20, 0), xy_(0, 0));
+ ini_Subs(sub1, list, xy_(20, 0), xy_(0, 0));
+ tst_FocusIndxs(owner, list, 0, 1, 0, 1, 0, 1); // 2 owner controls (0, 1); each has two subs (0, 1)
+
+ GfuiFocusOrderer.OrderByX(owner);
+ tst_FocusIndxs(owner, list, 3, 0, 5, 4, 2, 1);
+ }
+ @Test public void Manusl() {
+ ini_Subs(owner, list, xy_(0, 0), xy_(20, 0));
+ tst_FocusIndxs(owner, list, 0, 1);
+
+ GfuiElem sub1 = owner.SubElems().FetchAt(0);
+ GfuiElem sub2 = owner.SubElems().FetchAt(1);
+ sub1.Focus_idx_(1);
+ sub2.Focus_idx_(0);
+
+ GfuiFocusOrderer.OrderByX(owner);
+ tst_FocusIndxs(owner, list, 1, 0);
+ }
+ PointAdp xy_(int x, int y) {return PointAdp_.new_(x, y);}
+ GfuiElem sub_(GfuiElem owner, int i) {return owner.SubElems().FetchAt(i);}
+ void ini_Subs(GfuiElem owner, ListAdp list, PointAdp... points) {
+ for (int i = 0; i < points.length; i++) {
+ GfuiElem sub = GfuiElem_.sub_(Int_.XtoStr(i), owner);
+ sub.Pos_(points[i]);
+ sub.UnderElem().Core().Focus_index_set(i);
+ list.Add(sub);
+ }
+ }
+ void tst_FocusIndxs(GfuiElem owner, ListAdp list, int... expd) {
+ int[] actl = new int[list.Count()];
+ for (int i = 0; i < actl.length; i++) {
+ GfuiElem sub = (GfuiElem)list.FetchAt(i);
+ actl[i] = sub.UnderElem().Core().Focus_index();
+ }
+ Tfds.Eq_ary(expd, actl);
+ }
+ GfuiElem owner; ListAdp list;
+}
diff --git a/150_gfui/tst/gplx/gfui/GfuiMoveElemBtn_tst.java b/150_gfui/tst/gplx/gfui/GfuiMoveElemBtn_tst.java
new file mode 100644
index 000000000..3927c1f37
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfuiMoveElemBtn_tst.java
@@ -0,0 +1,35 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class GfuiMoveElemBtn_tst {
+ @Before public void setup() {
+ form = GfuiWin_.app_("form"); form.Size_(100, 100);
+ moveBtn = GfuiBtn_.new_("moveBtn");
+ GfuiMoveElemBnd bnd = GfuiMoveElemBnd.new_(); bnd.TargetElem_set(form);
+ moveBtn.IptBnds().Add(bnd);
+ }
+ @Test public void Basic() {
+ Tfds.Eq(form.X(), 0);
+ IptEventMgr.ExecKeyDown(moveBtn, IptEvtDataKey.test_(MoveRightArg()));
+ Tfds.Eq(form.X(), 10);
+ }
+
+ IptKey MoveRightArg() {return IptKey_.Ctrl.Add(IptKey_.Right);}
+ GfuiWin form; GfuiBtn moveBtn;
+}
diff --git a/150_gfui/tst/gplx/gfui/GfxAdpMok.java b/150_gfui/tst/gplx/gfui/GfxAdpMok.java
new file mode 100644
index 000000000..f68836a65
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfxAdpMok.java
@@ -0,0 +1,49 @@
+/*
+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.gfui; import gplx.*;
+public class GfxAdpMok implements GfxAdp {
+ public GfxItmList SubItms() {return subItms;} GfxItmList subItms = new GfxItmList();
+ public void DrawStringXtn(String s, FontAdp font, SolidBrushAdp brush, float x, float y, float width, float height, GfxStringData sd) {
+ float[] sizeAry = MeasureStringXtn(s, font, null);
+ SizeAdp size = SizeAdp_.new_((int)sizeAry[0], (int)sizeAry[1]);
+ GfxStringItm str = GfxStringItm.new_(PointAdp_.new_((int)x, (int)y), size, s, font, brush);
+ subItms.Add(str);
+ }
+ public void DrawRect(PenAdp pen, PointAdp location, SizeAdp size) {this.DrawRect(pen, location.X(), location.Y(), size.Width(), size.Height());}
+ public void DrawRect(PenAdp pen, RectAdp rect) {this.DrawRect(pen, rect.X(), rect.Y(), rect.Width(), rect.Height());}
+ public void DrawRect(PenAdp pen, int x, int y, int width, int height) {
+ GfxRectItm rect = GfxRectItm.new_(PointAdp_.new_(x, y), SizeAdp_.new_(width, height), pen.Width(), pen.Color());
+ subItms.Add(rect);
+ }
+ public void DrawLine(PenAdp pen, PointAdp src, PointAdp trg) {
+ GfxLineItm line = GfxLineItm.new_(src, trg, pen.Width(), pen.Color());
+ subItms.Add(line);
+ }
+ public void DrawImage(ImageAdp image, PointAdp location) {
+ // gfx.DrawImage(image, width, height);
+ }
+ public void DrawImage(ImageAdp img, int trg_x, int trg_y, int trg_w, int trg_h, int src_x, int src_y, int src_w, int src_h) {
+ // gfx.DrawImage(image, dst, src, GraphicsUnit.Pixel);
+ }
+ public void FillRect(SolidBrushAdp brush, int x, int y, int width, int height) {
+ // gfx.FillRect(brush, x, y, width, height);
+ }
+ public float[] MeasureStringXtn(String s, FontAdp font, GfxStringData str) {return new float[] {13 * String_.Len(s), 17};}
+ public void Rls() {}
+ public static GfxAdpMok new_() {return new GfxAdpMok();} GfxAdpMok() {}
+}
diff --git a/150_gfui/tst/gplx/gfui/GfxItm.java b/150_gfui/tst/gplx/gfui/GfxItm.java
new file mode 100644
index 000000000..103fe0678
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfxItm.java
@@ -0,0 +1,19 @@
+/*
+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.gfui; import gplx.*;
+public interface GfxItm {}
diff --git a/150_gfui/tst/gplx/gfui/GfxItmList.java b/150_gfui/tst/gplx/gfui/GfxItmList.java
new file mode 100644
index 000000000..cec13f7ca
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfxItmList.java
@@ -0,0 +1,30 @@
+/*
+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.gfui; import gplx.*;
+public class GfxItmList extends ListAdp_base {
+ @gplx.New public GfxItm FetchAt(int i) {return (GfxItm)FetchAt_base(i);}
+ public void Add(GfxItm gfxItm) {Add_base(gfxItm);}
+}
+class GfxItmListFxt {
+ public void tst_SubItm_count(GfxAdpMok gfx, int expd) {Tfds.Eq(expd, gfx.SubItms().Count());}
+ public void tst_SubItm(GfxAdpMok gfx, int i, GfxItm expd) {
+ GfxItm actl = gfx.SubItms().FetchAt(i);
+ Tfds.Eq(expd, actl);
+ }
+ public static GfxItmListFxt new_() {return new GfxItmListFxt();} GfxItmListFxt() {}
+}
diff --git a/150_gfui/tst/gplx/gfui/GfxItm_base.java b/150_gfui/tst/gplx/gfui/GfxItm_base.java
new file mode 100644
index 000000000..7aaf88c31
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfxItm_base.java
@@ -0,0 +1,33 @@
+/*
+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.gfui; import gplx.*;
+public abstract class GfxItm_base implements GfxItm {
+ public PointAdp Pos() {return pos;} PointAdp pos = PointAdp_.Zero;
+ public SizeAdp Size() {return size;} SizeAdp size = SizeAdp_.Zero;
+ @Override public String toString() {return String_bldr_.new_().Add_kv_obj("pos", pos).Add_kv_obj("size", size).XtoStr();}
+ @Override public int hashCode() {return this.toString().hashCode();}
+ @Override public boolean equals(Object obj) {
+ GfxItm_base comp = GfxItm_base.as_(obj); if (comp == null) return false;
+ return Object_.Eq(pos, comp.pos) && Object_.Eq(size, comp.size);
+ }
+ @gplx.Virtual public void ctor_GfxItmBase(PointAdp posVal, SizeAdp sizeVal) {
+ pos = posVal; size = sizeVal;
+ }
+ public static GfxItm_base as_(Object obj) {return obj instanceof GfxItm_base ? (GfxItm_base)obj : null;}
+ public static GfxItm_base cast_(Object obj) {try {return (GfxItm_base)obj;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, GfxItm_base.class, obj);}}
+}
diff --git a/150_gfui/tst/gplx/gfui/GfxLineItm.java b/150_gfui/tst/gplx/gfui/GfxLineItm.java
new file mode 100644
index 000000000..56ff872ef
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfxLineItm.java
@@ -0,0 +1,39 @@
+/*
+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.gfui; import gplx.*;
+public class GfxLineItm implements GfxItm {
+ public PointAdp Src() {return src;} PointAdp src = PointAdp_.Zero;
+ public PointAdp Trg() {return trg;} PointAdp trg = PointAdp_.Zero;
+ public float Width() {return width;} float width;
+ public ColorAdp Color() {return color;} ColorAdp color;
+
+ @Override public String toString() {return String_bldr_.new_().Add_kv_obj("src", src).Add_kv_obj("trg", trg).Add_kv_obj("width", width).Add_kv_obj("color", color.XtoHexStr()).XtoStr();}
+ @Override public int hashCode() {return this.toString().hashCode();}
+ @Override public boolean equals(Object obj) {
+ GfxLineItm comp = GfxLineItm.as_(obj); if (comp == null) return false;
+ return src.Eq(comp.src) && trg.Eq(comp.trg) && width == comp.width && color.Eq(comp.color);
+ }
+ public static GfxLineItm new_(PointAdp src, PointAdp trg, float width, ColorAdp color) {
+ GfxLineItm rv = new GfxLineItm();
+ rv.src = src; rv.trg = trg;
+ rv.width = width; rv.color = color;
+ return rv;
+ } GfxLineItm() {}
+ public static GfxLineItm as_(Object obj) {return obj instanceof GfxLineItm ? (GfxLineItm)obj : null;}
+ public static GfxLineItm cast_(Object obj) {try {return (GfxLineItm)obj;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, GfxLineItm.class, obj);}}
+}
diff --git a/150_gfui/tst/gplx/gfui/GfxRectItm.java b/150_gfui/tst/gplx/gfui/GfxRectItm.java
new file mode 100644
index 000000000..e7d8d2a2c
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfxRectItm.java
@@ -0,0 +1,36 @@
+/*
+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.gfui; import gplx.*;
+public class GfxRectItm extends GfxItm_base {
+ public float Width() {return width;} float width;
+ public ColorAdp Color() {return color;} ColorAdp color;
+
+ @Override public String toString() {return String_.Concat(super.toString(), String_bldr_.new_().Add_kv_obj("width", width).Add_kv("color", color.XtoHexStr()).XtoStr());}
+ @Override public int hashCode() {return this.toString().hashCode();}
+ @Override public boolean equals(Object obj) {
+ GfxRectItm comp = GfxRectItm.as_(obj); if (comp == null) return false;
+ return super.equals(comp) && width == comp.width && color.Eq(comp.color);
+ }
+ public static GfxRectItm new_(PointAdp pos, SizeAdp size, float width, ColorAdp color) {
+ GfxRectItm rv = new GfxRectItm();
+ rv.ctor_GfxItmBase(pos, size);
+ rv.width = width; rv.color = color;
+ return rv;
+ } GfxRectItm() {}
+ @gplx.New public static GfxRectItm as_(Object obj) {return obj instanceof GfxRectItm ? (GfxRectItm)obj : null;}
+}
diff --git a/150_gfui/tst/gplx/gfui/GfxStringItm.java b/150_gfui/tst/gplx/gfui/GfxStringItm.java
new file mode 100644
index 000000000..92e9d5b0c
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/GfxStringItm.java
@@ -0,0 +1,38 @@
+/*
+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.gfui; import gplx.*;
+public class GfxStringItm extends GfxItm_base {
+ public String Text() {return text;} private String text;
+ public FontAdp Font() {return font;} FontAdp font;
+ public SolidBrushAdp Brush() {return brush;} SolidBrushAdp brush;
+ @Override public int hashCode() {return this.toString().hashCode();}
+ @Override public boolean equals(Object obj) {
+ GfxStringItm comp = GfxStringItm.as_(obj); if (comp == null) return false;
+ return super.equals(obj) && String_.Eq(text, comp.text) && font.Eq(comp.font) && brush.Eq(comp.brush);
+ }
+ public static GfxStringItm new_(PointAdp pos, SizeAdp size, String text, FontAdp font, SolidBrushAdp brush) {
+ GfxStringItm rv = new GfxStringItm();
+ rv.ctor_GfxItmBase(pos, size);
+ rv.text = text; rv.font = font; rv.brush = brush;
+ return rv;
+ } GfxStringItm() {}
+ public static GfxStringItm test_(String text, FontAdp font, SolidBrushAdp brush) {
+ return GfxStringItm.new_(PointAdp_.Null, SizeAdp_.Null, text, font, brush);
+ }
+ @gplx.New public static GfxStringItm as_(Object obj) {return obj instanceof GfxStringItm ? (GfxStringItm)obj : null;}
+}
diff --git a/150_gfui/tst/gplx/gfui/ImageAdp_tst.java b/150_gfui/tst/gplx/gfui/ImageAdp_tst.java
new file mode 100644
index 000000000..c139b152e
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/ImageAdp_tst.java
@@ -0,0 +1,45 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+import gplx.ios.*;
+import gplx.security.*;
+public class ImageAdp_tst {
+ @Before public void setup() {
+ load = Tfds.RscDir.GenSubFil_nest("150_gfui", "imgs", "strawberry_java.bmp");
+ } ImageAdp img; Io_url load;
+ @Test public void load_() {
+ img = ImageAdp_.file_(load);
+ Tfds.Eq(80, img.Width());
+ Tfds.Eq(80, img.Height());
+ Tfds.Eq("80,80", img.Size().toString());
+ Tfds.Eq(img.Url(), load);
+ }
+ @Test public void SaveAsBmp() {
+ img = ImageAdp_.file_(load);
+ Io_url save = load.GenNewNameOnly("strawberry_temp");
+ DateAdp beforeModifiedTime = Io_mgr._.QueryFil(save).ModifiedTime();
+ img.SaveAsBmp(save);
+ DateAdp afterModifiedTime = Io_mgr._.QueryFil(save).ModifiedTime();
+ Tfds.Eq_true(CompareAble_.Is_more(afterModifiedTime, beforeModifiedTime));
+
+ String loadHash = HashAlgo_.Md5.CalcHash(ConsoleDlg_.Null, Io_mgr._.OpenStreamRead(load));
+ String saveHash = HashAlgo_.Md5.CalcHash(ConsoleDlg_.Null, Io_mgr._.OpenStreamRead(save));
+ Tfds.Eq(loadHash, saveHash);
+ }
+}
diff --git a/150_gfui/tst/gplx/gfui/IptArg_parser_tst.java b/150_gfui/tst/gplx/gfui/IptArg_parser_tst.java
new file mode 100644
index 000000000..db8255320
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/IptArg_parser_tst.java
@@ -0,0 +1,63 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class IptArg_parser_tst {
+ @Test public void KeyBasic() {
+ tst_parse_Key_("key.a", IptKey_.A);
+ tst_parse_Key_("key.d0", IptKey_.D0);
+ tst_parse_Key_("key.semicolon", IptKey_.Semicolon);
+ tst_parse_Key_("key.equal", IptKey_.Equal);
+ tst_parse_Key_("key.pageUp", IptKey_.PageUp);
+ tst_parse_Key_("key.ctrl", IptKey_.Ctrl);
+ tst_parse_Key_("key.none", IptKey_.None);
+ } void tst_parse_Key_(String raw, IptKey expd) {Tfds.Eq(expd.Val(), IptKey_.parse_(raw).Val());}
+ @Test public void KbdCmdModifiers() {
+ tst_parse_Key_("key.ctrl+key.enter", IptKey_.Ctrl.Add(IptKey_.Enter));
+ tst_parse_Key_("key.alt+key.escape", IptKey_.Alt.Add(IptKey_.Escape));
+ tst_parse_Key_("key.shift+key.f1", IptKey_.Shift.Add(IptKey_.F1));
+ tst_parse_Key_("key.shift+key.ctrl", IptKey_.Ctrl.Add(IptKey_.Shift));
+ tst_parse_Key_("key.ctrl+key.alt+key.slash", IptKey_.Ctrl.Add(IptKey_.Alt).Add(IptKey_.Slash));
+ }
+ @Test public void KeyWhitespace() {
+ tst_parse_Key_("key.ctrl + key.alt + key.slash", IptKey_.Ctrl.Add(IptKey_.Alt).Add(IptKey_.Slash));
+ }
+ @Test public void MouseBtn() {
+ tst_parse_MouseBtn_("mouse.left", IptMouseBtn_.Left);
+ tst_parse_MouseBtn_("mouse.right", IptMouseBtn_.Right);
+ tst_parse_MouseBtn_("mouse.middle", IptMouseBtn_.Middle);
+ tst_parse_MouseBtn_("mouse.x1", IptMouseBtn_.X1);
+ tst_parse_MouseBtn_("mouse.x2", IptMouseBtn_.X2);
+ } void tst_parse_MouseBtn_(String raw, IptMouseBtn expd) {Tfds.Eq(expd, IptMouseBtn_.parse_(raw));}
+ @Test public void MouseWheel() {
+ tst_parse_MouseWheel_("wheel.up", IptMouseWheel_.Up);
+ tst_parse_MouseWheel_("wheel.down", IptMouseWheel_.Down);
+ } void tst_parse_MouseWheel_(String raw, IptMouseWheel expd) {Tfds.Eq(expd, IptMouseWheel_.parse_(raw));}
+ @Test public void Mod() {
+ tst_parse_("mod.c", IptKey_.Ctrl);
+ tst_parse_("mod.cs", IptKey_.add_(IptKey_.Ctrl, IptKey_.Shift));
+ tst_parse_("mod.cas", IptKey_.add_(IptKey_.Ctrl, IptKey_.Alt, IptKey_.Shift));
+ tst_parse_("mod.c+key.c", IptKey_.add_(IptKey_.Ctrl, IptKey_.C));
+ }
+ @Test public void All() {
+ tst_parse_("key.c", IptKey_.C);
+ tst_parse_("mouse.left", IptMouseBtn_.Left);
+ tst_parse_("wheel.up", IptMouseWheel_.Up);
+ tst_parse_("mod.c", IptKey_.Ctrl);
+ } void tst_parse_(String raw, IptArg expd) {Tfds.Eq(expd, IptArg_.parse_(raw));}
+}
diff --git a/150_gfui/tst/gplx/gfui/IptEventType_tst.java b/150_gfui/tst/gplx/gfui/IptEventType_tst.java
new file mode 100644
index 000000000..59656ed9f
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/IptEventType_tst.java
@@ -0,0 +1,34 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class IptEventType_tst {
+ @Test public void Has() {
+ tst_Has(IptEventType_.KeyDown, IptEventType_.KeyDown, true);
+ tst_Has(IptEventType_.KeyUp, IptEventType_.KeyDown, false);
+ tst_Has(IptEventType_.None, IptEventType_.KeyDown, false);
+ tst_Has(IptEventType_.KeyDown, IptEventType_.None, false);
+ tst_Has(IptEventType_.KeyDown.Add(IptEventType_.KeyUp), IptEventType_.KeyDown, true);
+ tst_Has(IptEventType_.MouseDown.Add(IptEventType_.MouseUp), IptEventType_.KeyDown, false);
+ tst_Has(IptEventType_.KeyDown.Add(IptEventType_.KeyUp), IptEventType_.None, false);
+ } void tst_Has(IptEventType val, IptEventType find, boolean expd) {Tfds.Eq(expd, IptEventType_.Has(val, find));}
+ @Test public void add_() {
+ tst_add(IptEventType_.KeyDown, IptEventType_.KeyDown, IptEventType_.KeyDown.Val());
+ tst_add(IptEventType_.KeyDown, IptEventType_.KeyUp, IptEventType_.KeyDown.Val() + IptEventType_.KeyUp.Val());
+ } void tst_add(IptEventType lhs, IptEventType rhs, int expd) {Tfds.Eq(expd, IptEventType_.add_(lhs, rhs).Val());}
+}
diff --git a/150_gfui/tst/gplx/gfui/ScreenAdp_tst.java b/150_gfui/tst/gplx/gfui/ScreenAdp_tst.java
new file mode 100644
index 000000000..f45e15ccc
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/ScreenAdp_tst.java
@@ -0,0 +1,29 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class ScreenAdp_tst {
+ @Test public void parse_() {
+ ScreenAdp actl = ScreenAdp_.parse_("{screen{0}");
+ Tfds.Eq(0, actl.Index());
+ }
+ @Test public void opposite_() {
+ ScreenAdp actl = ScreenAdp_.from_point_(PointAdp_.new_(2000, 2000));
+ Tfds.Eq(0, actl.Index());
+ }
+}
diff --git a/150_gfui/tst/gplx/gfui/TabBox_tst.java b/150_gfui/tst/gplx/gfui/TabBox_tst.java
new file mode 100644
index 000000000..ee19e1853
--- /dev/null
+++ b/150_gfui/tst/gplx/gfui/TabBox_tst.java
@@ -0,0 +1,131 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class TabBox_tst {
+// @Before public void setup() {
+// fx = TabBoxFxt.new_();
+// } TabBoxFxt fx;
+ @Test public void Add() {
+// fx.Make(1).tst_Selected("0").FetchBtnAt(0).tst_X(0);
+// fx.Make(3).tst_Selected("2").FetchBtnAt(2).tst_X(160);
+ }
+// @Test public void DelAt() {
+// fx.Make(2).DelAt(1).tst_Btns("0");
+// fx.Make(2).DelAt(0).tst_Btns("1");
+// fx.Make(3).DelAt(0).tst_Btns("1", "2");
+// fx.Make(3).DelAt(1).tst_Btns("0", "2");
+// fx.Make(3).DelAt(2).tst_Btns("0", "1");
+
+// fx.Make(3).Select(1).DelAt(1).tst_Selected("2"); // 1 deleted; 2 shifted down into slot
+// fx.Make(3).Select(1).DelAt(0).tst_Selected("1"); // 0 deleted; 1 still remains active (but will have idx of 0
+// fx.Make(3).Select(2).DelAt(2).tst_Selected("1"); // 2 deleted; 1 selected
+// }
+// @Test public void Selected_byAdd() {
+// fx.Make(2).Select(0).tst_Selected("0").Select(1).tst_Selected("1");
+// }
+// @Test public void Selected_byBtn() {
+// fx.Make(2).tst_Selected("1");
+//
+// GfuiBtn btn = fx.TabBox().SubBtnArea().FetchAt(0);
+// btn.Click();
+// fx.tst_Selected("0");
+// }
+// @Test public void ReorderTab() {
+// fx.Make(3).Reorder(0, -1).tst_Raised(false);
+// fx.Make(3).Reorder(2, 1).tst_Raised(false);
+// fx.Make(3).Reorder(0, 1).tst_Btns("1", "0", "2").tst_Raised(true).tst_FocusOrder();
+// fx.Make(3).Reorder(0, 2).tst_Btns("1", "2", "0").tst_Raised(true).tst_FocusOrder();
+// fx.Make(3).Reorder(2, -1).tst_Btns("0", "2", "1").tst_Raised(true).tst_FocusOrder();
+// fx.Make(3).Reorder(0, 1).Reorder(1, 2).tst_Btns("0", "2", "1").tst_Raised(true);//.tst_FocusOrder(); // FIXME: broken after FocusOrder set for entire form (instead of per container)
+// }
+}
+class GfuiElemFxt {
+ public GfuiElem UnderElem() {return underElem;} GfuiElem underElem;
+ @gplx.Internal protected GfuiElemFxt tst_X(int expd) {Tfds.Eq(expd, underElem.X()); return this;}
+ public static GfuiElemFxt new_(GfuiElem elem) {
+ GfuiElemFxt rv = new GfuiElemFxt();
+ rv.underElem = elem;
+ return rv;
+ } GfuiElemFxt() {}
+}
+class TabBoxFxt implements GfoInvkAble {
+ @gplx.Internal protected TabBox TabBox() {return tabBox;}
+ @gplx.Internal protected TabBoxFxt Make(int count) {
+ for (int i = 0; i < tabBox.Tabs_Count(); i++)
+ tabBox.Tabs_DelAt(0);
+ for (int i = 0; i < count; i++)
+ tabBox.Tabs_Add(Int_.XtoStr(i), Int_.XtoStr(i));
+ return this;
+ }
+ @gplx.Internal protected TabBoxFxt DelAt(int index) {tabBox.Tabs_DelAt(index); return this;}
+// @gplx.Internal protected TabBoxFxt Select(int index) {tabBox.Tabs_Select(index); return this;}
+ @gplx.Internal protected GfuiElemFxt FetchBtnAt(int index) {
+ GfuiBtn btn = (GfuiBtn)tabBox.BtnBox().SubElems().FetchAt(index);
+ GfuiElemFxt fx_elem = GfuiElemFxt.new_(btn);
+ return fx_elem;
+ }
+// @gplx.Internal protected TabBoxFxt tst_BtnX(int idx, int expdX) {
+// Tfds.Eq(expdX, tabBox.SubBtnArea().FetchAt(idx).X());
+// return this;
+// }
+ @gplx.Internal protected TabBoxFxt tst_Selected(String expd) {
+ TabPnlItm curTab = tabBox.Tabs_SelectedItm();
+ GfuiBtn btn = (GfuiBtn)tabBox.BtnBox().SubElems().FetchAt(curTab.Idx());
+ Tfds.Eq(expd, btn.Text());
+ return this;
+ }
+ @gplx.Internal protected TabBoxFxt tst_Btns(String... expd) {
+ String[] actl = new String[tabBox.Tabs_Count() ];
+ for (int i = 0; i < tabBox.Tabs_Count() ; i++) {
+ GfuiBtn button = (GfuiBtn)tabBox.BtnBox().SubElems().FetchAt(i);
+ actl[i] = button.TextMgr().Val();
+ }
+ Tfds.Eq_ary(expd, actl);
+ return this;
+ }
+// @gplx.Internal protected TabBoxFxt tst_Raised(boolean expd) {Tfds.Eq(expd, received != null); return this;}
+// @gplx.Internal protected TabBoxFxt Reorder(int i, int delta) {
+// tabBox.Width_(240); // needed for lytMgr
+// TabBnd_reorderTab reorderBnd = TabBnd_reorderTab._;
+// received = null;
+// TabPnl pnl = tabBox.Tabs_FetchAt(i);
+// reorderBnd.MoveTab(pnl.SubTabBtn(), delta);
+// return this;
+// }
+// @gplx.Internal protected TabBoxFxt tst_FocusOrder() {
+// for (int i = 0; i < tabBox.SubBtnArea().SubZones().FetchAt(0).Count(); i++) {
+// GfuiElem subBtn = (GfuiElem)tabBox.SubBtnArea().SubZones().FetchAt(0).FetchAt(i);
+// Tfds.Eq(i, subBtn.UnderElem().Core().Focus_index());
+// }
+// return this;
+// }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, OrderChangedReceived_cmd)) OrderChangedReceived(m);
+ else return GfoInvkAble_.Rv_unhandled;
+ return this;
+ } public static final String OrderChangedReceived_cmd = "OrderChangedReceived";
+ TabBox tabBox;
+ public static TabBoxFxt new_() {
+ TabBoxFxt rv = new TabBoxFxt();
+ rv.tabBox = TabBox_.new_();
+ return rv;
+ } TabBoxFxt() {}
+ void OrderChangedReceived(GfoMsg msg) {
+ } //int[] received = null;
+}
diff --git a/150_gfui/xtn/gplx/gfui/Swt_btn.java b/150_gfui/xtn/gplx/gfui/Swt_btn.java
new file mode 100644
index 000000000..74b3fa498
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_btn.java
@@ -0,0 +1,102 @@
+/*
+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.gfui; import gplx.*;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+class Swt_btn implements GxwElem, Swt_control {
+ private Button btn;
+ public Swt_btn(Swt_control owner, KeyValHash ctorArgs) {
+ btn = new Button(owner.Under_composite(), SWT.FLAT | SWT.PUSH);
+ core = new Swt_core_cmds(btn);
+ btn.addKeyListener(new Swt_lnr_key(this));
+ btn.addMouseListener(new Swt_lnr_mouse(this));
+ }
+ @Override public Control Under_control() {return btn;}
+ @Override public Control Under_menu_control() {return btn;}
+ @Override public String TextVal() {return btn.getText();} @Override public void TextVal_set(String v) {btn.setText(v);}
+ @Override public GxwCore_base Core() {return core;} GxwCore_base core;
+ @Override public GxwCbkHost Host() {return host;} @Override public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host;
+ @Override public Composite Under_composite() {return null;}
+ @Override public void EnableDoubleBuffering() {}
+ @Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return null;}
+}
+class Swt_btn_no_border implements GxwElem, Swt_control {
+ public Swt_btn_no_border(Swt_control owner_control, KeyValHash ctorArgs) {
+ Composite owner = owner_control.Under_composite();
+ Make_btn_no_border(owner.getDisplay(), owner.getShell(), owner);
+ core = new Swt_core_cmds(box_btn);
+ box_btn.addKeyListener(new Swt_lnr_key(this));
+ box_btn.addMouseListener(new Swt_lnr_mouse(this));
+ }
+ @Override public Control Under_control() {return box_btn;}
+ @Override public Control Under_menu_control() {return box_btn;}
+ @Override public String TextVal() {return box_btn.getText();} @Override public void TextVal_set(String v) {box_btn.setText(v);}
+ @Override public GxwCore_base Core() {return core;} Swt_core_cmds core;
+ @Override public GxwCbkHost Host() {return host;} @Override public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host;
+ @Override public Composite Under_composite() {return null;}
+ @Override public void EnableDoubleBuffering() {}
+ @Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, GfuiBtn.Invk_btn_img)) return btn_img;
+ else if (ctx.Match(k, GfuiBtn.Invk_btn_img_)) Btn_img_((ImageAdp)m.CastObj("v"));
+ return null;
+ }
+ void Btn_img_(ImageAdp v) {
+ if (box_btn == null || v == null) return;
+ SizeAdp size = core.Size();
+ int dif = 6;
+ box_btn.setImage((Image)v.Resize(size.Width() - dif, size.Height() - dif).Under());
+ }
+ ImageAdp btn_img;
+ Composite box_grp;
+ Label box_btn;
+ void Make_btn_no_border(Display display, Shell shell, Control owner) {
+ box_grp = new Composite(shell, SWT.FLAT);
+ box_btn = new Label(shell, SWT.FLAT);
+ box_btn.setSize(25, 25);
+ box_btn.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
+ box_btn.addFocusListener(new Swt_clabel_lnr_focus(box_grp));
+ }
+}
+class Swt_clabel_lnr_focus implements FocusListener {
+ public Swt_clabel_lnr_focus(Control v) {this.surrogate = v;} Control surrogate;
+ @Override public void focusGained(org.eclipse.swt.events.FocusEvent e) {
+ surrogate.forceFocus();
+ }
+ @Override public void focusLost(org.eclipse.swt.events.FocusEvent arg0) {}
+}
\ No newline at end of file
diff --git a/150_gfui/xtn/gplx/gfui/Swt_clipboard.java b/150_gfui/xtn/gplx/gfui/Swt_clipboard.java
new file mode 100644
index 000000000..8df569968
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_clipboard.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.gfui; import gplx.*;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+class Swt_clipboard implements Gfui_clipboard {
+ public Swt_clipboard(Display display) {
+ this.display = display;
+ clipboard = new Clipboard(display);
+ } Display display; Clipboard clipboard;
+ public void Copy(String v) {
+ if (String_.Len_eq_0(v)) return;
+ TextTransfer textTransfer = TextTransfer.getInstance();
+ clipboard.setContents(new Object[]{v}, new Transfer[]{textTransfer});
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Gfui_clipboard_.Invk_copy)) Send_key(IptKey_.Ctrl, 'C');
+ else if (ctx.Match(k, Gfui_clipboard_.Invk_select_all)) Send_key(IptKey_.Ctrl, 'A');
+ else return GfoInvkAble_.Rv_unhandled;
+ return this;
+ }
+ @Override public void Rls() {clipboard.dispose();}
+ int Xto_keycode(IptKey modifier) {
+ switch (modifier.Val()) {
+ case IptKey_.KeyCode_Ctrl: return SWT.CTRL;
+ case IptKey_.KeyCode_Alt: return SWT.ALT;
+ case IptKey_.KeyCode_Shift: return SWT.SHIFT;
+ default: return SWT.NONE;
+ }
+ }
+ public void Send_key(IptKey mod, char key_press_char) {
+ Event event = new Event();
+ int modifier_key_code = Xto_keycode(mod);
+ event.keyCode = modifier_key_code; event.type = SWT.KeyDown; display.post(event);
+ event.keyCode = 0; event.character = key_press_char; display.post(event);
+ event.type = SWT.KeyUp; display.post(event);
+ event.keyCode = modifier_key_code; event.character = 0; display.post(event);
+ }
+}
diff --git a/150_gfui/xtn/gplx/gfui/Swt_control.java b/150_gfui/xtn/gplx/gfui/Swt_control.java
new file mode 100644
index 000000000..c69da862b
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_control.java
@@ -0,0 +1,44 @@
+/*
+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.gfui;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+interface Swt_control extends GxwElem {
+ Control Under_control();
+ Composite Under_composite();
+ Control Under_menu_control();
+}
+class Swt_control_ {
+ public static void X_set(Control c, int v) {Point point = c.getLocation(); c.setLocation(v, point.y);}
+ public static void Y_set(Control c, int v) {Point point = c.getLocation(); c.setLocation(point.x, v);}
+ public static void W_set(Control c, int v) {Point point = c.getSize(); c.setSize(v, point.y);}
+ public static void H_set(Control c, int v) {Point point = c.getSize(); c.setSize(point.x, v);}
+ public static void Pos_set(Control c, PointAdp v) {c.setLocation(v.X(), v.Y());}
+ public static void Pos_set(Control c, int x, int y) {c.setLocation(x, y);}
+ public static void Size_set(Control c, SizeAdp v) {c.setSize(v.Width(), v.Height());}
+ public static void Size_set(Control c, int w, int h) {c.setSize(w, h);}
+ public static void Rect_set(Control c, RectAdp v) {c.setBounds(Xto_rectangle(v));}
+ public static void Rect_set(Control c, int x, int y, int w, int h) {c.setBounds(Xto_rectangle(x, y, w, h));}
+ public static void Rect_add(Control c, RectAdp v, int x, int y, int w, int h) {c.setBounds(Xto_rectangle(v.X() + x, v.Y() + y, v.Width() + w, v.Height()+ h));}
+ public static Rectangle Xto_rectangle(int x, int y, int w, int h) {return new Rectangle(x, y, w, h);}
+ public static Rectangle Xto_rectangle(RectAdp v) {return new Rectangle(v.X(), v.Y(), v.Width(), v.Height());}
+ public static Swt_control cast_or_fail(GfuiElem elem) {return (Swt_control)elem.UnderElem();}
+}
\ No newline at end of file
diff --git a/150_gfui/xtn/gplx/gfui/Swt_core_cmds.java b/150_gfui/xtn/gplx/gfui/Swt_core_cmds.java
new file mode 100644
index 000000000..f06092dd1
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_core_cmds.java
@@ -0,0 +1,243 @@
+/*
+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.gfui;
+import gplx.Err_;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+class Swt_core_cmds extends GxwCore_base {
+ public Swt_core_cmds(Control control) {
+ compositeAble = control instanceof Composite;
+ this.control = control;
+ } Control control; boolean compositeAble = false;
+ @Override public int Width() {return control.getSize().x;} @Override public void Width_set(int v) {if (Cfg_resize_disabled) return; control.setSize(v, this.Height());}
+ @Override public int Height() {return control.getSize().y;} @Override public void Height_set(int v) {if (Cfg_resize_disabled) return; control.setSize(this.Width(), v);}
+ @Override public int X() {return control.getLocation().x;} @Override public void X_set(int v) {control.setLocation(v, this.Y());}
+ @Override public int Y() {return control.getLocation().y;} @Override public void Y_set(int v) {control.setLocation(this.X(), v);}
+ @Override public SizeAdp Size() {return SizeAdp_.new_(this.Width(), this.Height());} @Override public void Size_set(SizeAdp v) {if (Cfg_resize_disabled) return; control.setSize(v.Width(), v.Height());}
+ @Override public PointAdp Pos() {return PointAdp_.new_(this.X(), this.Y());} @Override public void Pos_set(PointAdp v) {control.setLocation(v.X(), v.Y());}
+ @Override public RectAdp Rect() {return RectAdp_.new_(this.X(), this.Y(), this.Width(), this.Height());}
+ @Override public void Rect_set(RectAdp v) {
+ if (Cfg_resize_disabled)
+ control.setLocation(v.X(), v.Y());
+ else
+ control.setBounds(v.X(), v.Y(), v.Width(), v.Height());
+ }
+ @Override public boolean Visible() {return control.isVisible();}
+ @Override public void Visible_set(boolean v) {control.setVisible(v);}
+ @Override public ColorAdp BackColor() {return XtoColorAdp(control.getBackground());} @Override public void BackColor_set(ColorAdp v) {control.setBackground(XtoColor(v));}
+ @Override public ColorAdp ForeColor() {return XtoColorAdp(control.getForeground());} @Override public void ForeColor_set(ColorAdp v) {control.setForeground(XtoColor(v));}
+ public boolean Cfg_resize_disabled = false;
+ ColorAdp XtoColorAdp(Color v) {return ColorAdp_.new_(0, v.getRed(), v.getGreen(), v.getBlue());}
+ Color XtoColor(ColorAdp v) {return new Color(control.getDisplay(), v.Red(), v.Green(), v.Blue());}
+ @Override public FontAdp TextFont() {
+ if (prv_font != null) return prv_font;
+ prv_font = Swt_kit.Control_font_get(control.getFont(), this);
+ return prv_font;
+ } FontAdp prv_font;
+ @Override public void TextFont_set(FontAdp v) {
+ Swt_kit.Control_font_set(v, this, control);
+ prv_font = v;
+ }
+ @Override public String TipText() {return control.getToolTipText();} @Override public void TipText_set(String v) {control.setToolTipText(v);}
+ @Override public void Controls_add(GxwElem sub) {
+ if (!compositeAble) throw Err_.new_("cannot add sub to control");
+ Composite owner_as_composite = (Composite)control;
+ Swt_control sub_as_WxSwt = (Swt_control)sub;
+ Control sub_as_swt = sub_as_WxSwt.Under_control();
+ sub_as_swt.setParent(owner_as_composite);
+ }
+ @Override public void Controls_del(GxwElem sub) {
+ if (!compositeAble) throw Err_.new_("cannot add sub to control");
+ Swt_control sub_as_WxSwt = (Swt_control)sub;
+ Control sub_as_swt = sub_as_WxSwt.Under_control();
+ sub_as_swt.dispose(); // SWT_NOTE: no way to officially remove sub from control; can only dispose
+ }
+ @Override public boolean Focus_has() {return control.isFocusControl();}
+ @Override public boolean Focus_able() {return focus_able;} boolean focus_able;
+ @Override public void Focus_able_(boolean v) {focus_able = v;}
+ @Override public int Focus_index() {return focusIndex;} @Override public void Focus_index_set(int v) {focusIndex = v;} int focusIndex;
+ @Override public void Focus() {
+ if (Focus_able())
+ control.forceFocus();
+ }
+ @Override public void Select_exec() {
+ control.setFocus();
+ }
+ @Override public void Zorder_front() {
+// Canvas c; c.moveAbove(arg0);
+ }
+ @Override public void Zorder_back() {
+// Canvas c; c.moveBelow(arg0);
+ }
+ @Override public void Invalidate() {control.redraw(); control.update();}
+ @Override public void Dispose() {control.dispose();}
+}
+class Swt_core_cmds_dual extends GxwCore_base {
+ public Swt_core_cmds_dual(Composite outer, Control inner, int inner_adj_x, int inner_adj_y, int inner_adj_w, int inner_adj_h) {
+ this.outer = outer; this.inner = inner;
+ outer_is_composite = outer instanceof Composite;
+ this.inner_adj_x = inner_adj_x; this.inner_adj_y = inner_adj_y; this.inner_adj_w = inner_adj_w; this.inner_adj_h = inner_adj_h;
+ } Control outer, inner; boolean outer_is_composite = false; int inner_adj_x, inner_adj_y, inner_adj_w, inner_adj_h;
+ @Override public int X() {return outer.getLocation().x;} @Override public void X_set(int v) {Swt_control_.X_set(outer, v);}
+ @Override public int Y() {return outer.getLocation().y;} @Override public void Y_set(int v) {Swt_control_.Y_set(outer, v);}
+ @Override public int Width() {return outer.getSize().x;} @Override public void Width_set(int v) {Swt_control_.W_set(outer, v); Swt_control_.W_set(outer, v + inner_adj_w);}
+ @Override public int Height() {return outer.getSize().y;} @Override public void Height_set(int v) {Swt_control_.H_set(outer, v); Swt_control_.H_set(outer, v + inner_adj_h);}
+ @Override public SizeAdp Size() {return SizeAdp_.new_(this.Width(), this.Height());} @Override public void Size_set(SizeAdp v) {Swt_control_.Size_set(outer, v); Swt_control_.Size_set(inner, v.Width() + inner_adj_w, v.Height() + inner_adj_h);}
+ @Override public PointAdp Pos() {return PointAdp_.new_(this.X(), this.Y());} @Override public void Pos_set(PointAdp v) {Swt_control_.Pos_set(outer, v);}
+ @Override public RectAdp Rect() {return RectAdp_.new_(this.X(), this.Y(), this.Width(), this.Height());} @Override public void Rect_set(RectAdp v) {Swt_control_.Rect_set(outer, v); Swt_control_.Size_set(inner, v.Width() + inner_adj_w, v.Height() + inner_adj_h);}
+ @Override public boolean Visible() {return outer.isVisible();}
+ @Override public void Visible_set(boolean v) {outer.setVisible(v);}
+ @Override public ColorAdp BackColor() {return XtoColorAdp(inner.getBackground());} @Override public void BackColor_set(ColorAdp v) {inner.setBackground(XtoColor(v));}
+ @Override public ColorAdp ForeColor() {return XtoColorAdp(inner.getForeground());} @Override public void ForeColor_set(ColorAdp v) {inner.setForeground(XtoColor(v));}
+ ColorAdp XtoColorAdp(Color v) {return ColorAdp_.new_(0, v.getRed(), v.getGreen(), v.getBlue());}
+ Color XtoColor(ColorAdp v) {return new Color(outer.getDisplay(), v.Red(), v.Green(), v.Blue());}
+ @Override public FontAdp TextFont() {
+ if (prv_font != null) return prv_font;
+ prv_font = Swt_kit.Control_font_get(inner.getFont(), this);
+ return prv_font;
+ } FontAdp prv_font;
+ @Override public void TextFont_set(FontAdp v) {
+ Swt_kit.Control_font_set(v, this, inner);
+ prv_font = v;
+ }
+ @Override public String TipText() {return inner.getToolTipText();} @Override public void TipText_set(String v) {inner.setToolTipText(v);}
+ @Override public void Controls_add(GxwElem sub) {
+ if (!outer_is_composite) throw Err_.new_("cannot add sub to outer");
+ Composite owner_as_composite = (Composite)outer;
+ Swt_control sub_as_WxSwt = (Swt_control)sub;
+ Control sub_as_swt = sub_as_WxSwt.Under_control();
+ sub_as_swt.setParent(owner_as_composite);
+ }
+ @Override public void Controls_del(GxwElem sub) {
+ if (!outer_is_composite) throw Err_.new_("cannot add sub to outer");
+ Swt_control sub_as_WxSwt = (Swt_control)sub;
+ Control sub_as_swt = sub_as_WxSwt.Under_control();
+ sub_as_swt.dispose(); // SWT_NOTE: no way to officially remove sub from outer; can only dispose
+ }
+ @Override public boolean Focus_has() {return inner.isFocusControl();}
+ @Override public boolean Focus_able() {return focus_able;} boolean focus_able;
+ @Override public void Focus_able_(boolean v) {focus_able = v;}
+ @Override public int Focus_index() {return focusIndex;} @Override public void Focus_index_set(int v) {focusIndex = v;} int focusIndex;
+ @Override public void Focus() {
+ if (Focus_able())
+ inner.forceFocus();
+ }
+ @Override public void Select_exec() {
+ inner.setFocus();
+ }
+ @Override public void Zorder_front() {}
+ @Override public void Zorder_back() {}
+ @Override public void Invalidate() {outer.update(); inner.update();}
+ @Override public void Dispose() {outer.dispose(); inner.dispose();}
+}
+interface Swt_core_cmds_frames_itm {
+ Control Itm();
+ void Rect_set(int w, int h);
+}
+class Swt_core_cmds_frames_itm_manual implements Swt_core_cmds_frames_itm {
+ public Swt_core_cmds_frames_itm_manual(Control control, int x, int y, int w, int h) {
+ this.control = control; this.x = x; this.y = y; this.w = w; this.h = h;
+ } Control control; int x, y, w, h;
+ public Control Itm() {return control;}
+ public void Rect_set(int new_w, int new_h) {
+ Swt_control_.Rect_set(control, x, y, new_w + w, new_h + h);
+ }
+}
+class Swt_core_cmds_frames_itm_center_v implements Swt_core_cmds_frames_itm {
+ public Swt_core_cmds_frames_itm_center_v(Control control, Swt_text_w_border margin_owner) {this.control = control; this.margin_owner = margin_owner;} Control control; Swt_text_w_border margin_owner;
+ public Control Itm() {return control;}
+ public void Rect_set(int new_w, int new_h) {
+ int margin_t = margin_owner.margins_t;
+ int margin_b = margin_owner.margins_b;
+ Swt_control_.Rect_set(control, 0, margin_t, new_w, new_h - (margin_t + margin_b));
+ }
+}
+class Swt_core_cmds_frames extends GxwCore_base {
+ public Swt_core_cmds_frames(Composite outer, Swt_core_cmds_frames_itm[] frames) {
+ this.outer = outer; this.frames = frames;
+ frames_len = frames.length;
+ this.inner = frames[frames_len - 1].Itm();
+ } Composite outer; Control inner; Swt_core_cmds_frames_itm[] frames; int frames_len;
+ void Frames_w_set(int v) {
+ for (int i = 0; i < frames_len; i++)
+ frames[i].Rect_set(v, this.Height());
+ }
+ void Frames_h_set(int v) {
+ for (int i = 0; i < frames_len; i++)
+ frames[i].Rect_set(this.Width(), v);
+ }
+ void Frames_size_set(SizeAdp v) {
+ for (int i = 0; i < frames_len; i++)
+ frames[i].Rect_set(v.Width(), v.Height());
+ }
+ @Override public int X() {return outer.getLocation().x;} @Override public void X_set(int v) {Swt_control_.X_set(outer, v);}
+ @Override public int Y() {return outer.getLocation().y;} @Override public void Y_set(int v) {Swt_control_.Y_set(outer, v);}
+ @Override public int Width() {return outer.getSize().x;} @Override public void Width_set(int v) {Swt_control_.W_set(outer, v); Frames_w_set(v);}
+ @Override public int Height() {return outer.getSize().y;} @Override public void Height_set(int v) {Swt_control_.H_set(outer, v); Frames_h_set(v);}
+ @Override public SizeAdp Size() {return SizeAdp_.new_(this.Width(), this.Height());} @Override public void Size_set(SizeAdp v) {Swt_control_.Size_set(outer, v); Frames_size_set(v);}
+ @Override public PointAdp Pos() {return PointAdp_.new_(this.X(), this.Y());} @Override public void Pos_set(PointAdp v) {Swt_control_.Pos_set(outer, v);}
+ @Override public RectAdp Rect() {return RectAdp_.new_(this.X(), this.Y(), this.Width(), this.Height());} @Override public void Rect_set(RectAdp v) {Swt_control_.Rect_set(outer, v); Frames_size_set(v.Size());}
+ @Override public boolean Visible() {return outer.isVisible();}
+ @Override public void Visible_set(boolean v) {outer.setVisible(v);}
+ @Override public ColorAdp BackColor() {return XtoColorAdp(inner.getBackground());}
+ @Override public void BackColor_set(ColorAdp v) {
+ Color color = XtoColor(v);
+// outer.setBackground(color);
+ for (int i = 0; i < frames_len; i++)
+ frames[i].Itm().setBackground(color);
+ }
+ @Override public ColorAdp ForeColor() {return XtoColorAdp(inner.getForeground());} @Override public void ForeColor_set(ColorAdp v) {inner.setForeground(XtoColor(v));}
+ ColorAdp XtoColorAdp(Color v) {return ColorAdp_.new_(0, v.getRed(), v.getGreen(), v.getBlue());}
+ Color XtoColor(ColorAdp v) {return new Color(outer.getDisplay(), v.Red(), v.Green(), v.Blue());}
+ @Override public FontAdp TextFont() {
+ if (prv_font != null) return prv_font;
+ prv_font = Swt_kit.Control_font_get(inner.getFont(), this);
+ return prv_font;
+ } FontAdp prv_font;
+ @Override public void TextFont_set(FontAdp v) {
+ Swt_kit.Control_font_set(v, this, inner);
+ prv_font = v;
+ }
+ @Override public String TipText() {return inner.getToolTipText();} @Override public void TipText_set(String v) {inner.setToolTipText(v);}
+ @Override public void Controls_add(GxwElem sub) {throw Err_.not_implemented_();}
+ @Override public void Controls_del(GxwElem sub) {}
+ @Override public boolean Focus_has() {return inner.isFocusControl();}
+ @Override public boolean Focus_able() {return focus_able;} boolean focus_able;
+ @Override public void Focus_able_(boolean v) {focus_able = v;}
+ @Override public int Focus_index() {return focusIndex;} @Override public void Focus_index_set(int v) {focusIndex = v;} int focusIndex;
+ @Override public void Focus() {
+ if (Focus_able())
+ inner.forceFocus();
+ }
+ @Override public void Select_exec() {
+ inner.setFocus();
+ }
+ @Override public void Zorder_front() {}
+ @Override public void Zorder_back() {}
+ @Override public void Invalidate() {
+ inner.redraw();
+ inner.update();
+ }
+ @Override public void Dispose() {outer.dispose(); inner.dispose();}
+}
diff --git a/150_gfui/xtn/gplx/gfui/Swt_core_lnrs.java b/150_gfui/xtn/gplx/gfui/Swt_core_lnrs.java
new file mode 100644
index 000000000..2181329f0
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_core_lnrs.java
@@ -0,0 +1,139 @@
+/*
+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.gfui;
+import gplx.Byte_ascii;
+import gplx.Enm_;
+import gplx.Err_;
+import gplx.GfoEvMgr_;
+import gplx.GfoInvkAble_;
+import gplx.GfoMsg_;
+import gplx.GfsCtx;
+import gplx.String_;
+import gplx.Tfds;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ToolItem;
+class Swt_lnr_show implements Listener {
+ boolean shown = false;
+ @Override public void handleEvent(Event ev) {
+ if (shown) return;
+ win.Opened();
+ }
+ public Swt_lnr_show(Swt_win win) {this.win = win;} Swt_win win;
+}
+class Swt_lnr_resize implements Listener {
+ @Override public void handleEvent(Event ev) {
+// win.Host().SizeChangedCbk();
+ GfoEvMgr_.Pub((GfuiWin)win.Host(), Gfui_html.Evt_win_resized);
+ }
+ public Swt_lnr_resize(Swt_win win) {this.win = win;} Swt_win win;
+}
+class Swt_lnr_key implements KeyListener {
+ public Swt_lnr_key(GxwElem elem) {this.elem = elem;} GxwElem elem;
+// static int counter = 0;
+ @Override public void keyPressed(KeyEvent ev) {
+ IptEvtDataKey data = XtoKeyData(ev);
+ if (!elem.Host().KeyDownCbk(data)) {
+ ev.doit = false;
+ }
+ }
+ @Override public void keyReleased(KeyEvent ev) {
+ if (!elem.Host().KeyUpCbk(XtoKeyData(ev))) ev.doit = false;
+ }
+ IptEvtDataKey XtoKeyData(KeyEvent ev) {
+ int val = ev.keyCode;
+ switch (val) {
+ case Byte_ascii.CarriageReturn: val = 10; break; // enter key is 13 whereas .net/swing is 10
+ case Byte_ascii.Ltr_a: case Byte_ascii.Ltr_b: case Byte_ascii.Ltr_c: case Byte_ascii.Ltr_d: case Byte_ascii.Ltr_e:
+ case Byte_ascii.Ltr_f: case Byte_ascii.Ltr_g: case Byte_ascii.Ltr_h: case Byte_ascii.Ltr_i: case Byte_ascii.Ltr_j:
+ case Byte_ascii.Ltr_k: case Byte_ascii.Ltr_l: case Byte_ascii.Ltr_m: case Byte_ascii.Ltr_n: case Byte_ascii.Ltr_o:
+ case Byte_ascii.Ltr_p: case Byte_ascii.Ltr_q: case Byte_ascii.Ltr_r: case Byte_ascii.Ltr_s: case Byte_ascii.Ltr_t:
+ case Byte_ascii.Ltr_u: case Byte_ascii.Ltr_v: case Byte_ascii.Ltr_w: case Byte_ascii.Ltr_x: case Byte_ascii.Ltr_y: case Byte_ascii.Ltr_z:
+ val -= 32; // lowercase keys are transmitted as ascii value, instead of key value; EX: "a" is 97 instead of 65
+ break;
+ case 16777217: val = IptKey_.Up.Val(); break;
+ case 16777218: val = IptKey_.Down.Val(); break;
+ case 16777219: val = IptKey_.Left.Val(); break;
+ case 16777220: val = IptKey_.Right.Val(); break;
+ case 16777221: val = IptKey_.PageUp.Val(); break;
+ case 16777222: val = IptKey_.PageDown.Val(); break;
+ case 16777223: val = IptKey_.Home.Val(); break;
+ case 16777224: val = IptKey_.End.Val(); break;
+ case 16777226: val = IptKey_.F1.Val(); break;
+ case 16777227: val = IptKey_.F2.Val(); break;
+ case 16777228: val = IptKey_.F3.Val(); break;
+ case 16777229: val = IptKey_.F4.Val(); break;
+ case 16777230: val = IptKey_.F5.Val(); break;
+ case 16777231: val = IptKey_.F6.Val(); break;
+ case 16777232: val = IptKey_.F7.Val(); break;
+ case 16777233: val = IptKey_.F8.Val(); break;
+ case 16777234: val = IptKey_.F9.Val(); break;
+ case 16777235: val = IptKey_.F10.Val(); break;
+ case 16777236: val = IptKey_.F11.Val(); break;
+ case 16777237: val = IptKey_.F12.Val(); break;
+ case 16777300: val = IptKey_.ScrollLock.Val(); break;
+ case 16777301: val = IptKey_.Pause.Val(); break;
+ case 327680: val = IptKey_.Insert.Val(); break;
+ }
+ if (Has_ctrl(ev.stateMask)) val |= IptKey_.KeyCode_Ctrl;
+ if (Enm_.HasInt(ev.stateMask, IptKey_.KeyCode_Shift)) val |= IptKey_.KeyCode_Alt;
+ if (Enm_.HasInt(ev.stateMask, IptKey_.KeyCode_Ctrl)) val |= IptKey_.KeyCode_Shift;
+// Tfds.Write(String_.Format("val={4} keyCode={0} stateMask={1} keyLocation={2} character={3}", ev.keyCode, ev.stateMask, ev.keyLocation, ev.character, val));
+ return IptEvtDataKey.int_(val);
+ }
+ public static boolean Has_ctrl(int val) {return Enm_.HasInt(val, IptKey_.KeyCode_Alt);} // NOTE:SWT's ctrl constant is different from SWING's
+}
+class Swt_lnr_mouse implements MouseListener {
+ public Swt_lnr_mouse(GxwElem elem) {this.elem = elem;} GxwElem elem;
+ @Override public void mouseDown(MouseEvent ev) {elem.Host().MouseDownCbk(XtoMouseData(ev));}
+ @Override public void mouseUp(MouseEvent ev) {elem.Host().MouseUpCbk(XtoMouseData(ev));}
+ @Override public void mouseDoubleClick(MouseEvent ev) {}
+ IptEvtDataMouse XtoMouseData(MouseEvent ev) {
+ IptMouseBtn btn = null;
+ switch (ev.button) {
+ case 1: btn = IptMouseBtn_.Left; break;
+ case 2: btn = IptMouseBtn_.Middle; break;
+ case 3: btn = IptMouseBtn_.Right; break;
+ case 4: btn = IptMouseBtn_.X1; break;
+ case 5: btn = IptMouseBtn_.X2; break;
+ }
+ return IptEvtDataMouse.new_(btn, IptMouseWheel_.None, ev.x, ev.y);
+ }
+// private static int X_to_swing(int v) {
+// switch (v) {
+// case gplx.gfui.IptMouseBtn_.Tid_left : return java.awt.event.InputEvent.BUTTON1_MASK;
+// case gplx.gfui.IptMouseBtn_.Tid_middle : return java.awt.event.InputEvent.BUTTON2_MASK;
+// case gplx.gfui.IptMouseBtn_.Tid_right : return java.awt.event.InputEvent.BUTTON3_MASK;
+// default : throw Err_.unhandled(v);
+// }
+// }
+}
+class Swt_lnr_toolitem implements Listener {
+ public Swt_lnr_toolitem(ToolItem itm, GxwElem elem) {this.itm = itm; this.elem = elem;} ToolItem itm; GxwElem elem;
+ @Override public void handleEvent(Event arg0) {
+ Rectangle rect = itm.getBounds();
+ elem.Host().MouseUpCbk(IptEvtDataMouse.new_(IptMouseBtn_.Left, IptMouseWheel_.None, rect.x, rect.y));
+ }
+}
\ No newline at end of file
diff --git a/150_gfui/xtn/gplx/gfui/Swt_demo_main.java b/150_gfui/xtn/gplx/gfui/Swt_demo_main.java
new file mode 100644
index 000000000..29a78b88a
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_demo_main.java
@@ -0,0 +1,199 @@
+/*
+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.gfui;
+import org.eclipse.swt.*;
+import org.eclipse.swt.browser.*;
+import org.eclipse.swt.custom.*;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+public class Swt_demo_main {
+ public static void main(String[] args) {
+// Drag_drop();
+// List_fonts();
+ keystrokes(args);
+ }
+ static void Drag_drop() {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout());
+ final CTabFolder folder = new CTabFolder(shell, SWT.BORDER);
+ folder.setLayoutData(new GridData(GridData.FILL_BOTH));
+ for (int i = 0; i < 10; i++) {
+ CTabItem item = new CTabItem(folder, SWT.NONE);
+ item.setText("item "+i);
+ Text text = new Text(folder, SWT.BORDER | SWT.MULTI | SWT.VERTICAL);
+ text.setText("Text control for "+i);
+ item.setControl(text);
+ if (i == 9) {
+ item.setShowClose(false);
+ item.setText("+");
+// item.setImage(new Image(Display.getDefault(), "J:\\gplx\\xowa\\user\\anonymous\\app\\img\\edit\\format-bold-A.png"));
+ }
+ }
+ ToolBar t = new ToolBar( folder, SWT.FLAT );
+ ToolItem i = new ToolItem( t, SWT.PUSH );
+ i.setText( "add" );
+ folder.setTopRight( t, SWT.RIGHT );
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ display.dispose();
+ }
+ static void keystrokes(String[] args)
+ {
+
+ Display display = new Display ();
+
+ final Shell shell = new Shell (display);
+
+// display.addFilter(SWT.KeyDown, new Listener() {
+//
+// public void handleEvent(Event e) {
+// if(((e.stateMask & SWT.CTRL) == SWT.CTRL) && (e.keyCode == 'f'))
+// {
+// System.out.println("From Display I am the Key down !!" + e.keyCode);
+// }
+// }
+// });
+ shell.addKeyListener(new KeyListener() {
+ public void keyReleased(KeyEvent e) {
+// if(((e.stateMask & SWT.CTRL) == SWT.CTRL) && (e.keyCode == 'f'))
+// {
+// shell.setBackground(orig);
+// System.out.println("Key up !!");
+// }
+ System.out.println(e.stateMask + " " + e.keyCode);
+ }
+ public void keyPressed(KeyEvent e) {
+// System.out.println(e.stateMask + " " + e.keyCode);
+ }
+ });
+ shell.addMouseListener(new MouseListener() {
+ @Override
+ public void mouseUp(MouseEvent arg0) {
+ // TODO Auto-generated method stub
+ System.out.println(arg0.button);
+ }
+
+ @Override
+ public void mouseDown(MouseEvent arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void mouseDoubleClick(MouseEvent arg0) {
+ // TODO Auto-generated method stub
+
+ }
+ });
+
+ shell.setSize (200, 200);
+ shell.open ();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch ()) display.sleep ();
+ }
+ display.dispose ();
+
+ }
+ static void List_fonts() {
+ java.awt.GraphicsEnvironment e = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment();
+ java.awt.Font[] fonts = e.getAllFonts(); // Get the fonts
+ for (java.awt.Font f : fonts) {
+ System.out.println(f.getFontName());
+ }
+ }
+ static void Permission_denied() {
+ String html
+ = "\n"
+ + "\n"
+ + "\n"
+ + "\n"
+ + "\n"
+ + " click to call permissionDeniedExample -> will throw error and not show sel.rangeCount \n"
+ + " click to call permissionDeniedExample inside a setTimeout -> will show sel.rangeCount \n"
+ + "\n"
+ + "\n"
+ ;
+
+ System.setProperty
+ ( "org.eclipse.swt.browser.XULRunnerPath"
+ // ADJUST THIS PATH AS NECESSARY ON YOUR MACHINE
+ , "C:\\xowa\\bin\\windows\\xulrunner"
+ );
+ Display display = new Display();
+ Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+ final Browser browser;
+ try {
+ browser = new Browser(shell, SWT.MOZILLA); // changed from none
+ browser.addLocationListener(new LocationListener() {
+ @Override
+ public void changing(LocationEvent arg0) {
+ if (arg0.location.equals("about:blank")) return;
+ arg0.doit = false;
+ }
+
+ @Override
+ public void changed(LocationEvent arg0) {
+ String location = arg0.location;
+ if (location.equals("about:blank")) return;
+
+ // build code
+ String code = "alert('unknown_link:" + location + "')";
+ if (location.contains("direct_call_fails"))
+ code = "permissionDeniedExample();";
+ else if (location.contains("wrapped_call_works"))
+ code = "setTimeout(function(){permissionDeniedExample();}, 1);";
+
+ // evaluate code
+ try {
+ browser.evaluate(code);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ arg0.doit = false;
+ }
+ });
+ } catch (SWTError e) {
+ System.out.println("Could not instantiate Browser: " + e.getMessage());
+ display.dispose();
+ return;
+ }
+ browser.setText(html);
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ display.dispose();
+ }
+}
diff --git a/150_gfui/xtn/gplx/gfui/Swt_dlg_msg.java b/150_gfui/xtn/gplx/gfui/Swt_dlg_msg.java
new file mode 100644
index 000000000..784327479
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_dlg_msg.java
@@ -0,0 +1,96 @@
+/*
+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.gfui; import gplx.*;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.swt.SWT;
+class Swt_dlg_file implements Gfui_dlg_file {
+ private FileDialog under;
+ public Swt_dlg_file(byte type, Shell shell) {
+ int file_dialog_type
+ = type == Gfui_kit_.File_dlg_type_save
+ ? SWT.SAVE
+ : SWT.OPEN
+ ;
+ under = new FileDialog(shell, file_dialog_type);
+ }
+ public Gfui_dlg_file Init_msg_(String v) {under.setText(v); return this;}
+ public Gfui_dlg_file Init_file_(String v) {under.setFileName(v); return this;}
+ public Gfui_dlg_file Init_dir_(Io_url v) {under.setFilterPath(v.Xto_api()); return this;}
+ public Gfui_dlg_file Init_exts_(String... v) {under.setFilterExtensions(v); return this;}
+ public String Ask() {return under.open();}
+}
+class Swt_dlg_msg implements Gfui_dlg_msg, Runnable {
+ public Swt_dlg_msg(Shell shell) {this.shell = shell;} Shell shell;
+ public Gfui_dlg_msg Init_msg_(String v) {msg = v; return this;} String msg;
+ public Gfui_dlg_msg Init_ico_(int v) {ico = Xto_swt_ico(v); return this;} int ico = -1;
+ public Gfui_dlg_msg Init_btns_(int... ary) {
+ int ary_len = ary.length;
+ btns = -1;
+ for (int i = 0; i < ary_len; i++) {
+ int swt_btn = Xto_swt_btn(ary[i]);
+ if (btns == -1) btns = swt_btn;
+ else btns |= swt_btn;
+ }
+ return this;
+ } int btns = -1;
+ public int Ask_rslt;
+ @Override public void run() {
+ Ask_rslt = this.Ask();
+ }
+ public boolean Ask(int expd) {return Ask() == expd;}
+ public int Ask() {
+ int ctor_ico = ico == -1 ? SWT.ICON_INFORMATION : ico;
+ int ctor_btn = btns == -1 ? SWT.OK : btns;
+ MessageBox mb = new MessageBox(shell, ctor_ico | ctor_btn);
+ if (msg != null) mb.setMessage(msg);
+ int rv = mb.open();
+ return Xto_gfui_btn(rv);
+ }
+ int Xto_swt_ico(int v) {
+ switch (v) {
+ case Gfui_dlg_msg_.Ico_error: return SWT.ICON_ERROR;
+ case Gfui_dlg_msg_.Ico_information: return SWT.ICON_INFORMATION;
+ case Gfui_dlg_msg_.Ico_question: return SWT.ICON_QUESTION;
+ case Gfui_dlg_msg_.Ico_warning: return SWT.ICON_WARNING;
+ case Gfui_dlg_msg_.Ico_working: return SWT.ICON_WORKING;
+ default: throw Err_mgr._.unhandled_(v);
+ }
+ }
+ int Xto_swt_btn(int v) {
+ switch (v) {
+ case Gfui_dlg_msg_.Btn_ok: return SWT.OK;
+ case Gfui_dlg_msg_.Btn_yes: return SWT.YES;
+ case Gfui_dlg_msg_.Btn_no: return SWT.NO;
+ case Gfui_dlg_msg_.Btn_ignore: return SWT.IGNORE;
+ case Gfui_dlg_msg_.Btn_abort: return SWT.ABORT;
+ case Gfui_dlg_msg_.Btn_cancel: return SWT.CANCEL;
+ default: throw Err_mgr._.unhandled_(v);
+ }
+ }
+ int Xto_gfui_btn(int v) {
+ switch (v) {
+ case SWT.OK: return Gfui_dlg_msg_.Btn_ok;
+ case SWT.YES: return Gfui_dlg_msg_.Btn_yes;
+ case SWT.NO: return Gfui_dlg_msg_.Btn_no;
+ case SWT.IGNORE: return Gfui_dlg_msg_.Btn_ignore;
+ case SWT.ABORT: return Gfui_dlg_msg_.Btn_abort;
+ case SWT.CANCEL: return Gfui_dlg_msg_.Btn_cancel;
+ default: throw Err_mgr._.unhandled_(v);
+ }
+ }
+}
diff --git a/150_gfui/xtn/gplx/gfui/Swt_html.java b/150_gfui/xtn/gplx/gfui/Swt_html.java
new file mode 100644
index 000000000..50dd303ba
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_html.java
@@ -0,0 +1,263 @@
+/*
+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.gfui;
+import gplx.*;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+class Swt_html implements Gxw_html, Swt_control, FocusListener {
+ private Swt_html_lnr_location lnr_location; private Swt_html_lnr_status lnr_status;
+ public Swt_html(Swt_kit kit, Swt_control owner_control, KeyValHash ctorArgs) {
+ this.kit = kit;
+ lnr_location = new Swt_html_lnr_location(this);
+ lnr_status = new Swt_html_lnr_status(this);
+ int browser_type = Swt_html.Browser_tid_none;
+ Object browser_type_obj = ctorArgs.FetchValOr(Swt_kit.Cfg_Html_BrowserType, null);
+ if (browser_type_obj != null) browser_type = Int_.cast_(browser_type_obj);
+ browser = new Browser(owner_control.Under_composite(), browser_type);
+ core = new Swt_core_cmds_html(this, browser);
+ browser.addKeyListener(new Swt_lnr_key(this));
+ browser.addMouseListener(new Swt_html_lnr_mouse(this, browser, kit));
+ browser.addLocationListener(lnr_location);
+ browser.addProgressListener(new Swt_html_lnr_progress(this));
+ browser.addStatusTextListener(lnr_status);
+ browser.addFocusListener(this);
+ browser.addTitleListener(new Swt_html_lnr_title(this));
+// browser.addTraverseListener(new Swt_html_lnr_Traverse(this));
+ }
+ public Swt_kit Kit() {return kit;} private Swt_kit kit;
+ @Override public Control Under_control() {return browser;} private Browser browser;
+ @Override public Composite Under_composite() {return null;}
+ @Override public Control Under_menu_control() {return browser;}
+ public String Html_doc_html() {return Eval_script_as_str(kit.Html_cfg().Doc_html());}
+ public void Html_doc_html_(String s) {browser.setText(s);} // DBG: Io_mgr._.SaveFilStr(Io_url_.new_fil_("C:\\temp.txt"), s)
+ public String Html_doc_selected_get_text_or_href() {return Eval_script_as_str(kit.Html_cfg().Doc_selected_get_text_or_href());}
+ public String Html_doc_selected_get_href_or_text() {return Eval_script_as_str(kit.Html_cfg().Doc_selected_get_href_or_text());}
+ public String Html_doc_selected_get_src_or_empty() {return Eval_script_as_str(kit.Html_cfg().Doc_selected_get_src_or_empty());}
+ public void Html_doc_body_focus() {Eval_script_as_exec(kit.Html_cfg().Doc_body_focus());}
+ public String Html_elem_atr_get_str(String elem_id, String atr_key) {return Eval_script_as_str(kit.Html_cfg().Elem_atr_get(elem_id, atr_key));}
+ public boolean Html_elem_atr_get_bool(String elem_id, String atr_key) {return Bool_.parse_((String)Eval_script(kit.Html_cfg().Elem_atr_get_toString(elem_id, atr_key)));}
+ public Object Html_elem_atr_get_obj(String elem_id, String atr_key) {return Eval_script(kit.Html_cfg().Elem_atr_get(elem_id, atr_key));}
+ public boolean Html_elem_atr_set(String elem_id, String atr_key, String atr_val){return Eval_script_as_exec(kit.Html_cfg().Elem_atr_set(elem_id, atr_key, Escape_quotes(atr_val)));}
+ public boolean Html_elem_atr_set_append(String elem_id, String atr_key, String atr_val)
+ {return Eval_script_as_exec(kit.Html_cfg().Elem_atr_set_append(elem_id, atr_key, Escape_quotes(atr_val)));}
+ public boolean Html_elem_delete(String elem_id) {return Eval_script_as_exec(kit.Html_cfg().Elem_delete(elem_id));}
+ public boolean Html_elem_replace_html(String id, String html) {return Eval_script_as_exec(kit.Html_cfg().Elem_replace_html(id, html));}
+ public boolean Html_gallery_packed_exec() {return Eval_script_as_exec(kit.Html_cfg().Gallery_packed_exec());}
+ public boolean Html_elem_focus(String elem_id) {return Eval_script_as_exec(kit.Html_cfg().Elem_focus(elem_id));}
+ public boolean Html_elem_scroll_into_view(String id) {return Eval_script_as_bool(kit.Html_cfg().Elem_scroll_into_view(Escape_quotes(id)));}
+ public String Html_window_vpos() {return Eval_script_as_str(kit.Html_cfg().Window_vpos());}
+ public boolean Html_window_print_preview() {return Eval_script_as_bool(kit.Html_cfg().Window_print_preview());}
+ public void Html_js_enabled_(boolean v) {browser.setJavascriptEnabled(v);}
+ public void Html_js_cbks_add(String func_name, GfoInvkAble invk) {new Swt_html_func(browser, func_name, invk);}
+ public String Html_js_eval_script(String script) {return Eval_script_as_str(script);}
+ public boolean Html_elem_img_update(String elem_id, String elem_src, int elem_width, int elem_height) {
+ elem_src = Escape_quotes(elem_src);
+ return Eval_script_as_bool(kit.Html_cfg().Elem_img_update(elem_id, elem_src, elem_width, elem_height));
+ }
+ public String Html_active_atr_get_str(String atr_key, String or) {
+ Object rv_obj = Eval_script(kit.Html_cfg().Active_atr_get_str(atr_key));
+ String rv = (String)rv_obj;
+ return rv == null || !eval_rslt.Result_pass() ? or : rv;
+ }
+ public void Html_js_eval_proc(String proc, String... args) {
+ Bry_fmtr fmtr = kit.Html_cfg().Js_scripts_get(proc);
+ String script = fmtr.Bld_str_many(args);
+ Eval_script(script);
+ }
+ public boolean Html_window_vpos_(String v) {
+ Gfui_html_cfg.Html_window_vpos_parse(v, scroll_top, node_path);
+ return Eval_script_as_exec(kit.Html_cfg().Window_vpos_(node_path.Val(), scroll_top.Val()));
+ } private String_obj_ref scroll_top = String_obj_ref.null_(), node_path = String_obj_ref.null_();
+ public boolean Html_doc_find(String elem_id, String find, boolean dir_fwd, boolean case_match, boolean wrap_find) {
+ if (String_.Eq(find, String_.Empty)) return false;
+ find = String_.Replace(find, "\\", "\\\\"); // escape \ -> \\
+ find = String_.Replace(find, "'", "\\'"); // escape ' -> \'; NOTE: \\' instead of \'
+ boolean search_text_is_diff = !String_.Eq(find, prv_find_str);
+ prv_find_str = find;
+ String script = String_.Eq(elem_id, Gfui_html.Elem_id_body)
+ ? kit.Html_cfg().Doc_find_html(find, dir_fwd, case_match, wrap_find, search_text_is_diff, prv_find_bgn)
+ : kit.Html_cfg().Doc_find_edit(find, dir_fwd, case_match, wrap_find, search_text_is_diff, prv_find_bgn);
+ Object result_obj = Eval_script(script);
+ try {prv_find_bgn = (int)Double_.cast_(result_obj);}
+ catch (Exception e) {Err_.Noop(e); return false;}
+ return true;
+ } private String prv_find_str = ""; private int prv_find_bgn;
+ public void Html_invk_src_(GfoEvObj invk) {lnr_location.Host_set(invk); lnr_status.Host_set(invk);}
+ private String Escape_quotes(String v) {return String_.Replace(String_.Replace(v, "'", "\\'"), "\"", "\\\"");}
+ @Override public GxwCore_base Core() {return core;} private GxwCore_base core;
+ @Override public GxwCbkHost Host() {return host;} @Override public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host;
+ @Override public String TextVal() {return browser.getText();}
+ @Override public void TextVal_set(String v) {browser.setText(v);}
+ @Override public void EnableDoubleBuffering() {}
+ @Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return GfoInvkAble_.Rv_unhandled;}
+ private boolean Eval_script_as_bool(String script) {
+ Object result_obj = Eval_script(script);
+ return eval_rslt.Result_pass() && Bool_.cast_or_(result_obj, false);
+ }
+ private boolean Eval_script_as_exec(String script) {Eval_script(script); return eval_rslt.Result_pass();}
+ private String Eval_script_as_str(String script) {return (String)Eval_script(script);}
+ public Object Eval_script(String script) {
+ eval_rslt.Clear();
+ try {
+ eval_rslt.Result_set(browser.evaluate(script));
+ return eval_rslt.Result();
+ }
+ catch (Exception e) {eval_rslt.Error_set(e.getMessage()); return eval_rslt.Error();}
+ } private Swt_html_eval_rslt eval_rslt = new Swt_html_eval_rslt();
+ @Override public void focusGained(FocusEvent arg0) {
+// if (!focus_acquired && Swt_kit.Html_box_focus_automatically) {
+// browser.forceFocus();
+// focus_acquired = true;
+// HtmlBox_focus();
+// }
+ } //boolean focus_acquired = false;
+ @Override public void focusLost(FocusEvent arg0) {
+// focus_acquired = false;
+ }
+ public static final int
+ Browser_tid_none = SWT.NONE
+ , Browser_tid_mozilla = SWT.MOZILLA
+ , Browser_tid_webKit = SWT.WEBKIT
+ ;
+}
+class Swt_core_cmds_html extends Swt_core_cmds {
+ public Swt_core_cmds_html(Swt_html html_box, Control control) {super(control); this.html_box = html_box;} Swt_html html_box;
+ @Override public void Focus() {
+ if (Focus_able())
+ control.forceFocus();
+ }
+ @Override public void Select_exec() {
+ this.Focus();
+ }
+}
+class Swt_html_eval_rslt {
+ public void Clear() {error = null; result = null;}
+ public boolean Result_pass() {return error == null;}
+ public Object Result() {return result;} public void Result_set(Object v) {result = v; error = null;} Object result;
+ public String Error () {return error;} public void Error_set(String v) {error = v; result = null;} String error;
+}
+class Swt_html_lnr_Traverse implements TraverseListener {
+ public Swt_html_lnr_Traverse(Swt_html html_box) {this.html_box = html_box;} Swt_html html_box;
+ @Override public void keyTraversed(TraverseEvent arg0) {}
+}
+class Swt_html_lnr_title implements TitleListener {
+ public Swt_html_lnr_title(Swt_html html_box) {this.html_box = html_box;} Swt_html html_box;
+ @Override public void changed(TitleEvent ev) {
+ try {UsrDlg_._.Note(ev.title);}
+ catch (Exception e) {html_box.Kit().Ask_ok("xowa.swt.html_box", "title.fail", Err_.Message_gplx_brief(e));} // NOTE: must catch error or will cause app to lock; currently called inside displaySync
+ }
+}
+class Swt_html_func extends BrowserFunction {
+ public Swt_html_func(Browser browser, String name, GfoInvkAble invk) {
+ super (browser, name);
+ this.browser = browser;
+ this.invk = invk;
+ } Browser browser; GfoInvkAble invk;
+ public Object function (Object[] args) {
+ try {
+ return gplx.gfui.Gfui_html.Js_args_exec(invk, args);
+ }
+ catch (Exception e) {
+ return Err_.Message_gplx_brief(e);
+ }
+ }
+}
+class Swt_html_lnr_status implements StatusTextListener {
+ public Swt_html_lnr_status(Swt_html html_box) {this.html_box = html_box;} Swt_html html_box;
+ public void Host_set(GfoEvObj host) {this.host = host;} GfoEvObj host;
+ @Override public void changed(StatusTextEvent ev) {
+ if (html_box.Kit().Mode_is_shutdown())
+ return; // shutting down raises status changed events; ignore, else SWT exception thrown; DATE:2014-05-29
+ String ev_text = ev.text;
+// if (String_.Has(ev_text, "Loading [MathJax]")) return; // suppress MathJax messages; // NOTE: disabled for 2.1 (which no longer outputs messages to status); DATE:2013-05-03
+ try {if (host != null) GfoEvMgr_.PubObj(host, Gfui_html.Evt_link_hover, "v", ev_text);}
+ catch (Exception e) {html_box.Kit().Ask_ok("xowa.gui.html_box", "status.fail", Err_.Message_gplx_brief(e));} // NOTE: must catch error or will cause app to lock; currently called inside displaySync
+ }
+}
+class Swt_html_lnr_progress implements ProgressListener {
+ public Swt_html_lnr_progress(Swt_html html_box) {this.html_box = html_box;} Swt_html html_box;
+ @Override public void changed(ProgressEvent arg0) {}
+ @Override public void completed(ProgressEvent arg0) {
+// UsrDlg_._.Note("done");
+ }
+}
+class Swt_html_lnr_location implements LocationListener {
+ public Swt_html_lnr_location(Swt_html html_box) {this.html_box = html_box;} Swt_html html_box;
+ public void Host_set(GfoEvObj host) {this.host = host;} GfoEvObj host;
+ @Override public void changed(LocationEvent arg) {Pub_evt(arg, Gfui_html.Evt_location_changed);}
+ @Override public void changing(LocationEvent arg) {Pub_evt(arg, Gfui_html.Evt_location_changing);}
+ void Pub_evt(LocationEvent arg, String evt) {
+ String location = arg.location;
+ if (String_.Eq(location, "about:blank")) return; // location changing event fires once when page is loaded; ignore
+ try {
+ GfoEvMgr_.PubObj(host, evt, "v", location);
+ arg.doit = false; // cancel navigation event, else there will be an error when trying to go to invalid location
+ }
+ catch (Exception e) {html_box.Kit().Ask_ok("xowa.gui.html_box", evt, Err_.Message_gplx_brief(e));} // NOTE: must catch error or will cause app to lock; currently called inside displaySync
+ }
+}
+class Swt_html_lnr_mouse implements MouseListener {
+ public Swt_html_lnr_mouse(GxwElem elem, Browser browser, Swt_kit kit) {this.elem = elem; this.browser = browser; this.kit = kit;} GxwElem elem; Browser browser; Swt_kit kit;
+ @Override public void mouseDown(MouseEvent ev) {
+ if (Is_at_scrollbar_area()) return;
+ elem.Host().MouseDownCbk(XtoMouseData(ev));
+ }
+ @Override public void mouseUp(MouseEvent ev) {
+ if (Is_at_scrollbar_area()) return;
+ elem.Host().MouseUpCbk(XtoMouseData(ev));
+ }
+ boolean Is_at_scrollbar_area() {
+ // WORKAROUND.SWT: SEE:NOTE_1:browser scrollbar and click
+ Point browser_size = browser.getSize();
+ Point click_pos = kit.Swt_display().getCursorLocation();
+ return click_pos.x >= browser_size.x - 12;
+ }
+ @Override public void mouseDoubleClick(MouseEvent ev) {}
+ IptEvtDataMouse XtoMouseData(MouseEvent ev) {
+ IptMouseBtn btn = null;
+ switch (ev.button) {
+ case 1: btn = IptMouseBtn_.Left; break;
+ case 2: btn = IptMouseBtn_.Middle; break;
+ case 3: btn = IptMouseBtn_.Right; break;
+ case 4: btn = IptMouseBtn_.X1; break;
+ case 5: btn = IptMouseBtn_.X2; break;
+ }
+ return IptEvtDataMouse.new_(btn, IptMouseWheel_.None, ev.x, ev.y);
+ }
+}
+/*
+NOTE_1:browser scrollbar and click
+a click in the scrollbar area will raise a mouse-down/mouse-up event in content-editable mode
+. a click should be consumed by the scrollbar and not have any effect elsewhere on the window
+. instead, a click event is raised, and counted twice
+ 1) for the scroll bar this will scroll the area.
+ 2) for the window. if keyboard-focus is set on a link, then it will activate the link.
+
+swt does not expose any scrollbar information (visible, width), b/c the scrollbar is controlled by the underlying browser
+so, assume:
+. scrollbar is always present
+. scrollbar has arbitrary width (currently 12)
+. and discard if click is in this scrollbar area
+
+two issues still occur with the workaround
+1) even if the scrollbar is not present, any click on the right-hand edge of the screen will be ignored
+2) click -> hold -> move mouse over to left -> release; the mouse up should be absorbed, but it is not due to position of release
+*/
diff --git a/150_gfui/xtn/gplx/gfui/Swt_img.java b/150_gfui/xtn/gplx/gfui/Swt_img.java
new file mode 100644
index 000000000..04752a8ce
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_img.java
@@ -0,0 +1,47 @@
+/*
+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.gfui; import gplx.*;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+class Swt_img implements ImageAdp {
+ public Swt_img(Gfui_kit kit, Image under, int w, int h) {this.kit = kit; this.under = under; this.width = w; this.height = h;}
+ public Gfui_kit Kit() {return kit;} Gfui_kit kit;
+ public SizeAdp Size() {if (size == null) size = SizeAdp_.new_(width, height); return size;} SizeAdp size;
+ public int Width() {return width;} int width;
+ public int Height() {return height;} int height;
+ public Io_url Url() {return url;} public ImageAdp Url_(Io_url v) {url = v; return this;} Io_url url = Io_url_.Null;
+ public Object Under() {return under;} Image under;
+ public boolean Disposed() {return under.isDisposed();}
+ public void Rls() {under.dispose();}
+ public void SaveAsBmp(Io_url url) {throw Err_.not_implemented_();}
+ public void SaveAsPng(Io_url url) {throw Err_.not_implemented_();}
+ public ImageAdp Resize(int trg_w, int trg_h) {return Extract_image(0, 0, width, height, trg_w, trg_h);}
+ public ImageAdp Extract_image(RectAdp src_rect, SizeAdp trg_size) {return Extract_image(src_rect.X(), src_rect.Y(), src_rect.Width(), src_rect.Height(), trg_size.Width(), trg_size.Height());}
+ public ImageAdp Extract_image(int src_x, int src_y, int src_w, int src_h, int trg_w, int trg_h) {
+ Image trg_img = new Image(Display.getDefault(), trg_w, trg_h);
+ GC gc = new GC(trg_img);
+ gc.setAntialias(SWT.ON);
+ gc.setInterpolation(SWT.HIGH);
+ gc.drawImage(under, src_x, src_y, src_w, src_h, 0, 0, trg_w, trg_h);
+ gc.dispose();
+ return new Swt_img(kit, trg_img, trg_w, trg_h);
+ }
+}
diff --git a/150_gfui/xtn/gplx/gfui/Swt_popup_grp.java b/150_gfui/xtn/gplx/gfui/Swt_popup_grp.java
new file mode 100644
index 000000000..4c590450f
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_popup_grp.java
@@ -0,0 +1,220 @@
+/*
+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.gfui; import java.security.acl.Owner;
+
+import gplx.*;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.events.MenuDetectEvent;
+import org.eclipse.swt.events.MenuDetectListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Decorations;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+class Swt_popup_grp implements Gfui_mnu_grp {
+ private Decorations owner_win; private Control owner_box; private boolean menu_is_bar = false;
+ Swt_popup_grp(String root_key){this.root_key = root_key;}
+ @Override public int Tid() {return Gfui_mnu_itm_.Tid_grp;}
+ @Override public String Uid() {return uid;} private String uid = Gfui_mnu_itm_.Gen_uid();
+ @Override public boolean Enabled() {return menu.getEnabled();} @Override public void Enabled_(boolean v) {menu.setEnabled(v);}
+ @Override public String Text() {return menu_item.getText();} @Override public void Text_(String v) {menu_item.setText(v);}
+ @Override public ImageAdp Img() {return img;} @Override public void Img_(ImageAdp v) {
+ img = v;
+ if (v == ImageAdp_.Null)
+ menu_item.setImage(null);
+ else
+ menu_item.setImage((Image)v.Under());
+ } private ImageAdp img;
+ @Override public boolean Selected() {return menu_item.getSelection();} @Override public void Selected_(boolean v) {menu_item.setSelection(v);}
+ public String Root_key() {return root_key;} private String root_key;
+ public Menu Under_menu() {return menu;} private Menu menu;
+ public MenuItem Under_menu_item() {return menu_item;} private MenuItem menu_item;
+ public Object Under() {return menu;}
+ @Override public void Itms_clear() {
+ menu.dispose();
+ if (menu_is_bar) {
+ menu = new Menu(owner_win, SWT.BAR);
+ owner_win.setMenuBar(menu);
+ }
+ else {
+ menu = new Menu(owner_box);
+ owner_box.setMenu(menu);
+ }
+ }
+ @Override public Gfui_mnu_itm Itms_add_btn_cmd(String txt, ImageAdp img, GfoInvkAble invk, String cmd) {
+ Swt_popup_itm itm = new Swt_popup_itm(menu);
+ itm.Text_(txt);
+ if (img != null) itm.Img_(img);
+ itm.Invk_set_cmd(invk, cmd);
+ return itm;
+ }
+ @Override public Gfui_mnu_itm Itms_add_btn_msg(String txt, ImageAdp img, GfoInvkAble invk, GfoInvkRootWkr root_wkr, GfoMsg invk_msg) {
+ Swt_popup_itm itm = new Swt_popup_itm(menu);
+ itm.Text_(txt);
+ if (img != null) itm.Img_(img);
+ itm.Invk_set_msg(root_wkr, invk, invk_msg);
+ return itm;
+ }
+ @Override public Gfui_mnu_itm Itms_add_chk_msg(String txt, ImageAdp img, GfoInvkAble invk, GfoInvkRootWkr root_wkr, GfoMsg msg_n, GfoMsg msg_y) {
+ Swt_popup_itm itm = new Swt_popup_itm(menu, SWT.CHECK);
+ itm.Text_(txt);
+ if (img != null) itm.Img_(img);
+ itm.Invk_set_chk(root_wkr, invk, msg_n, msg_y);
+ return itm;
+ }
+ @Override public Gfui_mnu_itm Itms_add_rdo_msg(String txt, ImageAdp img, GfoInvkAble invk, GfoInvkRootWkr root_wkr, GfoMsg msg) {
+ Swt_popup_itm itm = new Swt_popup_itm(menu, SWT.RADIO);
+ itm.Text_(txt);
+ if (img != null) itm.Img_(img);
+ itm.Invk_set_msg(root_wkr, invk, msg);
+ return itm;
+ }
+ @Override public Gfui_mnu_itm Itms_add_separator() {
+ new MenuItem(menu, SWT.SEPARATOR);
+ return null;
+ }
+ @Override public Gfui_mnu_grp Itms_add_grp(String txt, ImageAdp img) {
+ Swt_popup_itm itm = new Swt_popup_itm(menu, SWT.CASCADE);
+ if (img != null) itm.Img_(img);
+ itm.Text_(txt);
+
+ Swt_popup_grp grp = new_grp(root_key, owner_win);
+ grp.menu_item = itm.Under_menu_item();
+ itm.Text_(txt);
+
+ itm.Under_menu_item().setMenu(grp.Under_menu());
+ return grp;
+ }
+ public static Swt_popup_grp new_popup(String key, GfuiElem owner_elem) {
+ Swt_popup_grp rv = new Swt_popup_grp(key);
+ Shell owner_win = cast_to_shell(owner_elem.OwnerWin());
+ Control owner_box = ((Swt_control)owner_elem.UnderElem()).Under_control();
+ rv.owner_win = owner_win; rv.owner_box = owner_box;
+ rv.menu = new Menu(owner_box);
+ owner_box.setMenu(rv.menu);
+ return rv;
+ }
+
+ private static Swt_popup_grp new_grp(String key, Decorations owner_win) {
+ Swt_popup_grp rv = new Swt_popup_grp(key);
+ rv.owner_win = owner_win;
+ rv.menu = new Menu(owner_win, SWT.DROP_DOWN);
+ return rv;
+ }
+ public static Swt_popup_grp new_bar(String key, GfuiWin win) {
+ Swt_popup_grp rv = new Swt_popup_grp(key);
+ Shell owner_win = cast_to_shell(win);
+ rv.owner_win = owner_win;
+ rv.menu_is_bar = true;
+ rv.menu = new Menu(owner_win, SWT.BAR);
+ owner_win.setMenuBar(rv.menu);
+ return rv;
+ }
+ private static Shell cast_to_shell(GfuiWin win) {
+ return ((Swt_win)win.UnderElem()).UnderShell();
+ }
+}
+class Swt_lnr__menu_detect implements MenuDetectListener {
+ private GfuiElem elem;
+ public Swt_lnr__menu_detect(GfuiElem elem) {this.elem = elem;}
+ @Override public void menuDetected(MenuDetectEvent arg0) {
+ GfoEvMgr_.Pub(elem, GfuiElemKeys.Evt_menu_detected);
+ }
+}
+class Swt_popup_itm implements Gfui_mnu_itm {
+ private Menu menu;
+ public Swt_popup_itm(Menu menu) {
+ this.menu = menu; itm = new MenuItem(menu, SWT.NONE);
+ this.tid = Gfui_mnu_itm_.Tid_btn;
+ }
+ public Swt_popup_itm(Menu menu, int swt_type) {
+ this.menu = menu; itm = new MenuItem(menu, swt_type);
+ switch (swt_type) {
+ case SWT.CASCADE: this.tid = Gfui_mnu_itm_.Tid_grp; break;
+ case SWT.CHECK: this.tid = Gfui_mnu_itm_.Tid_chk; break;
+ case SWT.RADIO: this.tid = Gfui_mnu_itm_.Tid_rdo; break;
+ default: throw Err_.unhandled(swt_type);
+ }
+ }
+ @Override public int Tid() {return tid;} private int tid;
+ @Override public String Uid() {return uid;} private String uid = Gfui_mnu_itm_.Gen_uid();
+ @Override public boolean Enabled() {return itm.getEnabled();} @Override public void Enabled_(boolean v) {itm.setEnabled(v);}
+ @Override public String Text() {return itm.getText();} @Override public void Text_(String v) {itm.setText(v);}
+ @Override public ImageAdp Img() {return img;} @Override public void Img_(ImageAdp v) {
+ img = v;
+ if (v != ImageAdp_.Null)
+ itm.setImage((Image)v.Under());
+ } private ImageAdp img;
+ @Override public boolean Selected() {return itm.getSelection();}
+ @Override public void Selected_(boolean v) {
+ selected_changing = true;
+ itm.setSelection(v);
+ selected_changing = false;
+ }
+ public boolean Selected_changing() {return selected_changing;} private boolean selected_changing;
+ @Override public Object Under() {return menu;}
+ public MenuItem Under_menu_item() {return itm;} private MenuItem itm;
+ public void Invk_set_cmd(GfoInvkAble invk, String cmd) {
+ itm.addListener(SWT.Selection, new Swt_lnr__menu_btn_cmd(invk, cmd));
+ }
+ public void Invk_set_msg(GfoInvkRootWkr root_wkr, GfoInvkAble invk, GfoMsg msg) {
+ itm.addListener(SWT.Selection, new Swt_lnr__menu_btn_msg(root_wkr, invk, msg));
+ }
+ public void Invk_set_chk(GfoInvkRootWkr root_wkr, GfoInvkAble invk, GfoMsg msg_n, GfoMsg msg_y) {
+ itm.addListener(SWT.Selection, new Swt_lnr__menu_chk_msg(this, root_wkr, invk, msg_n, msg_y));
+ }
+}
+class Swt_lnr__menu_btn_cmd implements Listener {
+ public Swt_lnr__menu_btn_cmd(GfoInvkAble invk, String cmd) {this.invk = invk; this.cmd = cmd;} GfoInvkAble invk; String cmd;
+ public void handleEvent(Event ev) {
+ try {GfoInvkAble_.InvkCmd(invk, cmd);}
+ catch (Exception e) {Swt_kit._.Ask_ok("", "", "error while invoking command: cmd=~{0} err=~{1}", cmd, Err_.Message_gplx_brief(e));}
+ }
+}
+class Swt_lnr__menu_btn_msg implements Listener {
+ private GfoInvkRootWkr root_wkr; private GfoInvkAble invk; private GfoMsg msg;
+ public Swt_lnr__menu_btn_msg(GfoInvkRootWkr root_wkr, GfoInvkAble invk, GfoMsg msg) {this.root_wkr = root_wkr; this.invk = invk; this.msg = msg;}
+ public void handleEvent(Event ev) {
+ try {
+ msg.Args_reset();
+ root_wkr.Run_str_for(invk, msg);
+ }
+ catch (Exception e) {Swt_kit._.Ask_ok("", "", "error while invoking command: cmd=~{0} err=~{1}", msg.Key(), Err_.Message_gplx_brief(e));}
+ }
+}
+class Swt_lnr__menu_chk_msg implements Listener {
+ private Swt_popup_itm mnu_itm; private GfoInvkRootWkr root_wkr; private GfoInvkAble invk; private GfoMsg msg_n, msg_y;
+ public Swt_lnr__menu_chk_msg(Swt_popup_itm mnu_itm, GfoInvkRootWkr root_wkr, GfoInvkAble invk, GfoMsg msg_n, GfoMsg msg_y) {
+ this.mnu_itm = mnu_itm;
+ this.root_wkr = root_wkr; this.invk = invk; this.msg_n = msg_n; this.msg_y = msg_y;
+ }
+ public void handleEvent(Event ev) {
+ if (mnu_itm.Selected_changing()) return;
+ GfoMsg msg = mnu_itm.Under_menu_item().getSelection() ? msg_y : msg_n;
+ try {
+ msg.Args_reset();
+ root_wkr.Run_str_for(invk, msg);
+ }
+ catch (Exception e) {Swt_kit._.Ask_ok("", "", "error while invoking command: cmd=~{0} err=~{1}", msg.Key(), Err_.Message_gplx_brief(e));}
+ }
+}
diff --git a/150_gfui/xtn/gplx/gfui/Swt_tab_itm.java b/150_gfui/xtn/gplx/gfui/Swt_tab_itm.java
new file mode 100644
index 000000000..2c9aa27ea
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_tab_itm.java
@@ -0,0 +1,55 @@
+/*
+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.gfui;
+import gplx.*;
+import org.eclipse.swt.*;
+import org.eclipse.swt.custom.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+public class Swt_tab_itm implements Gxw_tab_itm, Swt_control, FocusListener {
+ public CTabFolder Tab_mgr() {return tab_mgr;} private CTabFolder tab_mgr;
+ public Swt_tab_mgr Tab_mgr_swt() {return tab_mgr_swt;} private Swt_tab_mgr tab_mgr_swt;
+ public Gfui_tab_itm_data Tab_data() {return (Gfui_tab_itm_data)tab_itm.getData();}
+ public Swt_tab_itm(Swt_tab_mgr tab_mgr_swt, Swt_kit kit, CTabFolder tab_mgr, Gfui_tab_itm_data tab_data) {
+ this.tab_mgr_swt = tab_mgr_swt; this.kit = kit; this.tab_mgr = tab_mgr;
+ tab_itm = new CTabItem(tab_mgr, SWT.CLOSE);
+ tab_itm.setData(tab_data);
+ // core = new Swt_core_cmds(tab_itm);
+ }
+ public Swt_kit Kit() {return kit;} private Swt_kit kit;
+ @Override public Control Under_control() {return null;}
+ @Override public Composite Under_composite() {return null;}
+ @Override public Control Under_menu_control() {throw Err_.not_implemented_();}
+ @Override public String Tab_name() {return tab_itm.getText();} @Override public void Tab_name_(String v) {tab_itm.setText(v);}
+ @Override public String Tab_tip_text() {return tab_itm.getToolTipText();} @Override public void Tab_tip_text_(String v) {tab_itm.setToolTipText(v);}
+ public void Subs_add(GfuiElem sub) {
+ Swt_control swt_control = Swt_control_.cast_or_fail(sub);
+ tab_itm.setControl(swt_control.Under_control());
+ }
+ public CTabItem Under_CTabItem() {return tab_itm;} private CTabItem tab_itm;
+ @Override public GxwCore_base Core() {return core;} GxwCore_base core;
+ @Override public GxwCbkHost Host() {return host;} @Override public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host;
+ @Override public String TextVal() {return "not implemented";}
+ @Override public void TextVal_set(String v) {}
+ @Override public void EnableDoubleBuffering() {}
+ @Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return GfoInvkAble_.Rv_unhandled;}
+ @Override public void focusGained(FocusEvent arg0) {}
+ @Override public void focusLost(FocusEvent arg0) {}
+}
+//#}
\ No newline at end of file
diff --git a/150_gfui/xtn/gplx/gfui/Swt_tab_mgr.java b/150_gfui/xtn/gplx/gfui/Swt_tab_mgr.java
new file mode 100644
index 000000000..b7e9e58be
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_tab_mgr.java
@@ -0,0 +1,269 @@
+/*
+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.gfui;
+import gplx.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.custom.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+public class Swt_tab_mgr implements Gxw_tab_mgr, Swt_control, FocusListener, GfoEvMgrOwner {
+ private GfuiInvkCmd cmd_async; // NOTE: async needed for some actions like responding to key_down and calling .setSelection; else app hangs; DATE:2014-04-30
+ public Swt_tab_mgr(Swt_kit kit, Swt_control owner_control, KeyValHash ctorArgs) {
+ this.kit = kit;
+ tab_folder = new CTabFolder(owner_control.Under_composite(), SWT.BORDER);
+ tab_folder.setBorderVisible(false);
+ tab_folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ tab_folder.setSimple(true);
+ tab_folder.addListener(SWT.Selection, new Swt_tab_mgr_lnr_selection(this));
+ tab_folder.addKeyListener(new Swt_lnr_key(this));
+
+ new Swt_tab_mgr_lnr_drag_drop(this, tab_folder);
+ tab_folder.addCTabFolder2Listener(new Swt_tab_mgr_lnr_close(this));
+ core = new Swt_core_cmds(tab_folder);
+ cmd_async = kit.New_cmd_async(this);
+ }
+ public Swt_kit Kit() {return kit;} private Swt_kit kit;
+ public CTabFolder Under_ctabFolder() {return tab_folder;}
+ @Override public Control Under_control() {return tab_folder;} private CTabFolder tab_folder;
+ @Override public Composite Under_composite() {return tab_folder;}
+ @Override public Control Under_menu_control() {return tab_folder;}
+ public GfoEvMgr EvMgr() {return ev_mgr;} private GfoEvMgr ev_mgr;
+ public void EvMgr_(GfoEvMgr v) {ev_mgr = v;}
+ public ColorAdp Btns_selected_color() {return btns_selected_color;} private ColorAdp btns_selected_color;
+ public void Btns_selected_color_(ColorAdp v) {
+ btns_selected_color = v;
+ tab_folder.setSelectionBackground(kit.New_color(v));
+ }
+ public ColorAdp Btns_unselected_color() {return btns_unselected_color;}
+ public void Btns_unselected_color_(ColorAdp v) {
+ btns_unselected_color = v;
+ tab_folder.setBackground(kit.New_color(v));
+ } private ColorAdp btns_unselected_color;
+ @Override public boolean Btns_curved() {return tab_folder.getSimple();} @Override public void Btns_curved_(boolean v) {tab_folder.setSimple(!v);}
+ @Override public boolean Btns_place_on_top() {return tab_folder.getTabPosition() == SWT.TOP;}
+ @Override public void Btns_place_on_top_(boolean v) {tab_folder.setTabPosition(v ? SWT.TOP : SWT.BOTTOM); tab_folder.layout();}
+ @Override public int Btns_height() {return tab_folder.getTabHeight();} @Override public void Btns_height_(int v) {tab_folder.setTabHeight(v); tab_folder.layout();}
+ @Override public boolean Btns_close_visible() {return btns_close_visible;} private boolean btns_close_visible = true;
+ @Override public void Btns_close_visible_(boolean v) {
+ this.btns_close_visible = v;
+ CTabItem[] itms = tab_folder.getItems();
+ int len = itms.length;
+ for (int i = 0; i < len; i++)
+ itms[i].setShowClose(v);
+ }
+ @Override public boolean Btns_unselected_close_visible() {return tab_folder.getUnselectedCloseVisible();} @Override public void Btns_unselected_close_visible_(boolean v) {
+ tab_folder.setUnselectedCloseVisible(v);}
+ @Override public Gxw_tab_itm Tabs_add(Gfui_tab_itm_data tab_data) {
+ Swt_tab_itm rv = new Swt_tab_itm(this, kit, tab_folder, tab_data);
+ rv.Under_CTabItem().setData(tab_data);
+ CTabItem ctab_itm = rv.Under_CTabItem();
+ ctab_itm.setShowClose(btns_close_visible);
+ return rv;
+ }
+ @Override public void Tabs_close_by_idx(int i) {
+ CTabItem itm = tab_folder.getItems()[i];
+ Gfui_tab_itm_data tab_data = Get_tab_data(itm);
+ CTabItem next_tab = Tabs_select_after_closing_itm(tab_data); // NOTE: must calc next_tab before calling Pub_tab_closed; latter will recalc idx
+ Pub_tab_closed(tab_data.Key()); // NOTE: dispose does not call event for .close; must manually raise event;
+ itm.dispose();
+ this.Tabs_select_by_itm(next_tab);
+ }
+ @Override public void Tabs_select_by_idx(int i) {
+ if (i == Gfui_tab_itm_data.Idx_null) return; // 0 tabs; return;
+ msg_tabs_select_by_idx_swt.Clear();
+ msg_tabs_select_by_idx_swt.Add("v", i);
+ cmd_async.Invk(GfsCtx._, 0, Invk_tabs_select_by_idx_swt, msg_tabs_select_by_idx_swt);
+ } private GfoMsg msg_tabs_select_by_idx_swt = GfoMsg_.new_cast_(Invk_tabs_select_by_idx_swt);
+ @Override public void Tabs_switch(int src, int trg) {Tabs_switch(tab_folder.getItem(src), tab_folder.getItem(trg));}
+ public boolean Tabs_switch(CTabItem src_tab_itm, CTabItem trg_tab_itm) {
+ Control temp_control = src_tab_itm.getControl();
+ src_tab_itm.setControl(trg_tab_itm.getControl());
+ trg_tab_itm.setControl(temp_control);
+
+ String temp_str = src_tab_itm.getText();
+ src_tab_itm.setText(trg_tab_itm.getText());
+ trg_tab_itm.setText(temp_str);
+
+ temp_str = src_tab_itm.getToolTipText();
+ src_tab_itm.setToolTipText(trg_tab_itm.getToolTipText());
+ trg_tab_itm.setToolTipText(temp_str);
+
+ Gfui_tab_itm_data src_tab_data = Get_tab_data(src_tab_itm);
+ Gfui_tab_itm_data trg_tab_data = Get_tab_data(trg_tab_itm);
+ int src_tab_idx = src_tab_data.Idx(), trg_tab_idx = trg_tab_data.Idx();
+ tab_folder.setSelection(trg_tab_itm);
+ GfoEvMgr_.PubVals(this, Gfui_tab_mgr.Evt_tab_switched, KeyVal_.new_("src", src_tab_data.Key()), KeyVal_.new_("trg", trg_tab_data.Key()));
+ return src_tab_idx < trg_tab_idx;
+ }
+ public void Tabs_select_by_itm(CTabItem itm) {
+ if (itm == null) return; // 0 tabs; return;
+ msg_tabs_select_by_itm_swt.Clear();
+ msg_tabs_select_by_itm_swt.Add("v", itm);
+ cmd_async.Invk(GfsCtx._, 0, Invk_tabs_select_by_itm_swt, msg_tabs_select_by_itm_swt);
+ } private GfoMsg msg_tabs_select_by_itm_swt = GfoMsg_.new_cast_(Invk_tabs_select_by_itm_swt);
+ private void Tabs_select_by_idx_swt(int idx) {
+ tab_folder.setSelection(idx);
+ CTabItem itm = tab_folder.getItem(idx);
+ Pub_tab_selected(Get_tab_key(itm)); // NOTE: setSelection does not call event for SWT.Selection; must manually raise event;
+ }
+ private void Tabs_select_by_itm_swt(CTabItem itm) {
+ tab_folder.setSelection(itm);
+ Pub_tab_selected(Get_tab_key(itm)); // NOTE: setSelection does not call event for SWT.Selection; must manually raise event;
+ }
+ public CTabItem Tabs_select_after_closing_itm(Gfui_tab_itm_data tab_data) {
+ int next_idx = Gfui_tab_itm_data.Get_idx_after_closing(tab_data.Idx(), tab_folder.getItemCount());
+ return next_idx == Gfui_tab_itm_data.Idx_null ? null : tab_folder.getItem(next_idx);
+ }
+ public void Pub_tab_selected(String key) {
+ GfoEvMgr_.PubObj(this, Gfui_tab_mgr.Evt_tab_selected, "key", key);
+ }
+ public void Pub_tab_closed(String key) {
+ GfoEvMgr_.PubObj(this, Gfui_tab_mgr.Evt_tab_closed, "key", key);
+ }
+ @Override public GxwCore_base Core() {return core;} GxwCore_base core;
+ @Override public GxwCbkHost Host() {return host;} @Override public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host;
+ @Override public String TextVal() {return "not implemented";}
+ @Override public void TextVal_set(String v) {}
+ @Override public void EnableDoubleBuffering() {}
+ @Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (String_.Eq(k, Invk_tabs_select_by_idx_swt)) Tabs_select_by_idx_swt(m.ReadInt("v"));
+ else if (String_.Eq(k, Invk_tabs_select_by_itm_swt)) Tabs_select_by_itm_swt((CTabItem)m.ReadObj("v", null));
+ else return GfoInvkAble_.Rv_unhandled;
+ return this;
+ }
+ @Override public void focusGained(FocusEvent arg0) {}
+ @Override public void focusLost(FocusEvent arg0) {}
+ private static String
+ Invk_tabs_select_by_idx_swt = "tabs_select_by_idx"
+ , Invk_tabs_select_by_itm_swt = "tabs_select_by_itm"
+ ;
+ public static Gfui_tab_itm_data Get_tab_data_by_obj(Object data) {return (Gfui_tab_itm_data)data;}
+ public static Gfui_tab_itm_data Get_tab_data(CTabItem itm) {return (Gfui_tab_itm_data)itm.getData();}
+ public static String Get_tab_key(CTabItem itm) {return ((Gfui_tab_itm_data)itm.getData()).Key();}
+}
+class Swt_tab_mgr_lnr_selection implements Listener {
+ public Swt_tab_mgr_lnr_selection(Swt_tab_mgr tab_folder) {this.tab_folder = tab_folder;} private Swt_tab_mgr tab_folder;
+ public void handleEvent(Event ev) {
+ tab_folder.Pub_tab_selected(Swt_tab_mgr.Get_tab_data_by_obj(ev.item.getData()).Key());
+ }
+}
+class Swt_tab_mgr_lnr_close extends CTabFolder2Adapter { // handles close when tab x is clicked
+ public Swt_tab_mgr_lnr_close(Swt_tab_mgr tab_folder) {this.tab_folder = tab_folder;} private Swt_tab_mgr tab_folder;
+ @Override public void close(CTabFolderEvent ev) {
+ Gfui_tab_itm_data tab_data = Swt_tab_mgr.Get_tab_data_by_obj(ev.item.getData());
+ tab_folder.Tabs_close_by_idx(tab_data.Idx());
+ ev.doit = false; // mark ev handled, since Tabs_close_by_idx closes tab
+ }
+}
+class Swt_tab_mgr_lnr_drag_drop implements Listener {
+ private boolean dragging = false;
+ private boolean drag_stop = false;
+ private CTabItem drag_itm;
+ private final Swt_tab_mgr tab_mgr; private final CTabFolder tab_folder; private final Display display;
+ private Point prv_mouse;
+ private Point dead_zone = null;
+ public Swt_tab_mgr_lnr_drag_drop(Swt_tab_mgr tab_mgr, CTabFolder tab_folder) {
+ this.tab_mgr = tab_mgr; this.tab_folder = tab_folder; this.display = tab_folder.getDisplay();
+ tab_folder.addListener(SWT.DragDetect, this);
+ tab_folder.addListener(SWT.MouseUp, this);
+ tab_folder.addListener(SWT.MouseMove, this);
+ tab_folder.addListener(SWT.MouseExit, this);
+ tab_folder.addListener(SWT.MouseEnter, this);
+ }
+ private void Drag_drop_bgn(CTabItem itm) {
+ dragging = true;
+ drag_stop = false;
+ drag_itm = itm;
+ dead_zone = null;
+ }
+ private void Drag_drop_end() {
+ tab_folder.setInsertMark(null, false);
+ dragging = false;
+ drag_stop = false;
+ drag_itm = null;
+ }
+ public void handleEvent(Event e) {
+ Point cur_mouse = e.type == SWT.DragDetect
+ ? tab_folder.toControl(display.getCursorLocation()) //see bug 43251
+ : new Point(e.x, e.y)
+ ;
+ switch (e.type) {
+ case SWT.DragDetect: {
+ CTabItem itm = tab_folder.getItem(cur_mouse);
+ if (itm == null) return;
+ this.Drag_drop_bgn(itm);
+ break;
+ }
+ case SWT.MouseEnter:
+ if (drag_stop) {
+ dragging = e.button != 0;
+ drag_stop = false;
+ }
+ break;
+ case SWT.MouseExit:
+ if (dragging)
+ Drag_drop_end();
+ break;
+ case SWT.MouseUp: {
+ if (!dragging) return;
+ Drag_drop_end();
+ break;
+ }
+ case SWT.MouseMove: {
+ if (!dragging) return;
+ CTabItem curr_itm = tab_folder.getItem(cur_mouse);
+ if (curr_itm == null) {
+ tab_folder.setInsertMark(null, false);
+ return;
+ }
+ if (curr_itm == drag_itm) return; // curr_itm is same as drag_itm; ignore
+ int cur_mouse_x = cur_mouse.x;
+ int prv_mouse_x = prv_mouse == null ? 0 : prv_mouse.x;
+ prv_mouse = cur_mouse; // set prv_mouse now b/c of early return below; note that cur_mouse_x and prv_mouse_x are cached above
+ if ( dead_zone != null // dead_zone exists
+ && Int_.Between(cur_mouse_x, dead_zone.x, dead_zone.y)) { // mouse is in dead_zone
+ int drag_idx = Swt_tab_mgr.Get_tab_data(drag_itm).Idx();
+ int curr_idx = Swt_tab_mgr.Get_tab_data(curr_itm).Idx();
+ if (drag_idx > curr_idx && cur_mouse_x < prv_mouse_x) {} // drag_itm is right of curr_itm, but mouse is moving left (direction reversed); cancel
+ else if (drag_idx < curr_idx && cur_mouse_x > prv_mouse_x) {} // drag_itm is left of curr_itm, but mouse is moving right (direction reversed); cancel
+ else
+ return; // in dead zone, and still moving in original direction; return early
+ }
+ boolean fwd = tab_mgr.Tabs_switch(drag_itm, curr_itm);
+ drag_itm = curr_itm;
+ Rectangle drag_rect = drag_itm.getBounds();
+ dead_zone = Calc_dead_zone(fwd, cur_mouse_x, drag_rect.x, drag_rect.width);
+ break;
+ }
+ }
+ }
+ public static Point Calc_dead_zone(boolean fwd, int mouse_x, int drag_l, int drag_w) {
+ if (fwd) { // drag_itm was moving fwd (moving right)
+ if (mouse_x < drag_l) return new Point(mouse_x, drag_l); // mouse_x < drag_l; create dead_zone until mouse_x reaches drag_l; occurs when moving drag is small_title and trg_itm is large_title
+ }
+ else { // drag_itm was moving bwd (moving left)
+ int drag_r = drag_l + drag_w;
+ if (mouse_x > drag_r) return new Point(drag_r, mouse_x); // mouse_x > drag_r; create dead_zone until mouse_x reaches drag_r
+ }
+ return null;
+ }
+}
+//#}
\ No newline at end of file
diff --git a/150_gfui/xtn/gplx/gfui/Swt_text.java b/150_gfui/xtn/gplx/gfui/Swt_text.java
new file mode 100644
index 000000000..f734e1e55
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_text.java
@@ -0,0 +1,59 @@
+/*
+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.gfui; import gplx.*;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+class Swt_text implements GxwTextFld, Swt_control {
+ private Text text_box;
+ public Swt_text(Swt_control owner_control, KeyValHash ctorArgs) {
+ int text_box_args = ctorArgs.Has(GfuiTextBox_.Ctor_Memo)
+ ? SWT.MULTI | SWT.WRAP | SWT.V_SCROLL
+ : SWT.NONE
+ ;
+ text_box = new Text(owner_control.Under_composite(), text_box_args);
+ core = new Swt_core_cmds(text_box);
+ text_box.addKeyListener(new Swt_lnr_key(this));
+ text_box.addMouseListener(new Swt_lnr_mouse(this));
+ }
+ @Override public Control Under_control() {return text_box;}
+ @Override public Composite Under_composite() {return null;}
+ @Override public Control Under_menu_control() {return text_box;}
+ @Override public int SelBgn() {return text_box.getCaretPosition();} @Override public void SelBgn_set(int v) {text_box.setSelection(v);}
+ @Override public int SelLen() {return text_box.getSelectionCount();} @Override public void SelLen_set(int v) {text_box.setSelection(this.SelBgn(), this.SelBgn() + v);}
+ @Override public String TextVal() {return text_box.getText();} @Override public void TextVal_set(String v) {text_box.setText(v);}
+ @Override public GxwCore_base Core() {return core;} GxwCore_base core;
+ @Override public GxwCbkHost Host() {return host;} @Override public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host;
+ @Override public void EnableDoubleBuffering() {}
+ @Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return null;}
+ public void Margins_set(int left, int top, int right, int bot) {}
+ @Override public boolean Border_on() {return false;} @Override public void Border_on_(boolean v) {} // SWT_TODO:borderWidth doesn't seem mutable
+ @Override public void CreateControlIfNeeded() {}
+ @Override public boolean OverrideTabKey() {return false;} @Override public void OverrideTabKey_(boolean v) {}
+}
diff --git a/150_gfui/xtn/gplx/gfui/Swt_text_w_border.java b/150_gfui/xtn/gplx/gfui/Swt_text_w_border.java
new file mode 100644
index 000000000..8c23b82e7
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_text_w_border.java
@@ -0,0 +1,89 @@
+/*
+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.gfui; import gplx.*;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+public class Swt_text_w_border implements GxwTextFld, Swt_control {
+ private Composite text_host;
+ private Composite text_margin;
+ private Text text_elem;
+ public Swt_text_w_border(Swt_control owner_control, Color color, KeyValHash ctorArgs) {
+ Composite owner = owner_control.Under_composite();
+ int text_elem_style = ctorArgs.Has(GfuiTextBox_.Ctor_Memo) ? SWT.MULTI | SWT.WRAP | SWT.V_SCROLL : SWT.FLAT;
+ New_box_text_w_border(owner.getDisplay(), owner.getShell(), text_elem_style, color);
+ core = new Swt_core_cmds_frames(text_host, new Swt_core_cmds_frames_itm[]
+ { new Swt_core_cmds_frames_itm_manual(text_margin, 1, 1, -2, -2)
+ , new Swt_core_cmds_frames_itm_center_v(text_elem, this)
+ });
+ text_elem.addKeyListener(new Swt_lnr_key(this));
+ text_elem.addMouseListener(new Swt_lnr_mouse(this));
+ }
+ @Override public Control Under_control() {return text_host;}
+ @Override public Composite Under_composite() {return null;}
+ @Override public Control Under_menu_control() {return text_elem;}
+ public Text Under_text() {return text_elem;}
+ @Override public int SelBgn() {return text_elem.getCaretPosition();} @Override public void SelBgn_set(int v) {text_elem.setSelection(v);}
+ @Override public int SelLen() {return text_elem.getSelectionCount();} @Override public void SelLen_set(int v) {text_elem.setSelection(this.SelBgn(), this.SelBgn() + v);}
+ @Override public String TextVal() {return text_elem.getText();} @Override public void TextVal_set(String v) {text_elem.setText(v);}
+ @Override public GxwCore_base Core() {return core;} Swt_core_cmds_frames core;
+ @Override public GxwCbkHost Host() {return host;} @Override public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host;
+ @Override public void EnableDoubleBuffering() {}
+ @Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ return null;
+ }
+ public int Margins_l() {return margins_l;} int margins_l;
+ public int Margins_r() {return margins_r;} int margins_r;
+ public int Margins_t() {return margins_t;} int margins_t;
+ public int Margins_b() {return margins_b;} int margins_b;
+ public void Margins_set(int left, int top, int right, int bot) {
+ this.margins_l = left; this.margins_t = top; this.margins_r = right; this.margins_b = bot;
+ }
+ @Override public boolean Border_on() {return false;} @Override public void Border_on_(boolean v) {} // SWT_TODO:borderWidth doesn't seem mutable
+ @Override public void CreateControlIfNeeded() {}
+ @Override public boolean OverrideTabKey() {return false;} @Override public void OverrideTabKey_(boolean v) {}
+ void New_box_text_w_border(Display display, Shell shell, int style, Color color) {
+ text_host = new Composite(shell, SWT.FLAT);
+ text_margin = new Composite(text_host, SWT.FLAT);
+ text_elem = new Text(text_margin, style);
+ text_elem .addTraverseListener(Swt_lnr_traverse_ignore_ctrl._); // do not allow ctrl+tab to change focus when pressed in text box; allows ctrl+tab to be used by other bindings; DATE:2014-04-30
+ text_host.setSize(20, 20);
+ text_host.setBackground(color);
+ text_margin.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
+ text_margin.setSize(20, 20);
+ text_elem.setSize(20 - 2, 20 - 2);
+ text_elem.setLocation(1, 1);
+ }
+}
+class Swt_lnr_traverse_ignore_ctrl implements TraverseListener {
+ public void keyTraversed(TraverseEvent e) {
+ if (Swt_lnr_key.Has_ctrl(e.stateMask)) e.doit = false;
+ }
+ public static final Swt_lnr_traverse_ignore_ctrl _ = new Swt_lnr_traverse_ignore_ctrl();
+}
\ No newline at end of file
diff --git a/150_gfui/xtn/gplx/gfui/Swt_win.java b/150_gfui/xtn/gplx/gfui/Swt_win.java
new file mode 100644
index 000000000..719a76875
--- /dev/null
+++ b/150_gfui/xtn/gplx/gfui/Swt_win.java
@@ -0,0 +1,114 @@
+/*
+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.gfui;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+import gplx.GfoInvkAbleCmd;
+import gplx.GfoMsg;
+import gplx.GfsCtx;
+import gplx.Io_url_;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+class Swt_win implements GxwWin, Swt_control {
+ public Display UnderDisplay() {return display;} private Display display;
+ public Shell UnderShell() {return shell;} private Shell shell;
+ @Override public Control Under_control() {return shell;}
+ @Override public Composite Under_composite() {return shell;}
+ @Override public Control Under_menu_control() {return shell;}
+ public Swt_win(Shell owner) {ctor(new Shell(owner, SWT.RESIZE | SWT.DIALOG_TRIM), owner.getDisplay());}
+ public Swt_win(Display display) {ctor(new Shell(display), display); }
+ Swt_lnr_show showLnr; // use ptr to dispose later
+ void ctor(Shell shell, Display display) {
+ this.shell = shell;
+ this.display = display;
+ ctrlMgr = new Swt_core_cmds(shell);
+ showLnr = new Swt_lnr_show(this);
+ resizeLnr = new Swt_lnr_resize(this);
+ shell.addListener(SWT.Show, showLnr);
+ shell.addListener(SWT.Resize, resizeLnr);
+ }
+ Swt_lnr_resize resizeLnr;
+ public void ShowWin() {shell.setVisible(true);}
+ public void HideWin() {shell.setVisible(false);}
+ public boolean Maximized() {return shell.getMaximized();} public void Maximized_(boolean v) {shell.setMaximized(v);}
+ public boolean Minimized() {return shell.getMinimized();} public void Minimized_(boolean v) {shell.setMinimized(v);}
+ public void CloseWin() {shell.close();}
+ public boolean Pin() {return pin;}
+ public void Pin_set(boolean val) {
+ // shell.setAlwaysOnTop(val);
+ pin = val;
+ } boolean pin = false;
+ public IconAdp IconWin() {return icon;} IconAdp icon;
+ public void IconWin_set(IconAdp i) {
+ if (i == null || i.Url() == Io_url_.Null) return;
+ icon = i;
+ Image image = null;
+ try {
+ image = new Image(display, new FileInputStream(i.Url().Xto_api()));
+ } catch (FileNotFoundException e1) {e1.printStackTrace();}
+ shell.setImage(image);
+ }
+ public void OpenedCmd_set(GfoInvkAbleCmd v) {whenLoadedCmd = v;} GfoInvkAbleCmd whenLoadedCmd = GfoInvkAbleCmd.Null;
+ public void Opened() {whenLoadedCmd.Invk();}
+ public GxwCore_base Core() {return ctrlMgr;} GxwCore_base ctrlMgr;
+ public GxwCbkHost Host() {return host;} public void Host_set(GxwCbkHost host) {this.host = host;} GxwCbkHost host = GxwCbkHost_.Null;
+ public String TextVal() {
+ return shell.getText();}
+ public void TextVal_set(String v) {
+ shell.setText(v);
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;}
+ public void SendKeyDown(IptKey key) {}
+ public void SendMouseMove(int x, int y) {}
+ public void SendMouseDown(IptMouseBtn btn) {}
+ //public void windowActivated(WindowEvent e) {}
+ //public void windowClosed(WindowEvent e) {}
+ //public void windowClosing(WindowEvent e) {host.DisposeCbk();}
+ //public void windowDeactivated(WindowEvent e) {}
+ //public void windowDeiconified(WindowEvent e) {host.SizeChangedCbk();}
+ //public void windowIconified(WindowEvent e) {host.SizeChangedCbk();}
+ //public void windowOpened(WindowEvent e) {whenLoadedCmd.Invk();}
+ //@Override public void processKeyEvent(KeyEvent e) {if (GxwCbkHost_.ExecKeyEvent(host, e)) super.processKeyEvent(e);}
+ //@Override public void processMouseEvent(MouseEvent e) {if (GxwCbkHost_.ExecMouseEvent(host, e)) super.processMouseEvent(e);}
+ //@Override public void processMouseWheelEvent(MouseWheelEvent e) {if (GxwCbkHost_.ExecMouseWheel(host, e)) super.processMouseWheelEvent(e);}
+ //@Override public void processMouseMotionEvent(MouseEvent e) {if (host.MouseMoveCbk(IptEvtDataMouse.new_(IptMouseBtn_.None, IptMouseWheel_.None, e.getX(), e.getY()))) super.processMouseMotionEvent(e);}
+ //@Override public void paint(Graphics g) {
+ // if (host.PaintCbk(PaintArgs.new_(GfxAdpBase.new_((Graphics2D)g), RectAdp_.Zero))) // ClipRect not used by any clients; implement when necessary
+ // super.paint(g);
+ //}
+ public void EnableDoubleBuffering() {}
+ public void TaskbarVisible_set(boolean val) {} public void TaskbarParkingWindowFix(GxwElem form) {}
+ void ctor_GxwForm() {
+ // this.setLayout(null); // use gfui layout
+ // this.ctrlMgr.BackColor_set(ColorAdp_.White); // default form backColor to white
+ // this.setUndecorated(true); // remove icon, titleBar, minimize, maximize, close, border
+ // this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // JAVA: cannot cancel alt+f4; set Close to noop, and manually control closing by calling this.CloseForm
+ // enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
+ // this.addWindowListener(this);
+ // GxwBoxListener lnr = new GxwBoxListener(this);
+ // this.addComponentListener(lnr);
+ // this.addFocusListener(lnr);
+ }
+}
diff --git a/400_xowa/.classpath b/400_xowa/.classpath
new file mode 100644
index 000000000..1a4b88bdd
--- /dev/null
+++ b/400_xowa/.classpath
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/400_xowa/.project b/400_xowa/.project
new file mode 100644
index 000000000..cd7955f03
--- /dev/null
+++ b/400_xowa/.project
@@ -0,0 +1,17 @@
+
+
+ 400_xowa
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/400_xowa/lib/luaj_xowa.jar b/400_xowa/lib/luaj_xowa.jar
new file mode 100644
index 000000000..414a1cd71
Binary files /dev/null and b/400_xowa/lib/luaj_xowa.jar differ
diff --git a/400_xowa/src/gplx/cache/Gfo_cache_mgr_base.java b/400_xowa/src/gplx/cache/Gfo_cache_mgr_base.java
new file mode 100644
index 000000000..b6022302d
--- /dev/null
+++ b/400_xowa/src/gplx/cache/Gfo_cache_mgr_base.java
@@ -0,0 +1,48 @@
+/*
+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.cache; import gplx.*;
+public class Gfo_cache_mgr_base {
+ private OrderedHash hash = OrderedHash_.new_bry_();
+ public int Compress_max() {return compress_max;} public void Compress_max_(int v) {compress_max = v;} private int compress_max = 16;
+ public int Compress_to() {return compress_to;} public void Compress_to_(int v) {compress_to = v;} private int compress_to = 8;
+ protected Object Base_get_or_null(byte[] key) {
+ Object rv_obj = hash.Fetch(key);
+ return rv_obj == null ? null : ((Gfo_cache_itm)rv_obj).Val();
+ }
+ protected void Base_add(byte[] key, Object val) {
+ if (hash.Count() >= compress_max) Compress();
+ Gfo_cache_itm itm = new Gfo_cache_itm(key, val);
+ hash.Add(key, itm);
+ }
+ protected void Base_del(byte[] key) {
+ hash.Del(key);
+ }
+ public void Compress() {
+ hash.SortBy(Gfo_cache_itm_comparer.Touched_asc);
+ int del_len = hash.Count() - compress_to;
+ ListAdp del_list = ListAdp_.new_();
+ for (int i = 0; i < del_len; i++) {
+ Gfo_cache_itm itm = (Gfo_cache_itm)hash.FetchAt(i);
+ del_list.Add(itm);
+ }
+ for (int i = 0; i < del_len; i++) {
+ Gfo_cache_itm itm = (Gfo_cache_itm)del_list.FetchAt(i);
+ hash.Del(itm.Key());
+ }
+ }
+}
diff --git a/400_xowa/src/gplx/cache/Gfo_cache_mgr_bry.java b/400_xowa/src/gplx/cache/Gfo_cache_mgr_bry.java
new file mode 100644
index 000000000..70984323c
--- /dev/null
+++ b/400_xowa/src/gplx/cache/Gfo_cache_mgr_bry.java
@@ -0,0 +1,38 @@
+/*
+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.cache; import gplx.*;
+public class Gfo_cache_mgr_bry extends Gfo_cache_mgr_base {
+ public Object Get_or_null(byte[] key) {return Base_get_or_null(key);}
+ public void Add(byte[] key, Object val) {Base_add(key, val);}
+ public void Del(byte[] key) {Base_del(key);}
+}
+class Gfo_cache_itm {
+ public Gfo_cache_itm(Object key, Object val) {this.key = key; this.val = val; this.Touched_update();}
+ public Object Key() {return key;} private Object key;
+ public Object Val() {return val;} private Object val;
+ public long Touched() {return touched;} private long touched;
+ public Gfo_cache_itm Touched_update() {touched = Env_.TickCount(); return this;}
+}
+class Gfo_cache_itm_comparer implements gplx.lists.ComparerAble {
+ public int compare(Object lhsObj, Object rhsObj) {
+ Gfo_cache_itm lhs = (Gfo_cache_itm)lhsObj;
+ Gfo_cache_itm rhs = (Gfo_cache_itm)rhsObj;
+ return Long_.Compare(lhs.Touched(), rhs.Touched());
+ }
+ public static final Gfo_cache_itm_comparer Touched_asc = new Gfo_cache_itm_comparer();
+}
diff --git a/400_xowa/src/gplx/core/bytes/Bry_bldr.java b/400_xowa/src/gplx/core/bytes/Bry_bldr.java
new file mode 100644
index 000000000..ec916e1c7
--- /dev/null
+++ b/400_xowa/src/gplx/core/bytes/Bry_bldr.java
@@ -0,0 +1,40 @@
+/*
+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.core.bytes; import gplx.*; import gplx.core.*;
+public class Bry_bldr {
+ public byte[] Val() {return val;} private byte[] val;
+ public Bry_bldr New_256() {return New(256);}
+ public Bry_bldr New(int len) {val = new byte[len]; return this;}
+ public Bry_bldr Set_rng_ws(byte v) {return Set_many(v, Byte_ascii.Space, Byte_ascii.Tab, Byte_ascii.NewLine, Byte_ascii.CarriageReturn);}
+ public Bry_bldr Set_rng_xml_identifier(byte v) {return Set_rng_alpha_lc(v).Set_rng_alpha_uc(v).Set_rng_num(v).Set_many(v, Byte_ascii.Underline, Byte_ascii.Dash);}
+ public Bry_bldr Set_rng_alpha(byte v) {return Set_rng_alpha_lc(v).Set_rng_alpha_uc(v);}
+ public Bry_bldr Set_rng_alpha_lc(byte v) {return Set_rng(v, Byte_ascii.Ltr_a, Byte_ascii.Ltr_z);}
+ public Bry_bldr Set_rng_alpha_uc(byte v) {return Set_rng(v, Byte_ascii.Ltr_A, Byte_ascii.Ltr_Z);}
+ public Bry_bldr Set_rng_num(byte v) {return Set_rng(v, Byte_ascii.Num_0, Byte_ascii.Num_9);}
+ public Bry_bldr Set_rng(byte v, int bgn, int end) {
+ for (int i = bgn; i <= end; i++)
+ val[i] = v;
+ return this;
+ }
+ public Bry_bldr Set_many(byte v, int... ary) {
+ int len = ary.length;
+ for (int i = 0; i < len; i++)
+ val[ary[i]] = v;
+ return this;
+ }
+}
diff --git a/400_xowa/src/gplx/core/enums/Gfo_enum_grp.java b/400_xowa/src/gplx/core/enums/Gfo_enum_grp.java
new file mode 100644
index 000000000..5215ee5fa
--- /dev/null
+++ b/400_xowa/src/gplx/core/enums/Gfo_enum_grp.java
@@ -0,0 +1,54 @@
+/*
+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.core.enums; import gplx.*; import gplx.core.*;
+class Gfo_enum_grp {
+// private OrderedHash itms = OrderedHash_.new_();
+ public Gfo_enum_grp(UuidAdp uid, String key, int id, String name, int sort, String xtn) {
+ this.uid = uid; this.key = key; this.id = id; this.name = name; this.sort = sort; this.xtn = xtn;
+ }
+ public UuidAdp Uid() {return uid;} private UuidAdp uid;
+ public String Key() {return key;} private String key;
+ public int Id() {return id;} private int id;
+ public String Name() {return name;} private String name;
+ public int Sort() {return sort;} private int sort;
+ public String Xtn() {return xtn;} private String xtn;
+}
+class Gfo_enum_itm {
+ public Gfo_enum_itm(UuidAdp uid, String key, int id, String name, int sort, String xtn) {
+ this.uid = uid; this.key = key; this.id = id; this.name = name; this.sort = sort; this.xtn = xtn;
+ }
+ public UuidAdp Uid() {return uid;} private UuidAdp uid;
+ public String Key() {return key;} private String key;
+ public int Id() {return id;} private int id;
+ public String Name() {return name;} private String name;
+ public int Sort() {return sort;} private int sort;
+ public String Xtn() {return xtn;} private String xtn;
+}
+/*
+enum_grps
+grp_guid,grp_key,grp_int,grp_name,grp_sort,grp_xtn
+0-1-2-3,xowa.wiki,0,wiki,,
+
+enum_itms
+grp_int,itm_guid,itm_key,itm_int,itm_name,itm_sort,itm_xtn
+1,0-1-2-3,0,en.wikipedia.org,0,enwiki,0,''
+
+class Gfo_enum_mgr {
+// public Gui
+}
+*/
diff --git a/400_xowa/src/gplx/core/ints/Int_ary_bldr.java b/400_xowa/src/gplx/core/ints/Int_ary_bldr.java
new file mode 100644
index 000000000..7e39ef74c
--- /dev/null
+++ b/400_xowa/src/gplx/core/ints/Int_ary_bldr.java
@@ -0,0 +1,23 @@
+/*
+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.core.ints; import gplx.*; import gplx.core.*;
+public class Int_ary_bldr {
+ public Int_ary_bldr(int len) {ary = new int[len];}
+ public Int_ary_bldr Set(int idx, int val) {ary[idx] = val; return this;}
+ public int[] Xto_int_ary() {return ary;} private int[] ary;
+}
diff --git a/400_xowa/src/gplx/fsdb/Binary_search_.java b/400_xowa/src/gplx/fsdb/Binary_search_.java
new file mode 100644
index 000000000..4234c1ed2
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Binary_search_.java
@@ -0,0 +1,52 @@
+/*
+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.fsdb; import gplx.*;
+public class Binary_search_ {
+ public static int Search(CompareAble[] ary, int ary_len, CompareAble val) {
+ if (ary_len == 1) return 0;
+ int interval = ary_len / 2;
+ int pos = interval - ListAdp_.Base1;
+ int pos_last = ary_len - 1;
+ int pos_prv = -1;
+ int loop_count = 0;
+ while (loop_count++ < 32) { // 32 bit integer
+ CompareAble lo = ary[pos];
+ CompareAble hi = pos + 1 == ary_len ? null : ary[pos + 1];
+ int adj = 0;
+ int lo_comp = val.compareTo(lo);
+ if (lo_comp == CompareAble_.Less) // val is < lo; search slots below
+ adj = -1;
+ else {
+ if (hi == null) return pos; // hi is null when at last slot in ary
+ int hi_comp = val.compareTo(hi);
+ if (hi_comp == CompareAble_.More) // val is > hi; search slots above
+ adj = 1;
+ else
+ return pos; // val is > lo and < hi; return slot
+ }
+ interval /= 2;
+ if (interval == 0) interval = 1; // do not allow 0 intervals; pos must always change;
+ pos += (interval * adj);
+ if (pos == 0 && pos_prv == 0) break; // NOTE: this will only happen when 1st member is not ""
+ if (pos < 0) pos = 0;
+ else if (pos > pos_last) pos = pos_last;
+ pos_prv = pos;
+ }
+ return Int_.MinValue; // should only occur if (a) ary's 0th slot is not ""; or (b) some unknown error
+ }
+}
diff --git a/400_xowa/src/gplx/fsdb/Binary_search__tst.java b/400_xowa/src/gplx/fsdb/Binary_search__tst.java
new file mode 100644
index 000000000..e565cc570
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Binary_search__tst.java
@@ -0,0 +1,47 @@
+/*
+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.fsdb; import gplx.*;
+import org.junit.*;
+public class Binary_search__tst {
+ private Binary_search__fxt fxt = new Binary_search__fxt();
+ @Test public void Basic() {
+ fxt.Init_ary("", "e", "j", "o", "t", "y");
+ fxt.Test_binary_search("a", 0);
+ fxt.Test_binary_search("f", 1);
+ fxt.Test_binary_search("k", 2);
+ fxt.Test_binary_search("p", 3);
+ fxt.Test_binary_search("u", 4);
+ fxt.Test_binary_search("z", 5);
+ }
+ @Test public void One() {
+ fxt.Init_ary("");
+ fxt.Test_binary_search("a", 0);
+ }
+}
+class Binary_search__fxt {
+ public void Init_ary(String... v) {
+ int ary_len = v.length;
+ ary = new String_obj_val[ary_len];
+ for (int i = 0; i < ary_len; i++)
+ ary[i] = String_obj_val.new_(v[i]);
+ } private String_obj_val[] ary;
+ public void Test_binary_search(String val, int expd) {
+ int actl = Binary_search_.Search(ary, ary.length, String_obj_val.new_(val));
+ Tfds.Eq(expd, actl, val);
+ }
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_bin_tbl.java b/400_xowa/src/gplx/fsdb/Fsdb_bin_tbl.java
new file mode 100644
index 000000000..d4b6a6ffe
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_bin_tbl.java
@@ -0,0 +1,131 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*; import gplx.ios.*;
+public class Fsdb_bin_tbl {
+ public static void Create_table(Db_provider p) {Sqlite_engine_.Tbl_create(p, Tbl_name, Tbl_sql);}
+ public static Db_stmt Insert_stmt(Db_provider p) {return Db_stmt_.new_insert_(p, Tbl_name, Fld_bin_owner_id, Fld_bin_owner_tid, Fld_bin_part_id, Fld_bin_data_url, Fld_bin_data);}
+ public static void Insert_rdr(Db_provider p, int id, byte tid, long bin_len, Io_stream_rdr bin_rdr) {
+ Db_stmt stmt = Insert_stmt(p);
+ try {Insert_rdr(stmt, id, tid, bin_len, bin_rdr);}
+ finally {stmt.Rls();}
+ }
+ public static long Insert_rdr(Db_stmt stmt, int id, byte tid, long bin_len, Io_stream_rdr bin_rdr) {
+ long rv = bin_len;
+ stmt.Clear()
+ .Val_int_(id)
+ .Val_byte_(tid)
+ .Val_int_(Null_part_id)
+ .Val_str_(Null_data_url)
+ ;
+ if (Sqlite_engine_.Supports_read_binary_stream)
+ stmt.Val_rdr_(bin_rdr, bin_len);
+ else {
+ byte[] bin_ary = Io_stream_rdr_.Load_all_as_bry(Bry_bfr.new_(), bin_rdr);
+ stmt.Val_bry_(bin_ary);
+ rv = bin_ary.length;
+ }
+ stmt.Exec_insert();
+ return rv;
+ }
+ public static void Delete(Db_provider p, int id) {
+ Db_stmt stmt = Delete_stmt(p);
+ try {Delete(stmt, id);}
+ finally {stmt.Rls();}
+ }
+ private static Db_stmt Delete_stmt(Db_provider p) {return Db_stmt_.new_delete_(p, Tbl_name, Fld_bin_owner_id);}
+ private static void Delete(Db_stmt stmt, int id) {
+ stmt.Clear()
+ .Val_int_(id)
+ .Exec_delete();
+ }
+ public static Io_stream_rdr Select_as_rdr(Db_provider p, int owner) {
+ Db_qry qry = Db_qry_.select_().From_(Tbl_name).Cols_(Fld_bin_data).Where_(Db_crt_.eq_(Fld_bin_owner_id, owner));
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ rdr = p.Exec_qry_as_rdr(qry);
+ if (rdr.MoveNextPeer()) {
+ if (Sqlite_engine_.Supports_read_binary_stream)
+ return rdr.ReadRdr(Fld_bin_data);
+ else
+ return gplx.ios.Io_stream_rdr_.mem_(Read_bin_data(rdr));
+ }
+ else
+ return gplx.ios.Io_stream_rdr_.Null;
+ }
+ finally {rdr.Rls();}
+ }
+ public static boolean Select_to_url(Db_provider p, int owner, Io_url url, byte[] bin_bfr, int bin_flush_when) {
+ Db_qry qry = Db_qry_.select_().From_(Tbl_name).Cols_(Fld_bin_data).Where_(Db_crt_.eq_(Fld_bin_owner_id, owner));
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ rdr = p.Exec_qry_as_rdr(qry);
+ if (rdr.MoveNextPeer()) {
+ if (Sqlite_engine_.Supports_read_binary_stream)
+ return Select_to_fsys__stream(rdr, url, bin_bfr, bin_flush_when);
+ else {
+ byte[] bry = Read_bin_data(rdr);
+ Io_mgr._.SaveFilBry(url, bry);
+ return true;
+ }
+ }
+ else
+ return false;
+ }
+ finally {rdr.Rls();}
+ }
+ public static boolean Select_to_fsys__stream(DataRdr rdr, Io_url url, byte[] bin_bfr, int bin_flush_when) {
+ Io_stream_rdr db_stream = Io_stream_rdr_.Null;
+ IoStream fs_stream = IoStream_.Null;
+ try {
+ db_stream = rdr.ReadRdr(Fld_bin_data); if (db_stream == Io_stream_rdr_.Null) return false;
+ fs_stream = Io_mgr._.OpenStreamWrite(url);
+ int pos = 0, flush_nxt = bin_flush_when;
+ while (true) {
+ int read = db_stream.Read(bin_bfr, pos, bin_bfr.length); if (read == Io_stream_rdr_.Read_done) break;
+ fs_stream.Write(bin_bfr, 0, read);
+ if (pos > flush_nxt) {
+ fs_stream.Flush();
+ flush_nxt += bin_flush_when;
+ }
+ }
+ fs_stream.Flush();
+ return true;
+ } finally {
+ db_stream.Rls();
+ fs_stream.Rls();
+ }
+ }
+ private static byte[] Read_bin_data(DataRdr rdr) {
+ byte[] rv = rdr.ReadBry(Fld_bin_data);
+ return rv == null ? Bry_.Empty : rv; // NOTE: bug in v0.10.1 where .ogg would save as null; return Bry_.Empty instead, else java.io.ByteArrayInputStream would fail on null
+ }
+ public static final String Tbl_name = "fsdb_bin", Fld_bin_owner_id = "bin_owner_id", Fld_bin_owner_tid = "bin_owner_tid", Fld_bin_part_id = "bin_part_id", Fld_bin_data_url = "bin_data_url", Fld_bin_data = "bin_data";
+ private static final String Tbl_sql = String_.Concat_lines_nl
+ ( "CREATE TABLE IF NOT EXISTS fsdb_bin"
+ , "( bin_owner_id integer NOT NULL PRIMARY KEY"
+ , ", bin_owner_tid byte NOT NULL"
+ , ", bin_part_id integer NOT NULL"
+ , ", bin_data_url varchar(255) NOT NULL"
+ , ", bin_data mediumblob NOT NULL"
+ , ");"
+ );
+ public static final byte Owner_tid_fil = 1, Owner_tid_thm = 2;
+ public static final int Null_db_bin_id = -1, Null_size = -1, Null_part_id = -1;
+ public static final String Null_data_url = "";
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_cfg_grp.java b/400_xowa/src/gplx/fsdb/Fsdb_cfg_grp.java
new file mode 100644
index 000000000..a1f79fa6b
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_cfg_grp.java
@@ -0,0 +1,63 @@
+/*
+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.fsdb; import gplx.*;
+public class Fsdb_cfg_grp {
+ private OrderedHash itms = OrderedHash_.new_();
+ public Fsdb_cfg_grp(String grp) {this.grp = grp;}
+ public String Grp() {return grp;} private String grp;
+ public void Insert(String key, String val) {
+ if (itms.Has(key)) throw Err_.new_fmt_("cfg_grp.Insert failed; key={0}", key);
+ Fsdb_cfg_itm itm = new Fsdb_cfg_itm(grp, key, val);
+ itms.Add(key, itm);
+ }
+ public void Update(String key, String val) {
+ Fsdb_cfg_itm itm = (Fsdb_cfg_itm)itms.Fetch(key);
+ if (itm == null) throw Err_.new_fmt_("cfg_grp.Update failed; key={0}", key);
+ itm.Val_(val);
+ }
+ public void Upsert(String key, String val) {
+ Fsdb_cfg_itm itm = (Fsdb_cfg_itm)itms.Fetch(key);
+ if (itm == null) {
+ itm = new Fsdb_cfg_itm(grp, key, val);
+ itms.Add(key, itm);
+ }
+ else
+ itm.Val_(val);
+ }
+ public boolean Get_yn_or_y(String key) {return Get_yn_or(key, Bool_.Y);}
+ public boolean Get_yn_or_n(String key) {return Get_yn_or(key, Bool_.N);}
+ public boolean Get_yn_or(String key, boolean or) {
+ String rv = Get_str_or(key, null);
+ return rv == null ? or : Yn.parse_(rv);
+ }
+ public int Get_int_or(String key, int or) {
+ String rv = Get_str_or(key, null);
+ return rv == null ? or : Int_.parse_(rv);
+ }
+ public String Get_str_or(String key, String or) {
+ Fsdb_cfg_itm itm = (Fsdb_cfg_itm)itms.Fetch(key);
+ return itm == null ? or : itm.Val();
+ }
+ public static final Fsdb_cfg_grp Null = new Fsdb_cfg_grp(); Fsdb_cfg_grp() {}
+}
+class Fsdb_cfg_itm {
+ public Fsdb_cfg_itm(String grp, String key, String val) {this.grp = grp; this.key = key; this.val = val;}
+ public String Grp() {return grp;} private String grp;
+ public String Key() {return key;} private String key;
+ public String Val() {return val;} public Fsdb_cfg_itm Val_(String v) {val = v; return this;} private String val;
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_cfg_mgr.java b/400_xowa/src/gplx/fsdb/Fsdb_cfg_mgr.java
new file mode 100644
index 000000000..c2a8b4c44
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_cfg_mgr.java
@@ -0,0 +1,79 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_cfg_mgr {
+ private HashAdp grps = HashAdp_.new_();
+ private Fsdb_cfg_tbl cfg_tbl;
+ public int Next_id() {return next_id++;} private int next_id = 1;
+ public boolean Schema_thm_page() {return schema_thm_page;} private boolean schema_thm_page = true;
+ public boolean Patch_next_id() {return patch_next_id;} private boolean patch_next_id = true;
+ public void Patch_next_id_exec(int last_id) {
+ if (last_id >= next_id)
+ next_id = last_id + 1;
+ cfg_tbl.Insert(Grp_core, Key_patch_next_id, "y");
+ }
+ public void Txn_save() {
+ this.Update_next_id();
+ }
+ public void Rls() {cfg_tbl.Rls();}
+ private void Update_next_id() {cfg_tbl.Update("core", "next_id", Int_.XtoStr(next_id));}
+ public Fsdb_cfg_mgr Update(String grp, String key, String new_val) {
+ String cur_val = cfg_tbl.Select_as_str_or(grp, key, null);
+ if (cur_val == null)
+ cfg_tbl.Insert(grp, key, new_val);
+ else
+ cfg_tbl.Update(grp, key, new_val);
+ return this;
+ }
+ public Fsdb_cfg_grp Grps_get_or_load(String grp_key) {
+ Fsdb_cfg_grp grp = (Fsdb_cfg_grp)grps.Fetch(grp_key);
+ if (grp == null) {
+ grp = cfg_tbl.Select_as_grp(grp_key);
+ grps.Add(grp_key, grp);
+ }
+ return grp;
+ }
+ public Fsdb_cfg_grp Grps_get_or_add(String grp_key) { // TEST:
+ Fsdb_cfg_grp grp = (Fsdb_cfg_grp)grps.Fetch(grp_key);
+ if (grp == null) {
+ grp = new Fsdb_cfg_grp(grp_key);
+ grps.Add(grp_key, grp);
+ }
+ return grp;
+ }
+ public static Fsdb_cfg_mgr load_(Fsdb_db_abc_mgr abc_mgr, Db_provider p) {return new Fsdb_cfg_mgr().Init_by_load(p);}
+ public static Fsdb_cfg_mgr make_(Fsdb_db_abc_mgr abc_mgr, Db_provider p) {return new Fsdb_cfg_mgr().Init_by_make(p);}
+ private Fsdb_cfg_mgr Init_by_load(Db_provider p) {
+ this.cfg_tbl = new Fsdb_cfg_tbl_sql().Ctor(p, false);
+ Fsdb_cfg_grp core_grp = Grps_get_or_load(Grp_core);
+ this.next_id = core_grp.Get_int_or(Key_next_id, -1); if (next_id == -1) throw Err_.new_("next_id not found in fsdb_cfg");
+ this.schema_thm_page = core_grp.Get_yn_or_n(Key_schema_thm_page);
+ this.patch_next_id = core_grp.Get_yn_or_n(Key_patch_next_id);
+ return this;
+ }
+ private Fsdb_cfg_mgr Init_by_make(Db_provider p) {
+ this.cfg_tbl = new Fsdb_cfg_tbl_sql().Ctor(p, true);
+ this.cfg_tbl.Insert(Grp_core, Key_next_id , "1"); // start next_id at 1
+ this.cfg_tbl.Insert(Grp_core, Key_schema_thm_page , "y"); // new dbs automatically have page and time in fsdb_xtn_tm
+ this.cfg_tbl.Insert(Grp_core, Key_patch_next_id , "y"); // new dbs automatically have correct next_id
+ return this;
+ }
+ public static final String Grp_core = "core";
+ public static final String Key_next_id = "next_id", Key_schema_thm_page = "schema.thm.page", Key_patch_next_id = "patch.next_id";
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_cfg_tbl.java b/400_xowa/src/gplx/fsdb/Fsdb_cfg_tbl.java
new file mode 100644
index 000000000..cd35e3ba5
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_cfg_tbl.java
@@ -0,0 +1,143 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public interface Fsdb_cfg_tbl extends RlsAble {
+ Fsdb_cfg_tbl Ctor(Db_provider provider, boolean created);
+ void Insert(String grp, String key, String val);
+ void Update(String grp, String key, String val);
+ int Select_as_int_or(String grp, String key, int or);
+ int Select_as_int_or_fail(String grp, String key);
+ String Select_as_str_or(String grp, String key, String or);
+ Fsdb_cfg_grp Select_as_grp(String grp);
+}
+abstract class Fsdb_cfg_tbl_base {
+ public abstract int Select_as_int_or(String grp, String key, int or);
+ public int Select_as_int_or_fail(String grp, String key) {
+ int rv = Select_as_int_or(grp, key, Int_.MinValue);
+ if (rv == Int_.MinValue) throw Err_.new_fmt_("fsdb_cfg did not have itm: grp={0} key={1}", grp, key);
+ return rv;
+ }
+}
+class Fsdb_cfg_tbl_mem extends Fsdb_cfg_tbl_base implements Fsdb_cfg_tbl {
+ private HashAdp grps = HashAdp_.new_();
+ public Fsdb_cfg_tbl Ctor(Db_provider provider, boolean created) {return this;}
+ public void Insert(String grp, String key, String val) {
+ Fsdb_cfg_grp grp_itm = Grps_get_or_make(grp);
+ grp_itm.Insert(key, val);
+ }
+ public void Update(String grp, String key, String val) {
+ Fsdb_cfg_grp grp_itm = Grps_get_or_make(grp);
+ grp_itm.Update(key, val);
+ }
+ @Override public int Select_as_int_or(String grp, String key, int or) {
+ Fsdb_cfg_grp grp_itm = Grps_get_or_null(grp);
+ return grp_itm == null ? or : grp_itm.Get_int_or(grp, or);
+ }
+ public String Select_as_str_or(String grp, String key, String or) {
+ Fsdb_cfg_grp grp_itm = Grps_get_or_null(grp);
+ return grp_itm == null ? or : grp_itm.Get_str_or(grp, or);
+ }
+ public Fsdb_cfg_grp Select_as_grp(String grp) {return Grps_get_or_null(grp);}
+ public void Rls() {}
+ private Fsdb_cfg_grp Grps_get_or_make(String grp) {
+ Fsdb_cfg_grp rv = (Fsdb_cfg_grp)grps.Fetch(grp);
+ if (rv == null) {
+ rv = new Fsdb_cfg_grp(grp);
+ grps.Add(grp, rv);
+ }
+ return rv;
+ }
+ public Fsdb_cfg_grp Grps_get_or_null(String grp) {return (Fsdb_cfg_grp)grps.Fetch(grp);}
+}
+class Fsdb_cfg_tbl_sql extends Fsdb_cfg_tbl_base implements Fsdb_cfg_tbl {
+ private Db_provider provider;
+ private Db_stmt stmt_insert, stmt_update, stmt_select;
+ public Fsdb_cfg_tbl Ctor(Db_provider provider, boolean created) {
+ this.provider = provider;
+ if (created) Create_table();
+ return this;
+ }
+ private void Create_table() {
+ Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
+ Sqlite_engine_.Idx_create(provider, Idx_main);
+ }
+ private Db_stmt Insert_stmt() {return Db_stmt_.new_insert_(provider, Tbl_name, Fld_cfg_grp, Fld_cfg_key, Fld_cfg_val);}
+ public void Insert(String grp, String key, String val) {
+ if (stmt_insert == null) stmt_insert = Insert_stmt();
+ stmt_insert.Clear()
+ .Val_str_(grp)
+ .Val_str_(key)
+ .Val_str_(val)
+ .Exec_insert();
+ }
+ private Db_stmt Update_stmt() {return Db_stmt_.new_update_(provider, Tbl_name, String_.Ary(Fld_cfg_grp, Fld_cfg_key), Fld_cfg_val);}
+ public void Update(String grp, String key, String val) {
+ if (stmt_update == null) stmt_update = Update_stmt();
+ stmt_update.Clear()
+ .Val_str_(val)
+ .Val_str_(grp)
+ .Val_str_(key)
+ .Exec_update();
+ }
+ private Db_stmt Select_stmt() {
+ Db_qry_select qry = Db_qry_.select_val_(Tbl_name, Fld_cfg_val, gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_cfg_grp, ""), Db_crt_.eq_(Fld_cfg_key, "")));
+ return provider.Prepare(qry);
+ }
+ @Override public int Select_as_int_or(String grp, String key, int or) {return Int_.parse_or_(Select_as_str_or(grp, key, null), or);}
+ public String Select_as_str_or(String grp, String key, String or) {
+ if (stmt_select == null) stmt_select = Select_stmt();
+ Object rv = (String)stmt_select.Clear()
+ .Val_str_(grp)
+ .Val_str_(key)
+ .Exec_select_val();
+ return rv == null ? or : (String)rv;
+ }
+ public Fsdb_cfg_grp Select_as_grp(String grp) {
+ Fsdb_cfg_grp rv = null;
+ Db_qry_select qry = Db_qry_.select_cols_(Tbl_name, gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_cfg_grp, "")), Fld_cfg_key, Fld_cfg_val);
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ rdr = provider.Prepare(qry).Clear().Val_str_(grp).Exec_select();
+ while (rdr.MoveNextPeer()) {
+ if (rv == null) rv = new Fsdb_cfg_grp(grp);
+ String key = rdr.ReadStr(Fld_cfg_key);
+ String val = rdr.ReadStr(Fld_cfg_val);
+ rv.Upsert(key, val);
+ }
+ }
+ finally {rdr.Rls();}
+ return rv == null ? Fsdb_cfg_grp.Null : rv;
+ }
+ public void Rls() {
+ if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
+ if (stmt_update != null) {stmt_update.Rls(); stmt_update = null;}
+ if (stmt_select != null) {stmt_select.Rls(); stmt_select = null;}
+ }
+ private static final String Tbl_name = "fsdb_cfg", Fld_cfg_grp = "cfg_grp", Fld_cfg_key = "cfg_key", Fld_cfg_val = "cfg_val";
+ private static final String Tbl_sql = String_.Concat_lines_nl
+ ( "CREATE TABLE IF NOT EXISTS fsdb_cfg"
+ , "( cfg_grp varchar(255) NOT NULL"
+ , ", cfg_key varchar(255) NOT NULL"
+ , ", cfg_val varchar(1024) NOT NULL"
+ , ");"
+ );
+ private static final Db_idx_itm
+ Idx_main = Db_idx_itm.sql_("CREATE INDEX IF NOT EXISTS fsdb_cfg__main ON fsdb_cfg (cfg_grp, cfg_key, cfg_val);")
+ ;
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_cfg_tbl_.java b/400_xowa/src/gplx/fsdb/Fsdb_cfg_tbl_.java
new file mode 100644
index 000000000..14f17c261
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_cfg_tbl_.java
@@ -0,0 +1,22 @@
+/*
+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.fsdb; import gplx.*;
+public class Fsdb_cfg_tbl_ {
+ public static Fsdb_cfg_tbl new_sql_() {return new Fsdb_cfg_tbl_sql();}
+ public static Fsdb_cfg_tbl new_mem_() {return new Fsdb_cfg_tbl_mem();}
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_db_abc_mgr.java b/400_xowa/src/gplx/fsdb/Fsdb_db_abc_mgr.java
new file mode 100644
index 000000000..1c2889515
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_db_abc_mgr.java
@@ -0,0 +1,112 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_db_abc_mgr implements RlsAble {
+ private Db_provider boot_provider;
+ public int Next_id() {return cfg_mgr.Next_id();}
+ public Fsdb_mnt_mgr Mnt_mgr() {return mnt_mgr;} private Fsdb_mnt_mgr mnt_mgr;
+ public Fsdb_db_abc_mgr(Fsdb_mnt_mgr mnt_mgr) {this.mnt_mgr = mnt_mgr;}
+ public Fsdb_db_atr_mgr Atr_mgr() {return atr_mgr;} private Fsdb_db_atr_mgr atr_mgr;
+ public Fsdb_db_bin_mgr Bin_mgr() {return bin_mgr;} private Fsdb_db_bin_mgr bin_mgr;
+ public Fsdb_cfg_mgr Cfg_mgr() {return cfg_mgr;} private Fsdb_cfg_mgr cfg_mgr;
+ public Fsdb_db_abc_mgr Init(Io_url dir) {
+ Io_url url = dir.GenSubFil("fsdb.abc.sqlite3");
+ if (Io_mgr._.ExistsFil(url))
+ Init_load(dir, url);
+ else
+ Init_make(dir, url);
+ return this;
+ }
+ public void Fil_insert(Fsdb_fil_itm rv , byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ int bin_db_id = bin_mgr.Get_id_for_insert(bin_len);
+ rv.Db_bin_id_(bin_db_id);
+ int fil_id = atr_mgr.Fil_insert(rv, dir, fil, ext_id, modified, hash, bin_db_id, bin_len, bin_rdr);
+ bin_len = bin_mgr.Insert(bin_db_id, fil_id, Fsdb_bin_tbl.Owner_tid_fil, bin_len, bin_rdr);
+ bin_mgr.Increment(bin_len);
+ }
+ public void Thm_insert(Fsdb_xtn_thm_itm rv, byte[] dir, byte[] fil, int ext_id, int w, int h, double thumbtime, int page, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ int bin_db_id = bin_mgr.Get_id_for_insert(bin_len);
+ rv.Db_bin_id_(bin_db_id);
+ int thm_id = atr_mgr.Thm_insert(rv, dir, fil, ext_id, w, h, thumbtime, page, modified, hash, bin_db_id, bin_len, bin_rdr);
+ bin_len = bin_mgr.Insert(bin_db_id, thm_id, Fsdb_bin_tbl.Owner_tid_thm, bin_len, bin_rdr);
+ bin_mgr.Increment(bin_len);
+ }
+ public void Img_insert(Fsdb_xtn_img_itm rv, byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr, int img_w, int img_h) {
+ int bin_db_id = bin_mgr.Get_id_for_insert(bin_len);
+ rv.Db_bin_id_(bin_db_id);
+ int fil_id = atr_mgr.Img_insert(rv, String_.new_utf8_(dir), String_.new_utf8_(fil), ext_id, img_w, img_h, modified, hash, bin_db_id, bin_len, bin_rdr);
+ bin_len = bin_mgr.Insert(bin_db_id, fil_id, Fsdb_bin_tbl.Owner_tid_fil, bin_len, bin_rdr);
+ bin_mgr.Increment(bin_len);
+ }
+ public boolean Thm_select_bin(byte[] dir, byte[] fil, Fsdb_xtn_thm_itm thm) {
+ Fsdb_fil_itm fil_itm = atr_mgr.Fil_select(dir, fil);
+ return atr_mgr.Thm_select(fil_itm.Id(), thm);
+ }
+ public Fsdb_fil_itm Fil_select_bin(byte[] dir, byte[] fil, boolean is_thumb, int width, double thumbtime) {
+ return atr_mgr.Fil_select(dir, fil);
+ }
+ public void Txn_open() {
+ boot_provider.Txn_mgr().Txn_bgn_if_none();
+ atr_mgr.Txn_open();
+ bin_mgr.Txn_open();
+ }
+ public void Txn_save() {
+ atr_mgr.Txn_save(boot_provider);
+ bin_mgr.Txn_save();
+ cfg_mgr.Txn_save();
+ }
+ public void Rls() {
+ atr_mgr.Rls();
+ bin_mgr.Rls();
+ cfg_mgr.Rls();
+ boot_provider.Rls();
+ }
+ private void Init_load(Io_url dir, Io_url boot_url) {
+ Db_connect connect = Db_connect_sqlite.load_(boot_url);
+ boot_provider = Db_provider_.new_(connect);
+ atr_mgr = Fsdb_db_atr_mgr.load_(this, boot_provider, dir);
+ bin_mgr = Fsdb_db_bin_mgr.load_(boot_provider, dir);
+ cfg_mgr = Fsdb_cfg_mgr.load_(this, boot_provider);
+ if (!cfg_mgr.Patch_next_id()) Fsdb_db_abc_mgr_.Patch_next_id(this, dir);
+ }
+ private void Init_make(Io_url dir, Io_url boot_url) {
+ Db_connect connect = Db_connect_sqlite.make_(boot_url);
+ boot_provider = Db_provider_.new_(connect);
+ Sqlite_engine_.Pragma_page_size_4096(boot_provider);
+ atr_mgr = Fsdb_db_atr_mgr.make_(this, boot_provider, dir);
+ bin_mgr = Fsdb_db_bin_mgr.make_(boot_provider, dir);
+ cfg_mgr = Fsdb_cfg_mgr.make_(this, boot_provider);
+ this.Txn_save(); // immediately save new entries in atr,cfg
+ }
+}
+class Fsdb_db_abc_mgr_ {
+ public static void Patch_next_id(Fsdb_db_abc_mgr abc_mgr, Io_url dir) {
+ if (!String_.Eq(dir.NameOnly(), "fsdb.user")) return;
+ Fsdb_db_atr_mgr atr_mgr = abc_mgr.Atr_mgr();
+ Fsdb_cfg_mgr cfg_mgr = abc_mgr.Cfg_mgr();
+ int last_id = -1;
+ if (atr_mgr.Len() > 0) {
+ Fsdb_db_atr_fil atr_fil = atr_mgr.Get_at(0);
+ int max_fil_id = Db_provider_.Select_fld0_as_int_or(atr_fil.Provider(), "SELECT Max(fil_id) AS MaxId FROM fsdb_fil;", -1);
+ int max_thm_id = Db_provider_.Select_fld0_as_int_or(atr_fil.Provider(), "SELECT Max(thm_id) AS MaxId FROM fsdb_xtn_thm;", -1);
+ last_id = max_fil_id > max_thm_id ? max_fil_id : max_thm_id;
+ }
+ cfg_mgr.Patch_next_id_exec(last_id);
+ }
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_db_atr_fil.java b/400_xowa/src/gplx/fsdb/Fsdb_db_atr_fil.java
new file mode 100644
index 000000000..ef5c8c4fe
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_db_atr_fil.java
@@ -0,0 +1,150 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*; import gplx.cache.*;
+public class Fsdb_db_atr_fil implements RlsAble {
+ private Gfo_cache_mgr_bry dir_cache = new Gfo_cache_mgr_bry();
+ private Fsdb_dir_tbl tbl_dir; private Fsdb_fil_tbl tbl_fil; private Fsdb_xtn_thm_tbl tbl_thm; private Fsdb_xtn_img_tbl tbl_img; private Bool_obj_ref img_needs_create = Bool_obj_ref.n_();
+ public Fsdb_db_atr_fil(Fsdb_db_abc_mgr abc_mgr, Io_url url, boolean create) {
+ this.abc_mgr = abc_mgr;
+ Db_connect connect = create ? Db_connect_sqlite.make_(url) : Db_connect_sqlite.load_(url);
+ provider = Db_provider_.new_(connect);
+ Sqlite_engine_.Pragma_page_size_4096(provider);
+ tbl_dir = new Fsdb_dir_tbl(provider, create);
+ tbl_fil = new Fsdb_fil_tbl(provider, create);
+ tbl_thm = new Fsdb_xtn_thm_tbl(this, provider, create);
+ tbl_img = new Fsdb_xtn_img_tbl(provider, create);
+ }
+ public Fsdb_db_abc_mgr Abc_mgr() {return abc_mgr;} private Fsdb_db_abc_mgr abc_mgr;
+ public Db_provider Provider() {return provider;} private Db_provider provider;
+ public int Id() {return id;} private int id;
+ public Io_url Url() {return url;} private Io_url url;
+ public String Path_bgn() {return path_bgn;} private String path_bgn;
+ public byte Cmd_mode() {return cmd_mode;} public Fsdb_db_atr_fil Cmd_mode_(byte v) {cmd_mode = v; return this;} private byte cmd_mode;
+ public void Rls() {
+ tbl_dir.Rls();
+ tbl_fil.Rls();
+ tbl_img.Rls();
+ tbl_thm.Rls();
+ provider.Txn_mgr().Txn_end_all();
+ provider.Rls();
+ }
+ public void Txn_open() {
+ provider.Txn_mgr().Txn_bgn_if_none();
+ }
+ public void Txn_save() {
+ provider.Txn_mgr().Txn_end_all();
+ }
+ public Fsdb_fil_itm Fil_select(byte[] dir, byte[] fil) {
+ Int_obj_ref dir_id_obj = (Int_obj_ref)dir_cache.Get_or_null(dir);
+ int dir_id = -1;
+ if (dir_id_obj == null) {
+ Fsdb_dir_itm dir_itm = tbl_dir.Select_itm(String_.new_utf8_(dir));
+ dir_id = dir_itm == Fsdb_dir_itm.Null ? -1 : dir_itm.Id();
+ dir_cache.Add(dir, Int_obj_ref.new_(dir_id));
+ }
+ else
+ dir_id = dir_id_obj.Val();
+ if (dir_id == Int_.Neg1) return Fsdb_fil_itm.Null;
+ return tbl_fil.Select_itm_by_name(dir_id, String_.new_utf8_(fil));
+ }
+ public boolean Thm_select(int owner_id, Fsdb_xtn_thm_itm thm) {
+ return tbl_thm.Select_itm_by_fil_width(owner_id, thm);
+ }
+ public int Fil_insert(Fsdb_fil_itm rv, String dir, String fil, int ext_id, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ int dir_id = Dir_id__get_or_insert(dir);
+ int fil_id = Fil_id__get_or_insert(Fsdb_xtn_tid_.Tid_none, dir_id, fil, ext_id, modified, hash, bin_db_id, bin_len);
+ rv.Id_(fil_id).Owner_(dir_id);
+ return fil_id;
+ }
+ public int Img_insert(Fsdb_xtn_img_itm rv, String dir, String fil, int ext_id, int img_w, int img_h, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ int dir_id = Dir_id__get_or_insert(dir);
+ img_needs_create.Val_(false);
+ int fil_id = Fil_id__get_or_insert(Fsdb_xtn_tid_.Tid_img, dir_id, fil, ext_id, modified, hash, bin_db_id, bin_len);
+ if (img_needs_create.Val()) // NOTE: fsdb_fil row can already exist; EX: thm gets inserted -> fsdb_fil row gets created with -1 bin_db_id; orig gets inserted -> fsdb_fil row already exists
+ tbl_img.Insert(fil_id, img_w, img_h);
+ rv.Id_(fil_id);
+ return fil_id;
+ }
+ public int Thm_insert(Fsdb_xtn_thm_itm rv, String dir, String fil, int ext_id, int thm_w, int thm_h, double thumbtime, int page, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ int dir_id = Dir_id__get_or_insert(dir);
+ int fil_id = Fil_id__get_or_insert(Fsdb_xtn_tid_.Tid_thm, dir_id, fil, ext_id, modified, hash, Fsdb_bin_tbl.Null_db_bin_id, Fsdb_bin_tbl.Null_size); // NOTE: bin_db_id must be set to NULL
+ int thm_id = abc_mgr.Next_id();
+ tbl_thm.Insert(thm_id, fil_id, thm_w, thm_h, thumbtime, page, bin_db_id, bin_len, modified, hash);
+ rv.Id_(thm_id).Owner_id_(fil_id).Dir_id_(dir_id);
+ return thm_id;
+ }
+ public static Fsdb_db_atr_fil load_(Fsdb_db_abc_mgr abc_mgr, DataRdr rdr, Io_url dir) {
+ Io_url url = dir.GenSubFil(rdr.ReadStr(Fsdb_db_atr_tbl.Fld_url));
+ Fsdb_db_atr_fil rv = new Fsdb_db_atr_fil(abc_mgr, url, false);
+ rv.id = rdr.ReadInt(Fsdb_db_atr_tbl.Fld_uid);
+ rv.url = url;
+ rv.path_bgn = rdr.ReadStr(Fsdb_db_atr_tbl.Fld_path_bgn);
+ rv.cmd_mode = Db_cmd_mode.Ignore;
+ return rv;
+ }
+ public static Fsdb_db_atr_fil make_(Fsdb_db_abc_mgr abc_mgr, int id, Io_url url, String path_bgn) {
+ Fsdb_db_atr_fil rv = new Fsdb_db_atr_fil(abc_mgr, url, true);
+ rv.id = id;
+ rv.url = url;
+ rv.path_bgn = path_bgn;
+ rv.cmd_mode = Db_cmd_mode.Create;
+ return rv;
+ }
+ private int Dir_id__get_or_insert(String dir_str) {
+ byte[] dir_bry = Bry_.new_utf8_(dir_str);
+ Object rv_obj = dir_cache.Get_or_null(dir_bry);
+ int rv = -1;
+ if (rv_obj != null) { // item found
+ rv = ((Int_obj_ref)rv_obj).Val();
+ if (rv == -1) // dir was previously -1; occurs when doing select on empty db (no dir, so -1 added) and then doing insert (-1 now needs to be dropped)
+ dir_cache.Del(dir_bry);
+ }
+ if (rv == -1) {
+ Fsdb_dir_itm itm = tbl_dir.Select_itm(dir_str);
+ if (itm == Fsdb_dir_itm.Null) {
+ rv = abc_mgr.Next_id();
+ tbl_dir.Insert(rv, dir_str, 0); // 0: always assume root owner
+ }
+ else {
+ rv = itm.Id();
+ }
+ dir_cache.Add(dir_bry, Int_obj_ref.new_(rv));
+ }
+ return rv;
+ }
+ private int Fil_id__get_or_insert(int xtn_tid, int dir_id, String fil, int ext_id, DateAdp modified, String hash, int bin_db_id, long bin_len) {
+ Fsdb_fil_itm fil_itm = tbl_fil.Select_itm_by_name(dir_id, fil);
+ int fil_id = fil_itm.Id();
+ if (fil_id == Fsdb_fil_itm.Null_id) { // new item
+ fil_id = abc_mgr.Next_id();
+ tbl_fil.Insert(fil_id, dir_id, fil, xtn_tid, ext_id, bin_len, modified, hash, bin_db_id);
+ img_needs_create.Val_(true);
+ }
+ else { // existing item
+ if ( fil_itm.Db_bin_id() == Fsdb_bin_tbl.Null_db_bin_id // prv row was previously inserted by thumb
+ && xtn_tid != Fsdb_xtn_tid_.Tid_thm // cur row is not thumb
+ ) {
+ tbl_fil.Update(fil_id, dir_id, fil, xtn_tid, ext_id, bin_len, modified, hash, bin_db_id); // update props; note that thumb inserts null props, whereas file will insert real props (EX: bin_db_id)
+ if (xtn_tid == Fsdb_xtn_tid_.Tid_img)
+ img_needs_create.Val_(true);
+ }
+ }
+ return fil_id;
+ }
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_db_atr_mgr.java b/400_xowa/src/gplx/fsdb/Fsdb_db_atr_mgr.java
new file mode 100644
index 000000000..aadd01d7b
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_db_atr_mgr.java
@@ -0,0 +1,76 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*; import gplx.cache.*;
+public class Fsdb_db_atr_mgr implements RlsAble {
+ private Fsdb_db_atr_fil[] itms; private Fsdb_db_atr_fil itms_0;
+ public int Len() {return itms.length;}
+ public Fsdb_db_atr_fil Get_at(int i) {return i == Id_0 ? itms_0 : itms[i];}
+ public Fsdb_fil_itm Fil_select(byte[] dir, byte[] fil) {return itms_0.Fil_select(dir, fil);}
+ public boolean Thm_select(int owner_id, Fsdb_xtn_thm_itm thm) {return itms_0.Thm_select(owner_id, thm);}
+ public int Fil_insert(Fsdb_fil_itm rv , byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ return itms_0.Fil_insert(rv, String_.new_utf8_(dir), String_.new_utf8_(fil), ext_id, modified, hash, bin_db_id, bin_len, bin_rdr);
+ }
+ public int Img_insert(Fsdb_xtn_img_itm rv, String dir, String fil, int ext_id, int img_w, int img_h, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ return itms_0.Img_insert(rv, dir, fil, ext_id, img_w, img_h, modified, hash, bin_db_id, bin_len, bin_rdr);
+ }
+ public int Thm_insert(Fsdb_xtn_thm_itm rv, byte[] dir, byte[] fil, int ext_id, int width, int height, double thumbtime, int page, DateAdp modified, String hash, int bin_db_id, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ return itms_0.Thm_insert(rv, String_.new_utf8_(dir), String_.new_utf8_(fil), ext_id, width, height, thumbtime, page, modified, hash, bin_db_id, bin_len, bin_rdr);
+ }
+ public void Txn_open() {
+ int len = itms.length;
+ for (int i = 0; i < len; i++) {
+ Fsdb_db_atr_fil itm = itms[i];
+ itm.Txn_open();
+ }
+ }
+ public void Txn_save(Db_provider provider) {
+ Fsdb_db_atr_tbl.Commit_all(provider, itms);
+ int len = itms.length;
+ for (int i = 0; i < len; i++) {
+ Fsdb_db_atr_fil itm = itms[i];
+ itm.Txn_save();
+ }
+ }
+ public void Rls() {
+ int len = itms.length;
+ for (int i = 0; i < len; i++) {
+ Fsdb_db_atr_fil itm = itms[i];
+ itm.Rls();
+ }
+ }
+ public static Fsdb_db_atr_mgr load_(Fsdb_db_abc_mgr abc_mgr, Db_provider p, Io_url dir) {
+ Fsdb_db_atr_mgr rv = new Fsdb_db_atr_mgr();
+ rv.itms = Fsdb_db_atr_tbl.Select_all(abc_mgr, p, dir);
+ rv.itms_0 = rv.itms[0];
+ return rv;
+ }
+ public static Fsdb_db_atr_mgr make_(Fsdb_db_abc_mgr abc_mgr, Db_provider p, Io_url dir) {
+ Fsdb_db_atr_tbl.Create_table(p);
+ Fsdb_db_atr_mgr rv = new Fsdb_db_atr_mgr();
+ Fsdb_db_atr_fil itm = Fsdb_db_atr_fil.make_(abc_mgr, Id_0, url_(dir, Id_0), Path_bgn_0);
+ rv.itms_0 = itm;
+ rv.itms = new Fsdb_db_atr_fil[] {itm};
+ return rv;
+ }
+ private static Io_url url_(Io_url dir, int id) {
+ return dir.GenSubFil_ary("fsdb.atr.", Int_.XtoStr_PadBgn(id, 2), ".sqlite3");
+ }
+ public static final int Id_0 = 0;
+ public static final String Path_bgn_0 = "";
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_db_atr_tbl.java b/400_xowa/src/gplx/fsdb/Fsdb_db_atr_tbl.java
new file mode 100644
index 000000000..177c8523d
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_db_atr_tbl.java
@@ -0,0 +1,64 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_db_atr_tbl {
+ public static void Create_table(Db_provider p) {Sqlite_engine_.Tbl_create(p, Tbl_name, Tbl_sql);}
+ public static Fsdb_db_atr_fil[] Select_all(Fsdb_db_abc_mgr abc_mgr, Db_provider p, Io_url dir) {
+ ListAdp rv = ListAdp_.new_();
+ Db_qry qry = Db_qry_select.new_().From_(Tbl_name).Cols_all_().OrderBy_asc_(Fld_uid);
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ rdr = p.Exec_qry_as_rdr(qry);
+ while (rdr.MoveNextPeer()) {
+ Fsdb_db_atr_fil itm = Fsdb_db_atr_fil.load_(abc_mgr, rdr, dir);
+ rv.Add(itm);
+ }
+ } finally {rdr.Rls();}
+ return (Fsdb_db_atr_fil[])rv.XtoAry(Fsdb_db_atr_fil.class);
+ }
+ public static void Commit_all(Db_provider provider, Fsdb_db_atr_fil[] ary) {
+ stmt_bldr.Init(provider);
+ try {
+ int len = ary.length;
+ for (int i = 0; i < len; i++)
+ Commit_itm(ary[i]);
+ stmt_bldr.Commit();
+ } finally {stmt_bldr.Rls();}
+ }
+ private static void Commit_itm(Fsdb_db_atr_fil itm) {
+ Db_stmt stmt = stmt_bldr.Get(itm.Cmd_mode());
+ switch (itm.Cmd_mode()) {
+ case Db_cmd_mode.Create: stmt.Clear().Val_int_(itm.Id()) .Val_str_(itm.Url().NameAndExt()).Val_str_(itm.Path_bgn()).Exec_insert(); break;
+ case Db_cmd_mode.Update: stmt.Clear() .Val_str_(itm.Url().NameAndExt()).Val_str_(itm.Path_bgn()).Val_int_(itm.Id()).Exec_update(); break;
+ case Db_cmd_mode.Delete: stmt.Clear().Val_int_(itm.Id()).Exec_delete(); break;
+ case Db_cmd_mode.Ignore: break;
+ default: throw Err_.unhandled(itm.Cmd_mode());
+ }
+ itm.Cmd_mode_(Db_cmd_mode.Ignore);
+ }
+ public static final String Tbl_name = "fsdb_db_atr", Fld_uid = "uid", Fld_url = "url", Fld_path_bgn = "path_bgn";
+ private static final String Tbl_sql = String_.Concat_lines_nl
+ ( "CREATE TABLE IF NOT EXISTS fsdb_db_atr"
+ , "( uid integer NOT NULL PRIMARY KEY"
+ , ", url varchar(255) NOT NULL"
+ , ", path_bgn varchar(255) NOT NULL"
+ , ");"
+ );
+ private static Db_stmt_bldr stmt_bldr = new Db_stmt_bldr(Tbl_name, String_.Ary(Fld_uid), Fld_url, Fld_path_bgn);
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_db_bin_fil.java b/400_xowa/src/gplx/fsdb/Fsdb_db_bin_fil.java
new file mode 100644
index 000000000..597726e51
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_db_bin_fil.java
@@ -0,0 +1,85 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*; import gplx.ios.*;
+public class Fsdb_db_bin_fil implements RlsAble {
+ public int Id() {return id;} private int id;
+ public Io_url Url() {return url;} private Io_url url;
+ public long Bin_max() {return bin_max;} private long bin_max;
+ public void Bin_max_(long v) {
+ bin_max = v;
+ if (cmd_mode == Db_cmd_mode.Ignore) cmd_mode = Db_cmd_mode.Update;
+ }
+ public long Bin_len() {return bin_len;} private long bin_len;
+ public void Bin_len_(long v) {
+ bin_len = v;
+ if (cmd_mode == Db_cmd_mode.Ignore) cmd_mode = Db_cmd_mode.Update;
+ }
+ public byte Cmd_mode() {return cmd_mode;} public Fsdb_db_bin_fil Cmd_mode_(byte v) {cmd_mode = v; return this;} private byte cmd_mode;
+ public Db_provider Provider() {
+ if (provider == null) {
+ if (cmd_mode == Db_cmd_mode.Create) {
+ provider = Db_provider_.new_(Db_connect_sqlite.make_(url));
+ Sqlite_engine_.Pragma_page_size_4096(provider);
+ Fsdb_bin_tbl.Create_table(provider);
+ }
+ else
+ provider = Db_provider_.new_(Db_connect_sqlite.load_(url));
+ }
+ return provider;
+ } private Db_provider provider;
+ public void Rls() {if (provider != null) provider.Rls();}
+ public long Insert(int bin_id, byte owner_tid, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ Db_stmt stmt = Db_stmt_.Null;
+ try {
+ stmt = Fsdb_bin_tbl.Insert_stmt(this.Provider());
+ return Fsdb_bin_tbl.Insert_rdr(stmt, bin_id, owner_tid, bin_len, bin_rdr);
+ }
+ finally {stmt.Rls();}
+ }
+ public boolean Get_to_url(int id, Io_url url, byte[] bin_bfr, int bin_flush_when) {
+ return Fsdb_bin_tbl.Select_to_url(this.Provider(), id, url, bin_bfr, bin_flush_when);
+ }
+ public Io_stream_rdr Get_as_rdr(int id) {
+ return Fsdb_bin_tbl.Select_as_rdr(this.Provider(), id);
+ }
+ public static Fsdb_db_bin_fil load_(DataRdr rdr, Io_url dir) {
+ return new_
+ ( rdr.ReadInt(Fsdb_db_bin_tbl.Fld_uid)
+ , dir.GenSubFil(rdr.ReadStr(Fsdb_db_bin_tbl.Fld_url))
+ , rdr.ReadLong(Fsdb_db_bin_tbl.Fld_bin_len)
+ , rdr.ReadLong(Fsdb_db_bin_tbl.Fld_bin_max)
+ , Db_cmd_mode.Ignore
+ );
+ }
+ public static Fsdb_db_bin_fil make_(int id, Io_url url, long bin_len, long bin_max) {
+ Fsdb_db_bin_fil rv = new_(id, url, bin_len, bin_max, Db_cmd_mode.Create);
+ rv.Provider(); // force table create
+ return rv;
+ }
+ private static Fsdb_db_bin_fil new_(int id, Io_url url, long bin_len, long bin_max, byte cmd_mode) {
+ Fsdb_db_bin_fil rv = new Fsdb_db_bin_fil();
+ rv.id = id;
+ rv.url = url;
+ rv.bin_len = bin_len;
+ rv.bin_max = bin_max;
+ rv.cmd_mode = cmd_mode;
+ return rv;
+ }
+ public static final Fsdb_db_bin_fil[] Ary_empty = new Fsdb_db_bin_fil[0];
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_db_bin_mgr.java b/400_xowa/src/gplx/fsdb/Fsdb_db_bin_mgr.java
new file mode 100644
index 000000000..c2775d110
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_db_bin_mgr.java
@@ -0,0 +1,99 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_db_bin_mgr implements RlsAble {
+ private Io_url dir;
+ private Fsdb_db_bin_fil[] itms = Fsdb_db_bin_fil.Ary_empty; private int itms_len = 0;
+ private Fsdb_db_bin_fil itms_n;
+ private Db_provider provider;
+ private Fsdb_db_bin_mgr(Io_url dir) {this.dir = dir;}
+ public int Len() {return itms.length;}
+ public long Db_bin_max() {return db_bin_max;}
+ public int Insert_to_bin() {return insert_to_bin;} public Fsdb_db_bin_mgr Insert_to_bin_(int v) {insert_to_bin = v; return this;} private int insert_to_bin = Fsdb_mnt_mgr.Insert_to_bin_null;
+ public Fsdb_db_bin_mgr Db_bin_max_(long v) {
+ db_bin_max = v;
+ for (int i = 0; i < itms_len; i++)
+ itms[i].Bin_max_(v);
+ return this;
+ } private long db_bin_max = Io_mgr.Len_mb * Long_.X_by_int(188);
+ public Fsdb_db_bin_fil Get_at(int i) {return itms[i];}
+ private Fsdb_db_bin_fil Get_cur() {return itms_len == 0 ? null : itms[itms_len - 1];}
+ public void Txn_open() {
+ Get_cur().Provider().Txn_mgr().Txn_bgn_if_none();
+ }
+ public void Txn_save() {
+ Fsdb_db_bin_tbl.Commit_all(provider, itms);
+ Get_cur().Provider().Txn_mgr().Txn_end_all();
+ }
+ public void Rls() {
+ int len = itms.length;
+ for (int i = 0; i < len; i++) {
+ Fsdb_db_bin_fil itm = itms[i];
+ itm.Rls();
+ }
+ }
+ public int Get_id_for_insert(long bin_len) {
+ if (insert_to_bin != Fsdb_mnt_mgr.Insert_to_bin_null) return insert_to_bin; // insert_to_bin specified; return it
+ if (itms_n.Bin_len() > itms_n.Bin_max())
+ Itms_add(0);
+ return itms_n.Id();
+ }
+ public void Increment(long bin_len) {
+ long new_bin_len = itms_n.Bin_len() + bin_len;
+ itms_n.Bin_len_(new_bin_len);
+ }
+ public long Insert(int db_id, int bin_id, byte owner_tid, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ Fsdb_db_bin_fil bin_fil = itms[db_id];
+ return bin_fil.Insert(bin_id, owner_tid, bin_len, bin_rdr);
+ }
+ public static Fsdb_db_bin_mgr load_(Db_provider p, Io_url dir) {
+ Fsdb_db_bin_mgr rv = new Fsdb_db_bin_mgr(dir);
+ rv.provider = p;
+ rv.itms = Fsdb_db_bin_tbl.Select_all(p, dir);
+ rv.itms_len = rv.itms.length;
+ rv.itms_n = rv.itms[rv.itms_len - 1];
+ return rv;
+ }
+ public static Fsdb_db_bin_mgr make_(Db_provider p, Io_url dir) {
+ Fsdb_db_bin_tbl.Create_table(p);
+ Fsdb_db_bin_mgr rv = new Fsdb_db_bin_mgr(dir);
+ rv.provider = p;
+ rv.Itms_add(0);
+ return rv;
+ }
+ private void Itms_add(long bin_len) {
+ Fsdb_db_bin_fil cur = Get_cur();
+ if (cur != null) {
+ cur.Provider().Txn_mgr().Txn_end_all();
+ cur.Provider().Rls();
+ }
+ int new_itms_len = itms_len + 1;
+ Fsdb_db_bin_fil[] new_itms = new Fsdb_db_bin_fil[new_itms_len];
+ for (int i = 0; i < itms_len; i++)
+ new_itms[i] = itms[i];
+ itms_n = Fsdb_db_bin_fil.make_(itms_len, url_(dir, itms_len), bin_len, db_bin_max);
+ itms = new_itms;
+ itms_len = new_itms_len;
+ itms[itms_len - 1] = itms_n;
+ this.Txn_open();
+ }
+ private static Io_url url_(Io_url dir, int id) {
+ return dir.GenSubFil_ary("fsdb.bin.", Int_.XtoStr_PadBgn(id, 4), ".sqlite3");
+ }
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_db_bin_tbl.java b/400_xowa/src/gplx/fsdb/Fsdb_db_bin_tbl.java
new file mode 100644
index 000000000..862ca34da
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_db_bin_tbl.java
@@ -0,0 +1,65 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_db_bin_tbl {
+ public static void Create_table(Db_provider p) {Sqlite_engine_.Tbl_create(p, Tbl_name, Tbl_sql);}
+ public static void Commit_all(Db_provider provider, Fsdb_db_bin_fil[] ary) {
+ stmt_bldr.Init(provider);
+ try {
+ int len = ary.length;
+ for (int i = 0; i < len; i++)
+ Commit_itm(ary[i]);
+ stmt_bldr.Commit();
+ } finally {stmt_bldr.Rls();}
+ }
+ private static void Commit_itm(Fsdb_db_bin_fil itm) {
+ Db_stmt stmt = stmt_bldr.Get(itm.Cmd_mode());
+ switch (itm.Cmd_mode()) {
+ case Db_cmd_mode.Create: stmt.Clear().Val_int_(itm.Id()) .Val_str_(itm.Url().NameAndExt()).Val_long_(itm.Bin_len()).Val_long_(itm.Bin_max()).Exec_insert(); break;
+ case Db_cmd_mode.Update: stmt.Clear() .Val_str_(itm.Url().NameAndExt()).Val_long_(itm.Bin_len()).Val_long_(itm.Bin_max()).Val_int_(itm.Id()).Exec_update(); break;
+ case Db_cmd_mode.Delete: stmt.Clear().Val_int_(itm.Id()).Exec_delete(); break;
+ case Db_cmd_mode.Ignore: break;
+ default: throw Err_.unhandled(itm.Cmd_mode());
+ }
+ itm.Cmd_mode_(Db_cmd_mode.Ignore);
+ }
+ public static Fsdb_db_bin_fil[] Select_all(Db_provider p, Io_url dir) {
+ ListAdp rv = ListAdp_.new_();
+ Db_qry qry = Db_qry_select.new_().From_(Tbl_name).Cols_all_().OrderBy_asc_(Fld_uid);
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ rdr = p.Exec_qry_as_rdr(qry);
+ while (rdr.MoveNextPeer()) {
+ Fsdb_db_bin_fil itm = Fsdb_db_bin_fil.load_(rdr, dir);
+ rv.Add(itm);
+ }
+ } finally {rdr.Rls();}
+ return (Fsdb_db_bin_fil[])rv.XtoAry(Fsdb_db_bin_fil.class);
+ }
+ public static final String Tbl_name = "fsdb_db_bin", Fld_uid = "uid", Fld_url = "url", Fld_bin_len = "bin_len", Fld_bin_max = "bin_max";
+ private static final String Tbl_sql = String_.Concat_lines_nl
+ ( "CREATE TABLE IF NOT EXISTS fsdb_db_bin"
+ , "( uid integer NOT NULL PRIMARY KEY"
+ , ", url varchar(255) NOT NULL"
+ , ", bin_len bigint NOT NULL"
+ , ", bin_max bigint NOT NULL"
+ , ");"
+ );
+ private static Db_stmt_bldr stmt_bldr = new Db_stmt_bldr(Tbl_name, String_.Ary(Fld_uid), Fld_url, Fld_bin_len, Fld_bin_max);
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_dir_itm.java b/400_xowa/src/gplx/fsdb/Fsdb_dir_itm.java
new file mode 100644
index 000000000..329c19afc
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_dir_itm.java
@@ -0,0 +1,25 @@
+/*
+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.fsdb; import gplx.*;
+public class Fsdb_dir_itm {
+ public Fsdb_dir_itm(int id, int owner, String name) {this.id = id; this.owner = owner; this.name = name;}
+ public int Id() {return id;} public Fsdb_dir_itm Id_(int v) {id = v; return this;} private int id;
+ public int Owner() {return owner;} public Fsdb_dir_itm Owner_(int v) {owner = v; return this;} private int owner;
+ public String Name() {return name;} public Fsdb_dir_itm Name_(String v) {name = v; return this;} private String name;
+ public static final Fsdb_dir_itm Null = new Fsdb_dir_itm(0, 0, "");
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_dir_tbl.java b/400_xowa/src/gplx/fsdb/Fsdb_dir_tbl.java
new file mode 100644
index 000000000..f334b5d43
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_dir_tbl.java
@@ -0,0 +1,87 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_dir_tbl {
+ private Db_provider provider;
+ private Db_stmt stmt_insert, stmt_update, stmt_select_by_name;
+ public Fsdb_dir_tbl(Db_provider provider, boolean created) {
+ this.provider = provider;
+ if (created) Create_table();
+ }
+ public void Rls() {
+ if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
+ if (stmt_update != null) {stmt_update.Rls(); stmt_update = null;}
+ if (stmt_select_by_name != null) {stmt_select_by_name.Rls(); stmt_select_by_name = null;}
+ }
+ public void Create_table() {
+ Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
+ Sqlite_engine_.Idx_create(provider, Idx_name);
+ }
+ private Db_stmt Insert_stmt() {return Db_stmt_.new_insert_(provider, Tbl_name, Fld_dir_id, Fld_dir_owner_id, Fld_dir_name);}
+ public void Insert(int id, String name, int owner_id) {
+ if (stmt_insert == null) stmt_insert = Insert_stmt();
+ try {
+ stmt_insert.Clear()
+ .Val_int_(id)
+ .Val_int_(owner_id)
+ .Val_str_(name)
+ .Exec_insert();
+ } catch (Exception exc) {stmt_insert = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
+ }
+ private Db_stmt Update_stmt() {return Db_stmt_.new_update_(provider, Tbl_name, String_.Ary(Fld_dir_id), Fld_dir_owner_id, Fld_dir_name);}
+ public void Update(int id, String name, int owner_id) {
+ if (stmt_update == null) stmt_update = Update_stmt();
+ try {
+ stmt_update.Clear()
+ .Val_int_(id)
+ .Val_str_(name)
+ .Val_int_(owner_id)
+ .Exec_update();
+ } catch (Exception exc) {stmt_update = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
+ }
+ private Db_stmt Select_itm_stmt() {
+ Db_qry qry = Db_qry_.select_().From_(Tbl_name).Cols_(Fld_dir_id, Fld_dir_owner_id).Where_(Db_crt_.eq_(Fld_dir_name, Bry_.Empty));
+ return provider.Prepare(qry);
+ }
+ public Fsdb_dir_itm Select_itm(String dir_name) {
+ if (stmt_select_by_name == null) stmt_select_by_name = Select_itm_stmt();
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ rdr = stmt_select_by_name.Clear()
+ .Val_str_(dir_name)
+ .Exec_select();
+ while (rdr.MoveNextPeer()) {
+ return new Fsdb_dir_itm(rdr.ReadInt(Fld_dir_id), rdr.ReadInt(Fld_dir_owner_id), dir_name);
+ }
+ return Fsdb_dir_itm.Null;
+ }
+ finally {rdr.Rls();}
+ }
+ public static final String Tbl_name = "fsdb_dir", Fld_dir_id = "dir_id", Fld_dir_owner_id = "dir_owner_id", Fld_dir_name = "dir_name";
+ private static final String Tbl_sql = String_.Concat_lines_nl
+ ( "CREATE TABLE IF NOT EXISTS fsdb_dir"
+ , "( dir_id integer NOT NULL PRIMARY KEY"
+ , ", dir_owner_id integer NOT NULL"
+ , ", dir_name varchar(255) NOT NULL"
+ , ");"
+ );
+ public static final Db_idx_itm
+ Idx_name = Db_idx_itm.sql_("CREATE INDEX IF NOT EXISTS fsdb_dir__name ON fsdb_dir (dir_name, dir_owner_id, dir_id);")
+ ;
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_fil_itm.java b/400_xowa/src/gplx/fsdb/Fsdb_fil_itm.java
new file mode 100644
index 000000000..f520717d0
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_fil_itm.java
@@ -0,0 +1,29 @@
+/*
+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.fsdb; import gplx.*;
+public class Fsdb_fil_itm {
+ public int Id() {return id;} public Fsdb_fil_itm Id_(int v) {id = v; return this;} private int id;
+ public int Owner() {return owner;} public Fsdb_fil_itm Owner_(int v) {owner = v; return this;} private int owner;
+ public int Ext_id() {return ext_id;} public Fsdb_fil_itm Ext_id_(int v) {ext_id = v; return this;} private int ext_id;
+ public String Name() {return name;} public Fsdb_fil_itm Name_(String v) {name = v; return this;} private String name;
+ public int Db_bin_id() {return bin_db_id;} public Fsdb_fil_itm Db_bin_id_(int v) {bin_db_id = v; return this;} private int bin_db_id;
+ public int Mnt_id() {return mnt_id;} public Fsdb_fil_itm Mnt_id_(int v) {mnt_id = v; return this;} private int mnt_id;
+ public Fsdb_fil_itm Init(int id, int owner, int ext_id, String name, int bin_db_id) {this.id = id; this.owner = owner; this.ext_id = ext_id; this.name = name; this.bin_db_id = bin_db_id; return this;}
+ public static final int Null_id = 0;
+ public static final Fsdb_fil_itm Null = new Fsdb_fil_itm().Init(Null_id, 0, 0, "", Fsdb_bin_tbl.Null_db_bin_id);
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_fil_tbl.java b/400_xowa/src/gplx/fsdb/Fsdb_fil_tbl.java
new file mode 100644
index 000000000..5aaf0bf63
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_fil_tbl.java
@@ -0,0 +1,134 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_fil_tbl {
+ private Db_provider provider;
+ private Db_stmt stmt_insert, stmt_update, stmt_select_by_name, stmt_select_by_id;
+ public Fsdb_fil_tbl(Db_provider provider, boolean created) {
+ this.provider = provider;
+ if (created) Create_table();
+ }
+ private void Create_table() {
+ Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
+ Sqlite_engine_.Idx_create(provider, Idx_owner);
+ }
+ public void Rls() {
+ if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
+ if (stmt_update != null) {stmt_update.Rls(); stmt_update = null;}
+ if (stmt_select_by_name != null) {stmt_select_by_name.Rls(); stmt_select_by_name = null;}
+ if (stmt_select_by_id != null) {stmt_select_by_id.Rls(); stmt_select_by_id = null;}
+ }
+ private Db_stmt Insert_stmt() {return Db_stmt_.new_insert_(provider, Tbl_name, Fld_fil_id, Fld_fil_owner_id, Fld_fil_name, Fld_fil_xtn_id, Fld_fil_ext_id, Fld_fil_bin_db_id, Fld_fil_size, Fld_fil_modified, Fld_fil_hash);}
+ public void Insert(int id, int owner_id, String name, int xtn_id, int ext_id, long size, DateAdp modified, String hash, int bin_db_id) {
+ if (stmt_insert == null) stmt_insert = Insert_stmt();
+ try {
+ stmt_insert.Clear()
+ .Val_int_(id)
+ .Val_int_(owner_id)
+ .Val_str_(name)
+ .Val_int_(xtn_id)
+ .Val_int_(ext_id)
+ .Val_int_(bin_db_id)
+ .Val_long_(size)
+ .Val_str_(Sqlite_engine_.X_date_to_str(modified))
+ .Val_str_(hash)
+ .Exec_insert();
+ } catch (Exception exc) {stmt_insert = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
+ }
+ private Db_stmt Update_stmt() {return Db_stmt_.new_update_(provider, Tbl_name, String_.Ary(Fld_fil_id), Fld_fil_owner_id, Fld_fil_name, Fld_fil_xtn_id, Fld_fil_ext_id, Fld_fil_bin_db_id, Fld_fil_size, Fld_fil_modified, Fld_fil_hash);}
+ public void Update(int id, int owner_id, String name, int xtn_id, int ext_id, long size, DateAdp modified, String hash, int bin_db_id) {
+ if (stmt_update == null) stmt_update = Update_stmt();
+ try {
+ stmt_update.Clear()
+ .Val_int_(owner_id)
+ .Val_str_(name)
+ .Val_int_(xtn_id)
+ .Val_int_(ext_id)
+ .Val_int_(bin_db_id)
+ .Val_long_(size)
+ .Val_str_(Sqlite_engine_.X_date_to_str(modified))
+ .Val_str_(hash)
+ .Val_int_(id)
+ .Exec_update();
+ } catch (Exception exc) {stmt_update = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
+ }
+ private Db_stmt Select_by_name_stmt() {
+ Db_qry qry = Sqlite_engine_.Supports_indexed_by
+ ? (Db_qry)Db_qry_sql.rdr_("SELECT * FROM fsdb_fil INDEXED BY fsdb_fil__owner WHERE fil_owner_id = ? AND fil_name = ?;")
+ : Db_qry_.select_().From_(Tbl_name).Cols_all_().Where_(gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_fil_owner_id, Int_.MinValue), Db_crt_.eq_(Fld_fil_name, "")))
+ ;
+ return provider.Prepare(qry);
+ }
+ public Fsdb_fil_itm Select_itm_by_name(int dir_id, String fil_name) {
+ if (stmt_select_by_name == null) stmt_select_by_name = Select_by_name_stmt();
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ rdr = stmt_select_by_name.Clear()
+ .Val_int_(dir_id)
+ .Val_str_(fil_name)
+ .Exec_select();
+ if (rdr.MoveNextPeer())
+ return load_(rdr);
+ else
+ return Fsdb_fil_itm.Null;
+ }
+ finally {rdr.Rls();}
+ }
+ private Db_stmt Select_by_id_stmt() {
+ Db_qry qry = Db_qry_.select_().From_(Tbl_name).Cols_all_().Where_(Db_crt_.eq_(Fld_fil_id, 0));
+ return provider.Prepare(qry);
+ }
+ public Fsdb_fil_itm Select_itm_by_id(int fil_id) {
+ if (stmt_select_by_id == null) stmt_select_by_id = Select_by_id_stmt();
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ rdr = stmt_select_by_name.Clear()
+ .Val_int_(fil_id)
+ .Exec_select();
+ if (rdr.MoveNextPeer())
+ return load_(rdr);
+ else
+ return Fsdb_fil_itm.Null;
+ }
+ finally {rdr.Rls();}
+ }
+ private Fsdb_fil_itm load_(DataRdr rdr) {
+ return new Fsdb_fil_itm().Init(rdr.ReadInt(Fld_fil_id), rdr.ReadInt(Fld_fil_owner_id), rdr.ReadInt(Fld_fil_ext_id), rdr.ReadStr(Fld_fil_name), rdr.ReadInt(Fld_fil_bin_db_id));
+ }
+ public static final String Tbl_name = "fsdb_fil", Fld_fil_id = "fil_id", Fld_fil_owner_id = "fil_owner_id", Fld_fil_name = "fil_name", Fld_fil_xtn_id = "fil_xtn_id", Fld_fil_ext_id = "fil_ext_id"
+ , Fld_fil_size = "fil_size", Fld_fil_modified = "fil_modified", Fld_fil_hash = "fil_hash", Fld_fil_bin_db_id = "fil_bin_db_id"
+ ;
+ private static final String Tbl_sql = String_.Concat_lines_nl
+ ( "CREATE TABLE IF NOT EXISTS fsdb_fil"
+ , "( fil_id integer NOT NULL PRIMARY KEY"
+ , ", fil_owner_id integer NOT NULL"
+ , ", fil_xtn_id integer NOT NULL"
+ , ", fil_ext_id integer NOT NULL"
+ , ", fil_bin_db_id integer NOT NULL" // group ints at beginning of table
+ , ", fil_name varchar(255) NOT NULL"
+ , ", fil_size bigint NOT NULL"
+ , ", fil_modified varchar(14) NOT NULL" // stored as yyyyMMddHHmmss
+ , ", fil_hash varchar(40) NOT NULL"
+ , ");"
+ );
+ public static final Db_idx_itm
+// Idx_name = Db_idx_itm.sql_ ("CREATE INDEX IF NOT EXISTS fsdb_fil__name ON fsdb_fil (fil_name, fil_owner_id, fil_id, fil_ext_id);")
+ Idx_owner = Db_idx_itm.sql_ ("CREATE INDEX IF NOT EXISTS fsdb_fil__owner ON fsdb_fil (fil_owner_id, fil_name, fil_id);")
+ ;
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_mnt_itm.java b/400_xowa/src/gplx/fsdb/Fsdb_mnt_itm.java
new file mode 100644
index 000000000..b8d8a65e5
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_mnt_itm.java
@@ -0,0 +1,26 @@
+/*
+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.fsdb; import gplx.*;
+public class Fsdb_mnt_itm {
+ public Fsdb_mnt_itm(int id, String name, String url) {this.id = id; this.name = name; this.url = url;}
+ public int Id() {return id;} public Fsdb_mnt_itm Id_(int v) {id = v; return this;} private int id;
+ public String Name() {return name;} public Fsdb_mnt_itm Name_(String v) {name = v; return this;} private String name;
+ public String Url() {return url;} public Fsdb_mnt_itm Url_(String v) {url = v; return this;} private String url;
+ public static final Fsdb_mnt_itm Null = new Fsdb_mnt_itm(0, "", "");
+ public static final Fsdb_mnt_itm[] Ary_empty = new Fsdb_mnt_itm[0];
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_mnt_mgr.java b/400_xowa/src/gplx/fsdb/Fsdb_mnt_mgr.java
new file mode 100644
index 000000000..baa8b870c
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_mnt_mgr.java
@@ -0,0 +1,119 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*; import gplx.xowa.files.fsdb.*;
+public class Fsdb_mnt_mgr implements GfoInvkAble {
+ private Db_provider provider;
+ private Fsdb_cfg_tbl tbl_cfg;
+ private Fsdb_db_abc_mgr[] ary; int ary_len = 0;
+ public Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public Fsdb_mnt_mgr Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v; return this;} private Gfo_usr_dlg usr_dlg = Gfo_usr_dlg_.Null;
+ public void Init(Io_url cur_dir) {
+ Fsdb_mnt_itm[] mnts = Db_load_or_make(cur_dir);
+ ary_len = mnts.length;
+ ary = new Fsdb_db_abc_mgr[ary_len];
+ for (int i = 0; i < ary_len; i++) {
+ Fsdb_mnt_itm itm = mnts[i];
+ Io_url abc_url = cur_dir.GenSubFil_nest(itm.Url(), "fsdb.abc.sqlite3");
+ ary[i] = new Fsdb_db_abc_mgr(this).Init(abc_url.OwnerDir());
+ }
+ insert_to_mnt = tbl_cfg.Select_as_int_or_fail("core", "mnt.insert_idx");
+ }
+ public int Insert_to_mnt() {return insert_to_mnt;} public Fsdb_mnt_mgr Insert_to_mnt_(int v) {insert_to_mnt = v; return this;} private int insert_to_mnt = Mnt_idx_user;
+ public int Abc_mgr_len() {return ary == null ? 0 : ary.length;}
+ public Fsdb_db_abc_mgr Abc_mgr_at(int i) {return ary[i];}
+ private Fsdb_mnt_itm[] Db_load_or_make(Io_url cur_dir) {
+ Bool_obj_ref created = Bool_obj_ref.n_();
+ provider = Sqlite_engine_.Provider_load_or_make_(cur_dir.GenSubFil("wiki.mnt.sqlite3"), created);
+ tbl_cfg = new Fsdb_cfg_tbl_sql().Ctor(provider, created.Val());
+ if (created.Val()) {
+ Fsdb_mnt_tbl.Create_table(provider);
+ Fsdb_mnt_tbl.Insert(provider, Mnt_idx_main, "fsdb.main", "fsdb.main");
+ Fsdb_mnt_tbl.Insert(provider, Mnt_idx_user, "fsdb.user", "fsdb.user");
+ tbl_cfg.Insert("core", "mnt.insert_idx", Int_.XtoStr(Mnt_idx_user));
+ }
+ return Fsdb_mnt_tbl.Select_all(provider);
+ }
+ public Fsdb_db_bin_fil Bin_db_get(int mnt_id, int bin_db_id) {
+ return ary[mnt_id].Bin_mgr().Get_at(bin_db_id);
+ }
+ public Fsdb_fil_itm Fil_select_bin(byte[] dir, byte[] fil, boolean is_thumb, int width, double thumbtime) {
+ for (int i = 0; i < ary_len; i++) {
+ Fsdb_fil_itm rv = ary[i].Fil_select_bin(dir, fil, is_thumb, width, thumbtime);
+ if (rv != Fsdb_fil_itm.Null && rv.Db_bin_id() != Fsdb_bin_tbl.Null_db_bin_id) { // NOTE: mnt_0 can have thumb, but mnt_1 can have itm; check for itm with Db_bin_id; DATE:2013-11-16
+ rv.Mnt_id_(i);
+ return rv;
+ }
+ }
+ return Fsdb_fil_itm.Null;
+ }
+ public boolean Thm_select_bin(byte[] dir, byte[] fil, Fsdb_xtn_thm_itm thm) {
+ for (int i = 0; i < ary_len; i++) {
+ boolean rv = ary[i].Thm_select_bin(dir, fil, thm);
+ if (rv) {
+ thm.Mnt_id_(i);
+ return rv;
+ }
+ }
+ return false;
+ }
+ public void Fil_insert(Fsdb_fil_itm rv , byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ ary[insert_to_mnt].Fil_insert(rv, dir, fil, ext_id, modified, hash, bin_len, bin_rdr);
+ }
+ public void Thm_insert(Fsdb_xtn_thm_itm rv, byte[] dir, byte[] fil, int ext_id, int w, int h, double thumbtime, int page, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr) {
+ ary[insert_to_mnt].Thm_insert(rv, dir, fil, ext_id, w, h, thumbtime, page, modified, hash, bin_len, bin_rdr);
+ }
+ public void Img_insert(Fsdb_xtn_img_itm rv, byte[] dir, byte[] fil, int ext_id, DateAdp modified, String hash, long bin_len, gplx.ios.Io_stream_rdr bin_rdr, int img_w, int img_h) {
+ ary[insert_to_mnt].Img_insert(rv, dir, fil, ext_id, modified, hash, bin_len, bin_rdr, img_w, img_h);
+ }
+ public void Bin_db_max_(long v) {
+ for (int i = 0; i < ary_len; i++)
+ ary[i].Bin_mgr().Db_bin_max_(v);
+ }
+ public void Insert_to_bin_(int v) {
+ for (int i = 0; i < ary_len; i++)
+ ary[i].Bin_mgr().Insert_to_bin_(v);
+ }
+ public void Txn_open() {
+ for (int i = 0; i < ary_len; i++)
+ ary[i].Txn_open();
+ }
+ public void Txn_save() {
+ for (int i = 0; i < ary_len; i++)
+ ary[i].Txn_save();
+ }
+ public void Rls() {
+ for (int i = 0; i < ary_len; i++)
+ ary[i].Rls();
+ tbl_cfg.Rls();
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk_bin_db_max_in_mb_)) this.Bin_db_max_(m.ReadLong("v") * Io_mgr.Len_mb);
+ else if (ctx.Match(k, Invk_insert_to_mnt_)) insert_to_mnt = m.ReadInt("v");
+ else if (ctx.Match(k, Invk_insert_to_bin_)) this.Insert_to_bin_(m.ReadInt("v"));
+ else return GfoInvkAble_.Rv_unhandled;
+ return this;
+ } private static final String Invk_bin_db_max_in_mb_ = "bin_db_max_in_mb_", Invk_insert_to_mnt_ = "insert_to_mnt_", Invk_insert_to_bin_ = "insert_to_bin_";
+ public static final int Mnt_idx_main = 0, Mnt_idx_user = 1, Insert_to_bin_null = -1;
+ public static void Patch(Fsdb_mnt_mgr mnt_mgr) {
+ mnt_mgr.Abc_mgr_at(Fsdb_mnt_mgr.Mnt_idx_main).Cfg_mgr()
+ .Update(Xof_fsdb_mgr_cfg.Grp_xowa, Xof_fsdb_mgr_cfg.Key_gallery_fix_defaults, "y")
+ .Update(Xof_fsdb_mgr_cfg.Grp_xowa, Xof_fsdb_mgr_cfg.Key_gallery_packed, "y")
+ .Update(Xof_fsdb_mgr_cfg.Grp_xowa, Xof_fsdb_mgr_cfg.Key_upright_patch, "y")
+ ;
+ }
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_mnt_tbl.java b/400_xowa/src/gplx/fsdb/Fsdb_mnt_tbl.java
new file mode 100644
index 000000000..652d07bd2
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_mnt_tbl.java
@@ -0,0 +1,67 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_mnt_tbl {
+ public static void Create_table(Db_provider p) {
+ Sqlite_engine_.Tbl_create(p, Tbl_name, Tbl_sql);
+ }
+ public static void Insert(Db_provider p, int id, String name, String url) {
+ Db_stmt stmt = Insert_stmt(p);
+ try {Insert(stmt, id, name, url);}
+ finally {stmt.Rls();}
+ }
+ private static Db_stmt Insert_stmt(Db_provider p) {return Db_stmt_.new_insert_(p, Tbl_name, Fld_mnt_id, Fld_mnt_name, Fld_mnt_url);}
+ private static void Insert(Db_stmt stmt, int id, String name, String url) {
+ stmt.Clear()
+ .Val_int_(id)
+ .Val_str_(name)
+ .Val_str_(url)
+ .Exec_insert();
+ }
+ public static Db_stmt Update_stmt(Db_provider p) {return Db_stmt_.new_update_(p, Tbl_name, String_.Ary(Fld_mnt_id), Fld_mnt_name, Fld_mnt_url);}
+ public static void Update(Db_stmt stmt, int id, String name, String url) {
+ stmt.Clear()
+ .Val_str_(name)
+ .Val_str_(url)
+ .Val_int_(id)
+ .Exec_update();
+ }
+ public static Fsdb_mnt_itm[] Select_all(Db_provider p) {
+ Db_qry qry = Db_qry_.select_().From_(Tbl_name);
+ DataRdr rdr = DataRdr_.Null;
+ ListAdp list = ListAdp_.new_();
+ try {
+ rdr = p.Exec_qry_as_rdr(qry);
+ while (rdr.MoveNextPeer()) {
+ Fsdb_mnt_itm itm = new Fsdb_mnt_itm(rdr.ReadInt(Fld_mnt_id), rdr.ReadStr(Fld_mnt_name), rdr.ReadStr(Fld_mnt_url));
+ list.Add(itm);
+ }
+ }
+ finally {rdr.Rls();}
+ return (Fsdb_mnt_itm[])list.XtoAryAndClear(Fsdb_mnt_itm.class);
+ }
+ public static final String Tbl_name = "fsdb_mnt", Fld_mnt_id = "mnt_id", Fld_mnt_name = "mnt_name", Fld_mnt_url = "mnt_url";
+ private static final String Tbl_sql = String_.Concat_lines_nl
+ ( "CREATE TABLE IF NOT EXISTS fsdb_mnt"
+ , "( mnt_id integer NOT NULL PRIMARY KEY"
+ , ", mnt_name varchar(255) NOT NULL"
+ , ", mnt_url varchar(255) NOT NULL"
+ , ");"
+ );
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_xtn_img_itm.java b/400_xowa/src/gplx/fsdb/Fsdb_xtn_img_itm.java
new file mode 100644
index 000000000..7f235b043
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_xtn_img_itm.java
@@ -0,0 +1,27 @@
+/*
+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.fsdb; import gplx.*;
+public class Fsdb_xtn_img_itm {
+ public int Id() {return id;} public void Id_(int v) {this.id = v;} private int id;
+ public int W() {return w;} public void W_(int v) {this.w = v;} private int w;
+ public int H() {return h;} public void H_(int v) {this.h = v;} private int h;
+ public int Db_bin_id() {return bin_db_id;} public Fsdb_xtn_img_itm Db_bin_id_(int v) {bin_db_id = v; return this;} private int bin_db_id;
+ public Fsdb_xtn_img_itm Init_by_load(int id, int w, int h) {this.id = id; this.w = w; this.h = h; return this;}
+ public static final Fsdb_xtn_img_itm Null = new Fsdb_xtn_img_itm();
+ public static final int Bits_default = 8;
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_xtn_img_tbl.java b/400_xowa/src/gplx/fsdb/Fsdb_xtn_img_tbl.java
new file mode 100644
index 000000000..a5d9618f5
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_xtn_img_tbl.java
@@ -0,0 +1,68 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_xtn_img_tbl {
+ private Db_provider provider;
+ private Db_stmt stmt_insert, stmt_select_by_id;
+ public Fsdb_xtn_img_tbl(Db_provider provider, boolean created) {
+ this.provider = provider;
+ if (created) Create_table();
+ }
+ public void Rls() {
+ if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
+ if (stmt_select_by_id != null) {stmt_select_by_id.Rls(); stmt_select_by_id = null;}
+ }
+ public void Create_table() {
+ Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
+ }
+ public Db_stmt Insert_stmt() {return Db_stmt_.new_insert_(provider, Tbl_name, Fld_img_id, Fld_img_w, Fld_img_h);}
+ public void Insert(int id, int w, int h) {
+ if (stmt_insert == null) stmt_insert = Insert_stmt();
+ try {
+ stmt_insert.Clear()
+ .Val_int_(id)
+ .Val_int_(w)
+ .Val_int_(h)
+ .Exec_insert();
+ } catch (Exception exc) {stmt_insert = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
+ }
+ public Db_stmt Select_itm_by_id_stmt() {return Db_stmt_.new_select_(provider, Tbl_name, String_.Ary(Fld_img_id), Fld_img_w, Fld_img_h); }
+ public Fsdb_xtn_img_itm Select_itm_by_id(int id) {
+ if (stmt_select_by_id == null) stmt_select_by_id = this.Select_itm_by_id_stmt();
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ rdr = stmt_select_by_id.Clear()
+ .Val_int_(id)
+ .Exec_select();
+ if (rdr.MoveNextPeer())
+ return new Fsdb_xtn_img_itm().Init_by_load(id, rdr.ReadInt(Fld_img_w), rdr.ReadInt(Fld_img_h));
+ else
+ return Fsdb_xtn_img_itm.Null;
+ }
+ finally {rdr.Rls();}
+ }
+ public static final String Tbl_name = "fsdb_xtn_img", Fld_img_id = "img_id", Fld_img_w = "img_w", Fld_img_h = "img_h";
+ private static final String Tbl_sql = String_.Concat_lines_nl
+ ( "CREATE TABLE IF NOT EXISTS fsdb_xtn_img"
+ , "( img_id integer NOT NULL PRIMARY KEY"
+ , ", img_w integer NOT NULL"
+ , ", img_h integer NOT NULL"
+ , ");"
+ );
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_xtn_thm_itm.java b/400_xowa/src/gplx/fsdb/Fsdb_xtn_thm_itm.java
new file mode 100644
index 000000000..bf15e423d
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_xtn_thm_itm.java
@@ -0,0 +1,56 @@
+/*
+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.fsdb; import gplx.*;
+public class Fsdb_xtn_thm_itm {
+ protected Fsdb_xtn_thm_itm() {}
+ public int Id() {return id;} public Fsdb_xtn_thm_itm Id_(int v) {id = v; return this;} private int id;
+ public Fsdb_fil_itm Owner() {return owner;} public Fsdb_xtn_thm_itm Owner_(Fsdb_fil_itm v) {owner = v; return this;} private Fsdb_fil_itm owner = Fsdb_fil_itm.Null;
+ public int Owner_id() {return owner_id;} public Fsdb_xtn_thm_itm Owner_id_(int v) {owner_id = v; return this;} private int owner_id;
+ public int Width() {return width;} public Fsdb_xtn_thm_itm Width_(int v) {width = v; return this;} private int width;
+ public double Thumbtime() {return thumbtime;} public Fsdb_xtn_thm_itm Thumbtime_(double v) {thumbtime = v; return this;} private double thumbtime;
+ public int Page() {return page;} public Fsdb_xtn_thm_itm Page_(int v) {page = v; return this;} private int page;
+ public int Height() {return height;} public Fsdb_xtn_thm_itm Height_(int v) {height = v; return this;} private int height;
+ public long Size() {return size;} public Fsdb_xtn_thm_itm Size_(long v) {size = v; return this;} private long size;
+ public String Modified() {return modified;} public Fsdb_xtn_thm_itm Modified_(String v) {modified = v; return this;} private String modified;
+ public String Hash() {return hash;} public Fsdb_xtn_thm_itm Hash_(String v) {hash = v; return this;} private String hash;
+ public int Dir_id() {return dir_id;} public Fsdb_xtn_thm_itm Dir_id_(int v) {dir_id = v; return this;} private int dir_id;
+ public int Db_bin_id() {return bin_db_id;} public Fsdb_xtn_thm_itm Db_bin_id_(int v) {bin_db_id = v; return this;} private int bin_db_id;
+ public int Mnt_id() {return mnt_id;} public Fsdb_xtn_thm_itm Mnt_id_(int v) {mnt_id = v; return this;} private int mnt_id;
+ public void Init_by_load(DataRdr rdr, boolean schema_thm_page) {
+ this.id = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_id);
+ this.owner_id = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_owner_id);
+ this.width = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_w);
+ this.height = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_h);
+ this.size = rdr.ReadLong(Fsdb_xtn_thm_tbl.Fld_thm_size);
+ this.modified = rdr.ReadStr(Fsdb_xtn_thm_tbl.Fld_thm_modified);
+ this.hash = rdr.ReadStr(Fsdb_xtn_thm_tbl.Fld_thm_hash);
+ this.bin_db_id = rdr.ReadInt(Fsdb_xtn_thm_tbl.Fld_thm_bin_db_id);
+ if (schema_thm_page) {
+ this.thumbtime = gplx.xowa.files.Xof_doc_thumb.Db_load_double(rdr, Fsdb_xtn_thm_tbl.Fld_thm_time);
+ this.page = gplx.xowa.files.Xof_doc_page.Db_load_int(rdr, Fsdb_xtn_thm_tbl.Fld_thm_page);
+ }
+ else {
+ this.thumbtime = gplx.xowa.files.Xof_doc_thumb.Db_load_int(rdr, Fsdb_xtn_thm_tbl.Fld_thm_thumbtime);
+ this.page = gplx.xowa.files.Xof_doc_page.Null;
+ }
+ }
+ public static Fsdb_xtn_thm_itm new_() {return new Fsdb_xtn_thm_itm();} // NOTE: Owner is null by default
+ public static Fsdb_xtn_thm_itm load_() {return new Fsdb_xtn_thm_itm().Owner_(new Fsdb_fil_itm());} // NOTE: Owner is new'd b/c load will use owner.Ext_id
+ public static final Fsdb_xtn_thm_itm Null = new Fsdb_xtn_thm_itm();
+ public static final Fsdb_xtn_thm_itm[] Ary_empty = new Fsdb_xtn_thm_itm[0];
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_xtn_thm_tbl.java b/400_xowa/src/gplx/fsdb/Fsdb_xtn_thm_tbl.java
new file mode 100644
index 000000000..b5647a853
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_xtn_thm_tbl.java
@@ -0,0 +1,128 @@
+/*
+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.fsdb; import gplx.*;
+import gplx.dbs.*;
+public class Fsdb_xtn_thm_tbl {
+ private Fsdb_db_atr_fil atr_fil; private Db_provider provider;
+ private Db_stmt stmt_insert, stmt_select_by_fil_w;
+ public Fsdb_xtn_thm_tbl(Fsdb_db_atr_fil atr_fil, Db_provider provider, boolean created) {
+ this.atr_fil = atr_fil; this.provider = provider;
+ if (created) Create_table();
+ }
+ private void Create_table() {
+ Sqlite_engine_.Tbl_create(provider, Tbl_name, Tbl_sql);
+ Sqlite_engine_.Idx_create(provider, Idx_name);
+ }
+ public void Rls() {
+ if (stmt_insert != null) {stmt_insert.Rls(); stmt_insert = null;}
+ if (stmt_select_by_fil_w != null) {stmt_select_by_fil_w.Rls(); stmt_select_by_fil_w = null;}
+ }
+ private boolean Schema_thm_page() {
+ if (schema_thm_page_init) {
+ schema_thm_page = atr_fil.Abc_mgr().Cfg_mgr().Schema_thm_page();
+ schema_thm_page_init = false;
+ }
+ return schema_thm_page;
+ } private boolean schema_thm_page, schema_thm_page_init = true;
+ private Db_stmt Make_stmt_insert() {
+ return this.Schema_thm_page()
+ ? Db_stmt_.new_insert_(provider, Tbl_name, Fld_thm_id, Fld_thm_owner_id, Fld_thm_w, Fld_thm_h, Fld_thm_bin_db_id, Fld_thm_size, Fld_thm_modified, Fld_thm_hash, Fld_thm_time, Fld_thm_page)
+ : Db_stmt_.new_insert_(provider, Tbl_name, Fld_thm_id, Fld_thm_owner_id, Fld_thm_w, Fld_thm_h, Fld_thm_bin_db_id, Fld_thm_size, Fld_thm_modified, Fld_thm_hash, Fld_thm_thumbtime)
+ ;
+ }
+ public void Insert(int id, int thm_owner_id, int width, int height, double thumbtime, int page, int bin_db_id, long size, DateAdp modified, String hash) {
+ if (stmt_insert == null) stmt_insert = Make_stmt_insert();
+ try {
+ stmt_insert.Clear()
+ .Val_int_(id)
+ .Val_int_(thm_owner_id)
+ .Val_int_(width)
+ .Val_int_(height)
+ .Val_int_(bin_db_id)
+ .Val_long_(size)
+ .Val_str_(Sqlite_engine_.X_date_to_str(modified))
+ .Val_str_(hash);
+ if (this.Schema_thm_page()) {
+ stmt_insert.Val_double_ (gplx.xowa.files.Xof_doc_thumb.Db_save_double(thumbtime));
+ stmt_insert.Val_int_ (gplx.xowa.files.Xof_doc_page.Db_save_int(page));
+ }
+ else
+ stmt_insert.Val_int_(gplx.xowa.files.Xof_doc_thumb.Db_save_int(thumbtime));
+ stmt_insert.Exec_insert();
+ } catch (Exception exc) {stmt_insert = null; throw Err_.err_(exc, "stmt failed");} // must reset stmt, else next call will fail
+ }
+ private Db_stmt Select_by_fil_w_stmt() {
+ Db_qry_select qry = Db_qry_.select_().From_(Tbl_name).Cols_all_();
+ gplx.criterias.Criteria crt
+ = this.Schema_thm_page()
+ ? gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_thm_owner_id, Int_.MinValue), Db_crt_.eq_(Fld_thm_w, Int_.MinValue), Db_crt_.eq_(Fld_thm_time, Int_.MinValue), Db_crt_.eq_(Fld_thm_page, Int_.MinValue))
+ : gplx.criterias.Criteria_.And_many(Db_crt_.eq_(Fld_thm_owner_id, Int_.MinValue), Db_crt_.eq_(Fld_thm_w, Int_.MinValue), Db_crt_.eq_(Fld_thm_thumbtime, Int_.MinValue))
+ ;
+ qry.Where_(crt);
+ return provider.Prepare(qry);
+ }
+ public boolean Select_itm_by_fil_width(int owner_id, Fsdb_xtn_thm_itm thm) {
+ if (stmt_select_by_fil_w == null) stmt_select_by_fil_w = Select_by_fil_w_stmt();
+ DataRdr rdr = DataRdr_.Null;
+ try {
+ stmt_select_by_fil_w.Clear()
+ .Val_int_(owner_id)
+ .Val_int_(thm.Width())
+ ;
+ if (this.Schema_thm_page()) {
+ stmt_select_by_fil_w.Val_double_(gplx.xowa.files.Xof_doc_thumb.Db_save_double(thm.Thumbtime()));
+ stmt_select_by_fil_w.Val_int_(gplx.xowa.files.Xof_doc_page.Db_save_int(thm.Page()));
+ }
+ else {
+ stmt_select_by_fil_w.Val_int_(gplx.xowa.files.Xof_doc_thumb.Db_save_int(thm.Thumbtime()));
+ }
+ rdr = stmt_select_by_fil_w.Exec_select();
+ if (rdr.MoveNextPeer()) {
+ thm.Init_by_load(rdr, this.Schema_thm_page());
+ return true;
+ }
+ else
+ return false;
+ }
+ finally {rdr.Rls();}
+ }
+ public static final String Tbl_name = "fsdb_xtn_thm"
+ , Fld_thm_id = "thm_id", Fld_thm_owner_id = "thm_owner_id", Fld_thm_w = "thm_w", Fld_thm_h = "thm_h"
+ , Fld_thm_thumbtime = "thm_thumbtime", Fld_thm_time = "thm_time", Fld_thm_page = "thm_page"
+ , Fld_thm_bin_db_id = "thm_bin_db_id", Fld_thm_size = "thm_size", Fld_thm_modified = "thm_modified", Fld_thm_hash = "thm_hash";
+ private static final String Tbl_sql = String_.Concat_lines_nl
+ ( "CREATE TABLE IF NOT EXISTS fsdb_xtn_thm"
+ , "( thm_id integer NOT NULL PRIMARY KEY"
+ , ", thm_owner_id integer NOT NULL"
+ , ", thm_w integer NOT NULL"
+ , ", thm_h integer NOT NULL"
+ //, ", thm_thumbtime integer NOT NULL" // removed; DATE:2014-01-23
+ , ", thm_time double NOT NULL" // replacement for thm_time
+ , ", thm_page integer NOT NULL"
+ , ", thm_bin_db_id integer NOT NULL"
+ , ", thm_size bigint NOT NULL"
+ , ", thm_modified varchar(14) NOT NULL" // stored as yyyyMMddHHmmss
+ , ", thm_hash varchar(40) NOT NULL"
+ , ");"
+ );
+ public static final Db_idx_itm
+ Idx_name = Db_idx_itm.sql_("CREATE INDEX IF NOT EXISTS fsdb_xtn_thm__owner ON fsdb_xtn_thm (thm_owner_id, thm_id, thm_w, thm_time, thm_page);")
+ ;
+ public static final DateAdp Modified_null = null;
+ public static final String Hash_null = "";
+}
diff --git a/400_xowa/src/gplx/fsdb/Fsdb_xtn_tid_.java b/400_xowa/src/gplx/fsdb/Fsdb_xtn_tid_.java
new file mode 100644
index 000000000..dc9cf7bd3
--- /dev/null
+++ b/400_xowa/src/gplx/fsdb/Fsdb_xtn_tid_.java
@@ -0,0 +1,21 @@
+/*
+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.fsdb; import gplx.*;
+public class Fsdb_xtn_tid_ {
+ public static final int Tid_none = 0, Tid_thm = 1, Tid_img = 2;
+}
diff --git a/400_xowa/src/gplx/gfs/Gfs_lxr.java b/400_xowa/src/gplx/gfs/Gfs_lxr.java
new file mode 100644
index 000000000..95c543af1
--- /dev/null
+++ b/400_xowa/src/gplx/gfs/Gfs_lxr.java
@@ -0,0 +1,214 @@
+/*
+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.gfs; import gplx.*;
+interface Gfs_lxr {
+ byte Lxr_tid();
+ int Process(Gfs_parser_ctx ctx, int bgn, int end);
+}
+class Gfs_lxr_whitespace implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_whitespace;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ byte[] src = ctx.Src(); int src_len = ctx.Src_len();
+ int rv = Gfs_lxr_.Rv_eos, cur_pos;
+ for (cur_pos = end; cur_pos < src_len; cur_pos++) {
+ byte b = src[cur_pos];
+ Object o = ctx.Trie().Match(b, src, cur_pos, src_len);
+ if (o == null) {
+ rv = Gfs_lxr_.Rv_null;
+ ctx.Process_null(cur_pos);
+ break;
+ }
+ else {
+ Gfs_lxr lxr = (Gfs_lxr)o;
+ if (lxr.Lxr_tid() == Gfs_lxr_.Tid_whitespace) {}
+ else {
+ rv = Gfs_lxr_.Rv_lxr;
+ ctx.Process_lxr(cur_pos, lxr);
+ break;
+ }
+ }
+ }
+ return rv;
+ }
+ public static final Gfs_lxr_whitespace _ = new Gfs_lxr_whitespace(); Gfs_lxr_whitespace() {}
+}
+class Gfs_lxr_comment_flat implements Gfs_lxr {
+ public Gfs_lxr_comment_flat(byte[] bgn_bry, byte[] end_bry) {
+ this.bgn_bry = bgn_bry; this.bgn_bry_len = bgn_bry.length;
+ this.end_bry = end_bry; this.end_bry_len = end_bry.length;
+ } byte[] bgn_bry, end_bry; int bgn_bry_len, end_bry_len;
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_comment;}
+ public int Process(Gfs_parser_ctx ctx, int lxr_bgn, int lxr_end) {
+ byte[] src = ctx.Src(); int src_len = ctx.Src_len();
+ int end_pos = Bry_finder.Find_fwd(src, end_bry, lxr_end, src_len);
+ // if (end_pos == Bry_.NotFound) throw Err_.new_fmt_("comment is not closed: {0}", String_.new_utf8_(end_bry));
+ return (end_pos == Bry_.NotFound)
+ ? src_len // allow eos to terminate flat comment; needed for "tidy-always-adds-nl-in-textarea" fix; NOTE: DATE:2014-06-21
+ : end_pos + end_bry_len; // position after end_bry
+ }
+}
+class Gfs_lxr_identifier implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_identifier;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ byte[] src = ctx.Src(); int src_len = ctx.Src_len();
+ int pos, rv = Gfs_lxr_.Rv_eos;
+ for (pos = end; pos < src_len; pos++) {
+ byte b = src[pos];
+ Object o = ctx.Trie().Match(b, src, pos, src_len);
+ if (o == null) { // invalid char; stop;
+ rv = Gfs_lxr_.Rv_null;
+ ctx.Process_null(pos);
+ break;
+ }
+ else {
+ Gfs_lxr lxr = (Gfs_lxr)o;
+ if (lxr.Lxr_tid() == Gfs_lxr_.Tid_identifier) {} // still an identifier; continue
+ else { // new lxr (EX: "." in "abc."); (a) hold word of "abc"; mark "." as new lxr;
+ ctx.Hold_word(bgn, pos);
+ rv = Gfs_lxr_.Rv_lxr;
+ ctx.Process_lxr(pos, lxr);
+ break;
+ }
+ }
+ }
+ if (rv == Gfs_lxr_.Rv_eos) ctx.Process_eos(); // eos
+ return rv;
+ }
+ public static final Gfs_lxr_identifier _ = new Gfs_lxr_identifier(); Gfs_lxr_identifier() {}
+}
+class Gfs_lxr_semic implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_semic;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ switch (ctx.Prv_lxr()) {
+ case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); ctx.Cur_nde_from_stack(); break; // a;
+ case Gfs_lxr_.Tid_quote:
+ case Gfs_lxr_.Tid_paren_end: ctx.Cur_nde_from_stack(); break; // a();
+ case Gfs_lxr_.Tid_semic: break; // a;; ignore;
+ default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Semic); break;
+ }
+ return end;
+ }
+ public static final Gfs_lxr_semic _ = new Gfs_lxr_semic(); Gfs_lxr_semic() {}
+}
+class Gfs_lxr_dot implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_dot;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ switch (ctx.Prv_lxr()) {
+ case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); break; // a.
+ case Gfs_lxr_.Tid_paren_end: break; // a().
+ default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Dot); break;
+ }
+ return end;
+ }
+ public static final Gfs_lxr_dot _ = new Gfs_lxr_dot(); Gfs_lxr_dot() {}
+}
+class Gfs_lxr_paren_bgn implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_paren_bgn;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ switch (ctx.Prv_lxr()) {
+ case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); break; // a(;
+ default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Paren_bgn); break;
+ }
+ return end;
+ }
+ public static final Gfs_lxr_paren_bgn _ = new Gfs_lxr_paren_bgn(); Gfs_lxr_paren_bgn() {}
+}
+class Gfs_lxr_paren_end implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_paren_end;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ switch (ctx.Prv_lxr()) {
+ case Gfs_lxr_.Tid_paren_bgn:
+ case Gfs_lxr_.Tid_quote: break; // "))", "abc)", "'abc')"
+ case Gfs_lxr_.Tid_identifier: ctx.Make_atr_by_idf(); break; // 123)
+ default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Paren_end); break;
+ }
+ return end;
+ }
+ public static final Gfs_lxr_paren_end _ = new Gfs_lxr_paren_end(); Gfs_lxr_paren_end() {}
+}
+class Gfs_lxr_quote implements Gfs_lxr {
+ public Gfs_lxr_quote(byte[] bgn_bry, byte[] end_bry) {
+ this.bgn_bry_len = bgn_bry.length;
+ this.end_bry = end_bry; this.end_bry_len = end_bry.length;
+ } private byte[] end_bry; private int bgn_bry_len, end_bry_len;
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_quote;}
+ public int Process(Gfs_parser_ctx ctx, int lxr_bgn, int lxr_end) {
+ byte[] src = ctx.Src(); int src_len = ctx.Src_len();
+ int end_pos = Bry_finder.Find_fwd(src, end_bry, lxr_end, src_len);
+ if (end_pos == Bry_.NotFound) throw Err_.new_fmt_("quote is not closed: {0}", String_.new_utf8_(end_bry));
+ Bry_bfr bfr = ctx.Tmp_bfr().Clear();
+ int prv_pos = lxr_end;
+ int nxt_pos = end_pos + end_bry_len;
+ if (Bry_.Match(src, nxt_pos, nxt_pos + end_bry_len, end_bry)) { // end_bry is doubled; EX: end_bry = ' and raw = a''
+ while (true) {
+ bfr.Add_mid(src, prv_pos, end_pos); // add everything up to end_bry
+ bfr.Add(end_bry); // add end_bry
+ prv_pos = nxt_pos + end_bry_len; // set prv_pos to after doubled end_bry
+ end_pos = Bry_finder.Find_fwd(src, end_bry, prv_pos, src_len);
+ if (end_pos == Bry_.NotFound) throw Err_.new_fmt_("quote is not closed: {0}", String_.new_utf8_(end_bry));
+ nxt_pos = end_pos + end_bry_len;
+ if (!Bry_.Match(src, nxt_pos, nxt_pos + end_bry_len, end_bry)) {
+ bfr.Add_mid(src, prv_pos, end_pos);
+ break;
+ }
+ }
+ ctx.Make_atr_by_bry(lxr_bgn + bgn_bry_len, end_pos, bfr.XtoAryAndClear());
+ }
+ else
+ ctx.Make_atr(lxr_bgn + bgn_bry_len, end_pos);
+ return end_pos + end_bry_len; // position after quote
+ }
+}
+class Gfs_lxr_curly_bgn implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_curly_bgn;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ switch (ctx.Prv_lxr()) {
+ case Gfs_lxr_.Tid_identifier: ctx.Make_nde(bgn, end); ctx.Stack_add(); break; // a{;
+ case Gfs_lxr_.Tid_paren_end: ctx.Stack_add(); break; // a(){; NOTE: node exists but needs to be pushed onto stack
+ default: ctx.Err_mgr().Fail_invalid_lxr(ctx, bgn, this.Lxr_tid(), Byte_ascii.Curly_bgn); break;
+ }
+ return end;
+ }
+ public static final Gfs_lxr_curly_bgn _ = new Gfs_lxr_curly_bgn(); Gfs_lxr_curly_bgn() {}
+}
+class Gfs_lxr_curly_end implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_curly_end;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ ctx.Stack_pop(bgn);
+ return end;
+ }
+ public static final Gfs_lxr_curly_end _ = new Gfs_lxr_curly_end(); Gfs_lxr_curly_end() {}
+}
+class Gfs_lxr_equal implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_eq;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ ctx.Make_nde(bgn, end).Op_tid_(Gfs_nde.Op_tid_assign);
+ return end;
+ }
+ public static final Gfs_lxr_equal _ = new Gfs_lxr_equal(); Gfs_lxr_equal() {}
+}
+class Gfs_lxr_comma implements Gfs_lxr {
+ public byte Lxr_tid() {return Gfs_lxr_.Tid_comma;}
+ public int Process(Gfs_parser_ctx ctx, int bgn, int end) {
+ switch (ctx.Prv_lxr()) {
+ case Gfs_lxr_.Tid_identifier: ctx.Make_atr_by_idf(); break; // 123,
+ }
+ return end;
+ }
+ public static final Gfs_lxr_comma _ = new Gfs_lxr_comma(); Gfs_lxr_comma() {}
+}
diff --git a/400_xowa/src/gplx/gfs/Gfs_lxr_.java b/400_xowa/src/gplx/gfs/Gfs_lxr_.java
new file mode 100644
index 000000000..ec463a001
--- /dev/null
+++ b/400_xowa/src/gplx/gfs/Gfs_lxr_.java
@@ -0,0 +1,39 @@
+/*
+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.gfs; import gplx.*;
+class Gfs_lxr_ {
+ public static final int Rv_init = -1, Rv_null = -2, Rv_eos = -3, Rv_lxr = -4;
+ public static final byte Tid_identifier = 1, Tid_dot = 2, Tid_semic = 3, Tid_paren_bgn = 4, Tid_paren_end = 5, Tid_curly_bgn = 6, Tid_curly_end = 7, Tid_quote = 8, Tid_comma = 9, Tid_whitespace = 10, Tid_comment = 11, Tid_eq = 12;
+ public static String Tid__name(byte tid) {
+ switch (tid) {
+ case Tid_identifier: return "identifier";
+ case Tid_dot: return "dot";
+ case Tid_semic: return "semic";
+ case Tid_paren_bgn: return "paren_bgn";
+ case Tid_paren_end: return "paren_end";
+ case Tid_curly_bgn: return "curly_bgn";
+ case Tid_curly_end: return "curly_end";
+ case Tid_quote: return "quote";
+ case Tid_comma: return "comma";
+ case Tid_whitespace: return "whitespace";
+ case Tid_comment: return "comment";
+ case Tid_eq: return "eq";
+ default: throw Err_.unhandled(tid);
+ }
+ }
+}
diff --git a/400_xowa/src/gplx/gfs/Gfs_msg_bldr.java b/400_xowa/src/gplx/gfs/Gfs_msg_bldr.java
new file mode 100644
index 000000000..ae0c3788c
--- /dev/null
+++ b/400_xowa/src/gplx/gfs/Gfs_msg_bldr.java
@@ -0,0 +1,49 @@
+/*
+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.gfs; import gplx.*;
+public class Gfs_msg_bldr implements GfoMsgParser {
+ Gfs_parser parser = new Gfs_parser();
+ public GfoMsg ParseToMsg(String s) {return Bld(s);}
+ public GfoMsg Bld(String src) {return Bld(Bry_.new_utf8_(src));}
+ public GfoMsg Bld(byte[] src) {
+ Gfs_nde nde = parser.Parse(src);
+ return Bld_msg(src, nde);
+ }
+ GfoMsg Bld_msg(byte[] src, Gfs_nde nde) {
+ boolean op_is_assign = (nde.Op_tid() == Gfs_nde.Op_tid_assign);
+ String name = String_.new_utf8_(nde.Name_bry(src));
+ if (op_is_assign) name += Tkn_mutator;
+ GfoMsg rv = GfoMsg_.new_parse_(name);
+ int len = nde.Atrs_len();
+ for (int i = 0; i < len; i++) {
+ Gfs_nde atr = nde.Atrs_get_at(i);
+ rv.Add("", String_.new_utf8_(atr.Name_bry(src)));
+ }
+ len = nde.Subs_len();
+ for (int i = 0; i < len; i++) {
+ Gfs_nde sub = nde.Subs_get_at(i);
+ if (op_is_assign) // NOTE: for now (a) assignss cannot be nested; EX: "a.b = c;" is okay but "a.b = c.d;" is not
+ rv.Add("", Bld_msg(src, sub).Key());
+ else
+ rv.Subs_add(Bld_msg(src, sub));
+ }
+ return rv;
+ }
+ public static final Gfs_msg_bldr _ = new Gfs_msg_bldr(); Gfs_msg_bldr() {}
+ public static final String Tkn_mutator = "_";
+}
diff --git a/400_xowa/src/gplx/gfs/Gfs_msg_bldr_tst.java b/400_xowa/src/gplx/gfs/Gfs_msg_bldr_tst.java
new file mode 100644
index 000000000..9ec4ff8d6
--- /dev/null
+++ b/400_xowa/src/gplx/gfs/Gfs_msg_bldr_tst.java
@@ -0,0 +1,76 @@
+/*
+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.gfs; import gplx.*;
+import org.junit.*;
+public class Gfs_msg_bldr_tst {
+ @Before public void init() {fxt.Clear();} Gfs_msg_bldr_fxt fxt = new Gfs_msg_bldr_fxt();
+ @Test public void Basic() {
+ fxt.Test_build("a;", fxt.msg_("a"));
+ }
+ @Test public void Dot() {
+ fxt.Test_build("a.b.c;"
+ , fxt.msg_("a").Subs_
+ ( fxt.msg_("b").Subs_
+ ( fxt.msg_("c")
+ )));
+ }
+ @Test public void Args() {
+ fxt.Test_build("a('b', 'c');", fxt.msg_("a", fxt.kv_("", "b"), fxt.kv_("", "c")));
+ }
+ @Test public void Args_num() {
+ fxt.Test_build("a(1);", fxt.msg_("a", fxt.kv_("", "1")));
+ }
+ @Test public void Assign() {
+ fxt.Test_build("a = 'b';", fxt.msg_("a_", fxt.kv_("", "b")));
+ }
+ @Test public void Assign_num() {
+ fxt.Test_build("a = 1;", fxt.msg_("a_", fxt.kv_("", "1")));
+ }
+}
+class Gfs_msg_bldr_fxt {
+ public void Clear() {} String_bldr sb = String_bldr_.new_(); Gfs_msg_bldr msg_bldr = Gfs_msg_bldr._;
+ public KeyVal kv_(String key, String val) {return KeyVal_.new_(key, val);}
+ public GfoMsg msg_(String key, KeyVal... args) {
+ GfoMsg rv = GfoMsg_.new_parse_(key);
+ int len = args.length;
+ for (int i = 0; i < len; i++) {
+ KeyVal kv = args[i];
+ rv.Add(kv.Key(), kv.Val());
+ }
+ return rv;
+ }
+ public void Test_build(String raw, GfoMsg... expd) {
+ GfoMsg root = msg_bldr.Bld(raw);
+ Tfds.Eq_str_lines(Xto_str(expd), Xto_str(Xto_ary(root)));
+ }
+ GfoMsg[] Xto_ary(GfoMsg msg) {
+ int len = msg.Subs_count();
+ GfoMsg[] rv = new GfoMsg[len];
+ for (int i = 0; i < len; i++)
+ rv[i] = msg.Subs_getAt(i);
+ return rv;
+ }
+ String Xto_str(GfoMsg[] ary) {
+ int len = ary.length;
+ for (int i = 0; i < len; i++) {
+ if (i != 0) sb.Add_char_crlf();
+ sb.Add(ary[i].XtoStr());
+ }
+ return sb.XtoStrAndClear();
+ }
+}
diff --git a/400_xowa/src/gplx/gfs/Gfs_nde.java b/400_xowa/src/gplx/gfs/Gfs_nde.java
new file mode 100644
index 000000000..9ec6df282
--- /dev/null
+++ b/400_xowa/src/gplx/gfs/Gfs_nde.java
@@ -0,0 +1,85 @@
+/*
+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.gfs; import gplx.*;
+public class Gfs_nde {
+ public byte[] Name_bry(byte[] src) {return name == null ? Bry_.Mid(src, name_bgn, name_end) : name;}
+ public byte[] Name() {return name;} public Gfs_nde Name_(byte[] v) {name = v; return this;} private byte[] name;
+ public int Name_bgn() {return name_bgn;} private int name_bgn = -1;
+ public int Name_end() {return name_end;} private int name_end = -1;
+ public Gfs_nde Name_rng_(int name_bgn, int name_end) {this.name_bgn = name_bgn; this.name_end = name_end; return this;}
+ public byte Op_tid() {return op_tid;} public Gfs_nde Op_tid_(byte v) {op_tid = v; return this;} private byte op_tid;
+ public void Subs_clear() {
+ for (int i = 0; i < subs_len; i++)
+ subs[i] = null;
+ subs_len = 0;
+ }
+ public int Subs_len() {return subs_len;} private int subs_len;
+ public Gfs_nde Subs_add_many(Gfs_nde... ary) {
+ int len = ary.length;
+ for (int i = 0; i < len; i++)
+ Subs_add(ary[i]);
+ return this;
+ }
+ public Gfs_nde Subs_add(Gfs_nde nde) {
+ int new_len = subs_len + 1;
+ if (new_len > subs_max) { // ary too small >>> expand
+ subs_max = new_len * 2;
+ Gfs_nde[] new_subs = new Gfs_nde[subs_max];
+ Array_.CopyTo(subs, 0, new_subs, 0, subs_len);
+ subs = new_subs;
+ }
+ subs[subs_len] = nde;
+ subs_len = new_len;
+ return this;
+ } Gfs_nde[] subs = Gfs_nde.Ary_empty; int subs_max; int[] subs_pos_ary = Int_.Ary_empty;
+ public Gfs_nde Subs_get_at(int i) {return subs[i];}
+ public Gfs_nde[] Subs_to_ary() {
+ Gfs_nde[] rv = new Gfs_nde[subs_len];
+ for (int i = 0; i < subs_len; i++)
+ rv[i] = subs[i];
+ return rv;
+ }
+ public int Atrs_len() {return args_len;} private int args_len;
+ public Gfs_nde Atrs_get_at(int i) {return args[i];}
+ public Gfs_nde Atrs_add_many(Gfs_nde... ary) {
+ int len = ary.length;
+ for (int i = 0; i < len; i++)
+ Atrs_add(ary[i]);
+ return this;
+ }
+ public Gfs_nde Atrs_add(Gfs_nde nde) {
+ int new_len = args_len + 1;
+ if (new_len > args_max) { // ary too small >>> expand
+ args_max = new_len * 2;
+ Gfs_nde[] new_args = new Gfs_nde[args_max];
+ Array_.CopyTo(args, 0, new_args, 0, args_len);
+ args = new_args;
+ }
+ args[args_len] = nde;
+ args_len = new_len;
+ return this;
+ } Gfs_nde[] args = Gfs_nde.Ary_empty; int args_max; int[] args_pos_ary = Int_.Ary_empty;
+ public Gfs_nde[] Atrs_to_ary() {
+ Gfs_nde[] rv = new Gfs_nde[args_len];
+ for (int i = 0; i < args_len; i++)
+ rv[i] = args[i];
+ return rv;
+ }
+ public static final Gfs_nde[] Ary_empty = new Gfs_nde[0];
+ public static final byte Op_tid_null = 0, Op_tid_assign = 1;
+}
diff --git a/400_xowa/src/gplx/gfs/Gfs_parser.java b/400_xowa/src/gplx/gfs/Gfs_parser.java
new file mode 100644
index 000000000..2d2a87175
--- /dev/null
+++ b/400_xowa/src/gplx/gfs/Gfs_parser.java
@@ -0,0 +1,103 @@
+/*
+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.gfs; import gplx.*;
+public class Gfs_parser {
+ ByteTrieMgr_fast trie = Gfs_parser_.trie_();
+ Gfs_parser_ctx ctx = new Gfs_parser_ctx();
+ public Gfs_nde Parse(byte[] src) {
+ ctx.Root().Subs_clear();
+ int src_len = src.length; if (src_len == 0) return ctx.Root();
+ ctx.Init(trie, src, src_len);
+ int pos = 0;
+ while (pos < src_len) {
+ byte b = src[pos];
+ Object o = trie.Match(b, src, pos, src_len);
+ if (o == null)
+ ctx.Err_mgr().Fail_unknown_char(ctx, pos, b);
+ else {
+ Gfs_lxr lxr = (Gfs_lxr)o;
+ while (lxr != null) {
+ int rslt = lxr.Process(ctx, pos, trie.Match_pos());
+ switch (lxr.Lxr_tid()) {
+ case Gfs_lxr_.Tid_whitespace: break;
+ case Gfs_lxr_.Tid_comment: break;
+ default: ctx.Prv_lxr_(lxr.Lxr_tid()); break;
+ }
+ switch (rslt) {
+ case Gfs_lxr_.Rv_lxr:
+ pos = ctx.Nxt_pos();
+ lxr = ctx.Nxt_lxr();
+ break;
+ case Gfs_lxr_.Rv_eos:
+ pos = src_len;
+ lxr = null;
+ break;
+ default:
+ pos = rslt;
+ lxr = null;
+ break;
+ }
+ }
+ }
+ }
+ switch (ctx.Prv_lxr()) {
+ case Gfs_lxr_.Tid_curly_end:
+ case Gfs_lxr_.Tid_semic: break;
+ default: ctx.Err_mgr().Fail_eos(ctx); break;
+ }
+ return ctx.Root();
+ }
+}
+class Gfs_parser_ {
+ public static ByteTrieMgr_fast trie_() {
+ ByteTrieMgr_fast rv = ByteTrieMgr_fast.ci_ascii_(); // NOTE:ci.ascii:gfs;letters/symbols only;
+ Gfs_lxr_identifier word_lxr = Gfs_lxr_identifier._;
+ trie_add_rng(rv, word_lxr, Byte_ascii.Ltr_a, Byte_ascii.Ltr_z);
+ trie_add_rng(rv, word_lxr, Byte_ascii.Ltr_A, Byte_ascii.Ltr_Z);
+ trie_add_rng(rv, word_lxr, Byte_ascii.Num_0, Byte_ascii.Num_9);
+ rv.Add(Byte_ascii.Underline, word_lxr);
+ trie_add_many(rv, Gfs_lxr_whitespace._, Byte_ascii.Space, Byte_ascii.NewLine, Byte_ascii.CarriageReturn, Byte_ascii.Tab);
+ trie_add_quote(rv, new byte[] {Byte_ascii.Apos});
+ trie_add_quote(rv, new byte[] {Byte_ascii.Quote});
+ trie_add_quote(rv, Bry_.new_ascii_("<:[\"\n"), Bry_.new_ascii_("\n\"]:>"));
+ trie_add_quote(rv, Bry_.new_ascii_("<:['\n"), Bry_.new_ascii_("\n']:>"));
+ trie_add_comment(rv, new byte[] {Byte_ascii.Slash, Byte_ascii.Slash}, new byte[] {Byte_ascii.NewLine});
+ trie_add_comment(rv, new byte[] {Byte_ascii.Slash, Byte_ascii.Asterisk}, new byte[] {Byte_ascii.Asterisk, Byte_ascii.Slash});
+ rv.Add(Byte_ascii.Semic, Gfs_lxr_semic._);
+ rv.Add(Byte_ascii.Paren_bgn, Gfs_lxr_paren_bgn._);
+ rv.Add(Byte_ascii.Paren_end, Gfs_lxr_paren_end._);
+ rv.Add(Byte_ascii.Curly_bgn, Gfs_lxr_curly_bgn._);
+ rv.Add(Byte_ascii.Curly_end, Gfs_lxr_curly_end._);
+ rv.Add(Byte_ascii.Dot, Gfs_lxr_dot._);
+ rv.Add(Byte_ascii.Comma, Gfs_lxr_comma._);
+ rv.Add(Byte_ascii.Eq, Gfs_lxr_equal._);
+ return rv;
+ }
+ private static void trie_add_rng(ByteTrieMgr_fast trie, Gfs_lxr lxr, byte bgn, byte end) {
+ for (byte b = bgn; b <= end; b++)
+ trie.Add(b, lxr);
+ }
+ private static void trie_add_many(ByteTrieMgr_fast trie, Gfs_lxr lxr, byte... ary) {
+ int len = ary.length;
+ for (int i = 0; i < len; i++)
+ trie.Add(ary[i], lxr);
+ }
+ private static void trie_add_quote(ByteTrieMgr_fast trie, byte[] bgn) {trie_add_quote(trie, bgn, bgn);}
+ private static void trie_add_quote(ByteTrieMgr_fast trie, byte[] bgn, byte[] end) {trie.Add(bgn, new Gfs_lxr_quote(bgn, end));}
+ private static void trie_add_comment(ByteTrieMgr_fast trie, byte[] bgn, byte[] end) {trie.Add(bgn, new Gfs_lxr_comment_flat(bgn, end));}
+}
diff --git a/400_xowa/src/gplx/gfs/Gfs_parser_ctx.java b/400_xowa/src/gplx/gfs/Gfs_parser_ctx.java
new file mode 100644
index 000000000..542b24af0
--- /dev/null
+++ b/400_xowa/src/gplx/gfs/Gfs_parser_ctx.java
@@ -0,0 +1,125 @@
+/*
+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.gfs; import gplx.*;
+class Gfs_parser_ctx {
+ public ByteTrieMgr_fast Trie() {return trie;} ByteTrieMgr_fast trie;
+ public Gfs_nde Root() {return root;} Gfs_nde root = new Gfs_nde();
+ public byte[] Src() {return src;} private byte[] src;
+ public int Src_len() {return src_len;} private int src_len;
+ public byte Prv_lxr() {return prv_lxr;} public Gfs_parser_ctx Prv_lxr_(byte v) {prv_lxr = v; return this;} private byte prv_lxr;
+ public Gfs_nde Cur_nde() {return cur_nde;} Gfs_nde cur_nde;
+ public int Nxt_pos() {return nxt_pos;} private int nxt_pos;
+ public Gfs_lxr Nxt_lxr() {return nxt_lxr;} Gfs_lxr nxt_lxr;
+ public Bry_bfr Tmp_bfr() {return tmp_bfr;} private Bry_bfr tmp_bfr = Bry_bfr.new_();
+ public void Process_eos() {}
+ public void Process_lxr(int nxt_pos, Gfs_lxr nxt_lxr) {this.nxt_pos = nxt_pos; this.nxt_lxr = nxt_lxr;}
+ public void Process_null(int cur_pos) {this.nxt_pos = cur_pos; this.nxt_lxr = null;}
+ public void Init(ByteTrieMgr_fast trie, byte[] src, int src_len) {
+ this.trie = trie; this.src = src; this.src_len = src_len;
+ cur_nde = root;
+ Stack_add();
+ }
+ public void Hold_word(int bgn, int end) {
+ cur_idf_bgn = bgn;
+ cur_idf_end = end;
+ } int cur_idf_bgn = -1, cur_idf_end = -1;
+ private void Held_word_clear() {cur_idf_bgn = -1; cur_idf_end = -1;}
+
+ public Gfs_nde Make_nde(int tkn_bgn, int tkn_end) { // "abc."; "abc("; "abc;"; "abc{"
+ Gfs_nde nde = new Gfs_nde().Name_rng_(cur_idf_bgn, cur_idf_end);
+ this.Held_word_clear();
+ cur_nde.Subs_add(nde);
+ cur_nde = nde;
+ return nde;
+ }
+ public void Make_atr_by_idf() {Make_atr(cur_idf_bgn, cur_idf_end); Held_word_clear();}
+ public void Make_atr_by_bry(int bgn, int end, byte[] bry) {Make_atr(bgn, end).Name_(bry);}
+ public Gfs_nde Make_atr(int bgn, int end) {
+ Gfs_nde nde = new Gfs_nde().Name_rng_(bgn, end);
+ cur_nde.Atrs_add(nde);
+ return nde;
+ }
+ public void Cur_nde_from_stack() {cur_nde = (Gfs_nde)nodes.FetchAtLast();}
+ public void Stack_add() {nodes.Add(cur_nde);} ListAdp nodes = ListAdp_.new_();
+ public void Stack_pop(int pos) {
+ if (nodes.Count() < 2) err_mgr.Fail_nde_stack_empty(this, pos); // NOTE: need at least 2 items; 1 to pop and 1 to set as current
+ ListAdp_.DelAt_last(nodes);
+ Cur_nde_from_stack();
+ }
+ public Gfs_err_mgr Err_mgr() {return err_mgr;} Gfs_err_mgr err_mgr = new Gfs_err_mgr();
+}
+class Gfs_err_mgr {
+ public void Fail_eos(Gfs_parser_ctx ctx) {Fail(ctx, Fail_msg_eos, ctx.Src_len());}
+ public void Fail_unknown_char(Gfs_parser_ctx ctx, int pos, byte c) {Fail(ctx, Fail_msg_unknown_char, pos, KeyVal_.new_("char", Char_.XtoStr((char)c)));}
+ public void Fail_nde_stack_empty(Gfs_parser_ctx ctx, int pos) {Fail(ctx, Fail_msg_nde_stack_empty, pos);}
+ public void Fail_invalid_lxr(Gfs_parser_ctx ctx, int pos, byte cur_lxr, byte c) {
+ Fail(ctx, Fail_msg_invalid_lxr, pos, KeyVal_.new_("char", Char_.XtoStr((char)c)), KeyVal_.new_("cur_lxr", Gfs_lxr_.Tid__name(cur_lxr)), KeyVal_.new_("prv_lxr", Gfs_lxr_.Tid__name(ctx.Prv_lxr())));
+ }
+ private void Fail(Gfs_parser_ctx ctx, String msg, int pos, KeyVal... args) {
+ byte[] src = ctx.Src(); int src_len = ctx.Src_len();
+ Fail_args_standard(src, src_len, pos);
+ int len = args.length;
+ for (int i = 0; i < len; i++) {
+ KeyVal arg = args[i];
+ tmp_fail_args.Add(arg.Key(), arg.Val_to_str_or_empty());
+ }
+ throw Err_.new_(Fail_msg(msg, tmp_fail_args));
+ }
+ private void Fail_args_standard(byte[] src, int src_len, int pos) {
+ tmp_fail_args.Add("excerpt_bgn", Fail_excerpt_bgn(src, src_len, pos));
+ tmp_fail_args.Add("excerpt_end", Fail_excerpt_end(src, src_len, pos));
+ tmp_fail_args.Add("pos" , pos);
+ }
+ public static final String Fail_msg_invalid_lxr = "invalid character", Fail_msg_unknown_char = "unknown char", Fail_msg_eos = "end of stream", Fail_msg_nde_stack_empty = "node stack empty";
+ String Fail_msg(String type, KeyValList fail_args) {
+ tmp_fail_bfr.Add_str(type).Add_byte(Byte_ascii.Colon);
+ int len = fail_args.Count();
+ for (int i = 0; i < len; i++) {
+ tmp_fail_bfr.Add_byte(Byte_ascii.Space);
+ KeyVal kv = fail_args.GetAt(i);
+ tmp_fail_bfr.Add_str(kv.Key());
+ tmp_fail_bfr.Add_byte(Byte_ascii.Eq).Add_byte(Byte_ascii.Apos);
+ tmp_fail_bfr.Add_str(kv.Val_to_str_or_empty()).Add_byte(Byte_ascii.Apos);
+ }
+ return tmp_fail_bfr.XtoStrAndClear();
+ }
+ Bry_bfr tmp_fail_bfr = Bry_bfr.reset_(255);
+ KeyValList tmp_fail_args = new KeyValList();
+ private static int excerpt_len = 50;
+ String Fail_excerpt_bgn(byte[] src, int src_len, int pos) {
+ int bgn = pos - excerpt_len; if (bgn < 0) bgn = 0;
+ Fail_excerpt_rng(tmp_fail_bfr, src, bgn, pos);
+ return tmp_fail_bfr.XtoStrAndClear();
+ }
+ String Fail_excerpt_end(byte[] src, int src_len, int pos) {
+ int end = pos + excerpt_len; if (end > src_len) end = src_len;
+ Fail_excerpt_rng(tmp_fail_bfr, src, pos, end);
+ return tmp_fail_bfr.XtoStrAndClear();
+ }
+ private static void Fail_excerpt_rng(Bry_bfr bfr, byte[] src, int bgn, int end) {
+ for (int i = bgn; i < end; i++) {
+ byte b = src[i];
+ switch (b) {
+ case Byte_ascii.Tab: bfr.Add(Esc_tab); break;
+ case Byte_ascii.NewLine: bfr.Add(Esc_nl); break;
+ case Byte_ascii.CarriageReturn: bfr.Add(Esc_cr); break;
+ default: bfr.Add_byte(b); break;
+ }
+ }
+ } static final byte[] Esc_nl = Bry_.new_ascii_("\\n"), Esc_cr = Bry_.new_ascii_("\\r"), Esc_tab = Bry_.new_ascii_("\\t");
+}
diff --git a/400_xowa/src/gplx/gfs/Gfs_parser_tst.java b/400_xowa/src/gplx/gfs/Gfs_parser_tst.java
new file mode 100644
index 000000000..27ff6362a
--- /dev/null
+++ b/400_xowa/src/gplx/gfs/Gfs_parser_tst.java
@@ -0,0 +1,196 @@
+/*
+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.gfs; import gplx.*;
+import org.junit.*;
+public class Gfs_parser_tst {
+ @Before public void init() {fxt.Clear();} Gfs_parser_fxt fxt = new Gfs_parser_fxt();
+ @Test public void Semicolon() {
+ fxt .Test_parse("a;", fxt.nde_("a"));
+ fxt .Test_parse("a;b;c;", fxt.nde_("a"), fxt.nde_("b"), fxt.nde_("c"));
+ fxt .Test_parse("a_0;", fxt.nde_("a_0"));
+ }
+ @Test public void Dot() {
+ fxt .Test_parse("a.b;", fxt.nde_("a").Subs_add(fxt.nde_("b")));
+ fxt .Test_parse("a.b;c.d;", fxt.nde_("a").Subs_add(fxt.nde_("b")), fxt.nde_("c").Subs_add(fxt.nde_("d")));
+ }
+ @Test public void Parens() {
+ fxt .Test_parse("a();b();", fxt.nde_("a"), fxt.nde_("b"));
+ fxt .Test_parse("a().b();c().d();", fxt.nde_("a").Subs_add(fxt.nde_("b")), fxt.nde_("c").Subs_add(fxt.nde_("d")));
+ }
+ @Test public void Num() {
+ fxt .Test_parse("a(1,2);", fxt.nde_("a").Atrs_add_many(fxt.val_("1"), fxt.val_("2")));
+ }
+ @Test public void Quote() {
+ fxt .Test_parse("a('b');", fxt.nde_("a").Atrs_add(fxt.val_("b")));
+ }
+ @Test public void Quote_escaped() {
+ fxt .Test_parse("a('b''c''d');", fxt.nde_("a").Atrs_add(fxt.val_("b'c'd")));
+ }
+ @Test public void Quote_escaped_2() {
+ fxt .Test_parse("a('a''''b');", fxt.nde_("a").Atrs_add(fxt.val_("a''b")));
+ }
+ @Test public void Quote_mixed() {
+ fxt .Test_parse("a('b\"c');", fxt.nde_("a").Atrs_add(fxt.val_("b\"c")));
+ }
+ @Test public void Comma() {
+ fxt .Test_parse("a('b','c','d');", fxt.nde_("a").Atrs_add_many(fxt.val_("b"), fxt.val_("c"), fxt.val_("d")));
+ }
+ @Test public void Ws() {
+ fxt .Test_parse(" a ( 'b' , 'c' ) ; ", fxt.nde_("a").Atrs_add_many(fxt.val_("b"), fxt.val_("c")));
+ }
+ @Test public void Comment_slash_slash() {
+ fxt .Test_parse("//z\na;//y\n", fxt.nde_("a"));
+ }
+ @Test public void Comment_slash_star() {
+ fxt .Test_parse("/*z*/a;/*y*/", fxt.nde_("a"));
+ }
+ @Test public void Curly() {
+ fxt .Test_parse("a{b;}", fxt.nde_("a").Subs_add(fxt.nde_("b")));
+ }
+ @Test public void Curly_nest() {
+ fxt .Test_parse("a{b{c{d;}}}"
+ , fxt.nde_("a").Subs_add
+ ( fxt.nde_("b").Subs_add
+ ( fxt.nde_("c").Subs_add
+ ( fxt.nde_("d")
+ ))));
+ }
+ @Test public void Curly_nest_peers() {
+ fxt .Test_parse(String_.Concat_lines_nl
+ ( "a{"
+ , " a0{"
+ , " a00{"
+ , " a000;"
+ , " }"
+ , " a01;"
+ , " }"
+ , " a1;"
+ , "}"
+ )
+ , fxt.nde_("a").Subs_add_many
+ ( fxt.nde_("a0").Subs_add_many
+ ( fxt.nde_("a00").Subs_add
+ ( fxt.nde_("a000")
+ )
+ , fxt.nde_("a01")
+ )
+ , fxt.nde_("a1")
+ ));
+ }
+ @Test public void Curly_dot() {
+ fxt .Test_parse("a{a0.a00;a1.a10;}"
+ , fxt.nde_("a").Subs_add_many
+ ( fxt.nde_("a0").Subs_add_many(fxt.nde_("a00"))
+ , fxt.nde_("a1").Subs_add_many(fxt.nde_("a10"))
+ ));
+ }
+ @Test public void Eq() {
+ fxt .Test_parse("a='b';", fxt.nde_("a").Atrs_add(fxt.val_("b")));
+ fxt .Test_parse("a.b.c='d';"
+ , fxt.nde_("a").Subs_add
+ ( fxt.nde_("b").Subs_add_many
+ ( fxt.nde_("c").Atrs_add(fxt.val_("d"))
+ )));
+ fxt .Test_parse("a.b{c='d'; e='f'}"
+ , fxt.nde_("a").Subs_add
+ ( fxt.nde_("b").Subs_add_many
+ ( fxt.nde_("c").Atrs_add(fxt.val_("d"))
+ , fxt.nde_("e").Atrs_add(fxt.val_("f"))
+ )));
+ }
+ @Test public void Curly_nest_peers2() {
+ fxt .Test_parse(String_.Concat_lines_nl
+ ( "a() {"
+ , " k1 = 'v1';"
+ , "}"
+ )
+ , fxt.nde_("a").Subs_add_many
+ ( fxt.nde_("k1").Atrs_add(fxt.val_("v1"))
+ )
+ );
+ }
+ @Test public void Fail() {
+ fxt .Test_parse_fail("a(.);", Gfs_err_mgr.Fail_msg_invalid_lxr); // (.)
+ fxt .Test_parse_fail("a..b;", Gfs_err_mgr.Fail_msg_invalid_lxr); // ..
+ fxt .Test_parse_fail("a.;", Gfs_err_mgr.Fail_msg_invalid_lxr); // .;
+ fxt .Test_parse_fail("a", Gfs_err_mgr.Fail_msg_eos); // eos
+ fxt .Test_parse_fail("a;~;", Gfs_err_mgr.Fail_msg_unknown_char); // ~
+ }
+}
+class Gfs_parser_fxt {
+ public void Clear() {}
+ public Gfs_nde nde_(String v) {return new Gfs_nde().Name_(Bry_.new_ascii_(v));}
+ public Gfs_nde val_(String v) {return new Gfs_nde().Name_(Bry_.new_ascii_(v));}
+ public void Test_parse(String src_str, Gfs_nde... expd) {
+ byte[] src_bry = Bry_.new_utf8_(src_str);
+ Gfs_nde root = parser.Parse(src_bry);
+ Tfds.Eq_str_lines(To_str(null, expd), To_str(src_bry, root.Subs_to_ary()));
+ } private Bry_bfr tmp_bfr = Bry_bfr.new_(), path_bfr = Bry_bfr.new_(); Gfs_parser parser = new Gfs_parser();
+ public void Test_parse_fail(String src_str, String expd_err) {
+ byte[] src_bry = Bry_.new_utf8_(src_str);
+ try {parser.Parse(src_bry);}
+ catch (Exception e) {
+ String actl_err = Err_.Message_gplx_brief(e);
+ actl_err = String_.GetStrBefore(actl_err, ":");
+ boolean match = String_.HasAtBgn(actl_err, expd_err);
+ if (!match) Tfds.Fail("expecting '" + expd_err + "' got '" + actl_err + "'");
+ return;
+ }
+ Tfds.Fail("expected to fail with " + expd_err);
+ }
+ public String To_str(byte[] src, Gfs_nde[] expd) {
+ int subs_len = expd.length;
+ for (int i = 0; i < subs_len; i++) {
+ path_bfr.Clear().Add_int_variable(i);
+ To_str(tmp_bfr, path_bfr, src, expd[i]);
+ }
+ return tmp_bfr.XtoStrAndClear();
+ }
+ public void To_str(Bry_bfr bfr, Bry_bfr path, byte[] src, Gfs_nde nde) {
+ To_str_atr(bfr, path, src, Atr_name, nde.Name(), nde.Name_bgn(), nde.Name_end());
+ int atrs_len = nde.Atrs_len();
+ for (int i = 0; i < atrs_len; i++) {
+ Gfs_nde atr = nde.Atrs_get_at(i);
+ int path_len_old = path.Len();
+ path.Add_byte(Byte_ascii.Dot).Add_byte((byte)(Byte_ascii.Ltr_a + i));
+ int path_len_new = path.Len();
+ To_str(bfr, path, src, atr);
+ path.Del_by(path_len_new - path_len_old);
+ }
+ int subs_len = nde.Subs_len();
+ for (int i = 0; i < subs_len; i++) {
+ Gfs_nde sub = nde.Subs_get_at(i);
+ int path_len_old = path.Len();
+ path.Add_byte(Byte_ascii.Dot).Add_int_variable(i);
+ int path_len_new = path.Len();
+ To_str(bfr, path, src, sub);
+ path.Del_by(path_len_new - path_len_old);
+ }
+ }
+ private void To_str_atr(Bry_bfr bfr, Bry_bfr path_bfr, byte[] src, byte[] name, byte[] val, int val_bgn, int val_end) {
+ if (val == null && val_bgn == -1 && val_end == -1) return;
+ bfr.Add_bfr(path_bfr).Add_byte(Byte_ascii.Colon);
+ bfr.Add(name);
+ if (val == null)
+ bfr.Add_mid(src, val_bgn, val_end);
+ else
+ bfr.Add(val);
+ bfr.Add_byte_nl();
+ }
+ private static final byte[] Atr_name = Bry_.new_ascii_("name=");
+}
diff --git a/400_xowa/src/gplx/gfs/Gfs_wtr.java b/400_xowa/src/gplx/gfs/Gfs_wtr.java
new file mode 100644
index 000000000..8402415f7
--- /dev/null
+++ b/400_xowa/src/gplx/gfs/Gfs_wtr.java
@@ -0,0 +1,46 @@
+/*
+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.gfs; import gplx.*;
+public class Gfs_wtr {
+ public byte Quote_char() {return quote_char;} public Gfs_wtr Quote_char_(byte v) {quote_char = v; return this;} private byte quote_char = Byte_ascii.Apos;
+ public Bry_bfr Bfr() {return bfr;} private Bry_bfr bfr = Bry_bfr.reset_(255);
+ public void Add_grp_bgn(byte[] key) {
+ bfr.Add(key); // key
+ bfr.Add_byte(Byte_ascii.Curly_bgn); // {
+ }
+ public void Add_grp_end(byte[] key) {
+ bfr.Add_byte(Byte_ascii.Curly_end); // }
+ }
+ public void Add_set_eq(byte[] key, byte[] val) {
+ bfr.Add(key); // key
+ bfr.Add_byte_eq(); // =
+ bfr.Add_byte(quote_char); // '
+ Write_val(val);
+ bfr.Add_byte(quote_char); // '
+ bfr.Add_byte(Byte_ascii.Semic); // ;
+ }
+ private void Write_val(byte[] bry) {
+ int bry_len = bry.length;
+ for (int i = 0; i < bry_len; i++) {
+ byte b = bry[i];
+ if (b == quote_char) // byte is quote
+ bfr.Add_byte(b); // double up
+ bfr.Add_byte(b);
+ }
+ }
+}
diff --git a/400_xowa/src/gplx/gfui/Gfui_bnd_parser.java b/400_xowa/src/gplx/gfui/Gfui_bnd_parser.java
new file mode 100644
index 000000000..ea425cba7
--- /dev/null
+++ b/400_xowa/src/gplx/gfui/Gfui_bnd_parser.java
@@ -0,0 +1,286 @@
+/*
+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.gfui; import gplx.*;
+public class Gfui_bnd_parser {
+ private Bry_bfr tmp_bfr = Bry_bfr.reset_(32);
+ private Hash_adp_bry
+ gfui_regy = Hash_adp_bry.ci_ascii_()
+ , norm_regy = Hash_adp_bry.ci_ascii_()
+ ;
+ private static final Gfui_bnd_tkn
+ Itm_sym_plus = new_sym_(Gfui_bnd_tkn.Tid_sym_plus , new byte[] {Byte_ascii.Plus})
+ , Itm_sym_pipe = new_sym_(Gfui_bnd_tkn.Tid_sym_pipe , new byte[] {Byte_ascii.Pipe})
+ , Itm_sym_comma = new_sym_(Gfui_bnd_tkn.Tid_sym_comma , new byte[] {Byte_ascii.Comma})
+// , Itm_sym_ws = new_sym_(Gfui_bnd_tkn.Tid_sym_ws , Bry_.Empty)
+ , Itm_sym_eos = new_sym_(Gfui_bnd_tkn.Tid_sym_eos , Bry_.Empty)
+ ;
+ private static final Gfui_bnd_tkn[] Mod_ary = new Gfui_bnd_tkn[]
+ { null
+ , new_mod_(Gfui_bnd_tkn.Tid_mod_c , "mod.c" , "Ctrl")
+ , new_mod_(Gfui_bnd_tkn.Tid_mod_a , "mod.a" , "Alt")
+ , new_mod_(Gfui_bnd_tkn.Tid_mod_ca , "mod.ca" , "Ctrl + Alt")
+ , new_mod_(Gfui_bnd_tkn.Tid_mod_s , "mod.s" , "Shift")
+ , new_mod_(Gfui_bnd_tkn.Tid_mod_cs , "mod.cs" , "Ctrl + Shift")
+ , new_mod_(Gfui_bnd_tkn.Tid_mod_as , "mod.as" , "Alt + Shift")
+ , new_mod_(Gfui_bnd_tkn.Tid_mod_cas , "mod.cas" , "Ctrl + Alt + Shift")
+ };
+ private byte[] src; private int src_len;
+ private ListAdp tkns = ListAdp_.new_(); private int mod_val = Mod_val_null;
+ public String X_to_norm(String src_str) {return Convert(Bool_.Y, src_str);}
+ public String X_to_gfui(String src_str) {return Convert(Bool_.N, src_str);}
+ private String Convert(boolean src_is_gfui, String src_str) {
+ this.src = Bry_.new_utf8_(src_str); this.src_len = src.length;
+ tkns.Clear(); mod_val = Mod_val_null;
+ int pos = 0; int itm_bgn = -1, itm_end = -1;
+ while (pos <= src_len) { // loop over bytes and break up tkns by symbols
+ byte b = pos == src_len ? Byte_ascii.NewLine: src[pos]; // treat eos as "\n" for purpose of separating tokens
+ Gfui_bnd_tkn sym_tkn = null;
+ switch (b) {
+ case Byte_ascii.Plus: // simultaneous; EX: Ctrl + S
+ sym_tkn = Itm_sym_plus;
+ break;
+ case Byte_ascii.Pipe: // alternate; EX: Ctrl + S | Ctrl + Alt + s
+ sym_tkn = Itm_sym_pipe;
+ break;
+ case Byte_ascii.Comma: // chorded; EX: Ctrl + S, Ctrl + T
+ sym_tkn = Itm_sym_comma;
+ break;
+ case Byte_ascii.NewLine: // eos: process anything in bfr
+ sym_tkn = Itm_sym_eos;
+ break;
+ case Byte_ascii.Space:
+ if (itm_bgn != -1) // if word started, " " ends word; EX: "Ctrl + A"; " +" ends "Ctrl"
+ itm_end = pos;
+ ++pos;
+ continue;
+ default: // letter / number; continue
+ if (itm_bgn == -1) // no word started; start it
+ itm_bgn = pos;
+ ++pos;
+ continue;
+ }
+ if (itm_end == -1) // end not set by space; char before symbol is end
+ itm_end = pos;
+ Process_sym(src_is_gfui, sym_tkn, itm_bgn, itm_end);
+ if (sym_tkn.Tid() == Gfui_bnd_tkn.Tid_sym_eos)
+ break;
+ else
+ ++pos;
+ itm_bgn = itm_end = -1;
+ }
+ int tkns_len = tkns.Count();
+ for (int i = 0; i < tkns_len; i++) {
+ Gfui_bnd_tkn tkn = (Gfui_bnd_tkn)tkns.FetchAt(i);
+ tkn.Write(tmp_bfr, !src_is_gfui);
+ }
+ return tmp_bfr.XtoStrAndClear();
+ }
+ private void Process_sym(boolean src_is_gfui, Gfui_bnd_tkn sym_tkn, int itm_bgn, int itm_end) {
+ Hash_adp_bry regy = src_is_gfui ? gfui_regy : norm_regy;
+ Gfui_bnd_tkn tkn = (Gfui_bnd_tkn)regy.Get_by_mid(src, itm_bgn, itm_end);
+ if (tkn == null) throw Err_.new_fmt_("unknown key: key={0}", String_.new_utf8_(src, itm_bgn, itm_end));
+ int mod_adj = Mod_val_null;
+ switch (tkn.Tid()) {
+ case Gfui_bnd_tkn.Tid_mod_c: mod_adj = Gfui_bnd_tkn.Tid_mod_c; break;
+ case Gfui_bnd_tkn.Tid_mod_a: mod_adj = Gfui_bnd_tkn.Tid_mod_a; break;
+ case Gfui_bnd_tkn.Tid_mod_s: mod_adj = Gfui_bnd_tkn.Tid_mod_s; break;
+ case Gfui_bnd_tkn.Tid_mod_cs: mod_adj = Gfui_bnd_tkn.Tid_mod_cs; break;
+ case Gfui_bnd_tkn.Tid_mod_as: mod_adj = Gfui_bnd_tkn.Tid_mod_as; break;
+ case Gfui_bnd_tkn.Tid_mod_ca: mod_adj = Gfui_bnd_tkn.Tid_mod_ca; break;
+ case Gfui_bnd_tkn.Tid_mod_cas: mod_adj = Gfui_bnd_tkn.Tid_mod_cas; break;
+ case Gfui_bnd_tkn.Tid_key: break;
+ default: throw Err_.unhandled(tkn.Tid());
+ }
+ switch (sym_tkn.Tid()) {
+ case Gfui_bnd_tkn.Tid_sym_plus: // EX: Ctrl + A
+ if (mod_adj != Mod_val_null) { // if mod, just update mod_val and exit
+ mod_val = Enm_.FlipInt(true, mod_val, mod_adj);
+ return;
+ }
+ break;
+ }
+ if (mod_val != Mod_val_null) { // modifier exists; add tkn
+ tkns.Add(Mod_ary[mod_val]);
+ tkns.Add(Itm_sym_plus);
+ mod_val = Mod_val_null;
+ }
+ tkns.Add(tkn); // add word
+ if (sym_tkn.Tid() != Gfui_bnd_tkn.Tid_sym_eos)
+ tkns.Add(sym_tkn);
+ }
+ private Gfui_bnd_parser Init_en() {
+ Init_itm_mod(Gfui_bnd_tkn.Tid_mod_c);
+ Init_itm_mod(Gfui_bnd_tkn.Tid_mod_a);
+ Init_itm_mod(Gfui_bnd_tkn.Tid_mod_s);
+ Init_itm_mod(Gfui_bnd_tkn.Tid_mod_ca);
+ Init_itm_mod(Gfui_bnd_tkn.Tid_mod_cs);
+ Init_itm_mod(Gfui_bnd_tkn.Tid_mod_as);
+ Init_itm_mod(Gfui_bnd_tkn.Tid_mod_cas);
+ Init_itm(Gfui_bnd_tkn.Tid_mod_c, "key.ctrl", "Ctrl");
+ Init_itm(Gfui_bnd_tkn.Tid_mod_a, "key.alt", "Atl");
+ Init_itm(Gfui_bnd_tkn.Tid_mod_s, "key.shift", "Shift");
+ Init_itm("key.a", "A");
+ Init_itm("key.b", "B");
+ Init_itm("key.c", "C");
+ Init_itm("key.d", "D");
+ Init_itm("key.e", "E");
+ Init_itm("key.f", "F");
+ Init_itm("key.g", "G");
+ Init_itm("key.h", "H");
+ Init_itm("key.i", "I");
+ Init_itm("key.j", "J");
+ Init_itm("key.k", "K");
+ Init_itm("key.l", "L");
+ Init_itm("key.m", "M");
+ Init_itm("key.n", "N");
+ Init_itm("key.o", "O");
+ Init_itm("key.p", "P");
+ Init_itm("key.q", "Q");
+ Init_itm("key.r", "R");
+ Init_itm("key.s", "S");
+ Init_itm("key.t", "T");
+ Init_itm("key.u", "U");
+ Init_itm("key.v", "V");
+ Init_itm("key.w", "W");
+ Init_itm("key.x", "X");
+ Init_itm("key.y", "Y");
+ Init_itm("key.z", "Z");
+ Init_itm("key.d0", "0");
+ Init_itm("key.d1", "1");
+ Init_itm("key.d2", "2");
+ Init_itm("key.d3", "3");
+ Init_itm("key.d4", "4");
+ Init_itm("key.d5", "5");
+ Init_itm("key.d6", "6");
+ Init_itm("key.d7", "7");
+ Init_itm("key.d8", "8");
+ Init_itm("key.d9", "9");
+ Init_itm("key.f1", "F1");
+ Init_itm("key.f2", "F2");
+ Init_itm("key.f3", "F3");
+ Init_itm("key.f4", "F4");
+ Init_itm("key.f5", "F5");
+ Init_itm("key.f6", "F6");
+ Init_itm("key.f7", "F7");
+ Init_itm("key.f8", "F8");
+ Init_itm("key.f9", "F9");
+ Init_itm("key.f10", "F10");
+ Init_itm("key.f11", "F11");
+ Init_itm("key.f12", "F12");
+ Init_itm("key.none", "None");
+ Init_itm("key.back", "Backspace");
+ Init_itm("key.tab", "Tab");
+ Init_itm("key.clear", "Clear");
+ Init_itm("key.enter", "Enter");
+ Init_itm("key.shiftKey", "ShiftKey");
+ Init_itm("key.ctrlKey", "CtrlKey");
+ Init_itm("key.altKey", "AltKey");
+ Init_itm("key.pause", "Pause");
+ Init_itm("key.capsLock", "CapsLock");
+ Init_itm("key.escape", "Escape");
+ Init_itm("key.space", "Space");
+ Init_itm("key.pageUp", "PageUp");
+ Init_itm("key.pageDown", "PageDown");
+ Init_itm("key.end", "End");
+ Init_itm("key.home", "Home");
+ Init_itm("key.left", "Left");
+ Init_itm("key.up", "Up");
+ Init_itm("key.right", "Right");
+ Init_itm("key.down", "Down");
+ Init_itm("key.printScreen", "PrintScreen");
+ Init_itm("key.insert", "Insert");
+ Init_itm("key.delete", "Delete");
+ Init_itm("key.numLock", "NumLock");
+ Init_itm("key.scrollLock", "ScrollLock");
+ Init_itm("key.semicolon", "Semicolon");
+ Init_itm("key.equal", "Equal");
+ Init_itm("key.comma", "Comma");
+ Init_itm("key.minus", "Minus");
+ Init_itm("key.period", "Period");
+ Init_itm("key.slash", "Slash");
+ Init_itm("key.tick", "Tick");
+ Init_itm("key.openBracket", "OpenBracket");
+ Init_itm("key.backslash", "Backslash");
+ Init_itm("key.closeBracket", "CloseBracket");
+ Init_itm("key.quote", "Quote");
+ Init_itm("mouse.middle", "Middle Click");
+ Init_itm("mouse.left", "Left Click");
+ Init_itm("mouse.right", "Right Click");
+ return this;
+ }
+ private void Init_itm(String gfui, String norm) {Init_itm(Gfui_bnd_tkn.Tid_key, gfui, norm);}
+ private void Init_itm_mod(int tid) {
+ Gfui_bnd_tkn itm = Mod_ary[tid];
+ gfui_regy.Add(itm.Bry_gfui(), itm);
+ norm_regy.Add(itm.Bry_norm(), itm);
+ }
+ private void Init_itm(byte tid, String gfui, String norm) {
+ byte[] gfui_bry = Bry_.new_utf8_(gfui);
+ byte[] norm_bry = Bry_.new_utf8_(norm);
+ Gfui_bnd_tkn itm = new Gfui_bnd_tkn(tid, gfui_bry, norm_bry);
+ gfui_regy.Add(gfui_bry, itm);
+ norm_regy.Add_if_new(norm_bry, itm);
+ }
+ private static final int Mod_val_null = 0;
+ public static Gfui_bnd_parser new_en_() {return new Gfui_bnd_parser().Init_en();} Gfui_bnd_parser() {}
+ private static Gfui_bnd_tkn new_sym_(byte tid, byte[] bry) {return new Gfui_bnd_tkn(tid, bry, bry);}
+ private static Gfui_bnd_tkn new_mod_(byte tid, String gfui, String norm) {return new Gfui_bnd_tkn(tid, Bry_.new_ascii_(gfui), Bry_.new_ascii_(norm));}
+}
+class Gfui_bnd_tkn {
+ public Gfui_bnd_tkn(byte tid, byte[] gfui, byte[] norm) {this.tid = tid; this.bry_gfui = gfui; this.bry_norm = norm;}
+ public byte Tid() {return tid;} private byte tid;
+ public byte[] Bry_gfui() {return bry_gfui;} private byte[] bry_gfui;
+ public byte[] Bry_norm() {return bry_norm;} private byte[] bry_norm;
+ public void Write(Bry_bfr bfr, boolean src_is_gfui) {
+ byte[] bry = src_is_gfui ? bry_gfui : bry_norm;
+ switch (tid) {
+ case Tid_mod_c: case Tid_mod_a: case Tid_mod_s:
+ case Tid_mod_ca: case Tid_mod_cs: case Tid_mod_as: case Tid_mod_cas:
+ bfr.Add(bry);
+ break;
+ case Tid_sym_plus:
+ if (!src_is_gfui)
+ bfr.Add_byte_space();
+ bfr.Add(bry);
+ if (!src_is_gfui)
+ bfr.Add_byte_space();
+ break;
+ case Tid_sym_pipe:
+ if (!src_is_gfui)
+ bfr.Add_byte_space();
+ bfr.Add(bry);
+ if (!src_is_gfui)
+ bfr.Add_byte_space();
+ break;
+ case Tid_sym_comma:
+ bfr.Add(bry);
+ if (!src_is_gfui)
+ bfr.Add_byte_space();
+ break;
+ case Tid_key:
+ bfr.Add(bry);
+ break;
+ }
+ }
+ public static final byte
+ Tid_mod_c = 1 , Tid_mod_a = 2 , Tid_mod_s = 4
+ , Tid_mod_ca = 3 , Tid_mod_cs = 5 , Tid_mod_as = 6, Tid_mod_cas = 7
+ , Tid_sym_plus = 8 , Tid_sym_pipe = 9 , Tid_sym_comma = 10, Tid_sym_eos = 11
+ , Tid_key = 12
+ ;
+}
diff --git a/400_xowa/src/gplx/gfui/Gfui_bnd_parser_tst.java b/400_xowa/src/gplx/gfui/Gfui_bnd_parser_tst.java
new file mode 100644
index 000000000..0446184fb
--- /dev/null
+++ b/400_xowa/src/gplx/gfui/Gfui_bnd_parser_tst.java
@@ -0,0 +1,56 @@
+/*
+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.gfui; import gplx.*;
+import org.junit.*;
+public class Gfui_bnd_parser_tst {
+ @Before public void init() {fxt.Clear();} private Gfui_bnd_parser_fxt fxt = new Gfui_bnd_parser_fxt();
+ @Test public void Norm_one() {
+ fxt.Test_x_to_norm("mod.c" , "Ctrl");
+ fxt.Test_x_to_norm("key.ctrl" , "Ctrl");
+ fxt.Test_x_to_norm("key.a" , "A");
+ fxt.Test_x_to_norm("key.left" , "Left");
+ }
+ @Test public void Norm_add() {
+ fxt.Test_x_to_norm("mod.c+key.a" , "Ctrl + A");
+ fxt.Test_x_to_norm("mod.ca+key.a" , "Ctrl + Alt + A");
+ fxt.Test_x_to_norm("mod.cas+key.a" , "Ctrl + Alt + Shift + A");
+ }
+ @Test public void Norm_chord() {
+ fxt.Test_x_to_norm("key.a,key.b" , "A, B");
+ }
+ @Test public void Norm_add_and_chord() {
+ fxt.Test_x_to_norm("mod.c+key.a,mod.a+key.b" , "Ctrl + A, Alt + B");
+ }
+ @Test public void Gfui_add() {
+ fxt.Test_x_to_gfui("Ctrl + A" , "mod.c+key.a");
+ fxt.Test_x_to_gfui("Ctrl + Shift + A" , "mod.cs+key.a");
+ fxt.Test_x_to_gfui("Ctrl + Alt + Shift + A" , "mod.cas+key.a");
+ }
+}
+class Gfui_bnd_parser_fxt {
+ private Gfui_bnd_parser parser;
+ public void Clear() {
+ parser = Gfui_bnd_parser.new_en_();
+ }
+ public void Test_x_to_norm(String key, String expd) {
+ Tfds.Eq(expd, parser.X_to_norm(key));
+ }
+ public void Test_x_to_gfui(String key, String expd) {
+ Tfds.Eq(expd, parser.X_to_gfui(key));
+ }
+}
diff --git a/400_xowa/src/gplx/html/Html_atrs.java b/400_xowa/src/gplx/html/Html_atrs.java
new file mode 100644
index 000000000..bb3e75ca0
--- /dev/null
+++ b/400_xowa/src/gplx/html/Html_atrs.java
@@ -0,0 +1,28 @@
+/*
+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.html; import gplx.*;
+public class Html_atrs {
+ public static final String
+ Src_str = "src"
+ ;
+ public static final byte[]
+ Id_bry = Bry_.new_ascii_("id")
+ , Cls_bry = Bry_.new_ascii_("class")
+ , Style_bry = Bry_.new_ascii_("style")
+ ;
+}
diff --git a/400_xowa/src/gplx/html/Html_consts.java b/400_xowa/src/gplx/html/Html_consts.java
new file mode 100644
index 000000000..4274f1626
--- /dev/null
+++ b/400_xowa/src/gplx/html/Html_consts.java
@@ -0,0 +1,42 @@
+/*
+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.html; import gplx.*;
+public class Html_consts {
+ public static final String Nl_str = "
";
+ public static final String
+ Comm_bgn_str = ""
+ , Img_str = "img"
+ ;
+ public static final byte[]
+ Lt = Bry_.new_ascii_("<"), Gt = Bry_.new_ascii_(">")
+ , Amp = Bry_.new_ascii_("&"), Quote = Bry_.new_ascii_("""), Apos = Bry_.new_ascii_("'")
+ , Eq = Bry_.new_ascii_("=")
+ , Nl_bry = Bry_.new_ascii_(Nl_str), Space_bry = Bry_.new_ascii_(" ")
+ , Comm_bgn = Bry_.new_ascii_(Comm_bgn_str), Comm_end = Bry_.new_ascii_(Comm_end_str)
+ , Hr_bry = Bry_.new_ascii_("")
+ , Br_bry = Bry_.new_ascii_(" ")
+ , Td_bgn_bry = Bry_.new_ascii_("
")
+ , Td_end_bry = Bry_.new_ascii_("
")
+ , Ul_tag_bry = Bry_.new_ascii_("ul")
+ ;
+ public static final int
+ Comm_bgn_len = Comm_bgn.length
+ , Comm_end_len = Comm_end.length
+ ;
+}
diff --git a/400_xowa/src/gplx/html/Html_nde.java b/400_xowa/src/gplx/html/Html_nde.java
new file mode 100644
index 000000000..d729db6bf
--- /dev/null
+++ b/400_xowa/src/gplx/html/Html_nde.java
@@ -0,0 +1,94 @@
+/*
+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.html; import gplx.*;
+public class Html_nde {
+ public Html_nde(byte[] src, boolean tag_tid_is_inline, int tag_lhs_bgn, int tag_lhs_end, int tag_rhs_bgn, int tag_rhs_end, int name_bgn, int name_end, int[] cur_atrs, int atrs_idx) {
+ this.src = src;
+ this.tag_tid_is_inline = tag_tid_is_inline;
+ this.tag_lhs_bgn = tag_lhs_bgn; this.tag_lhs_end = tag_lhs_end; this.tag_rhs_bgn = tag_rhs_bgn; this.tag_rhs_end = tag_rhs_end; this.name_bgn = name_bgn; this.name_end = name_end;
+ if (atrs_idx > 0) {
+ atrs = new int[atrs_idx];
+ for (int i = 0; i < atrs_idx; i++)
+ atrs[i] = cur_atrs[i];
+ atrs_len = atrs_idx / 5;
+ }
+ }
+ public byte[] Src() {return src;} private byte[] src;
+ public int[] Atrs() {return atrs;} private int[] atrs = Int_.Ary_empty;
+ public int Atrs_len() {return atrs_len;} private int atrs_len;
+ public boolean Tag_tid_is_inline() {return tag_tid_is_inline;} private boolean tag_tid_is_inline;
+ public int Tag_lhs_bgn() {return tag_lhs_bgn;} public Html_nde Tag_lhs_bgn_(int v) {tag_lhs_bgn = v; return this;} private int tag_lhs_bgn;
+ public int Tag_lhs_end() {return tag_lhs_end;} public Html_nde Tag_lhs_end_(int v) {tag_lhs_end = v; return this;} private int tag_lhs_end;
+ public int Tag_rhs_bgn() {return tag_rhs_bgn;} public Html_nde Tag_rhs_bgn_(int v) {tag_rhs_bgn = v; return this;} private int tag_rhs_bgn;
+ public int Tag_rhs_end() {return tag_rhs_end;} public Html_nde Tag_rhs_end_(int v) {tag_rhs_end = v; return this;} private int tag_rhs_end;
+ public int Name_bgn() {return name_bgn;} public Html_nde Name_bgn_(int v) {name_bgn = v; return this;} private int name_bgn;
+ public int Name_end() {return name_end;} public Html_nde Name_end_(int v) {name_end = v; return this;} private int name_end;
+ public void Clear() {tag_lhs_bgn = tag_rhs_bgn = -1;}
+ public String Atrs_val_by_key_str(String find_key_str) {return String_.new_utf8_(Atrs_val_by_key_bry(Bry_.new_utf8_(find_key_str)));}
+ public byte[] Atrs_val_by_key_bry(byte[] find_key_bry) {
+ for (int i = 0; i < atrs_len; i ++) {
+ int atrs_idx = i * 5;
+ int atr_key_bgn = atrs[atrs_idx + 1];
+ int atr_key_end = atrs[atrs_idx + 2];
+ if (Bry_.Match(src, atr_key_bgn, atr_key_end, find_key_bry))
+ return Atrs_vals_by_pos(src, atrs[atrs_idx + 0], atrs[atrs_idx + 3], atrs[atrs_idx + 4]);
+ }
+ return null;
+ }
+ byte[] Atrs_vals_by_pos(byte[] src, int quote_byte, int bgn, int end) {
+ Bry_bfr tmp_bfr = Bry_bfr.new_();
+ boolean dirty = false;
+ for (int i = bgn; i < end; i++) {
+ byte b = src[i];
+ switch (b) {
+ case Byte_ascii.Backslash:
+ if (!dirty) {dirty = true; tmp_bfr.Add_mid(src, bgn, i);}
+ ++i;
+ tmp_bfr.Add_byte(src[i]);
+ break;
+ default:
+ if (b == quote_byte) {
+ byte next_byte = src[i + 1];
+ if (next_byte == b) {
+ if (!dirty) {dirty = true; tmp_bfr.Add_mid(src, bgn, i);}
+ ++i;
+ tmp_bfr.Add_byte(src[i]);
+ }
+ }
+ else {
+ if (dirty)
+ tmp_bfr.Add_byte(b);
+ }
+ break;
+ }
+ }
+ return dirty ? tmp_bfr.XtoAryAndClear() : Bry_.Mid(src, bgn, end);
+ }
+ public byte[] Data(byte[] src) {
+ return Bry_.Mid(src, tag_lhs_end, tag_rhs_bgn);
+ }
+}
+// class Xoh_atr {
+// public byte[] Key_bry() {return key_bry;} private byte[] key_bry;
+// public byte[] Val_bry() {return val_bry;} private byte[] val_bry;
+// public int Key_bgn() {return key_bgn;} private int key_bgn;
+// public int Key_end() {return key_end;} private int key_end;
+// public int Val_bgn() {return val_bgn;} private int val_bgn;
+// public int Val_end() {return val_end;} private int val_end;
+// public byte Val_quote_tid() {return val_quote_tid;} private byte val_quote_tid;
+// }
diff --git a/400_xowa/src/gplx/html/Html_parser.java b/400_xowa/src/gplx/html/Html_parser.java
new file mode 100644
index 000000000..fac131420
--- /dev/null
+++ b/400_xowa/src/gplx/html/Html_parser.java
@@ -0,0 +1,165 @@
+/*
+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.html; import gplx.*;
+import gplx.core.bytes.*;
+public class Html_parser {
+ public Html_parser() {
+ Bry_bldr bry_bldr = new Bry_bldr();
+ bry_xnde_name = bry_bldr.New_256().Set_rng_xml_identifier(Scan_valid).Set_rng_ws(Scan_stop).Val();
+ bry_atr_key = bry_bldr.New_256().Set_rng_xml_identifier(Scan_valid).Set_rng_ws(Scan_stop).Set_many(Scan_stop, Byte_ascii.Eq).Val();
+ }
+ byte[] src; int pos, end; byte[] bry_xnde_name, bry_atr_key;
+ int cur_atrs_idx = 0; int[] cur_atrs = new int[250];// define max of 50 atrs;
+ public Html_nde[] Parse_as_ary(byte[] src) {return Parse_as_ary(src, 0, src.length, Wildcard, Wildcard);}
+ public Html_nde[] Parse_as_ary(byte[] src, int bgn, int end) {return Parse_as_ary(src, bgn, end, Wildcard, Wildcard);}
+ public Html_nde[] Parse_as_ary(byte[] src, int bgn, int end, byte[] find_key, byte[] find_val) { // flattens html into a list of hndes; only used for Options
+ this.src = src; pos = bgn; this.end = end;
+ ListAdp rv = ListAdp_.new_();
+ while (pos < end) {
+ byte b = src[pos++];
+ switch (b) {
+ case Byte_ascii.Lt:
+ if (xnde_init) {
+ if (Parse_xnde_lhs()) {
+ if (tag_tid_is_inline)
+ rv.Add(new Html_nde(src, tag_tid_is_inline, cur_lhs_bgn, cur_lhs_end, cur_rhs_bgn, pos, cur_name_bgn, cur_name_end, cur_atrs, cur_atrs_idx));
+ else
+ xnde_init = false;
+ }
+ }
+ else {
+ if (Parse_xnde_rhs()) {
+ rv.Add(new Html_nde(src, tag_tid_is_inline, cur_lhs_bgn, cur_lhs_end, cur_rhs_bgn, pos, cur_name_bgn, cur_name_end, cur_atrs, cur_atrs_idx));
+ }
+ xnde_init = true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return (Html_nde[])rv.XtoAry(Html_nde.class);
+ }
+ int cur_lhs_bgn, cur_lhs_end, cur_name_bgn, cur_name_end, cur_rhs_bgn; boolean xnde_init = true, tag_tid_is_inline = false;
+ private boolean Parse_xnde_rhs() {
+ cur_rhs_bgn = pos - 1; // -1 b/c "<" is already read
+ byte b = src[pos];
+ if (b != Byte_ascii.Slash) return false;
+ ++pos;
+ int name_len = cur_name_end - cur_name_bgn;
+ if (pos + name_len >= end) return false;
+ if (!Bry_.Match(src, pos, pos + name_len, src, cur_name_bgn, cur_name_end)) return false;
+ pos += name_len;
+ if (src[pos] != Byte_ascii.Gt) return false;
+ ++pos;
+ return true;
+ }
+ private boolean Parse_xnde_lhs() {
+ cur_atrs_idx = 0;
+ cur_lhs_bgn = pos - 1;
+ cur_name_bgn = pos;
+ tag_tid_is_inline = false;
+ byte rslt = Skip_while_valid(this.bry_atr_key);
+ if (rslt == Scan_invalid) return false;
+ cur_name_end = pos;
+ int key_bgn, key_end, val_bgn, quote_type;
+ while (true) {
+ if (pos >= end) return false;
+ key_bgn = key_end = val_bgn = quote_type = -1;
+ Skip_ws();
+ byte b = src[pos];
+ if (b == Byte_ascii.Slash) {
+ ++pos;
+ if (pos == end) return false;
+ byte next = src[pos];
+ if (next == Byte_ascii.Gt) {
+ tag_tid_is_inline = true;
+ ++pos;
+ break;
+ }
+ else return false; // NOTE: don't consume byte b/c false
+ }
+ else if (b == Byte_ascii.Gt) {
+ ++pos;
+ break;
+ }
+ key_bgn = pos;
+ rslt = Skip_while_valid(this.bry_atr_key);
+ if (rslt == Scan_invalid) return false;
+ key_end = pos;
+ Skip_ws();
+ if (src[pos++] != Byte_ascii.Eq) return false;
+ Skip_ws();
+ byte quote_byte = src[pos];
+ switch (quote_byte) {
+ case Byte_ascii.Quote: quote_type = quote_byte; break;
+ case Byte_ascii.Apos: quote_type = quote_byte; break;
+ default: return false;
+ }
+ val_bgn = ++pos; // ++pos: start val after quote
+ if (!Skip_to_quote_end(quote_byte)) return false;
+ cur_atrs[cur_atrs_idx + 0] = quote_type;
+ cur_atrs[cur_atrs_idx + 1] = key_bgn;
+ cur_atrs[cur_atrs_idx + 2] = key_end;
+ cur_atrs[cur_atrs_idx + 3] = val_bgn;
+ cur_atrs[cur_atrs_idx + 4] = pos - 1; // NOTE: Skip_to_quote_end positions after quote
+ cur_atrs_idx += 5;
+ }
+ cur_lhs_end = pos;
+ return true;
+ }
+ private void Skip_ws() {
+ while (pos < end) {
+ switch (src[pos]) {
+ case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.NewLine: case Byte_ascii.CarriageReturn:
+ ++pos;
+ break;
+ default:
+ return;
+ }
+ }
+ }
+ boolean Skip_to_quote_end(byte v) {
+ while (pos < end) {
+ byte b = src[pos++];
+ if (b == v) {
+ if (pos == end) return false;
+ byte next = src[pos];
+ if (next != v) return true;
+ else ++pos;
+ }
+ else if (b == Byte_ascii.Backslash) {
+ ++pos;
+ }
+ }
+ return false;
+ }
+ byte Skip_while_valid(byte[] comp) {
+ while (pos < end) {
+ byte rv = comp[src[pos]];
+ if (rv == Scan_valid)
+ ++pos;
+ else
+ return rv;
+ }
+ return Scan_invalid;
+ }
+ private static final byte Scan_invalid = 0, Scan_valid = 1, Scan_stop = 2;
+ public static final byte[] Wildcard = null;
+ public static final String Wildcard_str = null;
+}
diff --git a/400_xowa/src/gplx/html/Html_parser_tst.java b/400_xowa/src/gplx/html/Html_parser_tst.java
new file mode 100644
index 000000000..4c347e013
--- /dev/null
+++ b/400_xowa/src/gplx/html/Html_parser_tst.java
@@ -0,0 +1,53 @@
+/*
+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.html; import gplx.*;
+import org.junit.*;
+public class Html_parser_tst {
+ @Before public void init() {fxt.Clear();} private Xoh_parser_fxt fxt = new Xoh_parser_fxt();
+ @Test public void One() {fxt.Test_parse_find_all("", "id0");}
+ @Test public void Many() {fxt.Test_parse_find_all("", "id0", "id1", "id2");}
+ @Test public void Inline() {fxt.Test_parse_find_all("", "id0");}
+ @Test public void Mix() {fxt.Test_parse_find_all("012id=id2345abc", "id0", "id1", "id2");}
+ @Test public void Quote_double() {fxt.Test_parse_find_all("", "id'0");}
+ @Test public void Quote_escape() {fxt.Test_parse_find_all("", "id'0");}
+}
+class Xoh_parser_fxt {
+ public void Clear() {
+ if (parser == null) {
+ parser = new Html_parser();
+ }
+ } private Html_parser parser;
+ public Xoh_parser_fxt Test_parse_find_all(String raw_str, String... expd) {return Test_parse_find(raw_str, Html_parser.Wildcard_str, Html_parser.Wildcard_str, expd);}
+ public Xoh_parser_fxt Test_parse_find(String raw_str, String find_key, String find_val, String... expd) {
+ byte[] raw = Bry_.new_ascii_(raw_str);
+ Html_nde[] actl_ndes = parser.Parse_as_ary(raw, 0, raw.length, Bry_.new_ascii_(find_key), Bry_.new_ascii_(find_val));
+ String[] actl = Xto_ids(raw, actl_ndes);
+ Tfds.Eq_ary_str(expd, actl);
+ return this;
+ }
+ private String[] Xto_ids(byte[] src, Html_nde[] ary) {
+ int len = ary.length;
+ String[] rv = new String[len];
+ for (int i = 0; i < len; i++) {
+ Html_nde itm = ary[i];
+ String atr_val = itm.Atrs_val_by_key_str("id");
+ rv[i] = atr_val;
+ }
+ return rv;
+ }
+}
diff --git a/400_xowa/src/gplx/html/Html_selecter.java b/400_xowa/src/gplx/html/Html_selecter.java
new file mode 100644
index 000000000..810dd1cb7
--- /dev/null
+++ b/400_xowa/src/gplx/html/Html_selecter.java
@@ -0,0 +1,40 @@
+/*
+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.html; import gplx.*;
+public class Html_selecter {
+ public static Html_nde[] Select(byte[] src, Html_nde[] ary, Hash_adp_bry hash) {
+ ListAdp list = ListAdp_.new_();
+ int xndes_len = ary.length;
+ for (int i = 0; i < xndes_len; i++) {
+ Html_nde hnde = ary[i];
+ int[] atrs = hnde.Atrs();
+ int atrs_len = atrs.length;
+ for (int j = 0; j < atrs_len; j += 5) {
+ int atr_key_bgn = atrs[j + 1];
+ int atr_key_end = atrs[j + 2];
+ if (hash.Get_by_mid(src, atr_key_bgn, atr_key_end) != null) {
+ list.Add(hnde);
+ break;
+ }
+ }
+ }
+ Html_nde[] rv = (Html_nde[])list.XtoAry(Html_nde.class);
+ list.Clear();
+ return rv;
+ }
+}
diff --git a/400_xowa/src/gplx/html/Html_tags.java b/400_xowa/src/gplx/html/Html_tags.java
new file mode 100644
index 000000000..8ab6e61cb
--- /dev/null
+++ b/400_xowa/src/gplx/html/Html_tags.java
@@ -0,0 +1,36 @@
+/*
+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.html; import gplx.*;
+public class Html_tags {
+ public static final String
+ A_str = "a"
+ , Img_str = "img"
+ ;
+ public static final byte[]
+ Body_lhs = Bry_.new_ascii_("")
+ , Body_rhs = Bry_.new_ascii_("")
+ , Html_rhs = Bry_.new_ascii_("