KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > compare > EditionSelectionDialog


1 /*******************************************************************************
2  * Copyright (c) 2000, 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.compare;
12
13 import java.util.*;
14 import java.util.List JavaDoc;
15
16 import org.eclipse.compare.internal.*;
17 import org.eclipse.compare.structuremergeviewer.*;
18 import org.eclipse.core.runtime.Assert;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.jface.dialogs.IDialogConstants;
21 import org.eclipse.jface.preference.IPreferenceStore;
22 import org.eclipse.jface.resource.ImageDescriptor;
23 import org.eclipse.jface.viewers.*;
24 import org.eclipse.swt.SWT;
25 import org.eclipse.swt.events.*;
26 import org.eclipse.swt.graphics.Image;
27 import org.eclipse.swt.layout.GridData;
28 import org.eclipse.swt.widgets.*;
29
30 import com.ibm.icu.text.DateFormat;
31 import com.ibm.icu.text.MessageFormat;
32 import com.ibm.icu.util.Calendar;
33
34
35 /**
36  * A dialog where one input element can be compared against
37  * a list of historic variants (editions) of the same input element.
38  * The dialog can be used to implement functions like "Compare/Replace with Version" or
39  * "Compare/Replace from Local History" on workspace resources.
40  * <p>
41  * In addition it is possible to specify a subsection of the input element
42  * (e.g. a method in a Java source file) by means of a "path".
43  * In this case the dialog compares only the subsection (as specified by the path)
44  * with the corresponding subsection in the list of editions.
45  * Only those editions are shown where the subsection differs from the same subsection in
46  * another edition thereby minimizing the number of presented variants.
47  * This functionality can be used to implement "Replace from Local History"
48  * for the Java language.
49  * <p>
50  * Subsections of an input element are determined by first finding an
51  * <code>IStructureCreator</code> for the input's type.
52  * Then the method <code>locate</code> is used to extract the subsection.
53  * <p>
54  * Each edition (variant in the list of variants) must implement the <code>IModificationDate</code> interface
55  * so that the dialog can sort the editions and present them in a tree structure where every
56  * node corresponds one day.
57  * <p>
58  * The functionality is surfaced in a single function <code>selectEdition</code>.
59  * <p>
60  * Clients may instantiate this class; it is not intended to be subclassed.
61  * </p>
62  *
63  * @see IModificationDate
64  * @see ITypedElement
65  */

66 public class EditionSelectionDialog extends ResizableDialog {
67         
68     /**
69      * An item in an underlying edition.
70      */

71     private static class Pair {
72         
73         private ITypedElement fEdition;
74         private ITypedElement fItem;
75         private String JavaDoc fContent;
76         private IStructureCreator fStructureCreator;
77         private boolean fHasError= false;
78                 
79         Pair(IStructureCreator structureCreator, ITypedElement edition, ITypedElement item) {
80             fStructureCreator= structureCreator;
81             fEdition= edition;
82             fItem= item;
83         }
84         
85         Pair(IStructureCreator structureCreator, ITypedElement edition) {
86             this(structureCreator, edition, edition);
87         }
88         
89         ITypedElement getEdition() {
90             return fEdition;
91         }
92
93         ITypedElement getItem() {
94             return fItem;
95         }
96         
97         /*
98          * The content is lazily loaded
99          */

100         private String JavaDoc getContent() {
101             if (fContent == null) {
102                 if (fStructureCreator != null)
103                     fContent= fStructureCreator.getContents(fItem, false);
104                 else {
105                     if (fItem instanceof IStreamContentAccessor) {
106                         IStreamContentAccessor sca= (IStreamContentAccessor) fItem;
107                         try {
108                             fContent= Utilities.readString(sca);
109                         } catch (CoreException ex) {
110                             // NeedWork
111
CompareUIPlugin.log(ex);
112                         }
113                     }
114                 }
115                 if (fContent == null)
116                     fContent= ""; //$NON-NLS-1$
117
}
118             return fContent;
119         }
120         
121         public boolean equals(Object JavaDoc other) {
122             if (other != null && other.getClass() == getClass()) {
123                 if (getContent().equals(((Pair)other).getContent()))
124                     return true;
125             }
126             return super.equals(other);
127         }
128     }
129     
130     // Configuration options
131
private CompareConfiguration fCompareConfiguration;
132     private ArrayList fArrayList= new ArrayList();
133     /** use a side-by-side compare viewer */
134     private boolean fCompare= true;
135     /** show target on right hand side */
136     private boolean fTargetIsRight= false;
137     /** hide entries which have identical content */
138     private boolean fHideIdentical= true;
139     /** add mode if true, otherwise replace mode */
140     private boolean fAddMode= false;
141     /** compare mode if true, otherwise replace/add mode */
142     private boolean fCompareMode= false;
143     /** perform structure compare on editions */
144     private boolean fStructureCompare= false;
145     /** allow for multiple selection */
146     private boolean fMultiSelect= false;
147     
148     /**
149      * Maps from members to their corresponding editions.
150      * Has only a single entry if dialog is used in "Replace" (and not "Add") mode.
151      */

152     private HashMap fMemberEditions;
153     /**
154      * Maps from members to their corresponding selected edition.
155      */

156     private HashMap fMemberSelection;
157     /** The editions of the current selected member */
158     private List JavaDoc fCurrentEditions;
159     private Thread JavaDoc fThread;
160     private Pair fTargetPair;
161     /** The selected edition in the edition viewer */
162     private ITypedElement fSelectedItem;
163     private String JavaDoc fTitleArg;
164     private Image fTitleImage;
165     
166     // SWT controls
167
private CompareViewerSwitchingPane fContentPane;
168     private Button fCommitButton;
169     private Table fMemberTable;
170     private CompareViewerPane fMemberPane;
171     private Tree fEditionTree;
172     private CompareViewerPane fEditionPane;
173     private Image fDateImage;
174     private Image fTimeImage;
175     private CompareViewerSwitchingPane fStructuredComparePane;
176     private Label statusLabel;
177     
178     /**
179      * Creates a new modal, resizable dialog.
180      * Various titles, icons, and labels are configured from the given resource bundle.
181      * The following resource keys are used:
182      * <pre>
183      * key type description
184      * title String dialog title
185      * width Integer initial width of dialog
186      * height Integer initial height of dialog
187      * treeTitleFormat MessageFormat pane title for edition tree; arg 0 is the target
188      * dateIcon String icon for node in edition tree; path relative to plug-in
189      * timeIcon String icon for leaf in edition tree; path relative to plug-in
190      * todayFormat MessageFormat format string if date is todays date; arg 0 is date
191      * yesterdayFormat MessageFormat format string if date is yesterdays date; arg 0 is date
192      * dayFormat MessageFormat format string if date is any other date; arg 0 is date
193      * editionLabel String label for editions side of compare viewer; arg 0 is the date
194      * targetLabel String label for target side of compare viewer
195      * buttonLabel String label for OK button; default is IDialogConstants.OK_LABEL
196      * </pre>
197      *
198      * @param parent if not <code>null</code> the new dialog stays on top of this parent shell
199      * @param bundle <code>ResourceBundle</code> to configure the dialog
200      */

201     public EditionSelectionDialog(Shell parent, ResourceBundle bundle) {
202         super(parent, bundle);
203     }
204     
205     private CompareConfiguration getCompareConfiguration() {
206         if (fCompareConfiguration == null) {
207             fCompareConfiguration= new CompareConfiguration();
208             fCompareConfiguration.setLeftEditable(false);
209             fCompareConfiguration.setRightEditable(false);
210             fCompareConfiguration.setContainer(new CompareContainer() {
211                 public void setStatusMessage(String JavaDoc message) {
212                     if (statusLabel != null && !statusLabel.isDisposed()) {
213                         if (message == null) {
214                             statusLabel.setText(""); //$NON-NLS-1$
215
} else {
216                             statusLabel.setText(message);
217                         }
218                     }
219                 }
220             });
221         }
222         return fCompareConfiguration;
223     }
224     
225     /**
226      * Sets the help context for this dialog.
227      *
228      * @param contextId the help context id.
229      * @since 3.2
230      */

231     public void setHelpContextId(String JavaDoc contextId) {
232         super.setHelpContextId(contextId);
233     }
234     
235     /**
236      * Sets an additional and optional argument for the edition pane's title.
237      *
238      * @param titleArgument an optional argument for the edition pane's title
239      * @since 2.0
240      */

241     public void setEditionTitleArgument(String JavaDoc titleArgument) {
242         fTitleArg= titleArgument;
243     }
244     
245     /**
246      * Sets an optional image for the edition pane's title.
247      *
248      * @param titleImage an optional image for the edition pane's title
249      * @since 2.0
250      */

251     public void setEditionTitleImage(Image titleImage) {
252         fTitleImage= titleImage;
253     }
254     
255     /**
256      * Select the previous edition (presenting a UI).
257      *
258      * @param target the input object against which the editions are compared; must not be <code>null</code>
259      * @param inputEditions the list of editions (element type: <code>ITypedElement</code>s)
260      * @param ppath If <code>null</code> dialog shows full input; if non <code>null</code> it extracts a subsection
261      * @return returns the selected edition or <code>null</code> if error occurred.
262      * The returned <code>ITypedElement</code> is one of the original editions
263      * if <code>path</code> was <code>null</code>; otherwise
264      * it is an <code>ITypedElement</code> returned from <code>IStructureCreator.locate(path, item)</code>
265      * @since 2.0
266      */

267     public ITypedElement selectPreviousEdition(final ITypedElement target, ITypedElement[] inputEditions, Object JavaDoc ppath) {
268         Assert.isNotNull(target);
269         fTargetPair= new Pair(null, target);
270         
271         // sort input editions
272
final int count= inputEditions.length;
273         final IModificationDate[] editions= new IModificationDate[count];
274         for (int i= 0; i < count; i++)
275             editions[i]= (IModificationDate) inputEditions[i];
276         if (count > 1)
277             internalSort(editions);
278             
279         // find StructureCreator if ppath is not null
280
IStructureCreator structureCreator= null;
281         if (ppath != null) {
282             String JavaDoc type= target.getType();
283             StructureCreatorDescriptor scd= CompareUIPlugin.getDefault().getStructureCreator(type);
284             if (scd != null)
285                 structureCreator= scd.createStructureCreator();
286         }
287
288         if (fAddMode) {
289             // does not work in add mode
290
return null;
291         }
292             
293         if (structureCreator != null) {
294             Pair pair= createPair(structureCreator, ppath, target);
295             if (pair != null)
296                 fTargetPair= pair;
297             else
298                 ppath= null; // couldn't extract item because of error
299
}
300                     
301         // from front (newest) to back (oldest)
302
for (int i= 0; i < count; i++) {
303                 
304             ITypedElement edition= (ITypedElement) editions[i];
305             Pair pair= null;
306             
307             if (structureCreator != null && ppath != null) {
308                 // extract sub element from edition
309
pair= createPair(structureCreator, ppath, edition);
310             } else {
311                 pair= new Pair(null, edition);
312             }
313             
314             if (pair != null && pair.fHasError)
315                 return null;
316                 
317             if (pair != null && !fTargetPair.equals(pair)) {
318                 return pair.fItem;
319             }
320         }
321         
322         // nothing found
323
return null;
324     }
325     
326     /**
327      * Presents this modal dialog with the functionality described in the class comment above.
328      *
329      * @param target the input object against which the editions are compared; must not be <code>null</code>
330      * @param inputEditions the list of editions (element type: <code>ITypedElement</code>s)
331      * @param ppath If <code>null</code> dialog shows full input; if non <code>null</code> it extracts a subsection
332      * @return returns the selected edition or <code>null</code> if dialog was cancelled.
333      * The returned <code>ITypedElement</code> is one of the original editions
334      * if <code>path</code> was <code>null</code>; otherwise
335      * it is an <code>ITypedElement</code> returned from <code>IStructureCreator.locate(path, item)</code>
336      */

337     public ITypedElement selectEdition(final ITypedElement target, ITypedElement[] inputEditions, Object JavaDoc ppath) {
338         
339         Assert.isNotNull(target);
340         fTargetPair= new Pair(null, target);
341         
342         // sort input editions
343
final int count= inputEditions.length;
344         final IModificationDate[] editions= new IModificationDate[count];
345         for (int i= 0; i < count; i++)
346             editions[i]= (IModificationDate) inputEditions[i];
347         if (count > 1)
348             internalSort(editions);
349             
350         // find StructureCreator if ppath is not null
351
IStructureCreator structureCreator= null;
352         if (ppath != null) {
353             String JavaDoc type= target.getType();
354             StructureCreatorDescriptor scd= CompareUIPlugin.getDefault().getStructureCreator(type);
355             if (scd != null)
356                 structureCreator= scd.createStructureCreator();
357         }
358
359         if (!fAddMode) {
360             // replace mode
361

362             if (structureCreator != null) {
363                 Pair pair= createPair(structureCreator, ppath, target);
364                 if (pair != null)
365                     fTargetPair= pair;
366                 else
367                     ppath= null; // couldn't extract item because of error
368
}
369             
370             // set the left and right labels for the compare viewer
371
String JavaDoc targetLabel= getTargetLabel(target, fTargetPair.getItem());
372             if (fTargetIsRight)
373                 getCompareConfiguration().setRightLabel(targetLabel);
374             else
375                 getCompareConfiguration().setLeftLabel(targetLabel);
376             
377             if (structureCreator != null && ppath != null) { // extract sub element
378

379                 final IStructureCreator sc= structureCreator;
380                 final Object JavaDoc path= ppath;
381                 
382                 // construct the comparer thread
383
// and perform the background extract
384
fThread= new Thread JavaDoc() {
385                     public void run() {
386                                                                                 
387                         // from front (newest) to back (oldest)
388
for (int i= 0; i < count; i++) {
389                                 
390                             if (fEditionTree == null || fEditionTree.isDisposed())
391                                 break;
392                             ITypedElement edition= (ITypedElement) editions[i];
393                             
394                             // extract sub element from edition
395
Pair pair= createPair(sc, path, edition);
396                             if (pair != null)
397                                 sendPair(pair);
398                         }
399                         sendPair(null);
400                     }
401                 };
402             } else {
403                 // create tree widget
404
create();
405                 
406                 // from front (newest) to back (oldest)
407
for (int i= 0; i < count; i++)
408                     addMemberEdition(new Pair(null, (ITypedElement) editions[i]));
409             }
410             
411         } else {
412             // add mode
413
final Object JavaDoc container= ppath;
414             Assert.isNotNull(container);
415                                 
416             if (structureCreator == null)
417                 return null; // error
418

419             // extract all elements of container
420
final HashSet current= new HashSet();
421             IStructureComparator sco= structureCreator.locate(container, target);
422             if (sco != null) {
423                 Object JavaDoc[] children= sco.getChildren();
424                 if (children != null)
425                     for (int i= 0; i < children.length; i++)
426                         current.add(children[i]);
427             }
428             
429             final IStructureCreator sc= structureCreator;
430             
431             // construct the comparer thread
432
// and perform the background extract
433
fThread= new Thread JavaDoc() {
434                 public void run() {
435                     
436                     // from front (newest) to back (oldest)
437
for (int i= 0; i < count; i++) {
438                             
439                         if (fEditionTree == null || fEditionTree.isDisposed())
440                             break;
441                         ITypedElement edition= (ITypedElement) editions[i];
442                         
443                         IStructureComparator sco2= sc.locate(container, edition);
444                         if (sco2 != null) {
445                             Object JavaDoc[] children= sco2.getChildren();
446                             if (children != null) {
447                                 for (int i2= 0; i2 < children.length; i2++) {
448                                     ITypedElement child= (ITypedElement) children[i2];
449                                     if (!current.contains(child))
450                                         sendPair(new Pair(sc, edition, child));
451                                 }
452                             }
453                         }
454                     }
455                     sendPair(null);
456                 }
457             };
458         }
459         
460         open();
461         
462         if (getReturnCode() == OK)
463             return fSelectedItem;
464         return null;
465     }
466     
467     private Pair createPair(IStructureCreator sc, Object JavaDoc path, ITypedElement input) {
468         IStructureComparator scmp= sc.locate(path, input);
469         if (scmp == null && sc.getStructure(input) == null) { // parse error
470
Pair p= new Pair(sc, input);
471             p.fHasError= true;
472             return p;
473         }
474         if (scmp instanceof ITypedElement)
475             return new Pair(sc, input, (ITypedElement) scmp);
476         return null;
477     }
478
479     /**
480      * Controls whether identical entries are shown or not (default).
481      * This method must be called before <code>selectEdition</code>.
482      *
483      * @param hide if true identical entries are hidden; otherwise they are shown.
484      * @since 2.0
485      */

486     public void setHideIdenticalEntries(boolean hide) {
487         fHideIdentical= hide;
488     }
489
490     /**
491      * Controls whether workspace target is on the left (the default) or right hand side.
492      *
493      * @param isRight if true target is shown on right hand side.
494      * @since 2.0
495      */

496     public void setTargetIsRight(boolean isRight) {
497         fTargetIsRight= isRight;
498     }
499         
500     /**
501      * Controls whether the <code>EditionSelectionDialog</code> is in 'add' mode
502      * or 'replace' mode (the default).
503      *
504      * @param addMode if true dialog is in 'add' mode.
505      * @since 2.0
506      */

507     public void setAddMode(boolean addMode) {
508         fAddMode= addMode;
509         fMultiSelect= addMode;
510     }
511     
512     /**
513      * Controls whether the <code>EditionSelectionDialog</code> is in 'compare' mode
514      * or 'add/replace' (the default) mode.
515      *
516      * @param compareMode if true dialog is in 'add' mode.
517      * @since 2.0
518      */

519     public void setCompareMode(boolean compareMode) {
520         fCompareMode= compareMode;
521         fStructureCompare= fCompareMode && !fAddMode;
522     }
523     
524     /**
525      * Returns the input target that has been specified with the most recent call
526      * to <code>selectEdition</code>. If a not <code>null</code> path was specified this method
527      * returns a subsection of this target (<code>IStructureCreator.locate(path, target)</code>)
528      * instead of the input target.
529      * <p>
530      * For example if the <code>target</code> is a Java compilation unit and <code>path</code> specifies
531      * a method, the value returned from <code>getTarget</code> will be the method not the compilation unit.
532      *
533      * @return the last specified target or a subsection thereof.
534      */

535     public ITypedElement getTarget() {
536         return fTargetPair.getItem();
537     }
538     
539     /**
540      * Returns the editions that have been selected with the most
541      * recent call to <code>selectEdition</code>.
542      *
543      * @return the selected editions as an array.
544      * @since 2.1
545      */

546     public ITypedElement[] getSelection() {
547         ArrayList result= new ArrayList();
548         if (fMemberSelection != null) {
549             Iterator iter= fArrayList.iterator();
550             for (int i= 0; iter.hasNext(); i++) {
551                 Object JavaDoc edition= iter.next();
552                 Object JavaDoc item= fMemberSelection.get(edition);
553                 if (item != null)
554                     result.add(item);
555             }
556         } else if (fSelectedItem != null)
557             result.add(fSelectedItem);
558         return (ITypedElement[]) result.toArray(new ITypedElement[result.size()]);
559     }
560         
561     /**
562      * Returns a label for identifying the target side of a compare viewer.
563      * This implementation extracts the value for the key "targetLabel" from the resource bundle
564      * and passes it as the format argument to <code>MessageFormat.format</code>.
565      * The single format argument for <code>MessageFormat.format</code> ("{0}" in the format string)
566      * is the name of the given input element.
567      * <p>
568      * Subclasses may override to create their own label.
569      * </p>
570      *
571      * @param target the target element for which a label must be returned
572      * @param item if a path has been specified in <code>selectEdition</code> a sub element of the given target; otherwise the same as target
573      * @return a label the target side of a compare viewer
574      */

575     protected String JavaDoc getTargetLabel(ITypedElement target, ITypedElement item) {
576         String JavaDoc format= null;
577         if (target instanceof ResourceNode)
578             format= Utilities.getString(fBundle, "workspaceTargetLabel", null); //$NON-NLS-1$
579
if (format == null)
580             format= Utilities.getString(fBundle, "targetLabel"); //$NON-NLS-1$
581
if (format == null)
582             format= "x{0}"; //$NON-NLS-1$
583

584         return formatString(format, target.getName());
585     }
586
587     private String JavaDoc formatString(String JavaDoc string, String JavaDoc variable) {
588         if (hasVariable(string) || hasDoubleQuotes(string))
589             return MessageFormat.format(string, new Object JavaDoc[] { variable });
590         return string;
591     }
592     
593     private boolean hasDoubleQuotes(String JavaDoc string) {
594         return string.indexOf("''") != -1; //$NON-NLS-1$
595
}
596
597     private boolean hasVariable(String JavaDoc string) {
598         return string.indexOf("{0}") != -1; //$NON-NLS-1$
599
}
600
601     /**
602      * Returns a label for identifying the edition side of a compare viewer.
603      * This implementation extracts the value for the key "editionLabel" from the resource bundle
604      * and passes it as the format argument to <code>MessageFormat.format</code>.
605      * The single format argument for <code>MessageFormat.format</code> ("{0}" in the format string)
606      * is the formatted modification date of the given input element.
607      * <p>
608      * Subclasses may override to create their own label.
609      * </p>
610      *
611      * @param selectedEdition the selected edition for which a label must be returned
612      * @param item if a path has been specified in <code>selectEdition</code> a sub element of the given selectedEdition; otherwise the same as selectedEdition
613      * @return a label for the edition side of a compare viewer
614      */

615     protected String JavaDoc getEditionLabel(ITypedElement selectedEdition, ITypedElement item) {
616         String JavaDoc format= null;
617         if (selectedEdition instanceof ResourceNode)
618             format= Utilities.getString(fBundle, "workspaceEditionLabel", null); //$NON-NLS-1$
619
else if (selectedEdition instanceof HistoryItem)
620             format= Utilities.getString(fBundle, "historyEditionLabel", null); //$NON-NLS-1$
621
if (format == null)
622             format= Utilities.getString(fBundle, "editionLabel"); //$NON-NLS-1$
623
if (format == null)
624             format= "x{0}"; //$NON-NLS-1$
625

626
627         String JavaDoc date= ""; //$NON-NLS-1$
628
if (selectedEdition instanceof IModificationDate) {
629             long modDate= ((IModificationDate)selectedEdition).getModificationDate();
630             date= DateFormat.getDateTimeInstance().format(new Date(modDate));
631         }
632         
633         return formatString(format, date);
634     }
635     
636     /**
637      * Returns a label for identifying a node in the edition tree viewer.
638      * This implementation extracts the value for the key "workspaceTreeFormat" or
639      * "treeFormat" (in that order) from the resource bundle
640      * and passes it as the format argument to <code>MessageFormat.format</code>.
641      * The single format argument for <code>MessageFormat.format</code> ("{0}" in the format string)
642      * is the formatted modification date of the given input element.
643      * <p>
644      * Subclasses may override to create their own label.
645      * </p>
646      *
647      * @param edition the edition for which a label must be returned
648      * @param item if a path has been specified in <code>edition</code> a sub element of the given edition; otherwise the same as edition
649      * @param date this date will be returned as part of the formatted string
650      * @return a label of a node in the edition tree viewer
651      * @since 2.0
652      */

653     protected String JavaDoc getShortEditionLabel(ITypedElement edition, ITypedElement item, Date date) {
654         String JavaDoc format= null;
655         if (edition instanceof ResourceNode)
656             format= Utilities.getString(fBundle, "workspaceTreeFormat", null); //$NON-NLS-1$
657
if (format == null)
658             format= Utilities.getString(fBundle, "treeFormat", null); //$NON-NLS-1$
659
if (format == null)
660             format= "x{0}"; //$NON-NLS-1$
661

662         String JavaDoc ds= DateFormat.getTimeInstance().format(date);
663         return formatString(format, ds);
664     }
665     
666     /**
667      * Returns an image for identifying the edition side of a compare viewer.
668      * This implementation extracts the value for the key "editionLabel" from the resource bundle
669      * and passes it as the format argument to <code>MessageFormat.format</code>.
670      * The single format argument for <code>MessageFormat.format</code> ("{0}" in the format string)
671      * is the formatted modification date of the given input element.
672      * <p>
673      * Subclasses may override to create their own label.
674      * </p>
675      *
676      * @param selectedEdition the selected edition for which a label must be returned
677      * @param item if a path has been specified in <code>selectEdition</code> a sub element of the given selectedEdition; otherwise the same as selectedEdition
678      * @return a label the edition side of a compare viewer
679      * @since 2.0
680      */

681     protected Image getEditionImage(ITypedElement selectedEdition, ITypedElement item) {
682         if (selectedEdition instanceof ResourceNode)
683             return selectedEdition.getImage();
684         if (selectedEdition instanceof HistoryItem) {
685             if (fTimeImage == null) {
686                 String JavaDoc iconName= Utilities.getString(fBundle, "timeIcon", "obj16/resource_obj.gif"); //$NON-NLS-1$ //$NON-NLS-2$
687
ImageDescriptor id= CompareUIPlugin.getImageDescriptor(iconName);
688                 if (id != null)
689                     fTimeImage= id.createImage();
690             }
691             return fTimeImage;
692         }
693         return null;
694     }
695     
696     /* (non Javadoc)
697      * Creates SWT control tree.
698      */

699     protected synchronized Control createDialogArea(Composite parent2) {
700         
701         Composite parent= (Composite) super.createDialogArea(parent2);
702
703         getShell().setText(Utilities.getString(fBundle, "title")); //$NON-NLS-1$
704

705         Splitter vsplitter= new Splitter(parent, SWT.VERTICAL);
706         vsplitter.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL
707                     | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL));
708
709         vsplitter.addDisposeListener(
710             new DisposeListener() {
711                 public void widgetDisposed(DisposeEvent e) {
712                     if (fCompareConfiguration != null) {
713                         fCompareConfiguration.dispose();
714                         fCompareConfiguration= null;
715                     }
716                     if (fDateImage != null) {
717                         fDateImage.dispose();
718                         fDateImage= null;
719                     }
720                     if (fTimeImage != null) {
721                         fTimeImage.dispose();
722                         fTimeImage= null;
723                     }
724                 }
725             }
726         );
727         
728         if (fAddMode) {
729             // we need two panes: the left for the elements, the right one for the editions
730
Splitter hsplitter= new Splitter(vsplitter, SWT.HORIZONTAL);
731             
732             fMemberPane= new CompareViewerPane(hsplitter, SWT.BORDER | SWT.FLAT);
733             fMemberPane.setText(Utilities.getString(fBundle, "memberPaneTitle")); //$NON-NLS-1$
734

735             int flags= SWT.H_SCROLL | SWT.V_SCROLL;
736             if (fMultiSelect)
737                 flags|= SWT.CHECK;
738             fMemberTable= new Table(fMemberPane, flags);
739             fMemberTable.addSelectionListener(
740                 new SelectionAdapter() {
741                     public void widgetSelected(SelectionEvent e) {
742                         if (e.detail == SWT.CHECK) {
743                             if (e.item instanceof TableItem) {
744                                 TableItem ti= (TableItem) e.item;
745                                 Object JavaDoc data= ti.getData();
746                                 if (ti.getChecked())
747                                     fArrayList.add(data);
748                                 else
749                                     fArrayList.remove(data);
750                                     
751                                 if (fCommitButton != null)
752                                     fCommitButton.setEnabled(fArrayList.size() > 0);
753                                     
754                                 fMemberTable.setSelection(new TableItem[] { ti });
755                             }
756                         }
757                         handleMemberSelect(e.item);
758                     }
759                 }
760             );
761             fMemberPane.setContent(fMemberTable);
762             fMemberTable.setFocus();
763                         
764             fEditionPane= new CompareViewerPane(hsplitter, SWT.BORDER | SWT.FLAT);
765         } else {
766             if (fStructureCompare) {
767                 // we need two panes: the left for the elements, the right one for the structured diff
768
Splitter hsplitter= new Splitter(vsplitter, SWT.HORIZONTAL);
769                 
770                 fEditionPane= new CompareViewerPane(hsplitter, SWT.BORDER | SWT.FLAT);
771                 fStructuredComparePane= new CompareViewerSwitchingPane(hsplitter, SWT.BORDER | SWT.FLAT, true) {
772                     protected Viewer getViewer(Viewer oldViewer, Object JavaDoc input) {
773                         if (input instanceof ICompareInput)
774                             return CompareUI.findStructureViewer(oldViewer, (ICompareInput)input, this, getCompareConfiguration());
775                         return null;
776                     }
777                 };
778                 fStructuredComparePane.addSelectionChangedListener(
779                     new ISelectionChangedListener() {
780                         public void selectionChanged(SelectionChangedEvent e) {
781                             feedInput2(e.getSelection());
782                         }
783                     }
784                 );
785             } else {
786                 // only a single pane showing the editions
787
fEditionPane= new CompareViewerPane(vsplitter, SWT.BORDER | SWT.FLAT);
788             }
789             if (fTitleArg == null)
790                 fTitleArg= fTargetPair.getItem().getName();
791             String JavaDoc titleFormat= Utilities.getString(fBundle, "treeTitleFormat"); //$NON-NLS-1$
792
String JavaDoc title= MessageFormat.format(titleFormat, new String JavaDoc[] { fTitleArg });
793             fEditionPane.setText(title);
794             if (fTitleImage != null)
795                 fEditionPane.setImage(fTitleImage);
796         }
797         
798         fEditionTree= new Tree(fEditionPane, SWT.H_SCROLL | SWT.V_SCROLL);
799         fEditionTree.addSelectionListener(
800             new SelectionAdapter() {
801 // public void widgetDefaultSelected(SelectionEvent e) {
802
// handleDefaultSelected();
803
// }
804
public void widgetSelected(SelectionEvent e) {
805                     feedInput(e.item);
806                 }
807             }
808         );
809         fEditionPane.setContent(fEditionTree);
810         
811         // now start the thread (and forget about it)
812
if (fThread != null) {
813             fThread.start();
814             fThread= null;
815         }
816         
817         fContentPane= new CompareViewerSwitchingPane(vsplitter, SWT.BORDER | SWT.FLAT) {
818             protected Viewer getViewer(Viewer oldViewer, Object JavaDoc input) {
819                 return CompareUI.findContentViewer(oldViewer, input, this, getCompareConfiguration());
820             }
821         };
822         vsplitter.setWeights(new int[] { 30, 70 });
823         
824         IPreferenceStore store= getCompareConfiguration().getPreferenceStore();
825         if (store != null) {
826             if (store.getBoolean(ComparePreferencePage.SHOW_MORE_INFO)) {
827                 statusLabel = new Label(parent, SWT.NONE);
828                 statusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
829             }
830         }
831
832         applyDialogFont(parent);
833         return parent;
834     }
835     
836     /* (non-Javadoc)
837      * Method declared on Dialog.
838      */

839     protected void createButtonsForButtonBar(Composite parent) {
840         String JavaDoc buttonLabel= Utilities.getString(fBundle, "buttonLabel", IDialogConstants.OK_LABEL); //$NON-NLS-1$
841
if (fCompareMode) {
842             // only a 'Done' button
843
createButton(parent, IDialogConstants.CANCEL_ID, buttonLabel, false);
844         } else {
845             // a 'Cancel' and a 'Add/Replace' button
846
fCommitButton= createButton(parent, IDialogConstants.OK_ID, buttonLabel, true);
847             fCommitButton.setEnabled(false);
848             createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
849         }
850     }
851
852     /**
853      * Overidden to disable dismiss on double click in compare mode.
854      * @since 2.0
855      */

856     protected void okPressed() {
857         if (fCompareMode) {
858             // don't dismiss dialog
859
} else
860             super.okPressed();
861     }
862
863     //---- private stuff ----------------------------------------------------------------------------------------
864

865     /*
866      * Asynchroneously sends a Pair (or null) to the UI thread.
867      */

868     private void sendPair(final Pair pair) {
869         if (fEditionTree != null && !fEditionTree.isDisposed()) {
870             Display display= fEditionTree.getDisplay();
871             display.asyncExec(
872                 new Runnable JavaDoc() {
873                     public void run() {
874                         addMemberEdition(pair);
875                     }
876                 }
877             );
878         }
879     }
880     
881     private static void internalSort(IModificationDate[] keys) {
882         Arrays.sort(keys, new Comparator() {
883             public int compare(Object JavaDoc o1, Object JavaDoc o2) {
884                 IModificationDate d1= (IModificationDate) o1;
885                 IModificationDate d2= (IModificationDate) o2;
886                 long d= d2.getModificationDate() - d1.getModificationDate();
887                 if (d < 0)
888                     return -1;
889                 if (d > 0)
890                     return 1;
891                 return 0;
892             }
893         });
894     }
895     
896     /*
897      * Adds the given Pair to the member editions.
898      * If HIDE_IDENTICAL is true the new Pair is only added if its contents
899      * is different from the preceeding Pair.
900      * If the argument is <code>null</code> the message "No Editions found" is shown
901      * in the member or edition viewer.
902      */

903     private void addMemberEdition(Pair pair) {
904         
905         if (pair == null) { // end of list of pairs
906
if (fMemberTable != null) {
907                 if (!fMemberTable.isDisposed() && fMemberTable.getItemCount() == 0) {
908                     if (fMultiSelect) {
909                         fMemberTable.dispose();
910                         fMemberTable= new Table(fMemberPane, SWT.NONE);
911                         fMemberPane.setContent(fMemberTable);
912                     }
913                     TableItem ti= new TableItem(fMemberTable, SWT.NONE);
914                     ti.setText(Utilities.getString(fBundle, "noAdditionalMembersMessage")); //$NON-NLS-1$
915
}
916                 return;
917             }
918             if (fEditionTree != null && !fEditionTree.isDisposed() && fEditionTree.getItemCount() == 0) {
919                 TreeItem ti= new TreeItem(fEditionTree, SWT.NONE);
920                 ti.setText(Utilities.getString(fBundle, "notFoundInLocalHistoryMessage")); //$NON-NLS-1$
921
}
922             return;
923         }
924         
925         if (fMemberEditions == null)
926             fMemberEditions= new HashMap();
927         if (fMultiSelect && fMemberSelection == null)
928             fMemberSelection= new HashMap();
929         
930         ITypedElement item= pair.getItem();
931         List JavaDoc editions= (List JavaDoc) fMemberEditions.get(item);
932         if (editions == null) {
933             editions= new ArrayList();
934             fMemberEditions.put(item, editions);
935             if (fMemberTable != null && !fMemberTable.isDisposed()) {
936                 ITypedElement te= item;
937                 String JavaDoc name= te.getName();
938                 
939                 // find position
940
TableItem[] items= fMemberTable.getItems();
941                 int where= items.length;
942                 for (int i= 0; i < where; i++) {
943                     String JavaDoc n= items[i].getText();
944                     if (n.compareTo(name) > 0) {
945                         where= i;
946                         break;
947                     }
948                 }
949                 
950                 TableItem ti= new TableItem(fMemberTable, where, SWT.NULL);
951                 ti.setImage(te.getImage());
952                 ti.setText(name);
953                 ti.setData(editions);
954             }
955         }
956         if (fHideIdentical) {
957             Pair last= fTargetPair;
958             int size= editions.size();
959             if (size > 0)
960                 last= (Pair) editions.get(size-1);
961             if (last != null && last.equals(pair))
962                 return; // don't add since the new one is equal to old
963
}
964         editions.add(pair);
965         
966         if (!fAddMode || editions == fCurrentEditions)
967             addEdition(pair);
968     }
969         
970     /*
971      * Returns the number of s since Jan 1st, 1970.
972      * The given date is converted to GMT and daylight saving is taken into account too.
973      */

974     private long dayNumber(long date) {
975         int ONE_DAY_MS= 24*60*60 * 1000; // one day in milli seconds
976

977         Calendar calendar= Calendar.getInstance();
978         long localTimeOffset= calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
979         
980         return (date + localTimeOffset) / ONE_DAY_MS;
981     }
982     
983     /*
984      * Adds the given Pair to the edition tree.
985      * It takes care of creating tree nodes for different dates.
986      */

987     private void addEdition(Pair pair) {
988         if (fEditionTree == null || fEditionTree.isDisposed())
989             return;
990         
991         // find last day
992
TreeItem[] days= fEditionTree.getItems();
993         TreeItem lastDay= null;
994         if (days.length > 0)
995             lastDay= days[days.length-1];
996         
997         boolean first= lastDay == null;
998         
999         ITypedElement edition= pair.getEdition();
1000        ITypedElement item= pair.getItem();
1001        
1002        long ldate= ((IModificationDate)edition).getModificationDate();
1003        long day= dayNumber(ldate);
1004        Date date= new Date(ldate);
1005        if (lastDay == null || day != dayNumber(((Date)lastDay.getData()).getTime())) {
1006            lastDay= new TreeItem(fEditionTree, SWT.NONE);
1007            if (fDateImage == null) {
1008                String JavaDoc iconName= Utilities.getString(fBundle, "dateIcon", "obj16/day_obj.gif"); //$NON-NLS-2$ //$NON-NLS-1$
1009
ImageDescriptor id= CompareUIPlugin.getImageDescriptor(iconName);
1010                if (id != null)
1011                    fDateImage= id.createImage();
1012            }
1013            lastDay.setImage(fDateImage);
1014            String JavaDoc df= DateFormat.getDateInstance().format(date);
1015            long today= dayNumber(System.currentTimeMillis());
1016            
1017            String JavaDoc formatKey;
1018            if (day == today)
1019                formatKey= "todayFormat"; //$NON-NLS-1$
1020
else if (day == today-1)
1021                formatKey= "yesterdayFormat"; //$NON-NLS-1$
1022
else
1023                formatKey= "dayFormat"; //$NON-NLS-1$
1024
String JavaDoc pattern= Utilities.getString(fBundle, formatKey);
1025            if (pattern != null)
1026                df= MessageFormat.format(pattern, new String JavaDoc[] { df });
1027            lastDay.setText(df);
1028            lastDay.setData(date);
1029        }
1030        TreeItem ti= new TreeItem(lastDay, SWT.NONE);
1031        ti.setImage(getEditionImage(edition, item));
1032        
1033        String JavaDoc s= getShortEditionLabel(edition, item, date);
1034        if (pair.fHasError) {
1035            String JavaDoc pattern= Utilities.getString(fBundle, "parseErrorFormat"); //$NON-NLS-1$
1036
s= MessageFormat.format(pattern, new String JavaDoc[] { s } );
1037        }
1038        ti.setText(s);
1039        
1040        ti.setData(pair);
1041        
1042        // determine selected TreeItem
1043
TreeItem selection= first ? ti : null;
1044        if (fMemberSelection != null) {
1045            Object JavaDoc selected= fMemberSelection.get(fCurrentEditions);
1046            if (selected != null) {
1047                if (selected == pair.getItem())
1048                    selection= ti;
1049                else
1050                    selection= null;
1051            }
1052        }
1053        if (selection != null) {
1054            fEditionTree.setSelection(new TreeItem[] { selection });
1055            if (!fAddMode)
1056                fEditionTree.setFocus();
1057            feedInput(selection);
1058        }
1059        
1060        if (first) // expand first node
1061
lastDay.setExpanded(true);
1062    }
1063                        
1064    /*
1065     * Feeds selection from member viewer to edition viewer.
1066     */

1067    private void handleMemberSelect(Widget w) {
1068        Object JavaDoc data= w.getData();
1069        if (data instanceof List JavaDoc) {
1070            List JavaDoc editions= (List JavaDoc) data;
1071            if (editions != fCurrentEditions) {
1072                fCurrentEditions= editions;
1073                fEditionTree.removeAll();
1074                
1075                String JavaDoc pattern= Utilities.getString(fBundle, "treeTitleFormat"); //$NON-NLS-1$
1076
String JavaDoc title= MessageFormat.format(pattern, new Object JavaDoc[] { ((Item)w).getText() });
1077                fEditionPane.setText(title);
1078                                
1079                Iterator iter= editions.iterator();
1080                while (iter.hasNext()) {
1081                    Object JavaDoc item= iter.next();
1082                    if (item instanceof Pair)
1083                        addEdition((Pair) item);
1084                }
1085            }
1086        }
1087    }
1088    
1089    private void setInput(Object JavaDoc input) {
1090        if (!fCompare && input instanceof ICompareInput) {
1091            ICompareInput ci= (ICompareInput) input;
1092            if (fTargetIsRight)
1093                input= ci.getLeft();
1094            else
1095                input= ci.getRight();
1096        }
1097        fContentPane.setInput(input);
1098        if (fStructuredComparePane != null)
1099            fStructuredComparePane.setInput(input);
1100    }
1101    
1102    /*
1103     * Feeds selection from edition viewer to content (and structure) viewer.
1104     */

1105    private void feedInput(Widget w) {
1106        Object JavaDoc input= w.getData();
1107        boolean isOK= false;
1108        if (input instanceof Pair) {
1109            Pair pair= (Pair) input;
1110            fSelectedItem= pair.getItem();
1111            isOK= !pair.fHasError;
1112            
1113            ITypedElement edition= pair.getEdition();
1114            String JavaDoc editionLabel= getEditionLabel(edition, fSelectedItem);
1115            Image editionImage= getEditionImage(edition, fSelectedItem);
1116                    
1117            if (fAddMode) {
1118                if (fMemberSelection != null)
1119                    fMemberSelection.put(fCurrentEditions, fSelectedItem);
1120                setInput(fSelectedItem);
1121                fContentPane.setText(editionLabel);
1122                fContentPane.setImage(editionImage);
1123            } else {
1124                getCompareConfiguration();
1125                if (fTargetIsRight) {
1126                    fCompareConfiguration.setLeftLabel(editionLabel);
1127                    fCompareConfiguration.setLeftImage(editionImage);
1128                    setInput(new DiffNode(fSelectedItem, fTargetPair.getItem()));
1129                } else {
1130                    fCompareConfiguration.setRightLabel(editionLabel);
1131                    fCompareConfiguration.setRightImage(editionImage);
1132                    setInput(new DiffNode(fTargetPair.getItem(), fSelectedItem));
1133                }
1134            }
1135        } else {
1136            fSelectedItem= null;
1137            setInput(null);
1138        }
1139        if (fCommitButton != null) {
1140            if (fMultiSelect)
1141                fCommitButton.setEnabled(isOK && fSelectedItem != null && fArrayList.size() > 0);
1142            else
1143                fCommitButton.setEnabled(isOK && fSelectedItem != null && fTargetPair.getItem() != fSelectedItem);
1144        }
1145    }
1146    
1147    /*
1148     * Feeds selection from structure viewer to content viewer.
1149     */

1150    private void feedInput2(ISelection sel) {
1151        if (sel instanceof IStructuredSelection) {
1152            IStructuredSelection ss= (IStructuredSelection) sel;
1153            if (ss.size() == 1)
1154                fContentPane.setInput(ss.getFirstElement());
1155        }
1156    }
1157}
1158
Popular Tags