/** * Copyright (C) 2015 Valkyrie RCP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.valkyriercp.component; import com.jidesoft.swing.DefaultOverlayable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.Assert; import javax.swing.*; import java.awt.*; import java.text.MessageFormat; /** * Jide OSS implementation of overlay service. * <p> * Expects the target component to get attached an instance of <code>DefaultOverlayable</code> (AKA "overlayable"), in * other case this will not work. * <p> * For that reason this implementation should be used together with <code>JideBindingFactory</code> in order to find * <code>DefaultOverlayable</code> in the overlayable component hierarchy. * * @author <a href = "mailto:julio.arguello@gmail.com" >Julio Arg??ello (JAF)</a> * * @see DefaultOverlayable */ public class JideOverlayService implements OverlayService, SwingConstants { /** * The logger. */ private static final Logger LOGGER = LoggerFactory.getLogger(JideOverlayService.class); /** * Return value for searchs with no result. */ private static final int NOT_FOUND = -1; /** * Message when overlay is already installed. */ private static final MessageFormat NOT_FOUND_FMT = new MessageFormat("Overlayable not found for \"{0}\""); /** * Message when overlay is already installed. */ private static final MessageFormat ALREADY_INSTALLED_FMT = new MessageFormat( "Overlay \"{0}\" already installed into \"{1}\""); /** * Message when overlay is not installed yet. */ private static final MessageFormat NOT_INSTALLED_FMT = new MessageFormat( "Overlay \"{0}\" not installed into \"{1}\""); /** * The {@value #TARGET_COMPONENT_PARAM} method parameter. */ private static final String TARGET_COMPONENT_PARAM = "targetComponent"; /** * The {@value #OVERLAY} method parameter. */ private static final String OVERLAY = "overlay"; /** * {@inheritDoc} */ public Boolean isOverlayInstalled(JComponent targetComponent, JComponent overlay) { Assert.notNull(targetComponent, JideOverlayService.TARGET_COMPONENT_PARAM); Assert.notNull(overlay, JideOverlayService.OVERLAY); final DefaultOverlayable overlayable = this.findOverlayable(targetComponent); return this.isOverlayInstalled(overlayable, overlay); } /** * {@inheritDoc} * <p> * Employs a default position <code>SwingConstants.NORTH_WEST</code> and <code>null</code> insets to avoid changes. * * @see #installOverlay(JComponent, JComponent, int, Insets) */ @Override public Boolean installOverlay(JComponent targetComponent, JComponent overlay) { return this.installOverlay(targetComponent, overlay, SwingConstants.NORTH_WEST, null); } /** * {@inheritDoc} */ @Override public Boolean installOverlay(JComponent targetComponent, JComponent overlay, int position, Insets insets) { Assert.notNull(targetComponent, JideOverlayService.TARGET_COMPONENT_PARAM); Assert.notNull(overlay, JideOverlayService.OVERLAY); final DefaultOverlayable overlayable = this.findOverlayable(targetComponent); if ((overlayable != null) && !this.isOverlayInstalled(overlayable, overlay)) { // Install overlay and set location insets overlayable.addOverlayComponent(overlay, position, -1); if (insets != null) { overlayable.setOverlayLocationInsets(insets); } return this.hideOverlay(targetComponent, overlay); } else if (overlayable == null) { JideOverlayService.LOGGER.warn(JideOverlayService.NOT_FOUND_FMT.format(// new String[] { targetComponent.getName() })); return Boolean.FALSE; } else { JideOverlayService.LOGGER.warn(JideOverlayService.ALREADY_INSTALLED_FMT.format(// new String[] { overlay.getName(), targetComponent.getName() })); return Boolean.FALSE; } } /** * {@inheritDoc} * <p> * Employs <code>null</code> insets to avoid changes. * * @see #uninstallOverlay(JComponent, JComponent, Insets) */ public Boolean uninstallOverlay(JComponent targetComponent, JComponent overlay) { return this.uninstallOverlay(targetComponent, overlay, null); } /** * {@inheritDoc} */ public Boolean uninstallOverlay(JComponent targetComponent, JComponent overlay, Insets insets) { Assert.notNull(targetComponent, JideOverlayService.TARGET_COMPONENT_PARAM); Assert.notNull(overlay, JideOverlayService.OVERLAY); final DefaultOverlayable overlayable = this.findOverlayable(targetComponent); // If overlay is installed... if ((overlayable != null) && this.isOverlayInstalled(overlayable, overlay)) { // Uninstall overlay overlayable.removeOverlayComponent(overlay); // If location insets are not null then change them if (insets != null) { overlayable.setOverlayLocationInsets(insets); } return Boolean.TRUE; } else if (overlayable == null) { JideOverlayService.LOGGER.warn(JideOverlayService.NOT_FOUND_FMT.format(// new String[] { targetComponent.getName() })); return Boolean.FALSE; } else { JideOverlayService.LOGGER.warn(JideOverlayService.NOT_INSTALLED_FMT.format(// new String[] { overlay.getName(), targetComponent.getName() })); return Boolean.FALSE; } } /** * {@inheritDoc} * */ @Override public Boolean showOverlay(JComponent targetComponent, JComponent overlay) { return this.setVisible(targetComponent, overlay, Boolean.TRUE); } /** * {@inheritDoc} * */ @Override public Boolean hideOverlay(JComponent targetComponent, JComponent overlay) { return this.setVisible(targetComponent, overlay, Boolean.FALSE); } /** * {@inheritDoc} */ protected final Boolean isOverlayInstalled(DefaultOverlayable overlayable, JComponent overlay) { Assert.notNull(overlay, JideOverlayService.OVERLAY); if (overlayable != null) { return (overlayable.getOverlayLocation(overlay) != JideOverlayService.NOT_FOUND); } return Boolean.FALSE; } /** * Tries to find a <code>DefaultOverlayable</code> given a target component. * * @param targetComponent * the target component. * @return the associated <code>Overlayable</code> if found and <code>null</code> in other case. */ protected final DefaultOverlayable findOverlayable(JComponent targetComponent) { // Find overlayable in tart component container final Container parent = targetComponent.getParent(); if ((parent != null) && (parent instanceof DefaultOverlayable)) { return (DefaultOverlayable) parent; } return null; } /** * Show or hide the given overlay depending on the given <code>show</code> parameter. * * @param targetComponent * the target component. * @param overlay * the overlay component. * @param show * whether to show or hide the given overlay (<code>true</code> for showing). * * @return <code>true</code> if success and <code>false</code> in other case. */ protected final Boolean setVisible(JComponent targetComponent, JComponent overlay, Boolean show) { Assert.notNull(targetComponent, JideOverlayService.TARGET_COMPONENT_PARAM); Assert.notNull(overlay, JideOverlayService.OVERLAY); Assert.notNull(show, "show"); // If overlay is installed... if (this.isOverlayInstalled(targetComponent, overlay)) { // Definitely show or hide overlay overlay.setVisible(show); overlay.repaint(); return Boolean.TRUE; } return Boolean.FALSE; } }