Add dialog to notify user of discovery agents not loaded because prerequisites not satisfied. Bug 10486
--- a/connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/RemoteConnectionsActivator.java Fri Jan 29 15:11:48 2010 -0600
+++ b/connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/RemoteConnectionsActivator.java Fri Jan 29 15:42:36 2010 -0600
@@ -26,6 +26,7 @@
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IFilter;
import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
@@ -33,8 +34,11 @@
import com.nokia.carbide.remoteconnections.interfaces.IConnectionTypeProvider;
import com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager;
import com.nokia.carbide.remoteconnections.internal.api.IDeviceDiscoveryAgent;
+import com.nokia.carbide.remoteconnections.internal.api.IDeviceDiscoveryAgent.IPrerequisiteStatus;
import com.nokia.carbide.remoteconnections.internal.registry.Registry;
+import com.nokia.carbide.remoteconnections.internal.ui.DeviceDiscoveryPrequisiteErrorDialog;
import com.nokia.cpp.internal.api.utils.core.Logging;
+import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils;
/**
* The activator class controls the plug-in life cycle
@@ -51,6 +55,8 @@
private static RemoteConnectionsActivator plugin;
private Collection<IDeviceDiscoveryAgent> discoveryAgents;
+ private boolean ignoreAgentLoadErrors = false;
+ private static final String IGNORE_AGENT_LOAD_ERRORS_KEY = "ignoreAgentLoadErrors"; //$NON-NLS-1$
/**
* The constructor
@@ -64,17 +70,74 @@
Registry instance = Registry.instance();
instance.loadExtensions();
instance.loadConnections();
- loadAndStartDeviceDiscoveryAgents();
+
+ loadIgnoreAgentLoadErrorsFlag();
+ if (!ignoreAgentLoadErrors) {
+ checkPrerequisites();
+ // loading done in checkPrerequisites after load errors dealt with
+ } else {
+ // if we ignore the load errors
+ // go ahead and load anyway
+ loadAndStartDeviceDiscoveryAgents();
+ }
+ }
+
+ private void loadIgnoreAgentLoadErrorsFlag() {
+ ignoreAgentLoadErrors = getPreferenceStore().getBoolean(IGNORE_AGENT_LOAD_ERRORS_KEY);
+ }
+
+ private void checkPrerequisites() {
+ final Collection<String> agentNames = new ArrayList<String>();
+ final Collection<IPrerequisiteStatus> agentStatuses = new ArrayList<IPrerequisiteStatus>();
+ // load the extensions just to check statuses
+ // later we'll load them for real
+ Collection<IDeviceDiscoveryAgent> agents = new ArrayList<IDeviceDiscoveryAgent>();
+
+ loadExtensions(DISCOVERY_AGENT_EXTENSION, null, agents, null);
+
+ for (IDeviceDiscoveryAgent agent : agents) {
+ IPrerequisiteStatus status = agent.getPrerequisiteStatus();
+ if (!status.isOK()) {
+ agentNames.add(agent.getDisplayName());
+ agentStatuses.add(status);
+ }
+ }
+
+ if (!agentNames.isEmpty()) {
+ Display.getDefault().asyncExec(new Runnable() {
+
+ public void run() {
+ DeviceDiscoveryPrequisiteErrorDialog dlg = new DeviceDiscoveryPrequisiteErrorDialog(WorkbenchUtils.getSafeShell());
+ IPrerequisiteStatus[] statuses = (IPrerequisiteStatus[]) agentStatuses.toArray(new IPrerequisiteStatus[agentStatuses.size()]);
+ String[] names = agentNames.toArray(new String[agentNames.size()]);
+ for (int i = 0; i < names.length; i++) {
+ dlg.addAgentData(names[i], statuses[i].getErrorText(), statuses[i].getURL());
+ }
+ dlg.open();
+ ignoreAgentLoadErrors = dlg.isDontBotherMeOn();
+ dlg.close();
+
+ // now load and start agents for real
+ loadAndStartDeviceDiscoveryAgents();
+ }
+ });
+ }
}
public void stop(BundleContext context) throws Exception {
stopDeviceDiscoveryAgents();
Registry.instance().storeConnections();
Registry.instance().disposeConnections();
+ storeIgnoreAgentLoadErrorsFlag();
plugin = null;
super.stop(context);
}
+ private void storeIgnoreAgentLoadErrorsFlag() {
+ getPreferenceStore().setValue(IGNORE_AGENT_LOAD_ERRORS_KEY, ignoreAgentLoadErrors);
+ savePluginPreferences();
+ }
+
/**
* Returns the shared instance
*
--- a/connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/internal/api/IDeviceDiscoveryAgent.java Fri Jan 29 15:11:48 2010 -0600
+++ b/connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/internal/api/IDeviceDiscoveryAgent.java Fri Jan 29 15:42:36 2010 -0600
@@ -28,6 +28,31 @@
public interface IDeviceDiscoveryAgent {
/**
+ * An interface for discovery agents to implement that the manager uses
+ * before loading the agent to get errors about required components.
+ * <p>
+ * Every discovery agent must implement this interface.
+ */
+ public interface IPrerequisiteStatus {
+ /**
+ * Is the status OK?
+ * @return boolean
+ */
+ boolean isOK();
+ /**
+ * If status is not OK, return error message text.
+ * @return String
+ */
+ String getErrorText();
+ /**
+ * Optionally return a URL for user to browse to for more information on error.
+ * @return URL
+ */
+ URL getURL();
+
+ }
+
+ /**
* Starts agent. Once started, runs until stopped.
* @throws CoreException
*/
@@ -46,6 +71,22 @@
*/
URL getInformation();
+ /**
+ * Returns a display name for the particular discovery agent in case we need to
+ * let the user know errors from the agents.
+ * @return String
+ */
+ String getDisplayName();
+
+ /**
+ * Manager will call this to get any status of prerequisites not satisfied before
+ * the manager calls start(). The agent should check its prerequisites at this time.
+ * <p>
+ * If the agent has no prerequisites return a status of OK.
+ * @return IPrerequisiteStatus
+ */
+ IPrerequisiteStatus getPrerequisiteStatus();
+
// In addition, there may need to be an additional API to do a deeper form of discovery for
// connection mechanisms that require pairing (like BT or Wifi). In these cases, normal discovery
// will probably be for already paired devices, however, the user will want to discover all
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/internal/ui/DeviceDiscoveryPrequisiteErrorDialog.java Fri Jan 29 15:42:36 2010 -0600
@@ -0,0 +1,230 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+package com.nokia.carbide.remoteconnections.internal.ui;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+
+import com.nokia.carbide.remoteconnections.RemoteConnectionsActivator;
+
+public class DeviceDiscoveryPrequisiteErrorDialog extends Dialog {
+
+ private class AgentItem {
+ public String agentName;
+ public String agentErrorText;
+ public URL agentLocation;
+
+ AgentItem(String name, String text, URL location) {
+ agentName = name;
+ agentErrorText = text;
+ agentLocation = location;
+ // if location is not null and error text doesn't contain href
+ // then do it here
+ if (agentLocation != null && !agentErrorText.contains("href=")) {
+ String msg = String.format("%s - For more information go to: <a href=\"%s\">%s</a>",
+ agentErrorText, location.toString(), location.toString());
+ agentErrorText = msg;
+ }
+ }
+ }
+
+ private Collection<AgentItem> agentList = new ArrayList<AgentItem>();
+ private boolean isDontBotherMeOn = false;
+ private ListViewer agentListViewer;
+ private Link errorText;
+ private Button dontBotherMeCheckBox;
+
+ /**
+ * @param parentShell
+ */
+ public DeviceDiscoveryPrequisiteErrorDialog(Shell parentShell) {
+ super(parentShell);
+ agentList.clear();
+ }
+
+ /**
+ * @param parentShell
+ */
+ public DeviceDiscoveryPrequisiteErrorDialog(IShellProvider parentShell) {
+ super(parentShell);
+ agentList.clear();
+ }
+
+ public void addAgentData(String name, String errorText, URL location) {
+ agentList.add(new AgentItem(name, errorText, location));
+ }
+
+ public boolean isDontBotherMeOn() {
+ return isDontBotherMeOn;
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ // OK button == "Close"
+ // no Cancel button
+ createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, true);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ initializeDialogUnits(parent);
+
+ Composite container = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(1, true);
+ container.setLayout(layout);
+ container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ // Message at top
+ Text topMessage = new Text(container, SWT.MULTI | SWT.WRAP);
+ topMessage.setText("At least one device discovery agent had load errors that prevent it from discovering connections to devices. Select one to get more information about its error.");
+ topMessage.setEditable(false);
+ topMessage.setDoubleClickEnabled(false);
+ GridData topMsgData = new GridData(SWT.LEFT, SWT.CENTER, true, false);
+ topMsgData.heightHint = 48;
+ topMessage.setLayoutData(topMsgData);
+ topMessage.setToolTipText("Select an agent for more information about load errors.");
+
+ // next two panes can be resized with a sash form
+ SashForm sashForm = new SashForm(container, SWT.VERTICAL);
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ sashForm.setLayoutData(gridData);
+ sashForm.setToolTipText("Slide to adjust pane size above and below to see more text.");
+
+
+ // this pane lists all the agent display names
+ agentListViewer = new ListViewer(sashForm, SWT.V_SCROLL | SWT.BORDER);
+ agentListViewer.setContentProvider(new ArrayContentProvider());
+ agentListViewer.setLabelProvider(new LabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+ return ((AgentItem)element).agentName;
+ }
+
+ });
+ agentListViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ AgentItem item = (AgentItem) selection.getFirstElement();
+ errorText.setText(item.agentErrorText);
+ }
+
+ });
+ agentListViewer.setInput(agentList);
+
+ // pane to view the information about the selected agent
+ errorText = new Link(sashForm, SWT.V_SCROLL | SWT.BORDER | SWT.WRAP);
+ errorText.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+ errorText.setToolTipText("Error message for the selected agent above");
+ errorText.addListener(SWT.Selection, new Listener() {
+
+ public void handleEvent(Event event) {
+ // Launch an external browser
+ String siteText = event.text;
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ try {
+ IWebBrowser browser = workbench.getBrowserSupport().getExternalBrowser();
+ browser.openURL(new URL(siteText));
+ } catch (Exception e) {
+ RemoteConnectionsActivator.logError(e);
+ }
+ }
+
+ });
+
+ // add initial weights to the above two panes
+ sashForm.setWeights(new int[] {150,200});
+
+ // now the don't bother me check box
+ dontBotherMeCheckBox = new Button(container, SWT.CHECK);
+ dontBotherMeCheckBox.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, true, false));
+ dontBotherMeCheckBox.setText("Don't bother me again.");
+ dontBotherMeCheckBox.setToolTipText("Check this to ignore further discovery agent load errors");
+ dontBotherMeCheckBox.setSelection(isDontBotherMeOn);
+ dontBotherMeCheckBox.addSelectionListener(new SelectionAdapter() {
+
+ public void widgetSelected(SelectionEvent e) {
+ isDontBotherMeOn = dontBotherMeCheckBox.getSelection();
+ }
+
+ });
+
+ // now finish by selecting the top most agent in the list
+ // and bringing it into view
+ Object o = agentListViewer.getElementAt(0);
+ if (o != null)
+ agentListViewer.setSelection(new StructuredSelection(o));
+
+ ISelection selection = agentListViewer.getSelection();
+ if (selection != null && !selection.isEmpty()) {
+ agentListViewer.reveal(selection);
+ }
+
+ return container;
+ }
+
+ @Override
+ protected Point getInitialSize() {
+ return new Point(400,400);
+ }
+
+ @Override
+ protected void okPressed() {
+ // TODO Auto-generated method stub
+ super.okPressed();
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+ // set our title to the dialog
+ newShell.setText("Device Discovery Load Errors");
+ }
+}