/*******************************************************************************
 * Copyright (c) 2000, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.ui.internal;

import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;

/**
 * The abstract superclass for actions that depend on the active editor.
 * This implementation tracks the active editor (see <code>getActiveEditor</code>)
 * and updates the availability of the action when an editor becomes
 * active.
 * <p>
 * Subclasses must implement the following <code>IAction</code> method:
 * <ul>
 *   <li><code>run</code> - to do the action's work</li>
 * </ul>
 * </p>
 * <p>
 * Subclasses may extend any of the <code>IPartListener</code> methods if the
 * action availablity needs to be recalculated:
 * <ul>
 *   <li><code>partActivated</code></li>
 *   <li><code>partDeactivated</code></li>
 *   <li><code>partOpened</code></li>
 *   <li><code>partClosed</code></li>
 *   <li><code>partBroughtToTop</code></li>
 * </ul>
 * </p>
 * <p>
 * Subclasses may extend any of the <code>IPageListener</code> methods if the
 * action availablity needs to be recalculated:
 * <ul>
 *   <li><code>pageActivated</code></li>
 *   <li><code>pageClosed</code></li>
 *   <li><code>pageOpened</code></li>
 * </ul>
 * </p>
 * <p>
 * This method implements the <code>IPartListener</code> and
 * <code>IPageListener</code>interfaces, and automatically registers listeners
 * so that it can keep its enablement state up to date. Ordinarily, the
 * window's references to these listeners will be dropped automatically when
 * the window closes. However, if the client needs to get rid of an action
 * while the window is still open, the client must call
 * {@link IWorkbenchAction#dispose dispose} to give the action an
 * opportunity to deregister its listeners and to perform any other cleanup.
 * </p>
 */
public abstract class ActiveEditorAction extends PageEventAction {

    private IEditorPart activeEditor;

    /**
     * Creates a new action with the given text.
     *
     * @param text the string used as the text for the action,
     *   or <code>null</code> if there is no text
     * @param window the workbench window this action is
     *   registered with.
     */
    protected ActiveEditorAction(String text, IWorkbenchWindow window) {
        super(text, window);
        updateState();
    }

    /**
     * Notification that the active editor tracked
     * by the action is being activated.
     *
     * Subclasses may override.
     */
    protected void editorActivated(IEditorPart part) {
    }

    /**
     * Notification that the active editor tracked
     * by the action is being deactivated.
     *
     * Subclasses may override.
     */
    protected void editorDeactivated(IEditorPart part) {
    }

    /**
     * Return the active editor
     *
     * @return the page's active editor, and <code>null</code>
     *		if no active editor or no active page.
     */
    public final IEditorPart getActiveEditor() {
        return activeEditor;
    }

    @Override
	public void pageActivated(IWorkbenchPage page) {
        super.pageActivated(page);
        updateActiveEditor();
        updateState();
    }

    @Override
	public void pageClosed(IWorkbenchPage page) {
        super.pageClosed(page);
        updateActiveEditor();
        updateState();
    }

    @Override
	public void partActivated(IWorkbenchPart part) {
        super.partActivated(part);
        if (part instanceof IEditorPart) {
            updateActiveEditor();
            updateState();
        }
    }

    @Override
	public void partBroughtToTop(IWorkbenchPart part) {
        super.partBroughtToTop(part);
        if (part instanceof IEditorPart) {
            updateActiveEditor();
            updateState();
        }
    }

    @Override
	public void partClosed(IWorkbenchPart part) {
        super.partClosed(part);
        if (part instanceof IEditorPart) {
            updateActiveEditor();
            updateState();
        }
    }

    @Override
	public void partDeactivated(IWorkbenchPart part) {
        super.partDeactivated(part);
        if (part instanceof IEditorPart) {
            updateActiveEditor();
            updateState();
        }
    }

    /**
     * Set the active editor
     */
    private void setActiveEditor(IEditorPart part) {
        if (activeEditor == part) {
            return;
        }
        if (activeEditor != null) {
            editorDeactivated(activeEditor);
        }
        activeEditor = part;
        if (activeEditor != null) {
            editorActivated(activeEditor);
        }
    }

    /**
     * Update the active editor based on the current
     * active page.
     */
    private void updateActiveEditor() {
        if (getActivePage() == null) {
            setActiveEditor(null);
        } else {
            setActiveEditor(getActivePage().getActiveEditor());
        }
    }

    /**
     * Update the state of the action. By default, the action
     * is enabled if there is an active editor.
     *
     * Subclasses may override or extend this method.
     */
    protected void updateState() {
        setEnabled(getActiveEditor() != null);
    }

}
