/* * 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.project; import java.io.CharConversionException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.Action; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectUtils; import org.netbeans.api.project.SourceGroup; import org.netbeans.api.project.Sources; import org.netbeans.spi.project.ui.support.NodeFactory; import org.netbeans.spi.project.ui.support.NodeList; import org.openide.filesystems.FileObject; import org.openide.nodes.FilterNode; import org.openide.nodes.Node; import org.openide.util.ChangeSupport; import org.openide.util.lookup.Lookups; import org.openide.xml.XMLUtil; /** * * @author Sam Harwell */ @NodeFactory.Registration(projectType=GoProject.GO_PROJECT_ID, position=100) public final class GoSourceNodeFactory implements NodeFactory { // -J-Dorg.tvl.goworks.project.GoSourceNodeFactory.level=FINE private static final Logger LOGGER = Logger.getLogger(GoSourceNodeFactory.class.getName()); public GoSourceNodeFactory() { } @Override public NodeList<?> createNodes(Project p) { Project project = p.getLookup().lookup(Project.class); assert project != null; return new SourcesNodeList(project); } private static class SourcesNodeList implements NodeList<SourceGroupKey>, ChangeListener { private final Project project; private final ChangeSupport changeSupport = new ChangeSupport(this); public SourcesNodeList(Project proj) { project = proj; } @Override public List<SourceGroupKey> keys() { if (this.project.getProjectDirectory() == null || !this.project.getProjectDirectory().isValid()) { return Collections.<SourceGroupKey>emptyList(); } List<SourceGroupKey> result = new ArrayList<>(); final SourceGroup[] groups = getSources().getSourceGroups(GoSourcesImpl.SOURCES_TYPE_GO); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Go source groups: {0}", //NOI18N Arrays.toString(groups)); } for (SourceGroup group : groups) { result.add(new SourceGroupKey(group, true)); } return result; } @Override public void addChangeListener(ChangeListener l) { synchronized (changeSupport) { changeSupport.addChangeListener(l); } } @Override public void removeChangeListener(ChangeListener l) { synchronized (changeSupport) { changeSupport.removeChangeListener(l); } } @Override public Node node(SourceGroupKey key) { return new PackageViewFilterNode(key, project); } @Override public void addNotify() { getSources().addChangeListener(this); } @Override public void removeNotify() { getSources().removeChangeListener(this); } @Override public void stateChanged(ChangeEvent e) { // setKeys(getKeys()); // The caller holds ProjectManager.mutex() read lock SwingUtilities.invokeLater(new Runnable() { @Override public void run() { changeSupport.fireChange(); } }); } private Sources getSources() { return ProjectUtils.getSources(project); } } private static class SourceGroupKey { public final SourceGroup group; public final FileObject fileObject; public final boolean trueSource; SourceGroupKey(SourceGroup group, boolean trueSource) { this.group = group; this.fileObject = group.getRootFolder(); this.trueSource = trueSource; } @Override public int hashCode() { int hash = 5; String disp = this.group.getDisplayName(); hash = 79 * hash + (fileObject != null ? fileObject.hashCode() : 0); hash = 79 * hash + (disp != null ? disp.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (!(obj instanceof SourceGroupKey)) { return false; } else { SourceGroupKey otherKey = (SourceGroupKey) obj; if (fileObject != otherKey.fileObject && (fileObject == null || !fileObject.equals(otherKey.fileObject))) { return false; } String thisDisplayName = this.group.getDisplayName(); String otherDisplayName = otherKey.group.getDisplayName(); boolean oneNull = thisDisplayName == null; boolean twoNull = otherDisplayName == null; if (oneNull != twoNull || !thisDisplayName.equals(otherDisplayName)) { return false; } return true; } } } private static class PackageViewFilterNode extends FilterNode { private final String nodeName; private final Project project; private final boolean trueSource; public PackageViewFilterNode(SourceGroupKey sourceGroupKey, Project project) { super(PackageView.createPackageView(sourceGroupKey.group), null, Lookups.singleton(project)); this.project = project; this.nodeName = "Sources"; trueSource = sourceGroupKey.trueSource; } public @Override Action[] getActions(boolean context) { List<Action> actions = new ArrayList<>(Arrays.asList(super.getActions(context))); if (!trueSource) { // Just take out "New File..." as this would be misleading. Iterator<Action> scan = actions.iterator(); while (scan.hasNext()) { Action a = scan.next(); if (a != null && a.getClass().getName().equals("org.netbeans.modules.project.ui.actions.NewFile$WithSubMenu")) { // NOI18N scan.remove(); } } } return actions.toArray(new Action[actions.size()]); } public @Override String getHtmlDisplayName() { if (trueSource) { return super.getHtmlDisplayName(); } String htmlName = getOriginal().getHtmlDisplayName(); if (htmlName == null) { try { htmlName = XMLUtil.toElementContent(super.getDisplayName()); } catch (CharConversionException x) { return null; // never mind } } return "<font color='!controlShadow'>" + htmlName + "</font>"; // NOI18N } } }