KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > compare > internal > ResourceCompareInput


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  * Matt McCutchen (hashproduct+eclipse@gmail.com) - Bug 35390 Three-way compare cannot select (mis-selects) )ancestor resource
11  *******************************************************************************/

12 package org.eclipse.compare.internal;
13
14 import java.lang.reflect.InvocationTargetException JavaDoc;
15 import com.ibm.icu.text.MessageFormat;
16 import java.util.HashSet JavaDoc;
17 import java.util.Set JavaDoc;
18
19 import org.eclipse.core.resources.*;
20 import org.eclipse.core.runtime.*;
21
22 import org.eclipse.osgi.util.NLS;
23 import org.eclipse.swt.SWT;
24 import org.eclipse.swt.events.*;
25 import org.eclipse.swt.layout.*;
26 import org.eclipse.swt.widgets.*;
27
28 import org.eclipse.jface.action.*;
29 import org.eclipse.jface.dialogs.*;
30 import org.eclipse.jface.viewers.*;
31 import org.eclipse.jface.window.Window;
32
33 import org.eclipse.compare.*;
34 import org.eclipse.compare.structuremergeviewer.*;
35
36
37 /**
38  * A two-way or three-way compare for arbitrary IResources.
39  */

40 class ResourceCompareInput extends CompareEditorInput {
41     
42     private static final boolean NORMALIZE_CASE= true;
43     
44     private boolean fThreeWay= false;
45     private Object JavaDoc fRoot;
46     private IStructureComparator fAncestor;
47     private IStructureComparator fLeft;
48     private IStructureComparator fRight;
49     private IResource fAncestorResource;
50     private IResource fLeftResource;
51     private IResource fRightResource;
52     private DiffTreeViewer fDiffViewer;
53     private IAction fOpenAction;
54     
55     class MyDiffNode extends DiffNode {
56         
57         private boolean fDirty= false;
58         private ITypedElement fLastId;
59         private String JavaDoc fLastName;
60         
61         
62         public MyDiffNode(IDiffContainer parent, int description, ITypedElement ancestor, ITypedElement left, ITypedElement right) {
63             super(parent, description, ancestor, left, right);
64         }
65         public void fireChange() {
66             super.fireChange();
67             setDirty(true);
68             fDirty= true;
69             if (fDiffViewer != null)
70                 fDiffViewer.refresh(this);
71         }
72         void clearDirty() {
73             fDirty= false;
74         }
75         public String JavaDoc getName() {
76             if (fLastName == null)
77                 fLastName= super.getName();
78             if (fDirty)
79                 return '<' + fLastName + '>';
80             return fLastName;
81         }
82         
83         public ITypedElement getId() {
84             ITypedElement id= super.getId();
85             if (id == null)
86                 return fLastId;
87             fLastId= id;
88             return id;
89         }
90     }
91     
92     static class FilteredBufferedResourceNode extends BufferedResourceNode {
93         FilteredBufferedResourceNode(IResource resource) {
94             super(resource);
95         }
96         protected IStructureComparator createChild(IResource child) {
97             String JavaDoc name= child.getName();
98             if (CompareUIPlugin.getDefault().filter(name, child instanceof IContainer, false))
99                 return null;
100             return new FilteredBufferedResourceNode(child);
101         }
102     }
103     
104     /*
105      * Creates an compare editor input for the given selection.
106      */

107     ResourceCompareInput(CompareConfiguration config) {
108         super(config);
109     }
110             
111     public Viewer createDiffViewer(Composite parent) {
112         fDiffViewer= new DiffTreeViewer(parent, getCompareConfiguration()) {
113             protected void fillContextMenu(IMenuManager manager) {
114                 
115                 if (fOpenAction == null) {
116                     fOpenAction= new Action() {
117                         public void run() {
118                             handleOpen(null);
119                         }
120                     };
121                     Utilities.initAction(fOpenAction, getBundle(), "action.CompareContents."); //$NON-NLS-1$
122
}
123                 
124                 boolean enable= false;
125                 ISelection selection= getSelection();
126                 if (selection instanceof IStructuredSelection) {
127                     IStructuredSelection ss= (IStructuredSelection)selection;
128                     if (ss.size() == 1) {
129                         Object JavaDoc element= ss.getFirstElement();
130                         if (element instanceof MyDiffNode) {
131                             ITypedElement te= ((MyDiffNode) element).getId();
132                             if (te != null)
133                                 enable= !ITypedElement.FOLDER_TYPE.equals(te.getType());
134                         } else
135                             enable= true;
136                     }
137                 }
138                 fOpenAction.setEnabled(enable);
139                 
140                 manager.add(fOpenAction);
141                 
142                 super.fillContextMenu(manager);
143             }
144         };
145         return fDiffViewer;
146     }
147
148     class SelectAncestorDialog extends MessageDialog {
149         private IResource[] theResources;
150         IResource ancestorResource;
151         IResource leftResource;
152         IResource rightResource;
153         
154         private Button[] buttons;
155         
156         public SelectAncestorDialog(Shell parentShell, IResource[] theResources) {
157             super(parentShell, CompareMessages.SelectAncestorDialog_title,
158                 null, CompareMessages.SelectAncestorDialog_message,
159                 MessageDialog.QUESTION,
160                 new String JavaDoc[] { IDialogConstants.OK_LABEL,
161                     IDialogConstants.CANCEL_LABEL }, 0);
162             this.theResources = theResources;
163         }
164         
165         protected Control createCustomArea(Composite parent) {
166             Composite composite = new Composite(parent, SWT.NONE);
167             composite.setLayout(new GridLayout());
168             buttons = new Button[3];
169             for (int i = 0; i < 3; i++) {
170                 buttons[i] = new Button(composite, SWT.RADIO);
171                 buttons[i].addSelectionListener(selectionListener);
172                 buttons[i].setText(NLS.bind(CompareMessages.SelectAncestorDialog_option,
173                     theResources[i].getFullPath().toPortableString()));
174                 buttons[i].setFont(parent.getFont());
175                 // set initial state
176
buttons[i].setSelection(i == 0);
177             }
178             pickAncestor(0);
179             return composite;
180         }
181
182         private void pickAncestor(int i) {
183             ancestorResource = theResources[i];
184             leftResource = theResources[i == 0 ? 1 : 0];
185             rightResource = theResources[i == 2 ? 1 : 2];
186         }
187         
188         private SelectionListener selectionListener = new SelectionAdapter() {
189             public void widgetSelected(SelectionEvent e) {
190                 Button selectedButton = (Button) e.widget;
191                 if (!selectedButton.getSelection())
192                     return;
193                 for (int i = 0; i < 3; i++)
194                     if (selectedButton == buttons[i])
195                         pickAncestor(i);
196             }
197         };
198     }
199
200     // If the compare is three-way, this method asks the user which resource
201
// to use as the ancestor. Returns false if the user cancels the prompt,
202
// true otherwise.
203
boolean setSelection(ISelection s, Shell shell) {
204         
205         IResource[] selection= Utilities.getResources(s);
206
207         fThreeWay= selection.length == 3;
208         
209         if (fThreeWay) {
210             SelectAncestorDialog dialog =
211                 new SelectAncestorDialog(shell, selection);
212             int code = dialog.open();
213             if (code == Window.CANCEL)
214                 return false;
215             
216             fAncestorResource= dialog.ancestorResource;
217             fAncestor= getStructure(fAncestorResource);
218             fLeftResource= dialog.leftResource;
219             fRightResource= dialog.rightResource;
220         } else {
221             fAncestorResource= null;
222             fAncestor= null;
223             fLeftResource= selection[0];
224             fRightResource= selection[1];
225         }
226
227         fLeft= getStructure(fLeftResource);
228         fRight= getStructure(fRightResource);
229         return true;
230     }
231     
232     /*
233      * Returns true if compare can be executed for the given selection.
234      */

235     public boolean isEnabled(ISelection s) {
236         
237         IResource[] selection= Utilities.getResources(s);
238         if (selection.length < 2 || selection.length > 3)
239             return false;
240
241         boolean threeWay= selection.length == 3;
242         
243         if (threeWay)
244             // It only makes sense if they're all mutually comparable.
245
// If not, the user should compare two of them.
246
return comparable(selection[0], selection[1])
247                 && comparable(selection[0], selection[2])
248                 && comparable(selection[1], selection[2]);
249         
250         return comparable(selection[0], selection[1]);
251     }
252     
253     /**
254      * Initializes the images in the compare configuration.
255      */

256     void initializeCompareConfiguration() {
257         CompareConfiguration cc= getCompareConfiguration();
258         if (fLeftResource != null) {
259             cc.setLeftLabel(buildLabel(fLeftResource));
260             cc.setLeftImage(CompareUIPlugin.getImage(fLeftResource));
261         }
262         if (fRightResource != null) {
263             cc.setRightLabel(buildLabel(fRightResource));
264             cc.setRightImage(CompareUIPlugin.getImage(fRightResource));
265         }
266         if (fThreeWay && fAncestorResource != null) {
267             cc.setAncestorLabel(buildLabel(fAncestorResource));
268             cc.setAncestorImage(CompareUIPlugin.getImage(fAncestorResource));
269         }
270     }
271     
272     /*
273      * Returns true if both resources are either structured or unstructured.
274      */

275     private boolean comparable(IResource c1, IResource c2) {
276         return hasStructure(c1) == hasStructure(c2);
277     }
278     
279     /*
280      * Returns true if the given argument has a structure.
281      */

282     private boolean hasStructure(IResource input) {
283         
284         if (input instanceof IContainer)
285             return true;
286             
287         if (input instanceof IFile) {
288             IFile file= (IFile) input;
289             String JavaDoc type= file.getFileExtension();
290             if (type != null) {
291                 type= normalizeCase(type);
292                 return "JAR".equals(type) || "ZIP".equals(type); //$NON-NLS-2$ //$NON-NLS-1$
293
}
294         }
295         
296         return false;
297     }
298     
299     /*
300      * Creates a <code>IStructureComparator</code> for the given input.
301      * Returns <code>null</code> if no <code>IStructureComparator</code>
302      * can be found for the <code>IResource</code>.
303      */

304     private IStructureComparator getStructure(IResource input) {
305         
306         if (input instanceof IContainer)
307             return new FilteredBufferedResourceNode(input);
308             
309         if (input instanceof IFile) {
310             IStructureComparator rn= new FilteredBufferedResourceNode(input);
311             IFile file= (IFile) input;
312             String JavaDoc type= normalizeCase(file.getFileExtension());
313             if ("JAR".equals(type) || "ZIP".equals(type)) //$NON-NLS-2$ //$NON-NLS-1$
314
return new ZipFileStructureCreator().getStructure(rn);
315             return rn;
316         }
317         return null;
318     }
319     
320     /*
321      * Performs a two-way or three-way diff on the current selection.
322      */

323     public Object JavaDoc prepareInput(IProgressMonitor pm) throws InvocationTargetException JavaDoc {
324                 
325         try {
326             // fix for PR 1GFMLFB: ITPUI:WIN2000 - files that are out of sync with the file system appear as empty
327
fLeftResource.refreshLocal(IResource.DEPTH_INFINITE, pm);
328             fRightResource.refreshLocal(IResource.DEPTH_INFINITE, pm);
329             if (fThreeWay && fAncestorResource != null)
330                 fAncestorResource.refreshLocal(IResource.DEPTH_INFINITE, pm);
331             // end fix
332

333             pm.beginTask(Utilities.getString("ResourceCompare.taskName"), IProgressMonitor.UNKNOWN); //$NON-NLS-1$
334

335             String JavaDoc leftLabel= fLeftResource.getName();
336             String JavaDoc rightLabel= fRightResource.getName();
337             
338             String JavaDoc title;
339             if (fThreeWay) {
340                 String JavaDoc format= Utilities.getString("ResourceCompare.threeWay.title"); //$NON-NLS-1$
341
String JavaDoc ancestorLabel= fAncestorResource.getName();
342                 title= MessageFormat.format(format, new String JavaDoc[] {ancestorLabel, leftLabel, rightLabel});
343             } else {
344                 String JavaDoc format= Utilities.getString("ResourceCompare.twoWay.title"); //$NON-NLS-1$
345
title= MessageFormat.format(format, new String JavaDoc[] {leftLabel, rightLabel});
346             }
347             setTitle(title);
348             
349             Differencer d= new Differencer() {
350                 protected Object JavaDoc visit(Object JavaDoc parent, int description, Object JavaDoc ancestor, Object JavaDoc left, Object JavaDoc right) {
351                     return new MyDiffNode((IDiffContainer) parent, description, (ITypedElement)ancestor, (ITypedElement)left, (ITypedElement)right);
352                 }
353             };
354             
355             fRoot= d.findDifferences(fThreeWay, pm, null, fAncestor, fLeft, fRight);
356             return fRoot;
357             
358         } catch (CoreException ex) {
359             throw new InvocationTargetException JavaDoc(ex);
360         } finally {
361             pm.done();
362         }
363     }
364     
365     public String JavaDoc getToolTipText() {
366         if (fLeftResource != null && fRightResource != null) {
367             String JavaDoc leftLabel= fLeftResource.getFullPath().makeRelative().toString();
368             String JavaDoc rightLabel= fRightResource.getFullPath().makeRelative().toString();
369             if (fThreeWay) {
370                 String JavaDoc format= Utilities.getString("ResourceCompare.threeWay.tooltip"); //$NON-NLS-1$
371
String JavaDoc ancestorLabel= fAncestorResource.getFullPath().makeRelative().toString();
372                 return MessageFormat.format(format, new String JavaDoc[] {ancestorLabel, leftLabel, rightLabel});
373             }
374             String JavaDoc format= Utilities.getString("ResourceCompare.twoWay.tooltip"); //$NON-NLS-1$
375
return MessageFormat.format(format, new String JavaDoc[] {leftLabel, rightLabel});
376         }
377         // fall back
378
return super.getToolTipText();
379     }
380     
381     private String JavaDoc buildLabel(IResource r) {
382         String JavaDoc n= r.getFullPath().toString();
383         if (n.charAt(0) == IPath.SEPARATOR)
384             return n.substring(1);
385         return n;
386     }
387     
388     public void saveChanges(IProgressMonitor pm) throws CoreException {
389         super.saveChanges(pm);
390         if (fRoot instanceof DiffNode) {
391             try {
392                 commit(pm, (DiffNode) fRoot);
393             } finally {
394                 if (fDiffViewer != null)
395                     fDiffViewer.refresh();
396                 setDirty(false);
397             }
398         }
399     }
400     
401     /*
402      * Recursively walks the diff tree and commits all changes.
403      */

404     private static void commit(IProgressMonitor pm, DiffNode node) throws CoreException {
405         
406         if (node instanceof MyDiffNode)
407             ((MyDiffNode)node).clearDirty();
408         
409         ITypedElement left= node.getLeft();
410         if (left instanceof BufferedResourceNode)
411             ((BufferedResourceNode) left).commit(pm);
412             
413         ITypedElement right= node.getRight();
414         if (right instanceof BufferedResourceNode)
415             ((BufferedResourceNode) right).commit(pm);
416
417         IDiffElement[] children= node.getChildren();
418         if (children != null) {
419             for (int i= 0; i < children.length; i++) {
420                 IDiffElement element= children[i];
421                 if (element instanceof DiffNode)
422                     commit(pm, (DiffNode) element);
423             }
424         }
425     }
426     
427     /* (non Javadoc)
428      * see IAdaptable.getAdapter
429      */

430     public Object JavaDoc getAdapter(Class JavaDoc adapter) {
431         if (IFile.class.equals(adapter)) {
432             IProgressMonitor pm= new NullProgressMonitor();
433             // flush changes in any dirty viewer
434
flushViewers(pm);
435             IFile[] files= (IFile[]) getAdapter(IFile[].class);
436             if (files != null && files.length > 0)
437                 return files[0]; // can only return one: limitation on IDE.saveAllEditors; see #64617
438
return null;
439         }
440         if (IFile[].class.equals(adapter)) {
441             HashSet JavaDoc collector= new HashSet JavaDoc();
442             collectDirtyResources(fRoot, collector);
443             return collector.toArray(new IFile[collector.size()]);
444         }
445         return super.getAdapter(adapter);
446     }
447     
448     private void collectDirtyResources(Object JavaDoc o, Set JavaDoc collector) {
449         if (o instanceof DiffNode) {
450             DiffNode node= (DiffNode) o;
451             
452             ITypedElement left= node.getLeft();
453             if (left instanceof BufferedResourceNode) {
454                 BufferedResourceNode bn= (BufferedResourceNode) left;
455                 if (bn.isDirty()) {
456                     IResource resource= bn.getResource();
457                     if (resource instanceof IFile)
458                         collector.add(resource);
459                 }
460             }
461
462             ITypedElement right= node.getRight();
463             if (right instanceof BufferedResourceNode) {
464                 BufferedResourceNode bn= (BufferedResourceNode) right;
465                 if (bn.isDirty()) {
466                     IResource resource= bn.getResource();
467                     if (resource instanceof IFile)
468                         collector.add(resource);
469                 }
470             }
471                 
472             IDiffElement[] children= node.getChildren();
473             if (children != null) {
474                 for (int i= 0; i < children.length; i++) {
475                     IDiffElement element= children[i];
476                     if (element instanceof DiffNode)
477                         collectDirtyResources(element, collector);
478                 }
479             }
480         }
481     }
482     
483     private static String JavaDoc normalizeCase(String JavaDoc s) {
484         if (NORMALIZE_CASE && s != null)
485             return s.toUpperCase();
486         return s;
487     }
488     
489     public boolean canRunAsJob() {
490         return true;
491     }
492 }
493
494
Popular Tags