diff --git a/401_xowa_updater/.classpath b/401_xowa_updater/.classpath
new file mode 100644
index 000000000..4b6862e97
--- /dev/null
+++ b/401_xowa_updater/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/401_xowa_updater/src/gplx/xowa/Xoa_manifest_item.java b/401_xowa_updater/src/gplx/xowa/Xoa_manifest_item.java
new file mode 100644
index 000000000..3de05d093
--- /dev/null
+++ b/401_xowa_updater/src/gplx/xowa/Xoa_manifest_item.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.xowa; import gplx.*;
+public class Xoa_manifest_item {
+ public Xoa_manifest_item(Io_url src, Io_url trg) {
+ this.src = src;
+ this.trg = trg;
+ }
+ public Io_url Src() {return src;} private final Io_url src;
+ public Io_url Trg() {return trg;} private final Io_url trg;
+}
diff --git a/401_xowa_updater/src/gplx/xowa/Xoa_manifest_list.java b/401_xowa_updater/src/gplx/xowa/Xoa_manifest_list.java
new file mode 100644
index 000000000..768a20b3d
--- /dev/null
+++ b/401_xowa_updater/src/gplx/xowa/Xoa_manifest_list.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.xowa; import gplx.*;
+public class Xoa_manifest_list {
+ private final Ordered_hash hash = Ordered_hash_.New();
+ public int Len() {return hash.Len();}
+ public Xoa_manifest_item Get_at(int i) {return (Xoa_manifest_item)hash.Get_at(i);}
+ public void Del_at(int i) {
+ Xoa_manifest_item item = (Xoa_manifest_item)hash.Get_at(i);
+ hash.Del(item.Src().Raw());
+ }
+ public void Add(Io_url src, Io_url trg) {
+ Xoa_manifest_item item = new Xoa_manifest_item(src, trg);
+ hash.Add(src.Raw(), item);
+ }
+ public void Save(Bry_bfr bfr) {
+ // save as "src\ttrg\n"
+ int len = hash.Len();
+ for (int i = 0; i < len; i++) {
+ Xoa_manifest_item item = (Xoa_manifest_item)hash.Get_at(i);
+ bfr.Add_str_u8(item.Src().Raw());
+ bfr.Add_byte(Byte_ascii.Tab);
+ bfr.Add_str_u8(item.Trg().Raw());
+ bfr.Add_byte(Byte_ascii.Nl);
+ }
+ }
+ public void Load(byte[] src, int src_bgn, int src_end) {
+ int pos = src_bgn;
+ // load by "src\ttrg\n"
+ while (pos < src_end) {
+ // get pos
+ int tab_pos = Bry_find_.Find_fwd(src, Byte_ascii.Tab, pos, src_end);
+ if (tab_pos == Bry_find_.Not_found) throw Err_.new_wo_type("failed to find tab", "excerpt", Bry_.Mid(src, pos, src_end));
+ int nl_pos = Bry_find_.Find_fwd(src, Byte_ascii.Nl, tab_pos + 1, src_end);
+ if (nl_pos == Bry_find_.Not_found) throw Err_.new_wo_type("failed to find nl", "excerpt", Bry_.Mid(src, pos, src_end));
+
+ // create
+ Io_url src_url = Io_url_.new_fil_(String_.new_u8(src, pos, tab_pos));
+ Io_url trg_url = Io_url_.new_fil_(String_.new_u8(src, tab_pos + 1, nl_pos));
+ Xoa_manifest_item item = new Xoa_manifest_item(src_url, trg_url);
+ hash.Add(src_url.Raw(), item);
+
+ pos = nl_pos + 1;
+ }
+ }
+}
diff --git a/401_xowa_updater/src/gplx/xowa/Xoa_manifest_view.java b/401_xowa_updater/src/gplx/xowa/Xoa_manifest_view.java
new file mode 100644
index 000000000..c85d8240d
--- /dev/null
+++ b/401_xowa_updater/src/gplx/xowa/Xoa_manifest_view.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.xowa; import gplx.*; import gplx.xowa.*;
+import gplx.core.envs.*;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.net.*;
+import javax.swing.*;
+import javax.swing.border.Border;
+public class Xoa_manifest_view extends JFrame implements Gfo_invk {
+ private final Xoa_manifest_wkr wkr;
+ private String run_xowa_cmd;
+ public Xoa_manifest_view(Io_url manifest_url, Io_url update_root) {
+ super("XOWA Application Update");
+ // init window
+ this.setTitle("XOWA Application Update");
+ try {
+ UIManager.setLookAndFeel(
+ UIManager.getSystemLookAndFeelClassName());
+ }
+ catch (Exception e) {System.out.println(e.getMessage());}
+ this.setSize(700, 580);
+ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ this.setLocationRelativeTo(null);
+ this.setBackground(Color.WHITE);
+
+ // init panel
+ JPanel main_panel = new JPanel();
+ main_panel.setSize(700, 580);
+ this.setContentPane(main_panel);
+ New_text_area(main_panel);
+ run_xowa_lbl = New_link_lbl(this, main_panel, Invk__run_xowa, "Run XOWA");
+ this.setVisible(true);
+ this.wkr = new Xoa_manifest_wkr(this);
+ wkr.Init(manifest_url, update_root);
+ }
+ private JTextArea text_area;
+ private JLabel run_xowa_lbl;
+ private JScrollPane New_text_area(JPanel owner) {
+ // init textarea
+ text_area = new JTextArea();
+ text_area.setForeground(Color.BLACK);
+ text_area.setBackground(Color.WHITE);
+ text_area.setMargin(new Insets(0, 0, 0,0));
+ text_area.setLineWrap(true);
+ text_area.setWrapStyleWord(true); // else text will wrap in middle of words
+ text_area.setCaretColor(Color.BLACK);
+ text_area.getCaret().setBlinkRate(0);
+
+ // init scrollpane
+ JScrollPane text_scroll_pane = new JScrollPane(text_area);
+ text_scroll_pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
+ owner.add(text_scroll_pane, BorderLayout.CENTER);
+ text_scroll_pane.setPreferredSize(new Dimension(675, 500));
+ return text_scroll_pane;
+ }
+ private static JLabel New_link_lbl(Gfo_invk invk, JPanel owner, String invk_cmd, String text) {
+ JLabel rv = new JLabel();
+ rv.setText(text);
+ rv.setPreferredSize(new Dimension(80, 20));
+ owner.add(rv, BorderLayout.PAGE_END);
+ return rv;
+ }
+ public void Append(String s) {
+ text_area.setText(text_area.getText() + "> " + s + "\n");
+ }
+ public void Mark_done(String s) {
+ this.run_xowa_cmd = s;
+ run_xowa_lbl.setText("Run XOWA");
+ run_xowa_lbl.setCursor(new Cursor(Cursor.HAND_CURSOR));
+ run_xowa_lbl.addMouseListener(new Swing_mouse_adapter(Gfo_invk_cmd.New_by_key(this, Invk__run_xowa)));
+ }
+ public void Run_xowa() {
+ Runtime_.Exec(run_xowa_cmd);
+ System_.Exit();
+ }
+ public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
+ if (ctx.Match(k, Invk__run_xowa)) Run_xowa();
+ else return Gfo_invk_.Rv_unhandled;
+ return this;
+ } private static final String Invk__run_xowa = "run_xowa";
+
+ public static void Run(Io_url manifest_url, Io_url update_root) {
+ new Xoa_manifest_view(manifest_url, update_root);
+ }
+}
+class Swing_mouse_adapter extends MouseAdapter {
+ private final Gfo_invk_cmd cmd;
+ public Swing_mouse_adapter(Gfo_invk_cmd cmd) {this.cmd = cmd;}
+ @Override public void mouseClicked(MouseEvent ev) {
+ try {cmd.Exec();}
+ catch (Exception e) {
+ System.out.println(Err_.Message_gplx_full(e));
+ }
+ }
+}
diff --git a/401_xowa_updater/src/gplx/xowa/Xoa_manifest_wkr.java b/401_xowa_updater/src/gplx/xowa/Xoa_manifest_wkr.java
new file mode 100644
index 000000000..ccf883e79
--- /dev/null
+++ b/401_xowa_updater/src/gplx/xowa/Xoa_manifest_wkr.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.xowa; import gplx.*;
+import gplx.core.envs.*;
+class Xoa_manifest_wkr {
+ private final Xoa_manifest_view view;
+ private final Xoa_manifest_list list = new Xoa_manifest_list();
+ private Io_url manifest_url, update_root;
+ private String run_xowa_cmd;
+ public Xoa_manifest_wkr(Xoa_manifest_view view) {
+ this.view = view;
+ }
+ public void Init(Io_url manifest_url, Io_url update_root) {
+ // load manifest
+ this.manifest_url = manifest_url;
+ this.update_root = update_root;
+ view.Append("loading manifest from: " + manifest_url.Raw());
+ byte[] src = Io_mgr.Instance.LoadFilBry(manifest_url);
+
+ // parse manifest
+ int nl_pos = Bry_find_.Find_fwd(src, Byte_ascii.Nl);
+ if (nl_pos == Bry_find_.Not_found) throw Err_.new_wo_type("could not find nl in manifest", "manifest_url", manifest_url.Raw());
+ this.run_xowa_cmd = String_.new_u8(src, 0, nl_pos);
+ list.Load(src, nl_pos + 1, src.length);
+
+ this.Wait();
+ }
+ private void Wait() {
+ int tries = 0;
+ while (tries++ < 100) {
+ gplx.core.threads.Thread_adp_.Sleep(1000);
+ if (Copy_files())
+ break;
+ else {
+ String topmost = "#error";
+ if (list.Len() > 0) {
+ Xoa_manifest_item item = (Xoa_manifest_item)list.Get_at(0);
+ topmost = item.Src().Raw();
+ }
+ view.Append("waiting for XOWA to release file: " + topmost);
+ }
+ }
+ this.On_exit();
+ }
+ public void On_exit() {
+ // delte update root and manifest_url
+ view.Append("deleting update dir: " + update_root.Raw());
+ Io_mgr.Instance.DeleteDirDeep(update_root);
+ Io_mgr.Instance.DeleteFil(manifest_url);
+
+ view.Mark_done(run_xowa_cmd);
+ view.Run_xowa();
+ }
+ private boolean Copy_files() {
+ // loop list and copy items
+ int len = list.Len();
+ int idx = 0;
+ for (idx = 0; idx < len; idx++) {
+ Xoa_manifest_item item = (Xoa_manifest_item)list.Get_at(idx);
+ try {
+ Io_mgr.Instance.DeleteFil_args(item.Trg()).MissingFails_off().Exec();
+ Io_mgr.Instance.MoveFil_args(item.Src(), item.Trg(), true).Exec();;
+ view.Append(String_.Format("copied file: src={0} trg={1}", item.Src().Raw(), item.Trg().Raw()));
+ }
+ catch (Exception exc) {
+ view.Append(String_.Format("failed to copy file: src={0} trg={1} err={2}", item.Src().Raw(), item.Trg().Raw(), Err_.Message_lang(exc)));
+ return false;
+ }
+ }
+
+ // remove completed items
+ for (int i = 0; i < idx; i++) {
+ list.Del_at(0);
+ }
+ return true;
+ }
+}
diff --git a/401_xowa_updater/src/gplx/xowa/Xowa_app_updater.java b/401_xowa_updater/src/gplx/xowa/Xowa_app_updater.java
new file mode 100644
index 000000000..1475e1130
--- /dev/null
+++ b/401_xowa_updater/src/gplx/xowa/Xowa_app_updater.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.xowa;
+import gplx.Io_url_;
+import gplx.core.envs.*;
+public class Xowa_app_updater {
+ public static void main(String[] args) {
+ Env_.Init_swt(args, Xowa_app_updater.class);
+ if (args.length == 0) {
+ System.out.println("could not run app_updater; must pass 2 arguments: manifest url and update_root");
+ return;
+ }
+ Xoa_manifest_view.Run(Io_url_.new_fil_(args[0]), Io_url_.new_dir_(args[1]));
+ }
+}