Files
secondo/Javagui/viewer/hoese/Background.java
2026-01-23 17:03:45 +08:00

447 lines
12 KiB
Java

package viewer.hoese;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.swing.JComponent;
import sj.lang.ListExpr;
import tools.Reporter;
/**
* This class is to be extended by classes representing different kinds of
* backgrounds in the HoeseViever, e.g. SimpleBackground, ImageBackground, or
* TiledBackground.
*
* Specializations of this class should override the inherited paint() method.
*
* @author Christian Duentgen
*/
public abstract class Background {
private static final long serialVersionUID = 9039714158763811782L;
/**
* The name of the Background
*/
protected String name;
/**
* A license string to be displayed with the background
*/
protected String license;
/**
* The boundary of the complete background.
*/
protected Rectangle2D.Double bbox;
/**
* Structure to maintain the set of registered listeners
*/
protected LinkedList<BackgroundListener> listeners;
/**
* Whether the Background's bounding box is considered in calculation of the
* world's bounding box.
*/
protected boolean useforbbox;
/**
* String constant used as key for license within Property
*/
public static final String KEY_LICENSE = "license";
/**
* String constant used as key for name within Property
*/
public static final String KEY_NAME = "name";
/**
* String constant used as key for bbox within Property
*/
public static final String KEY_BBOX = "bbox";
/**
* String constant used as key for useforbbox within Property
*/
public static final String KEY_USEFORBBOX = "useforbbox";
/**
* String constant used as key for the background class name within Property
*/
public static final String KEY_BACKGROUNDCLASSNAME = "backgroundclassname";
@Override
public String toString(){
return getClass().getName()+"["+
"name = " + name + ", " +
"license = " + license + ", " +
"useforbbox = " + useforbbox + ", " +
"bbox = " + bbox + "] ";
}
/** Paints the background to g using the clipRect as bounding box and at as
* the transformation from world to screen coordinates.
*
**/
public abstract void paint(JComponent parent, Graphics2D g, AffineTransform at, Rectangle2D clipRect);
/** Returns a zoom value ensring that only a certain zoom level
* should be used, e.g., in a tiled map to ensure a non resized tile view.
**/
public double getAntiScale( AffineTransform at, Rectangle2D clipRect){
return 1.0;
}
/** Returns the zoom factor for single zoom in, zoom out.
**/
public double getZoomStep(){
return 1.25;
}
/** Returns true, if preload is supported. **/
public boolean supportsPreload(){
return false;
}
/** Returns the number of files to download if preloading is started
**/
public int numberOfPreloadFiles(Rectangle2D.Double clipRect){
return 0;
}
/** starts preloading of files.
**/
public void preload(Rectangle2D.Double clipRect, PreloadObserver observer){
}
/** Cancels a running preloading **/
public void cancelPreload() {
}
/**
* The constructor sets all member variables to null. SInce this is an
* abstract class, it should never be used anyway.
**/
public Background() {
name = null;
license = null;
bbox = null;
listeners = new LinkedList<BackgroundListener>();
}
/**
* Sets the Background's boundary (world coordinates)
* @param rect
* A Rectangle2D defining the Background's boundary
*/
public void setBBox(Rectangle2D.Double rect) {
bbox = (Rectangle2D.Double) rect.clone();
}
/**
* Returns the Background's boundary (world coordinates)
* @return The Background's boundary
*/
public Rectangle2D.Double getBBox() {
return bbox;
}
/**
* Display a dialog to allow a user to set up parameters for the Background.
* @param parent
* The parent of the dialog component used.
*/
public abstract void showConfigDialog(JComponent parent);
/**
* Set up the Background with parameters given as a Properties object. Can
* be used to restore the Background settings, e.g. from a file. All
* registered Listeners are informed. Additional data may be retrieved from
* files rooted at the given path.
*
* @param p
* The Background settings to restore.
* @param backgrounddatapath
* A path to a directory where additional data is stored in
* files.
*/
public void setConfiguration(Properties p, String backgrounddatapath) {
String n = p.getProperty(KEY_NAME);
if (n == null) {
Reporter.writeWarning("Could not set Background property: "
+ KEY_NAME + " not found).");
name = "Unnamed " + this.getClass().getName();
} else {
name = n;
}
n = p.getProperty(KEY_LICENSE);
if (n == null) {
Reporter.writeWarning("Could not set Background property: "
+ KEY_LICENSE + " not found).");
n = "";
} else {
license = null;
}
n = p.getProperty(KEY_BBOX);
if (n == null) {
Reporter.writeWarning("Could not set Background property: "
+ KEY_BBOX + " not found).");
bbox = null;
} else {
Rectangle2D.Double b = createRectangle2DFromString(n);
if (b != null) {
bbox = b;
}
}
n = p.getProperty(KEY_USEFORBBOX);
useforbbox = (n != null) && (n == "yes");
}
/**
* Creates a {@link Rectangle2D.Double} from its String representation, e.g.
* to restore a rectangle from a value in a {@link Properties} object.
*
* @param s
* The String to read from
* @return The Rectangle2D.Double represented by the String parameter
*/
public static Rectangle2D.Double createRectangle2DFromString(String s) {
if (s == null) {
return null;
}
StringTokenizer st = new StringTokenizer(s);
double[] values = new double[4];
int pos = 0;
while (st.hasMoreTokens() && pos < 4) {
Double d = Double.valueOf(st.nextToken());
if (d == null) {
return null;
}
values[pos] = d.doubleValue();
pos++;
}
if (st.hasMoreTokens() || pos < 4) {
return null;
}
return new Rectangle2D.Double(values[0], values[1], values[2],
values[3]);
}
/**
* Return the Background's settings as a Properties object. The Properties
* can be used to save Background settings for later reference. Additional
* data may be stored to files rooted at the given path.
*
* @param backgrounddatapath
* Path, where to store data files.
* @return The Background's settings as a Properties object.
*/
public Properties getConfiguration(String backgrounddatapath) {
Properties p = new Properties();
p.setProperty(KEY_BACKGROUNDCLASSNAME, this.getClass().getName());
if (name != null) {
p.setProperty(KEY_NAME, name);
}
if (license != null) {
p.setProperty(KEY_LICENSE, license);
}
if (bbox != null) {
String bboxstr = "" + bbox.getX() + " " + bbox.getY() + " "
+ bbox.getWidth() + " " + bbox.getHeight();
p.setProperty(KEY_BBOX, bboxstr);
}
if(useforbbox) {
p.setProperty(KEY_USEFORBBOX, "yes");
} else {
p.setProperty(KEY_USEFORBBOX, "no");
}
return p;
}
/**
* Add an Object as a listener to the Background. Listeners will be informed
* when the Background's content changed, so that it might be painted again.
* @param l
* The Object to enlist as a listener.
*/
public final void addBackgroundListener(BackgroundListener l) {
if (!listeners.contains(l)) {
listeners.add(l);
}
}
/**
* Removes an Object from the Background's listener list. That object will
* no longer be informed about changes to the Background.
* @param l
* The Object to remove from the listener list.
*/
public final void removeBackgroundListener(BackgroundListener l) {
listeners.remove(l);
}
/**
* This is a call-back method to be called by external objects requesting
* the Background to update it's internal data. E.g. it could be called by a
* FileDownloadManager after a requestes map tile download has been
* finished.
*
*/
public void handleBackgroundDataChangedEvent(BackgroundChangedEvent evt) {
// empty implementation
}
/**
* Returns the Background's name, e.g. to allow to choose between different
* available Backgrounds.
* @return The Background's name.
*/
public final String getName() {
return name;
}
/**
* Returns a text with a license to which the Background is bound. Many maps
* or pictures come with a license stating to display a copyright or license
* message together with the map/ picture. The returned license should be
* displayed at an appropriate place.
* @return The Background's license.
*/
public final String getLicense() {
return license;
}
/**
* Informs all enlisted Listeners about an update of the Background's state.
*/
protected final void informListeners(BackgroundChangedEvent evt) {
ListIterator<BackgroundListener> i = listeners.listIterator(0);
while (i.hasNext()) {
i.next().handleBackgroundChangedEvent(evt);
}
}
/**
* Check the flag that indicates whether the Background is to be considered
* when calculation the world's dimensions.
*
* @return true, iff the Background's bbox is considered in world's bbox.
*/
public final boolean useForBoundingBox() {
return useforbbox;
}
public final void setUseForBoundingBox(boolean b){
useforbbox = b;
}
/**
* Creates a nested list representation of the Background's configuration,
* that can be saved as part of a saved GUI session. The provided path
* indicates a directory where additional data files may be stored.
*
* @param backgrounddatapath
* Path to the data directory
* @return The listExpr representing this object.
*/
public ListExpr toListExpr(String backgrounddatapath) {
Properties p = getConfiguration(backgrounddatapath);
return ListExpr.fromProperties(p);
}
/**
* Restores the Background settings from a nested list representation of
* Background's configuration, so that the Background can be restored when
* loading a saved GUI session. The provided path indicates the directory
* with additional data files used for restoration.
*
* @param l
* The listExpr representing this object.
* @param backgrounddatapath
* Path to the data directory
*/
public void readFromList(ListExpr l, String backgrounddatapath) {
Properties p = new Properties();
ListExpr.toProperties(l, p); // ignore boolean result;
setConfiguration(p, backgrounddatapath);
}
/**
* Factory method, that restores and returns any Background object
* from an Properties object. If restoration fails, a SimpleBackground is
* returned.
*
* @param p
* The Properties to restore from.
* @param backgrounddatapath
* A directory with additional data.
* @return The restored Background object.
*/
public static final Background createFromProperties(Properties p,
String backgrounddatapath) {
String bgclassname = p.getProperty(KEY_BACKGROUNDCLASSNAME);
if (bgclassname == null) {
Reporter.writeError("Could not restore the Background (cannot determine Background class).");
return new SimpleBackground();
}
try {
Background inst = (Background) Class.forName(bgclassname)
.newInstance();
inst.setConfiguration(p, backgrounddatapath);
return inst;
} catch(Exception e) {
Reporter.writeError("Could not restore the Background (failed to create the instance).");
Reporter.debug(e);
return new SimpleBackground();
}
}
/**
* Factory method, that restores and returns any Background object
* from a ListExpr object. If restoration fails, a SimpleBackground is
* returned.
*
* @param l
* The ListExpr to restore from.
* @param backgrounddatapath
* A directory with additional data.
* @return The restored Background object.
*/
public static final Background createFromListExpr(ListExpr l,
String backgrounddatapath) {
Properties p = new Properties();
while (!(l.isAtom() || l.isEmpty())) {
ListExpr pair = l.first();
l = l.rest();
if ((pair.listLength() == 2)
&& (pair.first().isAtom() && pair.first().atomType() == ListExpr.STRING_ATOM)
&& (pair.second().isAtom() && pair.second().atomType() == ListExpr.TEXT_ATOM)) {
String key = pair.first().stringValue();
String value = pair.second().stringValue();
p.setProperty(key, value);
}
}
return createFromProperties(p, backgrounddatapath);
}
}