--- apisupport.ant/nbproject/project.xml
+++ apisupport.ant/nbproject/project.xml
@@ -155,6 +155,24 @@
+ org.netbeans.modules.java.hints.legacy.spi
+
+
+
+ 1
+ 1.7
+
+
+
+ org.netbeans.modules.java.lexer
+
+
+
+ 1
+ 1.24
+
+
+
org.netbeans.modules.java.platform
@@ -187,6 +205,15 @@
+ org.netbeans.modules.lexer
+
+
+
+ 2
+ 1.51
+
+
+
org.netbeans.modules.project.ant
@@ -240,6 +267,15 @@
+ org.netbeans.spi.editor.hints
+
+
+
+ 0
+ 1.30
+
+
+
org.netbeans.swing.outline
--- apisupport.ant/src/org/netbeans/modules/apisupport/project/java/hints/errors/SearchModuleDependency.java
+++ apisupport.ant/src/org/netbeans/modules/apisupport/project/java/hints/errors/SearchModuleDependency.java
@@ -0,0 +1,415 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ * theanuradha@netbeans.org
+ * markiewb@netbeans.org
+ *
+ * Portions Copyrighted 2008 Sun Microsystems, Inc.
+ * Portions Copyrighted 2013 markiewb@netbeans.org
+ */
+package org.netbeans.modules.apisupport.project.java.hints.errors;
+
+import com.sun.source.tree.ArrayTypeTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.NewArrayTree;
+import com.sun.source.tree.NewClassTree;
+import com.sun.source.tree.ParameterizedTypeTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.TreePath;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.lang.model.element.Name;
+import org.netbeans.api.java.lexer.JavaTokenId;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.lexer.Token;
+import org.netbeans.api.lexer.TokenHierarchy;
+import org.netbeans.api.lexer.TokenSequence;
+import org.netbeans.api.progress.ProgressUtils;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.modules.apisupport.project.ModuleDependency;
+import org.netbeans.modules.apisupport.project.NbModuleProject;
+import org.netbeans.modules.apisupport.project.ProjectXMLManager;
+import org.netbeans.modules.apisupport.project.ui.customizer.AddModulePanel;
+import org.netbeans.modules.apisupport.project.ui.customizer.SingleModuleProperties;
+import org.netbeans.modules.java.hints.spi.ErrorRule.Data;
+import org.netbeans.spi.editor.hints.ChangeInfo;
+import org.netbeans.spi.editor.hints.EnhancedFix;
+import org.netbeans.spi.editor.hints.Fix;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
+
+/**
+ * Fixable hint for an unresolved class which opens the NetBeans plattform
+ * module dependency dialog. The dialog will be prefilled with the name of the
+ * unresolved class.
+ *
+ * - Hint activation code taken from
+ * {@link org.netbeans.modules.maven.hints.errors.SearchClassDependencyInRepo}
+ * - Dialog opening code taken from
+ * {@link org.netbeans.modules.apisupport.project.ui.LibrariesNode.AddModuleDependencyAction}
+ *
+ *
+ * @author Anuradha G
+ * @author markiewb
+ */
+
+@Messages({
+ "LBL_Module_Dependency_Search_DisplayName=Add Module Dependency",
+ "# {0} - name of unknown symbol",
+ "FIX_Module_Dependency_Search=Search Module Dependency for {0}",
+ "FIX_Module_Dependency_UpdatingDependencies=Update dependencies"
+})
+public class SearchModuleDependency implements org.netbeans.modules.java.hints.spi.ErrorRule {
+
+ private AtomicBoolean cancel = new AtomicBoolean(false);
+
+ public SearchModuleDependency() {
+ }
+
+ @Override
+ public Set getCodes() {
+ return new HashSet(Arrays.asList(
+ "compiler.err.cant.resolve",//NOI18N
+ "compiler.err.cant.resolve.location",//NOI18N
+ "compiler.err.doesnt.exist",//NOI18N
+ "compiler.err.not.stmt"));//NOI18N
+
+ }
+
+ private boolean isHintEnabled() {
+ //TODO provide an option to disable this hint
+ return true;
+ }
+
+ @Override
+ public List run(final CompilationInfo info, String diagnosticKey,
+ final int offset, TreePath treePath, Data data) {
+ cancel.set(false);
+ if (!isHintEnabled()) {
+ return Collections.emptyList();
+ }
+ //copyed from ImportClass
+ int errorPosition = offset + 1; //TODO: +1 required to work OK, rethink
+
+ if (errorPosition == (-1)) {
+
+ return Collections.emptyList();
+ }
+ //copyed from ImportClass-end
+ FileObject fileObject = info.getFileObject();
+ Project project = FileOwnerQuery.getOwner(fileObject);
+ if (project == null) {
+ return Collections.emptyList();
+ }
+ NbModuleProject nbModuleProject = project.getLookup().lookup(NbModuleProject.class);
+ if (nbModuleProject == null) {
+ return Collections.emptyList();
+ }
+
+ //copyed from ImportClass
+ TreePath path = info.getTreeUtilities().pathFor(errorPosition);
+ if (path.getParentPath() == null) {
+ return Collections.emptyList();
+ }
+
+ Tree leaf = path.getParentPath().getLeaf();
+
+ switch (leaf.getKind()) {
+ case METHOD_INVOCATION: {
+ MethodInvocationTree mit = (MethodInvocationTree) leaf;
+
+ if (!mit.getTypeArguments().contains(path.getLeaf())) {
+ return Collections.emptyList();
+ }
+ }
+ //genaric handling
+
+ case PARAMETERIZED_TYPE: {
+ leaf = path.getParentPath().getParentPath().getLeaf();
+ }
+ break;
+ case ARRAY_TYPE: {
+ leaf = path.getParentPath().getParentPath().getLeaf();
+ }
+ break;
+ }
+ switch (leaf.getKind()) {
+ case VARIABLE: {
+ Name typeName = null;
+ VariableTree variableTree = (VariableTree) leaf;
+ if (variableTree.getType() != null) {
+ switch (variableTree.getType().getKind()) {
+ case IDENTIFIER: {
+ typeName = ((IdentifierTree) variableTree.getType()).getName();
+ }
+ break;
+ case PARAMETERIZED_TYPE: {
+ ParameterizedTypeTree ptt = ((ParameterizedTypeTree) variableTree.getType());
+ if (ptt.getType() != null && ptt.getType().getKind() == Kind.IDENTIFIER) {
+ typeName = ((IdentifierTree) ptt.getType()).getName();
+ }
+ }
+ break;
+ case ARRAY_TYPE: {
+ ArrayTypeTree ptt = ((ArrayTypeTree) variableTree.getType());
+ if (ptt.getType() != null && ptt.getType().getKind() == Kind.IDENTIFIER) {
+ typeName = ((IdentifierTree) ptt.getType()).getName();
+ }
+ }
+ break;
+
+ }
+ }
+
+ ExpressionTree initializer = variableTree.getInitializer();
+ if (typeName != null && initializer != null) {
+
+ Name itName = null;
+ switch (initializer.getKind()) {
+ case NEW_CLASS: {
+ ExpressionTree identifier;
+ NewClassTree classTree = (NewClassTree) initializer;
+ identifier = classTree.getIdentifier();
+
+ if (identifier != null) {
+
+ switch (identifier.getKind()) {
+ case IDENTIFIER:
+ itName = ((IdentifierTree) identifier).getName();
+ break;
+ case PARAMETERIZED_TYPE: {
+
+ ParameterizedTypeTree ptt = ((ParameterizedTypeTree) identifier);
+ if (ptt.getType() != null && ptt.getType().getKind() == Kind.IDENTIFIER) {
+ itName = ((IdentifierTree) ptt.getType()).getName();
+ }
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case NEW_ARRAY: {
+ NewArrayTree arrayTree = (NewArrayTree) initializer;
+ Tree type = arrayTree.getType();
+ if (type != null) {
+ if (type.getKind().equals(Kind.IDENTIFIER)) {
+ itName = ((IdentifierTree) type).getName();
+ }
+ }
+ }
+ break;
+ }
+
+ if (typeName.equals(itName)) {
+ return Collections.emptyList();
+ }
+ }
+ }
+ break;
+
+ }
+
+ String simpleOrQualifiedName = null;
+
+ // XXX somewhat crude; is there a simpler way?
+ TreePath p = path;
+ while (p != null) {
+ TreePath parent = p.getParentPath();
+ if (parent == null) {
+ break;
+ }
+ Kind parentKind = parent.getLeaf().getKind();
+ if (parentKind == Kind.IMPORT) {
+ simpleOrQualifiedName = p.getLeaf().toString();
+ break;
+ } else if (parentKind == Kind.MEMBER_SELECT || parentKind == Kind.IDENTIFIER) {
+ p = parent;
+ } else {
+ break;
+ }
+ }
+
+ if (simpleOrQualifiedName == null) {
+ try {
+ Token> ident = findUnresolvedElementToken(info, offset);
+ if (ident == null) {
+ return Collections.emptyList();
+ }
+ simpleOrQualifiedName = ident.text().toString();
+ } catch (IOException e) {
+ Exceptions.printStackTrace(e);
+ return Collections.emptyList();
+ }
+ }
+
+ //copyed from ImportClass-end
+ if (cancel.get()) {
+ return Collections.emptyList();
+ }
+ //#212331 star static imports need to be stripped of the .* part.
+ if (simpleOrQualifiedName.endsWith(".*")) {
+ simpleOrQualifiedName = simpleOrQualifiedName.substring(0, simpleOrQualifiedName.length() - ".*".length());
+ }
+
+ List fixes = new ArrayList();
+ fixes.add(new OpenDependencyDialogFix(nbModuleProject, simpleOrQualifiedName));
+ return fixes;
+ }
+
+ //copyed from ImportClass
+ private static Token findUnresolvedElementToken(CompilationInfo info, int offset) throws IOException {
+ TokenHierarchy> th = info.getTokenHierarchy();
+ TokenSequence ts = th.tokenSequence(JavaTokenId.language());
+
+ if (ts == null) {
+ return null;
+ }
+
+ ts.move(offset);
+ if (ts.moveNext()) {
+ Token t = ts.token();
+
+ if (t.id() == JavaTokenId.DOT) {
+ ts.moveNext();
+ t = ts.token();
+ } else {
+ if (t.id() == JavaTokenId.LT) {
+ ts.moveNext();
+ t = ts.token();
+ } else {
+ if (t.id() == JavaTokenId.NEW) {
+ boolean cont = ts.moveNext();
+
+ while (cont && ts.token().id() == JavaTokenId.WHITESPACE) {
+ cont = ts.moveNext();
+ }
+
+ if (!cont) {
+ return null;
+ }
+ t = ts.token();
+ }
+ }
+ }
+
+ if (t.id() == JavaTokenId.IDENTIFIER) {
+ return ts.offsetToken();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getId() {
+ return "NBM_MISSING_CLASS_NBMANT";//NOI18N
+ }
+
+
+ @Override
+ public String getDisplayName() {
+ return NbBundle.getMessage(SearchModuleDependency.class, "LBL_Module_Dependency_Search_DisplayName");
+ }
+
+ @Override
+ public void cancel() {
+ //cancel task
+ cancel.set(true);
+ }
+
+ static final class OpenDependencyDialogFix implements EnhancedFix {
+
+ private NbModuleProject project;
+ private String clazz;
+
+ public OpenDependencyDialogFix(NbModuleProject project, String clazz) {
+ this.project = project;
+ this.clazz = clazz;
+ }
+
+ @Override
+ public CharSequence getSortText() {
+ return getText();
+ }
+
+ @Override
+ public String getText() {
+ return NbBundle.getMessage(OpenDependencyDialogFix.class, "FIX_Module_Dependency_Search", clazz);
+ }
+
+ @Override
+ public ChangeInfo implement() throws Exception {
+ SingleModuleProperties props = SingleModuleProperties.getInstance(project);
+ final ModuleDependency[] newDeps = AddModulePanel.selectDependencies(props, clazz);
+ final AtomicBoolean cancel = new AtomicBoolean();
+ ProgressUtils.runOffEventDispatchThread(new Runnable() {
+ public @Override
+ void run() {
+ ProjectXMLManager pxm = new ProjectXMLManager(project);
+ try {
+ pxm.addDependencies(new HashSet(Arrays.asList(newDeps))); // XXX cannot cancel
+ ProjectManager.getDefault().saveProject(project);
+ } catch (IOException e) {
+// LOG.log(Level.INFO, "Cannot add selected dependencies: " + Arrays.asList(newDeps), e);
+ } catch (ProjectXMLManager.CyclicDependencyException ex) {
+ NotifyDescriptor.Message msg = new NotifyDescriptor.Message(ex.getLocalizedMessage(), NotifyDescriptor.WARNING_MESSAGE);
+ DialogDisplayer.getDefault().notify(msg);
+ }
+ }
+ }, NbBundle.getMessage(SearchModuleDependency.class, "FIX_Module_Dependency_UpdatingDependencies"), cancel, false);
+ return null;
+ }
+ }
+}
--- apisupport.ant/src/org/netbeans/modules/apisupport/project/resources/layer.xml
+++ apisupport.ant/src/org/netbeans/modules/apisupport/project/resources/layer.xml
@@ -249,4 +249,11 @@
+
+
+
+
+
+
+
--- apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/customizer/AddModulePanel.java
+++ apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/customizer/AddModulePanel.java
@@ -40,7 +40,9 @@
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
- */
+ *
+ * Portions Copyrighted 2013 markiewb@netbeans.org
+*/
package org.netbeans.modules.apisupport.project.ui.customizer;
@@ -103,7 +105,26 @@
private Timer timer;
public static ModuleDependency[] selectDependencies(final SingleModuleProperties props) {
- final AddModulePanel addPanel = new AddModulePanel(props);
+ // keep backwards compatibility
+ return selectDependencies(props, null);
+ }
+
+ /**
+ *
+ * @param props
+ * @param initialFilterText initial filter text or null if not given
+ * @return
+ */
+ public static ModuleDependency[] selectDependencies(final SingleModuleProperties props, final String initialFilterText) {
+ final AddModulePanel addPanel;
+ if (null != initialFilterText) {
+ // init dialog with filter text
+ addPanel = new AddModulePanel(props, initialFilterText);
+ }
+ else{
+ // keep backwards compatibility
+ addPanel = new AddModulePanel(props);
+ }
final DialogDescriptor descriptor = new DialogDescriptor(addPanel,
getMessage("CTL_AddModuleDependencyTitle"));
descriptor.setHelpCtx(new HelpCtx("org.netbeans.modules.apisupport.project.ui.customizer.AddModulePanel"));
@@ -132,10 +153,14 @@
}
public AddModulePanel(final SingleModuleProperties props) {
+ this(props, FILTER_DESCRIPTION);
+ }
+
+ private AddModulePanel(final SingleModuleProperties props, String initialString) {
this.props = props;
initComponents();
initAccessibility();
- filterValue.setText(FILTER_DESCRIPTION);
+ filterValue.setText(initialString);
fillUpUniverseModules();
moduleList.setCellRenderer(CustomizerComponentFactory.getDependencyCellRenderer(false));
moduleList.addListSelectionListener(new ListSelectionListener() {
--- java.hints.legacy.spi/nbproject/project.xml
+++ java.hints.legacy.spi/nbproject/project.xml
@@ -97,6 +97,7 @@
+ org.netbeans.modules.apisupport.ant
org.netbeans.modules.javadoc
org.netbeans.modules.javahints
org.netbeans.modules.maven.hints