KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ltk > ui > refactoring > history > RefactoringHistoryContentProvider


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ltk.ui.refactoring.history;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Calendar JavaDoc;
15 import java.util.List JavaDoc;
16
17 import org.eclipse.core.runtime.Assert;
18
19 import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy;
20 import org.eclipse.ltk.core.refactoring.history.RefactoringHistory;
21
22 import org.eclipse.ltk.internal.ui.refactoring.history.RefactoringHistoryCollection;
23 import org.eclipse.ltk.internal.ui.refactoring.history.RefactoringHistoryDate;
24 import org.eclipse.ltk.internal.ui.refactoring.history.RefactoringHistoryEntry;
25 import org.eclipse.ltk.internal.ui.refactoring.history.RefactoringHistoryNode;
26
27 import org.eclipse.jface.viewers.ITreeContentProvider;
28 import org.eclipse.jface.viewers.Viewer;
29
30 /**
31  * Tree content provider to display a refactoring history. This content provider
32  * may be used with {@link RefactoringHistory} elements and returns model
33  * elements suitable to be rendered using
34  * {@link RefactoringHistoryLabelProvider}.
35  * <p>
36  * Note: this class is not indented to be subclassed outside the refactoring
37  * framework.
38  * </p>
39  *
40  * @see IRefactoringHistoryControl
41  * @see RefactoringHistoryControlConfiguration
42  *
43  * @since 3.2
44  */

45 public class RefactoringHistoryContentProvider implements ITreeContentProvider {
46
47     /** The no elements constant */
48     private static final Object JavaDoc[] NO_ELEMENTS= {};
49
50     /**
51      * Implements a binary search which computes the index of the number, or a
52      * nearest approximative index if the number has not been found.
53      * <p>
54      * The array must be sorted in descending order.
55      * </p>
56      *
57      * @param array
58      * the array, sorted in descending order, to search for the
59      * number
60      * @param number
61      * the number to search for
62      * @return the index of the number in the array, or the nearest index,
63      * depending on <code>right</code>
64      */

65     private static int binarySearch(final long[] array, final long number) {
66         int left= 0;
67         int right= array.length - 1;
68         int median;
69         do {
70             median= (left + right) / 2;
71             if (number > array[median])
72                 right= median - 1;
73             else
74                 left= median + 1;
75         } while (number != array[median] && left <= right);
76         if (number == array[median])
77             return median;
78         return left;
79     }
80
81     /**
82      * Returns the index of the specified root kind in the structure.
83      *
84      * @param structure
85      * the structure
86      * @param kind
87      * the root kind
88      * @return the index, or <code>-1</code>
89      */

90     private static int getRefactoringRootKindIndex(final long[][] structure, final int kind) {
91         for (int index= structure.length - 1; index >= 0; index--) {
92             if (kind >= structure[index][1])
93                 return index;
94         }
95         return -1;
96     }
97
98     /** The refactoring history control configuration to use */
99     private final RefactoringHistoryControlConfiguration fControlConfiguration;
100
101     /** The refactoring history, or <code>null</code> */
102     private RefactoringHistory fRefactoringHistory= null;
103
104     /** The refactoring root structure, or <code>null</code> */
105     private long[][] fRefactoringRoots= null;
106
107     /** The refactoring time stamps, in descending order, or <code>null</code> */
108     private long[] fRefactoringStamps= null;
109
110     /**
111      * Creates a new refactoring history content provider.
112      *
113      * @param configuration
114      * the refactoring history control configuration
115      */

116     public RefactoringHistoryContentProvider(final RefactoringHistoryControlConfiguration configuration) {
117         Assert.isNotNull(configuration);
118         fControlConfiguration= configuration;
119     }
120
121     /**
122      * {@inheritDoc}
123      */

124     public void dispose() {
125         // Do nothing
126
}
127
128     /**
129      * {@inheritDoc}
130      */

131     public Object JavaDoc[] getChildren(final Object JavaDoc element) {
132         if (element instanceof RefactoringHistoryNode) {
133             final RefactoringHistoryNode node= (RefactoringHistoryNode) element;
134             final RefactoringDescriptorProxy[] proxies= getRefactoringDescriptorProxies();
135             if (proxies.length > 0) {
136                 final long[][] structure= getRefactoringRootStructure(proxies[0].getTimeStamp());
137                 final int kind= node.getKind();
138                 switch (kind) {
139                     case RefactoringHistoryNode.COLLECTION:
140                         return getRefactoringHistoryEntries(node);
141                     default: {
142                         if (node instanceof RefactoringHistoryDate) {
143                             final RefactoringHistoryDate date= (RefactoringHistoryDate) node;
144                             final long stamp= date.getTimeStamp();
145                             switch (kind) {
146                                 case RefactoringHistoryNode.TODAY:
147                                     return getRefactoringHistoryEntries(date, stamp, Long.MAX_VALUE);
148                                 case RefactoringHistoryNode.YESTERDAY:
149                                     return getRefactoringHistoryEntries(date, stamp, structure[getRefactoringRootKindIndex(structure, RefactoringHistoryNode.TODAY)][0] - 1);
150                                 case RefactoringHistoryNode.THIS_WEEK:
151                                     return getRefactoringHistoryDays(date, stamp, structure[getRefactoringRootKindIndex(structure, RefactoringHistoryNode.YESTERDAY)][0] - 1);
152                                 case RefactoringHistoryNode.LAST_WEEK:
153                                     return getRefactoringHistoryDays(date, stamp, structure[getRefactoringRootKindIndex(structure, RefactoringHistoryNode.THIS_WEEK)][0] - 1);
154                                 case RefactoringHistoryNode.THIS_MONTH:
155                                     return getRefactoringHistoryWeeks(date, stamp, structure[getRefactoringRootKindIndex(structure, RefactoringHistoryNode.LAST_WEEK)][0] - 1);
156                                 case RefactoringHistoryNode.LAST_MONTH:
157                                     return getRefactoringHistoryWeeks(date, stamp, structure[getRefactoringRootKindIndex(structure, RefactoringHistoryNode.THIS_MONTH)][0] - 1);
158                                 case RefactoringHistoryNode.DAY:
159                                     return getRefactoringHistoryEntries(date, stamp, stamp + 1000 * 60 * 60 * 24 - 1);
160                                 case RefactoringHistoryNode.WEEK:
161                                     return getRefactoringHistoryDays(date, stamp, stamp + 1000 * 60 * 60 * 24 * 7 - 1);
162                                 case RefactoringHistoryNode.MONTH: {
163                                     final Calendar JavaDoc calendar= Calendar.getInstance();
164                                     calendar.setTimeInMillis(stamp);
165                                     calendar.add(Calendar.MONTH, 1);
166                                     return getRefactoringHistoryWeeks(date, stamp, calendar.getTimeInMillis() - 1);
167                                 }
168                                 case RefactoringHistoryNode.YEAR: {
169                                     final Calendar JavaDoc calendar= Calendar.getInstance();
170                                     calendar.setTimeInMillis(stamp);
171                                     calendar.add(Calendar.YEAR, 1);
172                                     return getRefactoringHistoryMonths(date, stamp, calendar.getTimeInMillis() - 1);
173                                 }
174                             }
175                         }
176                     }
177                 }
178             }
179         } else if (element instanceof RefactoringHistory)
180             return getElements(element);
181         return NO_ELEMENTS;
182     }
183
184     /**
185      * {@inheritDoc}
186      */

187     public Object JavaDoc[] getElements(final Object JavaDoc element) {
188         if (element instanceof RefactoringHistory) {
189             if (fControlConfiguration.isTimeDisplayed())
190                 return getRootElements();
191             else if (fRefactoringHistory != null && !fRefactoringHistory.isEmpty())
192                 return new Object JavaDoc[] { new RefactoringHistoryCollection()};
193         }
194         return NO_ELEMENTS;
195     }
196
197     /**
198      * {@inheritDoc}
199      */

200     public Object JavaDoc getParent(final Object JavaDoc element) {
201         if (element instanceof RefactoringHistoryNode) {
202             final RefactoringHistoryNode node= (RefactoringHistoryNode) element;
203             return node.getParent();
204         }
205         return null;
206     }
207
208     /**
209      * Returns the refactoring descriptor proxies, sorted in descending order of
210      * their time stamps, and caches time stamp information.
211      *
212      * @return the refactoring descriptor proxies
213      */

214     private RefactoringDescriptorProxy[] getRefactoringDescriptorProxies() {
215         final RefactoringDescriptorProxy[] proxies= fRefactoringHistory.getDescriptors();
216         if (fRefactoringStamps == null) {
217             final int length= proxies.length;
218             fRefactoringStamps= new long[length];
219             for (int index= 0; index < length; index++)
220                 fRefactoringStamps[index]= proxies[index].getTimeStamp();
221         }
222         return proxies;
223     }
224
225     /**
226      * Returns the refactoring history days.
227      *
228      * @param parent
229      * the parent node, or <code>null</code>
230      * @param start
231      * the start time stamp, inclusive
232      * @param end
233      * the end time stamp. inclusive
234      *
235      * @return the refactoring history days
236      */

237     private Object JavaDoc[] getRefactoringHistoryDays(final RefactoringHistoryDate parent, final long start, final long end) {
238         final long time= parent.getTimeStamp();
239         final Calendar JavaDoc calendar= Calendar.getInstance();
240         final RefactoringDescriptorProxy[] proxies= getRefactoringDescriptorProxies();
241         final int[] range= getRefactoringHistoryRange(start, end);
242         final List JavaDoc list= new ArrayList JavaDoc(proxies.length);
243         int last= -1;
244         for (int index= range[0]; index <= range[1]; index++) {
245             long stamp= proxies[index].getTimeStamp();
246             if (stamp >= time) {
247                 calendar.setTimeInMillis(stamp);
248                 final int day= calendar.get(Calendar.DAY_OF_YEAR);
249                 if (day != last) {
250                     last= day;
251                     calendar.set(Calendar.MILLISECOND, 0);
252                     calendar.set(Calendar.SECOND, 0);
253                     calendar.set(Calendar.MINUTE, 0);
254                     calendar.set(Calendar.HOUR_OF_DAY, 0);
255                     stamp= calendar.getTimeInMillis();
256                     if (stamp < time)
257                         list.add(new RefactoringHistoryDate(parent, time, RefactoringHistoryNode.DAY));
258                     else
259                         list.add(new RefactoringHistoryDate(parent, stamp, RefactoringHistoryNode.DAY));
260                 }
261             }
262         }
263         return list.toArray();
264     }
265
266     /**
267      * Returns the refactoring history entries.
268      *
269      * @param parent
270      * the parent node, or <code>null</code>
271      * @param start
272      * the start time stamp, inclusive
273      * @param end
274      * the end time stamp. inclusive
275      *
276      * @return the refactoring history entries
277      */

278     private Object JavaDoc[] getRefactoringHistoryEntries(final RefactoringHistoryDate parent, final long start, final long end) {
279         final RefactoringDescriptorProxy[] proxies= getRefactoringDescriptorProxies();
280         final int[] range= getRefactoringHistoryRange(start, end);
281         final List JavaDoc list= new ArrayList JavaDoc(proxies.length);
282         for (int index= range[0]; index <= range[1]; index++)
283             list.add(new RefactoringHistoryEntry(parent, proxies[index]));
284         return list.toArray();
285     }
286
287     /**
288      * Returns the refactoring history entries.
289      *
290      * @param parent
291      * the parent node, or <code>null</code>
292      *
293      * @return the refactoring history entries
294      */

295     private Object JavaDoc[] getRefactoringHistoryEntries(final RefactoringHistoryNode parent) {
296         final RefactoringDescriptorProxy[] proxies= getRefactoringDescriptorProxies();
297         final List JavaDoc list= new ArrayList JavaDoc(proxies.length);
298         for (int index= 0; index < proxies.length; index++)
299             list.add(new RefactoringHistoryEntry(parent, proxies[index]));
300         return list.toArray();
301     }
302
303     /**
304      * Returns the refactoring history months.
305      *
306      * @param parent
307      * the parent node, or <code>null</code>
308      * @param start
309      * the start time stamp, inclusive
310      * @param end
311      * the end time stamp. inclusive
312      *
313      * @return the refactoring history months
314      */

315     private Object JavaDoc[] getRefactoringHistoryMonths(final RefactoringHistoryDate parent, final long start, final long end) {
316         final long time= parent.getTimeStamp();
317         final Calendar JavaDoc calendar= Calendar.getInstance();
318         final RefactoringDescriptorProxy[] proxies= getRefactoringDescriptorProxies();
319         final int[] range= getRefactoringHistoryRange(start, end);
320         final List JavaDoc list= new ArrayList JavaDoc(proxies.length);
321         int last= -1;
322         for (int index= range[0]; index <= range[1]; index++) {
323             long stamp= proxies[index].getTimeStamp();
324             if (stamp >= time) {
325                 calendar.setTimeInMillis(stamp);
326                 final int month= calendar.get(Calendar.MONTH);
327                 if (month != last) {
328                     last= month;
329                     calendar.set(Calendar.MILLISECOND, 0);
330                     calendar.set(Calendar.SECOND, 0);
331                     calendar.set(Calendar.MINUTE, 0);
332                     calendar.set(Calendar.HOUR_OF_DAY, 0);
333                     calendar.set(Calendar.DAY_OF_MONTH, 1);
334                     stamp= calendar.getTimeInMillis();
335                     if (stamp < time)
336                         list.add(new RefactoringHistoryDate(parent, time, RefactoringHistoryNode.MONTH));
337                     else
338                         list.add(new RefactoringHistoryDate(parent, stamp, RefactoringHistoryNode.MONTH));
339                 }
340             }
341         }
342         return list.toArray();
343     }
344
345     /**
346      * Returns the refactoring history range for the specified time stamps.
347      *
348      * @param start
349      * the start time stamp, inclusive
350      * @param end
351      * the end time stamp. inclusive
352      * @return An array containing the index range
353      */

354     private int[] getRefactoringHistoryRange(final long start, final long end) {
355         final int[] range= new int[2];
356         range[1]= binarySearch(fRefactoringStamps, start) - 1;
357         range[0]= binarySearch(fRefactoringStamps, end);
358         return range;
359     }
360
361     /**
362      * Returns the refactoring history weeks.
363      *
364      * @param parent
365      * the parent node, or <code>null</code>
366      * @param start
367      * the start time stamp, inclusive
368      * @param end
369      * the end time stamp. inclusive
370      *
371      * @return the refactoring history weeks
372      */

373     private Object JavaDoc[] getRefactoringHistoryWeeks(final RefactoringHistoryDate parent, final long start, final long end) {
374         final long time= parent.getTimeStamp();
375         final Calendar JavaDoc calendar= Calendar.getInstance();
376         final RefactoringDescriptorProxy[] proxies= getRefactoringDescriptorProxies();
377         final int[] range= getRefactoringHistoryRange(start, end);
378         final List JavaDoc list= new ArrayList JavaDoc(proxies.length);
379         int last= -1;
380         for (int index= range[0]; index <= range[1]; index++) {
381             long stamp= proxies[index].getTimeStamp();
382             if (stamp >= time) {
383                 calendar.setTimeInMillis(stamp);
384                 final int week= calendar.get(Calendar.WEEK_OF_YEAR);
385                 if (week != last) {
386                     last= week;
387                     calendar.set(Calendar.MILLISECOND, 0);
388                     calendar.set(Calendar.SECOND, 0);
389                     calendar.set(Calendar.MINUTE, 0);
390                     calendar.set(Calendar.HOUR_OF_DAY, 0);
391                     calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
392                     stamp= calendar.getTimeInMillis();
393                     if (stamp < time)
394                         list.add(new RefactoringHistoryDate(parent, time, RefactoringHistoryNode.WEEK));
395                     else
396                         list.add(new RefactoringHistoryDate(parent, stamp, RefactoringHistoryNode.WEEK));
397                 }
398             }
399         }
400         return list.toArray();
401     }
402
403     /**
404      * Computes and returns the refactoring root structure if necessary.
405      *
406      * @param stamp
407      * the time stamp of the oldest refactoring
408      * @return the refactoring root structure
409      */

410     private long[][] getRefactoringRootStructure(final long stamp) {
411         if (fRefactoringRoots == null) {
412             final long time= System.currentTimeMillis();
413             final Calendar JavaDoc calendar= Calendar.getInstance();
414             calendar.setTimeInMillis(time);
415             calendar.set(Calendar.HOUR_OF_DAY, 0);
416             calendar.set(Calendar.MINUTE, 0);
417             calendar.set(Calendar.SECOND, 0);
418             calendar.set(Calendar.MILLISECOND, 0);
419             final int zoneOffset= calendar.get(Calendar.ZONE_OFFSET);
420             final int dstOffset= calendar.get(Calendar.DST_OFFSET);
421             int count= 0;
422             final long[] thresholds= new long[32];
423             final int[] kinds= new int[32];
424             thresholds[count]= calendar.getTimeInMillis();
425             kinds[count]= RefactoringHistoryNode.TODAY;
426             count++;
427             calendar.add(Calendar.DATE, -1);
428             thresholds[count]= calendar.getTimeInMillis();
429             kinds[count]= RefactoringHistoryNode.YESTERDAY;
430             count++;
431             final int day= calendar.get(Calendar.DAY_OF_WEEK);
432             if (day != Calendar.SUNDAY) {
433                 calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
434                 thresholds[count]= calendar.getTimeInMillis();
435                 kinds[count]= RefactoringHistoryNode.THIS_WEEK;
436                 count++;
437                 calendar.add(Calendar.WEEK_OF_YEAR, -1);
438             }
439             calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
440             thresholds[count]= calendar.getTimeInMillis();
441             kinds[count]= RefactoringHistoryNode.LAST_WEEK;
442             count++;
443             calendar.setTimeInMillis(time);
444             calendar.set(Calendar.HOUR_OF_DAY, 0);
445             calendar.set(Calendar.MINUTE, 0);
446             calendar.set(Calendar.SECOND, 0);
447             calendar.set(Calendar.MILLISECOND, 0);
448             calendar.set(Calendar.DAY_OF_MONTH, 1);
449             if (thresholds[count - 1] >= calendar.getTimeInMillis()) {
450                 thresholds[count]= calendar.getTimeInMillis();
451                 kinds[count]= RefactoringHistoryNode.THIS_MONTH;
452                 count++;
453             }
454             calendar.add(Calendar.MONTH, -1);
455             thresholds[count]= calendar.getTimeInMillis();
456             kinds[count]= RefactoringHistoryNode.LAST_MONTH;
457             count++;
458             final int month= calendar.get(Calendar.MONTH);
459             if (month != 0) {
460                 calendar.set(Calendar.MONTH, 0);
461                 thresholds[count]= calendar.getTimeInMillis();
462                 kinds[count]= RefactoringHistoryNode.YEAR;
463                 count++;
464             }
465             if (stamp > 0) {
466                 final long localized= stamp + zoneOffset + dstOffset;
467                 calendar.set(Calendar.MONTH, 0);
468                 do {
469                     calendar.add(Calendar.YEAR, -1);
470                     thresholds[count]= calendar.getTimeInMillis();
471                     kinds[count]= RefactoringHistoryNode.YEAR;
472                     count++;
473                 } while (calendar.getTimeInMillis() > localized);
474             }
475             final long[][] result= new long[count - 1][2];
476             for (int index= 0; index < count - 1; index++) {
477                 result[index][0]= thresholds[index];
478                 result[index][1]= kinds[index];
479             }
480             fRefactoringRoots= result;
481         }
482         return fRefactoringRoots;
483     }
484
485     /**
486      * Returns the refactoring history root elements.
487      * <p>
488      * This method must only be called for refactoring histories with associated
489      * time information.
490      * </p>
491      *
492      * @return the refactoring history root elements
493      */

494     public Object JavaDoc[] getRootElements() {
495         final List JavaDoc list= new ArrayList JavaDoc(16);
496         if (fRefactoringHistory != null && !fRefactoringHistory.isEmpty()) {
497             final RefactoringDescriptorProxy[] proxies= getRefactoringDescriptorProxies();
498             if (proxies.length > 0) {
499                 final long[][] structure= getRefactoringRootStructure(proxies[0].getTimeStamp());
500                 int begin= 0;
501                 long end= Long.MAX_VALUE;
502                 for (int index= 0; index < proxies.length; index++) {
503                     final long stamp= proxies[index].getTimeStamp();
504                     for (int offset= begin; offset < structure.length; offset++) {
505                         final long start= structure[offset][0];
506                         if (stamp >= start && stamp <= end) {
507                             list.add(new RefactoringHistoryDate(null, start, (int) structure[offset][1]));
508                             begin= offset + 1;
509                             end= start - 1;
510                             break;
511                         }
512                     }
513                 }
514             }
515         }
516         return list.toArray();
517     }
518
519     /**
520      * {@inheritDoc}
521      */

522     public boolean hasChildren(final Object JavaDoc element) {
523         return !(element instanceof RefactoringHistoryEntry);
524     }
525
526     /**
527      * {@inheritDoc}
528      */

529     public void inputChanged(final Viewer viewer, final Object JavaDoc predecessor, final Object JavaDoc successor) {
530         if (predecessor == successor || fRefactoringHistory == successor)
531             return;
532         if (successor instanceof RefactoringHistory) {
533             if (successor.equals(fRefactoringHistory))
534                 return;
535             fRefactoringHistory= (RefactoringHistory) successor;
536         } else
537             fRefactoringHistory= null;
538         fRefactoringRoots= null;
539         fRefactoringStamps= null;
540     }
541 }
542
Popular Tags