omgraphichandlerlayer.java

来自「OpenMap是一个基于JavaBeansTM的开发工具包。利用OpenMap你」· Java 代码 · 共 1,519 行 · 第 1/4 页

JAVA
1,519
字号
     * reason the OMGraphicList is nulled out is so if another layer finishes
     * before yours does and gets repainted, your old OMGraphics don't get
     * painted along side their new ones - it's a mismatched situation. You can
     * set the ProjectionChangePolicy directly with the
     * setProjectionChangePolicy, or by overriding the getProjectionChangePolicy
     * method and returning the type you want by default if it is null.
     * 
     * @see com.bbn.openmap.layer.policy.ProjectionChangePolicy
     * @see com.bbn.openmap.layer.policy.StandardPCPolicy
     * @see com.bbn.openmap.layer.policy.ListResetPCPolicy
     */
    public void projectionChanged(ProjectionEvent pe) {
        if (Debug.debugging("layer")) {
            Debug.output("OMGraphicHandlerLayer " + getName()
                    + " projection changed, calling "
                    + getProjectionChangePolicy().getClass().getName());
        }
        getProjectionChangePolicy().projectionChanged(pe);
    }

    /**
     * Get the ProjectionChangePolicy that determines how a layer reacts and
     * gathers OMGraphics for a projection change.
     */
    public ProjectionChangePolicy getProjectionChangePolicy() {
        if (projectionChangePolicy == null) {
            projectionChangePolicy = new StandardPCPolicy(this);
        }
        return projectionChangePolicy;
    }

    /**
     * Set the ProjectionChangePolicy that determines how a layer reacts and
     * gathers OMGraphics for a projection change.
     */
    public void setProjectionChangePolicy(ProjectionChangePolicy pcp) {
        projectionChangePolicy = pcp;
        // Just to make sure,
        pcp.setLayer(this);
    }

    /**
     * Get the RenderPolicy that determines how an OMGraphicList is rendered.
     */
    public RenderPolicy getRenderPolicy() {
        if (renderPolicy == null) {
            renderPolicy = new StandardRenderPolicy(this);
        }
        return renderPolicy;
    }

    /**
     * Set the RenderPolicy that determines how the OMGraphicList is rendered.
     */
    public void setRenderPolicy(RenderPolicy rp) {
        renderPolicy = rp;
        // Just to make sure,
        rp.setLayer(this);
    }

    protected void interrupt() {
        try {
            synchronized (LAYERWORKER_LOCK) {
                if (layerWorker != null && interruptable) {
                    layerWorker.interrupt();
                }
            }
        } catch (SecurityException se) {
            Debug.output(getName()
                    + " layer caught a SecurityException when something tried to stop work on the worker thread");
        }
    }

    /**
     * Sets the SwingWorker off to call prepare(). If the SwingWorker passed in
     * is not null, start() is called on it.
     * 
     * @param worker null to reset the layerWorker variable, or a SwingWorker to
     *        start up.
     */
    protected void setLayerWorker(SwingWorker worker) {
        synchronized (LAYERWORKER_LOCK) {
            layerWorker = worker;

            if (layerWorker != null) {
                layerWorker.start();
            }
        }
    }

    protected SwingWorker getLayerWorker() {
        return layerWorker;
    }

    /**
     * Called from within the layer to create a LayerWorker to use for the
     * prepare() method. By default, a new LayerWorker is returned. This method
     * may be overridden to make the layer use an extended
     * LayerWorker/SwingWorker class.
     * 
     * @return SwingWorker/LayerWorker
     */
    protected SwingWorker createLayerWorker() {
        return new LayerWorker();
    }

    /**
     * This method is here to provide a default action for Layers as they act as
     * a ProjectionPainter. Normally, ProjectionPainters are expected to receive
     * the projection, gather/create OMGraphics that apply to the projection,
     * and render them into the Graphics provided. This is supposed to be done
     * in the same thread that calls this function, so the caller knows that
     * when this method returns, everything that the ProjectionPainter needed to
     * do is complete.
     * <P>
     * If the layer doesn't override this method, then the paint(Graphics)
     * method will be called.
     * 
     * @param proj Projection of the map.
     * @param g java.awt.Graphics to draw into.
     */
    public synchronized void renderDataForProjection(Projection proj, Graphics g) {
        if (proj == null) {
            Debug.error("Layer(" + getName()
                    + ").renderDataForProjection: null projection!");
            return;
        } else if (!proj.equals(getProjection())) {
            setProjection(proj.makeClone());
            setList(prepare());
        }
        paint(g);
    }

    /**
     * The default action is to get the OMGraphicList and render it.
     * 
     * @param g java.awt.Graphics object to render OMGraphics into.
     */
    public void paint(Graphics g) {
        getRenderPolicy().paint(g);
    }

    /**
     * A method that will launch a LayerWorker thread to call the prepare
     * method. This method will set in motion all the steps needed to create and
     * render the current OMGraphicList with the current projection. Nothing
     * more needs to be called, because the LayerWorker will be started, it will
     * call prepare(). Inside the prepare() method, the OMGraphicList should be
     * created and the OMGraphics generated for the current projection that can
     * be picked up in the getProjection() method, and the LayerWorker will call
     * workerComplete() which will call repaint() on this layer.
     */
    public void doPrepare() {
        synchronized (LAYERWORKER_LOCK) {
            if (isWorking()) {
                if (Debug.debugging("layer")) {
                    Debug.output(getName()
                            + " layer already working in prepare(), cancelling");
                }
                setCancelled(true);
                return;
            }
            // If there isn't a worker thread working on a projection
            // changed or other doPrepare call, then create a thread that
            // will do the real work. If there is a thread working on
            // this, then set the cancelled flag in the layer.
            setLayerWorker(createLayerWorker());
        }
    }

    /**
     * A check to see if the SwingWorker is doing something.
     */
    public boolean isWorking() {
        synchronized (LAYERWORKER_LOCK) {
            return (layerWorker != null && !layerWorker.isInterrupted());
        }
    }

    /**
     * This is the main method you should be concerned with when overriding this
     * class. You have to make sure that this method returns an OMGraphicList
     * that is ready to be rendered. That means they need to be generated with
     * the current projection, which can be retrieved by calling
     * getProjection().
     * <P>
     * 
     * This method will be called in a separate thread if doPrepare() is called
     * on the layer. This will automatically cause repaint() to be called, which
     * lets java know to call paint() on this class.
     * <P>
     * 
     * Note that the default action of this method is to get the OMGraphicList
     * as it is currently set in the layer, reprojects the list with the current
     * projection (calls generate() on them), and then returns the current list.
     * <P>
     * 
     * If your layer needs to change what is on the list based on what the
     * current projection is, you can either clear() the list yourself and add
     * new OMGraphics to it (remember to call generate(Projection) on them), and
     * return the list. You also have the option of setting a ListResetPCPolicy,
     * which will automatically set the list to null when the projection changes
     * before calling this method. The OMGraphicHandlerList will ignore a null
     * OMGraphicList.
     * <P>
     * 
     * NOTE: If you call prepare directly, you may need to call repaint(), too.
     * With all invocations of this method that are cause by a projection
     * change, repaint() will be called for you.
     * 
     * The method is synchronized in case renderDataForProjection() gets called
     * while in the middle of this method. For a different projection, that
     * would be bad.
     */
    public synchronized OMGraphicList prepare() {
        OMGraphicList currentList = getList();
        Projection proj = getProjection();

        // if the layer hasn't been added to the MapBean
        // the projection could be null.
        if (currentList != null && proj != null) {
            currentList.generate(proj);
        }

        return currentList;
    }

    /**
     * Set when the something has changed while a swing worker is gathering
     * graphics, and we want it to stop early.
     */
    // protected boolean cancelled = false;
    // protected Object CANCELLED_LOCK = new Object();
    protected final Object LAYERWORKER_LOCK = new Object();

    /**
     * Used to set the cancelled flag in the layer. The swing worker checks this
     * once in a while to see if the projection has changed since it started
     * working. If this is set to true, the swing worker quits when it is safe.
     */
    public void setCancelled(boolean set) {
        // synchronized (CANCELLED_LOCK) {
        synchronized (LAYERWORKER_LOCK) {
            // cancelled = set;
            if (set) {
                interrupt();// if the layerWorker is busy, stop it.
                // System.out.println(">>Interrupting (setCancelled)");
            }
        }
    }

    /** Check to see if the cancelled flag has been set. */
    public boolean isCancelled() {
        synchronized (LAYERWORKER_LOCK) {
            return layerWorker != null && layerWorker.isInterrupted();
        }
        /*
         * boolean ret = false; synchronized (CANCELLED_LOCK) { ret = cancelled; }
         * return ret;
         */
    }

    /**
     * The LayerWorker calls this method on the layer when it is done working.
     * If the calling worker is not the same as the "current" worker, then a new
     * worker is created.
     * 
     * @param worker the worker that has the graphics.
     */
    protected void workerComplete(LayerWorker worker) {
        synchronized (LAYERWORKER_LOCK) {
            if (layerWorker != worker) {
                return; //
            }
            if (layerWorker.isInterrupted()) {
                setCancelled(false); // reset
                setLayerWorker(createLayerWorker()); // try again with
                // current proj
                return;
            }
            // success!
            setLayerWorker(null);
            getProjectionChangePolicy().workerComplete((OMGraphicList) worker.get());
        }
        repaint();
        /*
         * if (!isCancelled()) { setLayerWorker(null);
         * getProjectionChangePolicy().workerComplete((OMGraphicList)
         * worker.get()); repaint(); } else { setCancelled(false);
         * setLayerWorker(createLayerWorker()); }
         */
    }

    /**
     * Since we can't have the main thread taking up the time to do the work to
     * create OMGraphics, we use this worker thread to do it.
     */
    class LayerWorker extends SwingWorker {
        /** Constructor used to create a worker thread. */
        public LayerWorker() {
            super();
        }

        /**
         * Compute the value to be returned by the <code>get</code> method.
         */
        public Object construct() {
            Debug.message("layer", getName() + "|LayerWorker.construct()");
            fireStatusUpdate(LayerStatusEvent.START_WORKING);
            String msg;

            try {

                long start = System.currentTimeMillis();
                OMGraphicList list = getRenderPolicy().prepare();
                long stop = System.currentTimeMillis();
                if (Debug.debugging("layer")) {
                    Debug.output(getName()
                            + "|LayerWorker.construct(): fetched "
                            + (list == null ? "null list "
                                    : (list.size() + " graphics ")) + "in "
                            + (double) ((stop - start) / 1000d) + " seconds");
                }
                return list;

            } catch (OutOfMemoryError e) {
                msg = getName() + "|LayerWorker.construct(): " + e.getMessage();
                if (Debug.debugging("layer")) {
                    Debug.output(msg);
                    e.printStackTrace();
                } else {
                    Debug.output(getName()
                            + " layer ran out of memory, attempting to recover...");
                }
            } catch (Exception e) {
                msg = getName() + "|LayerWorker.construct(): " + e.getMessage();
                Debug.output(msg);
                if (Debug.debugging("layer")) {
                    e.printStackTrace();
                }
            }

            // This is only called if there is an error.
            if (Debug.debugging("displayLayerErrors")) {
                fireRequestMessage(new InfoDisplayEvent(this, msg));
            }

            return null;
        }

        /**
         * Called on the event dispatching thread (not on the worker thread)
         * after the <code>construct</code> method has returned.
         */
        public void finished() {
            workerComplete(this);
            if (!isInterrupted()) {
                fireStatusUpdate(LayerStatusEvent.FINISH_WORKING);
            }
        }

        public String toString() {
            return getName() + " LayerWorker";
        }

    }

    /**
     * Overrides the Layer setProperties method. Also calls Layer's version. If
     * the ProjectionChangePolicy and RenderPolicy objects are set
     * programmatically and are PropertyConsumers, they will still have access
     * to properties if this method is called. Their property prefix will be
     * scoped as if the OMGraphicHandlerLayer had them created, with their
     * prefix being prefix + . + PropertyChangePolicyProperty and prefix + . +
     * RenderPolicyProperty.
     * 
     * @param prefix the token to prefix the property names
     * @param props the <code>Properties</code> object
     */
    public void setProperties(String prefix, Properties props) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?