/** Composite that displays the form sections that constitute the device overview page */ public class DeviceOverviewForm extends Composite implements XPathFocusable { /** Used for logging */ private static final LogDispatcher LOGGER = LocalizationFactory.createLogger(DeviceOverviewForm.class); /** Used to retrieve localized exception messages. */ private static final ExceptionLocalizer EXCEPTION_LOCALIZER = LocalizationFactory.createExceptionLocalizer(DeviceOverviewForm.class); /** The prefix for resources associated with this class. */ private static final String RESOURCE_PREFIX = "DeviceOverviewForm."; /** Constant for device overview forms margin height */ private static final int MARGIN_HEIGHT = EditorMessages.getInteger("Editor.marginHeight").intValue(); /** Constant for device overview forms margin width */ private static final int MARGIN_WIDTH = EditorMessages.getInteger("Editor.marginWidth").intValue(); /** Constant for device overview forms horizontal spacing */ private static final int HORIZONTAL_SPACING = EditorMessages.getInteger("Editor.horizontalSpacing").intValue(); /** Constant for device overview forms vertical spacing */ private static final int VERTICAL_SPACING = EditorMessages.getInteger("Editor.verticalSpacing").intValue(); /** The text for the Restore Defaults button. */ private static final String RESTORE_DEFAULTS_TEXT = DevicesMessages.getString(RESOURCE_PREFIX + "restoreDefaults.text"); /** Create a filter so that only device elements are included in the selection. */ private static final ODOMSelectionFilter DEVICE_FILTER = new ODOMSelectionFilter( null, new String[] {DeviceRepositorySchemaConstants.DEVICE_ELEMENT_NAME}, new ODOMSelectionFilterConfiguration(true, true)); /** FormSection that displays the hierarchy document in a tree format. */ private DeviceHierarchySection deviceHierarchySection; /** The ODOMEditor context for the device repository */ private DeviceEditorContext context; /** The Restore Defaults button. */ private Button restoreButton; /** Maintain the selected element so that we restore it if necessary (via the restore action). */ private Element deviceIDElement; /** * Initializes a <code>DeviceOverviewForm</code> with the given arguments * * @param parent the parent composite * @param style a bitset used to specify any styles * @param context the DeviceEditorContext. */ public DeviceOverviewForm(Composite parent, int style, DeviceEditorContext context) { super(parent, style); this.context = context; createDisplayArea(); } /** Creates the display area for this form */ private void createDisplayArea() { // create the top level layout for the form GridLayout layout = new GridLayout(); layout.marginHeight = MARGIN_HEIGHT; layout.marginWidth = MARGIN_WIDTH; layout.verticalSpacing = VERTICAL_SPACING; layout.horizontalSpacing = HORIZONTAL_SPACING; GridData data = new GridData(GridData.FILL_BOTH); setLayout(layout); setLayoutData(data); // set the background color to white Color white = getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); setBackground(white); // add an alerts and actions section AlertsActionsSection alerts = new AlertsActionsSection(this, SWT.NONE, context); alerts.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); // add a two column contianer for the form sections. The first // column will display the DeviceHierarchy section and the second // column will display the primary and secondary pattern sections. Composite formContainer = new Composite(this, SWT.NONE); GridLayout formLayout = new GridLayout(2, false); formLayout.marginWidth = 0; formLayout.marginHeight = 0; formLayout.horizontalSpacing = HORIZONTAL_SPACING; GridData formData = new GridData(GridData.FILL_BOTH); formContainer.setLayout(formLayout); formContainer.setLayoutData(formData); formContainer.setBackground(white); // add the hierarchy section to the formContainer deviceHierarchySection = new DeviceHierarchySection(formContainer, SWT.NONE, context); GridData hierarchyData = new GridData(GridData.FILL_VERTICAL); deviceHierarchySection.setLayoutData(hierarchyData); // add a scroll area for the patterns sections ScrolledComposite controlsScroller = new ScrolledComposite(formContainer, SWT.H_SCROLL | SWT.V_SCROLL); controlsScroller.setLayout(new FillLayout()); controlsScroller.setLayoutData(new GridData(GridData.FILL_BOTH)); controlsScroller.setExpandHorizontal(true); controlsScroller.setExpandVertical(true); controlsScroller.setAlwaysShowScrollBars(false); controlsScroller.setBackground(white); // add the container for the patterns sections Composite patternContainer = new Composite(controlsScroller, SWT.NONE); GridLayout patternLayout = new GridLayout(); patternLayout.marginHeight = 0; patternLayout.marginWidth = 0; patternLayout.verticalSpacing = VERTICAL_SPACING; GridData patternData = new GridData(GridData.FILL_BOTH); patternContainer.setLayout(patternLayout); patternContainer.setLayoutData(patternData); patternContainer.setBackground(white); // Add the primary patterns section PrimaryPatternsSection primaryPatterns = new PrimaryPatternsSection(patternContainer, SWT.NONE, context); primaryPatterns.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); // Add the secondary patterns section SecondaryPatternsSection secondaryPatterns = new SecondaryPatternsSection(patternContainer, SWT.NONE, context); secondaryPatterns.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); createRestoreMechanism(patternContainer); TACPatternsSection TACPatterns = new TACPatternsSection(patternContainer, SWT.NONE, context); TACPatterns.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); patternContainer.setSize(patternContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT)); patternContainer.layout(); controlsScroller.setMinSize(patternContainer.computeSize(SWT.DEFAULT, SWT.DEFAULT)); controlsScroller.setContent(patternContainer); layout(); } /** * Get the name of the selected device. * * @return the name of the selected device or null if none selected. */ String getSelectedDeviceName() { String selectedDeviceName = null; if (deviceIDElement != null) { selectedDeviceName = deviceIDElement.getAttributeValue(DeviceRepositorySchemaConstants.DEVICE_NAME_ATTRIBUTE); } return selectedDeviceName; } /** * Add the restore button and the standard element handling facility. * * @param parent the parent composite for the resotre button. */ private void createRestoreMechanism(Composite parent) { restoreButton = new Button(parent, SWT.NONE); restoreButton.setText(RESTORE_DEFAULTS_TEXT); restoreButton.setEnabled(!context.isAdminProject()); restoreButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END)); restoreButton.addSelectionListener( new SelectionListener() { public void widgetSelected(SelectionEvent e) { widgetDefaultSelected(e); } public void widgetDefaultSelected(SelectionEvent event) { if (deviceIDElement != null) { ((DeviceODOMElement) deviceIDElement).restore(); } } }); // Add a listener to the selection manager which responds to device // element selections. context .getODOMSelectionManager() .addSelectionListener( new ODOMElementSelectionListener() { public void selectionChanged(ODOMElementSelectionEvent event) { ODOMElementSelection selection = event.getSelection(); if (!selection.isEmpty()) { Element deviceElement = (Element) selection.getFirstElement(); // Retrieve the device name. final String deviceName = deviceElement.getAttributeValue( DeviceRepositorySchemaConstants.DEVICE_NAME_ATTRIBUTE); deviceIDElement = context .getDeviceRepositoryAccessorManager() .retrieveDeviceIdentification(deviceName); if (deviceIDElement == null) { Object params = new Object[] { deviceName, context.getDeviceRepositoryAccessorManager().getDeviceRepositoryName() }; LOGGER.error("device-not-found", params); String message = EXCEPTION_LOCALIZER.format("device-not-found", params); throw new UndeclaredThrowableException(new RepositoryException(message)); } else { DeviceODOMElement parent = (DeviceODOMElement) deviceIDElement.getParent(); if (parent == null) { LOGGER.error("device-no-parent", deviceName); String message = EXCEPTION_LOCALIZER.format("device-no-parent", deviceName); throw new UndeclaredThrowableException(new RepositoryException(message)); } else { parent.submitRestorableName(deviceName); } } } else { deviceIDElement = null; } } }, DEVICE_FILTER); } // javadoc inherited public boolean setFocus(XPath path) { // todo implement this return false; } }
/** * The form section that displays the available policies for devices and allows users to add and * remove policies. This section affects the device definitions document, the master device document * when a new policy is created and when a policy removed every device that has a setting for that * policy must also be modified. */ public class DeviceDefinitionPoliciesSection extends FormSection implements XPathFocusable { /** The prefix for property resources associated with this class. */ private static final String RESOURCE_PREFIX = "DeviceDefinitionPoliciesSection."; /** The default minimum width for device definition policies sections. */ private static final int DEFAULT_MIN_WIDTH = DevicesMessages.getInteger(RESOURCE_PREFIX + "minWidth").intValue(); /** Constant used as the title for this form section */ private static final String TITLE = DevicesMessages.getString(RESOURCE_PREFIX + "title"); /** Constant used as the message for this form section */ private static final String MESSAGE = DevicesMessages.getString(RESOURCE_PREFIX + "message"); /** The message for the dialog for policy deletion confirmation. */ private static final MessageFormat POLICY_DELETION_DIALOG_MESSAGE_FORMAT = new MessageFormat(DevicesMessages.getString(RESOURCE_PREFIX + "deletePolicyDialog.message")); /** The title for the dialog for policy deletion confirmation. */ private static final String POLICY_DELETION_DIALOG_TITLE = DevicesMessages.getString(RESOURCE_PREFIX + "deletePolicyDialog.title"); /** The text for the Yes button of the dialog for policy deletion confirmation. */ private static final String POLICY_DELETION_DIALOG_YES_TEXT = DevicesMessages.getString(RESOURCE_PREFIX + "deletePolicyDialog.yes"); /** The text for the No button of the dialog for policy deletion confirmation. */ private static final String POLICY_DELETION_DIALOG_NO_TEXT = DevicesMessages.getString(RESOURCE_PREFIX + "deletePolicyDialog.no"); /** The original delete actions that will be restored when this section loses focus. */ private IAction origDelete; /** The Delete Policy action. */ private Action deletePolicyAction; /** The new policy action. */ private Action newPolicyAction; /** The categoriesComposite control. */ private CategoriesComposite categoriesComposite; /** The DeviceEditorContext associated with this section. */ private final DeviceEditorContext context; /** Construct a new CategoriesSection. */ // rest of javadoc inherited public DeviceDefinitionPoliciesSection(Composite parent, int style, DeviceEditorContext context) { super(parent, style); setMinWidth(DEFAULT_MIN_WIDTH); this.context = context; DeviceRepositoryAccessorManager dram = context.getDeviceRepositoryAccessorManager(); Section section = SectionFactory.createSection(this, SWT.NONE, TITLE, MESSAGE); GridData data = new GridData(GridData.FILL_BOTH); section.setLayoutData(data); categoriesComposite = new CategoriesComposite(section, CategoriesComposite.POLICIES, dram); section.setClient(categoriesComposite); // Set up a focus listener for maintaining global actions. categoriesComposite .getTreeViewer() .getControl() .addFocusListener( new FocusListener() { public void focusGained(FocusEvent event) { IActionBars actionBars = DeviceDefinitionPoliciesSection.this.context.getActionBars(); origDelete = actionBars.getGlobalActionHandler(IWorkbenchActionConstants.DELETE); actionBars.setGlobalActionHandler( IWorkbenchActionConstants.DELETE, deletePolicyAction); actionBars.updateActionBars(); } public void focusLost(FocusEvent event) { IActionBars actionBars = DeviceDefinitionPoliciesSection.this.context.getActionBars(); actionBars.setGlobalActionHandler(IWorkbenchActionConstants.DELETE, origDelete); actionBars.updateActionBars(); } }); // We use the selection manager for event handling because it allows // use to use filters which we need for resolving category elements // for use with ODOMAction enablement. categoriesComposite.addSelectionChangedListener(context.getODOMSelectionManager()); data = new GridData(GridData.FILL_BOTH); categoriesComposite.setLayoutData(data); createActions(); createContextMenu(); createButtons(this, SWT.NONE); } /** Create the buttons that allow users to invoke actions on this section. */ private void createButtons(Composite parent, int style) { Composite buttonComposite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(2, false); buttonComposite.setLayout(layout); buttonComposite.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); new ActionButton(buttonComposite, style, newPolicyAction); new ActionButton(buttonComposite, style, deletePolicyAction); } // javadoc inherited public boolean setFocus(XPath path) { // todo implement this method return false; } /** Create the actions. */ private void createActions() { // New policy ODOMActionCommand command = new ODOMActionCommand() { public boolean enable(ODOMActionDetails details) { Element selectedCategory = categoriesComposite.getSelectedCategoryElement(); boolean enabled = selectedCategory != null; if (enabled) { // New policy is always enabled in admin mode when there // is a selection. enabled = context.isAdminProject(); if (!enabled) { String categoryName = selectedCategory.getAttributeValue( DeviceRepositorySchemaConstants.CATEGORY_NAME_ATTRIBUTE); enabled = categoryName.equals(DeviceRepositorySchemaConstants.CUSTOM_CATEGORY_NAME); } } return enabled; } public void run(ODOMActionDetails details) { NewDevicePolicyWizard wizard = new NewDevicePolicyWizard(getShell(), context.getDeviceRepositoryAccessorManager()); wizard.open(); String policyName = wizard.getPolicyName(); // If the custom category is selected then prefix the policy // name with the custom prefix to enable it to be identified // as a custom policy. if (categoriesComposite .getSelectedCategoryElement() .getAttributeValue(DeviceRepositorySchemaConstants.CATEGORY_NAME_ATTRIBUTE) .equals(DeviceRepositorySchemaConstants.CUSTOM_CATEGORY_NAME)) { StringBuffer buffer = new StringBuffer(EclipseDeviceRepository.getCustomPolicyNamePrefix()); buffer.append(policyName); policyName = buffer.toString(); } PolicyTypeComposition composition = wizard.getPolicyTypeComposition(); PolicyType type = wizard.getPolicyType(); if (policyName != null && composition != null && type != null) { // we don't allow policy creation to // be undoable try { context.getUndoRedoManager().enable(false); addNewPolicyToRepository(policyName, composition, type); } finally { context.getUndoRedoManager().enable(true); } selectNewPolicy(policyName); } } }; newPolicyAction = new ODOMAction( command, context, null, DevicesMessages.getResourceBundle(), RESOURCE_PREFIX + "newPolicy."); // Delete policy command = new ODOMActionCommand() { public boolean enable(ODOMActionDetails details) { boolean enabled = categoriesComposite.getSelectedPolicyElement() != null; if (enabled) { // New policy is always enabled in admin mode when there // is a selection. enabled = context.isAdminProject(); if (!enabled) { String categoryName = categoriesComposite .getSelectedCategoryElement() .getAttributeValue(DeviceRepositorySchemaConstants.CATEGORY_NAME_ATTRIBUTE); enabled = categoryName.equals(DeviceRepositorySchemaConstants.CUSTOM_CATEGORY_NAME); } } return enabled; } public void run(ODOMActionDetails details) { final String selectedPolicy = details .getElement(0) .getAttributeValue(DeviceRepositorySchemaConstants.POLICY_NAME_ATTRIBUTE); final String dialogMessage = POLICY_DELETION_DIALOG_MESSAGE_FORMAT.format(new Object[] {selectedPolicy}); // Get the shell for the dialog. final Shell shell = categoriesComposite.getShell(); // Create the confirmation dialog for the policy deletion. // The Yes button is at index 0 and has focus. There is no // image. final MessageDialog dialog = new MessageDialog( shell, POLICY_DELETION_DIALOG_TITLE, null, dialogMessage, MessageDialog.INFORMATION, new String[] {POLICY_DELETION_DIALOG_YES_TEXT, POLICY_DELETION_DIALOG_NO_TEXT}, 0); // Open the dialog. dialog.open(); // Only delete the policy if the user has confirmed the action // by pressing the Yes button at index 0. if (dialog.getReturnCode() == 0) { // Delete takes a while so use a BusyIndicator. BusyIndicator.showWhile( shell.getDisplay(), new Runnable() { public void run() { // BusyIndicator should display a busy // cursor automatically, but for some // reason does not do so here (it works // elsewhere within MCS). Experimentation // showed that manually setting a busy // cursor with Display.asyncExec or // Display.syncExec still did not produce // a busy cursor. Strangely, the only // combination that did work was manually // setting the busy cursor with // BusyIndicator.showWhile! // Also, NOT using any of Display.syncExec, // Display.asyncExec and BusyIndicator, // but running the code "as is" with manual // setting of the cursor also did NOT work. // @todo This is odd. BusyIndicator is broken? final Cursor busyCursor = new Cursor(shell.getDisplay(), SWT.CURSOR_WAIT); shell.setCursor(busyCursor); try { // we don't allow policy deletions to // be undoable context.getUndoRedoManager().enable(false); String policyName = categoriesComposite .getSelectedPolicyElement() .getAttributeValue( DeviceRepositorySchemaConstants.POLICY_NAME_ATTRIBUTE); context.getDeviceRepositoryAccessorManager().cleansePolicy(policyName); } catch (RepositoryException e) { EclipseCommonPlugin.handleError(ABPlugin.getDefault(), e); } finally { // ensure the undo redo manager is enabled. context.getUndoRedoManager().enable(true); // Restore the shell's default cursor // and dispose of the busy cursor // resources. shell.setCursor(null); } } }); } } }; deletePolicyAction = new ODOMAction( command, context, null, DevicesMessages.getResourceBundle(), RESOURCE_PREFIX + "deletePolicy."); } /** * Creates the context menu that is associated with the tree. * * <p><strong>The {@link #createActions} method must have been invoked prior to this * method</strong> */ private void createContextMenu() { // Create menu manager. MenuManager menuManager = new MenuManager(); menuManager.add(newPolicyAction); menuManager.add(new Separator()); menuManager.add(deletePolicyAction); // Create the menu and add it to the tree. final Tree tree = categoriesComposite.getTreeViewer().getTree(); Menu menu = menuManager.createContextMenu(tree); tree.setMenu(menu); } /** * Add a new policy to the device repository in use. This will add the policy to the definitions * document and to the master device file. * * @param policyName the name of the new policy. Cannot be null. * @param composition the PolicyTypeComposition of the new policy * @param type the PolicyType of the new policy * @throws IllegalArgumentException if the named policy already exists or if any of the arguments * are null. */ private void addNewPolicyToRepository( String policyName, PolicyTypeComposition composition, PolicyType type) { if (policyName == null) { throw new IllegalArgumentException("Cannot be null: " + policyName); } if (composition == null) { throw new IllegalArgumentException("Cannot be null: " + composition); } if (type == null) { throw new IllegalArgumentException("Cannot be null: " + type); } String masterDeviceName = context.getDeviceRepositoryAccessorManager().retrieveRootDeviceName(); boolean policyExists = context.getDeviceRepositoryAccessorManager().retrievePolicy(masterDeviceName, policyName) != null; if (policyExists) { throw new IllegalArgumentException( "Policy " + policyName + " already exists. Aborting new policy."); } // Add the policy to the definitions document Element category = categoriesComposite.getSelectedCategoryElement(); Element policy = context .getODOMFactory() .element(DeviceRepositorySchemaConstants.POLICY_ELEMENT_NAME, category.getNamespace()); policy.setAttribute(DeviceRepositorySchemaConstants.POLICY_NAME_ATTRIBUTE, policyName); category.addContent(policy); composition.addTypeElement(policy, type, context.getODOMFactory()); // Add the policy to the master device Element masterDevice = context.getDeviceRepositoryAccessorManager().retrieveDeviceElement(masterDeviceName); StringBuffer xPathBuffer = new StringBuffer(); xPathBuffer .append("//") . //$NON-NLS-1$ append(MCSNamespace.DEVICE.getPrefix()) .append(':') .append(DeviceRepositorySchemaConstants.POLICIES_ELEMENT_NAME); XPath policiesXPath = new XPath(xPathBuffer.toString(), new Namespace[] {MCSNamespace.DEVICE}); try { Element policies = policiesXPath.selectSingleElement(masterDevice); composition.addDefaultPolicyValue( policies, policyName, type, context.getODOMFactory(), context.getDeviceRepositoryAccessorManager()); } catch (XPathException e) { EclipseCommonPlugin.handleError(ABPlugin.getDefault(), e); } } /** * Get the name of the selected policy, if any, from this section. * * @return the selected policy name or null if no policy is selected. */ public Element getSelectedPolicyElement() { return categoriesComposite.getSelectedPolicyElement(); } /** * Get the name of the selected category. If a policy is selected then this method will return the * name of the category that the policy belongs to. * * @return the selected category name or null if no category or policy is selected. */ public String getSelectedCategoryName() { Element category = categoriesComposite.getSelectedCategoryElement(); return (category == null) ? null : category.getAttributeValue(DeviceRepositorySchemaConstants.CATEGORY_NAME_ATTRIBUTE); } /** * Get the name of the selected policy, if any, from this section. * * @return the selected policy name or null if no policy is selected. */ public String getSelectedPolicy() { Element element = categoriesComposite.getSelectedPolicyElement(); return element == null ? null : element.getAttributeValue(DeviceRepositorySchemaConstants.POLICY_NAME_ATTRIBUTE); } /** Add a SelectionChange listener that is notified when policy selection changes. */ public void addSelectionChangedListener(ISelectionChangedListener listener) { categoriesComposite.addSelectionChangedListener(listener); } /** Remove a SelectionChange listener that is notified when policy selection changes. */ public void removeSelectionChangedListener(ISelectionChangedListener listener) { categoriesComposite.removeSelectionChangedListener(listener); } /** * Select's the new named policy element in the tree. * * @param newPolicyName the name of the new policy to select. */ private void selectNewPolicy(final String newPolicyName) { // Create the XPath for selecting the new policy element just created // from the definitions document. final StringBuffer newPolicyXPathBuffer = new StringBuffer(); newPolicyXPathBuffer .append("//") .append(MCSNamespace.DEVICE_DEFINITIONS.getPrefix()) .append(':') .append(DeviceRepositorySchemaConstants.POLICY_ELEMENT_NAME) .append("[@") .append(DeviceRepositorySchemaConstants.POLICY_NAME_ATTRIBUTE) .append("=\"") .append(newPolicyName) .append("\"]"); final XPath newPolicyXPath = new XPath( newPolicyXPathBuffer.toString(), new Namespace[] {MCSNamespace.DEVICE_DEFINITIONS}); Element newPolicyElement = null; try { // Get the definitions root for the XPath search. final Element definitionsRoot = context .getDeviceRepositoryAccessorManager() .getDeviceDefinitionsDocument() .getRootElement(); // Retrieve the new policy element. newPolicyElement = newPolicyXPath.selectSingleElement(definitionsRoot); } catch (XPathException e) { EclipseCommonPlugin.handleError(ABPlugin.getDefault(), e); } TreeViewer treeViewer = categoriesComposite.getTreeViewer(); // Expand the tree to the new policy element's level and select it. treeViewer.expandToLevel(newPolicyElement, 1); treeViewer.setSelection(new StructuredSelection(newPolicyElement), true); } }