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

org.flexdock.docking.defaults.DockableComponentWrapper Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2004 Christopher M Butler
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.flexdock.docking.defaults;

import java.awt.Component;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;

import javax.swing.Icon;
import javax.swing.JComponent;

import org.flexdock.docking.Dockable;
import org.flexdock.docking.DockingManager;
import org.flexdock.docking.DockingPort;
import org.flexdock.docking.DockingStub;
import org.flexdock.docking.adapter.DockingAdapter;
import org.flexdock.docking.event.DockingEvent;
import org.flexdock.docking.event.DockingListener;
import org.flexdock.docking.props.DockablePropertySet;
import org.flexdock.docking.props.PropertyManager;
import org.flexdock.util.SwingUtility;
import org.flexdock.util.Utilities;

/**
 * This class models a {@code Dockable} implementation for wrapping a
 * {@code Component}. It is essentially the simplest means to turning a generic
 * {@code Component} into a {@code Dockable} instance. Compound
 * {@code Dockables} may have separate child components that are responsible for
 * drag initiation, whereas another component is the actual drag source. This is
 * shown in the manner that a {@code JInternalFrame} would be a draggable
 * component, while the frame's title pane is the actual drag initiator.
 * 

* The class, conversely, deals with the simple case, where a * {@code Component} itself must be docking-enabled. * {@code DockableComponentWrapper} wraps a {@code Component} and implements the * {@code Dockable} interface. Since the {@code Component} itself is being * docking-enabled, it serves as both the drag source and drag initiator. Thus, * {@code getComponent()} will return a reference to {@code 'this'} and * {@code getDragSources()} return a {@code List} containing the same * self-reference {@code Component}. *

* This class may be used by application code to enable docking capabilities on * a given {@code Component}. However, it is recommended that * {@code DockingManager.registerDockable(Component evtSrc, String desc)} be * used as a more automated, less invasive means of enabling docking on a * component. * {@code DockingManager.registerDockable(Component evtSrc, String desc)} will * automatically create a {@code DockableComponentWrapper} instance and register * the required drag listeners. * * @author Chris Butler */ public class DockableComponentWrapper implements Dockable { private Component dragSrc; private String persistentId; private ArrayList dockingListeners; private ArrayList dragListeners; private Hashtable clientProperties; private HashSet frameDragSources; /** * Creates a {@code DockableComponentWrapper} instance using the specified * source component, persistent ID, and docking description. This method is * used to create {@code Dockable} instances for simple {@code Components} * where the drag source and drag initiator are the same {@code Component}. *

* If {@code src} or {@code id} are {@code null}, then this method returns * a {@code null} reference. *

* {@code src} will be the {@code Component} returned by invoking * {@code getComponent()} on the resulting {@code Dockable} and will be * included in the {@code List} returned by {@code getDragSources()}. * {@code id} will be the value returned by invoking * {@code getPersistentId()} on the resulting {@code Dockable}. * {@code desc} may be used by the {@code Dockable} for descriptive purposes * (such as tab-text in a tabbed layout). It is not recommended to supply a * {@code null} value for {@code desc}, but doing so is not illegal. * * @param src * the source component * @param id * the persistent ID for the Dockable instance * @param desc * the docking description * @return a new {@code DockableComponentWrapper} instance * @see Dockable#getComponent() * @see Dockable#getDragSources() * @see Dockable#getPersistentId() * @see DockingManager#registerDockable(Component, String) */ public static DockableComponentWrapper create(Component src, String id, String desc) { if (src == null || id == null) { return null; } return new DockableComponentWrapper(src, id, desc); } public static DockableComponentWrapper create(DockingStub stub) { if (!(stub instanceof Component)) { return null; } return create((Component) stub, stub.getPersistentId(), stub .getTabText()); } public static DockableComponentWrapper create(DockingAdapter adapter) { if (adapter == null) { return null; } Component comp = adapter.getComponent(); String id = adapter.getPersistentId(); String tabText = adapter.getTabText(); DockableComponentWrapper dockable = create(comp, id, tabText); List dragSources = adapter.getDragSources(); Set frameDragSources = adapter.getFrameDragSources(); Icon icon = adapter.getDockbarIcon(); if (dragSources != null) { dockable.getDragSources().clear(); dockable.getDragSources().addAll(dragSources); } if (frameDragSources != null) { dockable.getFrameDragSources().clear(); dockable.getFrameDragSources().addAll(frameDragSources); } if (icon != null) { dockable.getDockingProperties().setDockbarIcon(icon); } return dockable; } /** * @param src * @param id * @param desc * @param resizable */ private DockableComponentWrapper(Component src, String id, String desc) { dragSrc = src; getDockingProperties().setDockableDesc(desc); persistentId = id; dockingListeners = new ArrayList(0); dragListeners = new ArrayList(1); // initialize the drag sources lists initDragListeners(); } private void initDragListeners() { // by default, use the wrapped source component as the drag source // and assume there is no frame drag source defined Component draggable = dragSrc; Component frameDragger = null; // if the wrapped source component is a DockingStub, then // we'll be able to pull some extra data from it if (dragSrc instanceof DockingStub) { DockingStub stub = (DockingStub) dragSrc; Component c = stub.getDragSource(); // if the stub defines a specific drag source, then // replace wrapped source component with the specified // drag source if (c != null) { draggable = c; } // if the stub defines a specified frame drag source, then // use it frameDragger = stub.getFrameDragSource(); } // add the "docking" drag source to the list if (draggable != null) { dragListeners.add(draggable); } // add the floating frame drag source to the list if (frameDragger != null) { getFrameDragSources().add(frameDragger); } } private Hashtable getInternalClientProperties() { if (clientProperties == null) { clientProperties = new Hashtable(2); } return clientProperties; } /** * Returns the {@code Component} used to create this * {@code DockableComponentWrapper} instance. * * @return the {@code Component} used to create this * {@code DockableComponentWrapper} instance. * @see Dockable#getComponent() * @see #create(Component, String, String) */ @Override public Component getComponent() { return dragSrc; } /** * Returns a {@code List} of {@code Components} used to initiate * drag-to-dock operation. By default, the returned {@code List} contains * the {@code Component} returned by {@code getComponent()}. * * @return a {@code List} of {@code Components} used to initiate * drag-to-dock operation. * @see Dockable#getDragSources() * @see #getComponent() * @see #create(Component, String, String) */ @Override public List getDragSources() { return dragListeners; } /** * Returns the persistent ID of this {@code DockableComponentWrapper} * instance provided when this object was instantiated. * * @return the persistent ID of this {@code DockableComponentWrapper} * @see Dockable#getPersistentId() * @see #create(Component, String, String) */ @Override public String getPersistentId() { return persistentId; } /** * Returns a {@code HashSet} of {@code Components} used as frame drag * sources when this {@code Dockable} is floating in a non-decorated * external dialog. The {@code HashSet} returned by this method is initially * empty. Because it is mutable, however, new {@code Components} may be * added to it. * * @return a {@code HashSet} of {@code Components} used as frame drag * sources when this {@code Dockable} is floating in a non-decorated * external dialog. * @see Dockable#getFrameDragSources() */ @Override public Set getFrameDragSources() { if (frameDragSources == null) { frameDragSources = new HashSet(); } return frameDragSources; } /** * Adds a {@code DockingListener} to observe docking events for this * {@code Dockable}. {@code null} arguments are ignored. * * @param listener * the {@code DockingListener} to add to this {@code Dockable}. * @see #getDockingListeners() * @see #removeDockingListener(DockingListener) */ @Override public void addDockingListener(DockingListener listener) { if (listener != null) { dockingListeners.add(listener); } } /** * Returns an array of all {@code DockingListeners} added to this * {@code Dockable}. If there are no listeners present for this * {@code Dockable}, then a zero-length array is returned. * * @return an array of all {@code DockingListeners} added to this * {@code Dockable}. * @see #addDockingListener(DockingListener) * @see #removeDockingListener(DockingListener) */ @Override public DockingListener[] getDockingListeners() { return (DockingListener[]) dockingListeners .toArray(new DockingListener[0]); } /** * Removes the specified {@code DockingListener} from this {@code Dockable}. * If the specified {@code DockingListener} is {@code null}, or the * listener has not previously been added to this {@code Dockable}, then no * {@code Exception} is thrown and no action is taken. * * @param listener * the {@code DockingListener} to remove from this * {@code Dockable} * @see #addDockingListener(DockingListener) * @see #getDockingListeners() */ @Override public void removeDockingListener(DockingListener listener) { if (listener != null) { dockingListeners.remove(listener); } } /** * No operation. Provided as a method stub to fulfull the * {@code DockingListener} interface contract. * * @param evt * the {@code DockingEvent} to respond to. * @see DockingListener#dockingCanceled(DockingEvent) */ @Override public void dockingCanceled(DockingEvent evt) { } /** * No operation. Provided as a method stub to fulfull the * {@code DockingListener} interface contract. * * @param evt * the {@code DockingEvent} to respond to. * @see DockingListener#dockingComplete(DockingEvent) */ @Override public void dockingComplete(DockingEvent evt) { } /** * No operation. Provided as a method stub to fulfull the * {@code DockingListener} interface contract. * * @param evt * the {@code DockingEvent} to respond to. * @see DockingListener#undockingComplete(DockingEvent) */ @Override public void undockingComplete(DockingEvent evt) { } /** * No operation. Provided as a method stub to fulfull the * {@code DockingListener} interface contract. * * @param evt * the {@code DockingEvent} to respond to. * @see DockingListener#undockingStarted(DockingEvent) */ @Override public void undockingStarted(DockingEvent evt) { } /** * No operation. Provided as a method stub to fulfull the * {@code DockingListener} interface contract. * * @param evt * the {@code DockingEvent} to respond to. * @see DockingListener#dragStarted(DockingEvent) */ @Override public void dragStarted(DockingEvent evt) { } /** * No operation. Provided as a method stub to fulfull the * {@code DockingListener} interface contract. * * @param evt * the {@code DockingEvent} to respond to. * @see DockingListener#dropStarted(DockingEvent) */ @Override public void dropStarted(DockingEvent evt) { } /** * Returns the value of the property with the specified key. Only properties * added with {@code putClientProperty} will return a non-{@code null} * value. If {@code key} is {@code null}, a {@code null} reference is * returned. *

* If the {@code Component} returned by {@code getComponent()} is an * instance of {@code JComponent}, then this method will dispatch to that * {@code JComponent's} {@code getClientProperty(Object, Object)} method. * Otherwise, this {@code DockableComponentWrapper} will provide its own * internal mapping of client properties. * * @param key * the key that is being queried * @return the value of this property or {@code null} * @see Dockable#getClientProperty(Object) * @see javax.swing.JComponent#getClientProperty(java.lang.Object) */ @Override public Object getClientProperty(Object key) { if (key == null) { return null; } Component c = getComponent(); if (c instanceof JComponent) { return ((JComponent) c).getClientProperty(key); } return getInternalClientProperties().get(key); } /** * Adds an arbitrary key/value "client property" to this {@code Dockable}. * {@code null} values are allowed. If {@code key} is {@code null}, then no * action is taken. *

* If the {@code Component} returned by {@code getComponent()} is an * instance of {@code JComponent}, then this method will dispatch to that * {@code JComponent's} {@code putClientProperty(Object, Object)} method. * Otherwise, this {@code DockableComponentWrapper} will provide its own * internal mapping of client properties. * * @param key * the new client property key * @param value * the new client property value; if {@code null} this method * will remove the property * @see Dockable#putClientProperty(Object, Object) * @see javax.swing.JComponent#putClientProperty(java.lang.Object, * java.lang.Object) */ @Override public void putClientProperty(Object key, Object value) { if (key == null) { return; } Component c = getComponent(); if (c instanceof JComponent) { SwingUtility.putClientProperty(c, key, value); } else { Utilities.put(getInternalClientProperties(), key, value); } } /** * Returns a {@code DockablePropertySet} instance associated with this * {@code Dockable}. This method returns the default implementation * supplied by the framework by invoking * {@code getDockablePropertySet(Dockable dockable)} on * {@code org.flexdock.docking.props.PropertyManager} and supplying an * argument of {@code this}. * * @return the {@code DockablePropertySet} associated with this * {@code Dockable}. This method will not return a {@code null} * reference. * @see Dockable#getDockingProperties() * @see org.flexdock.docking.props.PropertyManager#getDockablePropertySet(Dockable) */ @Override public DockablePropertySet getDockingProperties() { return PropertyManager.getDockablePropertySet(this); } /** * Returns the {@code DockingPort} within which this {@code Dockable} is * currently docked. If not currently docked, this method will return * {@code null}. *

* This method defers processing to * {@code getDockingPort(Dockable dockable)}, passing an argument of * {@code this}. * * @return the {@code DockingPort} within which this {@code Dockable} is * currently docked. * @see Dockable#getDockingPort() * @see DockingManager#getDockingPort(Dockable) */ @Override public DockingPort getDockingPort() { return DockingManager.getDockingPort(this); } /** * Provides the default {@code Dockable} implementation of * {@code dock(Dockable dockable)} by calling and returning * {@code DockingManager.dock(Dockable dockable, Dockable parent)}. * {@code 'this'} is passed as the {@code parent} parameter. * * @param dockable * the {@code Dockable} to dock relative to this {@code Dockable} * @return {@code true} if the docking operation was successful; * {@code false} otherwise. * @see Dockable#dock(Dockable) * @see DockingManager#dock(Dockable, Dockable) */ @Override public boolean dock(Dockable dockable) { return DockingManager.dock(dockable, this); } /** * Provides the default {@code Dockable} implementation of * {@code dock(Dockable dockable, String relativeRegion)} by calling and * returning * {@code DockingManager.dock(Dockable dockable, Dockable parent, String region)}. * {@code 'this'} is passed as the {@code parent} parameter. * * @param dockable * the {@code Dockable} to dock relative to this {@code Dockable} * @param relativeRegion * the docking region into which to dock the specified * {@code Dockable} * @return {@code true} if the docking operation was successful; * {@code false} otherwise. * @see Dockable#dock(Dockable, String) * @see DockingManager#dock(Dockable, Dockable, String) */ @Override public boolean dock(Dockable dockable, String relativeRegion) { return DockingManager.dock(dockable, this, relativeRegion); } /** * Provides the default {@code Dockable} implementation of * {@code dock(Dockable dockable, String relativeRegion, float ratio)} by * calling and returning * {@code DockingManager.dock(Dockable dockable, Dockable parent, String region, float proportion)}. * {@code 'this'} is passed as the {@code parent} parameter. * * @param dockable * the {@code Dockable} to dock relative to this {@code Dockable} * @param relativeRegion * the docking region into which to dock the specified * {@code Dockable} * @param ratio * the proportion of available space in the resulting layout to * allot to the new sibling {@code Dockable}. * @return {@code true} if the docking operation was successful; * {@code false} otherwise. * @see DockingManager#dock(Dockable, Dockable, String, float) */ @Override public boolean dock(Dockable dockable, String relativeRegion, float ratio) { return DockingManager.dock(dockable, this, relativeRegion, ratio); } @Override public void addPropertyChangeListener(PropertyChangeListener listener) { getDockingProperties().addPropertyChangeListener(listener); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { getDockingProperties().removePropertyChangeListener(listener); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy