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.timescale;
051:
052: import java.io.Serializable;
053: import java.util.Calendar;
054: import java.util.EventListener;
055:
056: import javax.swing.event.EventListenerList;
057:
058: import com.projity.graphic.configuration.GraphicConfiguration;
059: import com.projity.pm.graphic.model.cache.GraphicNode;
060: import com.projity.pm.scheduling.ScheduleEvent;
061: import com.projity.pm.scheduling.ScheduleEventListener;
062: import com.projity.pm.scheduling.ScheduleInterval;
063: import com.projity.pm.task.Project;
064: import com.projity.timescale.TimeInterval;
065: import com.projity.timescale.TimeIterator;
066: import com.projity.timescale.TimeScaleEvent;
067: import com.projity.timescale.TimeScaleListener;
068: import com.projity.timescale.TimeScaleManager;
069: import com.projity.util.DateTime;
070: import com.projity.workspace.SavableToWorkspace;
071: import com.projity.workspace.WorkspaceSetting;
072:
073: /**
074: *
075: */
076: public class CoordinatesConverter implements ScheduleEventListener,
077: Serializable, SavableToWorkspace {
078: private static final long serialVersionUID = 3657308109433257760L;
079: protected TimeScaleManager timescaleManager;
080: protected long origin;
081: protected long end;
082:
083: protected Project project;
084:
085: public CoordinatesConverter(Project project) {
086: this (project, TimeScaleManager.createInstance());
087: }
088:
089: /**
090: *
091: */
092: public CoordinatesConverter(Project project,
093: TimeScaleManager timescaleManager) {
094: this .project = project;
095: this .timescaleManager = timescaleManager;
096: updateLargeInterval(false);
097: project.addScheduleListener(this );
098: }
099:
100: /**
101: * @return Returns the origin.
102: */
103: public long getOrigin() {
104: //adaptOrigin(getLargeStart(),true);
105: return origin;
106: }
107:
108: public long getEnd() {
109: //adaptEnd(getLargeEnd(),true);
110: return end;
111: }
112:
113: /*public long getFloorOrigin() {
114: long t=getTimescaleManager().getScale().floor1(origin);
115: System.out.println("Origin: "+CalendarUtil.toString(t)+"/"+CalendarUtil.toString(origin));
116: return t;
117: }
118: public long getCeilEnd() {
119: long t=getTimescaleManager().getScale().ceil1(end);
120: System.out.println("End: "+CalendarUtil.toString(end)+"/"+CalendarUtil.toString(t));
121: return t;
122: }*/
123:
124: protected void adaptOrigin(Calendar calendar, boolean event) {
125: //System.out.println("adaptOrigin: begin");
126: getTimescaleManager().getScale().floor1(calendar, -1);
127:
128: long tmp = calendar.getTimeInMillis();
129: if (this .origin != tmp) {
130: //System.out.println("adaptOrigin: change: old="+CalendarUtil.toString(this.origin)+", new="+CalendarUtil.toString(tmp));
131: this .origin = tmp;
132: if (event)
133: fireTimeScaleChanged(this ,
134: TimeScaleEvent.ORIGIN_AND_END_CHANGE);
135: }
136: //System.out.println("adaptOrigin: end");
137: }
138:
139: protected void adaptEnd(Calendar calendar, boolean event) {
140: //System.out.println("adaptEnd: begin");
141: getTimescaleManager().getScale().ceil1(calendar, -1);
142:
143: long tmp = calendar.getTimeInMillis();
144:
145: if (this .end != tmp) {
146: //System.out.println("adaptEnd: change: old="+CalendarUtil.toString(this.end)+", new="+CalendarUtil.toString(tmp));
147: this .end = tmp;
148: if (event)
149: fireTimeScaleChanged(this ,
150: TimeScaleEvent.END_ONLY_CHANGE);
151: }
152: //System.out.println("adaptEnd: end");
153: }
154:
155: protected void adaptInterval(Calendar origin, Calendar end,
156: boolean event) {
157: int modifType = 0;
158: long tmp = this .end;
159: adaptEnd(end, false);
160: if (this .end != tmp)
161: modifType = TimeScaleEvent.END_ONLY_CHANGE;
162: tmp = this .origin;
163: adaptOrigin(origin, false);
164: if (this .origin != tmp)
165: modifType = TimeScaleEvent.ORIGIN_AND_END_CHANGE;
166: if (modifType > 0 && event)
167: fireTimeScaleChanged(this , modifType);
168:
169: }
170:
171: private long getProjectStart() {
172: long start = project.getEarliestStartingTaskOrStart();
173: return (start == 0) ? System.currentTimeMillis() : start;
174: }
175:
176: private long getProjectEnd() {
177: return project.getLatestFinishingTask();
178: }
179:
180: private Calendar getLargeStart() {
181: Calendar calendar = DateTime.calendarInstance();
182: calendar.setTimeInMillis(getProjectStart());
183: calendar.add(Calendar.DAY_OF_MONTH, -3);
184: //CalendarUtil.roundTime(calendar);
185: return calendar;
186:
187: }
188:
189: private Calendar getLargeEnd() {
190: long end = getProjectEnd();
191: Calendar calendar = DateTime.calendarInstance();
192: calendar.setTimeInMillis(getProjectEnd());
193: calendar.add(Calendar.DAY_OF_MONTH, 30);
194: //CalendarUtil.roundTime(calendar);
195: return calendar;
196: }
197:
198: protected void updateLargeInterval(boolean event) {
199: adaptInterval(getLargeStart(), getLargeEnd(), event);
200: //System.out.println("updateLargeInterval: "+CalendarUtil.toString(getOrigin())+", "+CalendarUtil.toString(getEnd()));
201: }
202:
203: public void toggleMinWidth(boolean normal) {
204: if (timescaleManager.toggleMinWidth(normal)) {
205: fireTimeScaleChanged(this , TimeScaleEvent.SCALE_CHANGE);
206: }
207: }
208:
209: public boolean canZoomIn() {
210: return timescaleManager.canZoomIn();
211: }
212:
213: public boolean canZoomOut() {
214: return timescaleManager.canZoomOut();
215: }
216:
217: public void zoomIn() {
218: if (timescaleManager.zoomIn()) {
219: updateLargeInterval(false);
220: fireTimeScaleChanged(this , TimeScaleEvent.SCALE_CHANGE);
221: }
222: }
223:
224: public void zoomOut() {
225: if (timescaleManager.zoomOut()) {
226: updateLargeInterval(false);
227: fireTimeScaleChanged(this , TimeScaleEvent.SCALE_CHANGE);
228: }
229: }
230:
231: public void zoomReset() {
232: if (timescaleManager.zoomReset()) {
233: updateLargeInterval(false);
234: fireTimeScaleChanged(this , TimeScaleEvent.SCALE_CHANGE);
235: }
236: }
237:
238: public long getIntervalDuration() {
239: return getTimescaleManager().getScale().getIntervalDuration();
240: }
241:
242: /**
243: * @return Returns the timescaleManager.
244: */
245: public TimeScaleManager getTimescaleManager() {
246: return timescaleManager;
247: }
248:
249: /**
250: * @param timescaleManager The timescaleManager to set.
251: */
252: public void setTimescaleManager(TimeScaleManager timescaleManager) {
253: this .timescaleManager = timescaleManager;
254: }
255:
256: public double toTime(double x) {
257: return getOrigin() + timescaleManager.getScale().toTime(x);
258: }
259:
260: public double toDuration(double w) {
261: return timescaleManager.getScale().toTime(w);
262: }
263:
264: public double toX(double t) {
265: return timescaleManager.getScale().toX(t - getOrigin());
266: }
267:
268: public double toW(double d) {
269: return timescaleManager.getScale().toX(d);
270: }
271:
272: public double getWidth() {
273: return toW(getEnd() - getOrigin());
274: }
275:
276: public TimeIterator getTimeIterator(double x1, double x2) {
277: return new TimeIterator(toTime(x1), toTime(x2),
278: timescaleManager.getScale(), getOrigin());
279: }
280:
281: public TimeIterator getTimeIterator(double x1, double x2,
282: boolean largeScale) {
283: return new TimeIterator(toTime(x1), toTime(x2),
284: timescaleManager.getScale(), getOrigin(), largeScale);
285: }
286:
287: // public TimeIterator getTimeIteratorFromDates(long start, long end){
288: // return new TimeIterator(start,end,timescaleManager.getScale(),getOrigin());
289: // }
290:
291: public TimeIterator getProjectTimeIterator() {
292: return new TimeIterator(getOrigin(), getEnd(), timescaleManager
293: .getScale(), getOrigin());
294: }
295:
296: public int countProjectIntervals() {
297: int count = 0;
298: TimeIterator iterator = getProjectTimeIterator();
299: TimeInterval interval;
300: while (iterator.hasNext()) {
301: interval = iterator.next();
302: count++;
303: }
304: return count;
305: }
306:
307: public void scheduleChanged(ScheduleEvent evt) {
308: updateLargeInterval(true);
309: //if project start or end have changed, it triggers a TimeScaleEvent
310: }
311:
312: //events handling
313:
314: protected EventListenerList listenerList = new EventListenerList();
315:
316: public void addTimeScaleListener(TimeScaleListener l) {
317: listenerList.add(TimeScaleListener.class, l);
318: }
319:
320: public void removeTimeScaleListener(TimeScaleListener l) {
321: listenerList.remove(TimeScaleListener.class, l);
322: }
323:
324: public TimeScaleListener[] getTimeScaleListeners() {
325: return (TimeScaleListener[]) listenerList
326: .getListeners(TimeScaleListener.class);
327: }
328:
329: protected void fireTimeScaleChanged(Object source, int type) {
330: Object[] listeners = listenerList.getListenerList();
331: TimeScaleEvent e = null;
332: for (int i = listeners.length - 2; i >= 0; i -= 2) {
333: if (listeners[i] == TimeScaleListener.class) {
334: if (e == null) {
335: e = new TimeScaleEvent(source, type);
336: }
337: ((TimeScaleListener) listeners[i + 1])
338: .timeScaleChanged(e);
339: }
340: }
341: }
342:
343: public EventListener[] getListeners(Class listenerType) {
344: return listenerList.getListeners(listenerType);
345: }
346:
347: public void restoreWorkspace(WorkspaceSetting w, int context) {
348: Workspace ws = (Workspace) w;
349: timescaleManager.setCurrentScaleIndex(ws.currentScaleIndex);
350: origin = ws.origin;
351: end = ws.end;
352: }
353:
354: public WorkspaceSetting createWorkspace(int context) {
355: Workspace ws = new Workspace();
356: ws.currentScaleIndex = timescaleManager.getCurrentScaleIndex();
357: ws.origin = origin;
358: ws.end = end;
359: return ws;
360: }
361:
362: public static class Workspace implements WorkspaceSetting {
363: private static final long serialVersionUID = -6767009284584575457L;
364: int currentScaleIndex;
365: long origin;
366: long end;
367:
368: public final int getCurrentScaleIndex() {
369: return currentScaleIndex;
370: }
371:
372: public final void setCurrentScaleIndex(int currentScaleIndex) {
373: this .currentScaleIndex = currentScaleIndex;
374: }
375:
376: public final long getEnd() {
377: return end;
378: }
379:
380: public final void setEnd(long end) {
381: this .end = end;
382: }
383:
384: public final long getOrigin() {
385: return origin;
386: }
387:
388: public final void setOrigin(long origin) {
389: this .origin = origin;
390: }
391: }
392:
393: public Project getProject() {
394: return project;
395: }
396:
397: public static double adaptSmallBarEndX(double start, double end,
398: GraphicNode node, GraphicConfiguration config) {
399: if (config == null)
400: config = GraphicConfiguration.getInstance();
401: if (config.getGanttBarMinWidth() == 0 || node == null
402: || node.getIntervalCount() > 1)
403: return end;
404: if (start < end && end - start < config.getGanttBarMinWidth()
405: && config.getGanttBarMinWidth() > 0)
406: return start + config.getGanttBarMinWidth();
407: else
408: return end;
409: }
410:
411: public ScheduleInterval adaptSmallBarTimeInterval(
412: ScheduleInterval interval, GraphicNode node,
413: GraphicConfiguration config) {
414: if (config == null)
415: config = GraphicConfiguration.getInstance();
416: if (config.getGanttBarMinWidth() == 0 || node == null
417: || node.getIntervalCount() > 1)
418: return interval;
419: if (config.getGanttBarMinWidth() > 0) {
420: double minT = timescaleManager.getScale().toTime(
421: config.getGanttBarMinWidth());
422: if (interval.getStart() != interval.getEnd()
423: && interval.getEnd() - interval.getStart() < minT) {
424: return new ScheduleInterval(interval.getStart(),
425: interval.getStart() + (long) minT);
426: }
427: }
428: return interval;
429: }
430:
431: }
|