001: /*
002: The contents of this file are subject to the Common Public Attribution License
003: Version 1.0 (the "License"); you may not use this file except in compliance with
004: the License. You may obtain a copy of the License at
005: http://www.projity.com/license . The License is based on the Mozilla Public
006: License Version 1.1 but Sections 14 and 15 have been added to cover use of
007: software over a computer network and provide for limited attribution for the
008: Original Developer. In addition, Exhibit A has been modified to be consistent
009: with Exhibit B.
010:
011: Software distributed under the License is distributed on an "AS IS" basis,
012: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
013: specific language governing rights and limitations under the License. The
014: Original Code is OpenProj. The Original Developer is the Initial Developer and
015: is Projity, Inc. All portions of the code written by Projity are Copyright (c)
016: 2006, 2007. All Rights Reserved. Contributors Projity, Inc.
017:
018: Alternatively, the contents of this file may be used under the terms of the
019: Projity End-User License Agreeement (the Projity License), in which case the
020: provisions of the Projity License are applicable instead of those above. If you
021: wish to allow use of your version of this file only under the terms of the
022: Projity License and not to allow others to use your version of this file under
023: the CPAL, indicate your decision by deleting the provisions above and replace
024: them with the notice and other provisions required by the Projity License. If
025: you do not delete the provisions above, a recipient may use your version of this
026: file under either the CPAL or the Projity License.
027:
028: [NOTE: The text of this license may differ slightly from the text of the notices
029: in Exhibits A and B of the license at http://www.projity.com/license. You should
030: use the latest text at http://www.projity.com/license for your modifications.
031: You may not remove this license text from the source files.]
032:
033: Attribution Information: Attribution Copyright Notice: Copyright © 2006, 2007
034: Projity, Inc. Attribution Phrase (not exceeding 10 words): Powered by OpenProj,
035: an open source solution from Projity. Attribution URL: http://www.projity.com
036: Graphic Image as provided in the Covered Code as file: openproj_logo.png with
037: alternatives listed on http://www.projity.com/logo
038:
039: Display of Attribution Information is required in Larger Works which are defined
040: in the CPAL as a work which combines Covered Code or portions thereof with code
041: not governed by the terms of the CPAL. However, in addition to the other notice
042: obligations, all copies of the Covered Code in Executable and Source Code form
043: distributed must, as a form of attribution of the original author, include on
044: each user interface screen the "OpenProj" logo visible to all users. The
045: OpenProj logo should be located horizontally aligned with the menu bar and left
046: justified on the top left of the screen adjacent to the File menu. The logo
047: must be at least 100 x 25 pixels. When users click on the "OpenProj" logo it
048: must direct them back to http://www.projity.com.
049: */
050: package com.projity.pm.graphic.spreadsheet.common;
051:
052: import java.util.ArrayList;
053: import java.util.Iterator;
054: import java.util.LinkedList;
055: import java.util.StringTokenizer;
056:
057: import javax.swing.table.AbstractTableModel;
058:
059: import org.apache.commons.collections.Closure;
060:
061: import com.projity.field.Field;
062: import com.projity.field.FieldContext;
063: import com.projity.graphic.configuration.ActionList;
064: import com.projity.graphic.configuration.CellFormat;
065: import com.projity.graphic.configuration.CellStyle;
066: import com.projity.grouping.core.Node;
067: import com.projity.pm.assignment.Assignment;
068: import com.projity.pm.graphic.model.cache.CacheInterval;
069: import com.projity.pm.graphic.model.cache.GraphicNode;
070: import com.projity.pm.graphic.model.cache.NodeModelCache;
071: import com.projity.pm.graphic.model.event.CacheEvent;
072: import com.projity.pm.graphic.model.event.CacheListener;
073: import com.projity.pm.graphic.model.event.CompositeCacheEvent;
074: import com.projity.pm.graphic.spreadsheet.SpreadSheetColumnModel;
075: import com.projity.pm.graphic.spreadsheet.SpreadSheetUtils;
076:
077: /**
078: *
079: */
080: public class CommonSpreadSheetModel extends AbstractTableModel
081: implements CacheListener/*implements ObjectEvent.Listener*/{
082: protected NodeModelCache cache = null;
083: protected FieldContext fieldContext = null; // only used if a field context is set
084: protected CellStyle cellStyle;
085: protected ActionList actionList;
086: protected SpreadSheetColumnModel colModel;
087:
088: /**
089: *
090: */
091: public CommonSpreadSheetModel(NodeModelCache cache,
092: SpreadSheetColumnModel colModel, CellStyle cellStyle,
093: ActionList actionList) {
094: super ();
095: // this.fieldArray = fieldArray;
096: this .colModel = colModel;
097: this .cellStyle = cellStyle;
098: this .actionList = actionList;
099: setCache(cache);
100: }
101:
102: protected CacheListener cacheListener = null;
103:
104: public void setCache(NodeModelCache cache) {
105: if (cache == this .cache)
106: return;
107: if (this .cache != null)
108: this .cache.removeNodeModelListener(this );
109: this .cache = cache;
110: cache.addNodeModelListener(this );
111: fireTableDataChanged();
112:
113: }
114:
115: public void graphicNodesCompositeEvent(
116: CompositeCacheEvent compositeEvent) {
117: for (Iterator i = compositeEvent.getNodeEvents().iterator(); i
118: .hasNext();) {
119: final CacheEvent e = (CacheEvent) i.next();
120: e.forIntervals(new Closure() {
121: public void execute(Object obj) {
122: CacheInterval i = (CacheInterval) obj;
123: if (e.getType() == CacheEvent.NODES_CHANGED)
124: fireTableRowsUpdated(i.getStart(), i.getEnd());
125: else if (e.getType() == CacheEvent.NODES_INSERTED)
126: fireTableRowsInserted(i.getStart(), i.getEnd());
127: else if (e.getType() == CacheEvent.NODES_REMOVED)
128: fireTableRowsDeleted(i.getStart(), i.getEnd());
129: }
130: });
131: }
132: }
133:
134: // public CommonSpreadSheetModel(NodeModel model,ArrayList fieldArray,CellStyle cellStyle,String viewName) {
135: // this(NodeModelCacheFactory.getInstance().createDefaultCache(model,viewName),fieldArray,cellStyle);
136: // }
137: public ArrayList getFieldArray() {
138: return colModel.getFieldArray();
139: }
140:
141: public void setFieldArray(ArrayList fieldArray) {
142: colModel.setFieldArray(fieldArray);
143: }
144:
145: public NodeModelCache getCache() {
146: return cache;
147: }
148:
149: /*public CellStyle getCellStyle() {
150: return cellStyle;
151: }
152: public void setCellStyle(CellStyle cellStyle) {
153: this.cellStyle = cellStyle;
154: }*/
155:
156: public Field getFieldInColumn(int col) {
157: return null;
158: }
159:
160: public String getColumnName(int col) {
161: return "" + col;
162: }
163:
164: public int getRowMultiple() { //for TimeSpreadSheet
165: return 1;
166: }
167:
168: //real rows
169: public int getRowCount() {
170: return getCache().getSize() * getRowMultiple();
171: }
172:
173: public GraphicNode getNode(int row) {
174: return getNodeFromCacheRow(row);
175: }
176:
177: public void changeCollapsedState(int row) {
178: getCache().changeCollapsedState(
179: (GraphicNode) getCache().getElementAt(row));
180: }
181:
182: public CellFormat getCellProperties(GraphicNode node) {
183: return cellStyle.getCellFormat(node);
184: }
185:
186: private String[] actions = null;
187:
188: public String[] getActionList() {
189: if (actions == null) {
190: actions = convertActions(actionList.getList(getCache()
191: .getModel()));
192: }
193: return actions;
194: }
195:
196: public void clearActions() {
197: actions = null;
198: }
199:
200: public static String[] convertActions(String actionList) {
201: if (actionList == null)
202: return null;
203: StringTokenizer st = new StringTokenizer(actionList, ",;:|");
204: String[] actions = new String[st.countTokens()];
205: for (int i = 0; i < actions.length; i++)
206: actions[i] = st.nextToken();
207: return actions;
208: }
209:
210: protected Node getNodeInRow(int row) {
211: return SpreadSheetUtils.getNodeInRow(row, getRowMultiple(),
212: cache);
213: // GraphicNode gnode = getNodeFromCacheRow(row);
214: // if (gnode == null)
215: // return null;
216: // return gnode.getNode();
217:
218: }
219:
220: public LinkedList getPreviousVisibleNodesFromRow(int row) {
221: LinkedList siblings = null;
222: for (int r = row - 1; r >= 0; r--) {
223: Node node = getNodeInRow(r);
224: if (node.getImpl() instanceof Assignment)
225: continue;
226: if (siblings == null)
227: siblings = new LinkedList();
228: siblings.addFirst(node);
229: if (!node.isVoid())
230: return siblings;
231: }
232: return null; //no need to move nodes in this case since they are children of root
233: }
234:
235: protected Node getNextNonVoidSiblingFromRow(int row) {
236: int rowCount = getRowCount();
237: Node ref = getNodeInRow(row);
238: Object parent = ref.getParent();
239: for (int r = row + 1; r < rowCount; r++) {
240: Node node = getNodeInRow(r);
241: if (node.getImpl() instanceof Assignment)
242: continue;
243: if (node.getParent() != parent)
244: break;
245: if (!node.isVoid())
246: return node;
247: }
248: return null;
249: }
250:
251: private GraphicNode getNodeFromCacheRow(int row) {
252: return SpreadSheetUtils.getNodeFromCacheRow(row,
253: getRowMultiple(), cache);
254: //return (GraphicNode) getCache().getElementAt(row/getRowMultiple());
255: }
256:
257: protected int findNodeRow(Node node, int searchEnd) { // limit endpoint because parents are always above
258: for (int i = 0; i < searchEnd; i++) {
259: if (getNodeInRow(i) == node)
260: return i;
261: }
262: return -1;
263: }
264:
265: public int findGraphicNodeRow(Object node) {
266: int row = getCache().getRowAt(node);
267: if (row == -1)
268: return -1;
269: return row * getRowMultiple();
270: }
271:
272: public Object getObjectInRow(int row) {
273: if (row == -1)
274: return null;
275: GraphicNode gnode = getNodeFromCacheRow(row);
276: if (gnode == null)
277: return null;
278: return gnode.getNode().getImpl();
279:
280: }
281:
282: private int findObjectRow(Object object) {
283: for (int i = 0; i < getRowCount(); i++) {
284: if (getObjectInRow(i) == object)
285: return i;
286: }
287: return -1;
288: }
289:
290: public int getColumnCount() {
291: // TODO Auto-generated method stub
292: return -1;
293: }
294:
295: public Object getValueAt(int rowIndex, int columnIndex) {
296: // TODO Auto-generated method stub
297: return null;
298: }
299:
300: /**
301: * @see javax.swing.table.TableModel#getColumnClass(int)
302: */
303: public Class getColumnClass(int col) {
304: //if (col==0) return String.class;
305: return getFieldInColumn(col).getDisplayType();
306: }
307:
308: public void fireUpdateAll() {
309: fireTableDataChanged();
310: // fireUpdate(NULL_ROW,NULL_COL);
311: }
312:
313: //
314: // private static final int NULL_ROW = -1;
315: // private static final int NULL_COL = 0;
316: //
317: // /**
318: // * Update a single cell, a column, a row, or everything
319: // * @param row
320: // * @param col
321: // */
322: // private void fireUpdate(int row, int col) { //cache row
323: // if (row == NULL_ROW) {
324: // if (col == NULL_COL) {
325: // fireTableDataChanged(); // everything changed
326: // } else { // a column changed
327: //
328: // //TODO this isn't updating correctly. Is there any reason to update the cache? Cells are just updated?
329: // fireTableChanged(new TableModelEvent(
330: // this,
331: // 0,
332: // getRowCount()-1,
333: // col,
334: // TableModelEvent.UPDATE));
335: // }
336: // } else {
337: // if (col == NULL_COL) {
338: // fireTableRowsUpdated(row*getRowMultiple(),row*getRowMultiple()+getRowMultiple()-1); // a row changed
339: // } else {
340: // for (int i=0; i<getRowMultiple();i++)
341: // fireTableCellUpdated(row*getRowMultiple()+i, col); // a cell changed
342: // }
343: // }
344: // }
345: //
346: //
347: //
348: // public void objectChanged(ObjectEvent objectEvent) {
349: // Object object= objectEvent.getObject();
350: // if (objectEvent.getSource() != this) { // if this was the source, then the event has alrady been fired for the cell
351: // if (object == null) {
352: // fireUpdate(NULL_ROW,NULL_COL) ;
353: // return;
354: // }
355: // int row = findObjectRow(objectEvent.getObject());
356: // fireUpdate(row,NULL_COL);
357: // }
358: // Node node = objectToNode(objectEvent.getObject()); // find the node if any
359: // nodeChanged(node,NULL_COL,getRowCount());// do node parents recursively
360: // }
361: //
362: //
363: ///**
364: // * Recursively update parent nodes
365: // * @param node starting node
366: // * @param col column to update
367: // * @param searchEnd end row number to use when searching. Because parents are always above children there is no need to search
368: // * for a parent node past its child
369: // */ private void nodeChanged(Node node, int col, int searchEnd) {
370: // node = getCache().getWalkersModel().getParent(node); // initial child will have already been done. Note also using model and not cache.
371: // if (node == null)
372: // return;
373: // int row = findNodeRow(node,searchEnd);
374: // if (row != NULL_ROW) {
375: // fireUpdate(row,col);
376: // searchEnd = row;
377: // }
378: // nodeChanged(node,col,searchEnd);
379: // }
380:
381: /**
382: * Finds the node for this object
383: * @param object
384: * @return Node found, null if not found
385: */
386: private Node objectToNode(Object object) {
387: return getCache().getWalkersModel().search(object);
388: }
389:
390: /**
391: * @param fieldContext The fieldContext to set.
392: */
393: public void setFieldContext(FieldContext fieldContext) {
394: this .fieldContext = fieldContext;
395: }
396:
397: public FieldContext getFieldContext() {
398: return fieldContext;
399: }
400:
401: public boolean isRowEditable(int row) {
402: return true;
403: }
404:
405: }
|