package uk.ac.leeds.ccg.geotools; import java.lang.*; import java.awt.*; import java.util.*; import java.io.*; /** * A theme holds all of the information needed by a viewer to display a thematic map, including a layer, shadeing and highlightng scheem. * A theme acts as a container for all of the aspects that make up a thematic display of a geographic feature. It * also handles all of the comunication between viewers, layers and some highlights. * Any clicks in the viewer can be set to pass to a theme where it will be converted to an ID from the layer and then finaly set in the highlightManager. * Once constructed a theme can be added to multiple viewers without problems.
* There are a number of parts that make up a theme, and this is reflected by the
* number of constructers, the following is a list of all the parts.
* Constructors that lack parts will make their own as needed.
* The main parts that make up a full theme are: *
* By setting the TipData for a theme it is posible to set what this string
* should be for each feature.
* The GeoData supplied to this method sould assosiate feature ids found in this
* theme with numeric or string values to display in the tool tips.
*
* An example of use might be:
* theme.setTipData(shapefileReader.readData("Names"));
*
* @author James Macgill
* @see #getTipText
* @param d A GeoData containing the new Tool Tip data for this theme.
*/
public void setTipData(GeoData t){
if(tipData!=t){
tipData=t;
// notifyThemeChangedListeners(ThemeChangedEvent.GEOGRAPHY);
}
//???change this to .DATA
}
/**
* Some layers have the ability to display short labels for each feature.
*
* By setting the LabelData for a theme it is posible to set what this string
* should be for each feature.
* The GeoData supplied to this method sould assosiate feature ids found in this
* theme with numeric or string values to display in the labels.
*
* An example of use might be:
* theme.setLabelData(shapefileReader.readData("Names"));
*
* @author James Macgill
* @param d A GeoData containing the new Label data for this theme.
*/
public void setLabelData(GeoData labels){
if(labelData!=labels){
System.out.println("Label data set to "+labels);
labelData = labels;
this.notifyThemeChangedListeners(ThemeChangedEvent.DATA);
}
}
/**
*
* @author James Macgill
* @return A GeoData containing the label data for this theme.
*/
public GeoData getLabelData(){
return labelData;
}
/**
* Viewers have the ability to display short popup messages
* in the form of tool tips when the users mouse rests over features
* in the map.
*
* This method provides flexible tooltips at the expence of being a little less
* straight forward than setTipData().
* To construct setup a tooltip this method needs a format string wich is a string
* containing special characters that will be parsed, and an array of GeoData columns
* to be put into the formatstring when the tooltip is shown
*
* An example of use might be:
*
* TooltipArray[0]=shapefileReader.readData("Country");
* TooltipArray[1]=shapefileReader.readData("Population");
* theme.setComplexTipData(TooltipArray, "%s: %s");
* This would produce tooltips of the form "Norway: 40000000" when run. Note that more than
* one element can be used, and static strings can be a part of the tooltip.
*
*
* @author Kjetil Thuen
* @see #setTipData
* @see #getTipText
* @param t An array of GeoDatas containing the new Tool Tip data for this theme.
* @param ts A formatstring.
*/
public void setComplexTipData(GeoData t[], String ts) {
if (complexTipData != t) {
complexTipData = t;
}
tipformat = ts;
}
/**
* gets the current geoData.
*/
public GeoData getGeoData(){
return data;
}
/**
* Filters can be used to prevent a theme from showing all of the features in the layer it contains.
* Once a filter is in place, the id of each feature to be ploted is pased to the filter and the feature is only
* drawn if the filter OKs it.
* @author James Macgill
* @param filter An implementation of the filter interface that will be used.
*/
public void setFilter(Filter filter){
if(this.filter!=null){
this.filter.removeFilterChangedListener(this);
}
this.filter = filter;
this.filter.addFilterChangedListener(this);
}
/**
* Returns the current filter in use by this theme.
* @return Filter the current filter, if none has been set then this will be NULL
*/
public Filter getFilter(){
return filter;
}
/**
* When this method is called by a viewer it will carry out all actions needed to
* paint this theme into the graphics provided.
* @param g A Graphics context to paint into.
* @param scale the Scaler to use when displaying this theme
*/
protected void paintScaled(Graphics g,Scaler scale){
if(layer.getStatus()!=layer.COMPLETED){return;}
System.out.println("Constructing geographics with "+labelData);
GeoGraphics gg = new GeoGraphics(g,scale,shade,data,labelData,style,filter,1);
layer.paintScaled(gg);
}
/**
* gets the geographic bounds from this themes layer
* @return GeoRectangle the bounds for this theme (from its layer).
*/
public GeoRectangle getBounds(){
return layer.getBounds();
}
/**
* Finds the id of the feature in this themes layer assoiated with the given point.
* and then passes that ID onto this themes HighlightManager.
* @param p The GeoPoint to set the highlight to.
*/
public void setHighlight(GeoPoint p){
if(highlight != null){
highlight.setHighlight(layer.getID(p));
}
}
//The ID of the highlight in the highlight manager has changed
/**
* Called to notify this theme that the highlight has changed.
* Theme will handle notifing all viwers that contain it that
* its highlight needs repainting.
*
* Required by highlightChangedListener interface and should only
* be called by a highlighManager.
* @param hce a HighlightChangedEvent.
*/
public void highlightChanged(HighlightChangedEvent hce){
//notify viewers
notifyThemeChangedListeners(ThemeChangedEvent.HIGHLIGHT);
}
/**
* Called to notify this theme that the selection has changed.
* Theme will handle notifing all viwers that contain it that
* its selectino needs repainting.
* Required by selectionChangedListener interface and should only
* be called by a selectionManager.
* @param sce a SelectionChangedEvent.
*/
public void selectionChanged(SelectionChangedEvent sce){
//notify viewers
notifyThemeChangedListeners(ThemeChangedEvent.SELECTION);
}
/**
* Used by the themes layer to pass informaion about a change in state
* @param lce A LayerChangedEvent.
*/
public void layerChanged(LayerChangedEvent lce){
if(DEBUG)System.out.println("theme changed "+lce.getReason());
if(lce.getReason()==lce.DATA){
shade.setRange(this.data);
}
notifyThemeChangedListeners(lce.getReason());
}
/**
* Used by the themes filter to pass information about a change in state
* @param fce A FilterChangedEvent
*/
public void filterChanged(FilterChangedEvent fce){
notifyThemeChangedListeners(fce.getReason());
}
/**
* Used to request a change in highligt to the feature that contains
* the given point.
*
* Generaly only used by viewers that contain this theme.
* @param hpce A HighlightPositionChangedEvent
*/
public void highlightPositionChanged(HighlightPositionChangedEvent hpce){
if(highlight != null){
if(!hpce.isValid()){
highlight.setHighlight(-1);
return;
}
if(hpce.getSource() instanceof Viewer){
Viewer v = (Viewer)hpce.getSource();
if(!v.isThemeVisible(this)){
return;
}
if(layer instanceof LockableSize){
highlight.setHighlight(((LockableSize)layer).getID(hpce.getPosition(),v.getScale()));
return;
}
}
highlight.setHighlight(layer.getID(hpce.getPosition()));
}
}
/**
* Used to request a change selection region to the features
* contained by the given rectangle.
*
* Generaly only used by viewers that contain this theme.
* @param hpce A SelectionRegionChangedEvent
*/
public void selectionRegionChanged(SelectionRegionChangedEvent srce){
if(selectionMgr != null && ! isSelectionLock()){
selectionMgr.setSelection(layer.getIDs(srce.getRegion(),selectionMgr.CONTAINS));
}
}
/**
* Used to request to togle the selected state of the feature at this
* location to the features
* contained by the given rectangle.
*
* Generaly only used by viewers that contain this theme.
* @param hpce A SelectionRegionChangedEvent
*/
public void selectionPositionChanged(SelectionPositionChangedEvent spce){
//System.out.println("T--->("+name+")Received selection position changed event");
if(selectionMgr != null && ! isSelectionLock()){
selectionMgr.toggleSelection(layer.getID(spce.getLocation()));
// int[] id = {layer.getID(spce.getLocation())};
// selectionMgr.setSelection(id);
}
}
/**
* Gets the bounding rectangle that will fit round all of the currently selected featrues
* @since 0.6.5
* @return GeoRectangle that defines the bounds of the selection
*/
public GeoRectangle getSelectionMapExtent(){
GeoRectangle sme = new GeoRectangle();
if(selectionMgr == null){return sme;}
int[] selected = selectionMgr.getSelection();
// System.out.println("T--->("+name+")Getting map extent for "+selected+" "+selected[0]);
return layer.getBoundsOf(selected);
}
/**
* A convineince method to set the highlight for this theme.
* A call could be made to the themes HighlightManager directly if it is
* available, if not this method will do that for you.
* Any themes that share this themes HighlightManager will have their highlights
* changed as well.
* @param id The int representing the id of the feature to highlight.
*/
public void setHighlight(int id){
if(highlight != null){
highlight.setHighlight(id);
}
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
/**
* Fetches the id of the feature found in the layer at the given point.
* @param p A GeoPoint for the location to test.
* @return int The id found at that point.
*/
public int getID(GeoPoint p){
/* if(layer instanceof LockableSize){
return layer.getID(p,v.getScale());
}*/
return layer.getID(p);
}
/**
* looks up a short string relating to the feature specified by the
* provided ID.
* Viewer is able to take this string and display it over the feature in the form
* of a popup tool tip (hence the name).
* The data for the tip text is set by calling setTipData.
*
* JM 08/May/2000 updated documentation.
*
* @see #setTipData
* @see #setComplexTipData
* @author James Macgill
* @param id An int containing the id of the feature to fetch the tool tip text for.
* @return String A short text description for the chosen feature. Returns null if no tipData is set or no feature matches the specifed ID.
**/
public String getTipText(int id){
if (complexTipData != null && tipformat != null) {
int arraycount=0;
int max=complexTipData.length;
char[]format = tipformat.toCharArray();
String tooltip = new String("");
String tmp = new String(" ");
for (int i=0; i
*
* JM 08/May/2000 updated documentation.
*
* @see #setTipData
* @author James Macgill
* @param p A GeoPoint specifing the location of interest to fetch the tool tip text for.
* @return String A short text description for the chosen feature. Returns null if no tipData is set or no feature contains the specified point.
**/
public String getTipText(GeoPoint p,Scaler scale){
if(layer instanceof LockableSize){
return getTipText(((LockableSize)layer).getID(p,scale));
}
return getTipText(getID(p));
}
/**
* A cut down version of paintScaled that only paints the
* highlight.
* Called by viewer when needed.
* @param g A graphics context to paint into
* @param scale The Scaler to use.
*/
protected void paintHighlight(Graphics g,Scaler scale){
if(layer.getStatus()!=layer.COMPLETED){return;}
if(highlight!=null){
layer.paintHighlight(g,scale,highlight.getHighlight(),highlightStyle);
}
}
/**
* A cut down version of paintScaled that only paints the
* current selection.
* Called by viewer when needed.
* @param g A graphics context to paint into
* @param scale The Scaler to use.
*/
protected void paintSelection(Graphics g,Scaler scale){
if(layer.getStatus()!=layer.COMPLETED){return;}
//System.out.println("T--->("+name+")Do we have a selection manager?");
if(selectionMgr!=null){
// System.out.println("T--->("+name+")We have a selection manager!");
layer.paintSelection(g,scale,selectionMgr.getSelection(),selectionStyle);
}
}
/**
* request to be notified of theme changes.
* Listeners will be notified if any major aspect of this theme
* changes, the resuting ThemeChangedEvent contains a reson code
* to describe the nature of the change.
* The data for the tip text is set by calling setTipData.
* Used by viewers to keep uptodate with their themes.
* @param tcl a ThemeChangedListener to add
*/
public void addThemeChangedListener(ThemeChangedListener tcl){
listeners.addElement(tcl);
}
/**
* request to end being notified of theme changes.
* @param tcl the ThemeChangedListener to remove.
*/
public void removeThemeChangedListener(ThemeChangedListener tcl){
listeners.removeElement(tcl);
}
/**
* Notify all theme change listeners of a change in this theme.
* @param reason an int reason code describing what has changed in this theme; take from ThemeChangedEvent.DATA/GEOGRAPHY
*/
private void notifyThemeChangedListeners(int reason){
Vector l;
ThemeChangedEvent tce = new ThemeChangedEvent(this,reason);
synchronized(this) {l = (Vector)listeners.clone(); }
for (int i = 0; i < l.size();i++) {
((ThemeChangedListener)l.elementAt(i)).themeChanged(tce);
}
}
public Layer getLayer(){
return layer;
}
//ian's gaz widget seems to need this
public void setLayer(Layer l){
layer.removeLayerChangedListener(this);
layer = l;
layer.addLayerChangedListener(this);
this.notifyThemeChangedListeners(ThemeChangedEvent.GEOGRAPHY);
}
public String toString() {
return "uk.ac.leeds.ccg.geotools.Theme ("+name+")";
}
}