KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > pde > internal > ui > editor > context > InputContext


1 /*******************************************************************************
2  * Copyright (c) 2003, 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.pde.internal.ui.editor.context;
12 import java.lang.reflect.InvocationTargetException JavaDoc;
13 import java.util.ArrayList JavaDoc;
14
15 import org.eclipse.core.filebuffers.IDocumentSetupParticipant;
16 import org.eclipse.core.resources.IFile;
17 import org.eclipse.core.resources.IResource;
18 import org.eclipse.core.resources.IWorkspace;
19 import org.eclipse.core.resources.ResourcesPlugin;
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.core.runtime.IPath;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.jface.dialogs.ErrorDialog;
25 import org.eclipse.jface.dialogs.IMessageProvider;
26 import org.eclipse.jface.text.BadLocationException;
27 import org.eclipse.jface.text.IDocument;
28 import org.eclipse.jface.text.TextUtilities;
29 import org.eclipse.jface.text.source.IAnnotationModel;
30 import org.eclipse.jface.window.Window;
31 import org.eclipse.osgi.util.NLS;
32 import org.eclipse.pde.core.IBaseModel;
33 import org.eclipse.pde.core.IEditable;
34 import org.eclipse.pde.core.IModelChangeProvider;
35 import org.eclipse.pde.core.IModelChangedEvent;
36 import org.eclipse.pde.core.IModelChangedListener;
37 import org.eclipse.pde.internal.core.text.IEditingModel;
38 import org.eclipse.pde.internal.core.util.PropertiesUtil;
39 import org.eclipse.pde.internal.ui.PDEPlugin;
40 import org.eclipse.pde.internal.ui.PDEUIMessages;
41 import org.eclipse.pde.internal.ui.editor.PDEFormEditor;
42 import org.eclipse.pde.internal.ui.editor.PDEStorageDocumentProvider;
43 import org.eclipse.swt.widgets.Shell;
44 import org.eclipse.text.edits.InsertEdit;
45 import org.eclipse.text.edits.MalformedTreeException;
46 import org.eclipse.text.edits.MoveSourceEdit;
47 import org.eclipse.text.edits.MultiTextEdit;
48 import org.eclipse.text.edits.TextEdit;
49 import org.eclipse.ui.IEditorInput;
50 import org.eclipse.ui.IFileEditorInput;
51 import org.eclipse.ui.PlatformUI;
52 import org.eclipse.ui.actions.WorkspaceModifyOperation;
53 import org.eclipse.ui.dialogs.SaveAsDialog;
54 import org.eclipse.ui.editors.text.ForwardingDocumentProvider;
55 import org.eclipse.ui.part.FileEditorInput;
56 import org.eclipse.ui.texteditor.IDocumentProvider;
57 import org.eclipse.ui.texteditor.IElementStateListener;
58 /**
59  * This class maintains objects associated with a single editor input.
60  */

61 public abstract class InputContext {
62     
63     private PDEFormEditor fEditor;
64     private IEditorInput fEditorInput;
65     private IBaseModel fModel;
66     private IModelChangedListener fModelListener;
67     private IDocumentProvider fDocumentProvider;
68     private IElementStateListener fElementListener;
69     protected ArrayList JavaDoc fEditOperations = new ArrayList JavaDoc();
70     
71     private boolean fValidated;
72     private boolean fPrimary;
73     private boolean fIsSourceMode;
74     private boolean fMustSynchronize;
75
76     class ElementListener implements IElementStateListener {
77         public void elementContentAboutToBeReplaced(Object JavaDoc element) {
78         }
79         public void elementContentReplaced(Object JavaDoc element) {
80             doRevert();
81         }
82         public void elementDeleted(Object JavaDoc element) {
83             dispose();
84         }
85         public void elementDirtyStateChanged(Object JavaDoc element, boolean isDirty) {
86             fMustSynchronize=true;
87         }
88         public void elementMoved(Object JavaDoc originalElement, Object JavaDoc movedElement) {
89             dispose();
90             fEditor.close(true);
91         }
92     }
93     public InputContext(PDEFormEditor editor, IEditorInput input, boolean primary) {
94         this.fEditor = editor;
95         this.fEditorInput = input;
96         setPrimary(primary);
97     }
98     public abstract String JavaDoc getId();
99
100     public IEditorInput getInput() {
101         return fEditorInput;
102     }
103     public PDEFormEditor getEditor() {
104         return fEditor;
105     }
106     public IBaseModel getModel() {
107         return fModel;
108     }
109     public IDocumentProvider getDocumentProvider() {
110         return fDocumentProvider;
111     }
112     
113     private IDocumentProvider createDocumentProvider(IEditorInput input) {
114         if (input instanceof IFileEditorInput) {
115             return new ForwardingDocumentProvider(
116                                 getPartitionName(),
117                                 getDocumentSetupParticipant(),
118                                 PDEPlugin.getDefault().getTextFileDocumentProvider());
119         }
120         return new PDEStorageDocumentProvider(getDocumentSetupParticipant());
121     }
122     
123     protected IDocumentSetupParticipant getDocumentSetupParticipant() {
124         return new IDocumentSetupParticipant() {
125             public void setup(IDocument document) {
126             }
127         };
128     }
129     
130     protected abstract String JavaDoc getPartitionName();
131         
132     protected abstract String JavaDoc getDefaultCharset();
133     
134     protected abstract IBaseModel createModel(IEditorInput input) throws CoreException;
135     
136     protected void create() {
137         fDocumentProvider = createDocumentProvider(fEditorInput);
138         try {
139             fDocumentProvider.connect(fEditorInput);
140             fModel = createModel(fEditorInput);
141             if (fModel instanceof IModelChangeProvider) {
142                 fModelListener = new IModelChangedListener() {
143                     public void modelChanged(IModelChangedEvent e) {
144                         if (e.getChangeType() != IModelChangedEvent.WORLD_CHANGED) {
145                             if (!fEditor.getLastDirtyState())
146                                 fEditor.fireSaveNeeded(fEditorInput, true);
147                             IModelChangeProvider provider = e.getChangeProvider();
148                             if (provider instanceof IEditingModel) {
149                                 // this is to guard against false notifications
150
// when a revert operation is performed, focus is taken away from a FormEntry
151
// and a text edit operation is falsely requested
152
if (((IEditingModel)provider).isDirty())
153                                     addTextEditOperation(fEditOperations, e);
154                             }
155                         }
156                     }
157                 };
158                 ((IModelChangeProvider) fModel).addModelChangedListener(fModelListener);
159             }
160
161             IAnnotationModel amodel = fDocumentProvider
162                     .getAnnotationModel(fEditorInput);
163             if (amodel != null)
164                 amodel.connect(fDocumentProvider.getDocument(fEditorInput));
165             fElementListener = new ElementListener();
166             fDocumentProvider.addElementStateListener(fElementListener);
167         } catch (CoreException e) {
168             PDEPlugin.logException(e);
169         }
170         
171     }
172     
173     public synchronized boolean validateEdit() {
174         if (!fValidated) {
175             if (fEditorInput instanceof IFileEditorInput) {
176                 IFile file = ((IFileEditorInput) fEditorInput).getFile();
177                 if (file.isReadOnly()) {
178                     Shell shell = fEditor.getEditorSite().getShell();
179                     IStatus validateStatus = PDEPlugin.getWorkspace().validateEdit(
180                         new IFile[]{file}, shell);
181                     fValidated=true; // to prevent loops
182
if (validateStatus.getSeverity() != IStatus.OK)
183                         ErrorDialog.openError(shell, fEditor.getTitle(), null,
184                             validateStatus);
185                     return validateStatus.getSeverity() == IStatus.OK;
186                 }
187             }
188         }
189         return true;
190     }
191     public void doSave(IProgressMonitor monitor) {
192         try {
193             IDocument doc = fDocumentProvider.getDocument(fEditorInput);
194             fDocumentProvider.aboutToChange(fEditorInput);
195             flushModel(doc);
196             fDocumentProvider.saveDocument(monitor, fEditorInput, doc, true);
197             fDocumentProvider.changed(fEditorInput);
198             fValidated=false;
199         }
200         catch (CoreException e) {
201             PDEPlugin.logException(e);
202         }
203     }
204     
205     protected abstract void addTextEditOperation(ArrayList JavaDoc ops, IModelChangedEvent event);
206     
207     public void flushEditorInput() {
208         if (fEditOperations.size() > 0) {
209             IDocument doc = fDocumentProvider.getDocument(fEditorInput);
210             fDocumentProvider.aboutToChange(fEditorInput);
211             flushModel(doc);
212             fDocumentProvider.changed(fEditorInput);
213             fValidated=false;
214         }
215     }
216     
217     protected void flushModel(IDocument doc) {
218         boolean flushed = true;
219         if (fEditOperations.size() > 0) {
220             try {
221                 MultiTextEdit edit = new MultiTextEdit();
222                 if (isNewlineNeeded(doc))
223                     insert(edit, new InsertEdit(doc.getLength(), TextUtilities.getDefaultLineDelimiter(doc)));
224                 for (int i = 0; i < fEditOperations.size(); i++) {
225                     insert(edit, (TextEdit)fEditOperations.get(i));
226                 }
227                 if (fModel instanceof IEditingModel)
228                     ((IEditingModel)fModel).setStale(true);
229                 edit.apply(doc);
230                 fEditOperations.clear();
231             } catch (MalformedTreeException e) {
232                 PDEPlugin.logException(e);
233                 flushed = false;
234             } catch (BadLocationException e) {
235                 PDEPlugin.logException(e);
236                 flushed = false;
237             }
238         }
239         // If no errors were encountered flushing the model, then undirty the
240
// model. This needs to be done regardless of whether there are any
241
// edit operations or not; since, the contributed actions need to be
242
// updated and the editor needs to be undirtied
243
if (flushed &&
244                 (fModel instanceof IEditable)) {
245             ((IEditable)fModel).setDirty(false);
246         }
247     }
248     
249     protected boolean isNewlineNeeded(IDocument doc) throws BadLocationException {
250         return PropertiesUtil.isNewlineNeeded(doc);
251     }
252     
253     protected static void insert(TextEdit parent, TextEdit edit) {
254         if (!parent.hasChildren()) {
255             parent.addChild(edit);
256             if (edit instanceof MoveSourceEdit) {
257                 parent.addChild(((MoveSourceEdit)edit).getTargetEdit());
258             }
259             return;
260         }
261         TextEdit[] children= parent.getChildren();
262         // First dive down to find the right parent.
263
for (int i= 0; i < children.length; i++) {
264             TextEdit child= children[i];
265             if (covers(child, edit)) {
266                 insert(child, edit);
267                 return;
268             }
269         }
270         // We have the right parent. Now check if some of the children have to
271
// be moved under the new edit since it is covering it.
272
for (int i= children.length - 1; i >= 0; i--) {
273             TextEdit child= children[i];
274             if (covers(edit, child)) {
275                 parent.removeChild(i);
276                 edit.addChild(child);
277             }
278         }
279         parent.addChild(edit);
280         if (edit instanceof MoveSourceEdit) {
281             parent.addChild(((MoveSourceEdit)edit).getTargetEdit());
282         }
283     }
284     
285     protected static boolean covers(TextEdit thisEdit, TextEdit otherEdit) {
286         if (thisEdit.getLength() == 0) // an insertion point can't cover anything
287
return false;
288         
289         int thisOffset= thisEdit.getOffset();
290         int thisEnd= thisEdit.getExclusiveEnd();
291         if (otherEdit.getLength() == 0) {
292             int otherOffset= otherEdit.getOffset();
293             return thisOffset < otherOffset && otherOffset < thisEnd;
294         }
295         int otherOffset= otherEdit.getOffset();
296         int otherEnd= otherEdit.getExclusiveEnd();
297         return thisOffset <= otherOffset && otherEnd <= thisEnd;
298     }
299
300     public boolean mustSave() {
301         if (!fIsSourceMode) {
302             if (fModel instanceof IEditable) {
303                 if (((IEditable)fModel).isDirty()) {
304                     return true;
305                 }
306             }
307         }
308         return fEditOperations.size() > 0 || fDocumentProvider.canSaveDocument(fEditorInput);
309     }
310     
311     public void dispose() {
312         IAnnotationModel amodel = fDocumentProvider.getAnnotationModel(fEditorInput);
313         if (amodel != null)
314             amodel.disconnect(fDocumentProvider.getDocument(fEditorInput));
315         fDocumentProvider.removeElementStateListener(fElementListener);
316         fDocumentProvider.disconnect(fEditorInput);
317         if (fModelListener != null && fModel instanceof IModelChangeProvider) {
318             ((IModelChangeProvider) fModel)
319                     .removeModelChangedListener(fModelListener);
320             //if (undoManager != null)
321
//undoManager.disconnect((IModelChangeProvider) model);
322
}
323         if (fModel!=null)
324             fModel.dispose();
325     }
326     /**
327      * @return Returns the primary.
328      */

329     public boolean isPrimary() {
330         return fPrimary;
331     }
332     /**
333      * @param primary The primary to set.
334      */

335     public void setPrimary(boolean primary) {
336         this.fPrimary = primary;
337     }
338     
339     public boolean setSourceEditingMode(boolean sourceMode) {
340         fIsSourceMode = sourceMode;
341         if (sourceMode) {
342             // entered source editing mode; in this mode,
343
// this context's document will be edited directly
344
// in the source editor. All changes in the model
345
// are caused by reconciliation and should not be
346
// fired to the world.
347
flushModel(fDocumentProvider.getDocument(fEditorInput));
348             fMustSynchronize=true;
349             return true;
350         }
351         // leaving source editing mode; if the document
352
// has been modified while in this mode,
353
// fire the 'world changed' event from the model
354
// to cause all the model listeners to become stale.
355
return synchronizeModelIfNeeded();
356     }
357     
358     private boolean synchronizeModelIfNeeded() {
359         if (fMustSynchronize) {
360             boolean result = synchronizeModel(fDocumentProvider.getDocument(fEditorInput));
361             fMustSynchronize=false;
362             return result;
363         }
364         return true;
365     }
366
367     public void doRevert() {
368         fMustSynchronize=true;
369         synchronizeModelIfNeeded();
370         /*
371         if (model instanceof IEditable) {
372             ((IEditable)model).setDirty(false);
373         }
374         */

375     }
376
377     public boolean isInSourceMode() {
378         return fIsSourceMode;
379     }
380
381     public boolean isModelCorrect() {
382         synchronizeModelIfNeeded();
383         return fModel!=null ? fModel.isValid() : false;
384     }
385     
386     protected boolean synchronizeModel(IDocument doc) {
387         return true;
388     }
389     public boolean matches(IResource resource) {
390         if (fEditorInput instanceof IFileEditorInput) {
391             IFileEditorInput finput = (IFileEditorInput)fEditorInput;
392             IFile file = finput.getFile();
393             if (file.equals(resource))
394                 return true;
395         }
396         return false;
397     }
398     /**
399      * @return Returns the validated.
400      */

401     public boolean isValidated() {
402         return fValidated;
403     }
404     /**
405      * @param validated The validated to set.
406      */

407     public void setValidated(boolean validated) {
408         this.fValidated = validated;
409     }
410     
411     public String JavaDoc getLineDelimiter() {
412         if (fDocumentProvider != null) {
413             IDocument document = fDocumentProvider.getDocument(fEditorInput);
414             if (document != null) {
415                 return TextUtilities.getDefaultLineDelimiter(document);
416             }
417         }
418         return System.getProperty("line.separator"); //$NON-NLS-1$
419
}
420     
421     /**
422      * @param input
423      * @throws CoreException
424      */

425     private void updateInput(IEditorInput newInput) throws CoreException {
426         deinitializeDocumentProvider();
427         fEditorInput = newInput;
428         initializeDocumentProvider();
429     }
430
431     /**
432      *
433      */

434     private void deinitializeDocumentProvider() {
435         IAnnotationModel amodel =
436             fDocumentProvider.getAnnotationModel(fEditorInput);
437         if (amodel != null) {
438             amodel.disconnect(fDocumentProvider.getDocument(fEditorInput));
439         }
440         fDocumentProvider.removeElementStateListener(fElementListener);
441         fDocumentProvider.disconnect(fEditorInput);
442     }
443
444     /**
445      * @throws CoreException
446      */

447     private void initializeDocumentProvider() throws CoreException {
448         fDocumentProvider.connect(fEditorInput);
449         IAnnotationModel amodel = fDocumentProvider.getAnnotationModel(fEditorInput);
450         if (amodel != null) {
451             amodel.connect(fDocumentProvider.getDocument(fEditorInput));
452         }
453         fDocumentProvider.addElementStateListener(fElementListener);
454     }
455     
456     /**
457      * @param monitor
458      */

459     public void doSaveAs(IProgressMonitor monitor) throws Exception JavaDoc {
460         // Get the editor shell
461
Shell shell = getEditor().getSite().getShell();
462         // Create the save as dialog
463
SaveAsDialog dialog = new SaveAsDialog(shell);
464         // Set the initial file name to the original file name
465
IFile file = null;
466         if (fEditorInput instanceof IFileEditorInput) {
467             file = ((IFileEditorInput) fEditorInput).getFile();
468             dialog.setOriginalFile(file);
469         }
470         // Create the dialog
471
dialog.create();
472         // Warn the user if the underlying file does not exist
473
if (fDocumentProvider.isDeleted(fEditorInput) &&
474                 (file != null)) {
475             String JavaDoc message = NLS.bind(PDEUIMessages.InputContext_errorMessageFileDoesNotExist, file.getName());
476             dialog.setErrorMessage(null);
477             dialog.setMessage(message, IMessageProvider.WARNING);
478         }
479         // Open the dialog
480
if (dialog.open() == Window.OK) {
481             // Get the path to where the new file will be stored
482
IPath path = dialog.getResult();
483             handleSaveAs(monitor, path);
484         }
485     }
486     
487     /**
488      * @param monitor
489      * @param path
490      * @throws Exception
491      * @throws CoreException
492      * @throws InterruptedException
493      * @throws InvocationTargetException
494      */

495     private void handleSaveAs(IProgressMonitor monitor, IPath path)
496             throws Exception JavaDoc, CoreException, InterruptedException JavaDoc,
497             InvocationTargetException JavaDoc {
498         // Ensure a new location was selected
499
if (path == null) {
500             monitor.setCanceled(true);
501             throw new Exception JavaDoc(PDEUIMessages.InputContext_errorMessageLocationNotSet);
502         }
503         // Resolve the new file location
504
IWorkspace workspace = ResourcesPlugin.getWorkspace();
505         IFile newFile = workspace.getRoot().getFile(path);
506         // Create the new editor input
507
final IEditorInput newInput = new FileEditorInput(newFile);
508         // Send notice of editor input changes
509
fDocumentProvider.aboutToChange(newInput);
510         // Flush any unsaved changes
511
flushModel(fDocumentProvider.getDocument(fEditorInput));
512         try {
513             // Execute the workspace modification in a separate thread
514
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(
515                     createWorkspaceModifyOperation(newInput));
516             monitor.setCanceled(false);
517             // Store the new editor input in this context
518
updateInput(newInput);
519         } catch (InterruptedException JavaDoc e) {
520             monitor.setCanceled(true);
521             throw e;
522         } catch (InvocationTargetException JavaDoc e) {
523             monitor.setCanceled(true);
524             throw e;
525         } finally {
526             fDocumentProvider.changed(newInput);
527         }
528     }
529     
530     /**
531      * @param newInput
532      * @return
533      */

534     private WorkspaceModifyOperation createWorkspaceModifyOperation(
535             final IEditorInput newInput) {
536         WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
537             public void execute(final IProgressMonitor monitor) throws CoreException {
538                 // Save the old editor input content to the new editor input
539
// location
540
fDocumentProvider.saveDocument(
541                         monitor,
542                         // New editor input location
543
newInput,
544                         // Old editor input content
545
fDocumentProvider.getDocument(fEditorInput),
546                         true);
547             }
548         };
549         return operation;
550     }
551     
552 }
553
Popular Tags