/*
* @(#)AbstractView.java
*
* Copyright (c) 1996-2010 The authors and contributors of JHotDraw.
* You may not use, copy or modify this file, except in compliance with the
* accompanying license terms.
*/
package org.jhotdraw.app;
import javax.annotation.Nullable;
import java.net.URI;
import java.util.*;
import javax.swing.*;
import java.util.concurrent.*;
import java.util.prefs.*;
import org.jhotdraw.util.prefs.PreferencesUtil;
/**
* This abstract class can be extended to implement a {@link View}.
*
* @author Werner Randelshofer
* @version $Id$
*/
public abstract class AbstractView extends JPanel implements View {
private static final long serialVersionUID = 1L;
private Application application;
/**
* The executor used to perform background tasks for the View in a
* controlled manner. This executor ensures that all background tasks
* are executed sequentually.
*/
@Nullable protected ExecutorService executor;
/**
* This is set to true, if the view has unsaved changes.
*/
private boolean hasUnsavedChanges;
/**
* The preferences of the view.
*/
protected Preferences preferences;
/**
* This id is used to make multiple open views of the same URI
* identifiable.
*/
private int multipleOpenId = 1;
/**
* This is set to true, if the view is showing.
*/
private boolean isShowing;
/**
* The title of the view.
*/
private String title;
/** List of objects that need to be disposed when this view is disposed. */
@Nullable private LinkedList<Disposable> disposables;
/**
* The URI of the view.
* Has a null value, if the view has not been loaded from a URI
* or has not been saved yet.
*/
@Nullable protected URI uri;
/**
* Creates a new instance.
*/
public AbstractView() {
preferences = PreferencesUtil.userNodeForPackage(getClass());
}
/** Initializes the view.
* This method does nothing, subclasses don't neet to call super. */
@Override
public void init() {
}
/** Starts the view.
* This method does nothing, subclasses don't neet to call super. */
@Override
public void start() {
}
/** Activates the view.
* This method does nothing, subclasses don't neet to call super. */
@Override
public void activate() {
}
/** Deactivates the view.
* This method does nothing, subclasses don't neet to call super. */
@Override
public void deactivate() {
}
/** Stops the view.
* This method does nothing, subclasses don't neet to call super. */
@Override
public void stop() {
}
/**
* Gets rid of all the resources of the view.
* No other methods should be invoked on the view afterwards.
*/
@SuppressWarnings("unchecked")
@Override
public void dispose() {
if (executor != null) {
executor.shutdown();
executor = null;
}
if (disposables != null) {
for (Disposable d : (LinkedList<Disposable>)disposables.clone()) {
d.dispose();
}
disposables = null;
}
removeAll();
}
@Override
public boolean canSaveTo(URI uri) {
return true;
}
@Override
@Nullable public URI getURI() {
return uri;
}
@Override
public void setURI(@Nullable URI newValue) {
URI oldValue = uri;
uri = newValue;
if (preferences != null && newValue != null) {
preferences.put("projectFile", newValue.toString());
}
firePropertyChange(URI_PROPERTY, oldValue, newValue);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
setLayout(new java.awt.BorderLayout());
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
@Override
public void setApplication(Application newValue) {
Application oldValue = application;
application = newValue;
firePropertyChange("application", oldValue, newValue);
}
@Override
public Application getApplication() {
return application;
}
@Override
public JComponent getComponent() {
return this;
}
@Override
public boolean isEmpty() {
return getURI()==null&&!hasUnsavedChanges();
}
/**
* Returns true, if the view has unsaved changes.
* This is a bound property.
*/
@Override
public boolean hasUnsavedChanges() {
return hasUnsavedChanges;
}
protected void setHasUnsavedChanges(boolean newValue) {
boolean oldValue = hasUnsavedChanges;
hasUnsavedChanges = newValue;
firePropertyChange(HAS_UNSAVED_CHANGES_PROPERTY, oldValue, newValue);
}
/**
* Executes the specified runnable on the worker thread of the view.
* Execution is performed sequentially in the same sequence as the
* runnables have been passed to this method.
*/
@Override
public void execute(Runnable worker) {
if (executor == null) {
executor = Executors.newSingleThreadExecutor();
}
executor.execute(worker);
}
@Override
public void setMultipleOpenId(int newValue) {
int oldValue = multipleOpenId;
multipleOpenId = newValue;
firePropertyChange(MULTIPLE_OPEN_ID_PROPERTY, oldValue, newValue);
}
@Override
public int getMultipleOpenId() {
return multipleOpenId;
}
@Override
public void setShowing(boolean newValue) {
boolean oldValue = isShowing;
isShowing = newValue;
firePropertyChange(SHOWING_PROPERTY, oldValue, newValue);
}
@Override
public boolean isShowing() {
return isShowing;
}
@Override
public void markChangesAsSaved() {
setHasUnsavedChanges(false);
}
@Override
public void setTitle(String newValue) {
String oldValue = title;
title = newValue;
firePropertyChange(TITLE_PROPERTY, oldValue, newValue);
}
@Override
public String getTitle() {
return title;
}
/**
* Adds a disposable object, which will be disposed when the specified view
* is disposed.
*
* @param disposable
*/
@Override
public void addDisposable(Disposable disposable) {
if (disposables == null) {
disposables = new LinkedList<>();
}
disposables.add(disposable);
}
/**
* Removes a disposable object, which was previously added.
*
* @param disposable
*/
@Override
public void removeDisposable(Disposable disposable) {
if (disposables != null) {
disposables.remove(disposable);
if (disposables.isEmpty()) {
disposables = null;
}
}
}
}