Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package org.shaman.rpg.editor.dbviewer; import java.awt.Dimension; import java.beans.*; import java.io.File; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JScrollPane; import javax.swing.JTextArea; import org.apache.commons.lang.ArrayUtils; import org.jdesktop.swingx.treetable.AbstractTreeTableModel; import org.jdesktop.swingx.treetable.TreeTableModel; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.shaman.database.*; import org.shaman.database.io.IOFactory; import org.shaman.database.io.Input; import org.shaman.rpg.editor.utilities.dataobject.DatabaseDataObject; /** * This class loads a database data object and creates a {@link TreeTableModel} * from that. * @author Sebastian Weiss */ public class TreeTableModelFactory { private static final Logger LOG = Logger.getLogger(TreeTableModelFactory.class.getName()); private TreeTableModelFactory() { } /** * Columns are: * Tree, Name, Class, Value. */ public static final int COLUMN_COUNT = 4; public static final String[] COLUMN_NAMES = { NbBundle.getMessage(TreeTableModelFactory.class, "DatabaseTable.Header.Tree"), NbBundle.getMessage(TreeTableModelFactory.class, "DatabaseTable.Header.Name"), NbBundle.getMessage(TreeTableModelFactory.class, "DatabaseTable.Header.Class"), NbBundle.getMessage(TreeTableModelFactory.class, "DatabaseTable.Header.Value") }; /** * Loads the database and creates a tree table model that displays the contents. * This method might take a while, so call this method in a worker thread. * @param obj the database to load * @return the tree table model */ public static <T extends Record> TreeTableModel createModel(DatabaseDataObject<T> obj) { //load database Database<T> db; File file = FileUtil.toFile(obj.getPrimaryFile()); try (Input in = IOFactory.createFileInput(file)) { ErrorCollector collector = new ErrorCollector(); db = new Database<>(in, collector); if (!collector.entries.isEmpty()) { //contains errors showErrors(collector); } } catch (Exception e) { Exceptions.printStackTrace(e); return new ErrorModel(e); } return new DatabaseTableModel(db.getRoot()); } private static void showErrors(ErrorCollector collector) { JTextArea area = new JTextArea(); for (Map.Entry<String, Integer> e : collector.entries.entrySet()) { area.append(e.getValue().toString()); area.append("x: "); area.append(e.getKey()); area.append("\n"); } JScrollPane pane = new JScrollPane(area); pane.setMinimumSize(new Dimension(200, 50)); DialogDisplayer.getDefault() .notifyLater(new NotifyDescriptor.Message(pane, NotifyDescriptor.ERROR_MESSAGE)); } private static class ErrorModel extends AbstractTreeTableModel { private final Exception e; private ErrorModel(Exception e) { super("unable to load database"); this.e = e; } @Override public int getColumnCount() { return 1; } @Override public Object getValueAt(Object o, int i) { return "unable to load database: " + e.getLocalizedMessage(); } @Override public Object getChild(Object parent, int index) { return null; } @Override public int getChildCount(Object parent) { return 0; } @Override public int getIndexOfChild(Object parent, Object child) { return -1; } @Override public String getColumnName(int column) { return "Error"; } } private static class Parameter { private final Record record; private final RecordTemplate.Attribute attribute; private Parameter(Record record, RecordTemplate.Attribute attribute) { this.record = record; this.attribute = attribute; } } private static class NullItem { private final String name; private final String id; private NullItem(String name, String id) { this.name = name; this.id = id; } } private static class DatabaseTableModel extends AbstractTreeTableModel { private DatabaseTableModel(Record root) { super(root); } @Override public int getColumnCount() { return COLUMN_COUNT; } @Override public Object getValueAt(Object o, int i) { if (o instanceof Record) { Record rec = (Record) o; //it is a record switch (i) { case 0: return o.getClass().getSimpleName(); case 1: return DatabaseSystem.intToName(DatabaseSystem.getRecordTemplate(rec.getClass()).getRecordID()); case 2: return rec.getClass().getName(); case 3: return o.toString(); } } else if (o instanceof Parameter) { //it is a parameter Parameter p = (Parameter) o; switch (i) { case 0: Method getter = p.attribute.getGetter(); return getFieldName(getter); case 1: return DatabaseSystem.intToName(p.attribute.getID()); case 2: return p.attribute.getGetter().getReturnType().getName(); case 3: return getParameterValue(p.attribute.getValue(p.record)); } } else if (o instanceof NullItem) { NullItem ei = (NullItem) o; switch (i) { case 0: return ei.name; case 1: return ei.id; case 2: return ""; case 3: return ""; } } throw new IllegalArgumentException("illegal column index " + i + " for node " + o); } private String getParameterValue(Object value) { if (value == null) { return "null"; } else if (value.getClass().isArray()) { return ArrayUtils.toString(value); } else if (value instanceof ByteBuffer) { ByteBuffer buf = (ByteBuffer) value; StringBuilder str = new StringBuilder(buf.capacity()); buf.rewind(); boolean b = false; while (buf.hasRemaining()) { if (b) str.append(","); b = true; str.append(String.format("%02x", buf.get())); } return str.toString(); } else { return String.valueOf(value); } } @Override public boolean isLeaf(Object node) { return (node instanceof Parameter); } @Override public Object getChild(Object parent, int index) { if (parent instanceof Parameter) { throw new IllegalArgumentException("there are no children for a leaf node"); } Record rec = (Record) parent; RecordTemplate template = DatabaseSystem.getRecordTemplate(rec.getClass()); List<? extends RecordTemplate.Attribute> attributes = template.getAttributes(); if (index < attributes.size()) { return new Parameter(rec, attributes.get(index)); } else { Group g = (Group) rec; Record sg = g.getSubgroup(index - attributes.size()); if (sg == null) { return new NullItem("null group", "index: " + (index - attributes.size())); } else { return sg; } } } @Override public int getChildCount(Object parent) { if (parent instanceof Parameter) { return 0; } Record rec = (Record) parent; RecordTemplate template = DatabaseSystem.getRecordTemplate(rec.getClass()); int count = template.getAttributes().size(); if (rec instanceof Group) { count += ((Group) rec).getSubgroupCount(); } return count; } @Override public int getIndexOfChild(Object parent, Object child) { if (parent == null || child == null || !(parent instanceof Record)) { return -1; } Record rec = (Record) parent; RecordTemplate template = DatabaseSystem.getRecordTemplate(rec.getClass()); List<? extends RecordTemplate.Attribute> attributes = template.getAttributes(); int index = attributes.indexOf(child); if (index >= 0) { return index; } else { if (rec instanceof Group) { Group g = (Group) rec; Record[] subgroups = g.getAllSubgroups(); index = ArrayUtils.indexOf(subgroups, child); return index; } else { return -1; } } } @Override public boolean isCellEditable(Object node, int column) { return false; } @Override public Class<?> getColumnClass(int column) { return String.class; } @Override public String getColumnName(int column) { return COLUMN_NAMES[column]; } } private static String getFieldName(Method method) { try { Class<?> clazz = method.getDeclaringClass(); BeanInfo info = Introspector.getBeanInfo(clazz); PropertyDescriptor[] props = info.getPropertyDescriptors(); for (PropertyDescriptor pd : props) { if (method.equals(pd.getWriteMethod()) || method.equals(pd.getReadMethod())) { // System.out.println(pd.getDisplayName()); return pd.getName(); } } } catch (Exception e) { LOG.log(Level.FINE, "unable to get field name for method " + method, e); } return method.getName(); } }