diff --git a/rse/plugins/org.eclipse.rse.efs/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.efs/META-INF/MANIFEST.MF index 5ff2073af40..816fe004efb 100644 --- a/rse/plugins/org.eclipse.rse.efs/META-INF/MANIFEST.MF +++ b/rse/plugins/org.eclipse.rse.efs/META-INF/MANIFEST.MF @@ -10,7 +10,11 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.rse.core;bundle-version="[3.0.0,4.0.0)", org.eclipse.rse.subsystems.files.core;bundle-version="[3.0.1,4.0.0)", org.eclipse.rse.services;bundle-version="[3.0.0,4.0.0)", - org.eclipse.rse.ui;bundle-version="[3.0.0,4.0.0)" + org.eclipse.rse.ui;bundle-version="[3.0.0,4.0.0)", + org.eclipse.core.resources;bundle-version="3.4.0", + org.eclipse.ui;bundle-version="3.4.0", + org.eclipse.ui.ide;bundle-version="3.4.0", + org.eclipse.ui.editors;bundle-version="3.4.0" Bundle-ActivationPolicy: lazy Eclipse-LazyStart: true Bundle-Vendor: %providerName diff --git a/rse/plugins/org.eclipse.rse.efs/src/org/eclipse/rse/internal/efs/Activator.java b/rse/plugins/org.eclipse.rse.efs/src/org/eclipse/rse/internal/efs/Activator.java index 0e9f3e64774..258291ea0ac 100644 --- a/rse/plugins/org.eclipse.rse.efs/src/org/eclipse/rse/internal/efs/Activator.java +++ b/rse/plugins/org.eclipse.rse.efs/src/org/eclipse/rse/internal/efs/Activator.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2006, 2007 IBM Corporation and others. All rights reserved. + * Copyright (c) 2006, 2009 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 @@ -17,11 +17,20 @@ * - Improve performance by RSEFileStore instance factory and caching IRemoteFile. * - Also remove unnecessary class RSEFileCache and obsolete branding files. * Martin Oberhuber (Wind River) - [188360] renamed from plugin org.eclipse.rse.eclipse.filesystem + * David McKnight (IBM) -[241315] [efs] Cannot restore editors for RSE/EFS-backed resources ********************************************************************************/ package org.eclipse.rse.internal.efs; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; import org.osgi.framework.BundleContext; /** @@ -32,6 +41,9 @@ public class Activator extends Plugin { //The shared instance. private static Activator plugin; + public static final String PLUGIN_ID = "org.eclipse.rse.efs"; //$NON-NLS-1$ + + /** * The constructor. */ @@ -39,25 +51,41 @@ public class Activator extends Plugin { plugin = this; } - /** - * This method is called upon plug-in activation - */ + public void start(BundleContext context) throws Exception { super.start(context); - ////We must not activate RSE plugins prematurely, since we are being - ////activated VERY early while the Resources plugin is not yet fully up - //RSECorePlugin.getDefault(); - //RSEUIPlugin.getDefault(); + final RemoteEditorManager mgr = RemoteEditorManager.getDefault(); + ResourcesPlugin.getWorkspace().addSaveParticipant(this, mgr); + ResourcesPlugin.getWorkspace().addResourceChangeListener(mgr, IResourceChangeEvent.POST_CHANGE); + + Job job = new Job("Add Listener"){ //$NON-NLS-1$ + protected IStatus run(IProgressMonitor monitor) { + + while (!PlatformUI.isWorkbenchRunning()){ + try { + //Checks in the loop are fast enough so we can poll often + Thread.sleep(100); + } + catch (InterruptedException e){} + } + IWorkbench wb = PlatformUI.getWorkbench(); + wb.addWorkbenchListener(mgr); + return Status.OK_STATUS; + } + }; + job.schedule(); + } - /** - * This method is called when the plug-in is stopped - */ public void stop(BundleContext context) throws Exception { - super.stop(context); + try { + ResourcesPlugin.getWorkspace().removeSaveParticipant(this); + ResourcesPlugin.getWorkspace().removeResourceChangeListener(RemoteEditorManager.getDefault()); + } finally { + super.stop(context); + } plugin = null; } - /** * Returns the shared instance. * @@ -66,5 +94,9 @@ public class Activator extends Plugin { public static Activator getDefault() { return plugin; } + + public static IStatus errorStatus(Throwable e) { + return new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage(), e); + } } \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.efs/src/org/eclipse/rse/internal/efs/RemoteEditorManager.java b/rse/plugins/org.eclipse.rse.efs/src/org/eclipse/rse/internal/efs/RemoteEditorManager.java new file mode 100644 index 00000000000..23ca6386f41 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.efs/src/org/eclipse/rse/internal/efs/RemoteEditorManager.java @@ -0,0 +1,284 @@ +/******************************************************************************** + * Copyright (c) 2009 IBM Corporation. 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Mike Kucera. + * + * Contributors: + * Mike Kucera (IBM) - [241315] [efs] Cannot restore editors for RSE/EFS-backed resources + * David McKnight (IBM) - [241315] [efs] Cannot restore editors for RSE/EFS-backed resources + ********************************************************************************/ +package org.eclipse.rse.internal.efs; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.ISaveContext; +import org.eclipse.core.resources.ISaveParticipant; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.rse.ui.RSEUIPlugin; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchListener; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.progress.UIJob; + +public class RemoteEditorManager implements ISaveParticipant, IResourceChangeListener, IWorkbenchListener { + public static final String PREFERENCE_EDITOR_LIST = "org.eclipse.rse.internal.efs.EditorSaver.preferenceEditorList"; //$NON-NLS-1$ + + private static RemoteEditorManager defaultInstance; + + private Map projectNameToUriMap = null; + + private RemoteEditorManager() {} + + public static synchronized RemoteEditorManager getDefault() { + if(defaultInstance == null) + defaultInstance = new RemoteEditorManager(); + return defaultInstance; + } + + + /** + * Restores remote editors when a remote project is opened. + */ + public void resourceChanged(IResourceChangeEvent event) { + String pref = RSEUIPlugin.getDefault().getPreferenceStore().getString(PREFERENCE_EDITOR_LIST); + Map projectNameToUriMap = getProjectNameToUriMap(pref); + if(projectNameToUriMap.isEmpty()) + return; + + IResourceDelta[] children = event.getDelta().getAffectedChildren(); + for(int i = 0; i < children.length; i++) { + IResourceDelta delta = children[i]; + + // if a project has just been opened + if((delta.getFlags() & IResourceDelta.OPEN) != 0) { + IProject project = delta.getResource().getProject(); + if(project.isOpen()) { + + // restore remote editors for the project + List uris = (List) projectNameToUriMap.remove(project.getName()); + if(uris != null) { + for(Iterator iter = uris.iterator(); iter.hasNext();) { + final String uriString = (String) iter.next(); + + Job job = new UIJob("Restore Remote Editor") { //$NON-NLS-1$ + public IStatus runInUIThread(IProgressMonitor monitor) { + if(monitor.isCanceled()) + return Status.OK_STATUS; + + try { + // got this code from http://wiki.eclipse.org/FAQ_How_do_I_open_an_editor_programmatically%3F + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IFileStore fileStore = EFS.getStore(new URI(uriString)); + IDE.openEditorOnFileStore(page, fileStore); + } catch (URISyntaxException e) { + return Activator.errorStatus(e); + } catch (PartInitException e) { + return Activator.errorStatus(e); + } catch (CoreException e) { + return Activator.errorStatus(e); + } + return Status.OK_STATUS; + } + }; + job.schedule(); + + } + } + } + } + } + + } + + /** + * Saves the URIs of remote resources that are open in editors into the + * plugin's preference store. + */ + public synchronized void saveRemoteEditors() { + IWorkbench wb = PlatformUI.getWorkbench(); + IWorkbenchWindow[] windows = wb.getWorkbenchWindows(); + if(windows.length > 0) { + String list = generateEditorList(); + RSEUIPlugin.getDefault().getPreferenceStore().putValue(PREFERENCE_EDITOR_LIST, list); + } + projectNameToUriMap = null; + } + + private Map getProjectNameToUriMap(String raw) { + if(projectNameToUriMap == null) { + projectNameToUriMap = new HashMap(); + + if(raw == null || raw.length() == 0) + return projectNameToUriMap; + + int index = 0; + while(true) { + int i = raw.indexOf(IPath.SEPARATOR, index); + if(i < 0) break; + String projectName = raw.substring(index, i); + index = i + 1; + i = raw.indexOf(' ', index); + if(i < 0) break; + String uriString = raw.substring(index, i); + index = i + 1; + + List uris = (List) projectNameToUriMap.get(projectName); + if(uris == null) { + uris = new LinkedList(); + projectNameToUriMap.put(projectName, uris); + } + uris.add(uriString); + } + } + return projectNameToUriMap; + } + + + private String generateEditorList() { + final StringBuffer sb = new StringBuffer(); + + forEachOpenRemoteEditor(new IEditorCallback() { + public void apply(IWorkbenchPage page, IEditorPart editor, IFile file) { + IProject project = file.getProject(); + URI uri = file.getLocationURI(); + sb.append(project.getName()); + sb.append(IPath.SEPARATOR); // not allowed in resource names + sb.append(uri); + sb.append(' '); // not allowed in URIs + } + }); + + return sb.toString(); + } + + + private static interface IEditorCallback { + public void apply(IWorkbenchPage page, IEditorPart editor, IFile file); + } + + private static void forEachOpenRemoteEditor(IEditorCallback callback) { + IWorkbench wb = PlatformUI.getWorkbench(); + IWorkbenchWindow[] windows = wb.getWorkbenchWindows(); + for (int w = 0; w < windows.length; w++){ + IWorkbenchWindow win = windows[w]; + IWorkbenchPage[] pages = win.getPages(); + for (int p = 0; p < pages.length; p++){ + IWorkbenchPage page = pages[p]; + IEditorReference[] activeReferences = page.getEditorReferences(); + for (int er = 0; er < activeReferences.length; er++){ + IEditorReference editorReference = activeReferences[er]; + + try { + IEditorInput input = editorReference.getEditorInput(); + if (input instanceof FileEditorInput){ + IFile file = ((FileEditorInput)input).getFile(); + URI uri = file.getLocationURI(); + if ("rse".equals(uri.getScheme())) { //$NON-NLS-1$ + IEditorPart editor = editorReference.getEditor(false); + callback.apply(page, editor, file); + } + } + } catch (PartInitException e){ + e.printStackTrace(); + } + } + } + } + } + + /** + * Close each editor that is open for any file that uses "rse" as it's uri scheme + * @return true if successful, false otherwise + */ + public boolean closeRemoteEditors() { + boolean result = true; + IWorkbench wb = PlatformUI.getWorkbench(); + IWorkbenchWindow[] windows = wb.getWorkbenchWindows(); + for (int w = 0; w < windows.length; w++){ + IWorkbenchWindow win = windows[w]; + IWorkbenchPage[] pages = win.getPages(); + for (int p = 0; p < pages.length && result; p++){ + IWorkbenchPage page = pages[p]; + IEditorReference[] activeReferences = page.getEditorReferences(); + for (int er = 0; er < activeReferences.length; er++){ + IEditorReference editorReference = activeReferences[er]; + + try { + IEditorInput input = editorReference.getEditorInput(); + if (input instanceof FileEditorInput){ + IFile file = ((FileEditorInput)input).getFile(); + URI uri = file.getLocationURI(); + if ("rse".equals(uri.getScheme())) { //$NON-NLS-1$ + IEditorPart editor = editorReference.getEditor(false); + + // close the editor + result = page.closeEditor(editor, true); + } + } + } catch (PartInitException e){ + e.printStackTrace(); + } + } + } + } + return result; + } + + + public void saving(ISaveContext context) throws CoreException { + saveRemoteEditors(); + } + + + public void doneSaving(ISaveContext context) { + } + + public void prepareToSave(ISaveContext context) throws CoreException { + } + + public void rollback(ISaveContext context) { + } + + + // for IWorkbenchListener + public void postShutdown(IWorkbench workbench) { + } + + // for IWorkbenchListener + public boolean preShutdown(IWorkbench workbench, boolean forced) { + saveRemoteEditors(); + return closeRemoteEditors(); + } + +}