001: package snow.sortabletable;
002:
003: import snow.utils.gui.Icons;
004: import java.net.URL;
005: import snow.utils.NetUtils;
006: import snow.utils.gui.GUIUtils;
007: import java.util.prefs.Preferences;
008: import java.awt.*;
009: import java.awt.event.*;
010: import javax.swing.*;
011: import javax.swing.event.*;
012: import javax.swing.table.*;
013: import java.nio.charset.*;
014: import java.nio.*;
015: import java.util.*;
016: import java.io.*;
017:
018: /**
019: ftp://ftp.unicode.org/Public/UNIDATA/unicodeData.txt
020: */
021:
022: public class UnicodeViewer extends JFrame {
023: final private UnicodeTableModel basicTableModel = new UnicodeTableModel();
024: final private SortableTableModel stm = new SortableTableModel(
025: basicTableModel, 1, true);
026: final private JTable table = new JTable(stm);
027:
028: private final JComboBox charsetCB;
029: private final JComboBox displayLimitCB = new JComboBox(
030: new String[] { "32768", "256", "1024", "2048", "4096",
031: "8192", "16384", "32768", "65536" });
032: private int charDisplayLimit = 8192;
033: StringBuilder allChars = new StringBuilder();
034: final private JDialog previewDialog;
035: final private JTextField previewLabel = new JTextField(20);
036:
037: public UnicodeViewer(boolean standalone) {
038: super ("Unicode viewer");
039: if (standalone) {
040: this .setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
041: }
042:
043: table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
044: stm.installGUI(table);
045: add(new JScrollPane(table), BorderLayout.CENTER);
046:
047: table.setDefaultRenderer(Object.class,
048: new UniversalTableCellRenderer(stm));
049: table.setDefaultRenderer(Integer.class,
050: new UniversalTableCellRenderer(stm));
051:
052: table.setFont(new Font("Dialog", Font.PLAIN, 16));
053: table.setRowHeight(21);
054:
055: JPanel northPan = new JPanel();
056: northPan.setLayout(new BoxLayout(northPan, BoxLayout.Y_AXIS));
057: add(northPan, BorderLayout.NORTH);
058:
059: JPanel optsPan = new JPanel(new FlowLayout(FlowLayout.LEFT, 3,
060: 2));
061: northPan.add(optsPan);
062:
063: MultiSearchPanel sp = new MultiSearchPanel("Filter: ", null,
064: stm);
065: northPan.add(sp);
066:
067: // initialize combobox for charsets
068: charsetCB = new JComboBox(collect_limited_Charsets());
069: optsPan.add(charsetCB);
070: charsetCB.setMaximumRowCount(30);
071: charsetCB.addActionListener(new ActionListener() {
072: public void actionPerformed(ActionEvent ae) {
073: Charset cs = (Charset) charsetCB.getSelectedItem();
074: basicTableModel.setCharset(cs);
075: }
076: });
077:
078: optsPan.add(new JLabel(" up to: "));
079: optsPan.add(displayLimitCB);
080: displayLimitCB.setMaximumRowCount(20);
081: displayLimitCB.addActionListener(new ActionListener() {
082: public void actionPerformed(ActionEvent ae) {
083: String limS = (String) displayLimitCB.getSelectedItem();
084: basicTableModel.setDisplayLimit(Integer.parseInt(limS));
085: }
086: });
087:
088: // only few !
089: //final JComboBox fontCB = new JComboBox(Toolkit.getDefaultToolkit().getFontList());
090: final String[] allFonts = GraphicsEnvironment
091: .getLocalGraphicsEnvironment()
092: .getAvailableFontFamilyNames();
093: final JComboBox fontCB = new JComboBox(allFonts);
094:
095: optsPan.add(fontCB);
096: fontCB.addActionListener(new ActionListener() {
097: public void actionPerformed(ActionEvent ae) {
098: String fn = (String) fontCB.getSelectedItem();
099: table.setFont(new Font(fn, Font.PLAIN, 16));
100: previewLabel.setFont(new Font(fn, Font.PLAIN, 64));
101: }
102: });
103:
104: File udata = new File(Preferences.userRoot().get(
105: "unicodedata_path", "c:/data/unicodedata.txt"));
106: if (!udata.exists()) {
107: udata = askUnicodeDataPath();
108: if (udata.exists()) {
109: Preferences.userRoot().put("unicodedata_path",
110: udata.getAbsolutePath());
111: }
112: }
113:
114: parseUnicodeData(udata);
115:
116: this .basicTableModel.setDisplayLimit(32768);
117: charsetCB.setSelectedIndex(0);
118: fontCB.setSelectedIndex(0);
119:
120: setSize(1000, 600);
121: setLocation(0, 150);
122: setVisible(true);
123:
124: previewDialog = new JDialog(this , "Preview", false);
125: previewDialog
126: .setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
127: previewDialog.setLayout(new BorderLayout());
128: previewDialog.add(previewLabel, BorderLayout.CENTER);
129: previewDialog.setSize(1000, 150);
130: previewDialog.setVisible(true);
131:
132: table.getSelectionModel().addListSelectionListener(
133: new ListSelectionListener() {
134: public void valueChanged(ListSelectionEvent lse) {
135: if (lse.getValueIsAdjusting())
136: return;
137:
138: int sel = table.getSelectedRow();
139: if (sel == -1) {
140: previewLabel.setText("");
141: return;
142: }
143:
144: int pos = stm
145: .getIndexInUnsortedFromTablePos(sel);
146: if (pos == -1) {
147: previewLabel.setText("");
148: return;
149: }
150:
151: String nt = previewLabel.getText()
152: + basicTableModel.getValueAt(pos, 3);
153: if (nt.length() > 20)
154: nt = nt.substring(nt.length() - 20, nt
155: .length());
156: previewLabel.setText(nt);
157: }
158: });
159:
160: //System.out.println((int) Character.MAX_VALUE+" ");
161: } // Constructor
162:
163: private Vector<Charset> collect_limited_Charsets() {
164: SortedMap<String, Charset> sm = Charset.availableCharsets();
165: Vector<Charset> items = new Vector<Charset>(sm.values());
166: for (int i = items.size() - 1; i >= 0; i--) {
167: /*ACCEPT ALL
168: Charset cs = (Charset) items.elementAt(i);
169: if(cs.newEncoder().averageBytesPerChar()!=1.0f)
170: {
171: items.remove(cs);
172: }*/
173: }
174: return items;
175: }
176:
177: final private Hashtable<Integer, String> names = new Hashtable<Integer, String>();
178:
179: public void parseUnicodeData(File file) {
180: FileReader fr = null;
181:
182: try {
183: fr = new FileReader(file);
184: BufferedReader br = new BufferedReader(fr);
185: String line = null;
186: while ((line = br.readLine()) != null) {
187: try {
188: // 0041 ; LATIN CAPITAL LETTER A ; Lu;0;L;;;;;N;;;;0061;
189: StringTokenizer tokenizer = new StringTokenizer(
190: line, ";");
191: String n = tokenizer.nextToken(); // 0041
192: String name = tokenizer.nextToken(); // name
193:
194: int code = Integer.parseInt(n, 16);
195: names.put(code, name);
196: } catch (Exception e) {
197: System.out.println("Cannot parse " + line);
198: }
199: }
200: } catch (Exception e) {
201: e.printStackTrace();
202: } finally {
203: try {
204: fr.close();
205: } catch (Exception e) {
206: }
207: }
208: }
209:
210: /** Offer download.
211: */
212: private File askUnicodeDataPath() {
213: final String[] rep = new String[] { "unicodedata.txt" };
214: final JDialog d = new JDialog(this , "Missing unicodedata file",
215: true); // modal
216: d
217: .add(
218: GUIUtils
219: .createReadOnlyDescriptionArea("The unicodedata.txt file (1MB) is missing."
220: + "\nThis is not mandatory but very useful to search for characters by name,"
221: + "\nfor example the cyrillic capital letter ksi (046e): \u046e."
222: + "\nThe file can be downloaded from the unicode organization homepage."),
223: BorderLayout.CENTER);
224: JPanel cp = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
225: d.add(cp, BorderLayout.SOUTH);
226: JButton cancel = new JButton("cancel", Icons.sharedCross);
227: cp.add(cancel);
228: cancel.addActionListener(new ActionListener() {
229: public void actionPerformed(ActionEvent ae) {
230: d.setVisible(false);
231: }
232: });
233:
234: JButton spec = new JButton("specify location");
235: cp.add(spec);
236: spec.addActionListener(new ActionListener() {
237: public void actionPerformed(ActionEvent ae) {
238: JFileChooser fs = new JFileChooser();
239:
240: fs.setFileSelectionMode(fs.FILES_ONLY);
241: fs
242: .setDialogTitle("Give the location of unicodedata.txt");
243: int resp = fs.showOpenDialog(d);
244: if (resp == JFileChooser.APPROVE_OPTION) {
245: rep[0] = fs.getSelectedFile().getAbsolutePath();
246: }
247: d.setVisible(false);
248: }
249: });
250:
251: JButton down = new JButton("download", Icons.sharedDownArrow);
252: cp.add(down);
253: down.addActionListener(new ActionListener() {
254: public void actionPerformed(ActionEvent ae) {
255:
256: JFileChooser fs = new JFileChooser();
257: fs.setFileSelectionMode(fs.FILES_ONLY);
258: fs
259: .setDialogTitle("Give the location to store unicodedata.txt");
260: int resp = fs.showSaveDialog(d);
261: if (resp == JFileChooser.APPROVE_OPTION) {
262: rep[0] = fs.getSelectedFile().getAbsolutePath();
263: try {
264: URL url = new URL(
265: "http://unicode.org/Public/UNIDATA/UnicodeData.txt");
266: NetUtils.download(url, fs.getSelectedFile());
267: } catch (Exception e) {
268: JOptionPane
269: .showMessageDialog(d,
270: "Cannot download:\n "
271: + e.getMessage(),
272: "Error",
273: JOptionPane.ERROR_MESSAGE);
274: e.printStackTrace();
275: }
276: }
277:
278: d.setVisible(false);
279: }
280: });
281:
282: d.pack();
283: d.setLocationRelativeTo(null);
284: d.setVisible(true);
285:
286: // dummy
287: return new File(rep[0]);
288: }
289:
290: /** Standalone launcher.
291: */
292: public static void main(String[] a) {
293: EventQueue.invokeLater(new Runnable() {
294: public void run() {
295: new UnicodeViewer(true);
296: }
297: });
298: }
299:
300: class UnicodeTableModel extends FineGrainTableModel {
301: private char[] representableCharsetChars = null;
302:
303: String[] COLUMN_NAMES = new String[] { "representable",
304: "hexcode", "intcode", "char", "name", "unicode block",
305: "type" }; //, "lowercase", "uppercase", "titlecase" };
306:
307: int[] COLUMN_PREFERED_SIZES = new int[] { 4, 8, 8, 8, 28, 16,
308: 4, 4, 4, 4 };
309:
310: @Override
311: public int getPreferredColumnWidth(int column) {
312: if (column >= 0 && column < COLUMN_PREFERED_SIZES.length)
313: return COLUMN_PREFERED_SIZES[column];
314: return -1;
315: }
316:
317: @Override
318: public String getColumnName(int col) {
319: return COLUMN_NAMES[col];
320: }
321:
322: @Override
323: public int getColumnAlignment(int column) {
324: if (column == 3 || column == 4)
325: return JLabel.LEFT;
326: return JLabel.CENTER;
327: }
328:
329: public int getColumnCount() {
330: return COLUMN_NAMES.length;
331: }
332:
333: public int getRowCount() {
334: return charDisplayLimit;
335: }
336:
337: public void setDisplayLimit(int lim) {
338: //System.out.println("set limit to "+lim);
339: fireTableModelWillChange();
340: charDisplayLimit = lim;
341: fireTableDataChanged();
342: fireTableModelHasChanged();
343: }
344:
345: public void setCharset(Charset cs) {
346: fireTableModelWillChange();
347: byte[] bb = new byte[256];
348: for (int i = 0; i < 256; i++) {
349: bb[i] = (byte) i;
350: }
351:
352: representableCharsetChars = cs.decode(ByteBuffer.wrap(bb))
353: .toString().toCharArray();
354: Arrays.sort(representableCharsetChars);
355: fireTableDataChanged();
356: fireTableModelHasChanged();
357: }
358:
359: public Object getValueAt(int row, int col) {
360: char c = (char) row;
361:
362: if (col == 0) {
363: if (representableCharsetChars == null)
364: return Boolean.TRUE;
365: int pos = Arrays.binarySearch(
366: representableCharsetChars, c);
367: return Boolean.valueOf(pos >= 0);
368: }
369:
370: if (col == 1) {
371: String hexCode = "000" + Integer.toHexString(row);
372: return hexCode.substring(hexCode.length() - 4, hexCode
373: .length());
374: }
375:
376: if (col == 2)
377: return row;
378:
379: if (col == 3)
380: return "" + c;
381: if (col == 4) {
382: Object n = names.get(row); //Character.toString(c);
383: if (n == null)
384: return "";
385: return "" + n;
386: }
387: if (col == 5) {
388: Character.UnicodeBlock ub = Character.UnicodeBlock
389: .of(c); // in 1.5, can be applied to INT
390: if (ub == null)
391: return "";
392: return "" + ub;
393: }
394:
395: if (col == 6)
396: return Integer.valueOf(Character.getType(c));
397:
398: if (col == 7)
399: return Boolean.valueOf(Character.isLowerCase(c));
400: if (col == 8)
401: return Boolean.valueOf(Character.isUpperCase(c));
402: if (col == 9)
403: return Boolean.valueOf(Character.isTitleCase(c));
404:
405: return "?";
406: }
407:
408: /*
409: public Class getColumnClass(int col)
410: {
411: if(col==0) return Integer.TYPE;
412: return String.class;
413: } */
414: }
415:
416: }
|