001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2020, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022 * USA.
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * -------------------
028 * BlockContainer.java
029 * -------------------
030 * (C) Copyright 2004-2020, by Object Refinery Limited.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 */
036
037package org.jfree.chart.block;
038
039import java.awt.Graphics2D;
040import java.awt.geom.Rectangle2D;
041import java.io.Serializable;
042import java.util.ArrayList;
043import java.util.Collections;
044import java.util.Iterator;
045import java.util.List;
046
047import org.jfree.chart.entity.EntityCollection;
048import org.jfree.chart.entity.StandardEntityCollection;
049import org.jfree.chart.ui.Size2D;
050import org.jfree.chart.util.Args;
051import org.jfree.chart.util.PublicCloneable;
052
053/**
054 * A container for a collection of {@link Block} objects.  The container uses
055 * an {@link Arrangement} object to handle the position of each block.
056 */
057public class BlockContainer extends AbstractBlock
058        implements Block, Cloneable, PublicCloneable, Serializable {
059
060    /** For serialization. */
061    private static final long serialVersionUID = 8199508075695195293L;
062
063    /** The blocks within the container. */
064    private List blocks;
065
066    /** The object responsible for laying out the blocks. */
067    private Arrangement arrangement;
068
069    /**
070     * Creates a new instance with default settings.
071     */
072    public BlockContainer() {
073        this(new BorderArrangement());
074    }
075
076    /**
077     * Creates a new instance with the specified arrangement.
078     *
079     * @param arrangement  the arrangement manager ({@code null} not
080     *                     permitted).
081     */
082    public BlockContainer(Arrangement arrangement) {
083        Args.nullNotPermitted(arrangement, "arrangement");
084        this.arrangement = arrangement;
085        this.blocks = new ArrayList();
086    }
087
088    /**
089     * Returns the arrangement (layout) manager for the container.
090     *
091     * @return The arrangement manager (never {@code null}).
092     */
093    public Arrangement getArrangement() {
094        return this.arrangement;
095    }
096
097    /**
098     * Sets the arrangement (layout) manager.
099     *
100     * @param arrangement  the arrangement ({@code null} not permitted).
101     */
102    public void setArrangement(Arrangement arrangement) {
103        Args.nullNotPermitted(arrangement, "arrangement");
104        this.arrangement = arrangement;
105    }
106
107    /**
108     * Returns {@code true} if there are no blocks in the container, and
109     * {@code false} otherwise.
110     *
111     * @return A boolean.
112     */
113    public boolean isEmpty() {
114        return this.blocks.isEmpty();
115    }
116
117    /**
118     * Returns an unmodifiable list of the {@link Block} objects managed by
119     * this arrangement.
120     *
121     * @return A list of blocks.
122     */
123    public List getBlocks() {
124        return Collections.unmodifiableList(this.blocks);
125    }
126
127    /**
128     * Adds a block to the container.
129     *
130     * @param block  the block ({@code null} permitted).
131     */
132    public void add(Block block) {
133        add(block, null);
134    }
135
136    /**
137     * Adds a block to the container.
138     *
139     * @param block  the block ({@code null} permitted).
140     * @param key  the key ({@code null} permitted).
141     */
142    public void add(Block block, Object key) {
143        this.blocks.add(block);
144        this.arrangement.add(block, key);
145    }
146
147    /**
148     * Clears all the blocks from the container.
149     */
150    public void clear() {
151        this.blocks.clear();
152        this.arrangement.clear();
153    }
154
155    /**
156     * Arranges the contents of the block, within the given constraints, and
157     * returns the block size.
158     *
159     * @param g2  the graphics device.
160     * @param constraint  the constraint ({@code null} not permitted).
161     *
162     * @return The block size (in Java2D units, never {@code null}).
163     */
164    @Override
165    public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) {
166        return this.arrangement.arrange(this, g2, constraint);
167    }
168
169    /**
170     * Draws the container and all the blocks within it.
171     *
172     * @param g2  the graphics device.
173     * @param area  the area.
174     */
175    @Override
176    public void draw(Graphics2D g2, Rectangle2D area) {
177        draw(g2, area, null);
178    }
179
180    /**
181     * Draws the block within the specified area.
182     *
183     * @param g2  the graphics device.
184     * @param area  the area.
185     * @param params  passed on to blocks within the container
186     *                ({@code null} permitted).
187     *
188     * @return An instance of {@link EntityBlockResult}, or {@code null}.
189     */
190    @Override
191    public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
192        // check if we need to collect chart entities from the container
193        EntityBlockParams ebp;
194        StandardEntityCollection sec = null;
195        if (params instanceof EntityBlockParams) {
196            ebp = (EntityBlockParams) params;
197            if (ebp.getGenerateEntities()) {
198                sec = new StandardEntityCollection();
199            }
200        }
201        Rectangle2D contentArea = (Rectangle2D) area.clone();
202        contentArea = trimMargin(contentArea);
203        drawBorder(g2, contentArea);
204        contentArea = trimBorder(contentArea);
205        contentArea = trimPadding(contentArea);
206        Iterator iterator = this.blocks.iterator();
207        while (iterator.hasNext()) {
208            Block block = (Block) iterator.next();
209            Rectangle2D bounds = block.getBounds();
210            Rectangle2D drawArea = new Rectangle2D.Double(bounds.getX()
211                    + area.getX(), bounds.getY() + area.getY(),
212                    bounds.getWidth(), bounds.getHeight());
213            Object r = block.draw(g2, drawArea, params);
214            if (sec != null) {
215                if (r instanceof EntityBlockResult) {
216                    EntityBlockResult ebr = (EntityBlockResult) r;
217                    EntityCollection ec = ebr.getEntityCollection();
218                    sec.addAll(ec);
219                }
220            }
221        }
222        BlockResult result = null;
223        if (sec != null) {
224            result = new BlockResult();
225            result.setEntityCollection(sec);
226        }
227        return result;
228    }
229
230    /**
231     * Tests this container for equality with an arbitrary object.
232     *
233     * @param obj  the object ({@code null} permitted).
234     *
235     * @return A boolean.
236     */
237    @Override
238    public boolean equals(Object obj) {
239        if (obj == this) {
240            return true;
241        }
242        if (!(obj instanceof BlockContainer)) {
243            return false;
244        }
245        if (!super.equals(obj)) {
246            return false;
247        }
248        BlockContainer that = (BlockContainer) obj;
249        if (!this.arrangement.equals(that.arrangement)) {
250            return false;
251        }
252        if (!this.blocks.equals(that.blocks)) {
253            return false;
254        }
255        return true;
256    }
257
258    /**
259     * Returns a clone of the container.
260     *
261     * @return A clone.
262     *
263     * @throws CloneNotSupportedException if there is a problem cloning.
264     */
265    @Override
266    public Object clone() throws CloneNotSupportedException {
267        BlockContainer clone = (BlockContainer) super.clone();
268        // TODO : complete this
269        return clone;
270    }
271
272}