001: /*
002: * uDig - User Friendly Desktop Internet GIS client
003: * http://udig.refractions.net
004: * (C) 2004, Refractions Research Inc.
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: */
017: package net.refractions.udig.project.render;
018:
019: import java.awt.Graphics2D;
020: import java.awt.Rectangle;
021:
022: import org.eclipse.core.runtime.IProgressMonitor;
023:
024: import com.vividsolutions.jts.geom.Envelope;
025:
026: /**
027: * Used to mark an implementation of RenderImpl.class; responsible for rendering a layer.
028: * <p>
029: * A renderer has the following responsibilities:
030: * <ul>
031: * <li>A renderer must draw to the image provided by it RenderContext</li>
032: * <li>A renderer reprojects victim data if required</li>
033: * <li>A renderer applies styles if necessary</li>
034: * <li>A renderer is responsible for registering with its layers to obtain notifications whent the
035: * layers' styles change</li>
036: * <li>If a renderer <b>does not </b> extends the RendererImpl class the renderer must notify its
037: * adapters(listeners) when its rendering state changes.</li>
038: * <li>If a renderer <b>does </b> extend the RendererImpl class it must call the setState() method
039: * when its render state changes or it wishes to notify its listeners that it needs to be redrawn.
040: * <p>
041: * The state that the renderer can use are the following:
042: * </p>
043: * <ul>
044: * <li>RENDERING - should be called when the renderer has data that it wishes to display on the
045: * screen. May be ignored if the executor uses a timer for refreshing rather than waiting for
046: * updates from the renderers</li>
047: * <li>DONE - Should be set when rendering is finished.</li>
048: * <li>RENDER_REQUEST - should be called when the renderer has received events indicating that it
049: * needs to be rerendered. The event listeners should <b>NEVER </b> call render(), instead
050: * setState(RENDER_REQUEST) should be used and the frame work will trigger a rerender, most-likely
051: * in a seperate thread.</li>
052: * </ul>
053: * </li>
054: * <li>If possible a renderer is responsible for registering with its data source, not layer, so it
055: * can receive notices of when the data changes. If another method of recieving update is required
056: * then the renderer is held responsible.</li>
057: * </ul>
058: *
059: * @author jeichar
060: * @since 0.1
061: */
062: public interface IRenderer {
063:
064: /** The name of the Extension Point for Renderers */
065: public static final String RENDER_EXT = "net.refractions.udig.project.renderer"; //$NON-NLS-1$
066:
067: /** Indicates that the renderer has been reset and does not have anything to show */
068: public static final int NEVER = 0x01;
069:
070: /** Indicates whether the renderer job is currently running */
071: public static final int RENDERING = 0x01 << 1;
072:
073: /**
074: * Indicates whether the renderer has finished rendering.
075: * <p>
076: * This implies that rendering has started and finished
077: */
078: public static final int DONE = 0x01 << 2;
079:
080: /** Indicates that the renderer has been disposed and can no longer be used */
081: public static final int DISPOSED = 0x01 << 3;
082:
083: /** Indicates that the renderer has started rendering but does not have data to be displayed */
084: public static final int STARTING = 0x01 << 5;
085:
086: /** Indicates that the renderer has been cancelled rendering */
087: public static final int CANCELLED = 0x01 << 6;
088:
089: /**
090: * When a renderer sets its state to RENDER_REQUEST that indicates that is needs to be
091: * rerendered. The container of the renderer(usually a renderExecutor) will respond by calling
092: * render. This is done so that the container can include run the renderer in a thread seperate
093: * from the one that called setState().
094: * <p> {@link #setRenderBounds(Envelope)} can be called to set the area that needs to be rendered}
095: */
096: public static final int RENDER_REQUEST = 0x01 << 4;
097:
098: /**
099: * Returns the current state of rendering.
100: * <p>
101: * The state is the current state of the {@linkplain org.eclipse.core.runtime.jobs.Job}
102: * </p>
103: * Options are:
104: * <ul>
105: * <li>{@linkplain #RENDERING}</li>
106: * <li>{@linkplain #DONE}</li>
107: * <li>{@linkplain #NEVER}</li>
108: * <li>{@linkplain #DISPOSED}</li>
109: * </ul>
110: *
111: * @return the current state of rendering.
112: */
113: public int getState();
114:
115: /**
116: * Requests the Renderer to render with the graphics2d object
117: * <p>
118: * This method will block
119: * </p>
120: *
121: * @param destination The objects that the Renderer will use for rendering
122: * @throws RenderException
123: */
124: public void render(Graphics2D destination, IProgressMonitor monitor)
125: throws RenderException;
126:
127: /**
128: * Ask the renderer to update the internal image using the smaller of getRenderBounds() or ViewportBounds.
129: *
130: * <h2>Render State</h2>
131: * Normally the RenderManager will update the screen every second. However if the renderer has data that must be displayed then
132: * it can call setState(RENDERING) and the Screen will be updated immediately. This should be called with care however since many
133: * such calls can cause performance problems.
134: *
135: *
136: * <h2>Internal Image</h2>
137: *
138: * The RenderContext maintains an "internal image" that you can access using getContext().getGraphics();
139: * you can use Image.createGraphics() to retrive a Graphics2d to draw with.
140: *
141: * Example Implementation:<pre><code>
142: * public void render( IProgressMonitor monitor ) throws RenderException {
143: * if( monitor == null ) monitor = NullProgressMonitor();
144: * Graphics2D g = getContext().getImage().createGraphics();
145: * render(g, monitor);
146: * }
147: * </code></pre>
148: *
149: * <h2>Updating a Portion of the Screen</h2>
150: *
151: * When the envelope (ie getRenderBounds()) is smaller than the ViewportBounds, the rendered area
152: * <b>DOES NOT TAKE UP THE WHOLE MapDisplay</b>. It only takes up the area that the envelope
153: * would map to. The purpose of this functionality is to allows only a small area of the
154: * MapDisplay to be refreshed rather than the whole area.
155: * <p>
156: * Please choose the smallest of:
157: * <ul>
158: * <li>getRenderBounds() - an Envelope in your CRS
159: * <li>viewPortBounds()
160: * </ul>
161: *
162: * </p>
163: * @see #getContext()
164: * @see IRenderContext#getImage()
165: * @see IRenderContext#getImage(int, int)
166: * <p>
167: * This method will block
168: * </p>
169: * <p>
170: * A value of null renders the bounds the entire viewport obtained from the
171: * ViewportModel.getBounds().
172: * </p>
173: * @throws RenderException
174: */
175: public void render(IProgressMonitor monitor) throws RenderException;
176:
177: /**
178: * Returns the renderer's context object
179: *
180: * @return the the renderer's context object
181: * @see IRenderContext
182: */
183: public IRenderContext getContext();
184:
185: /**
186: * Informs the renderer to dispose of resources
187: */
188: public void dispose();
189:
190: /**
191: * Indicates whether the framework is permitted to cache the results of the renderer.
192: *
193: * @return true if the framework may cache the resulting image and only request the new dirty
194: * areas.
195: */
196: public boolean isCacheable();
197:
198: /**
199: * Called to set the area that will be rendered.
200: */
201: public void setRenderBounds(Envelope boundsToRender);
202:
203: /**
204: * Gets the area that will be rendered next.
205: * <p>
206: * Please make use of the smaller of getRenderBounds() or the viewport bounds
207: * when rendering.
208: * </p>
209: *
210: * @return bounds to be drawn next
211: */
212: public Envelope getRenderBounds();
213:
214: /**
215: * Similar to render(Envelope) except the area is defined in screen coordinates. Performs the
216: * screen to world transformation and calls render(Envelope).
217: *
218: * @param screenArea the area of the screen to re-render.
219: */
220: public void setRenderBounds(Rectangle screenArea);
221:
222: }
|