blob: 3bd5b950b3c603947707da5741b2b125c7017f2c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.java.source.ui;
import java.awt.Toolkit;
import java.lang.ref.Reference;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.lang.model.element.ElementKind;
import javax.swing.Icon;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.modules.java.ui.Icons;
import org.netbeans.modules.parsing.lucene.support.Queries;
import org.netbeans.spi.jumpto.support.NameMatcherFactory;
import org.netbeans.spi.jumpto.type.TypeDescriptor;
import org.netbeans.spi.jumpto.type.TypeProvider;
import org.openide.cookies.EditCookie;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
/**
* Fast & dirty type provider, which fakes Java types from filenames.
* The provider is used just after project loads, and before the source roots
* are indexed by a proper Java indexer.
*
* <p/>
* The TypeProvider uses {@link OpenProjectFastIndex} as data source.
*
* @author sdedic
*/
@org.openide.util.lookup.ServiceProvider(service=org.netbeans.spi.jumpto.type.TypeProvider.class)
public final class FastTypeProvider implements TypeProvider {
private static final Logger LOG = Logger.getLogger(FastTypeProvider.class.getName());
/**
* Cancel flag, set by the infrastructure.
*/
private AtomicBoolean cancel = new AtomicBoolean();
/**
* Fast index instance
*/
private OpenProjectFastIndex fastIndex;
/**
* Cached class icon for results; we do not use other icons :)
*/
private Icon classIcon;
public FastTypeProvider() {
this(OpenProjectFastIndex.getDefault());
}
// used from unit tests
FastTypeProvider(OpenProjectFastIndex fastIndex) {
this.fastIndex = fastIndex;
}
private Icon getClassIcon() {
if (classIcon == null) {
classIcon = Icons.getElementIcon (ElementKind.CLASS, null);
}
return classIcon;
}
@Override
public void cancel() {
cancel.set(true);
}
@Override
public void cleanup() {
// no cleanup needed
}
@Override
@SuppressWarnings("fallthrough")
public void computeTypeNames(Context context, Result result) {
StringBuilder pattern = new StringBuilder();
boolean sensitive = true;
String quotedText = Pattern.quote(context.getText());
switch (context.getSearchType()) {
case CASE_INSENSITIVE_EXACT_NAME:
sensitive = false;
case CAMEL_CASE:
pattern.append(Queries.createCamelCaseRegExp(context.getText(), null, null, sensitive));
break;
case CASE_INSENSITIVE_CAMEL_CASE:
sensitive = false;
pattern.append(Queries.createCamelCaseRegExp(context.getText(), null, null, sensitive));
break;
case EXACT_NAME:
pattern.append("^").append(quotedText).append("$"); // NOI18N
break;
case CASE_INSENSITIVE_PREFIX:
sensitive = false;
case PREFIX:
pattern.append("^").append(quotedText); // NOI18N
break;
case CASE_INSENSITIVE_REGEXP:
sensitive = false;
case REGEXP:
pattern.append(
NameMatcherFactory.wildcardsToRegexp(
JavaTypeProvider.removeNonJavaChars(context.getText()),
false
)
);
break;
}
Pattern searchPattern = Pattern.compile(
pattern.toString(),
Pattern.MULTILINE +
(sensitive ? 0 : Pattern.CASE_INSENSITIVE));
for (Map.Entry<FileObject, OpenProjectFastIndex.NameIndex> one : fastIndex.copyIndexes().entrySet()) {
FileObject root = one.getKey();
Project p = FileOwnerQuery.getOwner(root);
if (context.getProject() != null && !context.getProject().equals(p)) {
continue;
}
OpenProjectFastIndex.NameIndex fileIndex = one.getValue();
Matcher m = searchPattern.matcher(fileIndex.files());
while (m.find()) {
if (cancel.get()) {
LOG.fine("Search canceled");
return;
}
if (m.start() == m.end()) {
continue;
}
CharSequence f = fileIndex.getFilename(m.start(), m.end());
CharSequence pkg = fileIndex.findPath(m.start());
SimpleDescriptor desc = new SimpleDescriptor(p, root, f, pkg);
result.addResult(desc);
}
}
}
@Override
public String getDisplayName() {
return NbBundle.getMessage(FastTypeProvider.class, "LBL_FastJavaIndex"); // NOI18N
}
@Override
public String name() {
return "fastJavaIndex"; // NOI18N
}
private class SimpleDescriptor extends TypeDescriptor {
public static final String JAVA_EXTENSION = ".java"; // NOI18N
private FileObject root;
private String simpleName;
private String pkgName;
private Project project;
public SimpleDescriptor(Project project, FileObject root, CharSequence simpleName, CharSequence pkgName) {
this.root = root;
this.simpleName = simpleName.toString();
this.pkgName = pkgName.toString();
this.project = project;
}
@Override
public String getContextName() {
return NbBundle.getMessage(FastTypeProvider.class, "FMT_TypeContextName",
pkgName == null ? NbBundle.getMessage(FastTypeProvider.class, "LBL_DefaultPackage") : pkgName);
}
@Override
@CheckForNull
public FileObject getFileObject() {
String s = simpleName;
if (pkgName != null && !"".equals(pkgName)) {
StringBuilder sb = new StringBuilder();
s = sb.append(pkgName).append('.').append(simpleName).toString().replaceAll("\\.", "/"); // NOI18N
}
return root.getFileObject(s + JAVA_EXTENSION);
}
@Override
public Icon getIcon() {
return getClassIcon();
}
@Override
public int getOffset() {
return -1;
}
@Override
public String getOuterName() {
return null;
}
@Override
public Icon getProjectIcon() {
return fastIndex.getProjectIcon(project);
}
@Override
public String getProjectName() {
return fastIndex.getProjectName(project);
}
@Override
public String getSimpleName() {
return simpleName.toString();
}
@Override
public String getTypeName() {
return simpleName;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(simpleName).append(" (");
if (pkgName == null || "".equals(pkgName)) {
sb.append("Default Package");
} else {
sb.append(pkgName);
}
sb.append(")");
return sb.toString();
}
@Override
public int hashCode() {
int hc = 17;
hc = hc * 31 + (root == null ? 0 : root.hashCode());
hc = hc * 31 + (pkgName == null ? 0 : pkgName.hashCode());
hc = hc * 31 + (simpleName == null ? 0 : simpleName.hashCode());
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof SimpleDescriptor)) {
return false;
}
final SimpleDescriptor other = (SimpleDescriptor) obj;
return root == null ? other.root == null : root.equals(other.root) &&
pkgName == null ? other.pkgName == null : pkgName.equals(other.pkgName) &&
simpleName == null ? other.simpleName == null : simpleName.equals(other.simpleName);
}
@Override
public void open() {
boolean success = false;
try {
final FileObject fo = getFileObject();
if (fo != null) {
final DataObject d = DataObject.find(fo);
final EditCookie cake = d.getCookie(EditCookie.class);
if (cake != null) {
cake.edit();
success = true;
}
}
} catch (DataObjectNotFoundException ex) {
Exceptions.printStackTrace(ex);
}
if (!success) {
Toolkit.getDefaultToolkit().beep();
}
}
}
}