diff --git a/api.io/arch.xml b/api.io/arch.xml new file mode 100644 --- /dev/null +++ b/api.io/arch.xml @@ -0,0 +1,1180 @@ + + +]> + + + + + &api-questions; + + + + + +

+ The module contains APIs for creating output panes (e.g. output tabs in Output Window in the IDE) + and for writing data into them. It also supports some advanced techniques, e.g. color text, + hyperlinks, code folding, scrolling to stored positions. +

+
+ +

+ SPI for providing custom implementations of output window is also included in this module, in package + org.netbeans.spi.io +

+
+
+ + + + + +

+ Unit test will be prepared for invocable code in API classes. But most of the + code is just definition of API and SPI. +

+
+ + + + + +

+ The design, implementation, preparing unit tests and reviews will + probably take several weeks. +

+
+ + + + + + + +

+ The basic use-case is printing a simple text, e.g. text output of an application, + into a dedicated pane in the UI, e.g. a tab in Output Window in the IDE. +

+
+    InputOutput io = InputOutput.get("UseCase1", true);
+    io.getOut().println("This is a simple output");
+    io.getOut().close();
+            
+
+ + +

+ Implementations can support hyperlinks. If the hyperlink is defined by a URI, + it will be opened by the UI part of the application when the hyperlink is clicked + in the output window. The following example will open a file and place the cursor + at line and column specified by query part of the URI (after question mark). +

+
+    InputOutput io = InputOutput.get("UseCase2", false);
+    io.getOut().print("A line containing a ");
+    io.getOut().print("hyperlink", Hyperlink.forURI(new URI("file://n:/test/Test.java?line=4&col=2")));
+    io.getOut().println(" for a URI.");
+    io.getOut().close();
+            
+
+ + +

+ Hyperlinks can be also used to invoke some code when clicked. +

+
+    InputOutput io = InputOutput.get("UseCase3", true);
+    io.getOut().print("A line containing a ");
+    io.getOut().print("hyperlink", Hyperlink.onClick(new Runnable() {
+        public void run() {
+            System.gc();
+        }
+    }));
+    io.getOut().println(" for invocation of custom code.");
+    io.getOut().close();
+            
+
+ + +

+ Print a color text. Users can select a predefined color for + common cases (debug, warning, failure, success), or custom + color specified as RGB value. +

+
+    InputOutput io = InputOutput.get("UseCase4", true);
+    io.getOut().println("Let's print some info", OutputColor.debug());
+    io.getOut().println("or warning with appropriate color", OutputColor.warning());
+    io.getOut().println("Maybe also text with custom reddish color", OutputColor.rgb(255, 16, 16));
+    io.getOut().close();
+            
+
+ + +

+ It is possible to reuse already created output pane and clear + all the previously printed text if it is not needed any more. +

+
+    InputOutput io = InputOutput.get("UseCase5", true);
+    io.getOut().println("Let's print some text");
+    io.getErr().println("and reset the pane immediately.");
+    io.reset();
+    io.getOut().println("The pane is now empty and we can reuse it simply");
+    io.getOut().close();
+            
+
+ +
+ + + + + +

+ The Input/Output API and SPI is a small module + which contains InputOutput and related interfaces used in + driving the Output Window. +

+

+ The normal implementation is org.netbeans.core.output2. +

+
+ + + + + + + + + + + + +

+ Backward compatibility of other modules is not broken. +

+

+ This module should replace original I/O API module + org.openide.io, which has the same goals, but which is + not UI independent, and which is difficult to extend. +

+
+ + + + + +

+ Yes. There is not much to internationalize. +

+
+ + + + + +

+ The module defines an API. +

+
+ + + + + +

+ N/A. No settings are read or written by this module. +

+
+ + + + + + 1.7 + + + + + + + JRE + + + + + + + + + + + + + + None. + + + + + + + Any. + + + + + + +

+ You will very likely also want to declare +

+
OpenIDE-Module-Requires: org.netbeans.api.io.IOProvider
+

to ensure that an Output Window implementation is in fact enabled.

+
+ + + + + +

+ Just the module JAR. +

+
+ + + + + +

+ Yes. +

+
+ + + + + +

+ No; only API classes are public. +

+
+ + + + + +

+ Anywhere. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ Should be thread safe. +

+
+ + + + + +

+ Plain Unicode text only. +

+
+ + + + + +

+ N/A +

+
+ + + + + +

+ None. +

+
+ + + + + +

+ IOProvider.getDefault() asks lookup for the first instance + of InputOutputProvider. This is normally provided by + org.netbeans.core.output2. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ N/A +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ Scalability in GUI speed and memory consumption is probably limited + only by the Output Window implementation. +

+
+ + + + + +

+ No special behavior. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No, but the implementation may. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ +
diff --git a/api.io/build.xml b/api.io/build.xml new file mode 100644 --- /dev/null +++ b/api.io/build.xml @@ -0,0 +1,5 @@ + + + Builds, tests, and runs the project org.netbeans.api.io + + diff --git a/api.io/manifest.mf b/api.io/manifest.mf new file mode 100644 --- /dev/null +++ b/api.io/manifest.mf @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: true +OpenIDE-Module: org.netbeans.api.io +OpenIDE-Module-Localizing-Bundle: org/netbeans/api/io/Bundle.properties +OpenIDE-Module-Specification-Version: 1.0 + diff --git a/api.io/nbproject/project.properties b/api.io/nbproject/project.properties new file mode 100644 --- /dev/null +++ b/api.io/nbproject/project.properties @@ -0,0 +1,4 @@ +is.autoload=true +javac.source=1.6 +javac.compilerargs=-Xlint -Xlint:-serial +javadoc.arch=${basedir}/arch.xml diff --git a/api.io/nbproject/project.xml b/api.io/nbproject/project.xml new file mode 100644 --- /dev/null +++ b/api.io/nbproject/project.xml @@ -0,0 +1,53 @@ + + + org.netbeans.modules.apisupport.project + + + org.netbeans.api.io + + + org.netbeans.api.annotations.common + + + + 1 + 1.25 + + + + org.openide.util.base + + + + 9.1 + + + + org.openide.util.lookup + + + + 8.26 + + + + + + unit + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.nbjunit + + + + + + org.netbeans.api.io + org.netbeans.spi.io + + + + diff --git a/api.io/src/org/netbeans/api/io/Bundle.properties b/api.io/src/org/netbeans/api/io/Bundle.properties new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/Bundle.properties @@ -0,0 +1,6 @@ +OpenIDE-Module-Display-Category=Infrastructure +OpenIDE-Module-Long-Description=\ + API classes for creating output panes (e.g. tabs in output window) and for wrinting data into them.\n\ + SPI for custom implementations of output window. +OpenIDE-Module-Name=I/O API and SPI +OpenIDE-Module-Short-Description=APIs and SPIs related to displaying output. diff --git a/api.io/src/org/netbeans/api/io/Hyperlink.java b/api.io/src/org/netbeans/api/io/Hyperlink.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/Hyperlink.java @@ -0,0 +1,224 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import java.net.URI; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullUnknown; +import org.openide.util.Parameters; + +/** + * Hyperlink in output window. It can be specified by a URI to open (e.g. file + + * row + col), or a {@link Runnable} to invoke when the hyperlink is clicked. + * + * @author jhavlin + */ +public abstract class Hyperlink { + + private final boolean important; + + private Hyperlink(boolean important) { + this.important = important; + } + + /** + * Check whether the hyperlink was created for a URI, and thus + * {@link #getURI()} will return a non-null value. + * + * @return Value true if the hyperlink was created using + * {@link #forURI(java.net.URI)} or {@link #forURI(java.net.URI, boolean)} + * method, false otherwise. + */ + public abstract boolean isForURI(); + + /** + * Check whether the hyperlink was created for a runnable, and thus + * {@link #getRunnable() ()} will return a non-null value. + * + * @return Value true if the hyperlink was created using + * {@link #onClick(java.lang.Runnable)} or + * {@link #forURI(java.net.URI, boolean)} method, false otherwise. + */ + public abstract boolean isOnClick(); + + /** + * Get the URI. + * + * @return A URI when the hyperlink was created for a URI, null otherwise. + * @see #isForURI() + */ + @NullUnknown + public abstract URI getURI(); + + /** + * Get the runnable. + * + * @return A runnable when the hyperlink was created for a runnable, null + * otherwise. + * @see #isOnClick() + */ + @NullUnknown + public abstract Runnable getRunnable(); + + /** + * @return True if the hyperlink has been marked as important, false if it + * is a standard link. + */ + public boolean isImportant() { + return important; + } + + /** + * Create a new hyperlink for specified URI. + * + * @param uri Hyperlink targed. + * + * @return The new hyperlink. + */ + @NonNull + public static Hyperlink forURI(@NonNull URI uri) { + return forURI(uri, false); + } + + /** + * Create a new hyperlink for specified {@link Runnable}, which will be + * invoked when the line is clicked. + * + * @param runnable The runnable to run on click. + * @return The new hyperlink. + */ + @NonNull + public static Hyperlink onClick(@NonNull Runnable runnable) { + return onClick(runnable, false); + } + + /** + * Create a new hyperlink for specified URI. + * + * @param uri Hyperlink targed. + * @param important True if the hyperlink should be handled as an important + * one, false if it is a standard one. + * + * @return The new hyperlink. + */ + @NonNull + public static Hyperlink forURI(@NonNull URI uri, boolean important) { + Parameters.notNull("uri", uri); + return new UriHyperlink(uri, important); + } + + /** + * Create a new hyperlink for specified {@link Runnable}, which will be + * invoked when the line is clicked. + * + * @param runnable The runnable to run on click. + * @param important True if the hyperlink should be handled as an important + * one, false if it is a standard one. + * @return The new hyperlink. + */ + @NonNull + public static Hyperlink onClick(@NonNull Runnable runnable, + boolean important) { + Parameters.notNull("runnable", runnable); + return new OnClickHyperlink(runnable, important); + } + + private static class OnClickHyperlink extends Hyperlink { + + private final Runnable runnable; + + public OnClickHyperlink(Runnable runnable, boolean important) { + super(important); + this.runnable = runnable; + } + + @Override + public boolean isForURI() { + return false; + } + + @Override + public boolean isOnClick() { + return true; + } + + @Override + public URI getURI() { + return null; + } + + @Override + public Runnable getRunnable() { + return this.runnable; + } + } + + private static class UriHyperlink extends Hyperlink { + + private final URI uri; + + public UriHyperlink(URI uri, boolean important) { + super(important); + this.uri = uri; + } + + @Override + public boolean isForURI() { + return true; + } + + @Override + public boolean isOnClick() { + return false; + } + + @Override + public URI getURI() { + return this.uri; + } + + @Override + public Runnable getRunnable() { + return null; + } + } +} diff --git a/api.io/src/org/netbeans/api/io/IOProvider.java b/api.io/src/org/netbeans/api/io/IOProvider.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/IOProvider.java @@ -0,0 +1,262 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.Reader; +import java.util.Collection; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.spi.io.InputOutputProvider; +import org.openide.util.Lookup; +import org.openide.util.Parameters; + +/** + * A factory for IO tabs shown in the output window. To create a new tab to + * write to, call e.g. + * IOProvider.getDefault().getIO("MyTab", false) (pass true if + * there may be an existing tab with the same name and you want to write to a + * new tab). + * + * @author Jesse Glick, Jaroslav Havlin + */ +public abstract class IOProvider { + + private IOProvider() { + } + + /** + * Get the default I/O provider. + *

+ * Normally this is taken from {@link Lookup#getDefault} but if there is no + * instance in lookup, a fallback instance is created which just uses the + * standard system I/O streams. This is useful for unit tests and perhaps + * for standalone usage of various libraries. + *

+ * + * @return The default instance (never null). + */ + @NonNull + public static IOProvider getDefault() { + InputOutputProvider def = Lookup.getDefault().lookup(InputOutputProvider.class); + if (def != null) { + return wrapProvider(def); + } else { + return wrapProvider(new Trivial()); + } + } + + private static IOProvider wrapProvider( + InputOutputProvider provider) { + + return new Impl(provider); + } + + /** + * Gets IOProvider of selected name or delegates to getDefault() if none was + * found. + * + * @param name ID of provider. + * @return The instance corresponding to provided name or default instance + * if not found. + */ + @NonNull + public static IOProvider get(@NonNull String name) { + Parameters.notNull("name", name); + + @SuppressWarnings("rawtypes") + Collection providers + = Lookup.getDefault().lookupAll(InputOutputProvider.class); + + for (InputOutputProvider p : providers) { + if (p.getName().equals(name)) { + return wrapProvider(p); + } + } + return getDefault(); + } + + /** + * Gets name (id) of provider. + * + * @return Name of this provider. + */ + @NonNull + public abstract String getName(); + + /** + * Get a named instance of InputOutput, which represents an output tab in + * the output window. Streams for reading/writing can be accessed via + * getters on the returned instance. + * + * @param name A localised display name for the tab. + * @param newIO If true, a new InputOutput is + * returned, else an existing InputOutput of the same name may + * be returned. + * @return An InputOutput instance for accessing the new tab. + * @see InputOutput + */ + @NonNull + public abstract InputOutput getIO(@NonNull String name, boolean newIO); + + /** + * Get a named instance of InputOutput, which represents an output tab in + * the output window. Streams for reading/writing can be accessed via + * getters on the returned instance. + * + * @param name A localised display name for the tab. + * @param newIO If true, a new InputOutput is + * returned, else an existing InputOutput of the same name may + * be returned. + * @param lookup Lookup which may contain additional information for various + * implementations of output window. + * @return An InputOutput instance for accessing the new tab. + * @see InputOutput + */ + @NonNull + public abstract InputOutput getIO(@NonNull String name, boolean newIO, + @NonNull Lookup lookup); + + /** + * Implementation of IOProvider that uses {@link InputOutputProvider} SPI + * internally. + * + * @param + * @param + */ + private static class Impl extends IOProvider { + + private final InputOutputProvider impl; + + public Impl(InputOutputProvider impl) { + this.impl = impl; + } + + @Override + public String getName() { + return impl.getName(); + } + + @Override + public InputOutput getIO(String name, boolean newIO) { + return getIO(name, newIO, Lookup.EMPTY); + } + + @Override + public InputOutput getIO(String name, boolean newIO, Lookup lookup) { + Parameters.notNull("name", name); + Parameters.notNull("lookup", lookup); + return InputOutput.create(impl, impl.getIO(name, newIO, lookup)); + } + } + + /** + * Trivial implementation of {@link IOProvider} that uses system input, + * output and error streams. + */ + private static class Trivial implements InputOutputProvider { + + @Override + public String getName() { + return "Trivial"; + } + + @Override + public Object getIO(String name, boolean newIO, Lookup lookup) { + return this; + } + + @Override + public Reader getIn(Object io) { + return new InputStreamReader(System.in); + } + + @Override + public PrintWriter getOut(Object io) { + return new PrintWriter(System.out); + } + + @Override + public PrintWriter getErr(Object io) { + return new PrintWriter(System.err); + } + + @Override + public void print(Object io, PrintWriter writer, String text, + Hyperlink link, OutputColor color, boolean printLineEnd) { + writer.print(text); + if (printLineEnd) { + writer.println(); + } + } + + @Override + public Lookup getIOLookup(Object io) { + return Lookup.EMPTY; + } + + @Override + public void resetIO(Object io) { + } + + @Override + public void selectIO(Object io) { + } + + @Override + public void showIO(Object io) { + } + + @Override + public void activateIO(Object io) { + } + + @Override + public void closeIO(Object io) { + } + + @Override + public boolean isIOClosed(Object io) { + return false; + } + } +} diff --git a/api.io/src/org/netbeans/api/io/InputOutput.java b/api.io/src/org/netbeans/api/io/InputOutput.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/InputOutput.java @@ -0,0 +1,275 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import java.io.PrintWriter; +import java.io.Reader; +import java.util.Collections; +import java.util.Map; +import java.util.WeakHashMap; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.spi.io.InputOutputProvider; +import org.openide.util.Lookup; + +/** + * An I/O connection to one tab on the Output Window. To acquire an instance to + * write to, call, e.g., + * IOProvider.getDefault().getInputOutput("someName", false). To + * get actual streams to write to, call getOut() or + * getErr() on the returned instance. + *

+ * Generally it is preferable not to hold a reference to an instance of + * {@link org.netbeans.api.io.InputOutput}, but rather to fetch it by name from + * {@link org.netbeans.api.io.IOProvider} as needed. + *

+ * + * @see OutputWriter + * @author Ian Formanek, Jaroslav Tulach, Petr Hamernik, Ales Novak, Jan + * Jancura, Jaroslav Havlin + */ +public abstract class InputOutput implements Lookup.Provider { + + private InputOutput() { + } + + /** + * Get a named instance of InputOutput from the default {@link IOProvider}, + * which represents an output tab in the output window. Streams for + * reading/writing can be accessed via getters on the returned instance. + * + *

+ * This is a shorthand for {@code IOProvider.getDefault().getIO(...)}. + *

+ * + * @param name A localised display name for the tab. + * @param newIO If true, a new InputOutput is + * returned, else an existing InputOutput of the same name may + * be returned. + * @return An InputOutput instance for accessing the new tab. + * @see IOProvider + */ + @NonNull + public static InputOutput get(@NonNull String name, boolean newIO) { + return IOProvider.getDefault().getIO(name, newIO); + } + + /** + * Get a named instance of InputOutput from the default {@link IOProvider}, + * which represents an output tab in the output window. Streams for + * reading/writing can be accessed via getters on the returned instance. + * + *

+ * This is a shorthand for {@code IOProvider.getDefault().getIO(...)}. + *

+ * + * @param name A localised display name for the tab. + * @param newIO If true, a new InputOutput is + * returned, else an existing InputOutput of the same name may + * be returned. + * @param lookup Lookup which may contain additional information for various + * implementations of output window. + * @return An InputOutput instance for accessing the new tab. + * @see IOProvider + */ + @NonNull + public static InputOutput get(@NonNull String name, boolean newIO, + @NonNull Lookup lookup) { + return IOProvider.getDefault().getIO(name, newIO, lookup); + } + + /** + * Get a reader to read from the tab. + * + * @return The reader. + */ + @NonNull + public abstract Reader getIn(); + + /** + * Acquire an output writer to write to the tab. + * + * @return The writer. + */ + @NonNull + public abstract OutputWriter getOut(); + + /** + * Get an output writer to write to the tab in error mode. This might show + * up in a different color than the regular output, e.g., or appear in a + * separate pane. + * + * @return The writer. + */ + @NonNull + public abstract OutputWriter getErr(); + + /** + * Clear the output pane. + */ + public abstract void reset(); + + /** + * Get lookup which may contain extensions provided by implementation of + * output window. + * + * @return The lookup. + */ + @NonNull + @Override + public abstract Lookup getLookup(); + + /** + * Closes this tab. The effect of calling any method on an instance of + * InputOutput after calling closeInputOutput() on it is + * undefined. + */ + public abstract void closeInputOutput(); + + /** + * Test whether this tab has been closed, either by a call to + * {@link #closeInputOutput()} or by the user closing the tab in the UI. + * + * @return Value true if it is closed. + */ + public abstract boolean isClosed(); + + /** + * Select this I/O, if possible (e.g. in tabbed pane). Do not open the + * output window if it is currently closed. + */ + public abstract void select(); + + /** + * Select and show this I/O, if possible (e.g. display minimized panel). + * Please note that this can be quite disturbing for the users, so please + * use with caution. + */ + public abstract void show(); + + /** + * Select, show and activate (focus) this I/O, if possible. Please note that + * this can be quite disturbing for the users, so please use with caution. + */ + public abstract void activate(); + + static InputOutput create( + InputOutputProvider provider, A io) { + + return new Impl(provider, io); + } + + private static class Impl extends InputOutput { + + private final Map cache + = Collections.synchronizedMap( + new WeakHashMap()); + + private final InputOutputProvider provider; + private final A ioObject; + + public Impl(InputOutputProvider provider, A ioObject) { + + this.provider = provider; + this.ioObject = ioObject; + } + + @Override + public Reader getIn() { + return provider.getIn(ioObject); + } + + @Override + public OutputWriter getOut() { + return createOrGetCachedWrapper(provider.getOut(ioObject)); + } + + @Override + public OutputWriter getErr() { + return createOrGetCachedWrapper(provider.getErr(ioObject)); + } + + @Override + @NonNull + public Lookup getLookup() { + return provider.getIOLookup(ioObject); + } + + @Override + public void reset() { + provider.resetIO(ioObject); + } + + private OutputWriter createOrGetCachedWrapper(B pw) { + OutputWriter ow = cache.get(pw); + if (ow == null) { + ow = OutputWriter.create(provider, ioObject, pw); + cache.put(pw, ow); + } + return ow; + } + + @Override + public void closeInputOutput() { + provider.closeIO(ioObject); + } + + @Override + public boolean isClosed() { + return provider.isIOClosed(ioObject); + } + + @Override + public void select() { + provider.selectIO(ioObject); + } + + @Override + public void show() { + provider.showIO(ioObject); + } + + @Override + public void activate() { + provider.activateIO(ioObject); + } + } +} diff --git a/api.io/src/org/netbeans/api/io/OutputColor.java b/api.io/src/org/netbeans/api/io/OutputColor.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/OutputColor.java @@ -0,0 +1,226 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.spi.io.InputOutputProvider; + +/** + * A color specified for part of text in output pane. It can be a predefined + * color for some type of text (success, debug, warning, failure), or arbitrary + * RGB color. + *

+ * Although using wide range of custom RGB colors may be tempting, predefined + * colors are recommended, as they can be configured to respect GUI theme in + * use. + *

+ * + * @author jhavlin + */ +public abstract class OutputColor { + + /** + * Type of the color - static (rgb) or dynamic. Visibility is public as it + * may be convenient for the implementators of {@link InputOutputProvider}. + *

+ * Note: New items may be added in the future. + *

+ */ + @SuppressWarnings("PublicInnerClass") + public enum Type { + WARNING, FAILURE, DEBUG, SUCCESS, RGB + } + + private final Type type; + private static final OutputColor CLR_WARNING = new TypeColor(Type.WARNING); + private static final OutputColor CLR_FAILURE = new TypeColor(Type.FAILURE); + private static final OutputColor CLR_DEBUG = new TypeColor(Type.DEBUG); + private static final OutputColor CLR_SUCCESS = new TypeColor(Type.SUCCESS); + + private OutputColor(Type type) { + this.type = type; + } + + /** + * Get RGB value for an {@link OutputColor} specified for a constant RGB + * color. + * + * @return RGB value of the color, or some undefined value if the + * {@link OutputColor} was created for a predefined color, not for constant + * RGB value. + */ + public abstract int getRGB(); + + /** + * Get type of this color. + * + * @return Some of predefined text types, or {@link Type#RGB} for colors + * created for constant RGB values. + */ + @NonNull + public Type getType() { + return this.type; + } + + /** + * Warning text color. + * + * @return Predefined color for text of type "warning". + */ + @NonNull + public static OutputColor warning() { + return CLR_WARNING; + } + + /** + * Failure text color. + * + * @return Predefined color for text of type "failure". + */ + @NonNull + public static OutputColor failure() { + return CLR_FAILURE; + } + + /** + * Debug text color. + * + * @return Predefined color for text of type "debug". + */ + @NonNull + public static OutputColor debug() { + return CLR_DEBUG; + } + + /** + * Success text color. + * + * @return Predefined color for text of type "success". + */ + @NonNull + public static OutputColor success() { + return CLR_SUCCESS; + } + + /** + * Arbitrary constant RGB color. + * + *

+ * Please note that it is recommended to use colors for predefined text + * types, which can respect color theme used by the GUI. + *

+ * + * @param r The red component, in the range (0 - 255). + * @param g The green component, in the range (0 - 255). + * @param b The blue component, in the range (0 - 255). + * + * @return Color specified for a constant RGB value. + * @throws IllegalArgumentException If some of color components is out of + * range. + */ + @NonNull + public static OutputColor rgb(int r, int g, int b) { + checkColorComponentRange("r", r); + checkColorComponentRange("g", g); + checkColorComponentRange("b", b); + int value = ((r & 0xFF) << 16) + | ((g & 0xFF) << 8) + | ((b & 0xFF)); + return rgb(value); + } + + /** + * Arbitrary constant RGB color. Creates an opaque sRGB color with the + * specified combined RGB value consisting of the red component in bits + * 16-23, the green component in bits 8-15, and the blue component in bits + * 0-7. + * + *

+ * Please note that it is recommended to use colors for predefined text + * types, which can respect color theme used by the GUI. + *

+ * + * @param rgbValue The combined RGB components. + * + * @return Color specified for a constant RGB value. + */ + @NonNull + public static OutputColor rgb(int rgbValue) { + return new RgbColor(rgbValue); + } + + private static void checkColorComponentRange(String name, + int colorComponent) { + + if (colorComponent < 0 || colorComponent > 255) { + throw new IllegalArgumentException("Color component " + name//NOI18N + + " is out of range (0 - 255): " + colorComponent); //NOI18N + } + } + + private static class TypeColor extends OutputColor { + + public TypeColor(Type type) { + super(type); + } + + @Override + public int getRGB() { + return 0; + } + } + + private static class RgbColor extends OutputColor { + + private final int value; + + public RgbColor(int value) { + super(Type.RGB); + this.value = value; + } + + @Override + public int getRGB() { + return value; + } + } +} diff --git a/api.io/src/org/netbeans/api/io/OutputWriter.java b/api.io/src/org/netbeans/api/io/OutputWriter.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/OutputWriter.java @@ -0,0 +1,307 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.Locale; +import org.netbeans.spi.io.InputOutputProvider; + +/** + * + * @author jhavlin + */ +public abstract class OutputWriter extends PrintWriter { + + private OutputWriter() { + super(new DummyWriter()); + } + + public abstract void print(String s, Hyperlink link, OutputColor color); + + public abstract void print(String s, Hyperlink link); + + public abstract void print(String s, OutputColor color); + + public abstract void println(String s, Hyperlink link, OutputColor color); + + public abstract void println(String s, Hyperlink link); + + public abstract void println(String s, OutputColor color); + + static OutputWriter create( + InputOutputProvider provider, A io, B writer) { + + return new Impl(provider, io, writer); + } + + private static class Impl extends OutputWriter { + + private final InputOutputProvider provider; + private final A io; + private final B writer; + + public Impl(InputOutputProvider provider, A io, B writer) { + this.provider = provider; + this.io = io; + this.writer = writer; + } + + @Override + public void print(String s, Hyperlink link, OutputColor color) { + provider.print(io, writer, s, link, color, false); + } + + @Override + public void print(String s, Hyperlink link) { + provider.print(io, writer, s, link, null, false); + } + + @Override + public void print(String s, OutputColor color) { + provider.print(io, writer, s, null, color, false); + } + + @Override + public void println(String s, Hyperlink link, OutputColor color) { + provider.print(io, writer, s, link, color, true); + } + + @Override + public void println(String s, Hyperlink link) { + provider.print(io, writer, s, link, null, true); + } + + @Override + public void println(String s, OutputColor color) { + provider.print(io, writer, s, null, color, true); + } + + @Override + public void flush() { + writer.flush(); + } + + @Override + public void close() { + writer.close(); + } + + @Override + public boolean checkError() { + return writer.checkError(); + } + + @Override + public void write(int c) { + writer.write(c); + } + + @Override + public void write(char[] buf, int off, int len) { + writer.write(buf, off, len); + } + + @Override + public void write(char[] buf) { + writer.write(buf); + } + + @Override + public void write(String s, int off, int len) { + writer.write(s, off, len); + } + + @Override + public void write(String s) { + writer.write(s); + } + + @Override + public void print(boolean b) { + writer.print(b); + } + + @Override + public void print(char c) { + writer.print(c); + } + + @Override + public void print(int i) { + writer.print(i); + } + + @Override + public void print(long l) { + writer.print(l); + } + + @Override + public void print(float f) { + writer.print(f); + } + + @Override + public void print(double d) { + writer.print(d); + } + + @Override + @SuppressWarnings("ImplicitArrayToString") + public void print(char[] s) { + writer.print(s); + } + + @Override + public void print(String s) { + writer.print(s); + } + + @Override + public void print(Object obj) { + writer.print(obj); + } + + @Override + public void println() { + writer.println(); + } + + @Override + public void println(boolean x) { + writer.println(x); + } + + @Override + public void println(char x) { + writer.println(x); + } + + @Override + public void println(int x) { + writer.println(x); + } + + @Override + public void println(long x) { + writer.println(x); + } + + @Override + public void println(float x) { + writer.println(x); + } + + @Override + public void println(double x) { + writer.println(x); + } + + @Override + @SuppressWarnings("ImplicitArrayToString") + public void println(char[] x) { + writer.println(x); + } + + @Override + public void println(String x) { + writer.println(x); + } + + @Override + public void println(Object x) { + writer.println(x); + } + + @Override + public PrintWriter printf(String format, Object... args) { + return writer.printf(format, args); + } + + @Override + public PrintWriter printf(Locale l, String format, Object... args) { + return writer.printf(l, format, args); + } + + @Override + public PrintWriter format(String format, Object... args) { + return writer.format(format, args); + } + + @Override + public PrintWriter format(Locale l, String format, Object... args) { + return writer.format(l, format, args); + } + + @Override + public PrintWriter append(CharSequence csq) { + return writer.append(csq); + } + + @Override + public PrintWriter append(CharSequence csq, int start, int end) { + return writer.append(csq, start, end); + } + + @Override + public PrintWriter append(char c) { + return writer.append(c); + } + } + + private static class DummyWriter extends Writer { + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + } + + @Override + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + } + } +} diff --git a/api.io/src/org/netbeans/spi/io/InputOutputProvider.java b/api.io/src/org/netbeans/spi/io/InputOutputProvider.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/spi/io/InputOutputProvider.java @@ -0,0 +1,231 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.spi.io; + +import java.io.PrintWriter; +import java.io.Reader; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; +import org.netbeans.api.io.Hyperlink; +import org.netbeans.api.io.InputOutput; +import org.netbeans.api.io.OutputColor; +import org.openide.util.Lookup; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * SPI for custom output window implementations. + *

+ * Use {@link ServiceProvider} annotation for registration. + *

+ * + * @author jhavlin + * + * @param Type of objects that will represent I/O instances (e.g. tabs in + * output window). + * @param Type of writers for standard and error streams. + */ +public interface InputOutputProvider { + + /** + * Get name of this provider. + * + * @return Name of this provider, never null. + */ + @NonNull + String getName(); + + /** + * Get or create an object that encapsulates state of a single I/O instance + * (e.g. tab in output window). + * + * @param name Display name of the output pane. + * @param newIO True to always create new I/O, false to return already + * existing instance if available. + * @param lookup Lookup with additional information. + * + * @return A single I/O instance, a newly created or already existing. + * @see InputOutput + */ + @NonNull + IO getIO(@NonNull String name, boolean newIO, @NonNull Lookup lookup); + + /** + * Get input of the passed I/O. + * + * @param io I/O instance. + * + * @return {@link} Reader for the input entered in the output pane. + */ + @NonNull + Reader getIn(@NonNull IO io); + + /** + * Get output stream of the passed I/O. + * + * @param io I/O instance. + * + * @return {@link PrintWriter} for the output stream. + */ + @NonNull + WRITER getOut(@NonNull IO io); + + /** + * Get error stream of the passed I/O. + * + * @param io The I/O instance. + * + * @return {@link PrintWriter} for the error stream. + */ + @NonNull + WRITER getErr(@NonNull IO io); + + /** + * Print enhanced text. It can represent a clickable hyperlink, and can be + * assigned some color. + * + *

+ * If the implementation doesn't support this feature, this method should + * call something like + * {@code writer.print(text); if (printLineEnd) {writer.println();}}. + *

+ * + * @param io The I/O instance. + * @param writer The Stream to write into. + * @param text Text to print. + * @param link Link which should be represented by the text, can be null for + * standard text. + * @param color Color of the text, can be null for the default color of the + * stream. + * @param printLineEnd True if new-line should be appended after printing + * {code text}. + */ + void print(@NonNull IO io, @NonNull WRITER writer, @NullAllowed String text, + @NullAllowed Hyperlink link, @NullAllowed OutputColor color, + boolean printLineEnd); + + /** + * Get lookup of an I/O instance, which can contain various extensions and + * additional info. + * + * @param io The I/O instance. + * + * @return The lookup, which can be empty, but never null. + */ + @NonNull + Lookup getIOLookup(@NonNull IO io); + + /** + * Reset the I/O. Clear previously written data and prepare it for new data. + *

+ * If the implementation doesn't support this feature, this method should do + * nothing. + *

+ * + * @param io The I/O instance. + */ + void resetIO(@NonNull IO io); + + /** + * Select the I/O instance, but do not show it if it is currently hidden. + * This is useful if several output panes are inside a tabbed pane, and the + * tab representing {@code io} should be selected. + *

+ * If the implementation doesn't support this feature, this method should do + * nothing. + *

+ * + * @param io The I/O instance. + * + * @see #showIO(java.lang.Object) + * @see #activateIO(java.lang.Object) + */ + void selectIO(IO io); + + /** + * Show output pane for the passed I/O instance. + *

+ * If the implementation doesn't support this feature, this method should do + * nothing. + *

+ * + * @param io The I/O instance. + * + * @see #selectIO(java.lang.Object) + * @see #activateIO(java.lang.Object) + */ + void showIO(IO io); + + /** + * Activate (focus) output pane for the passed I/O instance. + *

+ * If the implementation doesn't support this feature, this method can at + * least show the output pane, or do nothing. + *

+ * + * @param io The I/O instance. + * + * @see #selectIO(java.lang.Object) + * @see #showIO(java.lang.Object) + */ + void activateIO(IO io); + + /** + * Close the I/O, its output pane and release resources. + * + * @param io The I/O instance. + * + * @see #isIOClosed(java.lang.Object) + */ + void closeIO(IO io); + + /** + * Check whether the I/O is closed. + * + * @param io The I/O instance. + * + * @return True if the I/O was closed, false otherwise. + * + * @see #closeIO(java.lang.Object) + */ + boolean isIOClosed(IO io); +} diff --git a/api.io/src/org/netbeans/spi/io/Utilities.java b/api.io/src/org/netbeans/spi/io/Utilities.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/spi/io/Utilities.java @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.spi.io; + +import org.netbeans.spi.io.hyperlink.OpenUriHandler; +import java.net.URI; +import org.openide.util.Lookup; + +/** + * Utility methods for implementations of output window. + * + * @author jhavlin + */ +public final class Utilities { + + /** + * Handle the URI when a URI hyperlink is clicked in the output window. + * + * @param uri The URI to handle. + */ + public static void handleUri(URI uri) { + + for (OpenUriHandler handler + : Lookup.getDefault().lookupAll(OpenUriHandler.class)) { + + if (handler.handle(uri)) { + return; + } + } + } +} diff --git a/api.io/src/org/netbeans/spi/io/hyperlink/OpenUriHandler.java b/api.io/src/org/netbeans/spi/io/hyperlink/OpenUriHandler.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/spi/io/hyperlink/OpenUriHandler.java @@ -0,0 +1,68 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.spi.io.hyperlink; + +import java.net.URI; + +/** + * SPI for handlers that can process URI hyperlinks that were clicked in the + * Output Window. + * + * If the front-end and back-end of the application is separated, clicked URI + * hyperlinks can be handled on the front-end, possibly without any + * communication with the back-end. + * + * @author jhavlin + */ +public interface OpenUriHandler { + + /** + * Handle the passed URI, if it is supported by this handler. + * + * @param uri The URI to handle. + * + * @return True if the URI has been handled succesfully, false if this + * handler doesn't support it and thus it should be passed to next available + * handler. + */ + boolean handle(URI uri); +} diff --git a/api.io/test/unit/src/org/netbeans/api/io/HyperlinkTest.java b/api.io/test/unit/src/org/netbeans/api/io/HyperlinkTest.java new file mode 100644 --- /dev/null +++ b/api.io/test/unit/src/org/netbeans/api/io/HyperlinkTest.java @@ -0,0 +1,101 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import java.net.URI; +import java.net.URISyntaxException; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * + * @author jhavlin + */ +public class HyperlinkTest { + + @Test + public void testUriLink() throws URISyntaxException { + Hyperlink h = Hyperlink.forURI(new URI("file://x")); + assertTrue(h.isForURI()); + assertFalse(h.isOnClick()); + assertFalse(h.isImportant()); + assertNotNull(h.getURI()); + assertNull(h.getRunnable()); + assertEquals("file://x", h.getURI().toString()); + } + + @Test + public void testUriLinkImportant() throws URISyntaxException { + Hyperlink h = Hyperlink.forURI(new URI("file://x"), true); + assertTrue(h.isImportant()); + } + + @Test + public void testOnClickLink() { + + final boolean[] invoked = new boolean[1]; + Hyperlink h = Hyperlink.onClick(new Runnable() { + + @Override + public void run() { + invoked[0] = true; + } + }); + assertFalse(h.isForURI()); + assertTrue(h.isOnClick()); + assertFalse(h.isImportant()); + assertNull(h.getURI()); + assertNotNull(h.getRunnable()); + h.getRunnable().run(); + assertTrue("The passed code should be invoked", invoked[0]); + } + + @Test + public void testOnClickLinkImportant() { + Hyperlink h = Hyperlink.onClick(new Runnable() { + @Override + public void run() { + } + }, true); + assertTrue(h.isImportant()); + } +} diff --git a/api.io/test/unit/src/org/netbeans/api/io/IOProviderTest.java b/api.io/test/unit/src/org/netbeans/api/io/IOProviderTest.java new file mode 100644 --- /dev/null +++ b/api.io/test/unit/src/org/netbeans/api/io/IOProviderTest.java @@ -0,0 +1,252 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import java.io.PrintWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import org.junit.Test; +import static org.junit.Assert.*; +import org.netbeans.junit.MockServices; +import org.netbeans.spi.io.InputOutputProvider; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; + +/** + * + * @author jhavlin + */ +public class IOProviderTest { + + public IOProviderTest() { + } + + @Test + public void useCase1() { + InputOutput io = IOProvider.getDefault().getIO("UseCase1", true); + io.getOut().println("This is a simple output"); + io.getOut().close(); + } + + @Test + public void useCase2() throws URISyntaxException { + InputOutput io = IOProvider.getDefault().getIO("UseCase2", false); + io.getOut().print("A line containing a "); + io.getOut().print("hyperlink", Hyperlink.forURI(new URI( + "file://n:/test/Test.java?line=4&col=2"))); + io.getOut().println(" for a URI."); + io.getOut().close(); + } + + @Test + public void useCase3() { + InputOutput io = IOProvider.getDefault().getIO("UseCase3", true); + io.getOut().print("A line containing a "); + io.getOut().print("hyperlink", Hyperlink.onClick(new Runnable() { + @Override + public void run() { + System.gc(); + } + })); + io.getOut().println(" for invokation of custom code."); + io.getOut().close(); + } + + @Test + public void useCase4() { + InputOutput io = IOProvider.getDefault().getIO("UseCase4", true); + io.getOut().println("Let's print some info", OutputColor.debug()); + io.getOut().println("or warning with appropriate color", + OutputColor.warning()); + io.getOut().println("Maybe also text with custom reddish color", + OutputColor.rgb(255, 16, 16)); + io.getOut().close(); + } + + @Test + public void useCase5() { + InputOutput io = IOProvider.getDefault().getIO("UseCase5", true); + io.getOut().println("Let's print some text"); + io.getErr().println("and reset the pane immediately."); + io.reset(); + io.getOut().println("The pane is now empty and we can reuse it simply"); + io.getOut().close(); + } + + @Test + public void testTrivialImplementationAlwaysAvailable() { + assertEquals("Trivial", IOProvider.getDefault().getName()); + assertEquals("Trivial", IOProvider.get("Trivial").getName()); + assertEquals("Trivial", IOProvider.get("Another").getName()); + } + + @Test + public void testGetFromLookup() { + MockServices.setServices(MockInputOutputProvider.class); + try { + assertEquals("mock", IOProvider.getDefault().getName()); + assertEquals("mock", IOProvider.get("mock").getName()); + assertEquals("mock", IOProvider.get("wrong").getName()); + } finally { + MockServices.setServices(); + } + } + + @Test + public void testAllMethodsAreDelegatedToSPI() { + MockServices.setServices(MockInputOutputProvider.class); + try { + IOProvider.getDefault().getIO("test1", true); + Lookup lkp = IOProvider.getDefault() + .getIO("test1", false, Lookup.EMPTY).getLookup(); + CalledMethodList list = lkp.lookup(CalledMethodList.class); + assertEquals("getIO", list.get(0)); + assertEquals("getIO", list.get(1)); + assertEquals("getIOLookup", list.get(2)); + assertEquals(3, list.size()); + } finally { + MockServices.setServices(); + } + } + + @SuppressWarnings("PackageVisibleInnerClass") + static class CalledMethodList extends ArrayList { + } + + @SuppressWarnings("PublicInnerClass") + public static class MockInputOutputProvider implements + InputOutputProvider { + + private final CalledMethodList calledMethods = new CalledMethodList(); + private final StringWriter stringWriter = new StringWriter(); + private final Lookup lookup = Lookups.fixed(calledMethods, stringWriter); + + @Override + public String getName() { + return "mock"; + } + + @Override + public Object getIO(String name, boolean newIO, Lookup lookup) { + calledMethods.add("getIO"); + return new Object(); + } + + @Override + public Reader getIn(Object io) { + calledMethods.add("getIn"); + return new StringReader(""); + } + + @Override + public PrintWriter getOut(Object io) { + calledMethods.add("getOut"); + return new PrintWriter(stringWriter); + } + + @Override + public PrintWriter getErr(Object io) { + calledMethods.add("getErr"); + return new PrintWriter(stringWriter); + } + + @Override + public void print(Object io, PrintWriter writer, String text, + Hyperlink link, OutputColor color, boolean printLineEnd) { + if (link != null || color != null) { + stringWriter.append(""); + } + stringWriter.append(text); + if (link != null || color != null) { + stringWriter.append(""); + } + calledMethods.add("print"); + if (printLineEnd) { + stringWriter.append(System.getProperty("line.separator")); + } + } + + @Override + public Lookup getIOLookup(Object io) { + calledMethods.add("getIOLookup"); + return lookup; + } + + @Override + public void resetIO(Object io) { + calledMethods.add("resetIO"); + } + + @Override + public void selectIO(Object io) { + calledMethods.add("selectIO"); + } + + @Override + public void showIO(Object io) { + calledMethods.add("showIO"); + } + + @Override + public void activateIO(Object io) { + calledMethods.add("activateIO"); + } + + @Override + public void closeIO(Object io) { + calledMethods.add("closeIO"); + } + + @Override + public boolean isIOClosed(Object io) { + calledMethods.add("isIOClosed"); + return false; + } + } +} diff --git a/api.io/test/unit/src/org/netbeans/api/io/InputOutputTest.java b/api.io/test/unit/src/org/netbeans/api/io/InputOutputTest.java new file mode 100644 --- /dev/null +++ b/api.io/test/unit/src/org/netbeans/api/io/InputOutputTest.java @@ -0,0 +1,91 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import org.junit.Test; +import static org.junit.Assert.*; +import org.netbeans.junit.MockServices; +import org.openide.util.Lookup; + +/** + * + * @author jhavlin + */ +public class InputOutputTest { + + public InputOutputTest() { + } + + @Test + public void testAllMethodsAreDelegatedToSPI() { + MockServices.setServices(IOProviderTest.MockInputOutputProvider.class); + try { + InputOutput io = IOProvider.getDefault().getIO("test1", true); + io.getIn(); + io.getOut(); + io.getErr(); + io.select(); + io.show(); + io.activate(); + io.reset(); + io.isClosed(); + io.closeInputOutput(); + Lookup lkp = io.getLookup(); + IOProviderTest.CalledMethodList list + = lkp.lookup(IOProviderTest.CalledMethodList.class); + + assertEquals("getIO", list.get(0)); + assertEquals("getIn", list.get(1)); + assertEquals("getOut", list.get(2)); + assertEquals("getErr", list.get(3)); + assertEquals("selectIO", list.get(4)); + assertEquals("showIO", list.get(5)); + assertEquals("activateIO", list.get(6)); + assertEquals("resetIO", list.get(7)); + assertEquals("isIOClosed", list.get(8)); + assertEquals("closeIO", list.get(9)); + assertEquals("getIOLookup", list.get(10)); + } finally { + MockServices.setServices(); + } + } +} diff --git a/api.io/test/unit/src/org/netbeans/api/io/OutputColorTest.java b/api.io/test/unit/src/org/netbeans/api/io/OutputColorTest.java new file mode 100644 --- /dev/null +++ b/api.io/test/unit/src/org/netbeans/api/io/OutputColorTest.java @@ -0,0 +1,89 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author jhavlin + */ +public class OutputColorTest { + + @Test + public void testRgbColor() { + OutputColor c = OutputColor.rgb(127, 255, 1); + assertEquals(OutputColor.Type.RGB, c.getType()); + int value = c.getRGB(); + int r = value >> 16; + int g = value >> 8 & 0xFF; + int b = value & 0xFF; + assertEquals(127, r); + assertEquals(255, g); + assertEquals(1, b); + } + + @Test + public void testWarningColor() { + OutputColor c = OutputColor.warning(); + assertEquals(OutputColor.Type.WARNING, c.getType()); + } + + @Test + public void testFailureColor() { + OutputColor c = OutputColor.failure(); + assertEquals(OutputColor.Type.FAILURE, c.getType()); + } + + @Test + public void testDebugColor() { + OutputColor c = OutputColor.debug(); + assertEquals(OutputColor.Type.DEBUG, c.getType()); + } + + @Test + public void testSuccessColor() { + OutputColor c = OutputColor.success(); + assertEquals(OutputColor.Type.SUCCESS, c.getType()); + } +} diff --git a/api.io/test/unit/src/org/netbeans/api/io/OutputWriterTest.java b/api.io/test/unit/src/org/netbeans/api/io/OutputWriterTest.java new file mode 100644 --- /dev/null +++ b/api.io/test/unit/src/org/netbeans/api/io/OutputWriterTest.java @@ -0,0 +1,105 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.api.io; + +import java.io.StringWriter; +import java.net.URI; +import java.net.URISyntaxException; +import org.junit.Test; +import static org.junit.Assert.*; +import org.netbeans.junit.MockServices; +import org.openide.util.Lookup; + +/** + * + * @author jhavlin + */ +public class OutputWriterTest { + + public OutputWriterTest() { + } + + @Test + public void testAllMethodsAreDelegatedToSPI() throws URISyntaxException { + MockServices.setServices(IOProviderTest.MockInputOutputProvider.class); + try { + + InputOutput io = IOProvider.getDefault().getIO("test1", true); + OutputWriter ow = io.getOut(); + Lookup lkp = io.getLookup(); + + ow.print("Line"); + ow.print(" 1"); + ow.println(); + + ow.print("Hyperlink ", Hyperlink.forURI(new URI("file://x"))); + ow.print(" "); + ow.print("Color", OutputColor.debug()); + ow.print(" "); + ow.print("Color link", Hyperlink.forURI(new URI("file://y")), + OutputColor.debug()); + ow.println(); + + ow.println("Line with link", Hyperlink.forURI(new URI("file://z"))); + ow.println("Color line", OutputColor.debug()); + ow.println("Color line with link", + Hyperlink.forURI(new URI("file://a")), OutputColor.debug()); + + StringWriter sw = lkp.lookup(StringWriter.class); + sw.toString(); + + String[] lines = sw.toString().split( + System.getProperty("line.separator")); + + assertEquals("Line 1", lines[0]); + assertEquals("Hyperlink Color " + + "Color link", lines[1]); + assertEquals("Line with link", lines[2]); + assertEquals("Color line", lines[3]); + assertEquals("Color line with link", lines[4]); + + } finally { + MockServices.setServices(); + } + } + +} diff --git a/core.output2/manifest.mf b/core.output2/manifest.mf --- a/core.output2/manifest.mf +++ b/core.output2/manifest.mf @@ -2,7 +2,7 @@ OpenIDE-Module: org.netbeans.core.output2/1 OpenIDE-Module-Layer: org/netbeans/core/output2/layer.xml OpenIDE-Module-Localizing-Bundle: org/netbeans/core/output2/Bundle.properties -OpenIDE-Module-Provides: org.openide.windows.IOProvider +OpenIDE-Module-Provides: org.openide.windows.IOProvider org.netbeans.api.io.IOProvider AutoUpdate-Essential-Module: true OpenIDE-Module-Specification-Version: 1.38 diff --git a/core.output2/nbproject/project.xml b/core.output2/nbproject/project.xml --- a/core.output2/nbproject/project.xml +++ b/core.output2/nbproject/project.xml @@ -50,6 +50,14 @@ org.netbeans.core.output2 + org.netbeans.api.io + + + + 1.0 + + + org.netbeans.modules.options.api diff --git a/core.output2/src/org/netbeans/core/output2/BridgeUtils.java b/core.output2/src/org/netbeans/core/output2/BridgeUtils.java new file mode 100644 --- /dev/null +++ b/core.output2/src/org/netbeans/core/output2/BridgeUtils.java @@ -0,0 +1,133 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 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): + * + * Portions Copyrighted 2014 Sun Microsystems, Inc. + */ +package org.netbeans.core.output2; + +import java.awt.Color; +import org.netbeans.api.io.Hyperlink; +import org.netbeans.api.io.OutputColor; +import org.netbeans.spi.io.Utilities; +import org.openide.windows.IOColors; +import org.openide.windows.InputOutput; +import org.openide.windows.OutputEvent; +import org.openide.windows.OutputListener; + +/** + * Utilities for bridging from openide.io to api.io APIs. + * + * @author jhavlin + */ +public class BridgeUtils { + + /** + * Convert a hyperlink to an output listener. + * + * @param link The hyperlink. + * @return The wrapping output listener. + */ + public static OutputListener hyperlinkToOutputListener(final Hyperlink link) { + if (link == null) { + return null; + } else if (link.isOnClick()) { + return new OutputListenerAdapter() { + + @Override + public void outputLineAction(OutputEvent ev) { + link.getRunnable().run(); + } + }; + } else if (link.isForURI()) { + return new OutputListenerAdapter() { + + @Override + public void outputLineAction(OutputEvent ev) { + Utilities.handleUri(link.getURI()); + } + }; + } else { + return null; + } + } + + /** + * Convert AWT-independent {@link OutputColor} to {@link java.awt.Color}. + * + * @return Appropriate color, or null if default color should be used. + */ + public static Color outputColorToAwtColor(InputOutput io, OutputColor color) { + if (color == null) { + return null; + } + if (color.getType().equals(OutputColor.Type.RGB)) { + return new Color(color.getRGB()); + } else if (IOColors.isSupported(io)) { + switch (color.getType()) { + case DEBUG: + return IOColors.getColor(io, IOColors.OutputType.LOG_DEBUG); + case FAILURE: + return IOColors.getColor(io, IOColors.OutputType.LOG_FAILURE); + case WARNING: + return IOColors.getColor(io, IOColors.OutputType.LOG_WARNING); + case SUCCESS: + return IOColors.getColor(io, IOColors.OutputType.LOG_SUCCESS); + default: + return null; + } + } else { + return null; + } + } + + private static class OutputListenerAdapter implements OutputListener { + + @Override + public void outputLineSelected(OutputEvent ev) { + } + + @Override + public void outputLineAction(OutputEvent ev) { + } + + @Override + public void outputLineCleared(OutputEvent ev) { + } + } +} diff --git a/core.output2/src/org/netbeans/core/output2/NbIOProvider.java b/core.output2/src/org/netbeans/core/output2/NbIOProvider.java --- a/core.output2/src/org/netbeans/core/output2/NbIOProvider.java +++ b/core.output2/src/org/netbeans/core/output2/NbIOProvider.java @@ -44,22 +44,53 @@ package org.netbeans.core.output2; +import java.awt.Color; import java.io.IOException; +import java.io.Reader; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import java.util.WeakHashMap; import javax.swing.Action; +import org.netbeans.api.io.Hyperlink; +import org.netbeans.api.io.OutputColor; +import org.netbeans.spi.io.InputOutputProvider; import org.openide.util.Exceptions; +import org.openide.util.Lookup; import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; +import org.openide.util.lookup.ServiceProviders; +import org.openide.windows.IOColorLines; +import org.openide.windows.IOColorPrint; import org.openide.windows.IOContainer; import org.openide.windows.IOProvider; +import org.openide.windows.IOSelect; import org.openide.windows.InputOutput; +import org.openide.windows.OutputListener; import org.openide.windows.OutputWriter; /** * Supplies Output Window implementation through Lookup. * @author Jesse Glick, Tim Boudreau */ -@org.openide.util.lookup.ServiceProvider(service=org.openide.windows.IOProvider.class, position=100) -public final class NbIOProvider extends IOProvider { +@ServiceProviders({ + @ServiceProvider(service=IOProvider.class, position=100), + @ServiceProvider(service=InputOutputProvider.class, position=100) +}) +public final class NbIOProvider extends IOProvider + implements InputOutputProvider { + + private static final Set OPS_ACTIVATE; + private static final Set OPS_SELECT; + + static { + OPS_ACTIVATE = new HashSet(Arrays.asList( + IOSelect.AdditionalOperation.OPEN, + IOSelect.AdditionalOperation.REQUEST_VISIBLE, + IOSelect.AdditionalOperation.REQUEST_ACTIVE)); + OPS_SELECT = Collections.emptySet(); + } private static final WeakHashMap containerPairMaps = new WeakHashMap(); @@ -140,6 +171,105 @@ return result; } + @Override + public InputOutput getIO(String name, boolean newIO, Lookup lookup) { + Action[] action = lookup.lookup(Action[].class); + IOContainer ioContainer = lookup.lookup(IOContainer.class); + return getIO(name, newIO, action, ioContainer); + } + + @Override + public Reader getIn(InputOutput io) { + return io.getIn(); + } + + @Override + public OutputWriter getOut(InputOutput io) { + return io.getOut(); + } + + @Override + public OutputWriter getErr(InputOutput io) { + return io.getErr(); + } + + @Override + public void print(InputOutput io, OutputWriter writer, String text, + Hyperlink link, OutputColor outputColor, boolean printLineEnd) { + + Color awtColor = BridgeUtils.outputColorToAwtColor(io, outputColor); + OutputListener listener = BridgeUtils.hyperlinkToOutputListener(link); + boolean listenerImportant = link != null && link.isImportant(); + try { + if (printLineEnd && outputColor == null) { + writer.println(text, listener, listenerImportant); + } else if (printLineEnd && IOColorLines.isSupported(io)) { + IOColorLines.println(io, text, listener, listenerImportant, + awtColor); + } else if (IOColorPrint.isSupported(io)) { + IOColorPrint.print(io, text, listener, listenerImportant, + awtColor); + if (printLineEnd) { + writer.println(); + } + } else if (printLineEnd) { + writer.println(text); + } else { + writer.print(text); + } + } catch (IOException ex) { + // Ignored by the new API. + } + } + + @Override + public Lookup getIOLookup(InputOutput io) { + if (io instanceof Lookup.Provider) { + return ((Lookup.Provider) io).getLookup(); + } else { + return Lookup.EMPTY; + } + } + + @Override + public void resetIO(InputOutput io) { + try { + io.getOut().reset(); + } catch (IOException ex) { + // Ignored by the new API. + } + } + + @Override + public void selectIO(InputOutput io) { + if (IOSelect.isSupported(io)) { + IOSelect.select(io, OPS_SELECT); + } + } + + @Override + public void showIO(InputOutput io) { + io.select(); + } + + @Override + public void activateIO(InputOutput io) { + if (IOSelect.isSupported(io)) { + IOSelect.select(io, OPS_ACTIVATE); + } else { + io.select(); + } + } + + @Override + public void closeIO(InputOutput io) { + io.closeInputOutput(); + } + + @Override + public boolean isIOClosed(InputOutput io) { + return io.isClosed(); + } static void dispose (NbIO io) { IOContainer ioContainer = io.getIOContainer(); diff --git a/nbbuild/build.properties b/nbbuild/build.properties --- a/nbbuild/build.properties +++ b/nbbuild/build.properties @@ -100,6 +100,7 @@ config.javadoc.stable=\ api.annotations.common,\ api.html4j,\ + api.io,\ api.maven,\ autoupdate.services,\ autoupdate.ui,\ diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties --- a/nbbuild/cluster.properties +++ b/nbbuild/cluster.properties @@ -195,6 +195,7 @@ nb.cluster.platform=\ api.annotations.common,\ api.html4j,\ + api.io,\ api.progress,\ api.progress.compat8,\ api.progress.nb,\ diff --git a/openide.io/nbproject/org-openide-io.sig b/openide.io/nbproject/org-openide-io.sig --- a/openide.io/nbproject/org-openide-io.sig +++ b/openide.io/nbproject/org-openide-io.sig @@ -1,5 +1,5 @@ #Signature file v4.1 -#Version 1.45 +#Version 1.44.1 CLSS public abstract interface java.io.Closeable intf java.lang.AutoCloseable diff --git a/openide.io/nbproject/project.xml b/openide.io/nbproject/project.xml --- a/openide.io/nbproject/project.xml +++ b/openide.io/nbproject/project.xml @@ -59,19 +59,11 @@ - org.openide.util - - - - 9.0 - - - org.openide.util.base - 9.0 + 9.1