/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package edu.wpi.first.tableviewer; import edu.wpi.first.tableviewer.TableEntryData.EntryType; import edu.wpi.first.tableviewer.dialog.AbstractAddDialog; import edu.wpi.first.wpilibj.networktables2.NetworkTableNode; import edu.wpi.first.wpilibj.tables.ITable; import edu.wpi.first.wpilibj.tables.ITableListener; import java.awt.BorderLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.prefs.Preferences; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.netbeans.swing.outline.OutlineModel; public class OutlineFrame extends JFrame implements ITableListener { private final Outline outline; private final BranchNode rootBranch; private final NetworkTableNode node; private final boolean showMetadata; private final Preferences prefs = Preferences.userNodeForPackage(getClass()); public OutlineFrame(String title, NetworkTableNode node, boolean showMetadata) { this.node = node; this.showMetadata = showMetadata; setTitle(title); setDefaultCloseOperation(EXIT_ON_CLOSE); rootBranch = new BranchNode(node, "", "Root"); DefaultTreeModel outlineTreeModel = new DefaultTreeModel(rootBranch); OutlineModel outlineModel = DefaultOutlineModel.createOutlineModel( outlineTreeModel, new NetworkTableRowModel(), true, "Key"); outline = new Outline(); outline.setModel(outlineModel); AbstractAddDialog.setOutline(outline); AbstractTreeNode.setOutline(outline); AbstractTreeNode.setTreeModel(outlineTreeModel); outline.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { TreePath path = outline.getClosestPathForLocation(e.getX(), e.getY()); AbstractTreeNode node = (AbstractTreeNode) path.getLastPathComponent(); if (e.getClickCount() == 2) { // toggle boolean value // commented out because the deselection makes double clicking // difficult and annoying to do accurately // if (node instanceof LeafNode) { // LeafNode l = (LeafNode) node; // if (l.getData().getType() == EntryType.BOOLEAN) { // l.getData().setValue(!(boolean) l.getData().getValue()); // } // } } else if (SwingUtilities.isRightMouseButton(e)) { // create a menu if (node instanceof BranchNode) { ((BranchNode) node).getMenu(path).show(outline, e.getX(), e.getY()); } } } }); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { prefs.putInt("WindowX", getX()); prefs.putInt("WindowY", getY()); prefs.putInt("Width", getWidth()); prefs.putInt("Height", getHeight()); } @Override public void windowOpened(WindowEvent e) { // default to top-left corner setLocation(prefs.getInt("WindowX", 0), prefs.getInt("WindowY", 0)); // default to 600x400 setSize(prefs.getInt("Width", 600), prefs.getInt("Height", 400)); } }); JScrollPane scrollPane = new JScrollPane(); scrollPane.setViewportView(outline); add(scrollPane, BorderLayout.CENTER); node.addTableListener(this, true); } @Override public void valueChanged(ITable source, final String key, final Object value, boolean isNew) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { getBranchesToEntry(key, value); } }); } private void getBranchesToEntry(final String fullKey, Object value) { // a list of all the subtable names leading up to the entry in the given key // this splits by / and removes empty // elements CustomList subTableNames = splitDiscardingEmpty(fullKey, "/"); String key = ""; AbstractTreeNode currentNode = rootBranch, parentNode; for (String name : subTableNames) { parentNode = currentNode; currentNode = currentNode.get(name); key += "/" + name; if (subTableNames.getLast() == name) { // leaf if (currentNode == null) { currentNode = new LeafNode(node, key, new TableEntryData(name, value)); if (currentNode.data.isMetadata() && !showMetadata) { // don't show metadata directly // instead, show the value in the branch's "Type" field parentNode.data.setType(EntryType.getEntryType(currentNode.data.getValue().toString())); } else { parentNode.add(currentNode); TreePath path = new TreePath(currentNode.getPath()); outline.expandPath(path); } } else { ((LeafNode) currentNode).updateValue(value); } } else if (currentNode == null) { currentNode = new BranchNode(node, key, name); parentNode.add(currentNode); } } } private CustomList splitDiscardingEmpty(String str, String separator) { CustomList results = new CustomList<>(); for (String string : str.split(separator)) { if (string.length() > 0) { results.add(string); } } return results; } private class CustomList extends ArrayList { public E getLast() { return get(size() - 1); } } }