All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scijava.ui.DefaultUIService Maven / Gradle / Ivy

Go to download

SciJava Common is a shared library for SciJava software. It provides a plugin framework, with an extensible mechanism for service discovery, backed by its own annotation processor, so that plugins can be loaded dynamically. It is used by downstream projects in the SciJava ecosystem, such as ImageJ and SCIFIO.

There is a newer version: 2.99.0
Show newest version
/*
 * #%L
 * SciJava Common shared library for SciJava software.
 * %%
 * Copyright (C) 2009 - 2017 Board of Regents of the University of
 * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck
 * Institute of Molecular Cell Biology and Genetics, University of
 * Konstanz, and KNIME GmbH.
 * %%
 * 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;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.scijava.app.AppService;
import org.scijava.app.StatusService;
import org.scijava.app.event.StatusEvent;
import org.scijava.display.Display;
import org.scijava.display.DisplayService;
import org.scijava.display.event.DisplayActivatedEvent;
import org.scijava.display.event.DisplayCreatedEvent;
import org.scijava.display.event.DisplayDeletedEvent;
import org.scijava.display.event.DisplayUpdatedEvent;
import org.scijava.event.EventHandler;
import org.scijava.event.EventService;
import org.scijava.log.LogService;
import org.scijava.platform.event.AppQuitEvent;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.plugin.PluginInfo;
import org.scijava.plugin.PluginService;
import org.scijava.service.AbstractService;
import org.scijava.service.Service;
import org.scijava.thread.ThreadService;
import org.scijava.ui.DialogPrompt.MessageType;
import org.scijava.ui.DialogPrompt.OptionType;
import org.scijava.ui.DialogPrompt.Result;
import org.scijava.ui.event.UIShownEvent;
import org.scijava.ui.headless.HeadlessUI;
import org.scijava.ui.viewer.DisplayViewer;

/**
 * Default service for handling SciJava user interfaces.
 * 
 * @author Curtis Rueden
 */
@Plugin(type = Service.class)
public final class DefaultUIService extends AbstractService implements
	UIService
{

	@Parameter
	private LogService log;

	@Parameter
	private EventService eventService;

	@Parameter
	private StatusService statusService;

	@Parameter
	private ThreadService threadService;

	@Parameter
	private AppService appService;

	@Parameter
	private PluginService pluginService;

	@Parameter
	private DisplayService displayService;

	/**
	 * A list of extant display viewers. It's needed in order to find the viewer
	 * associated with a display.
	 */
	private List> displayViewers;

	/** List of available user interfaces, ordered by priority. */
	private List uiList;

	/** Map of available user interfaces, keyed off their names. */
	private Map uiMap;

	/** Whether lazy initialization is complete. */
	private boolean initialized;

	/** Whether the service was disposed */
	private boolean disposed;

	/** The default user interface to use, if one is not explicitly specified. */
	private UserInterface defaultUI;

	private boolean activationInvocationPending = false;

	// -- UIService methods --

	@Override
	public void addUI(final UserInterface ui) {
		addUI(null, ui);
	}

	@Override
	public void addUI(final String name, final UserInterface ui) {
		if (!initialized) discoverUIs();
		addUserInterface(name, ui);
	}

	@Override
	public void showUI() {
		if (disposed) return;
		final UserInterface ui = getDefaultUI();
		if (ui == null) throw noUIsAvailableException();
		showUI(ui);
	}

	@Override
	public void showUI(final String name) {
		final UserInterface ui = uiMap().get(name);
		if (ui == null) {
			throw new IllegalArgumentException("No such user interface: " + name);
		}
		showUI(ui);
	}

	@Override
	public void showUI(final UserInterface ui) {
		log.debug("Launching user interface: " + ui.getClass().getName());
		ui.show();
		// NB: Also show all the current displays.
		for (final Display display : displayService.getDisplays()) {
			ui.show(display);
		}
		eventService.publish(new UIShownEvent(ui));
	}

	@Override
	public boolean isVisible() {
		final UserInterface ui = getDefaultUI();
		if (ui == null) throw noUIsAvailableException();
		return ui.isVisible();
	}

	@Override
	public boolean isVisible(final String name) {
		final UserInterface ui = uiMap().get(name);
		if (ui == null) {
			throw new IllegalArgumentException("No such user interface: " + name);
		}
		return ui.isVisible();
	}

	@Override
	public void setHeadless(final boolean headless) {
		System.setProperty("java.awt.headless", String.valueOf(headless));
	}

	@Override
	public boolean isHeadless() {
		return Boolean.getBoolean("java.awt.headless");
	}

	@Override
	public UserInterface getDefaultUI() {
		if (!initialized) discoverUIs();
		if (isHeadless()) return uiMap().get(HeadlessUI.NAME);
		if (defaultUI != null) return defaultUI;
		return uiList().isEmpty() ? null : uiList().get(0);
	}

	@Override
	public void setDefaultUI(final UserInterface ui) {
		defaultUI = ui;
	}

	@Override
	public boolean isDefaultUI(final String name) {
		return getDefaultUI() == getUI(name);
	}

	@Override
	public UserInterface getUI(final String name) {
		return uiMap().get(name);
	}

	@Override
	public List getAvailableUIs() {
		return Collections.unmodifiableList(uiList());
	}

	@Override
	public List getVisibleUIs() {
		final ArrayList uis = new ArrayList<>();
		for (final UserInterface ui : uiList()) {
			if (ui.isVisible()) uis.add(ui);
		}
		return uis;
	}

	@Override
	public List>> getViewerPlugins() {
		@SuppressWarnings({ "rawtypes", "unchecked" })
		final List>> viewers =
			(List) pluginService.getPluginsOfType(DisplayViewer.class);
		return viewers;
	}

	@Override
	public void show(final Object o) {
		getDefaultUI().show(o);
	}

	@Override
	public void show(final String name, final Object o) {
		getDefaultUI().show(name, o);
	}

	@Override
	public void show(final Display display) {
		getDefaultUI().show(display);
	}

	@Override
	public void addDisplayViewer(final DisplayViewer viewer) {
		displayViewers().add(viewer);
	}

	@Override
	public DisplayViewer getDisplayViewer(final Display display) {
		for (final DisplayViewer displayViewer : displayViewers()) {
			if (displayViewer.getDisplay() == display) return displayViewer;
		}
		return null;
	}

	@Override
	public DialogPrompt.Result showDialog(final String message) {
		return showDialog(message, getTitle());
	}

	@Override
	public Result showDialog(final String message, final MessageType messageType)
	{
		return showDialog(message, getTitle(), messageType);
	}

	@Override
	public Result showDialog(final String message, final MessageType messageType,
		final OptionType optionType)
	{
		return showDialog(message, getTitle(), messageType, optionType);
	}

	@Override
	public DialogPrompt.Result
		showDialog(final String message, final String title)
	{
		return showDialog(message, title,
			DialogPrompt.MessageType.INFORMATION_MESSAGE);
	}

	@Override
	public DialogPrompt.Result showDialog(final String message,
		final String title, final DialogPrompt.MessageType messageType)
	{
		return showDialog(message, title, messageType,
			DialogPrompt.OptionType.DEFAULT_OPTION);
	}

	@Override
	public DialogPrompt.Result showDialog(final String message,
		final String title, final DialogPrompt.MessageType messageType,
		final DialogPrompt.OptionType optionType)
	{
		final UserInterface ui = getDefaultUI();
		if (ui == null) return null;
		final DialogPrompt dialogPrompt =
			ui.dialogPrompt(message, title, messageType, optionType);
		return dialogPrompt == null ? null : dialogPrompt.prompt();
	}

	@Override
	public File chooseFile(final File file, final String style) {
		final UserInterface ui = getDefaultUI();
		return ui == null ? null : ui.chooseFile(file, style);
	}

	@Override
	public File
		chooseFile(final String title, final File file, final String style)
	{
		final UserInterface ui = getDefaultUI();
		return ui == null ? null : ui.chooseFile(title, file, style);
	}

	@Override
	public File[] chooseFiles(File parent, File[] files, FileFilter filter, String style) {
		final UserInterface ui = getDefaultUI();
		return ui == null ? null : ui.chooseFiles(parent, files, filter, style);
	}
	
	@Override
	public List chooseFiles(File parent, List fileList, FileFilter filter, String style) {
		final UserInterface ui = getDefaultUI();
		return ui == null ? null : ui.chooseFiles(parent, fileList, filter, style);
	}

	@Override
	public void showContextMenu(final String menuRoot, final Display display,
		final int x, final int y)
	{
		final UserInterface ui = getDefaultUI();
		if (ui != null) ui.showContextMenu(menuRoot, display, x, y);
	}

	@Override
	public String getStatusMessage(final StatusEvent statusEvent) {
		final String appName = appService.getApp().getInfo().getName();
		return statusService.getStatusMessage(appName, statusEvent);
	}

	// -- Disposable methods --

	@Override
	public synchronized void dispose() {
		// dispose active display viewers
		// NB - copy list to avoid ConcurrentModificationExceptions
		final List> viewers = new ArrayList<>();
		viewers.addAll(displayViewers());
		for (final DisplayViewer viewer : viewers) {
			viewer.dispose();
		}

		// dispose UIs in reverse priority, "just in case" the order matters
		final List uis = getAvailableUIs();
		for (int i = uis.size() - 1; i >= 0; i--) {
			uis.get(i).dispose();
		}
		disposed = true;
	}

	// -- Event handlers --

	/**
	 * Called when a display is created. This is the magical place where the
	 * display model is connected with the real UI.
	 */
	@EventHandler
	protected void onEvent(final DisplayCreatedEvent e) {
		final Display display = e.getObject();

		for (final UserInterface ui : getVisibleUIs()) {
			ui.show(display);
		}
	}

	/**
	 * Called when a display is deleted. The display viewer is not removed from
	 * the list of viewers until after this returns.
	 */
	@EventHandler
	protected void onEvent(final DisplayDeletedEvent e) {
		final Display display = e.getObject();
		final DisplayViewer displayViewer = getDisplayViewer(display);
		if (displayViewer != null) {
			displayViewer.onDisplayDeletedEvent(e);
			displayViewers().remove(displayViewer);
		}
	}

	/** Called when a display is updated. */
	@EventHandler
	protected void onEvent(final DisplayUpdatedEvent e) {
		final Display display = e.getDisplay();
		final DisplayViewer displayViewer = getDisplayViewer(display);
		if (displayViewer != null) {
			displayViewer.onDisplayUpdatedEvent(e);
		}
	}

	/**
	 * Called when a display is activated.
	 * 

* The goal here is to eventually synchronize the window activation state with * the display activation state if the display activation state changed * programmatically. We queue a call on the UI thread to activate the display * viewer of the currently active window. *

*/ @EventHandler protected void onEvent(final DisplayActivatedEvent e) { // CTR FIXME: Verify whether this threading logic is really necessary. if (activationInvocationPending) return; activationInvocationPending = true; threadService.queue(new Runnable() { @Override public void run() { final Display activeDisplay = displayService.getActiveDisplay(); if (activeDisplay != null) { final DisplayViewer displayViewer = getDisplayViewer(activeDisplay); if (displayViewer != null) displayViewer.onDisplayActivatedEvent(e); } activationInvocationPending = false; } }); } @EventHandler protected void onEvent(@SuppressWarnings("unused") final AppQuitEvent event) { for (final UserInterface ui : getVisibleUIs()) { ui.saveLocation(); } } @EventHandler protected void onEvent(final StatusEvent event) { if (event.isWarning()) { // report warning messages to the user in a dialog box final String message = event.getStatusMessage(); if (message != null && !message.isEmpty()) { showDialog(message, MessageType.WARNING_MESSAGE); } } else { // tell each UI to report status updates in the status bar final int val = event.getProgressValue(); final int max = event.getProgressMaximum(); final String message = getStatusMessage(event); if (max < 0 && message == null) return; for (UserInterface ui : getAvailableUIs()) { final StatusBar statusBar = ui.getStatusBar(); if (statusBar != null) { if (max >= 0) { statusBar.setProgress(val, max); } if (message != null) { statusBar.setStatus(message); } } } } } // -- Helper methods -- private List> displayViewers() { if (!initialized) discoverUIs(); return displayViewers; } private List uiList() { if (!initialized) discoverUIs(); return uiList; } private Map uiMap() { if (!initialized) discoverUIs(); return uiMap; } /** Discovers available user interfaces. */ private synchronized void discoverUIs() { if (initialized) return; displayViewers = new ArrayList<>(); uiList = new ArrayList<>(); uiMap = new HashMap<>(); final List> infos = pluginService.getPluginsOfType(UserInterface.class); for (final PluginInfo info : infos) { // instantiate user interface final UserInterface ui = pluginService.createInstance(info); if (ui == null) continue; log.debug("Discovered user interface: " + ui.getClass().getName()); addUserInterface(info.getName(), ui); } // check system property for explicit UI preference final String uiProp = System.getProperty(UI_PROPERTY); final UserInterface ui = uiMap.get(uiProp); if (ui != null) { // set the default UI to the one provided by the system property setDefaultUI(ui); } initialized = true; } private void addUserInterface(final String name, final UserInterface ui) { // add to UI list uiList.add(ui); // add to UI map uiMap.put(ui.getClass().getName(), ui); if (name != null && !name.isEmpty()) uiMap.put(name, ui); } private String getTitle() { return appService.getApp().getTitle(); } private IllegalStateException noUIsAvailableException() { return new IllegalStateException("No UIs available. " + "Please add a component containing a UIPlugin " + "(e.g., scijava-ui-swing) to your class-path."); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy