# HG changeset patch # User Chad Peckham # Date 1264801356 21600 # Node ID d8886f16bea3a075e5a6e2b222c605b38b2a709f # Parent 6f65d25899caa51c966ca2f433d2c776a212bebb Add dialog to notify user of discovery agents not loaded because prerequisites not satisfied. Bug 10486 diff -r 6f65d25899ca -r d8886f16bea3 connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/RemoteConnectionsActivator.java --- 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 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 agentNames = new ArrayList(); + final Collection agentStatuses = new ArrayList(); + // load the extensions just to check statuses + // later we'll load them for real + Collection agents = new ArrayList(); + + 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 * diff -r 6f65d25899ca -r d8886f16bea3 connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/internal/api/IDeviceDiscoveryAgent.java --- 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. + *

+ * 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. + *

+ * 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 diff -r 6f65d25899ca -r d8886f16bea3 connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/internal/ui/DeviceDiscoveryPrequisiteErrorDialog.java --- /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: %s", + agentErrorText, location.toString(), location.toString()); + agentErrorText = msg; + } + } + } + + private Collection agentList = new ArrayList(); + 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"); + } +}