--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="chartool" default="dest" basedir=".">
+
+ <property name="src" location="src"/>
+ <property name="build" location="build"/>
+ <property name="dest" location="dest"/>
+ <property name="lib" location="lib"/>
+ <property name="temp" location="temp"/>
+ <property name="rhino.ftp.dir"
+ value="ftp://ftp.mozilla.org/pub/mozilla.org/js"/>
+ <property name="rhino.name" value="rhino1_7R2"/>
+ <property name="manifest.name" value="MANIFEST.MF"/>
+
+ <target name="init">
+ <mkdir dir="${build}"/>
+ <mkdir dir="${lib}"/>
+ </target>
+
+ <target name="rhino.check" depends="init">
+ <available file="${lib}/js.jar" property="rhino.exists"/>
+ </target>
+
+ <target name="download" depends="rhino.check" unless="rhino.exists">
+ <mkdir dir="${temp}"/>
+ <get src="${rhino.ftp.dir}/${rhino.name}.zip"
+ dest="${temp}/${rhino.name}.zip"/>
+ <unzip src="${temp}/${rhino.name}.zip" dest="${temp}"/>
+ <move file="${temp}/${rhino.name}/js.jar" todir="${lib}"/>
+ </target>
+
+ <target name="compile" depends="download">
+ <javac srcdir="${src}"
+ destdir="${build}"
+ classpath="${lib}/js.jar"/>
+ </target>
+
+ <target name="manifest" depends="compile">
+ <mkdir dir="${temp}"/>
+ <manifest file="${temp}/${manifest.name}">
+ <attribute name="Class-Path" value=". lib/js.jar"/>
+ <attribute name="Main-Class"
+ value="jp.sourceforge.sawarabifonts.chartool.Main"/>
+ </manifest>
+ </target>
+
+ <target name="dest" depends="manifest">
+ <mkdir dir="${dest}"/>
+ <copy todir="${dest}/lib">
+ <fileset dir="${lib}"/>
+ </copy>
+ <copy todir="${dest}/js">
+ <fileset dir="js"/>
+ </copy>
+ <jar destfile="${dest}/chartool.jar"
+ basedir="${build}"
+ manifest="${temp}/${manifest.name}"/>
+ </target>
+
+ <target name="clean">
+ <delete dir="${build}"/>
+ <delete dir="${temp}"/>
+ </target>
+</project>
--- /dev/null
+var fonts = [
+];
+
+var script = [
+ function(property, modifier) {
+ },
+ function(property, modifier) {
+ },
+];
+
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+public class CharProperty {
+ final String character;
+ final String name;
+ final String code;
+
+ public CharProperty(String character, String code) {
+ this(character, code, "");
+ }
+
+ public CharProperty(String character, String code, String name) {
+ this.character = character;
+ this.code = code;
+ this.name = name;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import javax.swing.JFrame;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.EvaluatorException;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.ScriptableObject;
+
+public class ConfigScript {
+ private final static ConfigScript instance = new ConfigScript();
+ private JsScriptableObject scriptable = null;
+
+ private ConfigScript() { }
+
+ public static ConfigScript getInstance() {
+ return instance;
+ }
+
+ public void load() throws IOException {
+ load("js/charpalette.js");
+ }
+
+ public void load(String filename) throws IOException {
+ File f = new File(filename);
+ FileReader in = new FileReader(f);
+ Context cx = Context.enter();
+ scriptable = new JsScriptableObject();
+ cx.initStandardObjects(scriptable);
+ setupVariables();
+ try {
+ cx.evaluateReader(scriptable, in, "<config>", 0, null);
+ } finally {
+ Context.exit();
+ }
+ }
+
+ public boolean isLoaded() {
+ return scriptable != null;
+ }
+
+ public String[] getFontNames() {
+ String[] ret = null;
+ if (scriptable.has("fonts", scriptable)) {
+ Object o = scriptable.get("fonts", scriptable);
+ try {
+ ret = (String[]) Context.jsToJava(o, String[].class);
+ } catch (EvaluatorException e) {
+ e.printStackTrace();
+ Logger.getLogger(Main.LOGNAME).warning(e.getMessage());
+ }
+ }
+ return ret;
+ }
+
+ private Function[] getScriptFunction() {
+ final String NAME = "script";
+ Function[] ret = null;
+ if (scriptable.has(NAME, scriptable)) {
+ Object o = scriptable.get(NAME, scriptable);
+ try {
+ ret = (Function[]) Context.jsToJava(o, Function[].class);
+ } catch (EvaluatorException e) {
+ e.printStackTrace();
+ Logger.getLogger(Main.LOGNAME).warning(e.getMessage());
+ }
+ }
+ return ret;
+ }
+
+ public void execScript(int id, String property, int modifier) throws Exception {
+ Function[] fs = getScriptFunction();
+ if (fs == null || fs.length <= id) { return ; }
+
+ Context cx = Context.enter();
+// Class<?> clazz = org.jdesktop.jdic.desktop.Desktop.class;
+// cx.setApplicationClassLoader(clazz.getClassLoader());
+ try {
+ fs[id].call(cx, scriptable, scriptable, new Object[] {property, modifier});
+ } finally {
+ Context.exit();
+ }
+ }
+
+ private void setupVariables() {
+ final int RO = ScriptableObject.READONLY;
+ final int DE = ScriptableObject.DONTENUM;
+ String home = System.getProperty("user.home");
+ ScriptableObject.defineProperty(scriptable, "HOME", home, RO);
+
+ String[] fs = new String[] { "alert" };
+ scriptable.defineFunctionProperties(fs, JsScriptableObject.class, DE);
+ }
+
+ public void setFrame(JFrame frame) {
+ scriptable.setFrame(frame);
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import javax.swing.JMenu;
+import javax.swing.JPopupMenu;
+import javax.swing.JTextField;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.text.TextAction;
+
+public class GlyphViewer extends JTextField {
+ private static final long serialVersionUID = 5811308266106026080L;
+
+ public GlyphViewer(GuiController controller) {
+ Font f = new Font(getFont().getFontName(), Font.PLAIN, 64);
+ setFont(f);
+ setHorizontalAlignment(JTextField.CENTER);
+ setEditable(false);
+ EmptyBorder m = new EmptyBorder(10, 10, 10, 10);
+ setBorder(new CompoundBorder(new EtchedBorder(), m));
+
+ controller.setGlyphViewer(this);
+ setPreferredSize(new Dimension(100, 100));
+
+ final JPopupMenu menu = new GlyphViewerMenu();
+ addCaretListener(new CaretListener() {
+ public void caretUpdate(CaretEvent e) {
+ String s = getSelectedText();
+ if (s != null && s.length() > 0) {
+ menu.show(GlyphViewer.this, 70, 70);
+ }
+ }
+ });
+ }
+
+ private void copyChar() {
+ Clipboard b = Toolkit.getDefaultToolkit().getSystemClipboard();
+ StringSelection s = new StringSelection(getText());
+ b.setContents(s, s);
+ }
+
+ private void changeFont(String nm) {
+ Font f = getFont();
+ int sz = f.getSize();
+ int st = f.getStyle();
+ setFont(new Font(nm, st, sz));
+ }
+
+ class GlyphViewerMenu extends JPopupMenu {
+ private static final long serialVersionUID = 847563481396381931L;
+
+ GlyphViewerMenu() {
+ add(new TextAction("Copy") {
+ private static final long serialVersionUID = -4087404094754292233L;
+ public void actionPerformed(ActionEvent e) { copyChar(); }
+ });
+ JMenu fontmenu = new JMenu("font");
+ setFontMenu(fontmenu, "Dialog");
+ try {
+ addCustomFontMenu(fontmenu);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Logger.getLogger(Main.LOGNAME).warning(e.getMessage());
+ }
+ add(fontmenu);
+ }
+
+ private void addCustomFontMenu(JMenu menu) throws IOException {
+ ConfigScript s = ConfigScript.getInstance();
+ if (! s.isLoaded()) { s.load(); }
+ String[] fnt = s.getFontNames();
+ if (fnt != null) {
+ for (String nm: fnt) setFontMenu(menu, nm);
+ } else {
+ String msg = "configuration of fonts is not found.";
+ System.err.println(msg);
+ Logger.getLogger(Main.LOGNAME).warning(msg);
+ }
+ }
+
+ private void setFontMenu(JMenu menu, final String nm) {
+ menu.add(new TextAction(nm) {
+ private static final long serialVersionUID = 7621704223879655193L;
+ public void actionPerformed(ActionEvent e) { changeFont(nm); }
+ });
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+import java.util.logging.Logger;
+
+public class GuiController {
+ private final Main main;
+ private GlyphViewer glyphViewer = null;
+ private SearchPanel searchPanel = null;
+ private PropertyPanel propertyPanel = null;
+
+ public GuiController(Main main) {
+ this.main = main;
+ }
+
+ public void setGlyphViewer(GlyphViewer g) {
+ this.glyphViewer = g;
+ }
+
+ public void setPropertyPanel(PropertyPanel p) {
+ this.propertyPanel = p;
+ }
+
+ public void setSearchPanel(SearchPanel s) {
+ this.searchPanel = s;
+ }
+
+ private boolean isHexChar(char ch) {
+ return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
+ (ch >= 'A' && ch <= 'F');
+ }
+
+ private boolean foundByCode(String searchText, int pos) {
+ char ch = searchText.charAt(pos);
+ int len = searchText.length();
+ if (isHexChar(ch)) {
+ boolean four = false;
+ int p = pos;
+ for (;;) {
+ four = p - pos >= 3;
+ if (p - pos == 4) {
+ if (showGlyphByCode(searchText, pos, pos + 5) ||
+ (four && showGlyphByCode(searchText, pos, pos + 4))) {
+ return true;
+ }
+ } else if (p + 1 < len && isHexChar(searchText.charAt(p + 1))) {
+ p++;
+ } else {
+ break;
+ }
+ }
+ int b = pos;
+ for (;;) {
+ four = p - b >= 3;
+ if (p - b == 4) {
+ if (showGlyphByCode(searchText, b, b + 5) ||
+ (four && showGlyphByCode(searchText, b + 1, b + 5))) {
+ return true;
+ }
+ } else if (b - 1 >= 0 && isHexChar(searchText.charAt(b - 1))) {
+ b--;
+ } else {
+ if (four) { return showGlyphByCode(searchText, b, b + 4); }
+ break;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void onSearch(String searchText, int pos, String selected) {
+ if (searchText.length() == 0) { return; }
+ if (pos >= searchText.length()) { pos = 0; }
+
+ if (! foundByCode(searchText, pos)) {
+ String s = searchText.substring(pos);
+ if (s.length() == 0) { s = searchText; }
+ try {
+ showGlyph(main.searchChar(s));
+ boolean h = Character.isHighSurrogate(s.charAt(0));
+ searchPanel.setCaretPosition(pos, h ? 2 : 1);
+ } catch (InvalidSearchStringException e) {
+ e.printStackTrace();
+ Logger.getLogger(Main.LOGNAME).warning(e.getMessage());
+ }
+ }
+ }
+
+ private boolean showGlyphByCode(String text, int pos0, int pos1) {
+ boolean ret = false;
+ int c = Integer.parseInt(text.substring(pos0, pos1), 16);
+ try {
+ CharProperty p = main.searchChar(c);
+ int len = p.character.length();
+ if ((len >= 2 && Character.isHighSurrogate(p.character.charAt(0)) &&
+ Character.isLowSurrogate(p.character.charAt(1))) || len <= 1) {
+ showGlyph(main.searchChar(c));
+ searchPanel.setCaretPosition(pos0, pos1 - pos0);
+ ret = true;
+ }
+ } catch (InvalidSearchStringException e) {
+ e.printStackTrace();
+ Logger.getLogger(Main.LOGNAME).warning(e.getMessage());
+ }
+ return ret;
+ }
+
+ private void showGlyph(CharProperty cp) {
+ if (cp != null) {
+ glyphViewer.setText(cp.character);
+ propertyPanel.setCode(cp.code);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+public class HistoryBuffer {
+ private final static int MAX_LENGTH = 100;
+ private final LinkedList<String> buffer = new LinkedList<String>();
+ private ListIterator<String> iterator = null;
+ private boolean prev = true;
+
+ public void add(String buf) {
+ buffer.add(buf);
+ if (buffer.size() >= MAX_LENGTH) { buffer.removeFirst(); }
+ iterator = buffer.listIterator(buffer.size() - 1);
+ prev = true;
+ }
+
+ public String getPrev() {
+ String ret = null;
+ if (! buffer.isEmpty() && iterator.hasPrevious()) {
+ ret = iterator.previous();
+ if (! prev && iterator.hasPrevious()) { ret = iterator.previous(); }
+ prev = true;
+ }
+ return ret;
+ }
+
+ public String getNext() {
+ String ret = null;
+ if (! buffer.isEmpty() && iterator.hasNext()) {
+ ret = iterator.next();
+ if (prev && iterator.hasNext()) { ret = iterator.next(); }
+ prev = false;
+ }
+ return ret;
+ }
+
+ public String getCurrent() {
+ return buffer.isEmpty() ? null : buffer.getLast();
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+public class InvalidSearchStringException extends Exception {
+ private static final long serialVersionUID = -320568592282581589L;
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+import org.mozilla.javascript.ScriptableObject;
+
+public class JsScriptableObject extends ScriptableObject {
+ private static final long serialVersionUID = 2857654503604299849L;
+
+ private JFrame frame = null;
+
+ @Override
+ public String getClassName() {
+ return "JsScriptableObject";
+ }
+
+ public void setFrame(JFrame frame) {
+ this.frame = frame;
+ }
+
+ public void alert(String message) {
+ if (frame != null) {
+ JOptionPane.showMessageDialog(frame, message);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.FileHandler;
+import java.util.logging.Logger;
+
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+public class Main {
+ public static final String LOGNAME = "jp.sourceforge.sawarabifonts.chartool.log";
+
+ public static void main(String[] args) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ Main m = new Main();
+ m.setupLogger();
+ m.showGUI();
+ }
+ });
+ }
+
+ private void showGUI() {
+ JFrame f = new JFrame();
+ setupConfigScript(f);
+ f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ f.add(new MainPanel(this));
+ f.setSize(340, 120);
+ f.setVisible(true);
+ }
+
+ private void setupLogger() {
+ Logger log = Logger.getLogger(LOGNAME);
+ try {
+ File f = new File("log");
+ if (! f.exists()) { f.mkdir(); }
+ log.addHandler(new FileHandler("log/error", 200000, 10, false));
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void setupConfigScript(JFrame frame) {
+ ConfigScript s = ConfigScript.getInstance();
+ if (! s.isLoaded()) {
+ try {
+ s.load();
+ } catch (IOException e) {
+ e.printStackTrace();
+ Logger.getLogger(LOGNAME).warning(e.getMessage());
+ }
+ }
+ s.setFrame(frame);
+ }
+
+ public CharProperty searchChar(String str) throws InvalidSearchStringException {
+ if (str == null || str.length() == 0) { return null; }
+
+ String code = null;
+ String ch = null;
+ char c = str.charAt(0);
+ if (Character.isHighSurrogate(c)) {
+ if (str.length() >= 2) {
+ char c1 = str.charAt(1);
+ int t = ((int) c - 0xd800) * 0x400 + (int) c1 - 0xdc00 + 0x10000;
+ code = Integer.toHexString(t);
+ ch = new String(new char[] { c, c1 });
+ } else {
+ code = fillZero(Integer.toHexString(c), 4);
+ ch = new String(new char[] { c });
+ }
+ } else {
+ code = fillZero(Integer.toHexString(c), 4);
+ ch = new String(new char[] { c });
+ }
+ return new CharProperty(ch, code);
+ }
+
+ public CharProperty searchChar(int code) throws InvalidSearchStringException {
+ String h = Integer.toHexString(code);
+ String s = null;
+ String c = null;
+ if (h.length() >= 5) {
+ int x = code - 0x10000;
+ int c0 = x / 0x400 + 0xd800;
+ int c1 = x % 0x400 + 0xdc00;
+ s = new String(new char[] { (char) c0, (char) c1});
+ c = h;
+ } else {
+ s = new String(new char[] { (char) code });
+ c = fillZero(h, 4);
+ }
+ return new CharProperty(s, c);
+ }
+
+ private String fillZero(String str, int length) {
+ String ret = str;
+ int l = str.length();
+ if (l < length) {
+ StringBuilder sb = new StringBuilder(length);
+ for (int i = 0; length - l - i > 0; i++) { sb.append('0'); }
+ sb.append(str);
+ ret = sb.toString();
+ }
+ return ret;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.border.EmptyBorder;
+
+class MainPanel extends JPanel {
+ private static final long serialVersionUID = 7520947148504510083L;
+
+ public MainPanel(Main m) {
+ GuiController c = new GuiController(m);
+ final SearchPanel sp = new SearchPanel(c);
+ PropertyPanel pp = new PropertyPanel(c);
+ GlyphViewer gv = new GlyphViewer(c);
+
+ EmptyBorder b = new EmptyBorder(10, 10, 10, 10);
+ this.setBorder(b);
+ this.setLayout(new BorderLayout());
+
+ JPanel p = new JPanel();
+ EmptyBorder e = new EmptyBorder(0, 10, 0, 0);
+ p.setBorder(e);
+ p.setLayout(new BorderLayout());
+ p.add(sp, BorderLayout.NORTH);
+ p.add(pp, BorderLayout.CENTER);
+ this.add(p, BorderLayout.CENTER);
+
+ this.add(gv, BorderLayout.WEST);
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() { sp.setFocus(); }
+ });
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+import java.awt.FontMetrics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.util.logging.Logger;
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+public class PropertyPanel extends JPanel {
+ private static final long serialVersionUID = -762290847824180418L;
+
+ private final static int MARGIN_LEFT = 5;
+ private final static int MARGIN_TOP = 5;
+ private final int labelWidth;
+ private final JButton[] buttons;
+ private final JLabel[] properties;
+
+ public PropertyPanel(GuiController controller) {
+ setLayout(null);
+ FontMetrics fm = getFontMetrics(getFont());
+ String[] t = new String[] { "Code: ", "Name: " };
+ buttons = new JButton[t.length];
+ properties = new JLabel[t.length];
+ labelWidth = setPropertyLabels(t, fm);
+ int maxWidth = setPropertyButtons(t, fm, labelWidth);
+ setPropertyLabels(t, fm, maxWidth);
+ addComponentListener(new ComponentAdapter() {
+ @Override public void componentResized(ComponentEvent e) {
+ onResized();
+ }
+ });
+
+ controller.setPropertyPanel(this);
+ }
+
+ public void setCode(String code) {
+ properties[0].setText(code);
+ }
+
+ private void setPropertyLabels(String[] text, FontMetrics fm, int x) {
+ int y = MARGIN_TOP;
+ int h = fm.getHeight();
+ for (int i = 0; i < text.length; i++) {
+ properties[i] = new JLabel();
+ add(properties[i]);
+ properties[i].setLocation(x, y);
+ y += h;
+ }
+ }
+
+ private int setPropertyLabels(String[] text, FontMetrics fm) {
+ int max = 0;
+ int y = MARGIN_TOP;
+ int h = fm.getHeight();
+ for (String t : text) {
+ JLabel n = new JLabel(t);
+ n = new JLabel(t);
+ add(n);
+ n.setLocation(MARGIN_LEFT, y);
+ int w = fm.stringWidth(t);
+ n.setSize(w, h);
+ y += h;
+ if (max < w) max = w;
+ }
+ return max + MARGIN_LEFT;
+ }
+
+ private int setPropertyButtons(String[] text, FontMetrics fm, int x) {
+ int w = fm.stringWidth("S");
+ int h = fm.getHeight();
+ int y = MARGIN_TOP;
+
+ for (int i = 0; i < text.length; i++) {
+ JButton b = new JButton("S");
+ b.setFocusable(false);
+ final int id = i;
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ String t = properties[id].getText();
+ ConfigScript s = ConfigScript.getInstance();
+ try {
+ s.execScript(id, t, e.getModifiers());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ Logger.getLogger(Main.LOGNAME).warning(ex.getMessage());
+ }
+ }
+ });
+ add(b);
+ b.setLocation(x, y);
+ b.setSize(w + 10, h);
+ y += h;
+ buttons[i] = b;
+ }
+ return w;
+ }
+
+ private void onResized() {
+ int y = MARGIN_TOP;
+ int h = getFontMetrics(getFont()).getHeight();
+ int w = getWidth() - labelWidth - buttons[0].getWidth();
+ for (int i = 0; i < properties.length; i++) {
+ properties[i].setLocation(labelWidth, y);
+ properties[i].setSize(w, h);
+ buttons[i].setLocation(labelWidth + w, y);
+ y += h;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
+ *
+ * This program 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
+ * of the License, or any later version.
+ *
+ * This program is distributed in the hope that 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. If not, see <http://www.gnu.org/licenses/>.
+ * ---
+ * Require JDK 1.5 (or later)
+ */
+package jp.sourceforge.sawarabifonts.chartool;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.JButton;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.Keymap;
+import javax.swing.text.TextAction;
+
+public class SearchPanel extends JPanel {
+ private static final long serialVersionUID = 1971690273660748828L;
+
+ private final JTextField searchField;
+ private final HistoryBuffer buffer = new HistoryBuffer();
+ private final SearchFieldPopup popup;
+
+ public SearchPanel(final GuiController controller) {
+ setLayout(new BorderLayout());
+
+ searchField = new JTextField();
+ popup = new SearchFieldPopup();
+ searchField.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.getButton() == MouseEvent.BUTTON3) {
+ popup.show(searchField, e.getX(), e.getY());
+ }
+ }
+ });
+ setupKeymap(controller);
+
+ add(searchField, BorderLayout.CENTER);
+ add(makeSearchButton(), BorderLayout.EAST);
+
+ controller.setSearchPanel(this);
+ }
+
+ private JButton makeSearchButton() {
+ JButton b = new JButton("Search");
+ Keymap k = searchField.getKeymap();
+ Action a = k.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
+ b.addActionListener(a);
+ b.setFocusable(false);
+
+ return b;
+ }
+
+ public void setFocus() {
+ searchField.requestFocusInWindow();
+ }
+
+ public void setCaretPosition(int position, int length) {
+ if (searchField.getText().length() > position) {
+ searchField.setSelectionStart(position);
+ searchField.setSelectionEnd(position + length);
+ } else {
+ searchField.setSelectionStart(0);
+ searchField.setSelectionEnd(length);
+ }
+ }
+
+ private void setupKeymap(final GuiController controller) {
+ Keymap map = JTextComponent.addKeymap("charpalette", searchField.getKeymap());
+ searchField.setKeymap(map);
+
+ setupSearchKeymap(controller);
+ setupHistoryUpKeymap();
+ setupHistoryDownKeymap();
+ }
+
+ private void setupHistoryUpKeymap() {
+ Keymap map = searchField.getKeymap();
+ KeyStroke key0 = KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_MASK);
+ KeyStroke key1 = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
+ Action a = new TextAction("history-up") {
+ private static final long serialVersionUID = 8417010810041845179L;
+ public void actionPerformed(ActionEvent e) {
+ String s = buffer.getPrev();
+ if (s != null) {
+ searchField.setText(s);
+ searchField.setCaretPosition(0);
+ }
+ }
+ };
+ map.addActionForKeyStroke(key0, a);
+ map.addActionForKeyStroke(key1, a);
+ }
+
+ private void setupHistoryDownKeymap() {
+ Keymap map = searchField.getKeymap();
+ KeyStroke key0 = KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_MASK);
+ KeyStroke key1 = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
+ Action a = new TextAction("history-down") {
+ private static final long serialVersionUID = 2292000606648845301L;
+ public void actionPerformed(ActionEvent e) {
+ String s = buffer.getNext();
+ if (s != null) {
+ searchField.setText(s);
+ searchField.setCaretPosition(0);
+ }
+ }
+ };
+ map.addActionForKeyStroke(key0, a);
+ map.addActionForKeyStroke(key1, a);
+ }
+
+ private void setupSearchKeymap(final GuiController controller) {
+ KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
+ Action a = new TextAction("search") {
+ private static final long serialVersionUID = 7670487950463928408L;
+ public void actionPerformed(ActionEvent e) {
+ String st = searchField.getSelectedText();
+ int p = searchField.getCaretPosition();
+ controller.onSearch(searchField.getText(), p, st);
+ String s = buffer.getCurrent();
+ String t = searchField.getText();
+ if (s == null || ! s.equals(t)) {
+ buffer.add(t);
+ }
+ }
+ };
+ searchField.getKeymap().addActionForKeyStroke(key, a);
+ }
+
+
+ class SearchFieldPopup extends JPopupMenu {
+ private static final long serialVersionUID = 5225317856689478836L;
+
+ final JMenuItem cut;
+ final JMenuItem copy;
+ final JMenuItem paste;
+ final JMenuItem clear;
+
+ SearchFieldPopup() {
+ cut = makeMenuItem("Cut", DefaultEditorKit.cutAction);
+ copy = makeMenuItem("Copy", DefaultEditorKit.copyAction);
+ paste = makeMenuItem("Paste", DefaultEditorKit.pasteAction);
+ clear = new JMenuItem(new TextAction("Clear") {
+ private static final long serialVersionUID = 3995545953271258486L;
+ public void actionPerformed(ActionEvent e) {
+ searchField.setText("");
+ }
+ });
+ add(cut);
+ add(copy);
+ add(paste);
+ add(clear);
+ }
+
+ private JMenuItem makeMenuItem(String name, String action) {
+ JMenuItem ret = null;
+ Action a = getActionFromTextField(action);
+ if (a != null) {
+ ret = new JMenuItem();
+ ret.setAction(a);
+ ret.setText(name);
+ }
+ return ret;
+ }
+
+ private Action getActionFromTextField(String name) {
+ ActionMap m = searchField.getActionMap();
+ return m.get(name);
+ }
+
+ private boolean isClipboardContentsString(Clipboard c) {
+ boolean ret = false;
+ try {
+ ret = c.isDataFlavorAvailable(DataFlavor.stringFlavor);
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+ private Clipboard getClipboard() {
+ Toolkit k = Toolkit.getDefaultToolkit();
+ return k.getSystemClipboard();
+ }
+
+ @Override
+ public void show(Component invoker, int x, int y) {
+ boolean s = searchField.getSelectedText() != null;
+ cut.setEnabled(s);
+ copy.setEnabled(s);
+ paste.setEnabled(isClipboardContentsString(getClipboard()));
+ clear.setEnabled(searchField.getText().length() != 0);
+ super.show(invoker, x, y);
+ }
+ }
+
+}