2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2010-2011 Sun Microsystems, Inc. All rights reserved.
6 * The contents of this file are subject to the terms of either the GNU
7 * General Public License Version 2 only ("GPL") or the Common
8 * Development and Distribution License("CDDL") (collectively, the
9 * "License"). You may not use this file except in compliance with the
10 * License. You can obtain a copy of the License at
11 * http://www.netbeans.org/cddl-gplv2.html
12 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13 * specific language governing permissions and limitations under the
14 * License. When distributing the software, include this License Header
15 * Notice in each file and include the License file at
16 * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17 * particular file as subject to the "Classpath" exception as provided
18 * by Sun in the GPL Version 2 section of the License file that
19 * accompanied this code. If applicable, add the following below the
20 * License Header, with the fields enclosed by brackets [] replaced by
21 * your own identifying information:
22 * "Portions Copyrighted [year] [name of copyright owner]"
24 * If you wish your version of this file to be governed by only the CDDL
25 * or only the GPL Version 2, indicate your decision by adding
26 * "[Contributor] elects to include this software in this distribution
27 * under the [CDDL or GPL Version 2] license." If you do not indicate a
28 * single choice of license, a recipient has the option to distribute
29 * your version of this file under either the CDDL, the GPL Version 2 or
30 * to extend the choice of license to its licensees as provided above.
31 * However, if you add GPL Version 2 code and therefore, elected the GPL
32 * Version 2 license, then the option applies only if the new code is
33 * made subject to such option by the copyright holder.
37 * Portions Copyrighted 2010-2011 Sun Microsystems, Inc.
40 package org.netbeans.modules.jackpot30.cmdline;
42 import java.awt.BorderLayout;
43 import java.awt.event.ActionEvent;
44 import java.awt.event.ActionListener;
45 import java.io.BufferedWriter;
47 import java.io.FileOutputStream;
48 import java.io.IOException;
49 import java.io.OutputStreamWriter;
50 import java.io.PrintStream;
51 import java.io.Writer;
52 import java.lang.reflect.InvocationTargetException;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.Collection;
57 import java.util.HashMap;
58 import java.util.Iterator;
59 import java.util.LinkedList;
60 import java.util.List;
62 import java.util.Map.Entry;
64 import java.util.TreeSet;
65 import java.util.concurrent.atomic.AtomicBoolean;
66 import java.util.logging.Level;
67 import java.util.logging.Logger;
68 import java.util.prefs.BackingStoreException;
69 import java.util.prefs.Preferences;
70 import java.util.regex.Pattern;
71 import javax.swing.JCheckBox;
72 import javax.swing.JDialog;
73 import javax.swing.JOptionPane;
74 import javax.swing.JPanel;
75 import javax.swing.SwingUtilities;
76 import javax.swing.event.ChangeListener;
77 import joptsimple.ArgumentAcceptingOptionSpec;
78 import joptsimple.OptionException;
79 import joptsimple.OptionParser;
80 import joptsimple.OptionSet;
81 import org.netbeans.api.java.classpath.ClassPath;
82 import org.netbeans.api.java.classpath.GlobalPathRegistry;
83 import org.netbeans.api.java.source.CompilationController;
84 import org.netbeans.api.java.source.ModificationResult;
85 import org.netbeans.core.startup.MainLookup;
86 import org.netbeans.modules.jackpot30.ui.settings.XMLHintPreferences;
87 import org.netbeans.modules.java.hints.jackpot.spi.PatternConvertor;
88 import org.netbeans.modules.java.hints.providers.spi.HintDescription;
89 import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
90 import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
91 import org.netbeans.modules.java.hints.spiimpl.RulesManager;
92 import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch;
93 import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.BatchResult;
94 import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Folder;
95 import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Resource;
96 import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.VerifiedSpansCallBack;
97 import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
98 import org.netbeans.modules.java.hints.spiimpl.batch.ProgressHandleWrapper;
99 import org.netbeans.modules.java.hints.spiimpl.batch.ProgressHandleWrapper.ProgressHandleAbstraction;
100 import org.netbeans.modules.java.hints.spiimpl.batch.Scopes;
101 import org.netbeans.modules.java.hints.spiimpl.options.HintsPanel;
102 import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
103 import org.netbeans.modules.java.hints.spiimpl.refactoring.Utilities.ClassPathBasedHintWrapper;
104 import org.netbeans.modules.java.source.parsing.JavaPathRecognizer;
105 import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
106 import org.netbeans.modules.parsing.impl.indexing.RepositoryUpdater;
107 import org.netbeans.spi.editor.hints.ErrorDescription;
108 import org.netbeans.spi.java.classpath.ClassPathProvider;
109 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
110 import org.netbeans.spi.java.hints.Hint.Kind;
111 import org.netbeans.spi.java.queries.SourceLevelQueryImplementation2;
112 import org.openide.filesystems.FileObject;
113 import org.openide.filesystems.FileStateInvalidException;
114 import org.openide.filesystems.FileUtil;
115 import org.openide.util.Exceptions;
116 import org.openide.util.Lookup;
117 import org.openide.util.NbPreferences;
118 import org.openide.util.RequestProcessor;
119 import org.openide.util.lookup.Lookups;
120 import org.openide.util.lookup.ProxyLookup;
121 import org.openide.util.lookup.ServiceProvider;
129 private static final String OPTION_APPLY = "apply";
130 private static final String OPTION_NO_APPLY = "no-apply";
131 private static final String SOURCE_LEVEL_DEFAULT = "1.7";
132 private static final String ACCEPTABLE_SOURCE_LEVEL_PATTERN = "(1\\.)?[2-9][0-9]*";
134 public static void main(String... args) throws IOException, ClassNotFoundException {
135 System.exit(compile(args));
138 public static int compile(String... args) throws IOException, ClassNotFoundException {
139 System.setProperty("netbeans.user", "/tmp/tmp-foo");
141 OptionParser parser = new OptionParser();
142 // ArgumentAcceptingOptionSpec<File> projects = parser.accepts("project", "project(s) to refactor").withRequiredArg().withValuesSeparatedBy(File.pathSeparatorChar).ofType(File.class);
143 ArgumentAcceptingOptionSpec<File> classpath = parser.accepts("classpath", "classpath").withRequiredArg().withValuesSeparatedBy(File.pathSeparatorChar).ofType(File.class);
144 ArgumentAcceptingOptionSpec<File> bootclasspath = parser.accepts("bootclasspath", "bootclasspath").withRequiredArg().withValuesSeparatedBy(File.pathSeparatorChar).ofType(File.class);
145 ArgumentAcceptingOptionSpec<File> sourcepath = parser.accepts("sourcepath", "sourcepath").withRequiredArg().withValuesSeparatedBy(File.pathSeparatorChar).ofType(File.class);
146 ArgumentAcceptingOptionSpec<File> cache = parser.accepts("cache", "a cache directory to store working data").withRequiredArg().ofType(File.class);
147 ArgumentAcceptingOptionSpec<File> out = parser.accepts("out", "output diff").withRequiredArg().ofType(File.class);
148 ArgumentAcceptingOptionSpec<File> configFile = parser.accepts("config-file", "configuration file").withRequiredArg().ofType(File.class);
149 ArgumentAcceptingOptionSpec<String> hint = parser.accepts("hint", "hint name").withRequiredArg().ofType(String.class);
150 ArgumentAcceptingOptionSpec<String> config = parser.accepts("config", "configurations").withRequiredArg().ofType(String.class);
151 ArgumentAcceptingOptionSpec<String> source = parser.accepts("source", "source level").withRequiredArg().ofType(String.class).defaultsTo(SOURCE_LEVEL_DEFAULT);
152 ArgumentAcceptingOptionSpec<File> hintFile = parser.accepts("hint-file", "file with rules that should be performed").withRequiredArg().ofType(File.class);
154 parser.accepts("list", "list all known hints");
155 parser.accepts("progress", "show progress");
156 parser.accepts("debug", "enable debugging loggers");
157 parser.accepts("help", "prints this help");
158 parser.accepts(OPTION_NO_APPLY, "do not apply changes - only print locations were the hint would be applied");
159 parser.accepts(OPTION_APPLY, "apply changes");
160 parser.accepts("show-gui", "show configuration dialog");
165 parsed = parser.parse(args);
166 } catch (OptionException ex) {
167 System.err.println(ex.getLocalizedMessage());
168 parser.printHelpOn(System.out);
172 if (!parsed.has("debug")) {
176 if (parsed.has("help")) {
177 parser.printHelpOn(System.out);
181 List<FileObject> roots = new ArrayList<FileObject>();
182 List<Folder> rootFolders = new ArrayList<Folder>();
184 for (String sr : parsed.nonOptionArguments()) {
185 File r = new File(sr);
186 FileObject root = FileUtil.toFileObject(r);
190 rootFolders.add(new Folder(root));
194 ClassPath bootCP = createClassPath(parsed.has(bootclasspath) ? parsed.valuesOf(bootclasspath) : null, createDefaultBootClassPath());
195 ClassPath compileCP = createClassPath(parsed.has(classpath) ? parsed.valuesOf(classpath) : null, ClassPath.EMPTY);
196 final ClassPath sourceCP = createClassPath(parsed.has(sourcepath) ? parsed.valuesOf(sourcepath) : null, ClassPathSupport.createClassPath(roots.toArray(new FileObject[0])));
197 final ClassPath binaryCP = ClassPathSupport.createProxyClassPath(bootCP, compileCP);
199 if (parsed.has("show-gui")) {
200 if (parsed.has(configFile)) {
201 final File settingsFile = parsed.valueOf(configFile);
203 SwingUtilities.invokeAndWait(new Runnable() {
204 @Override public void run() {
206 showGUICustomizer(settingsFile, binaryCP, sourceCP);
207 } catch (IOException ex) {
208 Exceptions.printStackTrace(ex);
209 } catch (BackingStoreException ex) {
210 Exceptions.printStackTrace(ex);
214 } catch (InterruptedException ex) {
215 Exceptions.printStackTrace(ex);
216 } catch (InvocationTargetException ex) {
217 Exceptions.printStackTrace(ex);
222 System.err.println("show-gui requires config-file");
227 File cacheDir = parsed.valueOf(cache);
228 boolean deleteCacheDir = false;
231 if (cacheDir == null) {
232 cacheDir = File.createTempFile("jackpot", "cache");
234 if (!(deleteCacheDir = cacheDir.mkdirs())) {
235 System.err.println("cannot create temporary cache");
240 if (cacheDir.isFile()) {
241 System.err.println("cache directory exists and is a file");
245 String[] cacheDirContent = cacheDir.list();
247 if (cacheDirContent != null && cacheDirContent.length > 0 && !new File(cacheDir, "segments").exists()) {
248 System.err.println("cache directory is not empty, but was not created by this tool");
254 CacheFolder.setCacheFolder(FileUtil.toFileObject(FileUtil.normalizeFile(cacheDir)));
256 org.netbeans.api.project.ui.OpenProjects.getDefault().getOpenProjects();
257 RepositoryUpdater.getDefault().start(false);
259 if (roots.isEmpty() && !parsed.has("list")) {
260 System.err.println("no source roots to work on");
264 Iterable<? extends HintDescription> hints;
266 if (parsed.has("list")) {
267 printHints(sourceCP, binaryCP);
271 Preferences settingsFromConfigFile;
272 Preferences hintSettingsPreferences;
273 HintsSettings hintSettings;
276 if (parsed.has(configFile)) {
277 settingsFromConfigFile = XMLHintPreferences.from(parsed.valueOf(configFile));
278 hintSettings = HintsSettings.createPreferencesBasedHintsSettings(hintSettingsPreferences = settingsFromConfigFile.node("settings"), false, null);
279 apply = settingsFromConfigFile.getBoolean("apply", false);
281 settingsFromConfigFile = null;
282 hintSettings = HintsSettings.createPreferencesBasedHintsSettings(hintSettingsPreferences = NbPreferences.root().node("tempSettings"), false, null);
286 if (parsed.has(hint)) {
287 if (settingsFromConfigFile != null) {
288 System.err.println("cannot specify --hint and --config-file together");
291 hints = findHints(sourceCP, binaryCP, parsed.valueOf(hint), hintSettings);
292 } else if (parsed.has(hintFile)) {
293 if (settingsFromConfigFile != null) {
294 System.err.println("cannot specify --hint-file and --config-file together");
297 FileObject hintFileFO = FileUtil.toFileObject(parsed.valueOf(hintFile));
298 assert hintFileFO != null;
299 hints = PatternConvertor.create(hintFileFO.asText());
300 for (HintDescription hd : hints) {
301 hintSettings.setEnabled(hd.getMetadata(), true);
304 hints = readHints(sourceCP, binaryCP, hintSettings, hintSettingsPreferences, settingsFromConfigFile != null ? settingsFromConfigFile.getBoolean("runDeclarative", true) : true);
307 if (parsed.has(config) && !parsed.has(hint)) {
308 System.err.println("--config cannot specified when no hint is specified");
312 if (parsed.has(config)) {
313 Iterator<? extends HintDescription> hit = hints.iterator();
314 HintDescription hd = hit.next();
317 System.err.println("--config cannot specified when more than one hint is specified");
322 Preferences prefs = hintSettings.getHintPreferences(hd.getMetadata());
324 boolean stop = false;
326 for (String c : parsed.valuesOf(config)) {
327 int assign = c.indexOf('=');
329 if (assign == (-1)) {
330 System.err.println("configuration option is missing '=' (" + c + ")");
335 prefs.put(c.substring(0, assign), c.substring(assign + 1));
343 String sourceLevel = parsed.valueOf(source);
345 if (!Pattern.compile(ACCEPTABLE_SOURCE_LEVEL_PATTERN).matcher(sourceLevel).matches()) {
346 System.err.println("unrecognized source level specification: " + sourceLevel);
350 if (parsed.has(OPTION_NO_APPLY)) {
352 } else if (parsed.has(OPTION_APPLY)) {
356 if (apply && !hints.iterator().hasNext()) {
357 System.err.println("no hints specified");
361 Object[] register2Lookup = new Object[] {
362 new ClassPathProviderImpl(bootCP, compileCP, sourceCP),
363 new JavaPathRecognizer(),
364 new SourceLevelQueryImpl(sourceCP, sourceLevel)
368 for (Object toRegister : register2Lookup) {
369 MainLookup.register(toRegister);
372 ProgressHandleWrapper progress = parsed.has("progress") ? new ProgressHandleWrapper(new ConsoleProgressHandleAbstraction(), 1) : new ProgressHandleWrapper(1);
375 apply(hints, rootFolders.toArray(new Folder[0]), progress, hintSettings, parsed.valueOf(out));
377 findOccurrences(hints, rootFolders.toArray(new Folder[0]), progress, hintSettings, parsed.valueOf(out));
379 } catch (Throwable e) {
382 for (Object toUnRegister : register2Lookup) {
383 MainLookup.unregister(toUnRegister);
387 if (deleteCacheDir) {
388 FileObject cacheDirFO = FileUtil.toFileObject(cacheDir);
390 if (cacheDirFO != null) {
391 //TODO: would be better to do j.i.File.delete():
400 private static Map<HintMetadata, Collection<? extends HintDescription>> listHints(ClassPath sourceFrom, ClassPath binaryFrom) {
401 Map<HintMetadata, Collection<? extends HintDescription>> result = new HashMap<HintMetadata, Collection<? extends HintDescription>>();
403 for (Entry<HintMetadata, ? extends Collection<? extends HintDescription>> entry: RulesManager.getInstance().readHints(null, Arrays.asList(sourceFrom, binaryFrom), null).entrySet()) {
404 result.put(entry.getKey(), entry.getValue());
410 private static Iterable<? extends HintDescription> findHints(ClassPath sourceFrom, ClassPath binaryFrom, String name, HintsSettings toEnableIn) {
411 List<HintDescription> descs = new LinkedList<HintDescription>();
413 for (Entry<HintMetadata, Collection<? extends HintDescription>> e : listHints(sourceFrom, binaryFrom).entrySet()) {
414 if (e.getKey().displayName.equals(name)) {
415 descs.addAll(e.getValue());
416 toEnableIn.setEnabled(e.getKey(), true);
423 private static Iterable<? extends HintDescription> allHints(ClassPath sourceFrom, ClassPath binaryFrom, HintsSettings toEnableIn) {
424 List<HintDescription> descs = new LinkedList<HintDescription>();
426 for (Entry<HintMetadata, Collection<? extends HintDescription>> e : listHints(sourceFrom, binaryFrom).entrySet()) {
427 if (e.getKey().kind != Kind.INSPECTION) continue;
428 if (!e.getKey().enabled) continue;
429 descs.addAll(e.getValue());
430 toEnableIn.setEnabled(e.getKey(), true);
436 private static Iterable<? extends HintDescription> readHints(ClassPath sourceFrom, ClassPath binaryFrom, HintsSettings toEnableIn, Preferences toEnableInPreferencesHack, boolean declarativeEnabledByDefault) {
437 Map<HintMetadata, ? extends Collection<? extends HintDescription>> hardcoded = RulesManager.getInstance().readHints(null, Arrays.<ClassPath>asList(), null);
438 Map<HintMetadata, ? extends Collection<? extends HintDescription>> all = RulesManager.getInstance().readHints(null, Arrays.asList(sourceFrom, binaryFrom), null);
439 List<HintDescription> descs = new LinkedList<HintDescription>();
441 for (Entry<HintMetadata, ? extends Collection<? extends HintDescription>> entry: all.entrySet()) {
442 if (hardcoded.containsKey(entry.getKey())) {
443 if (toEnableIn.isEnabled(entry.getKey())) {
444 descs.addAll(entry.getValue());
447 if (/*XXX: hack*/toEnableInPreferencesHack.node(entry.getKey().id).getBoolean("enabled", declarativeEnabledByDefault)) {
448 descs.addAll(entry.getValue());
456 private static final Logger TOP_LOGGER = Logger.getLogger("");
458 private static void prepareLoggers() {
459 TOP_LOGGER.setLevel(Level.OFF);
460 System.setProperty("RepositoryUpdate.increasedLogLevel", "OFF");
463 private static void findOccurrences(Iterable<? extends HintDescription> descs, Folder[] sourceRoot, ProgressHandleWrapper progress, HintsSettings settings, File out) throws IOException {
464 final Map<String, String> id2DisplayName = new HashMap<String, String>();
466 for (HintDescription hd : descs) {
467 if (hd.getMetadata() != null) {
468 id2DisplayName.put(hd.getMetadata().id, hd.getMetadata().displayName);
472 ProgressHandleWrapper w = progress.startNextPartWithEmbedding(1, 1);
473 BatchResult occurrences = BatchSearch.findOccurrences(descs, Scopes.specifiedFoldersScope(sourceRoot), w, settings);
475 List<MessageImpl> problems = new LinkedList<MessageImpl>();
476 BatchSearch.getVerifiedSpans(occurrences, progress, new VerifiedSpansCallBack() {
477 @Override public void groupStarted() {}
478 @Override public boolean spansVerified(CompilationController wc, Resource r, Collection<? extends ErrorDescription> hints) throws Exception {
479 for (ErrorDescription ed : hints) {
480 print(ed, id2DisplayName);
484 @Override public void groupFinished() {}
485 @Override public void cannotVerifySpan(Resource r) {
486 //TODO: ignored - what to do?
488 }, problems, new AtomicBoolean());
491 private static void print(ErrorDescription error, Map<String, String> id2DisplayName) throws IOException {
492 int lineNumber = error.getRange().getBegin().getLine();
493 String line = error.getFile().asLines().get(lineNumber);
494 int column = error.getRange().getBegin().getColumn();
495 StringBuilder b = new StringBuilder();
497 for (int i = 0; i < column; i++) {
498 if (Character.isWhitespace(line.charAt(i))) {
499 b.append(line.charAt(i));
507 String id = error.getId();
509 if (id != null && id.startsWith("text/x-java:")) {
510 id = id.substring("text/x-java:".length());
513 String idDisplayName = id2DisplayName.get(id);
515 if (idDisplayName == null) {
516 idDisplayName = "unknown";
519 for (Entry<String, String> remap : toIdRemap.entrySet()) {
520 idDisplayName = idDisplayName.replace(remap.getKey(), remap.getValue());
523 idDisplayName = idDisplayName.replaceAll("[^A-Za-z0-9]", "_").replaceAll("_+", "_");
525 idDisplayName = "[" + idDisplayName + "] ";
527 System.out.println(FileUtil.getFileDisplayName(error.getFile()) + ":" + (lineNumber + 1) + ": warning: " + idDisplayName + error.getDescription());
528 System.out.println(line);
529 System.out.println(b);
532 private static final Map<String, String> toIdRemap = new HashMap<String, String>() {{
534 put("!=", "not_equals");
537 private static void apply(Iterable<? extends HintDescription> descs, Folder[] sourceRoot, ProgressHandleWrapper progress, HintsSettings settings, File out) throws IOException {
538 ProgressHandleWrapper w = progress.startNextPartWithEmbedding(1, 1);
539 BatchResult occurrences = BatchSearch.findOccurrences(descs, Scopes.specifiedFoldersScope(sourceRoot), w, settings);
541 List<MessageImpl> problems = new LinkedList<MessageImpl>();
542 Collection<ModificationResult> diffs = BatchUtilities.applyFixes(occurrences, w, new AtomicBoolean(), problems);
548 outS = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(out)));
550 for (ModificationResult mr : diffs) {
551 org.netbeans.modules.jackpot30.indexing.batch.BatchUtilities.exportDiff(mr, null, outS);
556 } catch (IOException ex) {
557 Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
561 for (ModificationResult mr : diffs) {
567 private static void printHints(ClassPath sourceFrom, ClassPath binaryFrom) throws IOException {
568 Set<String> hints = new TreeSet<String>();
570 for (Entry<HintMetadata, Collection<? extends HintDescription>> e : listHints(sourceFrom, binaryFrom).entrySet()) {
571 hints.add(e.getKey().displayName);
574 for (String h : hints) {
575 System.out.println(h);
579 private static ClassPath createDefaultBootClassPath() throws IOException {
581 String cp = System.getProperty("sun.boot.class.path");
582 List<URL> urls = new ArrayList<URL>();
583 String[] paths = cp.split(Pattern.quote(System.getProperty("path.separator")));
585 for (String path : paths) {
586 File f = new File(path);
591 FileObject fo = FileUtil.toFileObject(FileUtil.normalizeFile(f));
593 if (FileUtil.isArchiveFile(fo)) {
594 fo = FileUtil.getArchiveRoot(fo);
598 urls.add(fo.getURL());
602 return ClassPathSupport.createClassPath(urls.toArray(new URL[0]));
603 } catch (FileStateInvalidException e) {
608 private static ClassPath createClassPath(Iterable<? extends File> roots, ClassPath def) {
609 if (roots == null) return def;
611 List<URL> rootURLs = new ArrayList<URL>();
613 for (File r : roots) {
614 rootURLs.add(FileUtil.urlForArchiveOrDir(r));
617 return ClassPathSupport.createClassPath(rootURLs.toArray(new URL[0]));
620 private static void showGUICustomizer(File settingsFile, ClassPath binaryCP, ClassPath sourceCP) throws IOException, BackingStoreException {
621 GlobalPathRegistry.getDefault().register(ClassPath.COMPILE, new ClassPath[] {binaryCP});
622 GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[] {sourceCP});
623 ClassPathBasedHintWrapper hints = new ClassPathBasedHintWrapper();
624 final Preferences p = XMLHintPreferences.from(settingsFile);
625 JPanel hintPanel = new HintsPanel(p.node("settings"), hints, true);
626 final JCheckBox runDeclarativeHints = new JCheckBox("Always Run Declarative Rules");
628 runDeclarativeHints.setToolTipText("Always run the declarative rules found on classpath? (Only those selected above will be run when unchecked.)");
629 runDeclarativeHints.setSelected(p.getBoolean("runDeclarative", true));
630 runDeclarativeHints.addActionListener(new ActionListener() {
631 @Override public void actionPerformed(ActionEvent e) {
632 p.putBoolean("runDeclarative", runDeclarativeHints.isSelected());
636 JPanel customizer = new JPanel(new BorderLayout());
638 customizer.add(hintPanel, BorderLayout.CENTER);
639 customizer.add(runDeclarativeHints, BorderLayout.SOUTH);
640 JOptionPane jop = new JOptionPane(customizer, JOptionPane.PLAIN_MESSAGE);
641 JDialog dialog = jop.createDialog("Select Hints");
643 jop.selectInitialValue();
644 dialog.setVisible(true);
647 Object result = jop.getValue();
649 if (result.equals(JOptionPane.OK_OPTION)) {
654 @ServiceProvider(service=Lookup.class)
655 public static final class LookupProviderImpl extends ProxyLookup {
657 public LookupProviderImpl() {
658 super(Lookups.forPath("Services/AntBasedProjectTypes"));
662 public static final class ClassPathProviderImpl implements ClassPathProvider {
663 private final ClassPath boot;
664 private final ClassPath compile;
665 private final ClassPath source;
667 public ClassPathProviderImpl(ClassPath boot, ClassPath compile, ClassPath source) {
669 this.compile = compile;
670 this.source = source;
674 public ClassPath findClassPath(FileObject file, String type) {
675 if (source.findOwnerRoot(file) != null) {
676 if (ClassPath.BOOT.equals(type)) {
678 } else if (ClassPath.COMPILE.equals(type)) {
680 } else if (ClassPath.SOURCE.equals(type)) {
689 public static final class SourceLevelQueryImpl implements SourceLevelQueryImplementation2 {
690 private final ClassPath sourceCP;
691 private final Result sourceLevel;
693 public SourceLevelQueryImpl(ClassPath sourceCP, final String sourceLevel) {
694 this.sourceCP = sourceCP;
695 this.sourceLevel = new Result() {
696 @Override public String getSourceLevel() {
699 @Override public void addChangeListener(ChangeListener listener) {}
700 @Override public void removeChangeListener(ChangeListener listener) {}
705 public Result getSourceLevel(FileObject javaFile) {
706 if (sourceCP.findOwnerRoot(javaFile) != null) {
715 private static final class ConsoleProgressHandleAbstraction implements ProgressHandleAbstraction {
717 private final int width = 80;
719 private int total = -1;
720 private int current = 0;
722 public ConsoleProgressHandleAbstraction() {
726 public synchronized void start(int totalWork) {
727 if (total != (-1)) throw new UnsupportedOperationException();
733 public synchronized void progress(int currentWorkDone) {
734 current = currentWorkDone;
739 public void progress(String message) {
743 public void finish() {
746 private void update() {
747 RequestProcessor.getDefault().post(new Runnable() {
756 private int currentShownDone = -1;
758 private void doUpdate() {
762 done = (int) ((((double) width - 2) / total) * current);
764 if (done == currentShownDone) {
768 currentShownDone = done;
771 int todo = width - done;
772 PrintStream pw = System.out;