diff --git a/src/main/java/org/scijava/AbstractGateway.java b/src/main/java/org/scijava/AbstractGateway.java index 0b55b646d..166aac342 100644 --- a/src/main/java/org/scijava/AbstractGateway.java +++ b/src/main/java/org/scijava/AbstractGateway.java @@ -98,7 +98,8 @@ public void launch(final String... args) { final int mainCount = main().execMains(); // display the user interface (NB: does not block) - if (mainCount == 0 && !ui().isHeadless()) ui().showUI(); + // NB: When running headless, the HeadlessUI will be used. + if (mainCount == 0) ui().showUI(); if (ui().isHeadless()) { // now that CLI processing/execution is done, we can shut down diff --git a/src/main/java/org/scijava/ui/DefaultUIService.java b/src/main/java/org/scijava/ui/DefaultUIService.java index 66f81401c..dfde08f9d 100644 --- a/src/main/java/org/scijava/ui/DefaultUIService.java +++ b/src/main/java/org/scijava/ui/DefaultUIService.java @@ -62,7 +62,7 @@ import org.scijava.ui.DialogPrompt.OptionType; import org.scijava.ui.DialogPrompt.Result; import org.scijava.ui.event.UIShownEvent; -import org.scijava.ui.headlessUI.HeadlessUI; +import org.scijava.ui.headless.HeadlessUI; import org.scijava.ui.viewer.DisplayViewer; /** @@ -176,7 +176,6 @@ public boolean isVisible(final String name) { return ui.isVisible(); } - @Override public void setHeadless(final boolean headless) { System.setProperty("java.awt.headless", String.valueOf(headless)); diff --git a/src/main/java/org/scijava/ui/headless/HeadlessDisplayViewer.java b/src/main/java/org/scijava/ui/headless/HeadlessDisplayViewer.java new file mode 100644 index 000000000..407667f04 --- /dev/null +++ b/src/main/java/org/scijava/ui/headless/HeadlessDisplayViewer.java @@ -0,0 +1,66 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2016 Board of Regents of the University of + * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck + * Institute of Molecular Cell Biology and Genetics. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.ui.headless; + +import org.scijava.display.Display; +import org.scijava.plugin.Plugin; +import org.scijava.ui.UserInterface; +import org.scijava.ui.viewer.AbstractDisplayViewer; +import org.scijava.ui.viewer.DisplayViewer; +import org.scijava.ui.viewer.DisplayWindow; +import org.scijava.util.ListUtils; + +/** + * A display viewer used when running headless. + * + * @author Curtis Rueden + */ +@Plugin(type = DisplayViewer.class) +public class HeadlessDisplayViewer extends AbstractDisplayViewer { + + @Override + public boolean isCompatible(final UserInterface ui) { + return ui instanceof HeadlessUI; + } + + @Override + public void view(final DisplayWindow w, final Display d) { + if (log() == null) return; + log().info(d.getName() + " = " + ListUtils.string(d, false)); + } + + @Override + public boolean canView(Display d) { + return true; + } + +} diff --git a/src/main/java/org/scijava/ui/headless/HeadlessUI.java b/src/main/java/org/scijava/ui/headless/HeadlessUI.java new file mode 100644 index 000000000..621661af6 --- /dev/null +++ b/src/main/java/org/scijava/ui/headless/HeadlessUI.java @@ -0,0 +1,124 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2016 Board of Regents of the University of + * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck + * Institute of Molecular Cell Biology and Genetics. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.ui.headless; + +import java.io.File; + +import org.scijava.Priority; +import org.scijava.display.Display; +import org.scijava.log.LogService; +import org.scijava.plugin.AbstractRichPlugin; +import org.scijava.plugin.Plugin; +import org.scijava.ui.DialogPrompt; +import org.scijava.ui.UserInterface; +import org.scijava.ui.viewer.DisplayWindow; +import org.scijava.util.ListUtils; + +/** + * A no-op user interface used when the application is running headless. + *

+ * Most operations do nothing. Attempting to show an object via one of the + * {@link #show} methods logs the object via the {@link LogService}. + *

+ * + * @author Richard Domander (Royal Veterinary College, London) + * @author Curtis Rueden + */ +@Plugin(type = UserInterface.class, name = HeadlessUI.NAME, + priority = Priority.VERY_LOW_PRIORITY) +public class HeadlessUI extends AbstractRichPlugin implements UserInterface { + + public static final String NAME = "headless"; + + private boolean visible; + + @Override + public void show() { + visible = true; + } + + @Override + public boolean isVisible() { + return visible; + } + + @Override + public void show(final String name, final Object o) { + // NB: Rather than creating a Display, let's just log it. + log().info(name + " = " + o); + } + + @Override + public void show(final Display display) { + // NB: Rather than looking for a DisplayViewer, let's just log it. + log().info(display.getName() + " = " + ListUtils.string(display, false)); + } + + @Override + public DisplayWindow createDisplayWindow(final Display display) { + return null; + } + + @Override + public DialogPrompt dialogPrompt(final String message, final String title, + final DialogPrompt.MessageType messageType, + final DialogPrompt.OptionType optionType) + { + return null; + } + + @Override + public File chooseFile(final String title, final File file, + final String style) + { + return null; + } + + @Override + public void showContextMenu(final String menuRoot, final Display display, + final int x, final int y) + {} + + @Override + public void saveLocation() {} + + @Override + public void restoreLocation() {} + + @Override + public boolean requiresEDT() { + return false; + } + + @Override + public void dispose() {} +} diff --git a/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java b/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java index 167e4e5ed..282380bfb 100644 --- a/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java +++ b/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java @@ -31,79 +31,15 @@ package org.scijava.ui.headlessUI; -import java.io.File; - -import org.scijava.Priority; -import org.scijava.display.Display; -import org.scijava.plugin.AbstractRichPlugin; -import org.scijava.plugin.Plugin; -import org.scijava.ui.DialogPrompt; -import org.scijava.ui.UserInterface; -import org.scijava.ui.viewer.DisplayWindow; - -/** - * A "null object" UI implementation that can be returned when a UIService is - * running headless - * - * @author Richard Domander (Royal Veterinary College, London) - * @author Curtis Rueden - */ -@Plugin(type = UserInterface.class, name = HeadlessUI.NAME, - priority = Priority.VERY_LOW_PRIORITY) -public class HeadlessUI extends AbstractRichPlugin implements UserInterface { - +/** @deprecated Use {@link org.scijava.ui.headless.HeadlessUI} instead. */ +@Deprecated +public class HeadlessUI extends org.scijava.ui.headless.HeadlessUI { + + /** + * @deprecated Use {@link org.scijava.ui.headless.HeadlessUI#NAME} instead. + */ + @Deprecated + @SuppressWarnings("hiding") public static final String NAME = "headless"; - @Override - public void show() {} - - @Override - public boolean isVisible() { - return false; - } - - @Override - public void show(final String name, final Object o) {} - - @Override - public void show(final Display display) {} - - @Override - public DisplayWindow createDisplayWindow(final Display display) { - return null; - } - - @Override - public DialogPrompt dialogPrompt(final String message, final String title, - final DialogPrompt.MessageType messageType, - final DialogPrompt.OptionType optionType) - { - return null; - } - - @Override - public File chooseFile(final String title, final File file, - final String style) - { - return null; - } - - @Override - public void showContextMenu(final String menuRoot, final Display display, - final int x, final int y) - {} - - @Override - public void saveLocation() {} - - @Override - public void restoreLocation() {} - - @Override - public boolean requiresEDT() { - return false; - } - - @Override - public void dispose() {} } diff --git a/src/main/java/org/scijava/util/ListUtils.java b/src/main/java/org/scijava/util/ListUtils.java index 33e8c7985..f71fca9ce 100644 --- a/src/main/java/org/scijava/util/ListUtils.java +++ b/src/main/java/org/scijava/util/ListUtils.java @@ -53,4 +53,69 @@ public static T first(final List list) { return list.get(0); } + /** + * Converts the given list to a string. + *

+ * The list elements will be separated by a comma then a space. The list will + * be enclosed in square brackets. + *

+ * + * @param list The list to stringify. + * @see #string(List, String, String, String, boolean) + */ + public static String string(final List list) { + return string(list, true); + } + + /** + * Converts the given list to a string. + *

+ * The list elements will be separated by a comma then a space. The list will + * be enclosed in square brackets unless it is a singleton with the + * {@code encloseSingletons} flag set to false. + *

+ * + * @param list The list to stringify. + * @param encloseSingletons Whether to enclose singleton lists in brackets. + * @return The stringified list. + * @see #string(List, String, String, String, boolean) + */ + public static String string(final List list, + final boolean encloseSingletons) + { + return string(list, "[", "]", ", ", encloseSingletons); + } + + /** + * Converts the given list to a string. + *

+ * The list elements will be comma-separated. It will be enclosed in square + * brackets unless the list is a singleton with the {@code encloseSingletons} + * flag set to false. + *

+ * + * @param list The list to stringify. + * @param lDelimiter The left-hand symbol(s) in which to enclose the list. + * @param rDelimiter The right-hand symbol(s) in which to enclose the list. + * @param separator The symbol(s) to place in between each element. + * @param encloseSingletons Whether to enclose singleton lists inside the + * delimiter symbols. + * @return The stringified list. + */ + public static String string(final List list, // + final String lDelimiter, final String rDelimiter, // + final String separator, final boolean encloseSingletons) + { + final boolean delimit = encloseSingletons || list.size() != 1; + final StringBuilder sb = new StringBuilder(); + if (delimit) sb.append(lDelimiter); + boolean first = true; + for (final Object e : list) { + if (first) first = false; + else sb.append(separator); + sb.append(e); + } + if (delimit) sb.append(rDelimiter); + return sb.toString(); + } } diff --git a/src/test/java/org/scijava/ui/UIServiceTest.java b/src/test/java/org/scijava/ui/UIServiceTest.java index aef87bd99..716a2a846 100644 --- a/src/test/java/org/scijava/ui/UIServiceTest.java +++ b/src/test/java/org/scijava/ui/UIServiceTest.java @@ -42,7 +42,7 @@ import org.junit.Test; import org.scijava.Context; import org.scijava.display.Display; -import org.scijava.ui.headlessUI.HeadlessUI; +import org.scijava.ui.headless.HeadlessUI; import org.scijava.ui.viewer.DisplayWindow; /**