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,1172 @@ + + +]> + + + + + &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();
+            
+
+ + +

+ 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.from(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. + + + + + + +

+ Normal module dependency is enough. +

+

+ Availability of some implementation of the SPI is guaranteed by + "OpenIDE-Module-Needs: org.netbeans.spi.io.InputOutputProvider" in + the manifest of this module. +

+
+ + + + + +

+ Just the module JAR. +

+
+ + + + + +

+ Yes. +

+
+ + + + + +

+ No; only API classes are public. +

+
+ + + + + +

+ Anywhere. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ No. +

+
+ + + + + +

+ API classes are thread safe, they mostly represent immutable + objects, or delegate to the SPI. +

+

+ Implementators of the SPI should ensure that their code is properly + synchronized, as it can be called from any thread. +

+
+ + + + + +

+ 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 +OpenIDE-Module-Needs: org.netbeans.spi.io.InputOutputProvider 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,54 @@ + + + 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 + org.netbeans.spi.io.support + + + + 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 writing 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/Fold.java b/api.io/src/org/netbeans/api/io/Fold.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/Fold.java @@ -0,0 +1,131 @@ +/* + * 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 org.netbeans.spi.io.InputOutputProvider; + +/** + * A fold (nested or standalone) in the output window. + * + *

+ * Methods of this class can be called in any thread. + *

+ * + * @author jhavlin + */ +public abstract class Fold { + + static final Fold UNSUPPORTED = new Fold() { + + @Override + public void setExpanded(boolean expanded) { + } + + @Override + void endFold() { + } + }; + + private Fold() { + } + + static Fold create( + InputOutputProvider provider, IO io, OW writer, + F fold) { + if (fold == null) { + return UNSUPPORTED; + } else { + return new Impl(provider, io, writer, fold); + } + } + + /** + * Set fold expansion state. + * + * @param expanded True to expand the fold, false to collapse it. + */ + public abstract void setExpanded(boolean expanded); + + abstract void endFold(); + + /** + * Expand the fold. + */ + public final void expand() { + setExpanded(true); + } + + /** + * Collapse the fold. + */ + public final void collapse() { + setExpanded(false); + } + + private static class Impl extends Fold { + + private final InputOutputProvider provider; + private final IO io; + private final OW writer; + private final F fold; + + public Impl(InputOutputProvider provider, IO io, + OW writer, F fold) { + + this.provider = provider; + this.io = io; + this.writer = writer; + this.fold = fold; + } + + @Override + public void setExpanded(boolean expanded) { + provider.setFoldExpanded(io, writer, fold, expanded); + } + + @Override + void endFold() { + provider.endFold(io, writer, fold); + } + } +} 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,116 @@ +/* + * 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.modules.io.HyperlinkAccessor; +import org.openide.util.Parameters; + +/** + * Hyperlink in output window. It can be specified by 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; + } + + static { + HyperlinkAccessor.setDefault(new HyperlinkAccessorImpl()); + } + + /** + * @return True if the hyperlink has been marked as important, false if it + * is a standard link. + */ + boolean isImportant() { + return 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. + * @return The new hyperlink. + */ + @NonNull + public static Hyperlink from(@NonNull Runnable runnable) { + return from(runnable, 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. + * @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 from(@NonNull Runnable runnable, + boolean important) { + Parameters.notNull("runnable", runnable); + return new OnClickHyperlink(runnable, important); + } + + @SuppressWarnings("PackageVisibleInnerClass") + static class OnClickHyperlink extends Hyperlink { + + private final Runnable runnable; + + public OnClickHyperlink(Runnable runnable, boolean important) { + super(important); + this.runnable = runnable; + } + + public Runnable getRunnable() { + return runnable; + } + } +} diff --git a/api.io/src/org/netbeans/api/io/HyperlinkAccessorImpl.java b/api.io/src/org/netbeans/api/io/HyperlinkAccessorImpl.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/HyperlinkAccessorImpl.java @@ -0,0 +1,77 @@ +/* + * 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.modules.io.HyperlinkAccessor; +import org.netbeans.spi.io.support.HyperlinkType; + +/** + * Implementation of accessor that enables retrieving information about + * hyperlinks in SPI. + * + * @author jhavlin + */ +class HyperlinkAccessorImpl extends HyperlinkAccessor { + + @Override + public HyperlinkType getType(Hyperlink hyperlink) { + if (hyperlink instanceof Hyperlink.OnClickHyperlink) { + return HyperlinkType.FROM_RUNNABLE; + } else { + throw new IllegalArgumentException("Unknown hyperlink."); //NOI18N + } + } + + @Override + public boolean isImportant(Hyperlink hyperlink) { + return hyperlink.isImportant(); + } + + @Override + public Runnable getRunnable(Hyperlink hyperlink) { + if (hyperlink instanceof Hyperlink.OnClickHyperlink) { + return ((Hyperlink.OnClickHyperlink) hyperlink).getRunnable(); + } else { + throw new IllegalArgumentException("Not an ON_CLICK link.");//NOI18N + } + } +} 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,296 @@ +/* + * 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 java.util.Set; +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). + * + *

+ * Methods of this class can be called in any thread. + *

+ * + * @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 id ID of provider. + * @return The instance corresponding to provided name or default instance + * if not found. + */ + @NonNull + public static IOProvider get(@NonNull String id) { + Parameters.notNull("id", id); + + @SuppressWarnings("rawtypes") + Collection providers + = Lookup.getDefault().lookupAll(InputOutputProvider.class); + + for (InputOutputProvider p : providers) { + if (p.getId().equals(id)) { + return wrapProvider(p); + } + } + return getDefault(); + } + + /** + * Gets identifier of this provider. + * + * @return Name of this provider. + */ + @NonNull + public abstract String getId(); + + /** + * 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 + * @param + */ + private static class Impl + extends IOProvider { + + private final InputOutputProvider impl; + + public Impl(InputOutputProvider impl) { + this.impl = impl; + } + + @Override + public String getId() { + return impl.getId(); + } + + @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 getId() { + 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 showIO(Object io, + Set operations) { + } + + @Override + public void closeIO(Object io) { + } + + @Override + public boolean isIOClosed(Object io) { + return false; + } + + @Override + public Void getCurrentPosition(Object io, PrintWriter writer) { + return null; + } + + @Override + public void scrollTo(Object io, PrintWriter writer, Void position) { + } + + @Override + public Void startFold(Object io, PrintWriter writer, boolean expanded) { + return null; + } + + @Override + public void endFold(Object io, PrintWriter writer, Void fold) { + } + + @Override + public void setFoldExpanded(Object io, PrintWriter writer, Void fold, + boolean expanded) { + } + + @Override + public String getIODescription(Object io) { + return null; + } + + @Override + public void setIODescription(Object io, String description) { + } + } +} 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,314 @@ +/* + * 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.EnumSet; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import org.netbeans.api.annotations.common.CheckForNull; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; +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. + *

+ * + *

+ * Methods of this class can be called in any thread. + *

+ * + * @see OutputWriter + * @author Ian Formanek, Jaroslav Tulach, Petr Hamernik, Ales Novak, Jan + * Jancura, Jaroslav Havlin + */ +public abstract class InputOutput implements Lookup.Provider { + + private static final Set DEFAULT_SHOW_OPERATIONS + = EnumSet.of(ShowOperation.OPEN, ShowOperation.MAKE_VISIBLE); + + 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 close() on it is + * undefined. + */ + public abstract void close(); + + /** + * Test whether this tab has been closed, either by a call to + * {@link #close()} or by the user closing the tab in the UI. + * + * @return Value true if it is closed. + */ + public abstract boolean isClosed(); + + /** + * Get description of this I/O instance. + * + * @return The description, or null if not set. + */ + @CheckForNull + public abstract String getDescription(); + + /** + * Set description of this I/O instance. It can be used e.g. as tooltip for + * output tab in the GUI. + * + * @param description The description, can be null. + */ + public abstract void setDescription(@NullAllowed String description); + + static InputOutput create( + InputOutputProvider provider, IO io) { + + return new Impl(provider, io); + } + + /** + * Show this I/O if possible (e.g. in tabbed pane). + *

+ * Calling this method is the same as calling: + *

+ *
+     * show(EnumSet.of(ShowOperation.OPEN, ShowOperation.MAKE_VISIBLE));
+     * 
+ * + * @see #show(java.util.Set) + */ + public final void show() { + show(DEFAULT_SHOW_OPERATIONS); + } + + /** + * Show this I/O if possible (e.g. in tabbed pane). + * + * @param operations Set of operations that should be invoked to show the + * output. If the set is empty or null, pane for this I/O will be only + * selected, but its component will not be opened or made visible. So it + * will stay closed or hidden if it is not opened or not visible. + * + * @see ShowOperation + */ + public abstract void show(@NullAllowed Set operations); + + private static class Impl + extends InputOutput { + + private final Map cache + = Collections.synchronizedMap( + new WeakHashMap()); + + private final InputOutputProvider provider; + private final IO ioObject; + + public Impl(InputOutputProvider provider, IO 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(OW pw) { + OutputWriter ow = cache.get(pw); + if (ow == null) { + ow = OutputWriter.create(provider, ioObject, pw); + cache.put(pw, ow); + } + return ow; + } + + @Override + public void close() { + provider.closeIO(ioObject); + } + + @Override + public boolean isClosed() { + return provider.isIOClosed(ioObject); + } + + @Override + public String getDescription() { + return provider.getIODescription(ioObject); + } + + @Override + public void setDescription(String description) { + provider.setIODescription(ioObject, description); + } + + @Override + public void show(Set operations) { + provider.showIO(ioObject, + operations != null + ? operations + : Collections.emptySet()); + } + } +} 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,198 @@ +/* + * 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.spi.io.support.OutputColorType; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.modules.io.OutputColorAccessor; + +/** + * 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 { + + + private final OutputColorType type; + private static final OutputColor CLR_WARNING = new TypeColor(OutputColorType.WARNING); + private static final OutputColor CLR_FAILURE = new TypeColor(OutputColorType.FAILURE); + private static final OutputColor CLR_DEBUG = new TypeColor(OutputColorType.DEBUG); + private static final OutputColor CLR_SUCCESS = new TypeColor(OutputColorType.SUCCESS); + + static { + OutputColorAccessor.setDefault(new OutputColorAccessorImpl()); + } + + private OutputColor(OutputColorType type) { + this.type = type; + } + + OutputColorType getType() { + return 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(OutputColorType type) { + super(type); + } + } + + @SuppressWarnings("PackageVisibleInnerClass") + static class RgbColor extends OutputColor { + + private final int value; + + public RgbColor(int value) { + super(OutputColorType.RGB); + this.value = value; + } + + public int getRGB() { + return value; + } + } +} diff --git a/api.io/src/org/netbeans/api/io/OutputColorAccessorImpl.java b/api.io/src/org/netbeans/api/io/OutputColorAccessorImpl.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/OutputColorAccessorImpl.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.api.io; + +import org.netbeans.modules.io.OutputColorAccessor; +import org.netbeans.spi.io.support.OutputColorType; + +/** + * Implementation of accessor that enables retrieving information about output + * colors in SPI. + * + * @author jhavlin + */ +class OutputColorAccessorImpl extends OutputColorAccessor{ + + @Override + public OutputColorType getType(OutputColor color) { + return color.getType(); + } + + @Override + public int getRgb(OutputColor color) { + if (color instanceof OutputColor.RgbColor) { + return ((OutputColor.RgbColor) color).getRGB(); + } else { + throw new IllegalArgumentException("Not an RGB color."); //NOI18N + } + } +} 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,366 @@ +/* + * 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.Collections; +import java.util.EnumSet; +import java.util.Locale; +import java.util.Set; +import org.netbeans.api.annotations.common.NullAllowed; +import org.netbeans.spi.io.InputOutputProvider; + +/** + * Extended {@link PrintWriter} for writing into output window or similar output + * GUI component. It can support features like color printing, hyperlinks, or + * folding. + * + *

+ * Methods of this class can be called in any thread. + *

+ * + * @author jhavlin + */ +public abstract class OutputWriter extends PrintWriter { + + private OutputWriter() { + super(new DummyWriter()); + } + + /** + * Get current position in the output stream. + * + * @return The position. + */ + public abstract Position getCurrentPosition(); + + /** + * Start a new fold. If a fold already exists, a nested fold will be + * created. + * + * @param expanded True if the fold should be expanded by default, false if + * it should be collapsed. + * + * @return The fold handle. + */ + public abstract Fold startFold(boolean expanded); + + /** + * Finish a fold. If it contains some unfinished nested folds, they will be + * finished as well. + * + * @param fold The fold to finish. + */ + public abstract void endFold(Fold fold); + + 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, IO io, OW writer) { + + return new Impl(provider, io, writer); + } + + private static class Impl + extends OutputWriter { + + private final InputOutputProvider provider; + private final IO io; + private final OW writer; + + public Impl(InputOutputProvider provider, + IO io, OW writer) { + + this.provider = provider; + this.io = io; + this.writer = writer; + } + + @Override + public Position getCurrentPosition() { + return Position.create(provider, io, writer, + provider.getCurrentPosition(io, 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); + } + + @Override + public Fold startFold(boolean expanded) { + F fold = provider.startFold(io, writer, expanded); + return Fold.create(provider, io, writer, fold); + } + + @Override + public void endFold(Fold fold) { + if (fold != Fold.UNSUPPORTED) { + fold.endFold(); + } + } + } + + 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/api/io/Position.java b/api.io/src/org/netbeans/api/io/Position.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/Position.java @@ -0,0 +1,106 @@ +/* + * 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 org.netbeans.spi.io.InputOutputProvider; + +/** + * + * Stored position in the output window. + * + *

+ * Methods of this class can be called in any thread. + *

+ * + * @author jhavlin + */ +public abstract class Position { + + static final Position UNSUPPORTED = new Position() { + + @Override + public void scrollTo() { + } + }; + + private Position() { + } + + /** + * Scroll to this position. + */ + public abstract void scrollTo(); + + static Position create( + InputOutputProvider provider, IO io, + OW writer, P position) { + + if (position == null) { + return UNSUPPORTED; + } else { + return new Impl(provider, io, writer, position); + } + } + + private static class Impl + extends Position { + + private final InputOutputProvider provider; + private final IO io; + private final OW ow; + private final P position; + + public Impl(InputOutputProvider provider, IO io, OW ow, + P position) { + this.provider = provider; + this.io = io; + this.ow = ow; + this.position = position; + } + + @Override + public void scrollTo() { + provider.scrollTo(io, ow, position); + } + } +} diff --git a/api.io/src/org/netbeans/api/io/ShowOperation.java b/api.io/src/org/netbeans/api/io/ShowOperation.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/api/io/ShowOperation.java @@ -0,0 +1,65 @@ +/* + * 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; + +/** + * Operations that should take part when showing a component. The actual + * behavior depends on implementation (some features may be unsupported). + * + * @author jhavlin + */ +public enum ShowOperation { + /** + * Open the GUI component (Output Window) if it is closed. + */ + OPEN, + /** + * Make the GUI component (Output Window) visible. E.g. show it if it is + * minimized. + */ + MAKE_VISIBLE, + /** + * Activate the GUI component (Output Window). E.g. highlight and possibly + * focus it. + */ + ACTIVATE +} diff --git a/api.io/src/org/netbeans/modules/io/HyperlinkAccessor.java b/api.io/src/org/netbeans/modules/io/HyperlinkAccessor.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/modules/io/HyperlinkAccessor.java @@ -0,0 +1,86 @@ +/* + * 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.modules.io; + +import org.netbeans.api.io.Hyperlink; +import org.netbeans.spi.io.support.HyperlinkType; + +/** + * + * @author jhavlin + */ +public abstract class HyperlinkAccessor { + + /** + * The default implementation is set in static initializer of + * {@link Hyperlink}. + */ + private static HyperlinkAccessor DEFAULT; + + public static void setDefault(HyperlinkAccessor def) { + HyperlinkAccessor.DEFAULT = def; + } + + public static HyperlinkAccessor getDefault() { + if (DEFAULT != null) { + return DEFAULT; + } + + // invokes static initializer of Item.class + // that will assign value to the DEFAULT field above + Class c = Hyperlink.class; + try { + Class.forName(c.getName(), true, c.getClassLoader()); + } catch (ClassNotFoundException ex) { + assert false : ex; + } + assert DEFAULT != null : + "The DEFAULT field must be initialized"; //NOI18N + return DEFAULT; + } + + public abstract HyperlinkType getType(Hyperlink hyperlink); + + public abstract boolean isImportant(Hyperlink hyperlink); + + public abstract Runnable getRunnable(Hyperlink hyperlink); +} diff --git a/api.io/src/org/netbeans/modules/io/OutputColorAccessor.java b/api.io/src/org/netbeans/modules/io/OutputColorAccessor.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/modules/io/OutputColorAccessor.java @@ -0,0 +1,84 @@ +/* + * 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.modules.io; + +import org.netbeans.api.io.OutputColor; +import org.netbeans.spi.io.support.OutputColorType; + +/** + * + * @author jhavlin + */ +public abstract class OutputColorAccessor { + + /** + * The default implementation is set in static initializer of + * {@link OutputColor}. + */ + private static OutputColorAccessor DEFAULT; + + public static void setDefault(OutputColorAccessor def) { + OutputColorAccessor.DEFAULT = def; + } + + public static OutputColorAccessor getDefault() { + if (DEFAULT != null) { + return DEFAULT; + } + + // invokes static initializer of Item.class + // that will assign value to the DEFAULT field above + Class c = OutputColor.class; + try { + Class.forName(c.getName(), true, c.getClassLoader()); + } catch (ClassNotFoundException ex) { + assert false : ex; + } + assert DEFAULT != null : + "The DEFAULT field must be initialized"; //NOI18N + return DEFAULT; + } + + public abstract OutputColorType getType(OutputColor color); + + public abstract int getRgb(OutputColor color); +} 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,329 @@ +/* + * 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 java.util.Set; +import org.netbeans.api.annotations.common.CheckForNull; +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.netbeans.api.io.ShowOperation; +import org.openide.util.Lookup; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * SPI for custom output window implementations. + *

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

+ * + *

+ * Note: Methods of this interface can be called in any thread by the + * infrastructure, so implementations should ensure proper synchronization. + *

+ * + * @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. + * @param Type of object that describes position of a character in the + * output window. If the implementation does not support this type of + * information, use {@link Void} here. + * @param Type of object that describes a fold in output window. If the + * implementation does not support this type of information, use {@link Void} + * here. + */ +public interface InputOutputProvider { + + /** + * Get identifier of this provider. + * + * @return Name of this provider, never null. + */ + @NonNull + String getId(); + + /** + * 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} 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); + + /** + * 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. + * @param operations Operations that should be performed to show the output. + * If the set is empty, the output pane (e.g. tab) can be selected, but no + * GUI component should be shown or made visible if it is currently closed + * or hidden. + * + * @see ShowOperation + */ + void showIO(@NonNull IO io, + Set operations); + + /** + * Close the I/O, its output pane and release resources. + * + * @param io The I/O instance. + * + * @see #isIOClosed(java.lang.Object) + */ + void closeIO(@NonNull 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(@NonNull IO io); + + /** + * Get current position. + * + * @param io The I/O instance. + * @param writer Output or error writer. If the streams are merged, the + * value can be ignored. + * + * @return The current position in the output pane. If this feature is not + * supported, return null. + */ + @CheckForNull + POS getCurrentPosition(@NonNull IO io, @NonNull WRITER writer); + + /** + * Scroll to a position. + *

+ * If this feature is not supported + * ({@link #getCurrentPosition(Object, PrintWriter)} returns null), this + * method should do nothing, it will be never called. + *

+ * + * @param io The I/O instance. + * @param writer Output or error writer. If the streams are merged, the + * value can be ignored. + * @param position The position to scroll to. + * + * @see #getCurrentPosition(java.lang.Object, java.io.PrintWriter) + */ + void scrollTo(@NonNull IO io, @NonNull WRITER writer, + @NonNull POS position); + + /** + * Start fold at the current position. If a fold is already open, start a + * new nested fold (but if a fold with the same start position already + * exists, no nested fold will be created, and the same start position will + * be returned). + * + * @param io The I/O instance. + * @param writer Output or error writer. If the streams are merged, the + * value can be ignored. + * @param expanded True if the new fold should be expanded by default, false + * if it should be collapsed. + * + * @return Object the fold. If the implementation doesn't support this + * feature, return null. + */ + @CheckForNull + FOLD startFold(@NonNull IO io, @NonNull WRITER writer, boolean expanded); + + /** + * Finish a fold specified by its start position. If some nested folds + * exist, they will be finished as well if needed. + * + *

+ * If this feature is not supported + * ({@link #startFold(Object, PrintWriter, boolean)} returns null), this + * method should do nothing, it will be never called. + *

+ * + * @param io The I/O instance. + * @param writer Output or error writer. If the streams are merged, the + * value can be ignored. + * @param fold The fold to finish. + */ + void endFold(@NonNull IO io, @NonNull WRITER writer, + @NonNull FOLD fold); + + /** + * Expand or collapse a fold. + * + *

+ * If this feature is not supported + * ({@link #startFold(Object, PrintWriter, boolean)} returns null), this + * method should do nothing, it will be never called. + *

+ * + * @param io The I/O instance. + * @param writer Output or error writer. If the streams are merged, the + * value can be ignored. + * @param fold The fold to finish. + * @param expanded True to expand the fold, false to collapse the fold. + */ + void setFoldExpanded(@NonNull IO io, @NonNull WRITER writer, + FOLD fold, boolean expanded); + + + /** + * Get description of an I/O instance. It can be used e.g. as tooltip text + * for the output tab. + * + * @param io The I/O instance. + * + * @return The description, or null if not set. + */ + @CheckForNull String getIODescription(@NonNull IO io); + + /** + * Set description of an I/O instance. + * + *

+ * If this feature is not supported, this method should do nothing. + *

+ * + * @param io The I/O instance. + * @param description The description, can be null. + * + * @see #getIODescription(java.lang.Object) + */ + void setIODescription(@NonNull IO io, @NullAllowed String description); +} diff --git a/api.io/src/org/netbeans/spi/io/support/HyperlinkType.java b/api.io/src/org/netbeans/spi/io/support/HyperlinkType.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/spi/io/support/HyperlinkType.java @@ -0,0 +1,54 @@ +/* + * 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.support; + +/** + * Type of the hyperlink. + *

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

+ * + * @author jhavlin + */ +public enum HyperlinkType { + FROM_RUNNABLE +} diff --git a/api.io/src/org/netbeans/spi/io/support/Hyperlinks.java b/api.io/src/org/netbeans/spi/io/support/Hyperlinks.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/spi/io/support/Hyperlinks.java @@ -0,0 +1,97 @@ +/* + * 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.support; + +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.io.Hyperlink; +import org.netbeans.modules.io.HyperlinkAccessor; + +/** + * Helper class for accessing information from {@link Hyperlink} objects. + * + * @author jhavlin + */ +public final class Hyperlinks { + + private Hyperlinks() { + } + + /** + * Get hyperlink type. + * + * @param hyperlink The hyperlink to get type of. + * @return The type of the hyperlink. + */ + @NonNull + public static HyperlinkType getType(@NonNull Hyperlink hyperlink) { + return HyperlinkAccessor.getDefault().getType(hyperlink); + } + + /** + * Check whether a hyperlink is important. + * + * @param hyperlink The hyperlink to check. + * + * @return True if the hyperlink has been marked as important, false if it + * is a standard link. + */ + public static boolean isImportant(@NonNull Hyperlink hyperlink) { + return HyperlinkAccessor.getDefault().isImportant(hyperlink); + } + + /** + * Get runnable associated with a hyperlink of type + * {@link HyperlinkType#FROM_RUNNABLE}. + * + * @param hyperlink The hyperlink to get runnable from. + * + * @return A runnable. + * @throws IllegalArgumentException if type of the hyperlink is not + * {@link HyperlinkType#FROM_RUNNABLE}. + * @see #getType(org.netbeans.api.io.Hyperlink) + * @see HyperlinkType + */ + @NonNull + public static Runnable getRunnable(@NonNull Hyperlink hyperlink) { + return HyperlinkAccessor.getDefault().getRunnable(hyperlink); + } +} diff --git a/api.io/src/org/netbeans/spi/io/support/OutputColorType.java b/api.io/src/org/netbeans/spi/io/support/OutputColorType.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/spi/io/support/OutputColorType.java @@ -0,0 +1,54 @@ +/* + * 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.support; + +/** + * Type of the color - static (rgb) or dynamic. + *

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

+ * + * @author jhavlin + */ +public enum OutputColorType { + WARNING, FAILURE, DEBUG, SUCCESS, RGB +} diff --git a/api.io/src/org/netbeans/spi/io/support/OutputColors.java b/api.io/src/org/netbeans/spi/io/support/OutputColors.java new file mode 100644 --- /dev/null +++ b/api.io/src/org/netbeans/spi/io/support/OutputColors.java @@ -0,0 +1,83 @@ +/* + * 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.support; + +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.io.OutputColor; +import org.netbeans.modules.io.OutputColorAccessor; + +/** + * Helper class for accessing information from {@link OutputColor} objects. + * + * @author jhavlin + */ +public final class OutputColors { + + private OutputColors() { + } + + /** + * Get type of a color. + * + * @param color The color to get type of. + * @return Type of color. + */ + @NonNull + public static OutputColorType getType(@NonNull OutputColor color) { + return OutputColorAccessor.getDefault().getType(color); + } + + /** + * Get RGB value for an {@link OutputColor} specified for a constant RGB + * color (type {@link OutputColorType#RGB}). + * + * @param color The color to get RGB value for. + * + * @return RGB value of the color. + * @throws IllegalArgumentException if the color is not of type + * {@link OutputColorType#RGB}. + */ + public static int getRGB(OutputColor color) { + return OutputColorAccessor.getDefault().getRgb(color); + } + +} 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,82 @@ +/* + * 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 static org.junit.Assert.*; +import org.junit.Test; +import org.netbeans.spi.io.support.HyperlinkType; +import org.netbeans.spi.io.support.Hyperlinks; + +/** + * + * @author jhavlin + */ +public class HyperlinkTest { + + @Test + public void testOnClickLink() { + + final boolean[] invoked = new boolean[1]; + Hyperlink h = Hyperlink.from(new Runnable() { + + @Override + public void run() { + invoked[0] = true; + } + }); + assertTrue(Hyperlinks.getType(h) == HyperlinkType.FROM_RUNNABLE); + assertFalse(h.isImportant()); + assertNotNull(Hyperlinks.getRunnable(h)); + Hyperlinks.getRunnable(h).run(); + assertTrue("The passed code should be invoked", invoked[0]); + } + + @Test + public void testOnClickLinkImportant() { + Hyperlink h = Hyperlink.from(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,286 @@ +/* + * 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.util.ArrayList; +import java.util.Set; +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() { + InputOutput io = IOProvider.getDefault().getIO("UseCase2", false); + io.getOut().print("A line containing a "); + io.getOut().print("hyperlink", Hyperlink.from(new Runnable() { + + @Override + public void run() { + // some action + } + })); + 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.from(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().getId()); + assertEquals("Trivial", IOProvider.get("Trivial").getId()); + assertEquals("Trivial", IOProvider.get("Another").getId()); + } + + @Test + public void testGetFromLookup() { + MockServices.setServices(MockInputOutputProvider.class); + try { + assertEquals("mock", IOProvider.getDefault().getId()); + assertEquals("mock", IOProvider.get("mock").getId()); + assertEquals("mock", IOProvider.get("wrong").getId()); + } 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 getId() { + 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 showIO(Object io, + Set operations) { + calledMethods.add("showIO"); + } + + @Override + public void closeIO(Object io) { + calledMethods.add("closeIO"); + } + + @Override + public boolean isIOClosed(Object io) { + calledMethods.add("isIOClosed"); + return false; + } + + @Override + public Object getCurrentPosition(Object io, PrintWriter writer) { + calledMethods.add("getCurrentPosition"); + return new Object(); + } + + @Override + public void scrollTo(Object io, PrintWriter writer, Object position) { + calledMethods.add("scrollTo"); + } + + @Override + public Object startFold(Object io, PrintWriter writer, boolean expanded) { + calledMethods.add("startFold"); + return new Object(); + } + + @Override + public void endFold(Object io, PrintWriter writer, Object foldNumber) { + calledMethods.add("endFold"); + } + + @Override + public void setFoldExpanded(Object io, PrintWriter writer, + Object foldNumber, boolean expanded) { + calledMethods.add("setFoldExpanded"); + } + + @Override + public String getIODescription(Object io) { + calledMethods.add("getIODescription"); + return null; + } + + @Override + public void setIODescription(Object io, String description) { + calledMethods.add("setIODescription"); + } + } +} 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 + @SuppressWarnings("ValueOfIncrementOrDecrementUsed") + public void testAllMethodsAreDelegatedToSPI() { + MockServices.setServices(IOProviderTest.MockInputOutputProvider.class); + try { + InputOutput io = IOProvider.getDefault().getIO("test1", true); + io.getIn(); + io.getOut(); + io.getErr(); + io.reset(); + io.isClosed(); + io.close(); + io.getDescription(); + io.setDescription(null); + Lookup lkp = io.getLookup(); + IOProviderTest.CalledMethodList list + = lkp.lookup(IOProviderTest.CalledMethodList.class); + + int order = 0; + assertEquals("getIO", list.get(order++)); + assertEquals("getIn", list.get(order++)); + assertEquals("getOut", list.get(order++)); + assertEquals("getErr", list.get(order++)); + assertEquals("resetIO", list.get(order++)); + assertEquals("isIOClosed", list.get(order++)); + assertEquals("closeIO", list.get(order++)); + assertEquals("getIODescription", list.get(order++)); + assertEquals("setIODescription", list.get(order++)); + assertEquals("getIOLookup", list.get(order++)); + } 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,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.netbeans.spi.io.support.OutputColorType; +import org.junit.Test; +import static org.junit.Assert.*; +import org.netbeans.spi.io.support.OutputColors; + +/** + * + * @author jhavlin + */ +public class OutputColorTest { + + @Test + public void testRgbColor() { + OutputColor c = OutputColor.rgb(127, 255, 1); + assertEquals(OutputColorType.RGB, OutputColors.getType(c)); + int value = OutputColors.getRGB(c); + 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(OutputColorType.WARNING, c.getType()); + } + + @Test + public void testFailureColor() { + OutputColor c = OutputColor.failure(); + assertEquals(OutputColorType.FAILURE, c.getType()); + } + + @Test + public void testDebugColor() { + OutputColor c = OutputColor.debug(); + assertEquals(OutputColorType.DEBUG, c.getType()); + } + + @Test + public void testSuccessColor() { + OutputColor c = OutputColor.success(); + assertEquals(OutputColorType.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,134 @@ +/* + * 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 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 + @SuppressWarnings("ValueOfIncrementOrDecrementUsed") + public void testAllMethodsAreDelegatedToSPI() { + MockServices.setServices(IOProviderTest.MockInputOutputProvider.class); + try { + + InputOutput io = IOProvider.getDefault().getIO("test1", true); + OutputWriter ow = io.getOut(); + Lookup lkp = io.getLookup(); + + IOProviderTest.CalledMethodList list + = lkp.lookup(IOProviderTest.CalledMethodList.class); + + io.show(); + Position p = ow.getCurrentPosition(); + p.scrollTo(); + Fold f = ow.startFold(true); + f.expand(); + f.collapse(); + ow.endFold(f); + + int order = 0; + assertEquals("getIO", list.get(order++)); + assertEquals("getOut", list.get(order++)); + assertEquals("getIOLookup", list.get(order++)); + assertEquals("showIO", list.get(order++)); + assertEquals("getCurrentPosition", list.get(order++)); + assertEquals("scrollTo", list.get(order++)); + assertEquals("startFold", list.get(order++)); + assertEquals("setFoldExpanded", list.get(order++)); + assertEquals("setFoldExpanded", list.get(order++)); + assertEquals("endFold", list.get(order++)); + + ow.print("Line"); + ow.print(" 1"); + ow.println(); + + Runnable runnable = new Runnable() { + + @Override + public void run() { + } + }; + + ow.print("Hyperlink ", Hyperlink.from(runnable)); + ow.print(" "); + ow.print("Color", OutputColor.debug()); + ow.print(" "); + ow.print("Color link", Hyperlink.from(runnable), + OutputColor.debug()); + ow.println(); + + ow.println("Line with link", Hyperlink.from(runnable)); + ow.println("Color line", OutputColor.debug()); + ow.println("Color line with link", + Hyperlink.from(runnable), 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.spi.io.InputOutputProvider 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 @@ -111,7 +119,7 @@ - 1.40 + 1.47 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 @@ -47,8 +47,12 @@ import java.io.IOException; import java.util.WeakHashMap; import javax.swing.Action; +import org.netbeans.spi.io.InputOutputProvider; import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; +import org.openide.util.lookup.ServiceProviders; +import org.openide.windows.BridgingIOProvider; import org.openide.windows.IOContainer; import org.openide.windows.IOProvider; import org.openide.windows.InputOutput; @@ -58,8 +62,12 @@ * 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 BridgingIOProvider { + private static final WeakHashMap containerPairMaps = new WeakHashMap(); 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/nbbuild/javadoctools/links.xml b/nbbuild/javadoctools/links.xml --- a/nbbuild/javadoctools/links.xml +++ b/nbbuild/javadoctools/links.xml @@ -240,3 +240,4 @@ + diff --git a/nbbuild/javadoctools/properties.xml b/nbbuild/javadoctools/properties.xml --- a/nbbuild/javadoctools/properties.xml +++ b/nbbuild/javadoctools/properties.xml @@ -239,3 +239,4 @@ + diff --git a/nbbuild/javadoctools/replaces.xml b/nbbuild/javadoctools/replaces.xml --- a/nbbuild/javadoctools/replaces.xml +++ b/nbbuild/javadoctools/replaces.xml @@ -239,3 +239,4 @@ + diff --git a/openide.io/apichanges.xml b/openide.io/apichanges.xml --- a/openide.io/apichanges.xml +++ b/openide.io/apichanges.xml @@ -107,6 +107,24 @@ + + + Create a provider abstract class that implements new I/O SPI + + + + + +

+ As new API and SPI for output windows has been introduced, it is + useful to have a convenient way for implementators of the original + API to support the new API as well. The BridgingIOProvider class + implements both SPIs, and its JavaDoc explains how to use it. +

+
+ + +
Created new user-friendly methods for working with FoldHandle instances. diff --git a/openide.io/manifest.mf b/openide.io/manifest.mf --- a/openide.io/manifest.mf +++ b/openide.io/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.openide.io -OpenIDE-Module-Specification-Version: 1.46 +OpenIDE-Module-Specification-Version: 1.47 OpenIDE-Module-Localizing-Bundle: org/openide/io/Bundle.properties OpenIDE-Module-Recommends: org.openide.windows.IOProvider, org.openide.windows.IOContainer$Provider AutoUpdate-Essential-Module: true 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,11 +59,11 @@
- org.openide.util + org.netbeans.api.io - 9.0 + 1.0 @@ -71,7 +71,7 @@ - 9.0 + 9.1 diff --git a/openide.io/src/org/openide/windows/BridgingIOProvider.java b/openide.io/src/org/openide/windows/BridgingIOProvider.java new file mode 100644 --- /dev/null +++ b/openide.io/src/org/openide/windows/BridgingIOProvider.java @@ -0,0 +1,378 @@ +/* + * 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.openide.windows; + +import java.awt.Color; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.EnumSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.Action; +import org.netbeans.api.io.Hyperlink; +import org.netbeans.api.io.OutputColor; +import org.netbeans.api.io.ShowOperation; +import org.netbeans.spi.io.support.Hyperlinks; +import org.netbeans.spi.io.InputOutputProvider; +import org.netbeans.spi.io.support.OutputColorType; +import org.netbeans.spi.io.support.OutputColors; +import org.openide.util.Lookup; +import org.openide.util.lookup.ServiceProvider; +import org.openide.util.lookup.ServiceProviders; +import org.openide.windows.IOColors.OutputType; +import org.openide.windows.IOPosition.Position; + +/** + * Abstract class for easy support of {@link InputOutputProvider}, the SPI for + * the new I/O API. + *

+ * This class is useful if you have a custom implementation of Output Window, + * which uses SPI contained in this module ({@link IOProvider} and related + * interfaces), and want to your implementation also accessible via the new I/O + * API in module api.io. + *

+ *

+ * To start supporting the new API: + *

+ *
    + *
  1. Add dependency on module api.io (I/O API ans SPI, + * org.netbeans.api.io)
  2. + *
  3. Make your I/O provider extend {@link BridgingIOProvider} instead of + * {@link IOProvider}
  4. + *
  5. Add {@link ServiceProvider} annotation for {@link InputOutputProvider}, + * {@link ServiceProviders} will be needed to allow multiple services: + *
    + *
    + *  @ServiceProviders({
    + *    @ServiceProvider(service=IOProvider.class, position=900),
    + *    @ServiceProvider(service=InputOutputProvider.class, position=900)
    + *  })
    + * public final class MyIOProvider extends BridgingIOProvider { ... }
    + * 
    + *
  6. + *
  7. If needed, override some of the method to improve performance.
  8. + *
+ * + * @author jhavlin + */ +public abstract class BridgingIOProvider extends IOProvider + implements InputOutputProvider { + + private static final Logger LOG + = Logger.getLogger(BridgingIOProvider.class.getName()); + + private final Deque foldStack = new ArrayDeque(); + + @Override + public String getId() { + return getName(); + } + + @Override + public InputOutput getIO(String name, boolean newIO, Lookup lookup) { + Action[] actions = lookup.lookup(Action[].class); + IOContainer container = lookup.lookup(IOContainer.class); + if (container == null && actions == null) { + return getIO(name, newIO); + } else if (newIO) { + if (container != null && actions != null) { + return getIO(name, actions, container); + } else if (actions != null) { + return getIO(name, actions); + } else { + return getIO(name, new Action[0], container); + } + } else { + return getIO(name, newIO, actions == null ? new Action[0] : actions, + container); + } + } + + @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 = outputColorToAwtColor(io, outputColor); + OutputListener listener = hyperlinkToOutputListener(link); + boolean listenerImportant = link != null && Hyperlinks.isImportant(link); + 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) { + LOG.log(Level.FINE, "Cannot print color or hyperlink", ex); //NOI18N + } + } + + @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) { + LOG.log(Level.FINE, "Cannot reset InputOutput.", ex); //NOI18N + } + } + + @Override + public void showIO(InputOutput io, + Set operations) { + if (operations.contains(ShowOperation.OPEN) + && operations.contains(ShowOperation.MAKE_VISIBLE) + && operations.size() == 2) { + io.select(); + } else { + IOSelect.select(io, showOperationsToIoSelect(operations)); + } + } + + /** + * Translate set of {@link ShowOperation}s to set of + * {@link IOSelect.AdditionalOperation}s. + */ + private Set showOperationsToIoSelect( + Set operations) { + Set res + = EnumSet.noneOf(IOSelect.AdditionalOperation.class); + for (ShowOperation so : operations) { + switch (so) { + case OPEN: + res.add(IOSelect.AdditionalOperation.OPEN); + break; + case MAKE_VISIBLE: + res.add(IOSelect.AdditionalOperation.REQUEST_VISIBLE); + break; + case ACTIVATE: + res.add(IOSelect.AdditionalOperation.REQUEST_ACTIVE); + break; + } + } + return res; + } + + @Override + public void closeIO(InputOutput io) { + io.closeInputOutput(); + } + + @Override + public boolean isIOClosed(InputOutput io) { + return io.isClosed(); + } + + @Override + public Position getCurrentPosition(InputOutput io, OutputWriter writer) { + if (IOPosition.isSupported(io)) { + return IOPosition.currentPosition(io); + } else { + return null; + } + } + + @Override + public void scrollTo(InputOutput io, OutputWriter writer, Position position) { + position.scrollTo(); + } + + @Override + public FoldHandle startFold(InputOutput io, OutputWriter writer, + boolean expanded) { + + if (IOFolding.isSupported(io)) { + synchronized (foldStack) { + if (foldStack.isEmpty()) { + foldStack.addLast(IOFolding.startFold(io, expanded)); + } else { + foldStack.addLast(foldStack.getLast().startFold(expanded)); + } + return foldStack.getLast(); + } + } else { + return null; + } + } + + @Override + public void endFold(InputOutput io, OutputWriter writer, FoldHandle fold) { + synchronized (foldStack) { + while (!foldStack.isEmpty()) { + if (foldStack.removeLast() == fold) { + break; + } + } + fold.silentFinish(); + } + } + + @Override + public void setFoldExpanded(InputOutput io, OutputWriter writer, + FoldHandle fold, boolean expanded) { + fold.setExpanded(expanded); + } + + @Override + public String getIODescription(InputOutput io) { + if (IOTab.isSupported(io)) { + return IOTab.getToolTipText(io); + } else { + return null; + } + } + + @Override + public void setIODescription(InputOutput io, String description) { + if (IOTab.isSupported(io)) { + IOTab.setToolTipText(io, description); + } + } + + /** + * Convert a hyperlink to an output listener. + * + * @param link The hyperlink. + * @return The wrapping output listener. + */ + private static OutputListener hyperlinkToOutputListener( + final Hyperlink link) { + + if (link == null) { + return null; + } + switch (Hyperlinks.getType(link)) { + case FROM_RUNNABLE: + return new OutputListenerAdapter() { + @Override + public void outputLineAction(OutputEvent ev) { + Hyperlinks.getRunnable(link).run(); + } + }; + default: + return null; + } + } + + /** + * Convert AWT-independent {@link OutputColor} to {@link java.awt.Color}. + * + * @return Appropriate color, or null if default color should be used. + */ + private static Color outputColorToAwtColor(InputOutput io, + OutputColor color) { + + if (color == null) { + return null; + } + OutputColorType type = OutputColors.getType(color); + if (type == OutputColorType.RGB) { + return new Color(OutputColors.getRGB(color)); + } else if (IOColors.isSupported(io)) { + switch (type) { + case DEBUG: + return IOColors.getColor(io, OutputType.LOG_DEBUG); + case FAILURE: + return IOColors.getColor(io, OutputType.LOG_FAILURE); + case WARNING: + return IOColors.getColor(io, OutputType.LOG_WARNING); + case SUCCESS: + return IOColors.getColor(io, 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) { + } + } +}