/* * Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC * All rights reserved. * * The source code of this document is proprietary work, and is not licensed for * distribution. For information about licensing, contact Sam Harwell at: * sam@tunnelvisionlabs.com */ package org.tvl.goworks.editor.go.formatting; import java.awt.Component; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.prefs.Preferences; import javax.swing.JCheckBox; import javax.swing.JPanel; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreePath; import org.antlr.netbeans.editor.formatting.BooleanFormatOption; import org.antlr.netbeans.editor.formatting.CategorySupport; import org.netbeans.modules.options.editor.spi.PreferencesCustomizer; import org.openide.util.NbBundle; import org.tvl.goworks.editor.GoEditorKit; /** * * @author Sam Harwell */ @NbBundle.Messages({ "SAMPLE_Spaces=" }) public class FormatSpaces extends JPanel implements TreeCellRenderer, MouseListener, KeyListener { private SpacesCategorySupport scs; private DefaultTreeModel model; private DefaultTreeCellRenderer dr = new DefaultTreeCellRenderer(); private JCheckBox renderer = new JCheckBox(); /** * Creates new form FormatSpaces */ @SuppressWarnings("LeakingThisInConstructor") public FormatSpaces() { initComponents(); model = createModel(); cfgTree.setModel(model); cfgTree.setRootVisible(false); cfgTree.setShowsRootHandles(true); cfgTree.setCellRenderer(this); cfgTree.setEditable(false); cfgTree.addMouseListener(this); cfgTree.addKeyListener(this); dr.setIcon(null); dr.setOpenIcon(null); dr.setClosedIcon(null); DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot(); for (int i = root.getChildCount(); i >= 0; i--) { cfgTree.expandRow(i); } } public static PreferencesCustomizer.Factory getController() { return new PreferencesCustomizer.Factory() { @Override public PreferencesCustomizer create(Preferences preferences) { return new SpacesCategorySupport(preferences, new FormatSpaces()); } }; } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; jScrollPane1 = new javax.swing.JScrollPane(); cfgTree = new javax.swing.JTree(); setName(org.openide.util.NbBundle.getMessage(FormatSpaces.class, "LBL_Spaces")); // NOI18N setOpaque(false); setLayout(new java.awt.GridBagLayout()); cfgTree.setRootVisible(false); jScrollPane1.setViewportView(cfgTree); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(jScrollPane1, gridBagConstraints); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTree cfgTree; private javax.swing.JScrollPane jScrollPane1; // End of variables declaration//GEN-END:variables @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { renderer.setBackground(selected ? dr.getBackgroundSelectionColor() : dr.getBackgroundNonSelectionColor()); renderer.setForeground(selected ? dr.getTextSelectionColor() : dr.getTextNonSelectionColor()); renderer.setEnabled(true); Object data = ((DefaultMutableTreeNode)value).getUserObject(); if (data instanceof Item) { Item item = ((Item)data); if (((DefaultMutableTreeNode)value).getAllowsChildren()) { Component component = dr.getTreeCellRendererComponent(tree, value, leaf, expanded, leaf, row, hasFocus); return component; } else { renderer.setText(item.displayName); renderer.setSelected(item.value); } } else { Component component = dr.getTreeCellRendererComponent(tree, value, leaf, expanded, leaf, row, hasFocus); return component; } return renderer; } @Override public void mouseClicked(MouseEvent e) { Point p = e.getPoint(); TreePath path = cfgTree.getPathForLocation(e.getPoint().x, e.getPoint().y); if (path != null) { Rectangle r = cfgTree.getPathBounds(path); if (r != null && r.contains(p)) { toggle(path); } } } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE || e.getKeyCode() == KeyEvent.VK_ENTER) { if (e.getSource() instanceof JTree) { JTree tree = (JTree)e.getSource(); TreePath path = tree.getSelectionPath(); if (toggle(path)) { e.consume(); } } } } @Override public void keyReleased(KeyEvent e) { } @NbBundle.Messages({ "LBL_BeforeKeywords=Before Keywords", "LBL_BeforeParentheses=Before Parentheses", "LBL_AroundOperators=Around Operators", "LBL_BeforeLeftBraces=Before Left Braces", "LBL_WithinParentheses=Within Parentheses", "LBL_Other=Other", "LBL_spaceBeforeWhile=\"while\"", "LBL_spaceBeforeElse=\"else\"", "LBL_spaceBeforeParensMethodDeclaration=Method Declaration", "LBL_spaceBeforeParensMethodCall=Method Call", "LBL_spaceBeforeParensIf=\"if\"", "LBL_spaceBeforeParensFor=\"for\"", "LBL_spaceBeforeParensWhile=\"while\"", "LBL_spaceBeforeParensSwitch=\"switch\"", "LBL_spaceAroundUnaryOperators=Unary Operators", "LBL_spaceAroundBinaryOperators=Binary Operators", "LBL_spaceAroundTernaryOperators=Ternary Operators", "LBL_spaceAroundAssignmentOperators=Assignment Operators", "LBL_spaceBeforeBraceTypeDeclaration=Type Declaration", "LBL_spaceBeforeBraceMethodDeclaration=Method Declaration", "LBL_spaceBeforeBraceIf=\"if\"", "LBL_spaceBeforeBraceElse=\"else\"", "LBL_spaceBeforeBraceFor=\"for\"", "LBL_spaceBeforeBraceDo=\"do\"", "LBL_spaceBeforeBraceWhile=\"while\"", "LBL_spaceBeforeBraceSwitch=\"switch\"", "LBL_spaceBeforeBraceStaticInitializer=Static Initializer", "LBL_spaceBeforeBraceArrayInitializer=Array Initializer", "LBL_spaceInParens=Parentheses", "LBL_spaceInParensMethodDeclaration=Method Declaration", "LBL_spaceInParensMethodCall=Method Call", "LBL_spaceInParensIf=\"if\"", "LBL_spaceInParensFor=\"for\"", "LBL_spaceInParensWhile=\"while\"", "LBL_spaceInParensSwitch=\"switch\"", "LBL_spaceInParensTypeCast=Type Cast", "LBL_spaceInParensBraces=Braces", "LBL_spaceInParensArrayInitBrackets=Array Initializer Brackets", "LBL_spaceBeforeComma=Before Comma", "LBL_spaceAfterComma=After Comma", "LBL_spaceBeforeSemicolon=Before Semicolon", "LBL_spaceAfterSemicolon=After Semicolon", "LBL_spaceBeforeColon=Before Colon", "LBL_spaceAfterColon=After Colon", "LBL_spaceAfterTypeCast=After Type Cast", }) private DefaultTreeModel createModel() { Item[] categories = new Item[] { new Item("BeforeKeywords", new Item(GoFormatOptions.spaceBeforeWhile), new Item(GoFormatOptions.spaceBeforeElse)), new Item("BeforeParentheses", new Item(GoFormatOptions.spaceBeforeParensMethodDeclaration), new Item(GoFormatOptions.spaceBeforeParensMethodCall), new Item(GoFormatOptions.spaceBeforeParensIf), new Item(GoFormatOptions.spaceBeforeParensFor), new Item(GoFormatOptions.spaceBeforeParensWhile), new Item(GoFormatOptions.spaceBeforeParensSwitch)), new Item("AroundOperators", new Item(GoFormatOptions.spaceAroundUnaryOperators), new Item(GoFormatOptions.spaceAroundBinaryOperators), new Item(GoFormatOptions.spaceAroundTernaryOperators), new Item(GoFormatOptions.spaceAroundAssignmentOperators)), new Item("BeforeLeftBraces", new Item(GoFormatOptions.spaceBeforeBraceTypeDeclaration), new Item(GoFormatOptions.spaceBeforeBraceMethodDeclaration), new Item(GoFormatOptions.spaceBeforeBraceIf), new Item(GoFormatOptions.spaceBeforeBraceElse), new Item(GoFormatOptions.spaceBeforeBraceFor), new Item(GoFormatOptions.spaceBeforeBraceDo), new Item(GoFormatOptions.spaceBeforeBraceWhile), new Item(GoFormatOptions.spaceBeforeBraceSwitch), new Item(GoFormatOptions.spaceBeforeBraceStaticInitializer), new Item(GoFormatOptions.spaceBeforeBraceArrayInitializer)), new Item("WithinParentheses", new Item(GoFormatOptions.spaceInParens), new Item(GoFormatOptions.spaceInParensMethodDeclaration), new Item(GoFormatOptions.spaceInParensMethodCall), new Item(GoFormatOptions.spaceInParensIf), new Item(GoFormatOptions.spaceInParensFor), new Item(GoFormatOptions.spaceInParensWhile), new Item(GoFormatOptions.spaceInParensSwitch), new Item(GoFormatOptions.spaceInParensTypeCast), new Item(GoFormatOptions.spaceInParensBraces), new Item(GoFormatOptions.spaceInParensArrayInitBrackets)), new Item("Other", new Item(GoFormatOptions.spaceBeforeComma), new Item(GoFormatOptions.spaceAfterComma), new Item(GoFormatOptions.spaceBeforeSemicolon), new Item(GoFormatOptions.spaceAfterSemicolon), new Item(GoFormatOptions.spaceBeforeColon), new Item(GoFormatOptions.spaceAfterColon), new Item(GoFormatOptions.spaceAfterTypeCast)), }; DefaultMutableTreeNode root = new DefaultMutableTreeNode("root", true); DefaultTreeModel dtm = new DefaultTreeModel(root); for (Item item : categories) { DefaultMutableTreeNode cn = new DefaultMutableTreeNode(item, true); root.add(cn); for (Item si : item.items) { DefaultMutableTreeNode in = new DefaultMutableTreeNode(si, false); cn.add(in); } } return dtm; } private boolean toggle(TreePath treePath) { if (treePath == null) { return false; } Object o = ((DefaultMutableTreeNode)treePath.getLastPathComponent()).getUserObject(); DefaultTreeModel dtm = (DefaultTreeModel)cfgTree.getModel(); DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath.getLastPathComponent(); if ( o instanceof Item ) { Item item = (Item)o; if ( node.getAllowsChildren() ) { return false; } item.value = !item.value; dtm.nodeChanged(node); dtm.nodeChanged(node.getParent()); scs.notifyChanged(); } return false; } // Innerclasses ------------------------------------------------------------ private static class Item { private static final Item[] EmptyItems = new Item[0]; BooleanFormatOption id; String displayName; boolean value; Item[] items; public Item(String category, Item... items) { this.id = null; this.items = items; this.displayName = NbBundle.getMessage(FormatSpaces.class, "LBL_" + category); // NOI18N } public Item(BooleanFormatOption option) { this.id = option; this.items = EmptyItems; this.displayName = NbBundle.getMessage(FormatSpaces.class, "LBL_" + option.getName()); // NOI18N } @Override public String toString() { return displayName; } } private static final class SpacesCategorySupport extends CategorySupport { @SuppressWarnings("LeakingThisInConstructor") public SpacesCategorySupport(Preferences preferences, FormatSpaces panel) { super(GoEditorKit.GO_MIME_TYPE, preferences, "spaces", panel, Bundle.SAMPLE_Spaces(), GoPreviewFormatter.INSTANCE); //NOI18N panel.scs = this; } @Override public void notifyChanged() { super.notifyChanged(); } @Override protected void addListeners() { // Should not do anything } @Override protected void loadFrom(Preferences preferences) { for (Item item : getAllItems()) { item.value = item.id.getValue(preferences); } } @Override protected void storeTo(Preferences preferences) { for (Item item : getAllItems()) { boolean df = item.id.getDefaultValue(); if (df == item.value) preferences.remove(item.id.getName()); else preferences.putBoolean(item.id.getName(), item.value); } } private List<Item> getAllItems() { List<Item> result = new LinkedList<>(); DefaultMutableTreeNode root = (DefaultMutableTreeNode) ((FormatSpaces) panel).model.getRoot(); @SuppressWarnings("rawtypes") Enumeration children = root.depthFirstEnumeration(); while( children.hasMoreElements() ) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) children.nextElement(); Object o = node.getUserObject(); if (o instanceof Item) { Item item = (Item) o; if ( item.id != null ) { result.add( item ); } } } return result; } } }