| /******************************************************************************* |
| * Copyright (c) 2009 Remy Chi Jian Suen 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: |
| * Remy Chi Jian Suen <remy.suen@gmail.com> - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.ecf.internal.sync.ui.resources; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.ecf.core.identity.ID; |
| import org.eclipse.ecf.core.util.ECFException; |
| import org.eclipse.ecf.datashare.IChannelContainerAdapter; |
| import org.eclipse.ecf.docshare2.DocShare; |
| import org.eclipse.ecf.internal.sync.resources.core.ResourcesShare; |
| import org.eclipse.ecf.internal.sync.resources.core.SyncResourcesCore; |
| import org.eclipse.jface.text.ITextSelection; |
| import org.eclipse.jface.text.source.IAnnotationModel; |
| import org.eclipse.jface.viewers.IPostSelectionProvider; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.ISelectionProvider; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.ui.IPageListener; |
| import org.eclipse.ui.IPartListener; |
| import org.eclipse.ui.IWindowListener; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.plugin.AbstractUIPlugin; |
| import org.eclipse.ui.statushandlers.StatusManager; |
| import org.eclipse.ui.texteditor.ITextEditor; |
| import org.osgi.framework.BundleContext; |
| |
| public class SyncResourcesUI extends AbstractUIPlugin { |
| |
| public static final String PLUGIN_ID = "org.eclipse.ecf.sync.ui.resources"; //$NON-NLS-1$ |
| |
| private static SyncResourcesUI instance; |
| |
| private IWindowListener windowListener = new IWindowListener() { |
| |
| public void windowOpened(IWorkbenchWindow window) { |
| window.addPageListener(pageListener); |
| } |
| |
| public void windowDeactivated(IWorkbenchWindow window) { |
| // nothing to do |
| } |
| |
| public void windowClosed(IWorkbenchWindow window) { |
| window.removePageListener(pageListener); |
| } |
| |
| public void windowActivated(IWorkbenchWindow window) { |
| // nothing to do |
| } |
| }; |
| |
| private IPageListener pageListener = new IPageListener() { |
| |
| public void pageOpened(IWorkbenchPage page) { |
| page.addPartListener(partListener); |
| } |
| |
| public void pageClosed(IWorkbenchPage page) { |
| page.removePartListener(partListener); |
| } |
| |
| public void pageActivated(IWorkbenchPage page) { |
| // nothing to do |
| } |
| }; |
| |
| private IPartListener partListener = new IPartListener() { |
| |
| public void partOpened(IWorkbenchPart part) { |
| ITextEditor editor = (ITextEditor) part |
| .getAdapter(ITextEditor.class); |
| if (editor != null) { |
| IFile file = (IFile) editor.getEditorInput().getAdapter( |
| IFile.class); |
| if (file != null) { |
| startSharing(editor, file); |
| } |
| } |
| } |
| |
| public void partDeactivated(IWorkbenchPart part) { |
| // nothing to do |
| } |
| |
| public void partClosed(IWorkbenchPart part) { |
| ITextEditor editor = (ITextEditor) part |
| .getAdapter(ITextEditor.class); |
| if (editor != null) { |
| IFile file = (IFile) editor.getEditorInput().getAdapter( |
| IFile.class); |
| if (file != null) { |
| stopSharing(editor, file); |
| } |
| } |
| } |
| |
| public void partBroughtToTop(IWorkbenchPart part) { |
| // nothing to do |
| } |
| |
| public void partActivated(IWorkbenchPart part) { |
| // nothing to do |
| } |
| }; |
| |
| private Map sharedFiles = new HashMap(); |
| |
| private Map sharedEditors = new HashMap(); |
| |
| private boolean share(IFile file) { |
| IPath path = file.getFullPath(); |
| Integer integer = (Integer) sharedFiles.get(path); |
| if (integer == null) { |
| sharedFiles.put(path, Integer.valueOf(1)); |
| return true; |
| } |
| sharedFiles.put(path, Integer.valueOf(integer.intValue() + 1)); |
| return false; |
| } |
| |
| private boolean unshare(IFile file) { |
| IPath path = file.getFullPath(); |
| Integer integer = (Integer) sharedFiles.remove(path); |
| if (integer == null) { |
| // if this file isn't being shared, will be null, return false |
| return false; |
| } |
| |
| if (integer.intValue() == 1) { |
| return true; |
| } |
| |
| sharedFiles.put(path, Integer.valueOf(integer.intValue() - 1)); |
| return false; |
| } |
| |
| private void startSharing(ITextEditor editor, IFile file) { |
| String projectName = file.getProject().getName(); |
| for (Iterator it = SyncResourcesCore.getResourceShares().iterator(); it |
| .hasNext();) { |
| ResourcesShare share = (ResourcesShare) it.next(); |
| if (share.isSharing(projectName) && share(file)) { |
| DocShare docShare = getDocShare(share.getContainerID()); |
| try { |
| IAnnotationModel annotationModel = editor |
| .getDocumentProvider().getAnnotationModel( |
| editor.getEditorInput()); |
| docShare.startSharing(share.getLocalID(), share |
| .getReceiverID(), file.getFullPath().toString(), |
| annotationModel); |
| ISelectionProvider provider = editor.getSelectionProvider(); |
| if (provider instanceof IPostSelectionProvider) { |
| ISelectionChangedListener listener = new SelectionChangedListener( |
| share.getReceiverID(), file.getFullPath() |
| .toString(), docShare); |
| ((IPostSelectionProvider) provider) |
| .addPostSelectionChangedListener(listener); |
| sharedEditors.put(editor, listener); |
| } |
| } catch (ECFException e) { |
| IStatus status = new Status(IStatus.ERROR, PLUGIN_ID, |
| "Could not send initiation request to " //$NON-NLS-1$ |
| + share.getReceiverID(), e); |
| log(status); |
| StatusManager.getManager().handle(status, |
| StatusManager.SHOW); |
| } catch (CoreException e) { |
| IStatus status = new Status(IStatus.ERROR, PLUGIN_ID, |
| "Could not connect to the file buffer of " //$NON-NLS-1$ |
| + file.getFullPath(), e); |
| log(status); |
| StatusManager.getManager().handle(status, |
| StatusManager.SHOW); |
| } |
| } |
| } |
| } |
| |
| private void stopSharing(ITextEditor editor, IFile file) { |
| String projectName = file.getProject().getName(); |
| for (Iterator it = SyncResourcesCore.getResourceShares().iterator(); it |
| .hasNext();) { |
| ResourcesShare share = (ResourcesShare) it.next(); |
| if (share.isSharing(projectName) && unshare(file)) { |
| DocShare docShare = getDocShare(share.getContainerID()); |
| stopSharing(docShare, share.getReceiverID(), editor, file); |
| } |
| } |
| } |
| |
| private void stopSharing(DocShare share, ID id, ITextEditor editor, |
| IFile file) { |
| try { |
| share.stopSharing(id, file.getFullPath().toString()); |
| } catch (ECFException e) { |
| log(new Status(IStatus.ERROR, PLUGIN_ID, |
| "Could not send stop message to " + id, e)); //$NON-NLS-1$ |
| } |
| |
| ISelectionChangedListener listener = (ISelectionChangedListener) sharedEditors |
| .remove(editor); |
| if (listener != null) { |
| ISelectionProvider provider = editor.getSelectionProvider(); |
| if (provider instanceof IPostSelectionProvider) { |
| ((IPostSelectionProvider) provider) |
| .removePostSelectionChangedListener(listener); |
| } |
| } |
| } |
| |
| public SyncResourcesUI() { |
| instance = this; |
| } |
| |
| public void start(BundleContext context) throws Exception { |
| super.start(context); |
| |
| getWorkbench().addWindowListener(windowListener); |
| |
| IWorkbenchWindow[] workbenchWindows = getWorkbench() |
| .getWorkbenchWindows(); |
| for (int i = 0; i < workbenchWindows.length; i++) { |
| workbenchWindows[i].addPageListener(pageListener); |
| IWorkbenchPage[] pages = workbenchWindows[i].getPages(); |
| for (int j = 0; j < pages.length; j++) { |
| pages[j].addPartListener(partListener); |
| } |
| } |
| } |
| |
| public static SyncResourcesUI getDefault() { |
| return instance; |
| } |
| |
| public Display getDisplay() { |
| return getWorkbench().getDisplay(); |
| } |
| |
| public static void log(IStatus status) { |
| instance.getLog().log(status); |
| } |
| |
| public void stop(BundleContext context) throws Exception { |
| getWorkbench().removeWindowListener(windowListener); |
| |
| IWorkbenchWindow[] workbenchWindows = getWorkbench() |
| .getWorkbenchWindows(); |
| for (int i = 0; i < workbenchWindows.length; i++) { |
| workbenchWindows[i].removePageListener(pageListener); |
| IWorkbenchPage[] pages = workbenchWindows[i].getPages(); |
| for (int j = 0; j < pages.length; j++) { |
| pages[j].removePartListener(partListener); |
| } |
| } |
| |
| super.stop(context); |
| } |
| |
| private static Map docshareChannels = new HashMap(); |
| |
| public static DocShare getDocShare(ID containerID) { |
| return (DocShare) docshareChannels.get(containerID); |
| } |
| |
| public static DocShare addDocShare(ID containerID, |
| IChannelContainerAdapter channelAdapter) throws ECFException { |
| DocShare docShare = (DocShare) docshareChannels.get(containerID); |
| if (docShare == null) { |
| return (DocShare) docshareChannels.put(containerID, |
| new WorkbenchAwareDocShare(channelAdapter)); |
| } |
| return docShare; |
| } |
| |
| public static DocShare removeDocShare(ID containerID) { |
| return (DocShare) docshareChannels.remove(containerID); |
| } |
| |
| public static ResourcesShare getResourceShare(ID containerID) { |
| return SyncResourcesCore.getResourcesShare(containerID); |
| } |
| |
| public static ResourcesShare addResourceShare(ID containerID, |
| IChannelContainerAdapter channelAdapter) throws ECFException { |
| ResourcesShare resourcesShare = SyncResourcesCore |
| .getResourcesShare(containerID); |
| if (resourcesShare == null) { |
| resourcesShare = new WorkbenchAwareResourcesShare(containerID, |
| channelAdapter); |
| SyncResourcesCore.addResourcesShare(containerID, resourcesShare); |
| } |
| return resourcesShare; |
| } |
| |
| public static ResourcesShare removeResourceShare(ID containerID) { |
| return SyncResourcesCore.removeResourcesShare(containerID); |
| } |
| |
| private class SelectionChangedListener implements ISelectionChangedListener { |
| |
| private ID targetID; |
| private String path; |
| private DocShare share; |
| |
| public SelectionChangedListener(ID targetID, String path, DocShare share) { |
| this.targetID = targetID; |
| this.path = path; |
| this.share = share; |
| } |
| |
| public void selectionChanged(SelectionChangedEvent e) { |
| ISelection selection = e.getSelection(); |
| if (selection instanceof ITextSelection) { |
| ITextSelection textSelection = (ITextSelection) selection; |
| try { |
| share.sendSelection(targetID, path, textSelection |
| .getOffset(), textSelection.getLength()); |
| } catch (ECFException exception) { |
| log(new Status(IStatus.ERROR, PLUGIN_ID, |
| "Could not send selection message to " + targetID, //$NON-NLS-1$ |
| exception)); |
| } |
| } |
| } |
| |
| } |
| |
| } |