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

com.pekinsoft.framework.TargetManager Maven / Gradle / Ivy

/*
 * Copyright (C) 2024 PekinSOFT Systems
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 * 
 * *****************************************************************************
 *  Project    :   application-framework-api
 *  Class      :   TargetManager.java
 *  Author     :   Sean Carrick
 *  Created    :   Jul 14, 2024
 *  Modified   :   Jul 14, 2024
 *  
 *  Purpose: See class JavaDoc for explanation
 *  
 *  Revision History:
 *  
 *  WHEN          BY                   REASON
 *  ------------  -------------------  -----------------------------------------
 *  Jul 14, 2024  Sean Carrick         Initial creation.
 * *****************************************************************************
 */

package com.pekinsoft.framework;

import com.pekinsoft.api.Targetable;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventObject;

/**
 * The {@code TargetManager} simply manages a single {@link Targetable} object
 * to which action commands are passed. The {@code target} property of the
 * {@code TargetManager} may be {@code null} if there is not currently an object
 * that implements {@code Targetable} as the current permanent focus
 * owner, nor do its parents implement the {@code Targetable} interface.
 * 

* The {@code TargetManager} is used by an application in situations where there * are multiple windows and/or distinct component hierarchies that all share a * common action, such as docked panels that attach to a database table and * allow for adding, updating and deleting records. Instead of the application * attempting to swap out its menu items and toolbar buttons based upon the * current focus owner, it can add a single application-level action to the * menus and toolbars that simply forward the action command to the current * focus owner, if that component implements the {@code Targetable} interface. *

* The {@code TargetManager} tracks the current permanent focus owner * and updates its {@code target} property based on the component that currently * holds the focus within an application. If the current focus owner does not * implement the {@code Targetable} interface, the {@code target} property is * set to {@code null}. If the current focus owner (or one of its parents) does * implement the {@code Targetable} interface, then that component is set as the * current {@code target}. *

* An application that uses the {@code TargetManager} should track whether the * {@code target} property has a valid {@code Targetable} set, and update the * {@code enabled} property of the menu items and toolbar buttons based on this * property's value. In other words, if {@code target == null}, the menu items * and toolbar buttons that rely on a target should be disabled until a valid * {@code target} exists. *

* The {@code TargetManager} is a singleton class, so only has the one instance * available for the application. * * @author Sean Carrick <sean at pekinsoft dot com> * * @version 1.0 * @since 2.0 */ public class TargetManager extends AbstractBean implements PropertyChangeListener { /** * Retrieves the {@code TargetManager} instance. * * @return the {@code TargetManager} singleton */ public static TargetManager getInstance() { if (instance == null) { instance = new TargetManager(); } return instance; } /** * Constructs a new {@code TargetManager} instance. This constructor may be * called by subclasses, if the {@code TargetManager} class is extended. */ protected TargetManager() { KeyboardFocusManager.getCurrentKeyboardFocusManager() .addPropertyChangeListener(this); } /** * Determines whether a valid {@link Targetable} instance is available to * perform an action. * * @return {@code true} if a {@code Targetable} instance is available */ public boolean isTargetAvailable() { return target != null; } /** * Retrieves the current {@code target} property value. This value will be * either a valid {@link Targetable} instance or {@code null}. * * @return the current {@code target} or {@code null} */ public Targetable getTarget() { return target; } /** * Sets the value of the {@code target} property to the specified * {@link Targetable} implementation. This method accepts {@code null} for * the new value. *

* The {@code TargetManager} object listens to the focus subsystem for * changes in the permanent focus owner and sets the {@code target} property * based upon those changes. If the {@code permanentFocusOwner} is not an * implementation of the {@code Targetable} interface, then its parent * hierarchy is examined to see if a {@code Targetable} instance exists in * it. If a {@code Targetable} instance is found, it is set as the value of * the {@code target} property, otherwise, {@code target} is set to * {@code null}. *

* While the {@code TargetManager} listens to the focus subsystem for the * changes in the permanent focus owner, an application may set the * {@code target} property manually at any time. *

* This is a bound property. * * @param target the new {@code Targetable} implementation or {@code null} */ public void setTarget(Targetable target) { Targetable old = getTarget(); this.target = target; firePropertyChange("target", old, getTarget()); System.out.println("TARGETMANAGER->TARGET = " + (target == null ? "NULL_TARGET" : target.getClass().getSimpleName())); } /** * A convenience method that is shorthand for calling:{@snippet lang="java": * TargetManager.getInstance().getTarget().doCommand(actionCommand, param); * } *

* This method checks to see if the {@code target} property is set to a * valid {@code Targetable} instance, and if that instance has the action * command required. If both conditions are met, the {@code target}'s * {@link Targetable#doCommand(String, EventObject) doCommand} method is * called and its return value is passed back to the caller. *

* If the {@code target} property is not set to a valid {@code Targetable} * instance, or the {@code target} does not support the specified action * command, {@code false} is returned. * * @param actionCommand the {@link javax.swing.Action#ACTION_COMMAND_KEY} to * be fired * @param param the {@link EventObject} that triggered the action * * @return {@code true} upon successfully executing the action; * {@code false} if the action command had no supporting * {@code target} */ public boolean doCommand(String actionCommand, EventObject param) { if (getTarget() != null) { if (getTarget().hasCommand(actionCommand)) { return getTarget().doCommand(actionCommand, param); } } return false; } /** * A convenience method that is shorthand for calling:{@snippet lang="java": * TargetManager.getTarget().hasCommand(actionCommand); * } *

* This method checks to see if the {@code target} property is set to a * valid {@link Targetable} instance, and if that instance supports the * action command required. The value of this call is returned to the * calling object. *

* If the {@code target} is {@code null}, {@code false} is returned. * * @param actionCommand the {@link javax.swing.Action#ACTION_COMMAND_KEY} to * be checked * * @return {@code true} if the {@code target} is not {@code null} and * supports the specified action command; {@code false} otherwise */ public boolean hasActionCommand(String actionCommand) { if (getTarget() != null) { return getTarget().hasCommand(actionCommand); } return false; } @Override public void propertyChange(PropertyChangeEvent pce) { if (pce.getPropertyName() != null) { switch (pce.getPropertyName()) { case "permanentFocusOwner" -> { Component component = (Component) pce.getNewValue(); System.out.println("Permanent Focus Owner: " + (component != null ? component.getClass().getSimpleName() : "NULL FOCUS OWNER")); if (component != null) { if (component instanceof Targetable target) { setTarget(target); } else if (component.getParent() != null) { Component parent = component.getParent(); while (parent != null && !parent.getClass().equals( Object.class)) { if (parent instanceof Targetable target) { setTarget(target); break; } parent = parent.getParent(); } } else { setTarget(null); } } else { setTarget(null); } } } } } private static TargetManager instance = null; private Targetable target = null; }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy