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.assignment;
051:
052: import java.util.Collection;
053: import java.util.Iterator;
054:
055: import javax.swing.undo.UndoableEditSupport;
056:
057: import com.projity.association.AssociationList;
058: import com.projity.configuration.Settings;
059: import com.projity.datatype.TimeUnit;
060: import com.projity.grouping.core.Node;
061: import com.projity.pm.resource.Resource;
062: import com.projity.pm.resource.ResourceImpl;
063: import com.projity.pm.resource.ResourcePool;
064: import com.projity.pm.scheduling.SchedulingType;
065: import com.projity.pm.snapshot.Snapshottable;
066: import com.projity.pm.task.NormalTask;
067: import com.projity.pm.task.Project;
068: import com.projity.pm.task.TaskSnapshot;
069: import com.projity.undo.AssignmentCreationEdit;
070: import com.projity.undo.AssignmentDeletionEdit;
071: import com.projity.undo.NodeUndoInfo;
072: import com.projity.undo.ScheduleBackupEdit;
073: import com.projity.undo.ScheduleEdit;
074:
075: /**
076: * Manages the creation and deleting of assignments as well as events
077: */
078: public class AssignmentService {
079:
080: private static AssignmentService instance = null;
081:
082: public static AssignmentService getInstance() {
083: if (instance == null)
084: instance = new AssignmentService();
085: return instance;
086: }
087:
088: public void newAssignments(Collection tasks, Collection resources,
089: double units, long delay, Object eventSource, boolean undo) {
090: if (tasks.size() == 0 || resources.size() == 0)
091: return;
092: int transactionId = 0;
093: Project transactionProject = null;
094: for (Iterator i = tasks.iterator(); i.hasNext();) {
095: NormalTask task = (NormalTask) i.next();
096: // if (!task.isAssignable())
097: // continue;
098: if (transactionId == 0) {
099: transactionProject = task.getProject();
100: transactionProject.beginUndoUpdate();
101: transactionId = transactionProject
102: .fireMultipleTransaction(0, true);
103:
104: //backup before any assignment operation
105: transactionProject.getUndoController().getEditSupport()
106: .postEdit(new ScheduleBackupEdit(tasks, this ));
107: }
108: // if task currently has no assignments, then we should not change duration if adding several at once
109: boolean taskHasNoAssignments = !task.hasRealAssignments()
110: || !task.hasLaborAssignment();
111: int oldSchedulingType = task.getSchedulingType();
112: boolean oldEffortDriven = task.isEffortDriven();
113: if (taskHasNoAssignments) {// if adding for first time
114: task.setSchedulingType(SchedulingType.FIXED_DURATION);
115: task.setEffortDriven(false);
116: }
117:
118: Iterator r = resources.iterator();
119: while (r.hasNext()) {
120: Resource resource = (Resource) r.next();
121: if (null == task.findAssignment(resource)) {
122: // double units = 1.0D;
123: //TODO Bug 330: this is slow and uses tons of memory when assigning many at once. optimizing by doing just one update
124: //The result is that AssignmentNodeModel.objectChanged(ObjectEvent objectEvent) is called for each assignment
125: //This needs to be batched as its current memory usage is unacceptable and it takes very long
126: //Perhaps one solution would be to replace hierarchy search() with a hash table for mapping impls to nodes
127:
128: //TODO It throws an event for assignment. A service for updating all the assignments at once should be added.
129: Assignment assignment = newAssignment(task,
130: resource, units, 0, eventSource, true);
131: if (!resource.isLabor()) // for assigning non temporal resources, use the value of 1
132: assignment.setRateUnit(TimeUnit.NON_TEMPORAL);
133: }
134: }
135: if (taskHasNoAssignments) {// if adding for first time, put back effort driven value
136: task.setSchedulingType(oldSchedulingType);
137: task.setEffortDriven(oldEffortDriven);
138: }
139: }
140: if (transactionId != 0) {
141: transactionProject.fireMultipleTransaction(transactionId,
142: false);
143: transactionProject.endUndoUpdate();
144: }
145:
146: }
147:
148: /**
149: * When importing, we don't update or recalculate duration
150: * @param task
151: * @param resource
152: * @param units
153: * @param delay
154: * @param eventSource
155: * @return
156: */
157: public Assignment newAssignment(NormalTask task, Resource resource,
158: double units, long delay, Object eventSource, boolean undo) {
159: Assignment assignment = Assignment.getInstance(task, resource,
160: units, delay);
161: if (!connect(assignment, eventSource, undo))
162: return null;
163: return assignment;
164: }
165:
166: public Assignment newAssignment(NormalTask task, Resource resource,
167: double units, long delay, Object eventSource) {
168: return newAssignment(task, resource, units, delay, eventSource,
169: true);
170: }
171:
172: public boolean connect(Assignment assignment, Object eventSource) {
173: return connect(assignment, eventSource, true);
174: }
175:
176: public boolean connect(Assignment assignment, Object eventSource,
177: boolean undo) {
178: if (!connect(assignment, eventSource, new NodeUndoInfo(undo)))
179: return false;
180: // UndoableEditSupport undoableEditSupport=getUndoableEditSupport(assignment);
181: // if (undoableEditSupport!=null&&undo){
182: // undoableEditSupport.postEdit(new AssignmentCreationEdit(assignment,eventSource));
183: // }
184: return true;
185: }
186:
187: public boolean connect(Node node, Object eventSource, boolean undo) {
188: return connect((Assignment) node.getImpl(), eventSource,
189: new NodeUndoInfo(node, undo));
190: }
191:
192: public boolean connect(Assignment assignment, Object eventSource,
193: NodeUndoInfo undo) {
194: if (!assignment.getTask().isAssignable())
195: return false;
196: ((NormalTask) assignment.getTask()).addAssignment(assignment);
197: assignment.getResource().addAssignment(assignment);
198: if (eventSource != null) {
199: assignment.getDocument().getObjectEventManager()
200: .fireCreateEvent(eventSource, assignment, undo);
201: ((ResourcePool) assignment.getResource().getDocument())
202: .getObjectEventManager().fireCreateEvent(
203: eventSource, assignment, undo);
204: }
205: return true;
206: }
207:
208: public void remove(Node node, Object eventSource, boolean undo) {
209: remove((Assignment) node.getImpl(), true, eventSource,
210: new NodeUndoInfo(node, undo));
211: }
212:
213: // public void remove(Assignment assignment, Object eventSource) {
214: // remove(assignment, eventSource,true);
215: // }
216: public void remove(Assignment assignment, Object eventSource,
217: boolean undo) {
218: remove(assignment, true, eventSource, new NodeUndoInfo(undo));
219: }
220:
221: public void remove(Assignment assignment, boolean cleanTaskLink,
222: Object eventSource, boolean undo) {
223: remove(assignment, cleanTaskLink, eventSource,
224: new NodeUndoInfo(undo));
225: // remove(assignment,(undo)?UNDO:eventSource);
226: // UndoableEditSupport undoableEditSupport=getUndoableEditSupport(assignment);
227: // if (undoableEditSupport!=null&&undo){
228: // undoableEditSupport.postEdit(new AssignmentDeletionEdit(assignment,eventSource));
229: // }
230: }
231:
232: public void remove(Collection assignments, Object eventSource,
233: boolean undo) {
234: UndoableEditSupport undoableEditSupport = null;
235:
236: try {
237: for (Iterator i = assignments.iterator(); i.hasNext();) {
238: Assignment assignment = (Assignment) i.next();
239: // if (undoableEditSupport==null&&undo){
240: // undoableEditSupport=getUndoableEditSupport(assignment);
241: // if (undoableEditSupport!=null){
242: // undoableEditSupport.beginUpdate();
243: // }
244: // }
245: remove(assignment, true, eventSource, undo);
246: }
247: } finally {
248: // if (undoableEditSupport!=null&&undo){
249: // undoableEditSupport.endUpdate();
250: // }
251: }
252: }
253:
254: public void remove(Assignment assignment, boolean cleanTaskLink,
255: Object eventSource, NodeUndoInfo undo) {
256: NormalTask task = (NormalTask) assignment.getTask();
257: Resource resource = assignment.getResource();
258:
259: if (task.findAssignment(resource) == null)
260: return; // avoids endless loop 9/1/06 hk
261:
262: if (cleanTaskLink)
263: task.removeAssignment(assignment);
264: resource.removeAssignment(assignment);
265:
266: // //remove assignment snapshots too 18/7/2006 lc
267: // //if (resource!=ResourceImpl.getUnassignedInstance())
268: // for (int s=0;s<Settings.numBaselines();s++){
269: // TaskSnapshot snapshot=(TaskSnapshot)task.getSnapshot(new Integer(s));
270: // if (snapshot==null) continue;
271: // AssociationList snapshotAssignments=snapshot.getHasAssignments().getAssignments();
272: // if (snapshotAssignments.size()>0){
273: // for (Iterator j=snapshotAssignments.iterator();j.hasNext();){
274: // Assignment snapshotAssignment=(Assignment)j.next();
275: // if (snapshotAssignment.getTask()==assignment.getTask()&&snapshotAssignment.getResource()==assignment.getResource())
276: // j.remove();
277: // }
278: // }
279: // //if (snapshotAssignments.size()==0&&s!=Snapshottable.CURRENT.intValue()) task.setSnapshot(new Integer(s), null);
280: // }
281:
282: // if (eventSource == null){ //case when default assignment is removed
283: // if ((undo==null||(undo!=null&&undo.isUndo()))){
284: // UndoableEditSupport undoableEditSupport=getUndoableEditSupport(assignment);
285: // if (undoableEditSupport!=null){
286: // undoableEditSupport.postEdit(new AssignmentDeletionEdit(assignment));
287: // }
288: // }
289: //
290: // }else {
291: if (eventSource != null) {
292: if (cleanTaskLink)
293: assignment.getDocument().getObjectEventManager()
294: .fireDeleteEvent(eventSource, assignment, undo);
295: if (assignment.getResource().getDocument() != null) // it's null if local project
296: ((ResourcePool) assignment.getResource().getDocument())
297: .getObjectEventManager().fireDeleteEvent(
298: eventSource, assignment);
299: }
300: }
301:
302: public void remove(Collection assignmentList, Object eventSource) {
303: Assignment assignment;
304: Iterator i = assignmentList.iterator();
305: while (i.hasNext()) {
306: assignment = (Assignment) i.next();
307: remove(assignment, true, eventSource, null);
308: }
309: }
310:
311: //fix
312: public void remove(Collection assignmentList, Collection toRemove) {
313: Assignment assignment;
314: Iterator i = assignmentList.iterator();
315: while (i.hasNext())
316: toRemove.add(i.next());
317: }
318:
319: //undo
320: public UndoableEditSupport getUndoableEditSupport(
321: Assignment assignment) {
322: if (assignment.getTask() == null)
323: return null;
324: else
325: return assignment.getTask().getProject()
326: .getUndoController().getEditSupport();
327: }
328:
329: }
|