diff --git a/eclipse/META-INF/MANIFEST.MF b/eclipse/META-INF/MANIFEST.MF index 964becbc8e..6833f00eae 100644 --- a/eclipse/META-INF/MANIFEST.MF +++ b/eclipse/META-INF/MANIFEST.MF @@ -20,7 +20,18 @@ Require-Bundle: org.eclipse.ui, org.eclipse.equinox.security, org.junit;resolution:=optional, org.eclipse.jdt.launching;resolution:=optional, - saros.core + org.eclipse.e4.ui.model.workbench, + org.eclipse.e4.ui.di, + org.eclipse.osgi, + org.eclipse.e4.ui.services, + org.eclipse.e4.core.di.annotations, + saros.core, + org.eclipse.osgi.services, + org.eclipse.e4.ui.workbench, + org.eclipse.equinox.ds, + org.eclipse.equinox.event, + org.eclipse.equinox.util, + org.eclipse.e4.ui.workbench.addons.swt Bundle-ActivationPolicy: lazy Export-Package: saros; uses:="org.eclipse.core.runtime, @@ -93,13 +104,14 @@ Export-Package: saros; org.eclipse.jface.viewers, saros.invitation, saros.net", - saros.ui.command_handlers, saros.ui.decorators; uses:="org.eclipse.core.runtime, saros.resource_change_handlers, org.eclipse.jface.viewers, saros.editor, saros.invitation", + saros.ui.e4.command_handlers, + saros.ui.handlers.menu, saros.ui.model, saros.ui.preference_pages, saros.ui.util, @@ -129,4 +141,10 @@ Export-Package: saros; saros.util;uses:="org.eclipse.core.resources,org.jivesoftware.smack.packet" Bundle-Vendor: Saros Project Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Import-Package: org.eclipse.core.filesystem \ No newline at end of file +Import-Package: javax.annotation;version="1.2.0", + javax.inject, + org.eclipse.core.filesystem, + org.eclipse.e4.core.commands, + org.eclipse.e4.core.services.events, + org.eclipse.e4.ui.workbench.modeling, + org.osgi.service.event;version="1.4.0" diff --git a/eclipse/build.gradle.kts b/eclipse/build.gradle.kts index 2ddf6d5b04..407eeedb82 100644 --- a/eclipse/build.gradle.kts +++ b/eclipse/build.gradle.kts @@ -45,6 +45,9 @@ dependencies { // This is a workaround for https://github.com/saros-project/saros/issues/1114 implementation("org.eclipse.platform:org.eclipse.ui.ide:3.17.200") implementation("org.eclipse.platform:org.eclipse.ui.workbench:3.120.0") + // This is a workaround for an Issues, same as https://github.com/saros-project/saros/issues/1114 + implementation("org.eclipse.platform:org.eclipse.e4.ui.services:1.3.700") + implementation("javax.inject:javax.inject:1") testImplementation(project(path = ":saros.core", configuration = "testing")) } diff --git a/eclipse/build.properties b/eclipse/build.properties index 7a227998f8..00ca315224 100644 --- a/eclipse/build.properties +++ b/eclipse/build.properties @@ -1,8 +1,4 @@ -source.. = src/,\ - ext-src/ - output.. = bin/ - bin.includes = META-INF/,\ .,\ plugin.xml,\ @@ -16,4 +12,7 @@ bin.includes = META-INF/,\ CHANGELOG,\ plugin.properties,\ saros.properties,\ - lib/ + lib/,\ + fragment.e4xmi +source.. = src/,\ + ext-src/ diff --git a/eclipse/fragment.e4xmi b/eclipse/fragment.e4xmi new file mode 100644 index 0000000000..f773df8ba2 --- /dev/null +++ b/eclipse/fragment.e4xmi @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + View + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eclipse/icons/merged16/contact_saros_obj_followmode.png b/eclipse/icons/merged16/contact_saros_obj_followmode.png new file mode 100644 index 0000000000..b2bd1f95ef Binary files /dev/null and b/eclipse/icons/merged16/contact_saros_obj_followmode.png differ diff --git a/eclipse/icons/merged16/contact_saros_obj_readonly.png b/eclipse/icons/merged16/contact_saros_obj_readonly.png new file mode 100644 index 0000000000..b44c2b5a98 Binary files /dev/null and b/eclipse/icons/merged16/contact_saros_obj_readonly.png differ diff --git a/eclipse/icons/merged16/user_saros_followmode_disabled.png b/eclipse/icons/merged16/user_saros_followmode_disabled.png new file mode 100644 index 0000000000..f40066126f Binary files /dev/null and b/eclipse/icons/merged16/user_saros_followmode_disabled.png differ diff --git a/eclipse/icons/merged16/user_saros_followmode_enabled.png b/eclipse/icons/merged16/user_saros_followmode_enabled.png new file mode 100644 index 0000000000..720965ae37 Binary files /dev/null and b/eclipse/icons/merged16/user_saros_followmode_enabled.png differ diff --git a/eclipse/plugin.xml b/eclipse/plugin.xml index 28d01713c5..24b6d1c78c 100644 --- a/eclipse/plugin.xml +++ b/eclipse/plugin.xml @@ -2,34 +2,12 @@ - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eclipse/src/saros/Saros.java b/eclipse/src/saros/Saros.java index 9d9edc6ab5..b7adbb1e29 100644 --- a/eclipse/src/saros/Saros.java +++ b/eclipse/src/saros/Saros.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.InputStream; import java.util.concurrent.atomic.AtomicBoolean; +import javax.inject.Inject; import org.apache.log4j.Logger; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.ConfigurationSource; @@ -11,12 +12,16 @@ import org.apache.logging.log4j.status.StatusLogger; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.ConfigurationScope; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.ui.di.UIEventTopic; +import org.eclipse.e4.ui.workbench.UIEvents; import org.eclipse.swt.SWTException; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchListener; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; +import org.osgi.service.event.Event; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; import saros.annotations.Component; @@ -130,10 +135,17 @@ public void start(BundleContext context) throws Exception { isLifecycleStarted = true; - getWorkbench().addWorkbenchListener(workbenchShutdownListener); isInitialized = true; } + @Inject + @Optional + public void applicationStarted( + @UIEventTopic(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE) Event event, Saros saros) { + + saros.getWorkbench().addWorkbenchListener(saros.workbenchShutdownListener); + } + @Override public void stop(BundleContext context) throws Exception { diff --git a/eclipse/src/saros/StartupSaros.java b/eclipse/src/saros/StartupSaros.java index a4a1dad43a..801d6b7eb0 100644 --- a/eclipse/src/saros/StartupSaros.java +++ b/eclipse/src/saros/StartupSaros.java @@ -1,88 +1,129 @@ package saros; +import java.util.List; +import javax.annotation.PostConstruct; import org.apache.log4j.Logger; -import org.eclipse.ui.IStartup; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.intro.IIntroManager; -import org.eclipse.ui.intro.IIntroPart; +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.e4.ui.model.application.MApplication; +import org.eclipse.e4.ui.model.application.ui.MElementContainer; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainer; +import org.eclipse.e4.ui.model.application.ui.basic.MPartStack; +import org.eclipse.e4.ui.model.application.ui.basic.MWindow; +import org.eclipse.e4.ui.workbench.UIEvents; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.EPartService; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; import saros.account.XMPPAccountStore; import saros.preferences.Preferences; import saros.repackaged.picocontainer.annotations.Inject; import saros.ui.util.SWTUtils; -import saros.ui.util.ViewUtils; import saros.ui.util.WizardUtils; import saros.ui.util.XMPPConnectionSupport; /** - * An instance of this class is instantiated when Eclipse starts, after the Saros plugin has been - * started. + * An instance of this class is instantiated when Eclipse starts, after the + * Saros plugin has been started. * - *

{@link #earlyStartup()} is called after the workbench is initialized. + *

+ * {@link #earlyStartup()} is called after the workbench is initialized. */ -public class StartupSaros implements IStartup { +public class StartupSaros { - private static final Logger log = Logger.getLogger(StartupSaros.class); + private static final Logger log = Logger.getLogger(StartupSaros.class); - @Inject private Preferences preferences; + @Inject + private Preferences preferences; - @Inject private XMPPAccountStore xmppAccountStore; - - public StartupSaros() { - SarosPluginContext.initComponent(this); - } - - /* - * Once the workbench is started, the method earlyStartup() will be called - * from a separate thread - */ - - @Override - public void earlyStartup() { - - if (xmppAccountStore.isEmpty()) SWTUtils.runSafeSWTAsync(log, StartupSaros::openSarosView); - - Integer testmode = Integer.getInteger("saros.testmode"); - - if (testmode != null) return; - - /* - * Only show the Configuration Wizard if no accounts are configured. If - * Saros is already configured, do not show the tutorial because the - * user is probably already experienced. - */ + @Inject + private XMPPAccountStore xmppAccountStore; /* - * TODO first display a dialog if the user wants to get some help. Afterwards open this wizard - * and maybe also open a web site with getting started? + * Once the workbench is started, the method earlyStartup() will be called + * from a separate thread */ - if (xmppAccountStore.isEmpty()) { - SWTUtils.runSafeSWTAsync(log, WizardUtils::openSarosConfigurationWizard); - return; + @PostConstruct + public void earlyStartup(IEventBroker eb, EPartService partService, + EModelService service, MApplication app) { + SarosPluginContext.initComponent(this); + + eb.subscribe(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE, + new EventHandler() { + + @Override + public void handleEvent(Event event) { + + // Create the View + MPart sarosView = partService + .createPart("saros.ui.views.SarosView"); + MWindow mainWindow = app.getChildren().get(0); + + List parts = service.findElements(mainWindow, + "bottomRight", MPartStack.class, null); + + if (parts.size() > 0) { + MPartStack partStackSaros = service + .createModelElement(MPartStack.class); + partStackSaros.getChildren().add(sarosView); + MPartSashContainer partSashContainer = service + .createModelElement(MPartSashContainer.class); + MPartStack partStackBottomRight = parts.get(0); + MElementContainer parent = partStackBottomRight + .getParent(); + parent.getChildren().remove(partStackBottomRight); + partSashContainer.getChildren() + .add(partStackBottomRight); + partSashContainer.getChildren().add(partStackSaros); + partSashContainer.setHorizontal(true); + parent.getChildren().add(partSashContainer); + } + + Integer testmode = Integer.getInteger("saros.testmode"); + + if (testmode != null) + return; + + /* + * Only show the Configuration Wizard if no accounts are + * configured. If Saros is already configured, do not show + * the tutorial because the user is probably already + * experienced. + */ + + /* + * TODO first display a dialog if the user wants to get some + * help. Afterwards open this wizard and maybe also open a + * web site with getting started? + */ + + if (xmppAccountStore.isEmpty()) { + SWTUtils.runSafeSWTAsync(log, + WizardUtils::openSarosConfigurationWizard); + return; + } + + /* + * HACK workaround for + * http://sourceforge.net/p/dpp/bugs/782/ Perform connecting + * after the view is created so that the necessary GUI + * elements for the chat have already installed their + * listeners. + * + * FIXME This will not work if the view is not created on + * startup ! + */ + + if (preferences.isAutoConnecting() + && xmppAccountStore.getDefaultAccount() != null) + SWTUtils.runSafeSWTAsync(log, + () -> XMPPConnectionSupport.getInstance() + .connect(true)); + + eb.unsubscribe(this); + } + }); } - - /* - * HACK workaround for http://sourceforge.net/p/dpp/bugs/782/ - * Perform connecting after the view is created so that the - * necessary GUI elements for the chat have already installed - * their listeners. - * - * FIXME This will not work if the view is not created on - * startup ! - */ - - if (preferences.isAutoConnecting() && xmppAccountStore.getDefaultAccount() != null) - SWTUtils.runSafeSWTAsync(log, () -> XMPPConnectionSupport.getInstance().connect(true)); - } - - private static void openSarosView() { - - IIntroManager m = PlatformUI.getWorkbench().getIntroManager(); - IIntroPart i = m.getIntro(); - /* - * if there is a welcome screen, do not open the SarosView - * because it would be maximized and hiding the workbench window. - */ - if (i == null) ViewUtils.openSarosView(); - } } diff --git a/eclipse/src/saros/ui/actions/ChangeXMPPAccountAction.java b/eclipse/src/saros/ui/actions/ChangeXMPPAccountAction.java deleted file mode 100644 index 950961cd94..0000000000 --- a/eclipse/src/saros/ui/actions/ChangeXMPPAccountAction.java +++ /dev/null @@ -1,255 +0,0 @@ -package saros.ui.actions; - -import java.util.List; -import org.apache.log4j.Logger; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.ActionContributionItem; -import org.eclipse.jface.action.IMenuCreator; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.MenuItem; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.handlers.IHandlerService; -import saros.SarosPluginContext; -import saros.account.IAccountStoreListener; -import saros.account.XMPPAccount; -import saros.account.XMPPAccountStore; -import saros.communication.connection.ConnectionHandler; -import saros.communication.connection.IConnectionStateListener; -import saros.net.ConnectionState; -import saros.net.xmpp.JID; -import saros.repackaged.picocontainer.annotations.Inject; -import saros.ui.ImageManager; -import saros.ui.Messages; -import saros.ui.util.SWTUtils; -import saros.ui.util.WizardUtils; -import saros.ui.util.XMPPConnectionSupport; - -/** - * In addition to the connect/disconnect action, this allows the user to switch between accounts. - */ -public class ChangeXMPPAccountAction extends Action implements IMenuCreator, Disposable { - - public static final String ACTION_ID = ChangeXMPPAccountAction.class.getName(); - - private static final Logger log = Logger.getLogger(ChangeXMPPAccountAction.class); - - private Menu accountMenu; - - @Inject private XMPPAccountStore accountService; - - @Inject private ConnectionHandler connectionHandler; - - private boolean isConnectionError; - - private boolean defaultAccountChanged; - - private final IConnectionStateListener connectionStateListener = - (state, error) -> SWTUtils.runSafeSWTAsync(log, () -> updateStatus(state)); - - private final IAccountStoreListener accountStoreListener = - new IAccountStoreListener() { - @Override - public void activeAccountChanged(final XMPPAccount activeAccount) { - defaultAccountChanged = true; - } - }; - - public ChangeXMPPAccountAction() { - SarosPluginContext.initComponent(this); - - setText(Messages.ChangeXMPPAccountAction_connect); - setId(ACTION_ID); - - connectionHandler.addConnectionStateListener(connectionStateListener); - setMenuCreator(this); - updateStatus(connectionHandler.getConnectionState()); - - accountService.addListener(accountStoreListener); - } - - @Override - public void run() { - - if (connectionHandler.isConnected()) { - XMPPConnectionSupport.getInstance().disconnect(); - return; - } - - final XMPPAccount lastUsedAccount = XMPPConnectionSupport.getInstance().getCurrentXMPPAccount(); - - final List accounts = accountService.getAllAccounts(); - - final boolean exists = accounts.indexOf(lastUsedAccount) != -1; - - final XMPPAccount defaultAccount = accountService.getDefaultAccount(); - - final boolean isEmpty = accountService.isEmpty(); - - if (!exists && (defaultAccount == null || isEmpty)) { - if (!MessageDialog.openQuestion( - SWTUtils.getShell(), - "Default account missing", - "A default account has not been set yet. Do you want set a default account?")) return; - - SWTUtils.runSafeSWTAsync(log, this::openPreferences); - return; - } - - final XMPPAccount accountToConnect; - - if (defaultAccountChanged || !exists) { - defaultAccountChanged = false; - accountToConnect = defaultAccount; - } else { - accountToConnect = lastUsedAccount; - } - - XMPPConnectionSupport.getInstance().connect(accountToConnect, false, false); - } - - @Override - public void dispose() { - connectionHandler.removeConnectionStateListener(connectionStateListener); - accountService.removeListener(accountStoreListener); - } - - @Override - public Menu getMenu(Menu parent) { - return null; - } - - @Override - public Menu getMenu(Control parent) { - accountMenu = new Menu(parent); - - final List accounts = accountService.getAllAccounts(); - - final String connectionId = connectionHandler.getConnectionID(); - - if (connectionHandler.isConnected() && connectionId != null) { - - final JID jid = new JID(connectionId); - - /* - * TODO this may filter out too much but this situation is somewhat rare (multiple accounts - * with same name and domain but different server - */ - - accounts.removeIf( - a -> - a.getUsername().equalsIgnoreCase(jid.getName()) - && a.getDomain().equalsIgnoreCase(jid.getDomain())); - } - - accounts.forEach(this::addMenuItem); - - new MenuItem(accountMenu, SWT.SEPARATOR); - - addActionToMenu( - accountMenu, - new Action(Messages.ChangeXMPPAccountAction_add_account) { - @Override - public void run() { - WizardUtils.openAddXMPPAccountWizard(); - } - }); - - addActionToMenu( - accountMenu, - new Action(Messages.ChangeXMPPAccountAction_configure_account) { - @Override - public void run() { - openPreferences(); - } - }); - return accountMenu; - } - - private void addMenuItem(final XMPPAccount account) { - // The additional @ is needed because @ has special meaning in - // Action#setText(), see JavaDoc of Action(). - - String accountText = account.getUsername() + "@" + account.getDomain() + "@"; - Action action = - new Action(accountText) { - - @Override - public void run() { - defaultAccountChanged = false; - XMPPConnectionSupport.getInstance().connect(account, false, false); - } - }; - - addActionToMenu(accountMenu, action); - } - - private void addActionToMenu(Menu parent, Action action) { - ActionContributionItem item = new ActionContributionItem(action); - item.fill(parent, -1); - } - - private void updateStatus(ConnectionState state) { - try { - switch (state) { - case CONNECTED: - isConnectionError = false; - setText(Messages.ChangeXMPPAccountAction_disconnect); - setImageDescriptor( - ImageManager.getImageDescriptor("/icons/elcl16/xmpp_disconnect_tsk.png")); - break; - case CONNECTING: - isConnectionError = false; - setText(Messages.ChangeXMPPAccountAction_connecting); - setDisabledImageDescriptor( - ImageManager.getImageDescriptor("/icons/elcl16/xmpp_connecting_misc.png")); - break; - case ERROR: - isConnectionError = true; - setImageDescriptor( - ImageManager.getImageDescriptor("/icons/elcl16/xmpp_connection_error_misc.png")); - break; - case NOT_CONNECTED: - setText(Messages.ChangeXMPPAccountAction_connect); - - if (!isConnectionError) - setImageDescriptor( - ImageManager.getImageDescriptor("/icons/elcl16/xmpp_connect_tsk.png")); - - break; - case DISCONNECTING: - default: - isConnectionError = false; - setText(Messages.ChangeXMPPAccountAction_disconnecting); - setDisabledImageDescriptor( - ImageManager.getImageDescriptor("/icons/elcl16/xmpp_disconnecting_misc.png")); - break; - } - - setEnabled( - state == ConnectionState.CONNECTED - || state == ConnectionState.NOT_CONNECTED - || state == ConnectionState.ERROR); - - } catch (RuntimeException e) { - log.error("Internal error in ChangeXMPPAccountAction:", e); - } - } - - private void openPreferences() { - IHandlerService service = - PlatformUI.getWorkbench() - .getActiveWorkbenchWindow() - .getActivePage() - .getActivePart() - .getSite() - .getService(IHandlerService.class); - try { - service.executeCommand("saros.ui.commands.OpenSarosPreferences", null); - } catch (Exception e) { - log.debug("Could execute command", e); - } - } -} diff --git a/eclipse/src/saros/ui/actions/Disposable.java b/eclipse/src/saros/ui/actions/Disposable.java deleted file mode 100644 index d3ce20aeb6..0000000000 --- a/eclipse/src/saros/ui/actions/Disposable.java +++ /dev/null @@ -1,13 +0,0 @@ -package saros.ui.actions; - -import saros.ui.views.SarosView; - -public interface Disposable { - - /** - * Gets called when the {@link SarosView} is about to being disposed. Actions implementing this - * interface should release all resources and remove all installed listeners that were allocated - * and installed during the lifetime of the action. - */ - public void dispose(); -} diff --git a/eclipse/src/saros/ui/actions/JumpToUserWithWriteAccessPositionAction.java b/eclipse/src/saros/ui/actions/JumpToUserWithWriteAccessPositionAction.java deleted file mode 100644 index 1666906173..0000000000 --- a/eclipse/src/saros/ui/actions/JumpToUserWithWriteAccessPositionAction.java +++ /dev/null @@ -1,94 +0,0 @@ -package saros.ui.actions; - -import java.util.List; -import org.apache.log4j.Logger; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.PlatformUI; -import saros.SarosPluginContext; -import saros.annotations.Component; -import saros.editor.EditorManager; -import saros.repackaged.picocontainer.annotations.Inject; -import saros.session.ISarosSessionManager; -import saros.session.User; -import saros.ui.ImageManager; -import saros.ui.Messages; -import saros.ui.util.selection.SelectionUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; -import saros.util.ThreadUtils; - -/** Action which triggers the viewport of the local user to be changed to a local user's one. */ -@Component(module = "action") -public class JumpToUserWithWriteAccessPositionAction extends Action implements Disposable { - - public static final String ACTION_ID = JumpToUserWithWriteAccessPositionAction.class.getName(); - - private static final Logger log = Logger.getLogger(JumpToUserWithWriteAccessPositionAction.class); - - protected ISelectionListener selectionListener = - new ISelectionListener() { - @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { - updateEnablement(); - } - }; - - @Inject protected ISarosSessionManager sessionManager; - - @Inject protected EditorManager editorManager; - - public JumpToUserWithWriteAccessPositionAction() { - super(Messages.JumpToUserWithWriteAccessPositionAction_title); - - setId(ACTION_ID); - setToolTipText(Messages.JumpToUserWithWriteAccessPositionAction_tooltip); - setImageDescriptor(ImageManager.getImageDescriptor("icons/elcl16/jump.png")); // $NON-NLS-1$ - - SarosPluginContext.initComponent(this); - - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); - updateEnablement(); - } - - public void updateEnablement() { - try { - List participants = - SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); - setEnabled( - sessionManager.getSession() != null - && participants.size() == 1 - && !participants.get(0).equals(sessionManager.getSession().getLocalUser())); - } catch (NullPointerException e) { - this.setEnabled(false); - } catch (Exception e) { - if (!PlatformUI.getWorkbench().isClosing()) - log.error("Unexpected error while updating enablement", e); // $NON-NLS-1$ - } - } - - /** @review runSafe OK */ - @Override - public void run() { - ThreadUtils.runSafeSync( - log, - new Runnable() { - @Override - public void run() { - List participants = - SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); - if (participants.size() == 1) { - editorManager.jumpToUser(participants.get(0)); - } else { - log.warn("More than one participant selected."); // $NON-NLS-1$ - } - } - }); - } - - @Override - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); - } -} diff --git a/eclipse/src/saros/ui/actions/LeaveSessionAction.java b/eclipse/src/saros/ui/actions/LeaveSessionAction.java deleted file mode 100644 index f9dcb6f65f..0000000000 --- a/eclipse/src/saros/ui/actions/LeaveSessionAction.java +++ /dev/null @@ -1,93 +0,0 @@ -package saros.ui.actions; - -import org.eclipse.jface.action.Action; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.swt.graphics.ImageData; -import saros.SarosPluginContext; -import saros.annotations.Component; -import saros.repackaged.picocontainer.annotations.Inject; -import saros.session.ISarosSession; -import saros.session.ISarosSessionManager; -import saros.session.ISessionLifecycleListener; -import saros.session.SessionEndReason; -import saros.ui.ImageManager; -import saros.ui.Messages; -import saros.ui.util.CollaborationUtils; - -/** Leaves the current Saros session. Is deactivated if there is no running session. */ -@Component(module = "action") -public class LeaveSessionAction extends Action implements Disposable { - - public static final String ACTION_ID = LeaveSessionAction.class.getName(); - - @Inject private ISarosSessionManager sessionManager; - - private final ISessionLifecycleListener sessionLifecycleListener = - new ISessionLifecycleListener() { - @Override - public void sessionStarted(ISarosSession newSarosSession) { - updateEnablement(); - } - - @Override - public void sessionEnded(ISarosSession oldSarosSession, SessionEndReason reason) { - updateEnablement(); - } - }; - - public LeaveSessionAction() { - setId(ACTION_ID); - setToolTipText(Messages.LeaveSessionAction_leave_session_tooltip); - setImageDescriptor( - new ImageDescriptor() { - @Override - public ImageData getImageData() { - return ImageManager.ELCL_SESSION_LEAVE.getImageData(); - } - }); - - SarosPluginContext.initComponent(this); - sessionManager.addSessionLifecycleListener(sessionLifecycleListener); - updateEnablement(); - } - - @Override - public void run() { - CollaborationUtils.leaveSession(); - } - - @Override - public void dispose() { - sessionManager.removeSessionLifecycleListener(sessionLifecycleListener); - } - - private void updateEnablement() { - ISarosSession session = sessionManager.getSession(); - - if (session == null) { - setEnabled(false); - return; - } - - if (session.isHost()) { - setToolTipText(Messages.LeaveSessionAction_stop_session_tooltip); - setImageDescriptor( - new ImageDescriptor() { - @Override - public ImageData getImageData() { - return ImageManager.ELCL_SESSION_TERMINATE.getImageData(); - } - }); - } else { - setToolTipText(Messages.LeaveSessionAction_leave_session_tooltip); - setImageDescriptor( - new ImageDescriptor() { - @Override - public ImageData getImageData() { - return ImageManager.ELCL_SESSION_LEAVE.getImageData(); - } - }); - } - setEnabled(true); - } -} diff --git a/eclipse/src/saros/ui/actions/NewContactAction.java b/eclipse/src/saros/ui/actions/NewContactAction.java deleted file mode 100644 index bdd0b7a66c..0000000000 --- a/eclipse/src/saros/ui/actions/NewContactAction.java +++ /dev/null @@ -1,50 +0,0 @@ -package saros.ui.actions; - -import org.eclipse.jface.action.Action; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.swt.graphics.ImageData; -import saros.SarosPluginContext; -import saros.communication.connection.ConnectionHandler; -import saros.communication.connection.IConnectionStateListener; -import saros.net.ConnectionState; -import saros.repackaged.picocontainer.annotations.Inject; -import saros.ui.ImageManager; -import saros.ui.Messages; -import saros.ui.util.WizardUtils; - -public class NewContactAction extends Action implements Disposable { - - public static final String ACTION_ID = NewContactAction.class.getName(); - - private final IConnectionStateListener connectionListener = - (state, error) -> setEnabled(state == ConnectionState.CONNECTED); - - @Inject private ConnectionHandler connectionHandler; - - public NewContactAction() { - setId(ACTION_ID); - setToolTipText(Messages.NewContactAction_tooltip); - setImageDescriptor( - new ImageDescriptor() { - @Override - public ImageData getImageData() { - return ImageManager.ELCL_CONTACT_ADD.getImageData(); - } - }); - - SarosPluginContext.initComponent(this); - - connectionHandler.addConnectionStateListener(connectionListener); - setEnabled(connectionHandler.isConnected()); - } - - @Override - public void dispose() { - connectionHandler.removeConnectionStateListener(connectionListener); - } - - @Override - public void run() { - WizardUtils.openAddContactWizard(); - } -} diff --git a/eclipse/src/saros/ui/actions/OpenChatAction.java b/eclipse/src/saros/ui/actions/OpenChatAction.java deleted file mode 100644 index 5f43b66af6..0000000000 --- a/eclipse/src/saros/ui/actions/OpenChatAction.java +++ /dev/null @@ -1,98 +0,0 @@ -package saros.ui.actions; - -import java.util.List; -import java.util.Objects; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; -import saros.SarosPluginContext; -import saros.communication.chat.single.SingleUserChatService; -import saros.communication.connection.ConnectionHandler; -import saros.net.xmpp.JID; -import saros.repackaged.picocontainer.annotations.Inject; -import saros.session.User; -import saros.ui.ImageManager; -import saros.ui.Messages; -import saros.ui.model.session.UserElement; -import saros.ui.util.selection.SelectionUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; -import saros.ui.widgets.chat.ChatRoomsComposite; - -public class OpenChatAction extends Action implements Disposable { - - public static final String ACTION_ID = OpenChatAction.class.getName(); - - @Inject private ConnectionHandler connectionHandler; - @Inject private SingleUserChatService chatService; - - private ChatRoomsComposite chatRoomsComposite; - - private ISelectionListener selectionListener = - new ISelectionListener() { - @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { - updateEnablement(); - } - }; - - public OpenChatAction(ChatRoomsComposite chatRoomsComposite) { - super(Messages.OpenChatAction_MenuItem); - SarosPluginContext.initComponent(this); - this.chatRoomsComposite = chatRoomsComposite; - - setId(ACTION_ID); - setImageDescriptor(ImageManager.getImageDescriptor("icons/view16/chat_misc.png")); - - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); - - updateEnablement(); - } - - @Override - public void run() { - JID localJID = connectionHandler.getLocalJID(); - JID jid = getSelectedJID(); - - if (Objects.equals(localJID, jid)) return; - - chatRoomsComposite.openChat(chatService.createChat(jid), true); - } - - @Override - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); - } - - private void updateEnablement() { - if (!connectionHandler.isConnected()) { - setEnabled(false); - return; - } - - if (getSelectedJID() != null) { - setEnabled(true); - } - } - - private JID getSelectedJID() { - List users = - SelectionRetrieverFactory.getSelectionRetriever(UserElement.class).getSelection(); - List contacts = SelectionRetrieverFactory.getSelectionRetriever(JID.class).getSelection(); - - if (users.size() + contacts.size() == 1) { - if (users.size() == 1) { - User user = users.get(0).getUser(); - if (user == null) { - return null; - } - - return user.getJID(); - } else { - return contacts.get(0); - } - } - - return null; - } -} diff --git a/eclipse/src/saros/ui/actions/OpenPreferencesAction.java b/eclipse/src/saros/ui/actions/OpenPreferencesAction.java deleted file mode 100644 index ee4b7f6d2c..0000000000 --- a/eclipse/src/saros/ui/actions/OpenPreferencesAction.java +++ /dev/null @@ -1,42 +0,0 @@ -package saros.ui.actions; - -import org.apache.log4j.Logger; -import org.eclipse.jface.action.Action; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.handlers.IHandlerService; -import saros.ui.ImageManager; -import saros.ui.Messages; - -public class OpenPreferencesAction extends Action { - - public static final String ACTION_ID = OpenPreferencesAction.class.getName(); - - private static final Logger log = Logger.getLogger(OpenPreferencesAction.class); - - public OpenPreferencesAction() { - super(Messages.OpenPreferencesAction_title); - - setId(ACTION_ID); - setToolTipText(Messages.OpenPreferencesAction_tooltip); - setImageDescriptor(ImageManager.getImageDescriptor(ImageManager.ELCL_PREFERENCES_OPEN)); - setEnabled(true); - } - - @Override - public void run() { - IHandlerService service = - PlatformUI.getWorkbench() - .getActiveWorkbenchWindow() - .getActivePage() - .getActivePart() - .getSite() - .getService(IHandlerService.class); - try { - service.executeCommand( - "saros.ui.commands.OpenSarosPreferences", //$NON-NLS-1$ - null); - } catch (Exception e) { - log.error("Could not execute command", e); // $NON-NLS-1$ - } - } -} diff --git a/eclipse/src/saros/ui/actions/RequestSessionInviteAction.java b/eclipse/src/saros/ui/actions/RequestSessionInviteAction.java deleted file mode 100644 index 7ce6c2616e..0000000000 --- a/eclipse/src/saros/ui/actions/RequestSessionInviteAction.java +++ /dev/null @@ -1,77 +0,0 @@ -package saros.ui.actions; - -import java.util.List; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; -import saros.SarosPluginContext; -import saros.communication.extensions.JoinSessionRequestExtension; -import saros.net.ITransmitter; -import saros.net.xmpp.JID; -import saros.repackaged.picocontainer.annotations.Inject; -import saros.session.ISarosSession; -import saros.session.ISarosSessionManager; -import saros.ui.Messages; -import saros.ui.util.selection.SelectionUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; - -/** - * Action for requesting an invitation to a session from a contact. - * - *

This currently relies on the fact, that only Saros/S has a working JoinSessionRequestHandler. - * To make this feature generic in the future we need to add another XMPP namespace - */ -public class RequestSessionInviteAction extends Action implements Disposable { - - @Inject private ISarosSessionManager sessionManager; - @Inject private ITransmitter transmitter; - - private ISelectionListener selectionListener = - new ISelectionListener() { - @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { - updateActionState(); - } - }; - - public static final String ACTION_ID = RequestSessionInviteAction.class.getName(); - - public RequestSessionInviteAction() { - super(Messages.RequestSessionInviteAction_title); - setId(ACTION_ID); - SarosPluginContext.initComponent(this); - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); - updateActionState(); - } - - @Override - public void run() { - ISarosSession session = sessionManager.getSession(); - JID jid = getSelectedJID(); - if (session != null || jid == null) { - return; - } - - transmitter.sendPacketExtension( - jid, JoinSessionRequestExtension.PROVIDER.create(new JoinSessionRequestExtension())); - } - - private JID getSelectedJID() { - List selected = SelectionRetrieverFactory.getSelectionRetriever(JID.class).getSelection(); - - if (selected.size() != 1) return null; - - return selected.get(0); - } - - private void updateActionState() { - ISarosSession session = sessionManager.getSession(); - setEnabled(session == null && getSelectedJID() != null); - } - - @Override - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); - } -} diff --git a/eclipse/src/saros/ui/actions/SendFileAction.java b/eclipse/src/saros/ui/actions/SendFileAction.java deleted file mode 100644 index beb4c5e54c..0000000000 --- a/eclipse/src/saros/ui/actions/SendFileAction.java +++ /dev/null @@ -1,86 +0,0 @@ -package saros.ui.actions; - -import java.io.File; -import java.util.List; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.action.Action; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.PlatformUI; -import saros.net.xmpp.JID; -import saros.net.xmpp.contact.XMPPContact; -import saros.session.User; -import saros.ui.Messages; -import saros.ui.jobs.OutgoingFileTransferJob; -import saros.ui.util.SWTUtils; -import saros.ui.util.selection.SelectionUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; - -/** Action for sending a file over XMPP. */ -public class SendFileAction extends Action implements Disposable { - - public static final String ACTION_ID = SendFileAction.class.getName(); - - private ISelectionListener selectionListener = (part, selection) -> updateEnablement(); - - public SendFileAction() { - super(Messages.SendFileAction_title); - - setImageDescriptor( - PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FILE)); - setId(ACTION_ID); - setToolTipText(Messages.SendFileAction_tooltip); - - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); - - updateEnablement(); - } - - @Override - public void run() { - JID jid = getSelectedJID(); - if (jid == null) return; - - FileDialog fd = new FileDialog(SWTUtils.getShell(), SWT.OPEN); - fd.setText(Messages.SendFileAction_filedialog_text); - - String filename = fd.open(); - if (filename == null) return; - - File file = new File(filename); - if (file.isDirectory()) return; - - Job job = new OutgoingFileTransferJob(jid, file); - job.setUser(true); - job.schedule(); - } - - @Override - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); - } - - private void updateEnablement() { - setEnabled(getSelectedJID() != null); - } - - private JID getSelectedJID() { - List sessionUsers = - SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); - - List contacts = - SelectionRetrieverFactory.getSelectionRetriever(XMPPContact.class).getSelection(); - - // currently only one transfer per click (maybe improved later) - if (contacts.size() + sessionUsers.size() != 1) return null; - - if (sessionUsers.size() == 1) { - if (sessionUsers.get(0).isLocal()) return null; - return sessionUsers.get(0).getJID(); - } - - return contacts.get(0).getOnlineJid().orElse(null); - } -} diff --git a/eclipse/src/saros/ui/actions/SkypeAction.java b/eclipse/src/saros/ui/actions/SkypeAction.java deleted file mode 100644 index 167ddf23c7..0000000000 --- a/eclipse/src/saros/ui/actions/SkypeAction.java +++ /dev/null @@ -1,97 +0,0 @@ -package saros.ui.actions; - -import java.util.List; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.text.Region; -import org.eclipse.jface.text.hyperlink.URLHyperlink; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; -import saros.SarosPluginContext; -import saros.communication.SkypeManager; -import saros.net.xmpp.contact.XMPPContact; -import saros.repackaged.picocontainer.annotations.Inject; -import saros.ui.ImageManager; -import saros.ui.Messages; -import saros.ui.util.selection.SelectionUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; - -/** An action for starting a Skype Audio Session to other contacts. */ -public class SkypeAction extends Action implements Disposable { - - public static final String ACTION_ID = SkypeAction.class.getName(); - - private ISelectionListener selectionListener = - new ISelectionListener() { - @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { - updateEnablement(); - } - }; - - @Inject private SkypeManager skypeManager; - - public SkypeAction() { - super(Messages.SkypeAction_title); - - SarosPluginContext.initComponent(this); - - setId(ACTION_ID); - setToolTipText(Messages.SkypeAction_tooltip); - setImageDescriptor( - new ImageDescriptor() { - @Override - public ImageData getImageData() { - return ImageManager.ELCL_CONTACT_SKYPE_CALL.getImageData(); - } - }); - - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); - updateEnablement(); - } - - private void updateEnablement() { - - setEnabled(false); - - final List contacts = - SelectionRetrieverFactory.getSelectionRetriever(XMPPContact.class).getSelection(); - - if (contacts.size() != 1) return; - - final String skypeName = skypeManager.getSkypeName(contacts.get(0)); - - setEnabled( - SkypeManager.isSkypeAvailable(false) - && skypeName != null - && !SkypeManager.isEchoService(skypeName)); - } - - @Override - public void run() { - - final List participants = - SelectionRetrieverFactory.getSelectionRetriever(XMPPContact.class).getSelection(); - - if (participants.size() != 1) return; - - final String skypeName = skypeManager.getSkypeName(participants.get(0)); - - if (skypeName == null || SkypeManager.isEchoService(skypeName)) return; - - final String uri = SkypeManager.getAudioCallUri(skypeName); - - if (uri == null) return; - - final URLHyperlink link = new URLHyperlink(new Region(0, 0), uri); - - link.open(); - } - - @Override - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); - } -} diff --git a/eclipse/src/saros/ui/actions/package-info.java b/eclipse/src/saros/ui/actions/package-info.java deleted file mode 100644 index d46ef64b81..0000000000 --- a/eclipse/src/saros/ui/actions/package-info.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * - * - *

Actions Overview

- * - * This package contains all possible actions in the saros view which a user can initiate. - * - *

This package comprises of the following subpackages: - * - *

    - *
  • the {@link saros.ui.actions.ChangeColorAction} allows the user to change his personal color - * which is also shown to all other session users. - *
  • the {@link saros.ui.actions.ChangeXMPPAccountAction} allows the user to switch between - * several accounts - *
  • the {@link saros.ui.actions.ConsistencyAction} calls {@link - * saros.concurrent.watchdog.ConsistencyWatchdogClient} and if an inconsistency is found, the - * Action gives you the possibility to resolve it. - *
  • the {@link saros.ui.actions.DeleteContactAction} allows the user to delete other contacts - * from his contact list. - *
  • the {@link saros.ui.actions.FollowModeAction} allows the user to follow the first person in - * the session which has {@link saros.session.User.Permission#WRITE_ACCESS}. Activated through - * toolbar-button. - *
  • the {@link saros.ui.actions.FollowThisPersonAction} allow to follow a selected session - * user. - *
  • the {@link saros.ui.actions.ChangeWriteAccessAction} is responsible for grant or revoke - * {@link saros.session.User.Permission#WRITE_ACCESS} to a non-host session user. - *
  • the {@link saros.ui.actions.JumpToUserWithWriteAccessPositionAction} allows the user to - * jump to a selected session user current viewpoint - *
  • the {@link saros.ui.actions.LeaveSessionAction} allows the user to leave a session. - *
  • the {@link saros.ui.actions.NewContactAction} allows to add a new contact to the contact - * list. - *
  • the {@link saros.ui.actions.RenameContactAction} allows to rename a contact in the contact - * list. - *
  • the {@link saros.ui.actions.SendFileAction} allows a user to send a file to a session user. - *
  • the {@link saros.ui.actions.SkypeAction} calls the {@link saros.communication.SkypeManager} - * to call a contact for Skype. - *
- */ -package saros.ui.actions; diff --git a/eclipse/src/saros/ui/command_handlers/AddContactHandler.java b/eclipse/src/saros/ui/command_handlers/AddContactHandler.java deleted file mode 100644 index f7b27fed3c..0000000000 --- a/eclipse/src/saros/ui/command_handlers/AddContactHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -package saros.ui.command_handlers; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import saros.ui.util.WizardUtils; - -public class AddContactHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - WizardUtils.openAddContactWizard(); - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/AddXMPPAccountHandler.java b/eclipse/src/saros/ui/command_handlers/AddXMPPAccountHandler.java deleted file mode 100644 index 62f228759b..0000000000 --- a/eclipse/src/saros/ui/command_handlers/AddXMPPAccountHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -package saros.ui.command_handlers; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import saros.ui.util.WizardUtils; - -public class AddXMPPAccountHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - WizardUtils.openAddXMPPAccountWizard(); - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/CreateXMPPAccountHandler.java b/eclipse/src/saros/ui/command_handlers/CreateXMPPAccountHandler.java deleted file mode 100644 index eee81f8206..0000000000 --- a/eclipse/src/saros/ui/command_handlers/CreateXMPPAccountHandler.java +++ /dev/null @@ -1,17 +0,0 @@ -package saros.ui.command_handlers; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import saros.ui.util.WizardUtils; - -public class CreateXMPPAccountHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - - WizardUtils.openCreateXMPPAccountWizard(true); - - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/GettingStartedHandler.java b/eclipse/src/saros/ui/command_handlers/GettingStartedHandler.java deleted file mode 100644 index 9dc9a9cc1b..0000000000 --- a/eclipse/src/saros/ui/command_handlers/GettingStartedHandler.java +++ /dev/null @@ -1,18 +0,0 @@ -package saros.ui.command_handlers; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import saros.ui.util.SWTUtils; - -public class GettingStartedHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - - SWTUtils.openInternalBrowser( - "https://www.saros-project.org/documentation/getting-started.html", "Welcome to Saros"); - - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/OpenSarosPreferencesHandler.java b/eclipse/src/saros/ui/command_handlers/OpenSarosPreferencesHandler.java deleted file mode 100644 index 1ff118f79d..0000000000 --- a/eclipse/src/saros/ui/command_handlers/OpenSarosPreferencesHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package saros.ui.command_handlers; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.preference.PreferenceDialog; -import org.eclipse.ui.dialogs.PreferencesUtil; - -public class OpenSarosPreferencesHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - PreferenceDialog pref = - PreferencesUtil.createPreferenceDialogOn(null, "saros.preferences", null, null); - if (pref != null) pref.open(); - - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/SessionAddContactsHandler.java b/eclipse/src/saros/ui/command_handlers/SessionAddContactsHandler.java deleted file mode 100644 index 0b62b50e27..0000000000 --- a/eclipse/src/saros/ui/command_handlers/SessionAddContactsHandler.java +++ /dev/null @@ -1,22 +0,0 @@ -package saros.ui.command_handlers; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import saros.net.xmpp.JID; -import saros.session.ISarosSession; -import saros.ui.util.WizardUtils; -import saros.ui.wizards.AddResourcesToSessionWizard; - -/** - * Handles the addition of {@link JID}s that must explicitly be selected in the opening {@link - * AddResourcesToSessionWizard} to the running {@link ISarosSession}. - */ -public class SessionAddContactsHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - WizardUtils.openAddContactsToSessionWizard(); - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/SessionAddResourcesHandler.java b/eclipse/src/saros/ui/command_handlers/SessionAddResourcesHandler.java deleted file mode 100644 index 81f60f2564..0000000000 --- a/eclipse/src/saros/ui/command_handlers/SessionAddResourcesHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -package saros.ui.command_handlers; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.resources.IResource; -import saros.session.ISarosSession; -import saros.ui.util.WizardUtils; -import saros.ui.wizards.AddResourcesToSessionWizard; - -/** - * Handles the addition of {@link IResource}s that must explicitly be selected in the opening {@link - * AddResourcesToSessionWizard} to the running {@link ISarosSession}. - * - *

This class is used to define the behavior of the saros menu entry to add reference points to a - * running session. - */ -public class SessionAddResourcesHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - WizardUtils.openAddResourcesToSessionWizard(null); - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/SessionAddSelectedContactsHandler.java b/eclipse/src/saros/ui/command_handlers/SessionAddSelectedContactsHandler.java deleted file mode 100644 index 3c1335fb0c..0000000000 --- a/eclipse/src/saros/ui/command_handlers/SessionAddSelectedContactsHandler.java +++ /dev/null @@ -1,23 +0,0 @@ -package saros.ui.command_handlers; - -import java.util.List; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import saros.net.xmpp.JID; -import saros.session.ISarosSession; -import saros.ui.util.CollaborationUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; - -/** Handles the addition of selected {@link JID}s to the running {@link ISarosSession}. */ -public class SessionAddSelectedContactsHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - - List jids = SelectionRetrieverFactory.getSelectionRetriever(JID.class).getSelection(); - - CollaborationUtils.addContactsToSession(jids); - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/SessionAddSelectedResourcesHandler.java b/eclipse/src/saros/ui/command_handlers/SessionAddSelectedResourcesHandler.java deleted file mode 100644 index 391f7c3556..0000000000 --- a/eclipse/src/saros/ui/command_handlers/SessionAddSelectedResourcesHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -package saros.ui.command_handlers; - -import java.util.HashSet; -import java.util.List; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.resources.IResource; -import saros.session.ISarosSession; -import saros.ui.util.WizardUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; - -/** - * Handles the addition of selected {@link IResource}s to the running {@link ISarosSession}. - * - *

An {@link saros.ui.wizards.AddResourcesToSessionWizard} is opened for this purpose with the - * currently selected resources preselected. - * - *

This class is used to define the behavior of the package explorer context menu entry to add - * reference points to a running session. - */ -public class SessionAddSelectedResourcesHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - - List selectedResources = - SelectionRetrieverFactory.getSelectionRetriever(IResource.class).getSelection(); - - WizardUtils.openAddResourcesToSessionWizard(new HashSet<>(selectedResources)); - - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/SessionLeaveHandler.java b/eclipse/src/saros/ui/command_handlers/SessionLeaveHandler.java deleted file mode 100644 index a0942cee0c..0000000000 --- a/eclipse/src/saros/ui/command_handlers/SessionLeaveHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -package saros.ui.command_handlers; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import saros.ui.util.CollaborationUtils; - -public class SessionLeaveHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - CollaborationUtils.leaveSession(); - return null; - } -} diff --git a/eclipse/src/saros/ui/command_handlers/StartSarosConfigurationHandler.java b/eclipse/src/saros/ui/command_handlers/StartSarosConfigurationHandler.java deleted file mode 100644 index df54518659..0000000000 --- a/eclipse/src/saros/ui/command_handlers/StartSarosConfigurationHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -package saros.ui.command_handlers; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import saros.ui.util.WizardUtils; - -public class StartSarosConfigurationHandler extends AbstractHandler { - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - WizardUtils.openSarosConfigurationWizard(); - return null; - } -} diff --git a/eclipse/src/saros/ui/handlers/menu/AddContactHandler.java b/eclipse/src/saros/ui/handlers/menu/AddContactHandler.java new file mode 100644 index 0000000000..baa3d2d12e --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/AddContactHandler.java @@ -0,0 +1,27 @@ +package saros.ui.handlers.menu; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import saros.SarosPluginContext; +import saros.communication.connection.ConnectionHandler; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.ui.util.WizardUtils; + +public class AddContactHandler { + @Inject private ConnectionHandler connectionHandler; + + public AddContactHandler() { + SarosPluginContext.initComponent(this); + } + + @Execute + public Object execute() { + WizardUtils.openAddContactWizard(); + return null; + } + + @CanExecute + public boolean canExecute() { + return connectionHandler.isConnected(); + } +} diff --git a/eclipse/src/saros/ui/handlers/menu/AddXMPPAccountHandler.java b/eclipse/src/saros/ui/handlers/menu/AddXMPPAccountHandler.java new file mode 100644 index 0000000000..9c3a4883c3 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/AddXMPPAccountHandler.java @@ -0,0 +1,13 @@ +package saros.ui.handlers.menu; + +import org.eclipse.e4.core.di.annotations.Execute; +import saros.ui.util.WizardUtils; + +public class AddXMPPAccountHandler { + + @Execute + public Object execute() { + WizardUtils.openAddXMPPAccountWizard(); + return null; + } +} diff --git a/eclipse/src/saros/ui/handlers/menu/CreateXMPPAccountHandler.java b/eclipse/src/saros/ui/handlers/menu/CreateXMPPAccountHandler.java new file mode 100644 index 0000000000..e816b5d629 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/CreateXMPPAccountHandler.java @@ -0,0 +1,15 @@ +package saros.ui.handlers.menu; + +import org.eclipse.e4.core.di.annotations.Execute; +import saros.ui.util.WizardUtils; + +public class CreateXMPPAccountHandler { + + @Execute + public Object execute() { + + WizardUtils.openCreateXMPPAccountWizard(true); + + return null; + } +} diff --git a/eclipse/src/saros/ui/handlers/menu/GettingStartedHandler.java b/eclipse/src/saros/ui/handlers/menu/GettingStartedHandler.java new file mode 100644 index 0000000000..0a272d55cc --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/GettingStartedHandler.java @@ -0,0 +1,14 @@ +package saros.ui.handlers.menu; + +import org.eclipse.e4.core.di.annotations.Execute; +import saros.ui.util.SWTUtils; + +public class GettingStartedHandler { + + @Execute + public void execute() { + + SWTUtils.openInternalBrowser( + "https://www.saros-project.org/documentation/getting-started.html", "Welcome to Saros"); + } +} diff --git a/eclipse/src/saros/ui/handlers/menu/OpenSarosPreferencesHandler.java b/eclipse/src/saros/ui/handlers/menu/OpenSarosPreferencesHandler.java new file mode 100644 index 0000000000..6bc3576779 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/OpenSarosPreferencesHandler.java @@ -0,0 +1,16 @@ +package saros.ui.handlers.menu; + +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.jface.preference.PreferenceDialog; +import org.eclipse.ui.dialogs.PreferencesUtil; + +public class OpenSarosPreferencesHandler { + + @Execute + public Object execute() { + PreferenceDialog pref = + PreferencesUtil.createPreferenceDialogOn(null, "saros.preferences", null, null); + if (pref != null) pref.open(); + return null; + } +} diff --git a/eclipse/src/saros/ui/handlers/menu/SessionAddContactsHandler.java b/eclipse/src/saros/ui/handlers/menu/SessionAddContactsHandler.java new file mode 100644 index 0000000000..5e3a98c0a4 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/SessionAddContactsHandler.java @@ -0,0 +1,36 @@ +package saros.ui.handlers.menu; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import saros.SarosPluginContext; +import saros.communication.connection.ConnectionHandler; +import saros.net.xmpp.JID; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSession; +import saros.session.ISarosSessionManager; +import saros.ui.util.WizardUtils; +import saros.ui.wizards.AddResourcesToSessionWizard; + +/** + * Handles the addition of {@link JID}s that must explicitly be selected in the opening {@link + * AddResourcesToSessionWizard} to the running {@link ISarosSession}. + */ +public class SessionAddContactsHandler { + @Inject private ConnectionHandler connectionHandler; + @Inject private ISarosSessionManager sessionManager; + + public SessionAddContactsHandler() { + SarosPluginContext.initComponent(this); + } + + @Execute + public Object execute() { + WizardUtils.openAddContactsToSessionWizard(); + return null; + } + + @CanExecute + public boolean canExecute() { + return connectionHandler.isConnected() && sessionManager.getSession() != null; + } +} diff --git a/eclipse/src/saros/ui/handlers/menu/SessionAddResourcesHandler.java b/eclipse/src/saros/ui/handlers/menu/SessionAddResourcesHandler.java new file mode 100644 index 0000000000..3df34b82ab --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/SessionAddResourcesHandler.java @@ -0,0 +1,40 @@ +package saros.ui.handlers.menu; + +import org.eclipse.core.resources.IResource; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import saros.SarosPluginContext; +import saros.communication.connection.ConnectionHandler; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSession; +import saros.session.ISarosSessionManager; +import saros.ui.util.WizardUtils; +import saros.ui.wizards.AddResourcesToSessionWizard; + +/** + * Handles the addition of {@link IResource}s that must explicitly be selected in the opening {@link + * AddResourcesToSessionWizard} to the running {@link ISarosSession}. + * + *

This class is used to define the behavior of the saros menu entry to add reference points to a + * running session. + */ +public class SessionAddResourcesHandler { + @Inject private ConnectionHandler connectionHandler; + @Inject private ISarosSessionManager sessionManager; + + public SessionAddResourcesHandler() { + SarosPluginContext.initComponent(this); + } + + @Execute + public Object execute() { + WizardUtils.openAddResourcesToSessionWizard(null); + return null; + } + + @CanExecute + public boolean canExecute() { + final ISarosSession session = sessionManager.getSession(); + return connectionHandler.isConnected() && session != null && session.hasWriteAccess(); + } +} diff --git a/eclipse/src/saros/ui/handlers/menu/SessionAddSelectedContactsHandler.java b/eclipse/src/saros/ui/handlers/menu/SessionAddSelectedContactsHandler.java new file mode 100644 index 0000000000..1144cd136d --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/SessionAddSelectedContactsHandler.java @@ -0,0 +1,53 @@ +package saros.ui.handlers.menu; + +import java.util.List; +import javax.inject.Named; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.jface.viewers.ISelection; +import saros.SarosPluginContext; +import saros.communication.connection.ConnectionHandler; +import saros.net.xmpp.JID; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSession; +import saros.session.ISarosSessionManager; +import saros.ui.util.CollaborationUtils; +import saros.ui.util.selection.SelectionUtils; + +/** Handles the addition of selected {@link JID}s to the running {@link ISarosSession}. */ +public class SessionAddSelectedContactsHandler { + + @Inject private ConnectionHandler connectionHandler; + @Inject private ISarosSessionManager sessionManager; + + public SessionAddSelectedContactsHandler() { + SarosPluginContext.initComponent(this); + } + + @Execute + public Object execute(@Named(IServiceConstants.ACTIVE_SELECTION) @Optional ISelection selection) { + + List jids = SelectionUtils.getAdaptableObjects(selection, JID.class); + + CollaborationUtils.addContactsToSession(jids); + return null; + } + + @CanExecute + public boolean canExecute( + @Named(IServiceConstants.ACTIVE_SELECTION) @Optional ISelection selection) { + final ISarosSession session = sessionManager.getSession(); + if (!(connectionHandler.isConnected() && session != null && session.hasWriteAccess())) { + return false; + } + List jids = SelectionUtils.getAdaptableObjects(selection, JID.class); + for (JID jid : jids) { + if (session.getUsers().stream().anyMatch(u -> u.getJID().equals(jid))) { + return false; + } + } + return true; + } +} diff --git a/eclipse/src/saros/ui/handlers/menu/SessionAddSelectedResourcesHandler.java b/eclipse/src/saros/ui/handlers/menu/SessionAddSelectedResourcesHandler.java new file mode 100644 index 0000000000..0426b896b6 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/SessionAddSelectedResourcesHandler.java @@ -0,0 +1,72 @@ +package saros.ui.handlers.menu; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.inject.Named; +import org.eclipse.core.resources.IResource; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.jface.viewers.ISelection; +import saros.SarosPluginContext; +import saros.communication.connection.ConnectionHandler; +import saros.filesystem.IReferencePoint; +import saros.filesystem.ResourceConverter; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSession; +import saros.session.ISarosSessionManager; +import saros.ui.util.WizardUtils; +import saros.ui.util.selection.SelectionUtils; + +/** + * Handles the addition of selected {@link IResource}s to the running {@link ISarosSession}. + * + *

An {@link saros.ui.wizards.AddResourcesToSessionWizard} is opened for this purpose with the + * currently selected resources preselected. + * + *

This class is used to define the behavior of the package explorer context menu entry to add + * reference points to a running session. + */ +public class SessionAddSelectedResourcesHandler { + @Inject private ConnectionHandler connectionHandler; + @Inject private ISarosSessionManager sessionManager; + + public SessionAddSelectedResourcesHandler() { + SarosPluginContext.initComponent(this); + } + + @Execute + public Object execute(@Named(IServiceConstants.ACTIVE_SELECTION) @Optional ISelection selection) { + + List selectedResources = + SelectionUtils.getAdaptableObjects(selection, IResource.class); + + WizardUtils.openAddResourcesToSessionWizard(new HashSet<>(selectedResources)); + + return null; + } + + @CanExecute + public boolean canExecute( + @Named(IServiceConstants.ACTIVE_SELECTION) @Optional ISelection selection) { + List resources = SelectionUtils.getAdaptableObjects(selection, IResource.class); + if (!(resources.size() > 0)) { + return false; + } + final ISarosSession session = sessionManager.getSession(); + if (!(connectionHandler.isConnected() && session != null && session.hasWriteAccess())) { + return false; + } + Set sharedReferencePoints = session.getReferencePoints(); + for (IResource resource : resources) { + saros.filesystem.IResource wrappedResource = + ResourceConverter.convertToResource(sharedReferencePoints, resource); + if (session.isShared(wrappedResource)) { + return false; + } + } + return true; + } +} diff --git a/eclipse/src/saros/ui/handlers/menu/SessionLeaveHandler.java b/eclipse/src/saros/ui/handlers/menu/SessionLeaveHandler.java new file mode 100644 index 0000000000..161fead514 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/SessionLeaveHandler.java @@ -0,0 +1,29 @@ +package saros.ui.handlers.menu; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import saros.SarosPluginContext; +import saros.communication.connection.ConnectionHandler; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSessionManager; +import saros.ui.util.CollaborationUtils; + +public class SessionLeaveHandler { + @Inject private ConnectionHandler connectionHandler; + @Inject private ISarosSessionManager sessionManager; + + public SessionLeaveHandler() { + SarosPluginContext.initComponent(this); + } + + @Execute + public Object execute() { + CollaborationUtils.leaveSession(); + return null; + } + + @CanExecute + public boolean canExecute() { + return connectionHandler.isConnected() && sessionManager.getSession() != null; + } +} diff --git a/eclipse/src/saros/ui/command_handlers/ShareResourcesHandler.java b/eclipse/src/saros/ui/handlers/menu/ShareResourcesHandler.java similarity index 53% rename from eclipse/src/saros/ui/command_handlers/ShareResourcesHandler.java rename to eclipse/src/saros/ui/handlers/menu/ShareResourcesHandler.java index 3220ba4292..3985d555b5 100644 --- a/eclipse/src/saros/ui/command_handlers/ShareResourcesHandler.java +++ b/eclipse/src/saros/ui/handlers/menu/ShareResourcesHandler.java @@ -1,12 +1,19 @@ -package saros.ui.command_handlers; +package saros.ui.handlers.menu; -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; +import javax.inject.Named; import org.eclipse.core.resources.IResource; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.jface.viewers.ISelection; +import saros.SarosPluginContext; +import saros.communication.connection.ConnectionHandler; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSessionManager; import saros.ui.menu_contributions.StartSessionWithProjects; import saros.ui.util.WizardUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; +import saros.ui.util.selection.SelectionUtils; /** * @JTourBusStop 1, Invitation Process: @@ -35,12 +42,24 @@ * *

Notice that this is done via the {@link saros.ui.wizards.StartSessionWizard}. */ -public class ShareResourcesHandler extends AbstractHandler { +public class ShareResourcesHandler { - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { + @Inject private ConnectionHandler connectionHandler; + @Inject private ISarosSessionManager sessionManager; + + public ShareResourcesHandler() { + SarosPluginContext.initComponent(this); + } + + @Execute + public Object execute(@Named(IServiceConstants.ACTIVE_SELECTION) @Optional ISelection selection) { WizardUtils.openStartSessionWizard( - SelectionRetrieverFactory.getSelectionRetriever(IResource.class).getSelection()); + SelectionUtils.getAdaptableObjects(selection, IResource.class)); return null; } + + @CanExecute + public boolean canExecute() { + return connectionHandler.isConnected() && sessionManager.getSession() == null; + } } diff --git a/eclipse/src/saros/ui/handlers/menu/StartSarosConfigurationHandler.java b/eclipse/src/saros/ui/handlers/menu/StartSarosConfigurationHandler.java new file mode 100644 index 0000000000..9285e12c55 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/menu/StartSarosConfigurationHandler.java @@ -0,0 +1,13 @@ +package saros.ui.handlers.menu; + +import org.eclipse.e4.core.di.annotations.Execute; +import saros.ui.util.WizardUtils; + +public class StartSarosConfigurationHandler { + + @Execute + public Object execute() { + WizardUtils.openSarosConfigurationWizard(); + return null; + } +} diff --git a/eclipse/src/saros/ui/command_handlers/package-info.java b/eclipse/src/saros/ui/handlers/menu/package-info.java similarity index 97% rename from eclipse/src/saros/ui/command_handlers/package-info.java rename to eclipse/src/saros/ui/handlers/menu/package-info.java index 7166e16d61..4579d531c0 100644 --- a/eclipse/src/saros/ui/command_handlers/package-info.java +++ b/eclipse/src/saros/ui/handlers/menu/package-info.java @@ -24,4 +24,4 @@ * href="http://help.eclipse.org/indigo/topic/org.eclipse.platform.doc.isv/guide/workbench_cmd_handlers.htm">plugin.xml * - org.eclipse.ui.handlers extension point */ -package saros.ui.command_handlers; +package saros.ui.handlers.menu; diff --git a/eclipse/src/saros/ui/actions/ChangeColorAction.java b/eclipse/src/saros/ui/handlers/popup/ChangeColorHandler.java similarity index 55% rename from eclipse/src/saros/ui/actions/ChangeColorAction.java rename to eclipse/src/saros/ui/handlers/popup/ChangeColorHandler.java index 59df904d56..09fa31b415 100644 --- a/eclipse/src/saros/ui/actions/ChangeColorAction.java +++ b/eclipse/src/saros/ui/handlers/popup/ChangeColorHandler.java @@ -1,23 +1,28 @@ -package saros.ui.actions; +package saros.ui.handlers.popup; import java.util.List; -import org.eclipse.jface.action.Action; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; import saros.SarosPluginContext; import saros.annotations.Component; import saros.repackaged.picocontainer.annotations.Inject; import saros.session.ISarosSession; import saros.session.ISarosSessionManager; import saros.session.User; -import saros.ui.ImageManager; import saros.ui.Messages; import saros.ui.util.SWTUtils; -import saros.ui.util.selection.SelectionUtils; import saros.ui.util.selection.retriever.SelectionRetrieverFactory; import saros.ui.wizards.ColorChooserWizard; @@ -27,49 +32,63 @@ * new color or abort the process */ @Component(module = "action") -public final class ChangeColorAction extends Action implements Disposable { +public final class ChangeColorHandler { - public static final String ACTION_ID = ChangeColorAction.class.getName(); + public static final String ID = ChangeColorHandler.class.getName(); private ISelectionListener selectionListener = new ISelectionListener() { + @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { + public void selectionChanged(MPart part, Object selection) { updateEnablement(); } }; @Inject private ISarosSessionManager sessionManager; - public ChangeColorAction() { - super(Messages.ChangeColorAction_title); + private MDirectMenuItem changeColorMenuItem; + + public ChangeColorHandler() { SarosPluginContext.initComponent(this); + } - setId(ACTION_ID); - setToolTipText(Messages.ChangeColorAction_tooltip); + @PostConstruct + public void postConstruct( + ESelectionService selectionService, EModelService modelService, MPart sarosView) { + selectionService.addSelectionListener(selectionListener); - setImageDescriptor( - ImageManager.getImageDescriptor("icons/elcl16/changecolor.png")); // $NON-NLS-1$ + MPopupMenu popupMenu = null; - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + MUIElement menuItem = modelService.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + changeColorMenuItem = (MDirectMenuItem) menuItem; + } updateEnablement(); } public void updateEnablement() { + if (changeColorMenuItem == null) return; + List participants = SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); ISarosSession session = sessionManager.getSession(); - setEnabled( + changeColorMenuItem.setEnabled( session != null && participants.size() == 1 && participants.get(0).equals(session.getLocalUser())); } - @Override - public void run() { + @Execute + public void execute() { ColorChooserWizard wizard = new ColorChooserWizard(); @@ -95,8 +114,8 @@ public void run() { Messages.ChangeColorAction_message_text); } - @Override - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); } } diff --git a/eclipse/src/saros/ui/actions/ChangeWriteAccessAction.java b/eclipse/src/saros/ui/handlers/popup/ChangeWriteAccessHandler.java similarity index 59% rename from eclipse/src/saros/ui/actions/ChangeWriteAccessAction.java rename to eclipse/src/saros/ui/handlers/popup/ChangeWriteAccessHandler.java index 44ee5edf72..170641ae38 100644 --- a/eclipse/src/saros/ui/actions/ChangeWriteAccessAction.java +++ b/eclipse/src/saros/ui/handlers/popup/ChangeWriteAccessHandler.java @@ -1,20 +1,26 @@ -package saros.ui.actions; +package saros.ui.handlers.popup; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.concurrent.CancellationException; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.apache.log4j.Logger; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.action.Action; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.ISelection; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; import saros.SarosPluginContext; import saros.repackaged.picocontainer.annotations.Inject; import saros.session.ISarosSession; @@ -24,46 +30,100 @@ import saros.session.SessionEndReason; import saros.session.User; import saros.session.User.Permission; -import saros.ui.ImageManager; import saros.ui.Messages; import saros.ui.util.SWTUtils; import saros.ui.util.selection.SelectionUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; import saros.util.ThreadUtils; /** * Change the write access of a session participant (granting write access, restricting to * read-only). */ -public class ChangeWriteAccessAction extends Action implements Disposable { +public class ChangeWriteAccessHandler { - private static final Logger log = Logger.getLogger(ChangeWriteAccessAction.class); + private static final Logger log = Logger.getLogger(ChangeWriteAccessHandler.class); public static final class WriteAccess { - public static final String ACTION_ID = - ChangeWriteAccessAction.class.getName() + "." + WriteAccess.class.getSimpleName(); - - public static ChangeWriteAccessAction newInstance() { - return new ChangeWriteAccessAction( - ACTION_ID, - Permission.WRITE_ACCESS, - Messages.GiveWriteAccessAction_title, - Messages.GiveWriteAccessAction_tooltip, - ImageManager.ICON_CONTACT_SAROS_SUPPORT); + public static final String ID = + ChangeWriteAccessHandler.class.getName() + "." + WriteAccess.class.getSimpleName(); + + private ChangeWriteAccessHandler handler; + + @PostConstruct + public void postConstruct( + ESelectionService selectionService, EModelService modelService, MPart sarosView) { + + MPopupMenu popupMenu = null; + + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + MUIElement menuItem = modelService.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + MDirectMenuItem changeWriteAccessItem = (MDirectMenuItem) menuItem; + handler = + new ChangeWriteAccessHandler( + Permission.WRITE_ACCESS, selectionService, changeWriteAccessItem); + } + } + + @Execute + public void execute() { + handler.execute(); + } + + @PreDestroy + public void preDestroy() { + handler.dispose(); + } + + @CanExecute + public boolean canExecute() { + return handler.canExecute(); } } public static final class ReadOnly { - public static final String ACTION_ID = - ChangeWriteAccessAction.class.getName() + "." + ReadOnly.class.getSimpleName(); - - public static ChangeWriteAccessAction newInstance() { - return new ChangeWriteAccessAction( - ACTION_ID, - Permission.READONLY_ACCESS, - Messages.RestrictToReadOnlyAccessAction_title, - Messages.RestrictToReadOnlyAccessAction_tooltip, - ImageManager.ICON_USER_SAROS_READONLY); + public static final String ID = + ChangeWriteAccessHandler.class.getName() + "." + ReadOnly.class.getSimpleName(); + + private ChangeWriteAccessHandler handler; + + @PostConstruct + public void postConstruct( + ESelectionService selectionService, EModelService modelService, MPart sarosView) { + + MPopupMenu popupMenu = null; + + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + MUIElement menuItem = modelService.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + MDirectMenuItem changeWriteAccessItem = (MDirectMenuItem) menuItem; + handler = + new ChangeWriteAccessHandler( + Permission.READONLY_ACCESS, selectionService, changeWriteAccessItem); + } + } + + @Execute + public void execute() { + handler.execute(); + } + + @PreDestroy + public void preDestroy() { + handler.dispose(); + } + + @CanExecute + public boolean canExecute() { + return handler.canExecute(); } } @@ -95,36 +155,25 @@ public void permissionChanged(User user) { private ISelectionListener selectionListener = new ISelectionListener() { + @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { + public void selectionChanged(MPart part, Object selection) { updateEnablement(); } }; - private ChangeWriteAccessAction( - final String id, - final Permission permission, - final String text, - final String tooltip, - final Image icon) { + private ESelectionService selectionService; + private MDirectMenuItem changeWriteAccessItem; - super(text); + private ChangeWriteAccessHandler( + final Permission permission, + ESelectionService selectionService, + MDirectMenuItem changeWriteAccessItem) { SarosPluginContext.initComponent(this); - - setId(id); - - setImageDescriptor( - new ImageDescriptor() { - @Override - public ImageData getImageData() { - return icon.getImageData(); - } - }); - - setToolTipText(tooltip); - this.permission = permission; + this.selectionService = selectionService; + this.changeWriteAccessItem = changeWriteAccessItem; /* * if SessionView is not "visible" on session start up this constructor @@ -138,29 +187,38 @@ public ImageData getImageData() { } sessionManager.addSessionLifecycleListener(sessionLifecycleListener); - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); + selectionService.addSelectionListener(selectionListener); updateEnablement(); } - private void updateEnablement() { + private boolean getEnabledState() { List participants = - SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), User.class); boolean sessionRunning = (sessionManager.getSession() != null); boolean selectedOneWithOppositePermission = (participants.size() == 1 && participants.get(0).getPermission() != permission); - setEnabled(sessionRunning && selectedOneWithOppositePermission); + return sessionRunning && selectedOneWithOppositePermission; + } + + private void updateEnablement() { + if (changeWriteAccessItem == null) return; + + changeWriteAccessItem.setEnabled(getEnabledState()); + } + + public boolean canExecute() { + return getEnabledState(); } - @Override public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); + selectionService.removeSelectionListener(selectionListener); sessionManager.removeSessionLifecycleListener(sessionLifecycleListener); } - @Override - public void run() { + public void execute() { ThreadUtils.runSafeSync( log, new Runnable() { @@ -171,7 +229,8 @@ public void run() { if (session == null) return; List participants = - SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), User.class); if (participants.size() == 1) { User selected = participants.get(0); if (selected.getPermission() != permission) { diff --git a/eclipse/src/saros/ui/actions/DeleteContactAction.java b/eclipse/src/saros/ui/handlers/popup/DeleteContactHandler.java similarity index 51% rename from eclipse/src/saros/ui/actions/DeleteContactAction.java rename to eclipse/src/saros/ui/handlers/popup/DeleteContactHandler.java index dc8e90d657..97f1b38d9f 100644 --- a/eclipse/src/saros/ui/actions/DeleteContactAction.java +++ b/eclipse/src/saros/ui/handlers/popup/DeleteContactHandler.java @@ -1,14 +1,26 @@ -package saros.ui.actions; +package saros.ui.handlers.popup; import java.text.MessageFormat; import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.apache.log4j.Logger; -import org.eclipse.jface.action.Action; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.workbench.UIEvents.UILifeCycle; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PlatformUI; +import org.eclipse.jface.viewers.ISelection; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; import saros.SarosPluginContext; import saros.communication.connection.ConnectionHandler; import saros.communication.connection.IConnectionStateListener; @@ -21,14 +33,13 @@ import saros.session.User; import saros.ui.Messages; import saros.ui.util.selection.SelectionUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; import saros.util.ThreadUtils; -public class DeleteContactAction extends Action implements Disposable { +public class DeleteContactHandler { - public static final String ACTION_ID = DeleteContactAction.class.getName(); + public static final String ID = DeleteContactHandler.class.getName(); - private static final Logger log = Logger.getLogger(DeleteContactAction.class); + private static final Logger log = Logger.getLogger(DeleteContactHandler.class); protected IConnectionStateListener connectionListener = (state, error) -> updateEnablement(); @@ -38,41 +49,82 @@ public class DeleteContactAction extends Action implements Disposable { @Inject private XMPPContactsService contactsService; @Inject private ISarosSessionManager sessionManager; + private MDirectMenuItem deleteContact; + private ESelectionService selectionService; + + private boolean workbenchIsClosing = false; + protected final String DELETE_ERROR_IN_SESSION = Messages.DeleteContactAction_delete_error_in_session; - public DeleteContactAction() { - super(Messages.DeleteContactAction_title); + public DeleteContactHandler() { + SarosPluginContext.initComponent(this); - setId(ACTION_ID); - setToolTipText(Messages.DeleteContactAction_tooltip); + connectionHandler.addConnectionStateListener(connectionListener); + } - IWorkbench workbench = PlatformUI.getWorkbench(); - setImageDescriptor( - workbench.getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_DELETE)); + @PostConstruct + public void postConstruct( + MPart sarosView, + EModelService modelService, + ESelectionService selectionService, + IEventBroker eb) { + this.selectionService = selectionService; + MPopupMenu popupMenu = null; + + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + MUIElement menuItem = modelService.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + deleteContact = (MDirectMenuItem) menuItem; + } - SarosPluginContext.initComponent(this); + eb.subscribe( + UILifeCycle.APP_SHUTDOWN_STARTED, + new EventHandler() { + + @Override + public void handleEvent(Event event) { + workbenchIsClosing = true; + } + }); + + selectionService.addSelectionListener(selectionListener); - connectionHandler.addConnectionStateListener(connectionListener); - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); updateEnablement(); } + @CanExecute + public boolean canExecute() { + return getEnabledState(); + } + + private boolean getEnabledState() { + List contacts = + SelectionUtils.getAdaptableObjects((ISelection) selectionService.getSelection(), JID.class); + + return connectionHandler.isConnected() && contacts.size() == 1; + } + protected void updateEnablement() { + if (deleteContact == null) { + return; + } try { - List contacts = - SelectionRetrieverFactory.getSelectionRetriever(JID.class).getSelection(); - this.setEnabled(connectionHandler.isConnected() && contacts.size() == 1); + deleteContact.setEnabled(getEnabledState()); } catch (NullPointerException e) { - this.setEnabled(false); + deleteContact.setEnabled(false); } catch (Exception e) { - if (!PlatformUI.getWorkbench().isClosing()) + if (!workbenchIsClosing) log.error("Unexpected error while updating enablement", e); // $NON-NLS-1$ } } /** @review runSafe OK */ - @Override + @Execute public void run() { ThreadUtils.runSafeSync( log, @@ -87,7 +139,8 @@ public void run() { public void runDeleteAction() { XMPPContact contact = null; List selectedRosterEntries = - SelectionRetrieverFactory.getSelectionRetriever(XMPPContact.class).getSelection(); + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), XMPPContact.class); if (selectedRosterEntries.size() == 1) { contact = selectedRosterEntries.get(0); } @@ -122,9 +175,9 @@ public void runDeleteAction() { } } - @Override - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); connectionHandler.removeConnectionStateListener(connectionListener); } } diff --git a/eclipse/src/saros/ui/actions/FollowThisPersonAction.java b/eclipse/src/saros/ui/handlers/popup/FollowThisPersonHandler.java similarity index 59% rename from eclipse/src/saros/ui/actions/FollowThisPersonAction.java rename to eclipse/src/saros/ui/handlers/popup/FollowThisPersonHandler.java index 8b86bcc0af..c5758f8e69 100644 --- a/eclipse/src/saros/ui/actions/FollowThisPersonAction.java +++ b/eclipse/src/saros/ui/handlers/popup/FollowThisPersonHandler.java @@ -1,13 +1,19 @@ -package saros.ui.actions; +package saros.ui.handlers.popup; import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.apache.log4j.Logger; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; import org.eclipse.jface.viewers.ISelection; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; import saros.SarosPluginContext; import saros.annotations.Component; import saros.editor.FollowModeManager; @@ -18,20 +24,18 @@ import saros.session.ISessionLifecycleListener; import saros.session.SessionEndReason; import saros.session.User; -import saros.ui.ImageManager; import saros.ui.Messages; import saros.ui.util.SWTUtils; import saros.ui.util.selection.SelectionUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; import saros.util.ThreadUtils; /** This follow mode action is used to select the person to follow. */ @Component(module = "action") -public class FollowThisPersonAction extends Action implements Disposable { +public class FollowThisPersonHandler { - public static final String ACTION_ID = FollowThisPersonAction.class.getName(); + public static final String ID = FollowThisPersonHandler.class.getName(); - private static final Logger log = Logger.getLogger(FollowThisPersonAction.class); + private static final Logger log = Logger.getLogger(FollowThisPersonHandler.class); protected ISessionLifecycleListener sessionLifecycleListener = new ISessionLifecycleListener() { @@ -70,8 +74,9 @@ public void startedFollowing(User target) { protected ISelectionListener selectionListener = new ISelectionListener() { + @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { + public void selectionChanged(MPart part, Object selection) { updateActionEnablement(); } }; @@ -80,38 +85,47 @@ public void selectionChanged(IWorkbenchPart part, ISelection selection) { private FollowModeManager followModeManager; - public FollowThisPersonAction() { - super(Messages.FollowThisPersonAction_follow_title); + private ESelectionService selectionService; + private MDirectMenuItem followThisPersonMenuItem; + public FollowThisPersonHandler() { SarosPluginContext.initComponent(this); + } - setImageDescriptor( - new ImageDescriptor() { - @Override - public ImageData getImageData() { - return ImageManager.ICON_USER_SAROS_FOLLOWMODE.getImageData(); - } - }); + @PostConstruct + public void postConstruct( + ESelectionService selectionService, MPart sarosView, EModelService modelService) { + this.selectionService = selectionService; + + MPopupMenu popupMenu = null; - setToolTipText(Messages.FollowThisPersonAction_follow_tooltip); - setId(ACTION_ID); + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + MUIElement menuItem = modelService.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + followThisPersonMenuItem = (MDirectMenuItem) menuItem; + } sessionManager.addSessionLifecycleListener(sessionLifecycleListener); - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); + selectionService.addSelectionListener(selectionListener); updateEnablement(); } /** @review runSafe OK */ - @Override - public void run() { + @Execute + public void execute() { ThreadUtils.runSafeSync( log, new Runnable() { @Override public void run() { List users = - SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), User.class); if (!canBeExecuted(users)) { log.warn( @@ -142,22 +156,24 @@ public void run() { protected void updateEnablement() { - List users = SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); + List users = + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), User.class); if (!canBeExecuted(users)) { - setEnabled(false); + followThisPersonMenuItem.setEnabled(false); return; } if (followModeManager.isFollowing(users.get(0))) { - setText(Messages.FollowThisPersonAction_stop_follow_title); - setToolTipText(Messages.FollowThisPersonAction_stop_follow_tooltip); + followThisPersonMenuItem.setLabel(Messages.FollowThisPersonAction_stop_follow_title); + followThisPersonMenuItem.setTooltip(Messages.FollowThisPersonAction_stop_follow_tooltip); } else { - setText(Messages.FollowThisPersonAction_follow_title); - setToolTipText(Messages.FollowThisPersonAction_follow_tooltip); + followThisPersonMenuItem.setLabel(Messages.FollowThisPersonAction_follow_title); + followThisPersonMenuItem.setTooltip(Messages.FollowThisPersonAction_follow_tooltip); } - setEnabled(true); + followThisPersonMenuItem.setEnabled(true); } protected boolean canBeExecuted(List users) { @@ -169,9 +185,9 @@ protected boolean canBeExecuted(List users) { && !users.get(0).isLocal(); } - @Override - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); sessionManager.removeSessionLifecycleListener(sessionLifecycleListener); } } diff --git a/eclipse/src/saros/ui/handlers/popup/JumpToUserWithWriteAccessPositionHandler.java b/eclipse/src/saros/ui/handlers/popup/JumpToUserWithWriteAccessPositionHandler.java new file mode 100644 index 0000000000..7cca7cb760 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/popup/JumpToUserWithWriteAccessPositionHandler.java @@ -0,0 +1,136 @@ +package saros.ui.handlers.popup; + +import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import org.apache.log4j.Logger; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.workbench.UIEvents.UILifeCycle; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; +import org.eclipse.jface.viewers.ISelection; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import saros.SarosPluginContext; +import saros.annotations.Component; +import saros.editor.EditorManager; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSessionManager; +import saros.session.User; +import saros.ui.util.selection.SelectionUtils; +import saros.util.ThreadUtils; + +/** Action which triggers the viewport of the local user to be changed to a local user's one. */ +@Component(module = "action") +public class JumpToUserWithWriteAccessPositionHandler { + + public static final String ID = JumpToUserWithWriteAccessPositionHandler.class.getName(); + + private static final Logger log = + Logger.getLogger(JumpToUserWithWriteAccessPositionHandler.class); + + protected ISelectionListener selectionListener = + new ISelectionListener() { + + @Override + public void selectionChanged(MPart part, Object selection) { + updateEnablement(); + } + }; + + @Inject protected ISarosSessionManager sessionManager; + + @Inject protected EditorManager editorManager; + + private ESelectionService selectionService; + private MDirectMenuItem jumpToUserWithWriteAccessPositionItem; + + private boolean workbenchIsClosing = false; + + public JumpToUserWithWriteAccessPositionHandler() { + SarosPluginContext.initComponent(this); + } + + @PostConstruct + public void postConstruct( + ESelectionService selectionService, + EModelService modelService, + MPart sarosView, + IEventBroker eb) { + this.selectionService = selectionService; + + MPopupMenu popupMenu = null; + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + + eb.subscribe( + UILifeCycle.APP_SHUTDOWN_STARTED, + new EventHandler() { + + @Override + public void handleEvent(Event event) { + workbenchIsClosing = true; + } + }); + + MUIElement menuItem = modelService.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + jumpToUserWithWriteAccessPositionItem = (MDirectMenuItem) menuItem; + } + + selectionService.addSelectionListener(selectionListener); + updateEnablement(); + } + + public void updateEnablement() { + try { + List participants = + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), User.class); + jumpToUserWithWriteAccessPositionItem.setEnabled( + sessionManager.getSession() != null + && participants.size() == 1 + && !participants.get(0).equals(sessionManager.getSession().getLocalUser())); + } catch (NullPointerException e) { + jumpToUserWithWriteAccessPositionItem.setEnabled(false); + } catch (Exception e) { + if (!workbenchIsClosing) + log.error("Unexpected error while updating enablement", e); // $NON-NLS-1$ + } + } + + /** @review runSafe OK */ + @Execute + public void execute() { + ThreadUtils.runSafeSync( + log, + new Runnable() { + @Override + public void run() { + List participants = + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), User.class); + if (participants.size() == 1) { + editorManager.jumpToUser(participants.get(0)); + } else { + log.warn("More than one participant selected."); // $NON-NLS-1$ + } + } + }); + } + + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); + } +} diff --git a/eclipse/src/saros/ui/handlers/popup/OpenChatHandler.java b/eclipse/src/saros/ui/handlers/popup/OpenChatHandler.java new file mode 100644 index 0000000000..25adc427fb --- /dev/null +++ b/eclipse/src/saros/ui/handlers/popup/OpenChatHandler.java @@ -0,0 +1,139 @@ +package saros.ui.handlers.popup; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Named; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; +import org.eclipse.jface.viewers.ISelection; +import saros.SarosPluginContext; +import saros.communication.chat.single.SingleUserChatService; +import saros.communication.connection.ConnectionHandler; +import saros.net.xmpp.JID; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.User; +import saros.ui.model.session.UserElement; +import saros.ui.util.selection.SelectionUtils; +import saros.ui.widgets.chat.ChatRoomsComposite; + +public class OpenChatHandler { + + public static final String ID = OpenChatHandler.class.getName(); + + @Inject private ConnectionHandler connectionHandler; + @Inject private SingleUserChatService chatService; + + private ISelectionListener selectionListener = + new ISelectionListener() { + + @Override + public void selectionChanged(MPart part, Object selection) { + updateEnablement(); + } + }; + + private MDirectMenuItem openChatMenuItem; + private ISelection selection; + + public OpenChatHandler() { + SarosPluginContext.initComponent(this); + } + + @PostConstruct + public void postConstruct( + ESelectionService selectionService, + EModelService modelService, + MPart sarosView, + @Named(IServiceConstants.ACTIVE_SELECTION) ISelection activeSelection) { + this.selection = activeSelection; + + MPopupMenu popupMenu = null; + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + + MUIElement menuItem = modelService.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + openChatMenuItem = (MDirectMenuItem) menuItem; + } + + selectionService.addSelectionListener(selectionListener); + + updateEnablement(); + } + + @Execute + public void execute() { + JID localJID = connectionHandler.getLocalJID(); + JID jid = getSelectedJID(); + + if (Objects.equals(localJID, jid)) return; + + Map data = openChatMenuItem.getTransientData(); + Object object = data.get("chatRoomsComposite"); + + if (object instanceof ChatRoomsComposite) { + ChatRoomsComposite chatRoomsComposite = (ChatRoomsComposite) object; + chatRoomsComposite.openChat(chatService.createChat(jid), true); + } + } + + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); + } + + @CanExecute + public boolean canExecute() { + return connectionHandler.isConnected() && getSelectedJID() != null; + } + + private void updateEnablement() { + if (openChatMenuItem == null) { + return; + } + + if (!connectionHandler.isConnected()) { + openChatMenuItem.setEnabled(false); + return; + } + + if (getSelectedJID() != null) { + openChatMenuItem.setEnabled(true); + } + } + + private JID getSelectedJID() { + List users = SelectionUtils.getAdaptableObjects(selection, UserElement.class); + List contacts = SelectionUtils.getAdaptableObjects(selection, JID.class); + + if (users.size() + contacts.size() == 1) { + if (users.size() == 1) { + User user = users.get(0).getUser(); + if (user == null) { + return null; + } + + return user.getJID(); + } else { + return contacts.get(0); + } + } + + return null; + } +} diff --git a/eclipse/src/saros/ui/actions/RemoveUserAction.java b/eclipse/src/saros/ui/handlers/popup/RemoveUserHandler.java similarity index 64% rename from eclipse/src/saros/ui/actions/RemoveUserAction.java rename to eclipse/src/saros/ui/handlers/popup/RemoveUserHandler.java index a62ebdd652..43915ab868 100644 --- a/eclipse/src/saros/ui/actions/RemoveUserAction.java +++ b/eclipse/src/saros/ui/handlers/popup/RemoveUserHandler.java @@ -1,43 +1,54 @@ -package saros.ui.actions; +package saros.ui.handlers.popup; import java.util.ArrayList; import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.action.Action; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; import saros.SarosPluginContext; import saros.repackaged.picocontainer.annotations.Inject; import saros.session.ISarosSession; import saros.session.ISarosSessionManager; import saros.session.ISessionLifecycleListener; import saros.session.User; -import saros.ui.ImageManager; import saros.ui.util.SWTUtils; import saros.ui.util.selection.SelectionUtils; import saros.ui.util.selection.retriever.SelectionRetrieverFactory; import saros.util.CoreUtils; -public class RemoveUserAction extends Action { +public class RemoveUserHandler { - public static final String ACTION_ID = RemoveUserAction.class.getName(); + public static final String ID = RemoveUserHandler.class.getName(); - private static final Logger log = Logger.getLogger(RemoveUserAction.class); + private static final Logger log = Logger.getLogger(RemoveUserHandler.class); @Inject private ISarosSessionManager sessionManager; private volatile ISarosSession session; + private ESelectionService selectionService; + private MDirectMenuItem removeUserItem; + private ISelectionListener selectionListener = new ISelectionListener() { + @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { + public void selectionChanged(MPart part, Object selection) { updateEnablement(); } }; @@ -72,14 +83,26 @@ public void run() { } }; - public RemoveUserAction() { - super("Remove from Session"); + public RemoveUserHandler() { SarosPluginContext.initComponent(this); + } - setId(ACTION_ID); - setImageDescriptor(ImageManager.getImageDescriptor("icons/elcl16/contact_remove_tsk.png")); + @PostConstruct + public void postConstruct( + ESelectionService selectionService, MPart sarosView, EModelService modelService) { + MPopupMenu popupMenu = null; + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + + MUIElement menuItem = modelService.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + removeUserItem = (MDirectMenuItem) menuItem; + } - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); + selectionService.addSelectionListener(selectionListener); sessionManager.addSessionLifecycleListener(sessionLifecycleListener); session = sessionManager.getSession(); @@ -87,8 +110,8 @@ public RemoveUserAction() { updateEnablement(); } - @Override - public void run() { + @Execute + public void execute() { final ISarosSession currentSession = session; @@ -131,8 +154,9 @@ public void run(IProgressMonitor monitor) throws InterruptedException { } } - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); sessionManager.removeSessionLifecycleListener(sessionLifecycleListener); } @@ -140,9 +164,12 @@ public void dispose() { private void updateEnablement() { ISarosSession currentSession = session; - List users = SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); + List users = + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), User.class); - setEnabled(currentSession != null && currentSession.isHost() && canRemoveUsers(users)); + removeUserItem.setEnabled( + currentSession != null && currentSession.isHost() && canRemoveUsers(users)); } private boolean canRemoveUsers(List users) { diff --git a/eclipse/src/saros/ui/actions/RenameContactAction.java b/eclipse/src/saros/ui/handlers/popup/RenameContactHandler.java similarity index 55% rename from eclipse/src/saros/ui/actions/RenameContactAction.java rename to eclipse/src/saros/ui/handlers/popup/RenameContactHandler.java index 7c3ea95a5d..4f38fb5cc7 100644 --- a/eclipse/src/saros/ui/actions/RenameContactAction.java +++ b/eclipse/src/saros/ui/handlers/popup/RenameContactHandler.java @@ -1,15 +1,26 @@ -package saros.ui.actions; +package saros.ui.handlers.popup; import java.text.MessageFormat; import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Named; import org.apache.log4j.Logger; -import org.eclipse.jface.action.Action; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.window.Window; import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; import saros.SarosPluginContext; import saros.communication.connection.ConnectionHandler; import saros.communication.connection.IConnectionStateListener; @@ -17,26 +28,25 @@ import saros.net.xmpp.contact.XMPPContact; import saros.net.xmpp.contact.XMPPContactsService; import saros.repackaged.picocontainer.annotations.Inject; -import saros.ui.ImageManager; import saros.ui.Messages; import saros.ui.util.SWTUtils; import saros.ui.util.selection.SelectionUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; import saros.util.ThreadUtils; /** Renames the nickname of the selected roster entry. */ -public class RenameContactAction extends Action { +public class RenameContactHandler { - public static final String ACTION_ID = RenameContactAction.class.getName(); + public static final String ID = RenameContactHandler.class.getName(); - private static final Logger log = Logger.getLogger(RenameContactAction.class); + private static final Logger log = Logger.getLogger(RenameContactHandler.class); private IConnectionStateListener connectionListener = (state, error) -> updateEnablement(); protected ISelectionListener selectionListener = new ISelectionListener() { + @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { + public void selectionChanged(MPart part, Object selection) { updateEnablement(); } }; @@ -44,29 +54,58 @@ public void selectionChanged(IWorkbenchPart part, ISelection selection) { @Inject private ConnectionHandler connectionHandler; @Inject private XMPPContactsService contactsService; - public RenameContactAction() { - super(Messages.RenameContactAction_title); - - setId(ACTION_ID); - setToolTipText(Messages.RenameContactAction_tooltip); - setImageDescriptor(ImageManager.ETOOL_EDIT); + private MDirectMenuItem renameContactMenuItem; + private ESelectionService selectionService; + public RenameContactHandler() { SarosPluginContext.initComponent(this); + } + @PostConstruct + public void postConstruct( + EModelService modelService, ESelectionService selectionService, MPart sarosView) { + this.selectionService = selectionService; + + MPopupMenu popupMenu = null; + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + // Search for menu item renameContact + MUIElement menuItem = modelService.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + renameContactMenuItem = (MDirectMenuItem) menuItem; + } connectionHandler.addConnectionStateListener(connectionListener); - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); + selectionService.addSelectionListener(selectionListener); + updateEnablement(); } + @CanExecute + public boolean canExecute() { + return getEnabledState(); + } + protected void updateEnablement() { - List contacts = SelectionRetrieverFactory.getSelectionRetriever(JID.class).getSelection(); + if (renameContactMenuItem == null) { + return; + } - setEnabled(connectionHandler.isConnected() && contacts.size() == 1); + renameContactMenuItem.setEnabled(getEnabledState()); } - @Override - public void run() { + private boolean getEnabledState() { + List contacts = + SelectionUtils.getAdaptableObjects((ISelection) selectionService.getSelection(), JID.class); + + return connectionHandler.isConnected() && contacts.size() == 1; + } + + @Execute + public void execute(@Named(IServiceConstants.ACTIVE_SELECTION) ISelection activeSelection) { ThreadUtils.runSafeSync( log, new Runnable() { @@ -74,7 +113,8 @@ public void run() { public void run() { XMPPContact contact = null; List selectedRosterEntries = - SelectionRetrieverFactory.getSelectionRetriever(XMPPContact.class).getSelection(); + SelectionUtils.getAdaptableObjects(activeSelection, XMPPContact.class); + if (selectedRosterEntries.size() == 1) { contact = selectedRosterEntries.get(0); /* @@ -116,8 +156,9 @@ public void run() { }); } - public void dispose() { - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); connectionHandler.removeConnectionStateListener(connectionListener); } } diff --git a/eclipse/src/saros/ui/handlers/popup/RequestSessionInviteHandler.java b/eclipse/src/saros/ui/handlers/popup/RequestSessionInviteHandler.java new file mode 100644 index 0000000000..07be045fc5 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/popup/RequestSessionInviteHandler.java @@ -0,0 +1,106 @@ +package saros.ui.handlers.popup; + +import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; +import org.eclipse.jface.viewers.ISelection; +import saros.SarosPluginContext; +import saros.communication.extensions.JoinSessionRequestExtension; +import saros.net.ITransmitter; +import saros.net.xmpp.JID; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSession; +import saros.session.ISarosSessionManager; +import saros.ui.util.selection.SelectionUtils; + +/** + * Action for requesting an invitation to a session from a contact. + * + *

This currently relies on the fact, that only Saros/S has a working JoinSessionRequestHandler. + * To make this feature generic in the future we need to add another XMPP namespace + */ +public class RequestSessionInviteHandler { + + @Inject private ISarosSessionManager sessionManager; + @Inject private ITransmitter transmitter; + + private ESelectionService selectionService; + private MDirectMenuItem requestSessionInviteMenuItem; + + private ISelectionListener selectionListener = + new ISelectionListener() { + + @Override + public void selectionChanged(MPart part, Object selection) { + updateActionState(); + } + }; + public static final String ID = RequestSessionInviteHandler.class.getName(); + + public RequestSessionInviteHandler() { + SarosPluginContext.initComponent(this); + } + + @PostConstruct + public void postConstruct( + EModelService modelService, ESelectionService selectionService, MPart sarosView) { + this.selectionService = selectionService; + + MPopupMenu popupMenu = null; + + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + + Object menuElement = modelService.find(ID, popupMenu); + if (menuElement instanceof MDirectMenuItem) { + requestSessionInviteMenuItem = (MDirectMenuItem) menuElement; + } + + selectionService.addSelectionListener(selectionListener); + updateActionState(); + } + + @Execute + public void execute() { + ISarosSession session = sessionManager.getSession(); + JID jid = getSelectedJID(); + if (session != null || jid == null) { + return; + } + + transmitter.sendPacketExtension( + jid, JoinSessionRequestExtension.PROVIDER.create(new JoinSessionRequestExtension())); + } + + private JID getSelectedJID() { + List selected = + SelectionUtils.getAdaptableObjects((ISelection) selectionService.getSelection(), JID.class); + + if (selected.size() != 1) return null; + + return selected.get(0); + } + + private void updateActionState() { + if (requestSessionInviteMenuItem == null) return; + + ISarosSession session = sessionManager.getSession(); + requestSessionInviteMenuItem.setEnabled(session == null && getSelectedJID() != null); + } + + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); + } +} diff --git a/eclipse/src/saros/ui/handlers/popup/SendFileHandler.java b/eclipse/src/saros/ui/handlers/popup/SendFileHandler.java new file mode 100644 index 0000000000..b7ed966a23 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/popup/SendFileHandler.java @@ -0,0 +1,115 @@ +package saros.ui.handlers.popup; + +import java.io.File; +import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.FileDialog; +import saros.net.xmpp.JID; +import saros.net.xmpp.contact.XMPPContact; +import saros.session.User; +import saros.ui.Messages; +import saros.ui.jobs.OutgoingFileTransferJob; +import saros.ui.util.SWTUtils; +import saros.ui.util.selection.SelectionUtils; + +/** Action for sending a file over XMPP. */ +public class SendFileHandler { + + public static final String ID = SendFileHandler.class.getName(); + + private ISelectionListener selectionListener = (part, selection) -> updateEnablement(); + + private MDirectMenuItem sendFileMenuItem; + private ESelectionService selectionService; + + @PostConstruct + public void postConstruct( + MPart sarosView, EModelService service, ESelectionService selectionService) { + selectionService.addSelectionListener(selectionListener); + this.selectionService = selectionService; + // TODO: create icon + + MPopupMenu popupMenu = null; + + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + MUIElement menuItem = service.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + sendFileMenuItem = (MDirectMenuItem) menuItem; + } + + updateEnablement(); + } + + @Execute + public void run() { + JID jid = getSelectedJID(); + if (jid == null) return; + + FileDialog fd = new FileDialog(SWTUtils.getShell(), SWT.OPEN); + fd.setText(Messages.SendFileAction_filedialog_text); + + String filename = fd.open(); + if (filename == null) return; + + File file = new File(filename); + if (file.isDirectory()) return; + + Job job = new OutgoingFileTransferJob(jid, file); + job.setUser(true); + job.schedule(); + } + + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); + } + + private void updateEnablement() { + if (sendFileMenuItem == null) return; + + sendFileMenuItem.setEnabled(getSelectedJID() != null); + } + + @CanExecute + public boolean canExecute() { + return getSelectedJID() != null; + } + + private JID getSelectedJID() { + List sessionUsers = + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), User.class); + + List contacts = + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), XMPPContact.class); + + // currently only one transfer per click (maybe improved later) + if (contacts.size() + sessionUsers.size() != 1) return null; + + if (sessionUsers.size() == 1) { + if (sessionUsers.get(0).isLocal()) return null; + return sessionUsers.get(0).getJID(); + } + + return contacts.get(0).getOnlineJid().orElse(null); + } +} diff --git a/eclipse/src/saros/ui/handlers/popup/SkypeHandler.java b/eclipse/src/saros/ui/handlers/popup/SkypeHandler.java new file mode 100644 index 0000000000..09dfa357ed --- /dev/null +++ b/eclipse/src/saros/ui/handlers/popup/SkypeHandler.java @@ -0,0 +1,123 @@ +package saros.ui.handlers.popup; + +import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Named; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.hyperlink.URLHyperlink; +import org.eclipse.jface.viewers.ISelection; +import saros.SarosPluginContext; +import saros.communication.SkypeManager; +import saros.net.xmpp.contact.XMPPContact; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.ui.util.selection.SelectionUtils; + +/** An action for starting a Skype Audio Session to other contacts. */ +public class SkypeHandler { + + public static final String ID = SkypeHandler.class.getName(); + + private ISelectionListener selectionListener = + new ISelectionListener() { + + @Override + public void selectionChanged(MPart part, Object selection) { + updateEnablement(); + } + }; + + @Inject private SkypeManager skypeManager; + + private MDirectMenuItem skypeMenuEntry; + private ESelectionService selectionService; + + public SkypeHandler() { + SarosPluginContext.initComponent(this); + } + + @PostConstruct + public void postConstruct( + EModelService service, MPart sarosView, ESelectionService selectionService) { + this.selectionService = selectionService; + + MPopupMenu popupMenu = null; + for (MMenu menu : sarosView.getMenus()) { + if (menu instanceof MPopupMenu) { + popupMenu = (MPopupMenu) menu; + } + } + + MUIElement menuItem = service.find(ID, popupMenu); + if (menuItem instanceof MDirectMenuItem) { + skypeMenuEntry = (MDirectMenuItem) menuItem; + } + + selectionService.addSelectionListener(selectionListener); + updateEnablement(); + } + + private void updateEnablement() { + if (skypeMenuEntry == null) { + return; + } + + skypeMenuEntry.setEnabled(getEnabledState()); + } + + @CanExecute + public boolean canExecute() { + return getEnabledState(); + } + + private boolean getEnabledState() { + final List contacts = + SelectionUtils.getAdaptableObjects( + (ISelection) selectionService.getSelection(), XMPPContact.class); + + if (contacts.size() != 1) return false; + + final String skypeName = skypeManager.getSkypeName(contacts.get(0)); + + return SkypeManager.isSkypeAvailable(false) + && skypeName != null + && !SkypeManager.isEchoService(skypeName); + } + + @Execute + public void run(@Named(IServiceConstants.ACTIVE_SELECTION) ISelection activeSelection) { + + final List participants = + SelectionUtils.getAdaptableObjects(activeSelection, XMPPContact.class); + + if (participants.size() != 1) return; + + final String skypeName = skypeManager.getSkypeName(participants.get(0)); + + if (skypeName == null || SkypeManager.isEchoService(skypeName)) return; + + final String uri = SkypeManager.getAudioCallUri(skypeName); + + if (uri == null) return; + + final URLHyperlink link = new URLHyperlink(new Region(0, 0), uri); + + link.open(); + } + + @PreDestroy + public void dispose(ESelectionService selectionService) { + selectionService.removeSelectionListener(selectionListener); + } +} diff --git a/eclipse/src/saros/ui/handlers/toolbar/ChangeXMPPAccountHandler.java b/eclipse/src/saros/ui/handlers/toolbar/ChangeXMPPAccountHandler.java new file mode 100644 index 0000000000..0e66a4055d --- /dev/null +++ b/eclipse/src/saros/ui/handlers/toolbar/ChangeXMPPAccountHandler.java @@ -0,0 +1,215 @@ +package saros.ui.handlers.toolbar; + +import java.util.List; +import java.util.Map; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import org.apache.log4j.Logger; +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.e4.core.commands.ECommandService; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MToolItem; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.jface.dialogs.MessageDialog; +import saros.SarosPluginContext; +import saros.account.IAccountStoreListener; +import saros.account.XMPPAccount; +import saros.account.XMPPAccountStore; +import saros.communication.connection.ConnectionHandler; +import saros.communication.connection.IConnectionStateListener; +import saros.net.ConnectionState; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.ui.Messages; +import saros.ui.util.SWTUtils; +import saros.ui.util.XMPPConnectionSupport; + +/** + * In addition to the connect/disconnect action, this allows the user to switch between accounts. + */ +public class ChangeXMPPAccountHandler { + + static class AddAccountToMenuHandler { + + @Execute + public void execute(MDirectMenuItem item) { + defaultAccountChanged = false; + + Map objectData = item.getTransientData(); + Object data = objectData.get("account"); + + if (data instanceof XMPPAccount) { + XMPPAccount account = (XMPPAccount) data; + XMPPConnectionSupport.getInstance().connect(account, false, false); + } + } + } + + public static final String ID = ChangeXMPPAccountHandler.class.getName(); + + private static final String PLATFORM_PLUGIN_SAROS_ECLIPSE = "platform:/plugin/saros.eclipse"; + + private static final Logger log = Logger.getLogger(ChangeXMPPAccountHandler.class); + + @Inject private XMPPAccountStore accountService; + + @Inject private ConnectionHandler connectionHandler; + + private boolean isConnectionError; + + protected static boolean defaultAccountChanged; + + private final IConnectionStateListener connectionStateListener = + (state, error) -> SWTUtils.runSafeSWTAsync(log, () -> updateStatus(state)); + + private final IAccountStoreListener accountStoreListener = + new IAccountStoreListener() { + @Override + public void activeAccountChanged(final XMPPAccount activeAccount) { + defaultAccountChanged = true; + } + }; + + private boolean isEnabled = false; + + private MToolItem connectToolItem; + + private ECommandService commandService; + + public ChangeXMPPAccountHandler() { + SarosPluginContext.initComponent(this); + } + + @PostConstruct + public void postConstruct( + EModelService service, MPart sarosView, ECommandService commandService) { + this.commandService = commandService; + + MUIElement toolBarElement = service.find(ID, sarosView.getToolbar()); + if (toolBarElement instanceof MToolItem) { + connectToolItem = (MToolItem) toolBarElement; + } + + connectionHandler.addConnectionStateListener(connectionStateListener); + updateStatus(connectionHandler.getConnectionState()); + + accountService.addListener(accountStoreListener); + } + + @Execute + public void execute() { + if (connectionHandler.isConnected()) { + XMPPConnectionSupport.getInstance().disconnect(); + return; + } + + final XMPPAccount lastUsedAccount = XMPPConnectionSupport.getInstance().getCurrentXMPPAccount(); + + final List accounts = accountService.getAllAccounts(); + + final boolean exists = accounts.indexOf(lastUsedAccount) != -1; + + final XMPPAccount defaultAccount = accountService.getDefaultAccount(); + + final boolean isEmpty = accountService.isEmpty(); + + if (!exists && (defaultAccount == null || isEmpty)) { + if (!MessageDialog.openQuestion( + SWTUtils.getShell(), + "Default account missing", + "A default account has not been set yet. Do you want set a default account?")) return; + + SWTUtils.runSafeSWTAsync(log, this::openPreferences); + return; + } + + final XMPPAccount accountToConnect; + + if (defaultAccountChanged || !exists) { + defaultAccountChanged = false; + accountToConnect = defaultAccount; + } else { + accountToConnect = lastUsedAccount; + } + + XMPPConnectionSupport.getInstance().connect(accountToConnect, false, false); + } + + @PreDestroy + public void dispose() { + connectionHandler.removeConnectionStateListener(connectionStateListener); + accountService.removeListener(accountStoreListener); + } + + @CanExecute + public boolean canExecute() { + return isEnabled; + } + + private void updateStatus(ConnectionState state) { + if (connectToolItem == null) { + return; + } + try { + switch (state) { + case CONNECTED: + isConnectionError = false; + connectToolItem.setLabel(Messages.ChangeXMPPAccountAction_disconnect); + connectToolItem.setIconURI( + PLATFORM_PLUGIN_SAROS_ECLIPSE + "/icons/elcl16/xmpp_disconnect_tsk.png"); + break; + case CONNECTING: + isConnectionError = false; + connectToolItem.setLabel(Messages.ChangeXMPPAccountAction_connecting); + connectToolItem.setIconURI( + PLATFORM_PLUGIN_SAROS_ECLIPSE + "/icons/elcl16/xmpp_connecting_misc.png"); + break; + case ERROR: + isConnectionError = true; + connectToolItem.setIconURI( + PLATFORM_PLUGIN_SAROS_ECLIPSE + "/icons/elcl16/xmpp_connection_error_misc.png"); + break; + case NOT_CONNECTED: + connectToolItem.setLabel(Messages.ChangeXMPPAccountAction_connect); + + if (!isConnectionError) + connectToolItem.setIconURI( + PLATFORM_PLUGIN_SAROS_ECLIPSE + "/icons/elcl16/xmpp_connect_tsk.png"); + break; + case DISCONNECTING: + default: + isConnectionError = false; + connectToolItem.setLabel(Messages.ChangeXMPPAccountAction_disconnecting); + connectToolItem.setIconURI( + PLATFORM_PLUGIN_SAROS_ECLIPSE + "/icons/elcl16/xmpp_disconnecting_misc.png"); + break; + } + + boolean setEnabled = + state == ConnectionState.CONNECTED + || state == ConnectionState.NOT_CONNECTED + || state == ConnectionState.ERROR; + + isEnabled = setEnabled; + + connectToolItem.setEnabled(setEnabled); + + } catch (RuntimeException e) { + log.error("Internal error in ChangeXMPPAccountAction:", e); + } + } + + private void openPreferences() { + Command openPreferencesCmd = + commandService.getCommand("saros.ui.commands.OpenSarosPreferences"); + try { + openPreferencesCmd.executeWithChecks(new ExecutionEvent()); + } catch (Exception e) { + log.debug("Could execute command", e); + } + } +} diff --git a/eclipse/src/saros/ui/actions/ConsistencyAction.java b/eclipse/src/saros/ui/handlers/toolbar/ConsistencyHandler.java similarity index 81% rename from eclipse/src/saros/ui/actions/ConsistencyAction.java rename to eclipse/src/saros/ui/handlers/toolbar/ConsistencyHandler.java index ef1ff7220b..625526aa1f 100644 --- a/eclipse/src/saros/ui/actions/ConsistencyAction.java +++ b/eclipse/src/saros/ui/handlers/toolbar/ConsistencyHandler.java @@ -1,22 +1,26 @@ -package saros.ui.actions; +package saros.ui.handlers.toolbar; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import java.util.Set; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.apache.log4j.Logger; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.jface.action.Action; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MToolItem; +import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.window.Window; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; @@ -33,7 +37,6 @@ import saros.session.ISarosSessionManager; import saros.session.ISessionLifecycleListener; import saros.session.SessionEndReason; -import saros.ui.ImageManager; import saros.ui.Messages; import saros.ui.util.SWTUtils; import saros.ui.views.SarosView; @@ -47,11 +50,11 @@ * will display "bar" if the action is disabled. */ @Component(module = "action") -public class ConsistencyAction extends Action implements Disposable { +public class ConsistencyHandler { - public static final String ACTION_ID = ConsistencyAction.class.getName(); + public static final String ID = ConsistencyHandler.class.getName(); - private static final Logger log = Logger.getLogger(ConsistencyAction.class); + private static final Logger log = Logger.getLogger(ConsistencyHandler.class); private static final int MIN_ALPHA_VALUE = 64; private static final int MAX_ALPHA_VALUE = 255; @@ -61,25 +64,11 @@ public class ConsistencyAction extends Action implements Disposable { private static final int FADE_DOWN = -1; private static final int FADE_UP = 1; - private static final ImageDescriptor IN_SYNC = - ImageManager.getImageDescriptor("icons/etool16/in_sync.png"); // $NON-NLS-1$; + private boolean isConsistent = false; - private static final Image OUT_SYNC = - ImageManager.getImage("icons/etool16/out_sync.png"); // $NON-NLS-1$; - - private static class MemoryImageDescriptor extends ImageDescriptor { - - private final ImageData data; - - public MemoryImageDescriptor(ImageData data) { - this.data = data; - } - - @Override - public ImageData getImageData() { - return data; - } - } + private static final String IN_SYNC = "platform:/plugin/saros.eclipse/icons/etool16/in_sync.png"; + private static final String OUT_SYNC = + "platform:/plugin/saros.eclipse/icons/etool16/out_sync.png"; private final ISessionLifecycleListener sessionLifecycleListener = new ISessionLifecycleListener() { @@ -111,12 +100,9 @@ public void setValue(Boolean newValue) { private volatile ISarosSession sarosSession; - public ConsistencyAction() { - - setId(ACTION_ID); - setImageDescriptor(IN_SYNC); - setToolTipText(Messages.ConsistencyAction_tooltip_no_inconsistency); + private MToolItem consistencyToolItem; + public ConsistencyHandler() { SarosPluginContext.initComponent(this); sessionManager.addSessionLifecycleListener(sessionLifecycleListener); @@ -124,6 +110,19 @@ public ConsistencyAction() { setSession(sessionManager.getSession()); } + @PostConstruct + public void postConstruct(EModelService service, MPart sarosView) { + MUIElement toolItem = service.find(ID, sarosView.getToolbar()); + if (toolItem instanceof MToolItem) { + consistencyToolItem = (MToolItem) toolItem; + } + } + + @CanExecute + public boolean canExecute() { + return isConsistent; + } + private void setSession(ISarosSession newSession) { // TODO Why are we removing the listener and adding it again? @@ -134,13 +133,18 @@ private void setSession(ISarosSession newSession) { sarosSession = newSession; - if (sarosSession != null) setDisabledImageDescriptor(IN_SYNC); - else setDisabledImageDescriptor(null); + if (consistencyToolItem == null) return; + + if (sarosSession != null) { + consistencyToolItem.setIconURI(IN_SYNC); + } else { + consistencyToolItem.setIconURI(null); + } if (sarosSession != null) { inconsistentObservable.addAndNotify(isConsistencyListener); } else { - setEnabled(false); + consistencyToolItem.setEnabled(false); /* * make sure we reset the default "enabled image" otherwise the GUI @@ -152,14 +156,13 @@ private void setSession(ISarosSession newSession) { new Runnable() { @Override public void run() { - setImageDescriptor(IN_SYNC); + consistencyToolItem.setIconURI(IN_SYNC); } }); } } private void handleConsistencyChange(Boolean isInconsistent) { - final ISarosSession currentSession = sarosSession; if (currentSession == null) return; @@ -184,11 +187,13 @@ private void handleConsistencyChange(Boolean isInconsistent) { "Inconsistency indicator goes: " //$NON-NLS-1$ + (isInconsistent ? "on" : "off")); // $NON-NLS-1$ //$NON-NLS-2$ - setEnabled(isInconsistent); + if (consistencyToolItem != null) { + consistencyToolItem.setEnabled(isInconsistent); - if (!isInconsistent) { - setToolTipText(Messages.ConsistencyAction_tooltip_no_inconsistency); - return; + if (!isInconsistent) { + consistencyToolItem.setTooltip(Messages.ConsistencyAction_tooltip_no_inconsistency); + return; + } } SWTUtils.runSafeSWTSync( @@ -223,9 +228,11 @@ public void run() { String files = sb.toString(); // set tooltip - setToolTipText( - MessageFormat.format( - Messages.ConsistencyAction_tooltip_inconsistency_detected, files)); + if (consistencyToolItem != null) { + consistencyToolItem.setTooltip( + MessageFormat.format( + Messages.ConsistencyAction_tooltip_inconsistency_detected, files)); + } // TODO Balloon is too aggressive at the moment, when // the host is slow in sending changes (for instance @@ -240,7 +247,7 @@ public void run() { }); } - @Override + @Execute public void run() { final ISarosSession currentSession = sarosSession; @@ -329,7 +336,7 @@ public void run(IProgressMonitor monitor) throws InterruptedException { } } - @Override + @PreDestroy public void dispose() { sessionManager.removeSessionLifecycleListener(sessionLifecycleListener); } @@ -340,7 +347,11 @@ private void startFading(final int startValue, final int direction) { isFading = false; - if (display.isDisposed() || !isEnabled()) return; + if (consistencyToolItem == null) { + return; + } + + if (display.isDisposed() || !consistencyToolItem.isEnabled()) return; isFading = true; @@ -350,9 +361,8 @@ private void startFading(final int startValue, final int direction) { @Override public void run() { - - if (!isEnabled()) { - setImageDescriptor(IN_SYNC); + if (!consistencyToolItem.isEnabled()) { + consistencyToolItem.setIconURI(IN_SYNC); isFading = false; return; } @@ -368,32 +378,10 @@ public void run() { newDirection = FADE_UP; } - setImageDescriptor(new MemoryImageDescriptor(modifyAlphaChannel(OUT_SYNC, newValue))); + // TODO: create modified icon startFading(newValue, newDirection); } }); } - - private static ImageData modifyAlphaChannel(Image image, int alpha) { - - if (alpha < 0) alpha = 0; - - if (alpha > 255) alpha = 255; - - ImageData data = image.getImageData(); - - for (int x = 0; x < data.width; x++) { - for (int y = 0; y < data.height; y++) { - int a = data.getAlpha(x, y); - - // value depends on the image, must be determined empirically - if (a <= MIN_ALPHA_VALUE) continue; - - data.setAlpha(x, y, alpha); - } - } - - return data; - } } diff --git a/eclipse/src/saros/ui/actions/FollowModeAction.java b/eclipse/src/saros/ui/handlers/toolbar/FollowModeHandler.java similarity index 59% rename from eclipse/src/saros/ui/actions/FollowModeAction.java rename to eclipse/src/saros/ui/handlers/toolbar/FollowModeHandler.java index b1b4460aa1..56bb28ce30 100644 --- a/eclipse/src/saros/ui/actions/FollowModeAction.java +++ b/eclipse/src/saros/ui/handlers/toolbar/FollowModeHandler.java @@ -1,23 +1,25 @@ -package saros.ui.actions; +package saros.ui.handlers.toolbar; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.apache.log4j.Logger; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.ActionContributionItem; -import org.eclipse.jface.action.IMenuCreator; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.MenuItem; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.di.AboutToShow; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectToolItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.ISelectionListener; import saros.SarosPluginContext; import saros.editor.FollowModeManager; import saros.editor.IFollowModeListener; @@ -28,23 +30,35 @@ import saros.session.ISessionListener; import saros.session.SessionEndReason; import saros.session.User; -import saros.ui.ImageManager; import saros.ui.Messages; import saros.ui.util.SWTUtils; -import saros.ui.util.selection.SelectionUtils; import saros.util.CoreUtils; /** Action to enter into FollowMode via toolbar. */ -public class FollowModeAction extends Action implements IMenuCreator, Disposable { +public class FollowModeHandler { - public static final String ACTION_ID = FollowModeAction.class.getName(); + public static final String ID = FollowModeHandler.class.getName(); - private static final Logger log = Logger.getLogger(FollowModeAction.class); + static class FollowUserHandler { + + @Execute + public void execute(MDirectMenuItem item) { + Map itemData = item.getTransientData(); + Object user = itemData.get("user"); + + if (user instanceof User || user == null) { + followUser((User) user); + } + } + } + + private static final Logger log = Logger.getLogger(FollowModeHandler.class); private ISelectionListener selectionListener = new ISelectionListener() { + @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { + public void selectionChanged(MPart part, Object selection) { updateEnablement(); } }; @@ -102,7 +116,7 @@ public void sessionStarted(final ISarosSession session) { public void run() { currentlyFollowedUser = followModeManager.getFollowedUser(); - FollowModeAction.this.session = session; + FollowModeHandler.this.session = session; currentRemoteSessionUsers.clear(); currentRemoteSessionUsers.addAll(session.getRemoteUsers()); updateEnablement(); @@ -124,7 +138,7 @@ public void sessionEnded(ISarosSession oldSarosSession, SessionEndReason reason) @Override public void run() { - FollowModeAction.this.session = null; + FollowModeHandler.this.session = null; currentRemoteSessionUsers.clear(); updateEnablement(); } @@ -164,133 +178,91 @@ public void run() { @Inject private ISarosSessionManager sessionManager; - private FollowModeManager followModeManager; + private static FollowModeManager followModeManager; private ISarosSession session; private User currentlyFollowedUser; - private Menu followUserMenu; - private final Set currentRemoteSessionUsers = new LinkedHashSet(); - private final ImageDescriptor followModeEnabledImageDescriptor = - new ImageDescriptor() { - @Override - public ImageData getImageData() { - return ImageManager.ICON_USER_SAROS_FOLLOWMODE.getImageData(); - } - }; + private final String followModeEnabledImageURI = + "platform:/plugin/saros.eclipse/icons/merged16/user_saros_followmode_enabled.png"; - private final ImageDescriptor followModeDisabledImageDescriptor = - new ImageDescriptor() { - @Override - public ImageData getImageData() { - return ImageManager.ICON_USER_SAROS_FOLLOWMODE_DISABLED.getImageData(); - } - }; + private final String followModeDisabledImageURI = + "platform:/plugin/saros.eclipse/icons/merged16/user_saros_followmode_disabled.png"; - public FollowModeAction() { + public FollowModeHandler() { SarosPluginContext.initComponent(this); - setId(ACTION_ID); - setText(Messages.FollowModeAction_enter_followmode); - setMenuCreator(this); - session = sessionManager.getSession(); sessionManager.addSessionLifecycleListener(sessionLifecycleListener); + } + + private MDirectToolItem followModeItem; - SelectionUtils.getSelectionService().addSelectionListener(selectionListener); + @PostConstruct + public void postConstruct( + EModelService service, MPart sarosView, ESelectionService selectionService) { + MUIElement toolbarElement = service.find(ID, sarosView.getToolbar()); + + if (toolbarElement instanceof MDirectToolItem) { + followModeItem = (MDirectToolItem) toolbarElement; + } + + selectionService.addSelectionListener(selectionListener); if (session != null) currentRemoteSessionUsers.addAll(session.getRemoteUsers()); updateEnablement(); } - @Override - public void run() { + @Execute + public void run(MDirectToolItem toolBarElement) { if (session == null) return; - if (!isEnabled()) return; + if (!toolBarElement.isEnabled()) return; followUser(getNextUserToFollow()); } - @Override - public void dispose() { - if (followUserMenu != null) followUserMenu.dispose(); - + @PreDestroy + public void dispose(ESelectionService selectionService) { sessionManager.removeSessionLifecycleListener(sessionLifecycleListener); - SelectionUtils.getSelectionService().removeSelectionListener(selectionListener); + selectionService.removeSelectionListener(selectionListener); } - @Override - public Menu getMenu(Control parent) { - if (followUserMenu != null) followUserMenu.dispose(); - - followUserMenu = null; - - if (session == null) return null; - - followUserMenu = new Menu(parent); + @AboutToShow + public void createMenu(List items, EModelService service) { + if (session == null) return; List users = new ArrayList(currentRemoteSessionUsers); - for (User user : users) addActionToMenu(followUserMenu, createAction(user)); + for (User user : users) { + // The additional @ is needed because @ has special meaning in + // Action#setText(), see JavaDoc of Action(). - new MenuItem(followUserMenu, SWT.SEPARATOR); + String followUserMessage = getFollowUserMessage(user); - Action disableFollowModeAction = - new Action(Messages.FollowModeAction_leave_followmode) { - @Override - public void run() { - followUser(null); - } - }; + if (followUserMessage.contains("@")) followUserMessage += "@"; - disableFollowModeAction.setImageDescriptor(followModeDisabledImageDescriptor); + // Create menu item + MDirectMenuItem userMenuItem = service.createModelElement(MDirectMenuItem.class); + userMenuItem.setLabel(followUserMessage); + userMenuItem.setContributionURI( + "bundleclass://saros.eclipse/saros.ui.e4.toolbar.FollowModeHandler$FollowUserHandler"); + userMenuItem.setIconURI(followModeEnabledImageURI); - addActionToMenu(followUserMenu, disableFollowModeAction); - return followUserMenu; - } - - @Override - public Menu getMenu(Menu parent) { - return null; + items.add(userMenuItem); + } } - private void followUser(User user) { + private static void followUser(User user) { if (followModeManager != null) followModeManager.follow(user); } - private Action createAction(final User user) { - // The additional @ is needed because @ has special meaning in - // Action#setText(), see JavaDoc of Action(). - - String followUserMessage = getFollowUserMessage(user); - - if (followUserMessage.contains("@")) followUserMessage += "@"; - - Action action = - new Action(followUserMessage) { - - @Override - public void run() { - followUser(user); - } - }; - - action.setImageDescriptor(followModeEnabledImageDescriptor); - return action; - } - - private void addActionToMenu(Menu parent, Action action) { - ActionContributionItem item = new ActionContributionItem(action); - item.fill(parent, -1); - } - /** Returns the next user to follow or null if follow mode should be disabled. */ private User getNextUserToFollow() { if (currentRemoteSessionUsers.isEmpty()) return null; @@ -311,22 +283,33 @@ private User getNextUserToFollow() { return nextUser; } + @CanExecute + public boolean canExecute() { + return session != null && !currentRemoteSessionUsers.isEmpty(); + } + private void updateEnablement() { - setEnabled(session != null && !currentRemoteSessionUsers.isEmpty()); - setImageDescriptor( - currentlyFollowedUser != null - ? followModeEnabledImageDescriptor - : followModeDisabledImageDescriptor); + if (followModeItem == null) { + return; + } + + followModeItem.setEnabled(session != null && !currentRemoteSessionUsers.isEmpty()); + + if (currentlyFollowedUser != null) { + followModeItem.setIconURI(followModeEnabledImageURI); + } else { + followModeItem.setIconURI(followModeDisabledImageURI); + } - if (isEnabled()) { + if (followModeItem.isEnabled()) { User nextUserToFollow = getNextUserToFollow(); - setToolTipText( + followModeItem.setTooltip( nextUserToFollow == null ? Messages.FollowModeAction_leave_followmode : getFollowUserMessage(nextUserToFollow)); } else // display default text - setToolTipText(null); + followModeItem.setTooltip(null); } private String getFollowUserMessage(User user) { diff --git a/eclipse/src/saros/ui/handlers/toolbar/LeaveSessionHandler.java b/eclipse/src/saros/ui/handlers/toolbar/LeaveSessionHandler.java new file mode 100644 index 0000000000..111138afb1 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/toolbar/LeaveSessionHandler.java @@ -0,0 +1,103 @@ +package saros.ui.handlers.toolbar; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MToolItem; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import saros.SarosPluginContext; +import saros.annotations.Component; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSession; +import saros.session.ISarosSessionManager; +import saros.session.ISessionLifecycleListener; +import saros.session.SessionEndReason; +import saros.ui.Messages; +import saros.ui.util.CollaborationUtils; + +/** Leaves the current Saros session. Is deactivated if there is no running session. */ +@Component(module = "action") +public class LeaveSessionHandler { + + public static final String ID = LeaveSessionHandler.class.getName(); + + private static final String SAROS_ECLIPSE_URI = "platform:/plugin/saros.eclipse/"; + + @Inject private ISarosSessionManager sessionManager; + + private MToolItem leaveSessionToolItem; + + private static final String ELCL_SESSION_TERMINATE = + SAROS_ECLIPSE_URI + "icons/elcl16/session_terminate_tsk.png"; + private static final String ELCL_SESSION_LEAVE = + SAROS_ECLIPSE_URI + "icons/elcl16/session_leave_tsk.png"; + + private final ISessionLifecycleListener sessionLifecycleListener = + new ISessionLifecycleListener() { + @Override + public void sessionStarted(ISarosSession newSarosSession) { + updateEnablement(); + } + + @Override + public void sessionEnded(ISarosSession oldSarosSession, SessionEndReason reason) { + updateEnablement(); + } + }; + + public LeaveSessionHandler() { + SarosPluginContext.initComponent(this); + sessionManager.addSessionLifecycleListener(sessionLifecycleListener); + } + + @PostConstruct + public void construct(EModelService service, MPart sarosView) { + MUIElement toolBarElement = service.find(ID, sarosView.getToolbar()); + + if (toolBarElement instanceof MToolItem) { + leaveSessionToolItem = (MToolItem) toolBarElement; + } + updateEnablement(); + } + + @Execute + public void run() { + CollaborationUtils.leaveSession(); + } + + @CanExecute + public boolean canExecute() { + ISarosSession session = sessionManager.getSession(); + return session != null; + } + + @PreDestroy + public void dispose() { + sessionManager.removeSessionLifecycleListener(sessionLifecycleListener); + } + + private void updateEnablement() { + ISarosSession session = sessionManager.getSession(); + + if (leaveSessionToolItem == null) { + return; + } + + if (session == null) { + leaveSessionToolItem.setEnabled(false); + return; + } + + if (session.isHost()) { + leaveSessionToolItem.setTooltip(Messages.LeaveSessionAction_stop_session_tooltip); + leaveSessionToolItem.setIconURI(ELCL_SESSION_TERMINATE); + } else { + leaveSessionToolItem.setTooltip(Messages.LeaveSessionAction_leave_session_tooltip); + leaveSessionToolItem.setIconURI(ELCL_SESSION_LEAVE); + } + leaveSessionToolItem.setEnabled(true); + } +} diff --git a/eclipse/src/saros/ui/handlers/toolbar/NewContactHandler.java b/eclipse/src/saros/ui/handlers/toolbar/NewContactHandler.java new file mode 100644 index 0000000000..c3842cbc48 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/toolbar/NewContactHandler.java @@ -0,0 +1,45 @@ +package saros.ui.handlers.toolbar; + +import javax.annotation.PreDestroy; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import saros.SarosPluginContext; +import saros.communication.connection.ConnectionHandler; +import saros.communication.connection.IConnectionStateListener; +import saros.net.ConnectionState; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.ui.util.WizardUtils; + +public class NewContactHandler { + + public static final String ID = NewContactHandler.class.getName(); + + private final IConnectionStateListener connectionListener = + (state, error) -> connectionState = state == ConnectionState.CONNECTED; + + private boolean connectionState = false; + + @Inject private ConnectionHandler connectionHandler; + + public NewContactHandler() { + SarosPluginContext.initComponent(this); + + connectionHandler.addConnectionStateListener(connectionListener); + connectionState = connectionHandler.isConnected(); + } + + @PreDestroy + public void dispose() { + connectionHandler.removeConnectionStateListener(connectionListener); + } + + @CanExecute + public boolean canExecute() { + return connectionState; + } + + @Execute + public void run() { + WizardUtils.openAddContactWizard(); + } +} diff --git a/eclipse/src/saros/ui/handlers/toolbar/OpenPreferencesHandler.java b/eclipse/src/saros/ui/handlers/toolbar/OpenPreferencesHandler.java new file mode 100644 index 0000000000..550e0f116f --- /dev/null +++ b/eclipse/src/saros/ui/handlers/toolbar/OpenPreferencesHandler.java @@ -0,0 +1,25 @@ +package saros.ui.handlers.toolbar; + +import org.apache.log4j.Logger; +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.e4.core.commands.ECommandService; +import org.eclipse.e4.core.di.annotations.Execute; + +public class OpenPreferencesHandler { + + public static final String ID = OpenPreferencesHandler.class.getName(); + + private static final Logger log = Logger.getLogger(OpenPreferencesHandler.class); + + @Execute + public void run(ECommandService commandService) { + Command openPreferencesCmd = + commandService.getCommand("saros.ui.commands.OpenSarosPreferences"); + try { + openPreferencesCmd.executeWithChecks(new ExecutionEvent()); + } catch (Exception e) { + log.error("Could not execute command", e); // $NON-NLS-1$ + } + } +} diff --git a/eclipse/src/saros/ui/handlers/toolbar/XMPPAccountMenu.java b/eclipse/src/saros/ui/handlers/toolbar/XMPPAccountMenu.java new file mode 100644 index 0000000000..0d339d5809 --- /dev/null +++ b/eclipse/src/saros/ui/handlers/toolbar/XMPPAccountMenu.java @@ -0,0 +1,65 @@ +package saros.ui.handlers.toolbar; + +import java.util.List; +import java.util.Map; +import org.eclipse.e4.ui.di.AboutToShow; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import saros.SarosPluginContext; +import saros.account.XMPPAccount; +import saros.account.XMPPAccountStore; +import saros.communication.connection.ConnectionHandler; +import saros.net.xmpp.JID; +import saros.repackaged.picocontainer.annotations.Inject; + +public class XMPPAccountMenu { + + @Inject private XMPPAccountStore accountService; + + @Inject private ConnectionHandler connectionHandler; + + public XMPPAccountMenu() { + SarosPluginContext.initComponent(this); + } + + @AboutToShow + public void createMenu(List items, EModelService service) { + final List accounts = accountService.getAllAccounts(); + + final String connectionId = connectionHandler.getConnectionID(); + + if (connectionHandler.isConnected() && connectionId != null) { + + final JID jid = new JID(connectionId); + + /* + * TODO this may filter out too much but this situation is somewhat rare (multiple accounts + * with same name and domain but different server + */ + + accounts.removeIf( + a -> + a.getUsername().equalsIgnoreCase(jid.getName()) + && a.getDomain().equalsIgnoreCase(jid.getDomain())); + } + + accounts.forEach( + account -> { + // The additional @ is needed because @ has special meaning in + // Action#setText(), see JavaDoc of Action(). + + String accountText = account.getUsername() + "@" + account.getDomain(); + + MDirectMenuItem accountElement = service.createModelElement(MDirectMenuItem.class); + accountElement.setContributionURI( + "bundleclass://saros.eclipse/saros.ui.e4.toolbar.ChangeXMPPAccountHandler$AddAccountToMenuHandler"); + accountElement.setLabel(accountText); + + Map objectData = accountElement.getTransientData(); + objectData.put("account", account); + + items.add(accountElement); + }); + } +} diff --git a/eclipse/src/saros/ui/util/SWTUtils.java b/eclipse/src/saros/ui/util/SWTUtils.java index c92eeb658b..96b98ccf7d 100644 --- a/eclipse/src/saros/ui/util/SWTUtils.java +++ b/eclipse/src/saros/ui/util/SWTUtils.java @@ -21,6 +21,8 @@ public class SWTUtils { private static final Logger log = Logger.getLogger(SWTUtils.class); + private static Display display; + private static class CallableResult { private T result; private Exception exception; @@ -187,7 +189,21 @@ public static void runSafeSWTSync(final Logger log, final Runnable runnable) { * @return the display of the current workbench */ public static Display getDisplay() { - return PlatformUI.getWorkbench().getDisplay(); + /** + * This is a temporary solution. Migrating the UI from Eclipse3 to Eclipse4 caused an earlier + * initialization of Saros and its context. Calling PlatformUI.getWorkbench.getDisplay() can not + * be used, since the Workbench wont be created at that point, when this function is first + * called. Continuing the migration it would be best to find an other solution by replacing all + * calls to this function and keeping track of the display another way or find an equivalent to + * PlatformUI.getWorkbench.getDisplay() working in E4. + */ + if (display == null) { + display = Display.getCurrent(); + if (display == null) { + display = Display.getDefault(); + } + } + return display; } /** @@ -205,18 +221,6 @@ public static Shell getShell() { if (display.isDisposed()) return null; - final IWorkbench workbench = PlatformUI.getWorkbench(); - - final IWorkbenchWindow activeWorkbenchWindow = workbench.getActiveWorkbenchWindow(); - - if (activeWorkbenchWindow != null && !activeWorkbenchWindow.getShell().isDisposed()) - return activeWorkbenchWindow.getShell(); - - final IWorkbenchWindow[] workbenchWindows = workbench.getWorkbenchWindows(); - - if (workbenchWindows.length > 0 && !workbenchWindows[0].getShell().isDisposed()) - return workbenchWindows[0].getShell(); - return display.getActiveShell(); } } diff --git a/eclipse/src/saros/ui/views/PopupMenu.java b/eclipse/src/saros/ui/views/PopupMenu.java new file mode 100644 index 0000000000..84e01833aa --- /dev/null +++ b/eclipse/src/saros/ui/views/PopupMenu.java @@ -0,0 +1,347 @@ +package saros.ui.views; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.PostConstruct; +import javax.inject.Named; +import org.eclipse.e4.ui.di.AboutToShow; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ISelection; +import saros.SarosPluginContext; +import saros.communication.InfoManager; +import saros.net.xmpp.JID; +import saros.net.xmpp.contact.XMPPContact; +import saros.preferences.PreferenceConstants; +import saros.repackaged.picocontainer.annotations.Inject; +import saros.session.ISarosSession; +import saros.session.ISarosSessionManager; +import saros.session.User; +import saros.ui.Messages; +import saros.ui.handlers.popup.ChangeColorHandler; +import saros.ui.handlers.popup.ChangeWriteAccessHandler; +import saros.ui.handlers.popup.DeleteContactHandler; +import saros.ui.handlers.popup.FollowThisPersonHandler; +import saros.ui.handlers.popup.JumpToUserWithWriteAccessPositionHandler; +import saros.ui.handlers.popup.OpenChatHandler; +import saros.ui.handlers.popup.RemoveUserHandler; +import saros.ui.handlers.popup.RenameContactHandler; +import saros.ui.handlers.popup.RequestSessionInviteHandler; +import saros.ui.handlers.popup.SendFileHandler; +import saros.ui.handlers.popup.SkypeHandler; +import saros.ui.util.selection.SelectionUtils; + +/** + * This class is responsible for creating the context menu for the saros view. + * The class is referenced by the fragment defining the popup menu. The + * createPopupMenu() method will be called by the eclipse 4 framework each time + * the context menu needs to be created. + */ +class PopupMenu { + + @Inject + protected ISarosSessionManager sarosSessionManager; + @Inject + private InfoManager infoManager; + + /* + * TODO What about having actions as (disposable and recreatable?) + * singletons? This map (together with register and get methods) would not + * be necessary, actions could be added to the menus at will (through a + * method that would remember only the disposable ones, so they can be + * disposed when necessary). + */ + private Map registeredMenuElements = new HashMap(); + + private static final String ICONS_DIR_PATH = "platform:/plugin/saros.eclipse/icons/"; + + private EModelService modelService; + + public PopupMenu() { + SarosPluginContext.initComponent(this); + } + + @PostConstruct + public void postConstruct(EModelService modelService) { + this.modelService = modelService; + + /** + * There are a few additional things in the Saros view. + * + *

+ * There is tool bar that holds the icons along the top (also see + * fragment.e4xmi). + * + *

+ * Also, there are context menus which appear when you: - right-click on + * a person in your current session - right-click on a contact in the + * contact list. + */ + createUIElements(); + } + + @AboutToShow + public void createPopupMenu(List elements, + EModelService modelService, + @Named(IServiceConstants.ACTIVE_SELECTION) ISelection activeSelection) { + addRosterMenuItems(elements, modelService, activeSelection); + addSessionMenuItems(elements, modelService, activeSelection); + } + + protected void addRosterMenuItems(List elements, + EModelService modelService, ISelection activeSelection) { + + /* + * Do not display the following actions if participants are selected. + */ + List participants = SelectionUtils + .getAdaptableObjects(activeSelection, User.class); + if (participants.size() > 0) + return; + + /* + * Do not display the following actions if no contacts are selected. + */ + List contacts = SelectionUtils + .getAdaptableObjects(activeSelection, XMPPContact.class); + if (contacts.isEmpty()) + return; + + XMPPContact contact = contacts.get(0); + + // TODO OLD Behavior: here (and at other places) we check if contact is + // online + // (currently you can invite a contact without saros support and get a + // error message), + // but could check already for saros support via + // contact.hasSarosSupport(). In this case + // we should probably add a Information about missing saros support. + if (sarosSessionManager.getSession() == null + && contact.getStatus().isOnline()) { + MMenu shareResourcesSubMenu = modelService + .createModelElement(MMenu.class); + shareResourcesSubMenu.setLabel("Share Resource(s)..."); + shareResourcesSubMenu.setIconURI( + "platform:/plugin/saros.eclipse/icons/elcl16/session_tsk.png"); + + List menuEntries = shareResourcesSubMenu + .getChildren(); + + StartSessionWithProjects sswp = new StartSessionWithProjects( + modelService, activeSelection); + sswp.createMenu(menuEntries); + + elements.add(shareResourcesSubMenu); + elements.add(modelService.createModelElement(MMenuSeparator.class)); + } + + // TODO: Currently only Saros/S is known to have a working + // JoinSessionRequestHandler, + // remove this once the situation changes / change this to it's own + // feature. + if (infoManager + .getRemoteInfo(contact, PreferenceConstants.SERVER_SUPPORT) + .isPresent()) { + elements.add(getMenuElement(RequestSessionInviteHandler.ID)); + elements.add(modelService.createModelElement(MMenuSeparator.class)); + } + + MMenuElement openChat = getMenuElement(OpenChatHandler.ID); + Map data = openChat.getTransientData(); + data.put("chatRoomsComposite", SarosView.chatRooms); + + // Add menu elements to popup menu + elements.add(getMenuElement(SkypeHandler.ID)); + elements.add(openChat); + elements.add(getMenuElement(SendFileHandler.ID)); + elements.add(getMenuElement(RenameContactHandler.ID)); + elements.add(getMenuElement(DeleteContactHandler.ID)); + } + + protected void addSessionMenuItems(List elements, + EModelService modelService, ISelection activeSelection) { + + /* + * TODO The decision whether to show an entry at all is made here, + * whereas the decision whether to enable an entry is encapsulated in + * each action. That does not feel right. + */ + /* + * Do not display the following actions if no participants are selected. + */ + List participants = SelectionUtils + .getAdaptableObjects(activeSelection, User.class); + if (participants.size() == 0) + return; + + /* + * Do not display the following actions if non-participants are + * selected. + */ + List contacts = SelectionUtils.getAdaptableObjects(activeSelection, + JID.class); + + if (contacts.size() > 0) + return; + + boolean isHost = false; + + ISarosSession session = sarosSessionManager.getSession(); + + if (session != null) + isHost = session.isHost(); + + if (participants.size() != 1) + return; + + if (participants.get(0).isLocal()) { + elements.add(getMenuElement(ChangeColorHandler.ID)); + + if (isHost) { + elements.add( + getMenuElement(ChangeWriteAccessHandler.WriteAccess.ID)); + + elements + .add(getMenuElement(ChangeWriteAccessHandler.ReadOnly.ID)); + } + } else { + if (isHost) { + elements.add( + getMenuElement(ChangeWriteAccessHandler.WriteAccess.ID)); + + elements + .add(getMenuElement(ChangeWriteAccessHandler.ReadOnly.ID)); + + elements.add(getMenuElement(RemoveUserHandler.ID)); + elements + .add(modelService.createModelElement(MMenuSeparator.class)); + } + elements.add(getMenuElement(FollowThisPersonHandler.ID)); + elements.add( + getMenuElement(JumpToUserWithWriteAccessPositionHandler.ID)); + + elements.add(modelService.createModelElement(MMenuSeparator.class)); + + elements.add(getMenuElement(OpenChatHandler.ID)); + elements.add(getMenuElement(SendFileHandler.ID)); + } + } + + private void registerMenuElement(MMenuElement menuItem) { + String id = menuItem.getElementId(); + if (registeredMenuElements.containsKey(id)) { + throw new IllegalArgumentException( + "tried to register menu element with id " + id + + " more than once"); + } + registeredMenuElements.put(id, menuItem); + } + + private MMenuElement getMenuElement(String menuElementId) { + MMenuElement menuElement = registeredMenuElements.get(menuElementId); + + if (menuElement == null) { + throw new IllegalArgumentException("a menu element for id " + + menuElementId + " is not registered"); + } + menuElement.setVisible(true); + return menuElement; + } + + private MMenuElement createMenuItem(String id, String label, String tooltip, + String iconPath, String handlerClass) { + MDirectMenuItem item = modelService + .createModelElement(MDirectMenuItem.class); + item.setElementId(id); + item.setLabel(label); + item.setContributionURI(handlerClass); + + if (tooltip != null) + item.setTooltip(tooltip); + if (iconPath != null) + item.setIconURI(iconPath); + + return item; + } + + /** + * Creates all needed menu items once and registers them, so they can be + * requested when constructing the context menu. + * + *

+ * In the eclipse 4 framework you can only reference icons with their path + * an not by an {@link ImageDescriptor}. So we created all referenced + * overlaid images. + */ + private void createUIElements() { + // ContextMenus Session + registerMenuElement(createMenuItem( + ChangeWriteAccessHandler.WriteAccess.ID, + Messages.GiveWriteAccessAction_title, + Messages.GiveWriteAccessAction_tooltip, + ICONS_DIR_PATH + "obj16/contact_saros_obj.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.ChangeWriteAccessHandler$WriteAccess")); + registerMenuElement(createMenuItem(ChangeWriteAccessHandler.ReadOnly.ID, + Messages.RestrictToReadOnlyAccessAction_title, + Messages.RestrictToReadOnlyAccessAction_tooltip, + ICONS_DIR_PATH + "merged16/contact_saros_obj_readonly.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.ChangeWriteAccessHandler$ReadOnly")); + registerMenuElement(createMenuItem(FollowThisPersonHandler.ID, + Messages.FollowThisPersonAction_follow_title, + Messages.FollowThisPersonAction_follow_tooltip, + ICONS_DIR_PATH + "merged16/contact_saros_obj_followmode.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.FollowThisPersonHandler")); + registerMenuElement(createMenuItem( + JumpToUserWithWriteAccessPositionHandler.ID, + Messages.JumpToUserWithWriteAccessPositionAction_title, + Messages.JumpToUserWithWriteAccessPositionAction_tooltip, + ICONS_DIR_PATH + "elcl16/jump.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.JumpToUserWithWriteAccessPositionHandler")); + // Using file_obj icon from org.eclipse.ui + registerMenuElement(createMenuItem(SendFileHandler.ID, + Messages.SendFileAction_title, Messages.SendFileAction_tooltip, + "platform:/plugin/org.eclipse.ui/icons/full/obj16/file_obj.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.SendFileHandler")); + registerMenuElement(createMenuItem(ChangeColorHandler.ID, + Messages.ChangeColorAction_title, + Messages.ChangeColorAction_tooltip, + ICONS_DIR_PATH + "elcl16/changecolor.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.ChangeColorHandler")); + registerMenuElement(createMenuItem(RemoveUserHandler.ID, + "Remove from Session", null, + ICONS_DIR_PATH + "elcl16/contact_remove_tsk.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.RemoveUserHandler")); + registerMenuElement(createMenuItem(RequestSessionInviteHandler.ID, + Messages.RequestSessionInviteAction_title, null, null, + "bundleclass://saros.eclipse/saros.ui.handlers.popup.RequestSessionInviteHandler")); + + // ContextMenus Roster/Contact list + registerMenuElement(createMenuItem(SkypeHandler.ID, + Messages.SkypeAction_title, Messages.SkypeAction_tooltip, + ICONS_DIR_PATH + "elcl16/contact_skype_call_tsk.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.SkypeHandler")); + registerMenuElement(createMenuItem(RenameContactHandler.ID, + Messages.RenameContactAction_title, + Messages.RenameContactAction_tooltip, + ICONS_DIR_PATH + "etool16/edit.gif", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.RenameContactHandler")); + // Using delete icon from org.eclipse.ui + registerMenuElement(createMenuItem(DeleteContactHandler.ID, + Messages.DeleteContactAction_title, + Messages.DeleteContactAction_tooltip, + "platform:/plugin/org.eclipse.ui/icons/full/etool16/delete.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.DeleteContactHandler")); + + // ContextMenus Both + registerMenuElement(createMenuItem(OpenChatHandler.ID, + Messages.OpenChatAction_MenuItem, null, + ICONS_DIR_PATH + "view16/chat_misc.png", + "bundleclass://saros.eclipse/saros.ui.handlers.popup.OpenChatHandler")); + } +} diff --git a/eclipse/src/saros/ui/views/SarosView.java b/eclipse/src/saros/ui/views/SarosView.java index b47d527e9b..7342a9fba5 100644 --- a/eclipse/src/saros/ui/views/SarosView.java +++ b/eclipse/src/saros/ui/views/SarosView.java @@ -1,23 +1,23 @@ package saros.ui.views; -import java.util.HashMap; import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.apache.log4j.Logger; import org.eclipse.core.runtime.Platform; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.action.IMenuListener; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.IToolBarManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.services.EMenuService; +import org.eclipse.e4.ui.workbench.modeling.EPartService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.e4.ui.workbench.modeling.IPartListener; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; @@ -32,26 +32,17 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; -import org.eclipse.ui.IActionBars; -import org.eclipse.ui.IPartListener2; -import org.eclipse.ui.IViewPart; -import org.eclipse.ui.IWorkbenchActionConstants; -import org.eclipse.ui.IWorkbenchPartReference; -import org.eclipse.ui.part.ViewPart; import saros.SarosPluginContext; import saros.annotations.Component; import saros.communication.InfoManager; import saros.editor.EditorManager; -import saros.net.xmpp.JID; import saros.net.xmpp.contact.ContactStatus.Type; import saros.net.xmpp.contact.IContactsUpdate; import saros.net.xmpp.contact.XMPPContact; import saros.net.xmpp.contact.XMPPContactsService; import saros.preferences.EclipsePreferenceConstants; -import saros.preferences.PreferenceConstants; import saros.repackaged.picocontainer.annotations.Inject; import saros.session.ISarosSession; import saros.session.ISarosSessionManager; @@ -59,33 +50,12 @@ import saros.session.SessionEndReason; import saros.session.User; import saros.ui.BalloonNotification; -import saros.ui.ImageManager; import saros.ui.Messages; -import saros.ui.actions.ChangeColorAction; -import saros.ui.actions.ChangeWriteAccessAction; -import saros.ui.actions.ChangeXMPPAccountAction; -import saros.ui.actions.ConsistencyAction; -import saros.ui.actions.DeleteContactAction; -import saros.ui.actions.Disposable; -import saros.ui.actions.FollowModeAction; -import saros.ui.actions.FollowThisPersonAction; -import saros.ui.actions.JumpToUserWithWriteAccessPositionAction; -import saros.ui.actions.LeaveSessionAction; -import saros.ui.actions.NewContactAction; -import saros.ui.actions.OpenChatAction; -import saros.ui.actions.OpenPreferencesAction; -import saros.ui.actions.RemoveUserAction; -import saros.ui.actions.RenameContactAction; -import saros.ui.actions.RequestSessionInviteAction; -import saros.ui.actions.SendFileAction; -import saros.ui.actions.SkypeAction; -import saros.ui.menu_contributions.StartSessionWithProjects; import saros.ui.model.roster.RosterEntryElement; import saros.ui.sounds.SoundPlayer; import saros.ui.sounds.Sounds; import saros.ui.util.LayoutUtils; import saros.ui.util.SWTUtils; -import saros.ui.util.selection.retriever.SelectionRetrieverFactory; import saros.ui.widgets.ConnectionStateComposite; import saros.ui.widgets.chat.ChatRoomsComposite; import saros.ui.widgets.viewer.ViewerComposite; @@ -106,651 +76,424 @@ /** This view displays the contact list, the Saros Session and Saros Chat. */ @Component(module = "ui") -public class SarosView extends ViewPart { +public class SarosView { - private static final Logger log = Logger.getLogger(SarosView.class); + private static final Logger log = Logger.getLogger(SarosView.class); - public static final String ID = "saros.ui.views.SarosView"; + public static final String ID = "saros.ui.views.SarosView"; - private final IContactsUpdate contactsUpdate = - new IContactsUpdate() { + private final IContactsUpdate contactsUpdate = new IContactsUpdate() { private final Set wasAlreadyAvailable = new HashSet<>(); @Override - public void update(Optional contactOptional, UpdateType type) { - if (type != IContactsUpdate.UpdateType.STATUS || !contactOptional.isPresent()) { - return; - } - - XMPPContact contact = contactOptional.get(); - Type contactStatus = contact.getStatus().getType(); - boolean wasAvailable = wasAlreadyAvailable.contains(contact); - - if (contactStatus == Type.AVAILABLE && !wasAvailable) { - wasAlreadyAvailable.add(contact); - if (playAvailableSound) SoundPlayer.playSound(Sounds.USER_ONLINE); - } else if (contactStatus == Type.OFFLINE && wasAvailable) { - wasAlreadyAvailable.remove(contact); - if (playUnavailableSound) SoundPlayer.playSound(Sounds.USER_OFFLINE); - } - } - }; + public void update(Optional contactOptional, + UpdateType type) { + if (type != IContactsUpdate.UpdateType.STATUS + || !contactOptional.isPresent()) { + return; + } - private final IPartListener2 partListener = - new IPartListener2() { - @Override - public void partInputChanged(IWorkbenchPartReference partRef) { - // do nothing + XMPPContact contact = contactOptional.get(); + Type contactStatus = contact.getStatus().getType(); + boolean wasAvailable = wasAlreadyAvailable.contains(contact); + + if (contactStatus == Type.AVAILABLE && !wasAvailable) { + wasAlreadyAvailable.add(contact); + if (playAvailableSound) + SoundPlayer.playSound(Sounds.USER_ONLINE); + } else if (contactStatus == Type.OFFLINE && wasAvailable) { + wasAlreadyAvailable.remove(contact); + if (playUnavailableSound) + SoundPlayer.playSound(Sounds.USER_OFFLINE); + } } + }; - @Override - public void partVisible(IWorkbenchPartReference partRef) { - // do nothing - } + private final IPartListener partListener = new IPartListener() { @Override - public void partHidden(IWorkbenchPartReference partRef) { - // do nothing + public void partVisible(MPart part) { + // TODO Auto-generated method stub + } @Override - public void partOpened(IWorkbenchPartReference partRef) { - // do nothing + public void partHidden(MPart part) { + // TODO Auto-generated method stub + } @Override - public void partDeactivated(IWorkbenchPartReference partRef) { - if (sessionDisplay != null && !sessionDisplay.isDisposed()) { - sessionDisplay - .getViewer() - .setSelection( - new ISelection() { - @Override - public boolean isEmpty() { + public void partDeactivated(MPart part) { + if (sessionDisplay != null && !sessionDisplay.isDisposed()) { + sessionDisplay.getViewer().setSelection(new ISelection() { + @Override + public boolean isEmpty() { return true; - } - }); - } + } + }); + } } @Override - public void partClosed(IWorkbenchPartReference partRef) { - getViewSite().getPage().removePartListener(partListener); - } + public void partBroughtToTop(MPart part) { + // TODO Auto-generated method stub - @Override - public void partBroughtToTop(IWorkbenchPartReference partRef) { - // do nothing } @Override - public void partActivated(IWorkbenchPartReference partRef) { - // do nothing + public void partActivated(MPart part) { + // TODO Auto-generated method stub + } - }; + }; - private final IPropertyChangeListener propertyListener = - new IPropertyChangeListener() { + private final IPropertyChangeListener propertyListener = new IPropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { - boolean newValue = Boolean.parseBoolean(event.getNewValue().toString()); - switch (event.getProperty()) { + boolean newValue = Boolean + .parseBoolean(event.getNewValue().toString()); + switch (event.getProperty()) { case EclipsePreferenceConstants.ENABLE_BALLOON_NOTIFICATION: - showBalloonNotifications = newValue; - break; + showBalloonNotifications = newValue; + break; case EclipsePreferenceConstants.SOUND_PLAY_EVENT_CONTACT_ONLINE: - playAvailableSound = newValue; - break; + playAvailableSound = newValue; + break; case EclipsePreferenceConstants.SOUND_PLAY_EVENT_CONTACT_OFFLINE: - playUnavailableSound = newValue; - break; - } + playUnavailableSound = newValue; + break; + } } - }; + }; - private final ISessionLifecycleListener sessionLifecycleListener = - new ISessionLifecycleListener() { + private final ISessionLifecycleListener sessionLifecycleListener = new ISessionLifecycleListener() { @Override - public void sessionEnded(ISarosSession session, SessionEndReason reason) { - showStopNotification(session.getHost(), reason); + public void sessionEnded(ISarosSession session, + SessionEndReason reason) { + showStopNotification(session.getHost(), reason); } - }; + }; + + protected Composite leftComposite; - protected Composite leftComposite; + protected ViewerComposite sessionDisplay; - protected ViewerComposite sessionDisplay; + static ChatRoomsComposite chatRooms; - protected ChatRoomsComposite chatRooms; + @Inject + protected IPreferenceStore preferenceStore; - @Inject protected IPreferenceStore preferenceStore; + @Inject + protected ISarosSessionManager sarosSessionManager; - @Inject protected ISarosSessionManager sarosSessionManager; + @Inject + protected EditorManager editorManager; - @Inject protected EditorManager editorManager; + @Inject + private XMPPContactsService contactsService; - @Inject private XMPPContactsService contactsService; + @Inject + private InfoManager infoManager; - @Inject private InfoManager infoManager; + private static EPartService ePartService; - private static volatile boolean showBalloonNotifications; - private volatile boolean playAvailableSound; - private volatile boolean playUnavailableSound; + private static volatile boolean showBalloonNotifications; + private volatile boolean playAvailableSound; + private volatile boolean playUnavailableSound; - private Composite notificationAnchor; + private Composite notificationAnchor; - /** - * Stores actions by their {@link IAction#getId() ID}, so they can (1) be {@linkplain - * #getAction(String) retrieved} and (2) {@linkplain Disposable#dispose() disposed} when and if - * necessary. - */ - /* - * TODO What about having actions as (disposable and recreatable?) - * singletons? This map (together with register and get methods) would not - * be necessary, actions could be added to the menus at will (through a - * method that would remember only the disposable ones, so they can be - * disposed when necessary). - */ - private Map registeredActions = new HashMap(); + public SarosView() { + SarosPluginContext.initComponent(this); + preferenceStore.addPropertyChangeListener(propertyListener); + sarosSessionManager + .addSessionLifecycleListener(sessionLifecycleListener); + + showBalloonNotifications = preferenceStore + .getBoolean(EclipsePreferenceConstants.ENABLE_BALLOON_NOTIFICATION); + playAvailableSound = preferenceStore.getBoolean( + EclipsePreferenceConstants.SOUND_PLAY_EVENT_CONTACT_ONLINE); + playUnavailableSound = preferenceStore.getBoolean( + EclipsePreferenceConstants.SOUND_PLAY_EVENT_CONTACT_OFFLINE); + } + + /** + * @JTourBusStop 2, The Interface Tour: + * + *

+ * The createPartControl method constructs the view's + * controls. + * + *

+ * Notice that the SarosView class doesn't contain everything. + * Rather it arranges and manages other components which carry + * out most of the functionality. + * + *

+ * You should have noticed that the Saros view is divided into + * parts, left and right. The left side is a composite of the + * session information and the roster. The right side + * alternates between an info/chat window. + */ + @PostConstruct + public void createPartControl(Composite parent, EPartService partService, + EMenuService menuService, ESelectionService selectionService) { - public SarosView() { - super(); - SarosPluginContext.initComponent(this); - preferenceStore.addPropertyChangeListener(propertyListener); - sarosSessionManager.addSessionLifecycleListener(sessionLifecycleListener); + ePartService = partService; - showBalloonNotifications = - preferenceStore.getBoolean(EclipsePreferenceConstants.ENABLE_BALLOON_NOTIFICATION); - playAvailableSound = - preferenceStore.getBoolean(EclipsePreferenceConstants.SOUND_PLAY_EVENT_CONTACT_ONLINE); - playUnavailableSound = - preferenceStore.getBoolean(EclipsePreferenceConstants.SOUND_PLAY_EVENT_CONTACT_OFFLINE); - } + GridData gridData; - /** - * @JTourBusStop 2, The Interface Tour: - * - *

The createPartControl method constructs the view's controls. - * - *

Notice that the SarosView class doesn't contain everything. Rather it arranges and manages - * other components which carry out most of the functionality. - * - *

You should have noticed that the Saros view is divided into parts, left and right. The left - * side is a composite of the session information and the roster. The right side alternates - * between an info/chat window. - */ - @Override - public void createPartControl(Composite parent) { + final GridLayout layout = new GridLayout(1, false); - GridData gridData; + layout.horizontalSpacing = 0; + layout.verticalSpacing = 0; - final GridLayout layout = new GridLayout(1, false); + parent.setLayout(layout); - layout.horizontalSpacing = 0; - layout.verticalSpacing = 0; + final SashForm baseSashForm = new SashForm(parent, SWT.SMOOTH); - parent.setLayout(layout); + gridData = new GridData(SWT.FILL, SWT.FILL, true, true); - final SashForm baseSashForm = new SashForm(parent, SWT.SMOOTH); + baseSashForm.setLayoutData(gridData); + /* + * LEFT COLUMN + */ + leftComposite = new Composite(baseSashForm, SWT.BORDER); + leftComposite.setLayout(LayoutUtils.createGridLayout()); + leftComposite.setBackground( + Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); - gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + /** Sash weight remembering */ + leftComposite.addControlListener(new ControlListener() { + @Override + public void controlResized(ControlEvent e) { + preferenceStore.setValue( + EclipsePreferenceConstants.SAROSVIEW_SASH_WEIGHT_LEFT, + baseSashForm.getWeights()[0]); + preferenceStore.setValue( + EclipsePreferenceConstants.SAROSVIEW_SASH_WEIGHT_RIGHT, + baseSashForm.getWeights()[1]); + } - baseSashForm.setLayoutData(gridData); - /* - * LEFT COLUMN - */ - leftComposite = new Composite(baseSashForm, SWT.BORDER); - leftComposite.setLayout(LayoutUtils.createGridLayout()); - leftComposite.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); - - /** Sash weight remembering */ - leftComposite.addControlListener( - new ControlListener() { - @Override - public void controlResized(ControlEvent e) { - preferenceStore.setValue( - EclipsePreferenceConstants.SAROSVIEW_SASH_WEIGHT_LEFT, - baseSashForm.getWeights()[0]); - preferenceStore.setValue( - EclipsePreferenceConstants.SAROSVIEW_SASH_WEIGHT_RIGHT, - baseSashForm.getWeights()[1]); - } - - @Override - public void controlMoved(ControlEvent e) { - // NOP - } + @Override + public void controlMoved(ControlEvent e) { + // NOP + } }); - ConnectionStateComposite connectionStateComposite = - new ConnectionStateComposite(leftComposite, SWT.NONE); - connectionStateComposite.setLayoutData(LayoutUtils.createFillHGrabGridData()); + ConnectionStateComposite connectionStateComposite = new ConnectionStateComposite( + leftComposite, SWT.NONE); + connectionStateComposite + .setLayoutData(LayoutUtils.createFillHGrabGridData()); - sessionDisplay = new XMPPSessionDisplayComposite(leftComposite, SWT.V_SCROLL); - sessionDisplay.setLayoutData(LayoutUtils.createFillGridData()); + sessionDisplay = new XMPPSessionDisplayComposite(leftComposite, + SWT.V_SCROLL); + sessionDisplay.setLayoutData(LayoutUtils.createFillGridData()); - final Control control = sessionDisplay.getViewer().getControl(); + final Control control = sessionDisplay.getViewer().getControl(); - control.addMouseListener( - new MouseAdapter() { - @Override - public void mouseDoubleClick(MouseEvent event) { + control.addMouseListener(new MouseAdapter() { + @Override + public void mouseDoubleClick(MouseEvent event) { - if (!(control instanceof Tree)) return; + if (!(control instanceof Tree)) + return; - TreeItem treeItem = ((Tree) control).getItem(new Point(event.x, event.y)); + TreeItem treeItem = ((Tree) control) + .getItem(new Point(event.x, event.y)); - if (treeItem == null) return; + if (treeItem == null) + return; - RosterEntryElement rosterEntryElement = - Platform.getAdapterManager() + RosterEntryElement rosterEntryElement = Platform + .getAdapterManager() .getAdapter(treeItem.getData(), RosterEntryElement.class); - if (rosterEntryElement == null) return; + if (rosterEntryElement == null) + return; - chatRooms.openChat(rosterEntryElement.getJID(), true); - } + chatRooms.openChat(rosterEntryElement.getJID(), true); + } }); - /* - * RIGHT COLUMN - */ - Composite rightComposite = new Composite(baseSashForm, SWT.NONE); - rightComposite.setLayout(new FillLayout()); + /* + * RIGHT COLUMN + */ + Composite rightComposite = new Composite(baseSashForm, SWT.NONE); + rightComposite.setLayout(new FillLayout()); - /* - * Initialize sash form weights from preferences (remembering the layout - * of the saros view), if no prefs exist (first start) use a 50/50 space - * distribution. - * - * Can only set the sash weights after adding all direct child elements - * of the baseSashForm. - */ - int[] weights = - new int[] { - preferenceStore.getInt(EclipsePreferenceConstants.SAROSVIEW_SASH_WEIGHT_LEFT), - preferenceStore.getInt(EclipsePreferenceConstants.SAROSVIEW_SASH_WEIGHT_RIGHT) - }; - baseSashForm.setWeights(weights); + /* + * Initialize sash form weights from preferences (remembering the layout + * of the saros view), if no prefs exist (first start) use a 50/50 space + * distribution. + * + * Can only set the sash weights after adding all direct child elements + * of the baseSashForm. + */ + int[] weights = new int[] { + preferenceStore + .getInt(EclipsePreferenceConstants.SAROSVIEW_SASH_WEIGHT_LEFT), + preferenceStore.getInt( + EclipsePreferenceConstants.SAROSVIEW_SASH_WEIGHT_RIGHT) }; + baseSashForm.setWeights(weights); - chatRooms = new ChatRoomsComposite(rightComposite, SWT.NONE); + chatRooms = new ChatRoomsComposite(rightComposite, SWT.NONE); - notificationAnchor = new Composite(parent, SWT.NONE); + notificationAnchor = new Composite(parent, SWT.NONE); - gridData = new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false); - gridData.heightHint = 0; + gridData = new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false); + gridData.heightHint = 0; - notificationAnchor.setLayoutData(gridData); - notificationAnchor.setVisible(false); + notificationAnchor.setLayoutData(gridData); + notificationAnchor.setVisible(false); - /** - * @JTourBusStop 3, The Interface Tour: - * - *

There are a few additional things in the Saros view. - * - *

There is tool bar that holds the icons along the top (also see addToolbarItems() below). - * - *

Also, there are context menus which appear when you: - right-click on a person in your - * current session - right-click on a contact in the contact list. - */ - createActions(); + Viewer sessionViewer = sessionDisplay.getViewer(); - /* - * Toolbar - */ - IActionBars bars = getViewSite().getActionBars(); - IToolBarManager toolBar = bars.getToolBarManager(); - addToolBarItems(toolBar); + menuService.registerContextMenu(sessionViewer.getControl(), + "saros.ui.popup.menu"); - /* - * Context Menu - */ - MenuManager menuManager = new MenuManager(); - menuManager.setRemoveAllWhenShown(true); - addMenuStartSeparator(menuManager); - addRosterMenuItems(menuManager); - addSessionMenuItems(menuManager); - addAdditionsSeparator(menuManager); - - Viewer sessionViewer = sessionDisplay.getViewer(); - Menu menu = menuManager.createContextMenu(sessionViewer.getControl()); - sessionViewer.getControl().setMenu(menu); - getSite().registerContextMenu(menuManager, sessionViewer); - getSite().setSelectionProvider(sessionViewer); - - contactsService.addListener(contactsUpdate); - - getViewSite().getPage().addPartListener(partListener); - } - - protected void addToolBarItems(IToolBarManager toolBar) { - toolBar.add(getAction(ChangeXMPPAccountAction.ACTION_ID)); - toolBar.add(getAction(NewContactAction.ACTION_ID)); - toolBar.add(getAction(OpenPreferencesAction.ACTION_ID)); - toolBar.add(new Separator()); - toolBar.add(getAction(FollowModeAction.ACTION_ID)); - toolBar.add(getAction(ConsistencyAction.ACTION_ID)); - toolBar.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); - toolBar.add(getAction(LeaveSessionAction.ACTION_ID)); - } - - /** @param menuManager */ - protected void addRosterMenuItems(MenuManager menuManager) { - - menuManager.addMenuListener( - new IMenuListener() { - @Override - public void menuAboutToShow(final IMenuManager manager) { - /* - * Do not display the following actions if participants are - * selected. - */ - List participants = - SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); - if (participants.size() > 0) return; - - /* - * Do not display the following actions if no contacts are - * selected. - */ - List contacts = - SelectionRetrieverFactory.getSelectionRetriever(XMPPContact.class).getSelection(); - if (contacts.isEmpty()) return; - - XMPPContact contact = contacts.get(0); - - // TODO OLD Behavior: here (and at other places) we check if contact is online - // (currently you can invite a contact without saros support and get a error message), - // but could check already for saros support via contact.hasSarosSupport(). In this case - // we should probably add a Information about missing saros support. - if (sarosSessionManager.getSession() == null && contact.getStatus().isOnline()) { - MenuManager shareResourcesSubMenu = - new MenuManager( - "Share Resource(s)...", - ImageManager.getImageDescriptor(ImageManager.ELCL_SESSION), - "Share_Resources"); - - shareResourcesSubMenu.add(new StartSessionWithProjects()); - // TODO it seems it not that trivial to add tooltips to these entries - manager.add(shareResourcesSubMenu); - manager.add(new Separator()); - } + sessionViewer + .addSelectionChangedListener(new ISelectionChangedListener() { - // TODO: Currently only Saros/S is known to have a working JoinSessionRequestHandler, - // remove this once the situation changes / change this to it's own feature. - if (infoManager - .getRemoteInfo(contact, PreferenceConstants.SERVER_SUPPORT) - .isPresent()) { - manager.add(getAction(RequestSessionInviteAction.ACTION_ID)); - manager.add(new Separator()); - } - - manager.add(getAction(SkypeAction.ACTION_ID)); - manager.add(getAction(OpenChatAction.ACTION_ID)); - manager.add(getAction(SendFileAction.ACTION_ID)); - manager.add(getAction(RenameContactAction.ACTION_ID)); - manager.add(getAction(DeleteContactAction.ACTION_ID)); - } - }); - } - - /** @param menuManager */ - protected void addSessionMenuItems(MenuManager menuManager) { - - /* - * TODO The decision whether to show an entry at all is made here, - * whereas the decision whether to enable an entry is encapsulated in - * each action. That does not feel right. - */ - menuManager.addMenuListener( - new IMenuListener() { - - @Override - public void menuAboutToShow(IMenuManager manager) { - /* - * Do not display the following actions if no participants are - * selected. - */ - List participants = - SelectionRetrieverFactory.getSelectionRetriever(User.class).getSelection(); - if (participants.size() == 0) return; - - /* - * Do not display the following actions if non-participants are - * selected. - */ - List contacts = - SelectionRetrieverFactory.getSelectionRetriever(JID.class).getSelection(); - - if (contacts.size() > 0) return; - - boolean isHost = false; - - ISarosSession session = sarosSessionManager.getSession(); - - if (session != null) isHost = session.isHost(); - - if (participants.size() != 1) return; - - if (participants.get(0).isLocal()) { - manager.add(getAction(ChangeColorAction.ACTION_ID)); - - if (isHost) { - manager.add(getAction(ChangeWriteAccessAction.WriteAccess.ACTION_ID)); - - manager.add(getAction(ChangeWriteAccessAction.ReadOnly.ACTION_ID)); - } - } else { - if (isHost) { - manager.add(getAction(ChangeWriteAccessAction.WriteAccess.ACTION_ID)); - - manager.add(getAction(ChangeWriteAccessAction.ReadOnly.ACTION_ID)); - - manager.add(getAction(RemoveUserAction.ACTION_ID)); - manager.add(new Separator()); - } - manager.add(getAction(FollowThisPersonAction.ACTION_ID)); - manager.add(getAction(JumpToUserWithWriteAccessPositionAction.ACTION_ID)); - manager.add(new Separator()); - manager.add(getAction(OpenChatAction.ACTION_ID)); - manager.add(getAction(SendFileAction.ACTION_ID)); - } - } - }); - } - - /** - * Adds the {@link IWorkbenchActionConstants#MB_ADDITIONS additions} {@link Separator} to the - * {@link MenuManager} in order to let others extend the menu. - * - * @param menuManager - */ - protected void addAdditionsSeparator(MenuManager menuManager) { - menuManager.addMenuListener( - new IMenuListener() { - @Override - public void menuAboutToShow(IMenuManager manager) { - manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); - } - }); - } - - protected void addMenuStartSeparator(MenuManager menuManager) { - menuManager.addMenuListener( - new IMenuListener() { - @Override - public void menuAboutToShow(IMenuManager manager) { - Separator menuStart = new Separator("menustart"); - menuStart.setVisible(false); - manager.add(menuStart); - } - }); - } + @Override + public void selectionChanged(SelectionChangedEvent event) { + selectionService.setSelection(event.getSelection()); + } + }); - @Override - public void dispose() { - super.dispose(); + contactsService.addListener(contactsUpdate); - contactsService.removeListener(contactsUpdate); - - for (IAction action : registeredActions.values()) - if (action instanceof Disposable) ((Disposable) action).dispose(); - } - - /** - * Display a notification next to the given control. - * - * @param title - * @param text - * @param control - */ - public static void showNotification( - final String title, final String text, final Control control) { - if (title == null) throw new NullPointerException("title is null"); + partService.addPartListener(partListener); + } - if (text == null) throw new NullPointerException("text is null"); + @PreDestroy + public void dispose(EPartService partService) { + partService.removePartListener(partListener); + contactsService.removeListener(contactsUpdate); + } - if (!showBalloonNotifications) return; + /** + * Display a notification next to the given control. + * + * @param title + * @param text + * @param control + */ + public static void showNotification(final String title, final String text, + final Control control) { + if (title == null) + throw new NullPointerException("title is null"); - SWTUtils.runSafeSWTAsync( - log, - new Runnable() { - @Override - public void run() { + if (text == null) + throw new NullPointerException("text is null"); - Control attachToControl = control; + if (!showBalloonNotifications) + return; - if (attachToControl != null) { - BalloonNotification.showNotification( - attachToControl, SWT.LEFT | SWT.BOTTOM, title, text); - return; + SWTUtils.runSafeSWTAsync(log, new Runnable() { + @Override + public void run() { + + Control attachToControl = control; + + if (attachToControl != null) { + BalloonNotification.showNotification(attachToControl, + SWT.LEFT | SWT.BOTTOM, title, text); + return; + } + + if (ePartService != null) { + MPart sarosView = ePartService + .findPart("saros.ui.e4.views.SarosView"); + if (sarosView != null && sarosView.getObject() != null) { + attachToControl = ((SarosView) sarosView + .getObject()).notificationAnchor; + } + } else { + attachToControl = Display.getCurrent().getFocusControl(); + } + // IViewPart sarosView = SWTUtils.findView(SarosView.ID); + + /* + * If no session view is open then show the balloon notification + * in the control which has the keyboard focus + */ + + /* + * if (sarosView != null) { attachToControl = ((SarosView) + * sarosView).notificationAnchor; } else { attachToControl = + * Display.getCurrent().getFocusControl(); } + */ + + BalloonNotification.showNotification(attachToControl, + SWT.LEFT | SWT.BOTTOM, title, text); } + }); + } - IViewPart sarosView = SWTUtils.findView(SarosView.ID); - - /* - * If no session view is open then show the balloon notification - * in the control which has the keyboard focus - */ + /** + * Displays a notification next to the Saros View. If the view cannot be + * found the notification is displayed next to the element that has the + * current focus. The visibility time of the notification will vary, + * depending on how much words the text contains. This method SHOULD + * NOT be called directly from the business logic. + * + * @param title + * the title of the notification + * @param text + * the text of the notification + * @throws NullPointerException + * if title or text is null + */ + public static void showNotification(final String title, final String text) { + showNotification(title, text, null); + } - if (sarosView != null) { - attachToControl = ((SarosView) sarosView).notificationAnchor; - } else { - attachToControl = Display.getCurrent().getFocusControl(); - } + /** + * TODO Move to (yet-to-be-created) IDE-independent NotificationHandler + * class + */ + public static void showStopNotification(User user, + SessionEndReason reason) { + String text = null; + String title = null; + + switch (reason) { + case KICKED: + title = Messages.SessionStop_host_removed_you_title; + text = CoreUtils + .format(Messages.SessionStop_host_removed_you_message, user); + break; + + case HOST_LEFT: + title = Messages.SessionStop_host_closed_session_title; + text = CoreUtils + .format(Messages.SessionStop_host_closed_session_message, user); + break; + case CONNECTION_LOST: + // TODO display the error + return; + case LOCAL_USER_LEFT: + return; + default: + log.warn("no UI notification available for stop reason: " + reason); + return; + } - BalloonNotification.showNotification( - attachToControl, SWT.LEFT | SWT.BOTTOM, title, text); - } - }); - } - - /** - * Displays a notification next to the Saros View. If the view cannot be found the notification is - * displayed next to the element that has the current focus. The visibility time of the - * notification will vary, depending on how much words the text contains. This method SHOULD - * NOT be called directly from the business logic. - * - * @param title the title of the notification - * @param text the text of the notification - * @throws NullPointerException if title or text is null - */ - public static void showNotification(final String title, final String text) { - showNotification(title, text, null); - } - - /** TODO Move to (yet-to-be-created) IDE-independent NotificationHandler class */ - public static void showStopNotification(User user, SessionEndReason reason) { - String text = null; - String title = null; - - switch (reason) { - case KICKED: - title = Messages.SessionStop_host_removed_you_title; - text = CoreUtils.format(Messages.SessionStop_host_removed_you_message, user); - break; - - case HOST_LEFT: - title = Messages.SessionStop_host_closed_session_title; - text = CoreUtils.format(Messages.SessionStop_host_closed_session_message, user); - break; - case CONNECTION_LOST: - // TODO display the error - return; - case LOCAL_USER_LEFT: - return; - default: - log.warn("no UI notification available for stop reason: " + reason); - return; + showNotification(title, text); } - showNotification(title, text); - } - - /** - * Remove any balloon notifications that might be left, because they have become obsolete for a - * reason - */ - public static void clearNotifications() { - SWTUtils.runSafeSWTAsync( - log, - new Runnable() { - @Override - public void run() { - BalloonNotification.removeAllActiveNotifications(); - } + /** + * Remove any balloon notifications that might be left, because they have + * become obsolete for a reason + */ + public static void clearNotifications() { + SWTUtils.runSafeSWTAsync(log, new Runnable() { + @Override + public void run() { + BalloonNotification.removeAllActiveNotifications(); + } }); - } - - @Override - public void setFocus() { - // TODO Auto-generated method stub - } - - private void createActions() { - - // ContextMenus Session - registerAction(ChangeWriteAccessAction.WriteAccess.newInstance()); - registerAction(ChangeWriteAccessAction.ReadOnly.newInstance()); - registerAction(new FollowThisPersonAction()); - registerAction(new JumpToUserWithWriteAccessPositionAction()); - registerAction(new SendFileAction()); - registerAction(new ChangeColorAction()); - registerAction(new RemoveUserAction()); - registerAction(new RequestSessionInviteAction()); - - // ContextMenus Roster/Contact list - registerAction(new SkypeAction()); - registerAction(new RenameContactAction()); - registerAction(new DeleteContactAction()); - - // ContextMenus Both - registerAction(new OpenChatAction(chatRooms)); - - // Toolbar - registerAction(new ChangeXMPPAccountAction()); - registerAction(new NewContactAction()); - registerAction(new OpenPreferencesAction()); - registerAction(new FollowModeAction()); - registerAction(new ConsistencyAction()); - registerAction(new LeaveSessionAction()); - } - - private IAction getAction(String id) { - IAction action = registeredActions.get(id); - - if (action == null) - throw new IllegalArgumentException("an action for id " + id + " is not registered"); - - return action; - } - - private IAction registerAction(IAction action) { - IAction oldAction = registeredActions.put(action.getId(), action); - - if (oldAction != null) - throw new IllegalArgumentException( - "tried to register action with id " + action.getId() + " more than once"); - - return action; - } + } } diff --git a/eclipse/src/saros/ui/views/StartSessionWithProjects.java b/eclipse/src/saros/ui/views/StartSessionWithProjects.java new file mode 100644 index 0000000000..cd964494c0 --- /dev/null +++ b/eclipse/src/saros/ui/views/StartSessionWithProjects.java @@ -0,0 +1,141 @@ +package saros.ui.views; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import javax.inject.Inject; +import javax.inject.Named; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.jface.viewers.ISelection; +import saros.net.xmpp.JID; +import saros.ui.Messages; +import saros.ui.util.CollaborationUtils; +import saros.ui.util.WizardUtils; +import saros.ui.util.selection.SelectionUtils; +import saros.ui.wizards.StartSessionWizard; + +/** + * Creates a context menu filled with entries, each of which represents a project that currently + * exists in the workspace. Each entry will trigger a session negotiation with the given project. + * + *

In addition, if multiple projects are present in the workspace, an additional entry will be + * displayed which will open a {@linkplain StartSessionWizard wizard} instead. + */ +public class StartSessionWithProjects { + + @Inject + public StartSessionWithProjects( + EModelService service, + @Named(IServiceConstants.ACTIVE_SELECTION) ISelection activeSelection) { + this.service = service; + selection = activeSelection; + } + + static class MultipleProjectMenuItemHandler { + + @Execute + public void execute() { + WizardUtils.openStartSessionWizard(null); + } + } + + static class ProjectMenuItemHandler { + + @Execute + public void execute(MDirectMenuItem menuItem) { + Map objectData = menuItem.getTransientData(); + IProject project = (IProject) objectData.get("project"); + List contacts = (List) objectData.get("contacts"); + + CollaborationUtils.startSession(Collections.singleton(project), contacts); + } + } + + private List menuEntries; + private EModelService service; + + private ISelection selection; + + public void createMenu(List menuEntries) { + this.menuEntries = menuEntries; + + final List contacts = SelectionUtils.getAdaptableObjects(selection, JID.class); + + final IProject[] projects = getSortedWorkspaceProjects(); + + if (projects.length == 0) { + createNoProjectsMenuItem(0); + return; + } + + int idx; + + for (idx = 0; idx < projects.length; idx++) createProjectMenuItem(idx, projects[idx], contacts); + + if (idx > 1) { + menuEntries.add(idx++, service.createModelElement(MMenuSeparator.class)); + createMultipleProjectMenuItem(idx); + } + } + + /** Returns a sorted list of all {@link IProject}s in the {@link IWorkspace}. */ + private IProject[] getSortedWorkspaceProjects() { + final IProject[] workspaceProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + + Arrays.sort( + workspaceProjects, + new Comparator() { + @Override + public int compare(final IProject a, final IProject b) { + return a.getName().compareToIgnoreCase(b.getName()); + } + }); + + return workspaceProjects; + } + + /** Creates a menu entry which shares projects with the given Contacts. */ + private void createProjectMenuItem( + final int index, final IProject project, final List contacts) { + + MDirectMenuItem projectMenuItem = service.createModelElement(MDirectMenuItem.class); + projectMenuItem.setLabel(project.getName()); + projectMenuItem.setContributionURI( + "bundleclass://saros.eclipse/saros.ui.e4.views.StartSessionWithProjects$MultipleProjectMenuItemHandler"); + // TODO: set icon for menu element, old e3 variant : workbenchLabelProvider.getImage(project) + + Map objectData = projectMenuItem.getTransientData(); + objectData.put("project", project); + objectData.put("contacts", contacts); + + menuEntries.add(index, projectMenuItem); + } + + private void createMultipleProjectMenuItem(final int index) { + MDirectMenuItem multipleProjectMenuItem = service.createModelElement(MDirectMenuItem.class); + multipleProjectMenuItem.setLabel("Specific resource tree(s)..."); + multipleProjectMenuItem.setContributionURI( + "bundleclass://saros.eclipse/saros.ui.e4.views.StartSessionWithProjects$MultipleProjectMenuItemHandler"); + + menuEntries.add(index, multipleProjectMenuItem); + } + + /** Creates a menu entry which indicates that no Saros enabled contacts are online. */ + private void createNoProjectsMenuItem(final int index) { + MDirectMenuItem noProjectsMenuItem = service.createModelElement(MDirectMenuItem.class); + noProjectsMenuItem.setLabel(Messages.SessionWithProjects_no_projects_in_workspace); + noProjectsMenuItem.setEnabled(false); + + menuEntries.add(index, noProjectsMenuItem); + } +} diff --git a/stf/build.gradle.kts b/stf/build.gradle.kts index efc7af91a5..460c972942 100644 --- a/stf/build.gradle.kts +++ b/stf/build.gradle.kts @@ -33,6 +33,9 @@ dependencies { // This is a workaround for https://github.com/saros-project/saros/issues/1114 implementation("org.eclipse.platform:org.eclipse.ui.ide:3.17.200") implementation("org.eclipse.platform:org.eclipse.ui.workbench:3.120.0") + // This is a workaround for an Issues, same as https://github.com/saros-project/saros/issues/1114 + implementation("org.eclipse.platform:org.eclipse.e4.ui.services:1.3.700") + implementation("javax.inject:javax.inject:1") compile(project(path = ":saros.eclipse", configuration = "testing")) releaseDep(fileTree("libs"))