<commit_before>/* ###
 * IP: GHIDRA
 *
 * 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 docking;

import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.event.MouseEvent;
import java.util.*;

import javax.swing.*;

import docking.action.*;
import docking.help.HelpDescriptor;
import docking.help.HelpService;
import ghidra.util.HelpLocation;
import ghidra.util.UniversalIdGenerator;
import ghidra.util.exception.AssertException;

/**
 * Abstract base class for creating dockable GUI components within a tool.  
 * <p>
 * The one method that must be implemented is {@link #getComponent()} which is where the top level
 * Swing JComponent is returned to be docked into the tool.  Typically, the GUI components are
 * created in the constructor along with any local actions for the provider.  The getComponent() 
 * method then simply returns the top level component previously created by this provider.
 * <p>
 * There are many other methods for configuring how to dock the component, set title information,
 * configure grouping, set the help, add actions, and receive show/hide notifications, some
 * of which are highlighted below.  Typically, implementers will use these methods to configure
 * how the GUI component behaves within the tool, and then add the business logic that uses and reacts
 * to the GUI components created in this provider.
 * <p>
 * To effectively use this class you merely need to create your component, add your actions to 
 * this class ({@link #addLocalAction(DockingActionIf)}) and then add this provider to the tool
 * ({@link #addToTool()}).
 * <p>
 * This also provides several useful convenience methods:
 * <ul>
 *  <li>{@link #addLocalAction(DockingActionIf)}
 *  <li>{@link #addToTool()}
 *  <li>{@link #setVisible(boolean)}  
 *  <li>{@link #setTitle(String)}
 *  <li>{@link #setIcon(Icon)}
 * </ul>
 * <p>
 * There are a handful of stub methods that can be overridden as desired:
 * <ul>
 *  <li>{@link #componentActivated()} and {@link #componentDeactived()}
 *  <li>{@link #componentHidden()} and {@link #componentShown()}
 * </ul>
 * <p>
 * Note: This class was created so that implementors could add local actions within the constructor
 * without having to understand that they must first add themselves to the WindowManager.
 */

public abstract class ComponentProvider implements HelpDescriptor, ActionContextProvider {
	public static final String DEFAULT_WINDOW_GROUP = "Default";
	// maps for mapping old provider names and owner to new names and/or owner
	private static Map<String, String> oldOwnerMap = new HashMap<>();
	private static Map<String, String> oldNameMap = new HashMap<>();
	protected DockingTool dockingTool;
	private String name;
	private final String owner;
	private String title;
	private String subTitle;
	private String tabText;
	private Icon icon;
	private Set<DockingActionIf> actionSet = new LinkedHashSet<>();
	private String windowMenuGroup;
	private boolean isTransient;
	private HelpLocation helpLocation;
	private String group = DEFAULT_WINDOW_GROUP;
	private WindowPosition defaultWindowPosition = WindowPosition.WINDOW;
	private WindowPosition defaultIntraGroupPosition = WindowPosition.STACK;
	private final Class<?> contextType;

	private long instanceID = UniversalIdGenerator.nextID().getValue();
	private boolean instanceIDHasBeenInitialized;

	/**
	 * Creates a new component provider with a default location of {@link WindowPosition#WINDOW}.
	 * @param tool The tool will manage and show this provider
	 * @param name The providers name.  This is used to group similar providers into a tab within
	 *        the same window.
	 * @param owner The owner of this provider, usually a plugin name.
	 */
	public ComponentProvider(DockingTool tool, String name, String owner) {
		this(tool, name, owner, null);
	}

	/**
	 * Creates a new component provider with a default location of {@link WindowPosition#WINDOW}.
	 * @param tool The tool that will manage and show this provider.
	 * @param name The providers name.  This is used to group similar providers into a tab within
	 *        the same window.
	 * @param owner The owner of this provider, usually a plugin name.
	 * @param contextType the type of context supported by this provider; may be null (see
	 *        {@link #getContextType()}
	 */
	public ComponentProvider(DockingTool tool, String name, String owner, Class<?> contextType) {
		this.dockingTool = tool;
		this.name = name;
		this.owner = owner;
		this.title = name;
		this.contextType = contextType;
	}

	/**
	 * Returns the component to be displayed
	 * @return the component to be displayed
	 */
	public abstract JComponent getComponent();

	/**
	 * A method that allows children to set the <tt>instanceID</tt> to a desired value (useful for
	 * restoring saved IDs).
	 * <p>
	 * Note: this can be called only once during the lifetime of the calling instance; otherwise, an 
	 * {@link AssertException} will be thrown.
	 * @param newID the new ID of this provider
	 */
	protected void initializeInstanceID(long newID) {
		if (instanceIDHasBeenInitialized) {
			if (newID != instanceID) {
				throw new AssertException("Cannot initialize the instanceID more than once");
			}
		}

		instanceIDHasBeenInitialized = true;
		instanceID = newID;
	}

	/**
	 * A unique ID for this provider
	 * @return unique ID for this provider
	 */
	public final long getInstanceID() {
		return instanceID;
	}

	// Default implementation
	public void requestFocus() {

		KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
		Component focusOwner = kfm.getFocusOwner();
		if (focusOwner != null && SwingUtilities.isDescendingFrom(focusOwner, getComponent())) {
			return;
		}

		getComponent().requestFocus();
	}

	/**
	 * Returns true if this provider has focus
	 * 
	 * @return true if this provider has focus
	 */
	public boolean isFocusedProvider() {
		DockingWindowManager dwm = DockingWindowManager.getInstance(getComponent());
		ComponentPlaceholder placeholder = dwm.getFocusedComponent();
		return placeholder.getProvider() == this;
	}

	/**
	 * Adds this provider to the tool in a new window that is not initially visible.  The provider
	 * will then show up in the "Windows" menu of the tool
	 */
	public void addToTool() {
		if (isInTool()) {
			throw new IllegalStateException("Component already added: " + name);
		}
		dockingTool.addComponentProvider(this, false);
		for (DockingActionIf action : actionSet) {
			dockingTool.addLocalAction(this, action);
		}
		if (subTitle != null) {
			setSubTitle(subTitle);
		}
	}

	/**
	 * Removes this provider from the tool.
	 */
	public void removeFromTool() {<commit_msg>Tests - fix for failing FG test<commit_after>/* ###
 * IP: GHIDRA
 *
 * 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 docking;

import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.event.MouseEvent;
import java.util.*;

import javax.swing.*;

import docking.action.*;
import docking.help.HelpDescriptor;
import docking.help.HelpService;
import ghidra.util.HelpLocation;
import ghidra.util.UniversalIdGenerator;
import ghidra.util.exception.AssertException;

/**
 * Abstract base class for creating dockable GUI components within a tool.  
 * <p>
 * The one method that must be implemented is {@link #getComponent()} which is where the top level
 * Swing JComponent is returned to be docked into the tool.  Typically, the GUI components are
 * created in the constructor along with any local actions for the provider.  The getComponent() 
 * method then simply returns the top level component previously created by this provider.
 * <p>
 * There are many other methods for configuring how to dock the component, set title information,
 * configure grouping, set the help, add actions, and receive show/hide notifications, some
 * of which are highlighted below.  Typically, implementers will use these methods to configure
 * how the GUI component behaves within the tool, and then add the business logic that uses and reacts
 * to the GUI components created in this provider.
 * <p>
 * To effectively use this class you merely need to create your component, add your actions to 
 * this class ({@link #addLocalAction(DockingActionIf)}) and then add this provider to the tool
 * ({@link #addToTool()}).
 * <p>
 * This also provides several useful convenience methods:
 * <ul>
 *  <li>{@link #addLocalAction(DockingActionIf)}
 *  <li>{@link #addToTool()}
 *  <li>{@link #setVisible(boolean)}  
 *  <li>{@link #setTitle(String)}
 *  <li>{@link #setIcon(Icon)}
 * </ul>
 * <p>
 * There are a handful of stub methods that can be overridden as desired:
 * <ul>
 *  <li>{@link #componentActivated()} and {@link #componentDeactived()}
 *  <li>{@link #componentHidden()} and {@link #componentShown()}
 * </ul>
 * <p>
 * Note: This class was created so that implementors could add local actions within the constructor
 * without having to understand that they must first add themselves to the WindowManager.
 */

public abstract class ComponentProvider implements HelpDescriptor, ActionContextProvider {
	public static final String DEFAULT_WINDOW_GROUP = "Default";
	// maps for mapping old provider names and owner to new names and/or owner
	private static Map<String, String> oldOwnerMap = new HashMap<>();
	private static Map<String, String> oldNameMap = new HashMap<>();
	protected DockingTool dockingTool;
	private String name;
	private final String owner;
	private String title;
	private String subTitle;
	private String tabText;
	private Icon icon;
	private Set<DockingActionIf> actionSet = new LinkedHashSet<>();
	private String windowMenuGroup;
	private boolean isTransient;
	private HelpLocation helpLocation;
	private String group = DEFAULT_WINDOW_GROUP;
	private WindowPosition defaultWindowPosition = WindowPosition.WINDOW;
	private WindowPosition defaultIntraGroupPosition = WindowPosition.STACK;
	private final Class<?> contextType;

	private long instanceID = UniversalIdGenerator.nextID().getValue();
	private boolean instanceIDHasBeenInitialized;

	/**
	 * Creates a new component provider with a default location of {@link WindowPosition#WINDOW}.
	 * @param tool The tool will manage and show this provider
	 * @param name The providers name.  This is used to group similar providers into a tab within
	 *        the same window.
	 * @param owner The owner of this provider, usually a plugin name.
	 */
	public ComponentProvider(DockingTool tool, String name, String owner) {
		this(tool, name, owner, null);
	}

	/**
	 * Creates a new component provider with a default location of {@link WindowPosition#WINDOW}.
	 * @param tool The tool that will manage and show this provider.
	 * @param name The providers name.  This is used to group similar providers into a tab within
	 *        the same window.
	 * @param owner The owner of this provider, usually a plugin name.
	 * @param contextType the type of context supported by this provider; may be null (see
	 *        {@link #getContextType()}
	 */
	public ComponentProvider(DockingTool tool, String name, String owner, Class<?> contextType) {
		this.dockingTool = tool;
		this.name = name;
		this.owner = owner;
		this.title = name;
		this.contextType = contextType;
	}

	/**
	 * Returns the component to be displayed
	 * @return the component to be displayed
	 */
	public abstract JComponent getComponent();

	/**
	 * A method that allows children to set the <tt>instanceID</tt> to a desired value (useful for
	 * restoring saved IDs).
	 * <p>
	 * Note: this can be called only once during the lifetime of the calling instance; otherwise, an 
	 * {@link AssertException} will be thrown.
	 * @param newID the new ID of this provider
	 */
	protected void initializeInstanceID(long newID) {
		if (instanceIDHasBeenInitialized) {
			if (newID != instanceID) {
				throw new AssertException("Cannot initialize the instanceID more than once");
			}
		}

		instanceIDHasBeenInitialized = true;
		instanceID = newID;
	}

	/**
	 * A unique ID for this provider
	 * @return unique ID for this provider
	 */
	public final long getInstanceID() {
		return instanceID;
	}

	// Default implementation
	public void requestFocus() {

		KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
		Component focusOwner = kfm.getFocusOwner();
		if (focusOwner != null && SwingUtilities.isDescendingFrom(focusOwner, getComponent())) {
			return;
		}

		getComponent().requestFocus();
	}

	/**
	 * Returns true if this provider has focus
	 * 
	 * @return true if this provider has focus
	 */
	public boolean isFocusedProvider() {
		DockingWindowManager dwm = DockingWindowManager.getInstance(getComponent());
		if (dwm == null) {
			return false; // can happen in testing
		}
		ComponentPlaceholder placeholder = dwm.getFocusedComponent();
		return placeholder != null && placeholder.getProvider() == this;
	}

	/**
	 * Adds this provider to the tool in a new window that is not initially visible.  The provider
	 * will then show up in the "Windows" menu of the tool
	 */
	public void addToTool() {
		if (isInTool()) {
			throw new IllegalStateException("Component already added: " + name);
		}
		dockingTool.addComponentProvider(this, false);
		for (DockingActionIf action : actionSet) {
			dockingTool.addLocalAction(this, action);
		}
		if (subTitle != null) {
			setSubTitle(subTitle);
		}
	}

	/**
	 * Removes this provider from the tool.
	 */
	public void removeFromTool() {
{'fraction_non_alphanumeric': 0.08743093922651933, 'fraction_numerical': 0.0005524861878453039, 'mean_word_length': 4.224025974025974, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4154734', 'n_tokens_mistral': 4017, 'n_tokens_neox': 3824, 'n_words': 1628}