/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.esa.snap.netbeans.docwin;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.openide.windows.TopComponent;
import javax.swing.Action;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Logger;
/**
* A {@code TopComponent} designed to serve as an editor for a "document" object.
* In contrast to a "normal" {@code TopComponent}, a {@code DocumentTopComponent}
* retains a selected state even after component deactivation. It can also be undocked/floated
* into a {@link WorkspaceTopComponent} and thereby undergo the usual {@code TopComponent} lifecyle as
* indicated by the various notification methods given by the interface {@link NotifiableComponent}:
* <ol>
* <li>{@link #componentOpened()}/{@link #componentClosed()} method will be called if the corresponding internal frame is activated/deactivated;</li>
* <li>{@link #componentActivated()}/{@link #componentDeactivated()} method will be called if the corresponding internal frame is activated/deactivated;</li>
* <li>{@link #componentShowing()}/{@link #componentHidden()} method will be called if the corresponding internal frame is iconified/deiconified.</li>
* </ol>
* <p>
* Document windows keep a constant reference to the document object which it exposes through the window's lookup.
* Overrides may use the {@link #getDynamicContent() content} to alter the objects in the exposed lookup,
* however, the document object will always remain in it.
*
* @param <D> The document type.
* @param <V> The view type.
* @author Norman Fomferra
* @since 1.0
*/
public abstract class DocumentTopComponent<D, V> extends TopComponent
implements DocumentWindow<D, V>, NotifiableComponent {
private static final Logger LOG = Logger.getLogger(DocumentTopComponent.class.getName());
private final D document;
private final InstanceContent dynamicContent;
public DocumentTopComponent(D document) {
if (document == null) {
throw new NullPointerException("document");
}
this.document = document;
this.dynamicContent = new InstanceContent();
associateLookup(new ProxyLookup(Lookups.fixed(document), new AbstractLookup(dynamicContent)));
}
protected InstanceContent getDynamicContent() {
return dynamicContent;
}
@Override
public final D getDocument() {
return document;
}
@Override
public final TopComponent getTopComponent() {
return this;
}
@Override
public final boolean isSelected() {
return DocumentWindowManager.getDefault().getSelectedWindow() == this;
}
@Override
public void requestSelected() {
if (isOpened()) {
requestActive();
} else {
requestVisible();
DocumentWindowManager.getDefault().requestSelected(this);
}
}
@Override
public Action[] getActions() {
Action[] baseActions = super.getActions();
Action[] extraActions = WorkspaceTopComponent.getExtraActions(this);
if (extraActions.length > 0) {
ArrayList<Action> actions = new ArrayList<>(Arrays.asList(baseActions));
if (!actions.isEmpty()) {
actions.add(null);
}
actions.addAll(Arrays.asList(extraActions));
return actions.toArray(new Action[actions.size()]);
}
return baseActions;
}
@Override
public int getPersistenceType() {
return PERSISTENCE_NEVER;
}
/**
* Called when this component opened for the first time or after being closed.
*/
@Override
public void componentOpened() {
}
/**
* Called when this component was closed.
*/
@Override
public void componentClosed() {
}
/**
* Called when this component is about to be shown.
*/
@Override
public void componentShowing() {
}
/**
* Called when this component was hidden.
*/
@Override
public void componentHidden() {
}
/**
* Called when this component is activated.
*/
@Override
public void componentActivated() {
}
/**
* Called when this component is deactivated.
*/
@Override
public void componentDeactivated() {
}
/**
* Called when this component was selected.
* <p>
* Default implementation simply calls {@link #updateSelectedState}.
*/
@Override
public void componentSelected() {
updateSelectedState();
}
/**
* Called when this component was deselected.
* <p>
* Default implementation simply calls {@link #updateSelectedState}.
*/
@Override
public void componentDeselected() {
updateSelectedState();
}
/**
* Called when the document is about to be closed.
* The default implementation makes an attempt to close this window by
* calling {@code DocumentWindowManager.getDefault().closeWindow(this)}.
*/
@Override
public void documentClosing() {
DocumentWindowManager.getDefault().closeWindow(this);
}
/**
* Does anything that indicates the selected state of this component. The default implementation
* simply calls {@link #repaint()}.
*/
protected void updateSelectedState() {
repaint();
}
}