/******************************************************************* Copyright (c) 2001-2010 Apprisant Technologies Inc. All rights reserved. Apprisant Technologies permits non-exclusive royalty free use, copying and modification of this demo program source code for the purposes of evaluating the Apprisant Toolkit or building applications that use it. This software and documentation is provided "AS IS". APPRISANT TECHNOLOGIES DISCLAIMS ANY REPRESENTATIONS AND WARRANTIES, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTY OF MERCHANTABILITY AND FITNESS OF THIS PRODUCT FOR ANY PARTICULAR PURPOSE. APPRISANT TECHNOLOGIES SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY ANY PARTY, INCLUDING LOST PROFITS, ARISING FROM THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ITS DERIVATIONS. ********************************************************************/ package project; import java.awt.geom.*; import java.util.*; import java.io.*; import apprisant.diagram.*; import apprisant.diagram.data.*; import apprisant.diagram.env.AGLog; import apprisant.diagram.awtext.Dimension2D; import project.Job.Priority; // enum class import apprisant.diagram.render.AGRenderer; /* The element model and layout manager for the Project demo. The element model adds the headers. The layout manager maintains the jobs in left-aligned rows. */ public class ProjectModel extends KeyModel { // Header element display attribute static final String PRIORITY = "priority"; // Holds the header elements private ArrayList headers; public ProjectModel() { super(); super.add(createHeaderElements()); super.setLayout(new ProjectLayout()); } ArrayList createHeaderElements() { headers = new ArrayList(); GeneralElement e; // High priority header e = new GeneralElement("h1", 0.0, 0.0); e.setAttribute(PRIORITY, "High Priority"); e.setSelectable(false); headers.add(e); // Medium priority header e = new GeneralElement("h2", 0.0, 0.0); e.setAttribute(PRIORITY, "Medium Priority"); e.setSelectable(false); headers.add(e); // Low priority header e = new GeneralElement("h3", 0.0, 0.0); e.setAttribute(PRIORITY, "Low Priority"); e.setSelectable(false); headers.add(e); return headers; } /* Override these because the layout cannot be set externally, and this prevents Geo writing it to the diagram file. */ @Override public void setLayout (DiagramLayout layout) { } @Override public DiagramLayout getLayout() { return null; } class ProjectLayout extends AbstractLayout { // Name of the rectangle in the renderer definitions static final String PROJECT_RECT = "projectRect"; // Positioning constant static final double GAP = 12; // Parameters set in the calcParams method called at initialization. double verticalOffset = 0.0; double verticalIncrement = 0.0; double horizontalIncrement = 0.0; // Arrays to sort projects by priority, in left to right order. ArrayList highRow = new ArrayList(); ArrayList mediumRow = new ArrayList(); ArrayList lowRow = new ArrayList(); boolean initialized = false; ProjectLayout() { super(); } /* Overriden to calculate the positioning parameters. This method is called when the diagram becomes displayable and subsequently when the sizes of the graphics drawn by the renderers may have changed. */ @Override public void initialize() { RenderManager renMgr = model.getDiagram().getRenderManager(); if (renMgr == null) return; try { // Calculate layout parameters from element bounds calcParams(); // Position the header elements positionHeaders(); highRow.clear(); mediumRow.clear(); lowRow.clear(); initialized = true; // Position any elements already in the model List elements = model.getElements(); if (elements.size() > headers.size()) added(elements); } catch (AGException ae) { AGLog.log("ProjectLayout", "initializing layout", AGLog.ERROR, ae); } } /** Calculates the layout parameters and sets the diagram's scroll increments. */ private void calcParams() throws AGException { // Get the project rectangle to use in the calculations RenderManager renMgr = model.getDiagram().getRenderManager(); RectangularShape projectRect = (RectangularShape) renMgr.getDefinitions().get(PROJECT_RECT); // Calculate positioning parameters using the bounds of the first // header element. GeneralElement h1 = headers.get(0); Rectangle2D bounds = renMgr.calcBounds ((AGRenderer) null, h1, RenderManager.B_PLAIN); if (bounds == null) throw new AGException("Null bounds for header."); verticalOffset = Math.round(bounds.getY() + bounds.getHeight()) + GAP; verticalIncrement = projectRect.getHeight() + 1.5 * GAP + verticalOffset; horizontalIncrement = projectRect.getWidth() + GAP; // Set the scroll increments ViewManager viewMgr = diagram.getViewManager(); viewMgr.setScrollIncrements (new Dimension2D.Double (horizontalIncrement, verticalIncrement)); } /** Position the header elements. */ private void positionHeaders() { headers.get(0).setPoint(0.0, 0.0); headers.get(1).setPoint(0.0, verticalIncrement); headers.get(2).setPoint(0.0, 2.0 * verticalIncrement); } /* Position all the elements in the model. Not used in this demo program. */ @Override public void update() { if (! initialized) return; positionRow(highRow, verticalOffset); positionRow(mediumRow, verticalOffset + verticalIncrement); positionRow(lowRow, verticalOffset + 2 * verticalIncrement); valid = true; } /* Position projects by priority as they are added. May get called before initialize. */ @Override public void added (Collection elements) { if (! initialized) return; for (GeneralElement e : elements) { Job job = (Job) e.getDataObject(); if (job == null) continue; // skip header elements // Position the element and add it to the correct row Priority priority = job.getPriority(); if (priority == Priority.HIGH) { highRow.add(e); e.setPoint((highRow.size()-1) * horizontalIncrement, verticalOffset); } else if (priority == Priority.MEDIUM) { mediumRow.add(e); e.setPoint((mediumRow.size()-1) * horizontalIncrement, verticalOffset + verticalIncrement); } else if (priority == Priority.LOW) { lowRow.add(e); e.setPoint((lowRow.size()-1) * horizontalIncrement, verticalOffset + 2 * verticalIncrement); } } } /* Close the gaps as projects are removed. Only gets called after the diagram has been displayed. */ @Override public void removed (Collection elements) { // Variables to track which rows are modified int highIdx = highRow.size(); int mediumIdx = mediumRow.size(); int lowIdx = lowRow.size(); for (GeneralElement e : elements) { Job job = (Job) e.getDataObject(); if (job == null) continue; Priority priority = job.getPriority(); // Remove the projects from the row arrays if (priority == Priority.HIGH) { highIdx = Math.min(highIdx, highRow.indexOf(e)); highRow.remove(e); } else if (priority == Priority.MEDIUM) { mediumIdx = Math.min(mediumIdx, mediumRow.indexOf(e)); mediumRow.remove(e); } else { lowIdx = Math.min(lowIdx, lowRow.indexOf(e)); lowRow.remove(e); } } // Reposition the projects in the rows from which projects have // been removed if ( highIdx < highRow.size() ) { positionRow(highRow, verticalOffset); model.moved(highRow.subList(highIdx, highRow.size())); } if ( mediumIdx < mediumRow.size() ) { positionRow(mediumRow, verticalOffset + verticalIncrement); model.moved (mediumRow.subList(mediumIdx, mediumRow.size())); } if ( lowIdx < lowRow.size() ) { positionRow(lowRow, verticalOffset + 2 * verticalIncrement); model.moved(lowRow.subList(lowIdx, lowRow.size())); } } /* Position one row of projects. */ private void positionRow (List priorityArray, double vertOffset) { int i = 0; for (GeneralElement e : priorityArray) { e.setPoint((i++) * horizontalIncrement, vertOffset); } } } }