001: /*******************************************************************************
002: * Copyright (c) 2003, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.ui.editor.context;
011:
012: import java.util.ArrayList;
013: import java.util.Enumeration;
014: import java.util.Hashtable;
015:
016: import org.eclipse.core.resources.IFile;
017: import org.eclipse.core.resources.IProject;
018: import org.eclipse.core.resources.IResource;
019: import org.eclipse.core.resources.IResourceChangeEvent;
020: import org.eclipse.core.resources.IResourceChangeListener;
021: import org.eclipse.core.resources.IResourceDelta;
022: import org.eclipse.core.resources.IResourceDeltaVisitor;
023: import org.eclipse.core.runtime.CoreException;
024: import org.eclipse.core.runtime.IProgressMonitor;
025: import org.eclipse.pde.core.IBaseModel;
026: import org.eclipse.pde.core.IModelChangeProvider;
027: import org.eclipse.pde.internal.ui.PDEPlugin;
028: import org.eclipse.pde.internal.ui.PDEUIMessages;
029: import org.eclipse.pde.internal.ui.editor.IModelUndoManager;
030: import org.eclipse.pde.internal.ui.editor.PDEFormEditor;
031: import org.eclipse.swt.widgets.Display;
032: import org.eclipse.swt.widgets.Shell;
033: import org.eclipse.ui.IEditorInput;
034: import org.eclipse.ui.IFileEditorInput;
035:
036: public abstract class InputContextManager implements
037: IResourceChangeListener {
038: private PDEFormEditor editor;
039: private Hashtable inputContexts;
040: private ArrayList monitoredFiles;
041: private ArrayList listeners;
042: private IModelUndoManager undoManager;
043:
044: /**
045: *
046: */
047: public InputContextManager(PDEFormEditor editor) {
048: this .editor = editor;
049: inputContexts = new Hashtable();
050: listeners = new ArrayList();
051: PDEPlugin.getWorkspace().addResourceChangeListener(this ,
052: IResourceChangeEvent.POST_CHANGE);
053: }
054:
055: public void addInputContextListener(IInputContextListener listener) {
056: if (!listeners.contains(listener))
057: listeners.add(listener);
058: }
059:
060: public void removeInputContextListener(
061: IInputContextListener listener) {
062: listeners.remove(listener);
063: }
064:
065: /**
066: *
067: *
068: */
069: public void dispose() {
070: PDEPlugin.getWorkspace().removeResourceChangeListener(this );
071: // dispose input contexts
072: for (Enumeration contexts = inputContexts.elements(); contexts
073: .hasMoreElements();) {
074: InputContext context = (InputContext) contexts
075: .nextElement();
076: unhookUndo(context);
077: context.dispose();
078: }
079: inputContexts.clear();
080: undoManager = null;
081: }
082:
083: /**
084: * Saves dirty contexts.
085: * @param monitor
086: */
087: public void save(IProgressMonitor monitor) {
088: for (Enumeration contexts = inputContexts.elements(); contexts
089: .hasMoreElements();) {
090: InputContext context = (InputContext) contexts
091: .nextElement();
092: if (context.mustSave())
093: context.doSave(monitor);
094: }
095: }
096:
097: public IProject getCommonProject() {
098: for (Enumeration contexts = inputContexts.elements(); contexts
099: .hasMoreElements();) {
100: InputContext context = (InputContext) contexts
101: .nextElement();
102: IEditorInput input = context.getInput();
103: if (input instanceof IFileEditorInput)
104: return ((IFileEditorInput) input).getFile()
105: .getProject();
106: }
107: return null;
108: }
109:
110: public boolean hasContext(String id) {
111: return findContext(id) != null;
112: }
113:
114: public InputContext findContext(String id) {
115: for (Enumeration contexts = inputContexts.elements(); contexts
116: .hasMoreElements();) {
117: InputContext context = (InputContext) contexts
118: .nextElement();
119: if (context.getId().equals(id))
120: return context;
121: }
122: return null;
123: }
124:
125: public InputContext findContext(IResource resource) {
126: for (Enumeration contexts = inputContexts.elements(); contexts
127: .hasMoreElements();) {
128: InputContext context = (InputContext) contexts
129: .nextElement();
130: if (context.matches(resource))
131: return context;
132: }
133: return null;
134: }
135:
136: public abstract IBaseModel getAggregateModel();
137:
138: public InputContext getContext(IEditorInput input) {
139: return (InputContext) inputContexts.get(input);
140: }
141:
142: public void putContext(IEditorInput input, InputContext context) {
143: inputContexts.put(input, context);
144: fireContextChange(context, true);
145: }
146:
147: /**
148: * Update the key (the editor input in this case) associated with the
149: * input context without firing a context change event.
150: * Used for save as operations.
151: * @param newInput
152: * @param oldInput
153: * @throws Exception
154: */
155: private void updateInputContext(IEditorInput newInput,
156: IEditorInput oldInput) throws Exception {
157: Object value = null;
158: // Retrieve the input context referenced by the old editor input and
159: // remove it from the context manager
160: if (inputContexts.containsKey(oldInput)) {
161: value = inputContexts.remove(oldInput);
162: } else {
163: throw new Exception(
164: PDEUIMessages.InputContextManager_errorMessageInputContextNotFound);
165: }
166: // Re-insert the input context back into the context manager using the
167: // new editor input as its key
168: inputContexts.put(newInput, value);
169: }
170:
171: /**
172: * @param monitor
173: * @param contextID
174: * @throws Exception
175: */
176: public void saveAs(IProgressMonitor monitor, String contextID)
177: throws Exception {
178: // Find the existing context
179: InputContext inputContext = findContext(contextID);
180: if (inputContext != null) {
181: // Keep the old editor input
182: IEditorInput oldInput = editor.getEditorInput();
183: // Perform the save as operation
184: inputContext.doSaveAs(monitor);
185: // Get the new editor input
186: IEditorInput newInput = inputContext.getInput();
187: // Update the context manager accordingly
188: updateInputContext(newInput, oldInput);
189: } else {
190: throw new Exception(
191: PDEUIMessages.InputContextManager_errorMessageInputContextNotFound);
192: }
193: }
194:
195: public InputContext getPrimaryContext() {
196: for (Enumeration contexts = inputContexts.elements(); contexts
197: .hasMoreElements();) {
198: InputContext context = (InputContext) contexts
199: .nextElement();
200: if (context.isPrimary())
201: return context;
202: }
203: return null;
204: }
205:
206: public InputContext[] getInvalidContexts() {
207: ArrayList result = new ArrayList();
208: for (Enumeration contexts = inputContexts.elements(); contexts
209: .hasMoreElements();) {
210: InputContext context = (InputContext) contexts
211: .nextElement();
212: if (context.isModelCorrect() == false)
213: result.add(context);
214: }
215: return (InputContext[]) result.toArray(new InputContext[result
216: .size()]);
217: }
218:
219: public boolean isDirty() {
220: for (Enumeration contexts = inputContexts.elements(); contexts
221: .hasMoreElements();) {
222: InputContext context = (InputContext) contexts
223: .nextElement();
224: if (context.mustSave())
225: return true;
226: }
227: return false;
228: }
229:
230: public void monitorFile(IFile file) {
231: if (monitoredFiles == null)
232: monitoredFiles = new ArrayList();
233: monitoredFiles.add(file);
234: }
235:
236: /* (non-Javadoc)
237: * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
238: */
239: public void resourceChanged(IResourceChangeEvent event) {
240: IResourceDelta delta = event.getDelta();
241:
242: try {
243: delta.accept(new IResourceDeltaVisitor() {
244: public boolean visit(IResourceDelta delta) {
245: int kind = delta.getKind();
246: IResource resource = delta.getResource();
247: if (resource instanceof IFile) {
248: if (kind == IResourceDelta.ADDED)
249: asyncStructureChanged((IFile) resource,
250: true);
251: else if (kind == IResourceDelta.REMOVED)
252: asyncStructureChanged((IFile) resource,
253: false);
254: return false;
255: }
256: return true;
257: }
258: });
259: } catch (CoreException e) {
260: PDEPlugin.logException(e);
261: }
262: }
263:
264: private void asyncStructureChanged(final IFile file,
265: final boolean added) {
266: if (editor == null || editor.getEditorSite() == null)
267: return;
268: Shell shell = editor.getEditorSite().getShell();
269: Display display = shell != null ? shell.getDisplay() : Display
270: .getDefault();
271:
272: display.asyncExec(new Runnable() {
273: public void run() {
274: structureChanged(file, added);
275: }
276: });
277: }
278:
279: private void structureChanged(IFile file, boolean added) {
280: if (monitoredFiles == null)
281: return;
282: for (int i = 0; i < monitoredFiles.size(); i++) {
283: IFile ifile = (IFile) monitoredFiles.get(i);
284: if (ifile.equals(file)) {
285: if (added) {
286: fireStructureChange(file, true);
287: } else {
288: fireStructureChange(file, false);
289: removeContext(file);
290: }
291: }
292: }
293: }
294:
295: private void removeContext(IFile file) {
296: for (Enumeration contexts = inputContexts.elements(); contexts
297: .hasMoreElements();) {
298: InputContext context = (InputContext) contexts
299: .nextElement();
300: IEditorInput input = context.getInput();
301: if (input instanceof IFileEditorInput) {
302: IFileEditorInput fileInput = (IFileEditorInput) input;
303: if (file.equals(fileInput.getFile())) {
304: inputContexts.remove(input);
305: fireContextChange(context, false);
306: return;
307: }
308: }
309: }
310: }
311:
312: protected void fireStructureChange(IFile file, boolean added) {
313: for (int i = 0; i < listeners.size(); i++) {
314: IInputContextListener listener = (IInputContextListener) listeners
315: .get(i);
316: if (added)
317: listener.monitoredFileAdded(file);
318: else
319: listener.monitoredFileRemoved(file);
320: }
321: }
322:
323: protected void fireContextChange(InputContext context, boolean added) {
324: for (int i = 0; i < listeners.size(); i++) {
325: IInputContextListener listener = (IInputContextListener) listeners
326: .get(i);
327: if (added)
328: listener.contextAdded(context);
329: else
330: listener.contextRemoved(context);
331: }
332: if (added)
333: hookUndo(context);
334: else
335: unhookUndo(context);
336: }
337:
338: public void undo() {
339: if (undoManager != null && undoManager.isUndoable())
340: undoManager.undo();
341: }
342:
343: public void redo() {
344: if (undoManager != null && undoManager.isRedoable())
345: undoManager.redo();
346: }
347:
348: private void hookUndo(InputContext context) {
349: if (undoManager == null)
350: return;
351: IBaseModel model = context.getModel();
352: if (model instanceof IModelChangeProvider)
353: undoManager.connect((IModelChangeProvider) model);
354: }
355:
356: private void unhookUndo(InputContext context) {
357: if (undoManager == null)
358: return;
359: IBaseModel model = context.getModel();
360: if (model instanceof IModelChangeProvider)
361: undoManager.disconnect((IModelChangeProvider) model);
362: }
363:
364: /**
365: * @return Returns the undoManager.
366: */
367: public IModelUndoManager getUndoManager() {
368: return undoManager;
369: }
370:
371: /**
372: * @param undoManager The undoManager to set.
373: */
374: public void setUndoManager(IModelUndoManager undoManager) {
375: this.undoManager = undoManager;
376: }
377: }
|