KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > ui > synchronize > SaveableCompareEditorInput


1 /*******************************************************************************
2  * Copyright (c) 2006, 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  *******************************************************************************/

11 package org.eclipse.team.ui.synchronize;
12
13 import java.lang.reflect.InvocationTargetException JavaDoc;
14
15 import org.eclipse.compare.*;
16 import org.eclipse.compare.structuremergeviewer.*;
17 import org.eclipse.core.resources.IFile;
18 import org.eclipse.core.resources.IResource;
19 import org.eclipse.core.runtime.*;
20 import org.eclipse.jface.action.*;
21 import org.eclipse.jface.resource.ImageDescriptor;
22 import org.eclipse.jface.resource.ImageRegistry;
23 import org.eclipse.jface.text.IDocument;
24 import org.eclipse.jface.text.ITextViewer;
25 import org.eclipse.jface.util.IPropertyChangeListener;
26 import org.eclipse.jface.viewers.*;
27 import org.eclipse.osgi.util.NLS;
28 import org.eclipse.swt.events.DisposeEvent;
29 import org.eclipse.swt.events.DisposeListener;
30 import org.eclipse.swt.graphics.Image;
31 import org.eclipse.swt.widgets.*;
32 import org.eclipse.team.internal.ui.*;
33 import org.eclipse.team.internal.ui.history.CompareFileRevisionEditorInput;
34 import org.eclipse.team.internal.ui.synchronize.LocalResourceSaveableComparison;
35 import org.eclipse.team.internal.ui.synchronize.LocalResourceTypedElement;
36 import org.eclipse.team.internal.ui.synchronize.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener;
37 import org.eclipse.team.ui.mapping.SaveableComparison;
38 import org.eclipse.ui.*;
39 import org.eclipse.ui.actions.*;
40 import org.eclipse.ui.keys.IBindingService;
41 import org.eclipse.ui.services.IDisposable;
42
43 /**
44  * A compare editor input that makes use of a {@link Saveable} to manage the save
45  * lifecycle of the editor input. If the element returned from
46  * {@link #createFileElement(IFile)} is used as the left side of the compare input
47  * and the default saveable returned from {@link #createSaveable()} is used, then
48  * this compare input will provide the complete save lifecycle for the local file.
49  * <p>
50  * Clients may subclass this class.
51  * </p>
52  * @since 3.3
53  */

54 public abstract class SaveableCompareEditorInput extends CompareEditorInput implements ISaveablesSource {
55
56     private ICompareInputChangeListener compareInputChangeListener;
57     private final IWorkbenchPage page;
58     private final ListenerList inputChangeListeners = new ListenerList(ListenerList.IDENTITY);
59     private Saveable saveable;
60     private IPropertyListener propertyListener;
61     
62     /**
63      * Return a typed element that represents a local file. If the element
64      * returned from this method is used as the left contributor of the compare
65      * input for a {@link SaveableCompareEditorInput}, then the file will
66      * be properly saved when the compare editor input or viewers are saved.
67      * @param file the file
68      * @return a typed element that represents a local file.
69      */

70     public static ITypedElement createFileElement(IFile file) {
71         return new LocalResourceTypedElement(file);
72     }
73     
74     private static ITypedElement getFileElement(ICompareInput input,
75             CompareEditorInput editorInput) {
76         if (input.getLeft() instanceof LocalResourceTypedElement) {
77             return (LocalResourceTypedElement) input.getLeft();
78         }
79         if (editorInput instanceof CompareFileRevisionEditorInput) {
80             return ((CompareFileRevisionEditorInput) editorInput).getLocalElement();
81         }
82         return null;
83     }
84     
85     private class InternalResourceSaveableComparison extends LocalResourceSaveableComparison implements ISharedDocumentAdapterListener {
86         private LocalResourceTypedElement lrte;
87         private boolean connected = false;
88         public InternalResourceSaveableComparison(
89                 ICompareInput input, CompareEditorInput editorInput) {
90             super(input, editorInput, SaveableCompareEditorInput.getFileElement(input, editorInput));
91             ITypedElement element = SaveableCompareEditorInput.getFileElement(input, editorInput);
92             if (element instanceof LocalResourceTypedElement) {
93                 lrte = (LocalResourceTypedElement) element;
94                 if (lrte.isConnected()) {
95                     registerSaveable(true);
96                 } else {
97                     lrte.setSharedDocumentListener(this);
98                 }
99             }
100         }
101         protected void fireInputChange() {
102             SaveableCompareEditorInput.this.fireInputChange();
103         }
104         public void dispose() {
105             super.dispose();
106             if (lrte != null)
107                 lrte.setSharedDocumentListener(null);
108         }
109         public void handleDocumentConnected() {
110             if (connected)
111                 return;
112             connected = true;
113             registerSaveable(false);
114             if (lrte != null)
115                 lrte.setSharedDocumentListener(null);
116         }
117         
118         private void registerSaveable(boolean init) {
119             ICompareContainer container = getContainer();
120             IWorkbenchPart part = container.getWorkbenchPart();
121             if (part != null) {
122                 ISaveablesLifecycleListener lifecycleListener= getSaveablesLifecycleListener(part);
123                 // Remove this saveable from the lifecycle listener
124
if (!init)
125                     lifecycleListener.handleLifecycleEvent(
126                             new SaveablesLifecycleEvent(part, SaveablesLifecycleEvent.POST_CLOSE, new Saveable[] { this }, false));
127                 // Now fix the hashing so it uses the connected document
128
initializeHashing();
129                 // Finally, add this saveable back to the listener
130
lifecycleListener.handleLifecycleEvent(
131                         new SaveablesLifecycleEvent(part, SaveablesLifecycleEvent.POST_OPEN, new Saveable[] { this }, false));
132             }
133         }
134         public void handleDocumentDeleted() {
135             // Ignore
136
}
137         public void handleDocumentDisconnected() {
138             // Ignore
139
}
140         public void handleDocumentFlushed() {
141             // Ignore
142
}
143         public void handleDocumentSaved() {
144             // Ignore
145
}
146     }
147     
148     /**
149      * Creates a <code>LocalResourceCompareEditorInput</code> which is initialized with the given
150      * compare configuration.
151      * The compare configuration is passed to subsequently created viewers.
152      *
153      * @param configuration the compare configuration
154      * @param page the workbench page that will contain the editor
155      */

156     public SaveableCompareEditorInput(CompareConfiguration configuration, IWorkbenchPage page) {
157         super(configuration);
158         this.page = page;
159     }
160
161     /* (non-Javadoc)
162      * @see org.eclipse.compare.CompareEditorInput#contentsCreated()
163      */

164     protected void contentsCreated() {
165         super.contentsCreated();
166         compareInputChangeListener = new ICompareInputChangeListener() {
167             public void compareInputChanged(ICompareInput source) {
168                 if (source == getCompareResult()) {
169                     boolean closed = false;
170                     if (source.getKind() == Differencer.NO_CHANGE) {
171                         closed = closeEditor(true);
172                     }
173                     if (!closed) {
174                         // The editor was closed either because the compare input still has changes
175
// or because the editor input is dirty. In either case, fire the changes
176
// to the registered listeners
177
propogateInputChange();
178                     }
179                 }
180             }
181         };
182         getCompareInput().addCompareInputChangeListener(compareInputChangeListener);
183         
184         if (getSaveable() instanceof SaveableComparison) {
185             SaveableComparison scm = (SaveableComparison) saveable;
186             propertyListener = new IPropertyListener() {
187                 public void propertyChanged(Object JavaDoc source, int propId) {
188                     if (propId == SaveableComparison.PROP_DIRTY) {
189                         setDirty(saveable.isDirty());
190                     }
191                 }
192             };
193             scm.addPropertyListener(propertyListener);
194         }
195         setDirty(saveable.isDirty());
196     }
197
198     private ISaveablesLifecycleListener getSaveablesLifecycleListener(
199             IWorkbenchPart part) {
200         ISaveablesLifecycleListener listener = (ISaveablesLifecycleListener)Utils.getAdapter(part, ISaveablesLifecycleListener.class);
201         if (listener == null)
202             listener = (ISaveablesLifecycleListener) part.getSite().getService(ISaveablesLifecycleListener.class);
203         return listener;
204     }
205     
206     /* (non-Javadoc)
207      * @see org.eclipse.compare.CompareEditorInput#handleDispose()
208      */

209     protected void handleDispose() {
210         super.handleDispose();
211         ICompareInput compareInput = getCompareInput();
212         if (compareInput != null)
213             compareInput.removeCompareInputChangeListener(compareInputChangeListener);
214         if (saveable instanceof SaveableComparison) {
215             SaveableComparison scm = (SaveableComparison) saveable;
216             scm.removePropertyListener(propertyListener);
217         }
218         if (saveable instanceof LocalResourceSaveableComparison) {
219             LocalResourceSaveableComparison rsc = (LocalResourceSaveableComparison) saveable;
220             rsc.dispose();
221         }
222         if (getCompareResult() instanceof IDisposable) {
223             ((IDisposable) getCompareResult()).dispose();
224         }
225     }
226     
227     /**
228      * Prepare the compare input of this editor input. This method is not intended to be overridden of
229      * extended by subclasses (but is not final for backwards compatibility reasons).
230      * The implementation of this method in this class
231      * delegates the creation of the compare input to the {@link #prepareCompareInput(IProgressMonitor)}
232      * method which subclasses must implement.
233      * @see org.eclipse.compare.CompareEditorInput#prepareInput(org.eclipse.core.runtime.IProgressMonitor)
234      */

235     protected Object JavaDoc prepareInput(IProgressMonitor monitor)
236             throws InvocationTargetException JavaDoc, InterruptedException JavaDoc {
237         final ICompareInput input = prepareCompareInput(monitor);
238         if (input != null)
239             setTitle(NLS.bind(TeamUIMessages.SyncInfoCompareInput_title, new String JavaDoc[] { input.getName()}));
240         return input;
241     }
242
243     /**
244      * Method called from {@link #prepareInput(IProgressMonitor)} to obtain the input.
245      * It's purpose is to ensure that the input is an instance of {@link ICompareInput}.
246      * @param monitor a progress monitor
247      * @return the compare input
248      * @throws InvocationTargetException
249      * @throws InterruptedException
250      */

251     protected abstract ICompareInput prepareCompareInput(IProgressMonitor monitor)
252         throws InvocationTargetException JavaDoc, InterruptedException JavaDoc;
253     
254     /**
255      * Return the compare input of this editor input.
256      * @return the compare input of this editor input
257      */

258     protected final ICompareInput getCompareInput() {
259         return (ICompareInput)getCompareResult();
260     }
261     
262     /**
263      * Callback from the resource saveable that is invoked when the resource is
264      * saved so that this input can fire a change event for its input. Subclasses
265      * only need this method if the left side of their compare input is
266      * an element returned from {@link #createFileElement(IFile)}.
267      */

268     protected abstract void fireInputChange();
269     
270     /**
271      * Close the editor if it is not dirty. If it is still dirty, let the
272      * content merge viewer handle the compare input change.
273      * @param checkForUnsavedChanges whether to check for unsaved changes
274      * @return <code>true</code> if the editor was closed (note that the
275      * close may be asynchronous)
276      */

277     protected boolean closeEditor(boolean checkForUnsavedChanges) {
278         if (isSaveNeeded() && checkForUnsavedChanges) {
279             return false;
280         } else {
281             Runnable JavaDoc runnable = new Runnable JavaDoc() {
282                 public void run() {
283                     IEditorPart part = getPage().findEditor(SaveableCompareEditorInput.this);
284                     getPage().closeEditor(part, false);
285                 }
286             };
287             if (Display.getCurrent() != null) {
288                 runnable.run();
289             } else {
290                 Display display = getPage().getWorkbenchWindow().getShell().getDisplay();
291                 display.asyncExec(runnable);
292             }
293             return true;
294         }
295     }
296     
297     private IWorkbenchPage getPage() {
298         if (page == null)
299             return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
300         return page;
301     }
302     
303     /* package */ void propogateInputChange() {
304         if (!inputChangeListeners.isEmpty()) {
305             Object JavaDoc[] allListeners = inputChangeListeners.getListeners();
306             for (int i = 0; i < allListeners.length; i++) {
307                 final ICompareInputChangeListener listener = (ICompareInputChangeListener)allListeners[i];
308                 SafeRunner.run(new ISafeRunnable() {
309                     public void run() throws Exception JavaDoc {
310                         listener.compareInputChanged((ICompareInput)SaveableCompareEditorInput.this.getCompareResult());
311                     }
312                     public void handleException(Throwable JavaDoc exception) {
313                         // Logged by the safe runner
314
}
315                 });
316             }
317         }
318     }
319
320     /**
321      * Get the saveable that provides the save behavior for this compare editor input.
322      * The {@link #createSaveable()} is called to create the saveable if it does not yet exist.
323      * This method cannot be called until after the input is prepared (i.e. until after
324      * the {@link #run(IProgressMonitor)} method is called which will in turn will invoke
325      * {@link #prepareCompareInput(IProgressMonitor)}.
326      * @return saveable that provides the save behavior for this compare editor input.
327      */

328     protected Saveable getSaveable() {
329         if (saveable == null) {
330             saveable = createSaveable();
331         }
332         return saveable;
333     }
334     
335     /**
336      * Create the saveable that provides the save behavior for this compare editor input.
337      * By default, a saveable that handles local files is returned
338      * @return the saveable that provides the save behavior for this compare editor input
339      */

340     protected Saveable createSaveable() {
341         Object JavaDoc compareResult = getCompareResult();
342         Assert.isNotNull(compareResult, "This method cannot be called until after prepareInput is called"); //$NON-NLS-1$
343
return new InternalResourceSaveableComparison((ICompareInput)compareResult, this);
344     }
345
346     /* (non-Javadoc)
347      * @see org.eclipse.ui.ISaveablesSource#getActiveSaveables()
348      */

349     public Saveable[] getActiveSaveables() {
350         if (getCompareResult() == null)
351             return new Saveable[0];
352         return new Saveable[] { getSaveable() };
353     }
354
355     /* (non-Javadoc)
356      * @see org.eclipse.ui.ISaveablesSource#getSaveables()
357      */

358     public Saveable[] getSaveables() {
359         return getActiveSaveables();
360     }
361     
362     /* (non-Javadoc)
363      * @see org.eclipse.compare.CompareEditorInput#addCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
364      */

365     public void addCompareInputChangeListener(ICompareInput input,
366             ICompareInputChangeListener listener) {
367         if (input == getCompareResult()) {
368             inputChangeListeners.add(listener);
369         } else {
370             super.addCompareInputChangeListener(input, listener);
371         }
372     }
373     
374     /* (non-Javadoc)
375      * @see org.eclipse.compare.CompareEditorInput#removeCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
376      */

377     public void removeCompareInputChangeListener(ICompareInput input,
378             ICompareInputChangeListener listener) {
379         if (input == getCompareResult()) {
380             inputChangeListeners.remove(listener);
381         } else {
382             super.removeCompareInputChangeListener(input, listener);
383         }
384     }
385     
386     /* (non-Javadoc)
387      * @see org.eclipse.compare.CompareEditorInput#getAdapter(java.lang.Class)
388      */

389     public Object JavaDoc getAdapter(Class JavaDoc adapter) {
390         if (IFile.class.equals(adapter)) {
391             IResource resource = Utils.getResource(getCompareResult());
392             if (resource instanceof IFile) {
393                 return resource;
394             }
395         }
396         return super.getAdapter(adapter);
397     }
398     
399     /*
400      * (non-Javadoc)
401      * @see org.eclipse.compare.CompareEditorInput#getTitleImage()
402      */

403     public Image getTitleImage() {
404         ImageRegistry reg = TeamUIPlugin.getPlugin().getImageRegistry();
405         Image image = reg.get(ITeamUIImages.IMG_SYNC_VIEW);
406         if (image == null) {
407             image = getImageDescriptor().createImage();
408             reg.put(ITeamUIImages.IMG_SYNC_VIEW, image);
409         }
410         return image;
411     }
412
413     /*
414      * (non-Javadoc)
415      * @see org.eclipse.ui.IEditorInput#getImageDescriptor()
416      */

417     public ImageDescriptor getImageDescriptor() {
418         return TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_SYNC_VIEW);
419     }
420     
421     /* (non-Javadoc)
422      * @see org.eclipse.compare.CompareEditorInput#findContentViewer(org.eclipse.jface.viewers.Viewer, org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.swt.widgets.Composite)
423      */

424     public Viewer findContentViewer(Viewer oldViewer, ICompareInput input, Composite parent) {
425         Viewer newViewer = super.findContentViewer(oldViewer, input, parent);
426         boolean isNewViewer= newViewer != oldViewer;
427         if (isNewViewer && newViewer instanceof IPropertyChangeNotifier && saveable instanceof IPropertyChangeListener) {
428             // Register the model for change events if appropriate
429
final IPropertyChangeNotifier dsp= (IPropertyChangeNotifier) newViewer;
430             final IPropertyChangeListener pcl = (IPropertyChangeListener) saveable;
431             dsp.addPropertyChangeListener(pcl);
432             Control c= newViewer.getControl();
433             c.addDisposeListener(
434                 new DisposeListener() {
435                     public void widgetDisposed(DisposeEvent e) {
436                         dsp.removePropertyChangeListener(pcl);
437                     }
438                 }
439             );
440         }
441         return newViewer;
442     }
443
444     /* (non-Javadoc)
445      * @see org.eclipse.compare.CompareEditorInput#canRunAsJob()
446      */

447     public boolean canRunAsJob() {
448         return true;
449     }
450     
451     public boolean isDirty() {
452         if (saveable != null)
453             return saveable.isDirty();
454         return super.isDirty();
455     }
456     
457     public void registerContextMenu(final MenuManager menu,
458             final ISelectionProvider selectionProvider) {
459         super.registerContextMenu(menu, selectionProvider);
460         final Saveable saveable = getSaveable();
461         if (saveable instanceof LocalResourceSaveableComparison) {
462             menu.addMenuListener(new IMenuListener() {
463                 public void menuAboutToShow(IMenuManager manager) {
464                     handleMenuAboutToShow(manager, saveable, selectionProvider);
465                 }
466             });
467         }
468     }
469     
470     /* package */ void handleMenuAboutToShow (IMenuManager manager, Saveable saveable, ISelectionProvider provider) {
471         if (provider instanceof ITextViewer) {
472             ITextViewer v = (ITextViewer) provider;
473             IDocument d = v.getDocument();
474             IDocument other = (IDocument)Utils.getAdapter(saveable, IDocument.class);
475             if (d == other) {
476                 ITypedElement element = getFileElement(getCompareInput(), this);
477                 if (element instanceof IResourceProvider) {
478                     IResourceProvider rp = (IResourceProvider) element;
479                     IResource resource = rp.getResource();
480                     StructuredSelection selection = new StructuredSelection(resource);
481                     IWorkbenchPart workbenchPart = getContainer().getWorkbenchPart();
482                     if (workbenchPart != null) {
483                         IWorkbenchSite ws = workbenchPart.getSite();
484                         
485                         MenuManager submenu1 =
486                             new MenuManager(getShowInMenuLabel());
487                         IContributionItem showInMenu = ContributionItemFactory.VIEWS_SHOW_IN.create(ws.getWorkbenchWindow());
488                         submenu1.add(showInMenu);
489                         manager.insertAfter("file", submenu1); //$NON-NLS-1$
490
MenuManager submenu2 =
491                             new MenuManager(TeamUIMessages.OpenWithActionGroup_0);
492                         submenu2.add(new OpenWithMenu(ws.getPage(), resource));
493                         manager.insertAfter("file", submenu2); //$NON-NLS-1$
494

495                         OpenFileAction openFileAction = new OpenFileAction(ws.getPage());
496                         openFileAction.selectionChanged(selection);
497                         manager.insertAfter("file", openFileAction); //$NON-NLS-1$
498
}
499                 }
500             }
501         }
502     }
503     
504     private String JavaDoc getShowInMenuLabel() {
505         String JavaDoc keyBinding= null;
506         
507         IBindingService bindingService= (IBindingService)PlatformUI.getWorkbench().getAdapter(IBindingService.class);
508         if (bindingService != null)
509             keyBinding= bindingService.getBestActiveBindingFormattedFor("org.eclipse.ui.navigate.showInQuickMenu"); //$NON-NLS-1$
510

511         if (keyBinding == null)
512             keyBinding= ""; //$NON-NLS-1$
513

514         return NLS.bind(TeamUIMessages.SaveableCompareEditorInput_0, keyBinding);
515     }
516
517 }
518
Popular Tags