| /******************************************************************************* |
| * Copyright (c) 2001, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Jens Lukowski/Innoopract - initial renaming/restructuring |
| * |
| *******************************************************************************/ |
| package org.eclipse.wst.sse.ui; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IStorage; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.source.AnnotationModel; |
| import org.eclipse.jface.text.source.IAnnotationModel; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IFileEditorInput; |
| import org.eclipse.ui.IStorageEditorInput; |
| import org.eclipse.ui.editors.text.FileDocumentProvider; |
| import org.eclipse.ui.editors.text.ILocationProvider; |
| import org.eclipse.ui.editors.text.TextFileDocumentProvider; |
| import org.eclipse.ui.texteditor.IElementStateListener; |
| import org.eclipse.wst.sse.core.IFactoryRegistry; |
| import org.eclipse.wst.sse.core.IModelManager; |
| import org.eclipse.wst.sse.core.IModelManagerPlugin; |
| import org.eclipse.wst.sse.core.IStructuredModel; |
| import org.eclipse.wst.sse.ui.extensions.breakpoint.IExtendedStorageEditorInput; |
| import org.eclipse.wst.sse.ui.nls.ResourceHandler; |
| import org.eclipse.wst.sse.ui.registry.AdapterFactoryProvider; |
| import org.eclipse.wst.sse.ui.registry.AdapterFactoryRegistry; |
| import org.eclipse.wst.sse.ui.util.Assert; |
| |
| |
| /** |
| * A TextFileDocumentProvider that is IStructuredModel aware. This |
| * implementation is marked as final since it will change significantly in C4, |
| * possibly even be removed. |
| * |
| * @deprecated - no longer used |
| */ |
| public final class TextFileModelProvider extends TextFileDocumentProvider implements IModelProvider { |
| |
| /** |
| * Collection of info that goes with a model. |
| */ |
| protected class ModelInfo { |
| public IAnnotationModel fAnnotationModel; |
| public IEditorInput fElement; |
| public boolean fShouldReleaseOnInfoDispose; |
| public IStructuredModel fStructuredModel; |
| |
| public ModelInfo(IStructuredModel structuredModel, IEditorInput element, IAnnotationModel model, boolean selfCreated) { |
| fElement = element; |
| fStructuredModel = structuredModel; |
| fAnnotationModel = model; |
| fShouldReleaseOnInfoDispose = selfCreated; |
| } |
| } |
| |
| private static TextFileModelProvider fInstance = null; |
| private static IModelManager fModelManager; |
| |
| public synchronized static TextFileModelProvider getInstance() { |
| if (fInstance == null) |
| fInstance = new TextFileModelProvider(); |
| return fInstance; |
| } |
| |
| /** |
| * Utility method also used in subclasses |
| */ |
| protected static IModelManager getModelManager() { |
| if (fModelManager == null) { |
| // get the model manager from the plugin |
| // note: we can use the static "ID" variable, since we pre-req |
| // that plugin |
| IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID); |
| fModelManager = plugin.getModelManager(); |
| } |
| return fModelManager; |
| } |
| |
| protected IElementStateListener fInternalListener; |
| /** IStructuredModel information of all connected elements */ |
| private Map fModelInfoMap = new HashMap(); |
| |
| protected TextFileModelProvider() { |
| super(); |
| } |
| |
| public void addProviderFactories(IStructuredModel structuredModel) { |
| // (mostly) COPIED FROM FileModelProvider |
| EditorPlugin plugin = ((EditorPlugin) Platform.getPlugin(EditorPlugin.ID)); |
| AdapterFactoryRegistry adapterRegistry = plugin.getAdapterFactoryRegistry(); |
| Iterator adapterFactoryList = adapterRegistry.getAdapterFactories(); |
| |
| IFactoryRegistry factoryRegistry = structuredModel.getFactoryRegistry(); |
| Assert.isNotNull(factoryRegistry, "model in invalid state"); |
| |
| while (adapterFactoryList.hasNext()) { |
| try { |
| AdapterFactoryProvider provider = (AdapterFactoryProvider) adapterFactoryList.next(); |
| if (provider.isFor(structuredModel.getModelHandler())) { |
| provider.addAdapterFactories(structuredModel); |
| } |
| } catch (Exception e) { |
| Logger.logException(e); |
| } |
| } |
| // END COPY FileModelProvider |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#commitFileBuffer(org.eclipse.core.runtime.IProgressMonitor, |
| * org.eclipse.ui.editors.text.TextFileDocumentProvider.FileInfo, |
| * boolean) |
| */ |
| protected void commitFileBuffer(IProgressMonitor monitor, FileInfo info, boolean overwrite) throws CoreException { |
| IStructuredModel model = getModel(info.fElement); |
| if (model != null) { |
| String contents = model.getStructuredDocument().get(); |
| info.fTextFileBuffer.getDocument().set(contents); |
| } |
| super.commitFileBuffer(monitor, info, overwrite); |
| } |
| |
| protected String computePath(IEditorInput input) { |
| /** |
| * Typically CVS will return a path of "filename.ext" and the input's |
| * name will be "filename.ext version". The path must be used to load |
| * the model so that the suffix will be available to compute the |
| * contentType properly. The editor input name can then be set as the |
| * base location for display on the editor title bar. |
| */ |
| String path = null; |
| boolean addHash = false; |
| try { |
| if (input instanceof IStorageEditorInput) { |
| IStorage storage = ((IStorageEditorInput) input).getStorage(); |
| if (storage != null) { |
| IPath storagePath = storage.getFullPath(); |
| String name = storage.getName(); |
| // if either the name or storage path are null or they are |
| // identical, add a hash to it to guarantee uniqueness |
| addHash = storagePath == null || storagePath.toString().equals(name); |
| if (storagePath != null) |
| path = storagePath.makeAbsolute().toString(); |
| if (path == null) |
| path = name; |
| } |
| } else if (input.getAdapter(ILocationProvider.class) != null) { |
| IPath locationPath = ((ILocationProvider) input.getAdapter(ILocationProvider.class)).getPath(input); |
| if (locationPath != null) { |
| path = locationPath.toString(); |
| } |
| } |
| |
| } catch (CoreException e) { |
| Logger.logException(e); |
| return null; |
| } finally { |
| if (path == null) |
| path = ""; //$NON-NLS-1$ |
| } |
| if (addHash) |
| path = input.hashCode() + path; |
| return path; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createAnnotationModel(org.eclipse.core.resources.IFile) |
| */ |
| protected IAnnotationModel createAnnotationModel(IFile file) { |
| String id = file.getFullPath().toString(); |
| IAnnotationModel model = new StructuredResourceMarkerAnnotationModel(file, id); |
| IEditorInput input = null; |
| Iterator i = getConnectedElementsIterator(); |
| while (input == null && i.hasNext()) { |
| FileInfo info = (FileInfo) i.next(); |
| if (getSystemFile(info).equals(file)) { |
| input = (IEditorInput) info.fElement; |
| } |
| } |
| ModelInfo modelInfo = getModelInfoFor(input); |
| modelInfo.fAnnotationModel = model; |
| return model; |
| } |
| |
| /** |
| * Also create ModelInfo - extra resource synchronization classes should |
| * be stored within the ModelInfo |
| */ |
| protected FileInfo createFileInfo(Object element) throws CoreException { |
| FileInfo info = super.createFileInfo(element); |
| // create the corresponding ModelInfo if necessary |
| if (getModelInfoFor((IEditorInput) element) == null) { |
| createModelInfo((IEditorInput) element); |
| } |
| |
| return info; |
| } |
| |
| public void createModelInfo(IEditorInput input) { |
| if (getModelInfoFor(input) == null) { |
| IStructuredModel structuredModel = selfCreateModel(input); |
| createModelInfo(input, structuredModel, true); |
| } |
| } |
| |
| /** |
| * To be used when model is provided to us, ensures that when setInput is |
| * used on this input, the given model will be used. |
| */ |
| public void createModelInfo(IEditorInput input, IStructuredModel structuredModel, boolean releaseModelOnDisconnect) { |
| // we have to make sure factories are added, whether we created or |
| // not. |
| if (getModelInfoFor(input) != null || getModelInfoFor(structuredModel) != null) |
| return; |
| |
| if (input instanceof IExtendedStorageEditorInput) { |
| ((IExtendedStorageEditorInput) input).addElementStateListener(fInternalListener); |
| } |
| |
| addProviderFactories(structuredModel); |
| |
| ModelInfo modelInfo = new ModelInfo(structuredModel, input, null, releaseModelOnDisconnect); |
| // to help with downstream usage, create a dummy/"null" annotation |
| // model |
| if (!(input instanceof IFileEditorInput)) { |
| modelInfo.fAnnotationModel = new AnnotationModel(); |
| } |
| fModelInfoMap.put(input, modelInfo); |
| } |
| |
| protected void disposeFileInfo(Object element, FileInfo info) { |
| if (element instanceof IEditorInput) { |
| IEditorInput input = (IEditorInput) element; |
| ModelInfo modelInfo = getModelInfoFor(input); |
| disposeModelInfo(modelInfo); |
| } |
| super.disposeFileInfo(element, info); |
| } |
| |
| /** |
| * disconnect from this model info |
| * |
| * @param info |
| */ |
| public void disposeModelInfo(ModelInfo info) { |
| if (info.fElement instanceof IStorageEditorInput) { |
| if (info.fElement instanceof IExtendedStorageEditorInput) { |
| ((IExtendedStorageEditorInput) info.fElement).removeElementStateListener(fInternalListener); |
| } |
| if (info.fShouldReleaseOnInfoDispose) { |
| info.fStructuredModel.releaseFromEdit(); |
| } |
| } |
| fModelInfoMap.remove(info.fElement); |
| } |
| |
| /** |
| * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#doSaveDocument(org.eclipse.core.runtime.IProgressMonitor, |
| * java.lang.Object, org.eclipse.jface.text.IDocument, boolean) |
| */ |
| protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException { |
| new FileDocumentProvider().saveDocument(monitor, element, document, overwrite); |
| } |
| |
| /** |
| * Overridden to use ModelInfo's annotation model |
| * |
| * @see org.eclipse.ui.texteditor.IDocumentProvider#getAnnotationModel(java.lang.Object) |
| */ |
| public IAnnotationModel getAnnotationModel(Object element) { |
| // override behavior an retrieve the annotation model from the model |
| // info |
| ModelInfo info = getModelInfoFor((IEditorInput) element); |
| if (info != null) |
| return info.fAnnotationModel; |
| return null; |
| } |
| |
| public IDocument getDocument(Object element) { |
| IDocument document = null; |
| |
| IStructuredModel model = getModel(element); |
| if (model != null) |
| document = model.getStructuredDocument(); |
| |
| return document; |
| } |
| |
| protected IEditorInput getInputFor(IDocument document) { |
| IStructuredModel model = getModelManager().getExistingModelForRead(document); |
| IEditorInput input = getInputFor(model); |
| model.releaseFromRead(); |
| return input; |
| } |
| |
| protected IEditorInput getInputFor(IStructuredModel structuredModel) { |
| IEditorInput result = null; |
| ModelInfo info = getModelInfoFor(structuredModel); |
| if (info != null) |
| result = info.fElement; |
| return result; |
| } |
| |
| public IStructuredModel getModel(IEditorInput element) { |
| IStructuredModel result = null; |
| ModelInfo info = getModelInfoFor(element); |
| if (info != null) { |
| result = info.fStructuredModel; |
| } |
| return result; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.wst.sse.ui.IModelProvider#getModel(java.lang.Object) |
| */ |
| public IStructuredModel getModel(Object element) { |
| if (element instanceof IEditorInput) |
| return getModel((IEditorInput) element); |
| return null; |
| } |
| |
| protected ModelInfo getModelInfoFor(IEditorInput element) { |
| ModelInfo result = (ModelInfo) fModelInfoMap.get(element); |
| return result; |
| } |
| |
| protected ModelInfo getModelInfoFor(IStructuredModel structuredModel) { |
| ModelInfo result = null; |
| if (structuredModel != null) { |
| ModelInfo[] modelInfos = (ModelInfo[]) fModelInfoMap.values().toArray(new ModelInfo[0]); |
| for (int i = 0; i < modelInfos.length; i++) { |
| ModelInfo info = modelInfos[i]; |
| if (structuredModel.equals(info.fStructuredModel)) { |
| result = info; |
| break; |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * @param input |
| * @return |
| */ |
| private File getSystemFile(IEditorInput input) { |
| File file = null; |
| ILocationProvider provider = (ILocationProvider) input.getAdapter(ILocationProvider.class); |
| if (provider != null) { |
| IPath fullPath = provider.getPath(input); |
| if (fullPath != null) { |
| file = fullPath.toFile(); |
| } |
| } |
| return file; |
| } |
| |
| /** |
| * Method loadModel. |
| * |
| * @param input |
| * @return IStructuredModel |
| */ |
| public IStructuredModel loadModel(IEditorInput input) { |
| return loadModel(input, false); |
| } |
| |
| /** |
| * Method loadModel. |
| * |
| * @param input |
| * @param logExceptions |
| * @return IStructuredModel |
| */ |
| public IStructuredModel loadModel(IEditorInput input, boolean logExceptions) { |
| InputStream contents = null; |
| IStructuredModel model = null; |
| File file = getSystemFile(input); |
| if (file != null) { |
| String path = file.getAbsolutePath(); |
| try { |
| contents = new FileInputStream(file); |
| // first parameter must be unique |
| model = getModelManager().getModelForEdit(path, contents, null); |
| model.setBaseLocation(path); |
| } catch (IOException e) { |
| if (logExceptions) |
| Logger.logException(ResourceHandler.getString("32concat_EXC_", new Object[]{input}), e); //$NON-NLS-1$ |
| } |
| try { |
| contents.close(); |
| } catch (Exception e1) { |
| // do nothing, this is just to ensure the resource isn't held |
| // open |
| } |
| } |
| return model; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.texteditor.IDocumentProvider#resetDocument(java.lang.Object) |
| */ |
| public void resetDocument(Object element) throws CoreException { |
| super.resetDocument(element); |
| FileInfo info = getFileInfo(element); |
| File file = getSystemFile(info); |
| if (file != null && file.exists()) { |
| IStructuredModel model = getModel(element); |
| InputStream fis = null; |
| try { |
| fis = new FileInputStream(file); |
| } catch (FileNotFoundException e) { |
| // possibly nothing if the file was deleted, shouldn't happen |
| // otherwise |
| } |
| if (fis != null) { |
| String oldContents = model.getStructuredDocument().get(); |
| try { |
| model.reload(fis); |
| info.fTextFileBuffer.getDocument().set(model.getStructuredDocument().get()); |
| } catch (IOException e1) { |
| Logger.logException("Exception caught reloading model from " + file.getName(), e1); //$NON-NLS-1$ |
| model.getStructuredDocument().set(oldContents); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @param input |
| * @return |
| */ |
| protected IStructuredModel selfCreateModel(IEditorInput input) { |
| return loadModel(input); |
| } |
| } |