private void addPlainAction(RuleAction menuAction) { final ToolItem button = new ToolItem(mLayoutToolBar, SWT.PUSH); URL iconUrl = menuAction.getIconUrl(); String title = menuAction.getTitle(); if (iconUrl != null) { button.setImage(IconFactory.getInstance().getIcon(iconUrl)); button.setToolTipText(title); } else { button.setText(title); } button.setData(menuAction); button.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { RuleAction menuAction = (RuleAction) button.getData(); menuAction .getCallback() .action(menuAction, getSelectedNodes(), menuAction.getId(), false); updateSelection(); } }); }
/** * Attempts to update the existing toolbar actions, if the action list is similar to the current * list. Returns false if this cannot be done and the contents must be replaced. */ private boolean updateActions(@NonNull List<RuleAction> actions) { List<RuleAction> before = mPrevActions; List<RuleAction> after = actions; if (before == null) { return false; } if (!before.equals(after) || after.size() > mLayoutToolBar.getItemCount()) { return false; } int actionIndex = 0; for (int i = 0, max = mLayoutToolBar.getItemCount(); i < max; i++) { ToolItem item = mLayoutToolBar.getItem(i); int style = item.getStyle(); Object data = item.getData(); if (data != null) { // One action can result in multiple toolbar items (e.g. a choice action // can result in multiple radio buttons), so we've have to replace all of // them with the corresponding new action RuleAction prevAction = before.get(actionIndex); while (prevAction != data) { actionIndex++; if (actionIndex == before.size()) { return false; } prevAction = before.get(actionIndex); if (prevAction == data) { break; } else if (!(prevAction instanceof RuleAction.Separator)) { return false; } } RuleAction newAction = after.get(actionIndex); assert newAction.equals(prevAction); // Maybe I can do this lazily instead? // Update action binding to the new action item.setData(newAction); // Sync button states: the checked state is not considered part of // RuleAction equality if ((style & SWT.CHECK) != 0) { assert newAction instanceof Toggle; Toggle toggle = (Toggle) newAction; item.setSelection(toggle.isChecked()); } else if ((style & SWT.RADIO) != 0) { assert newAction instanceof Choices; Choices choices = (Choices) newAction; String current = choices.getCurrent(); String id = (String) item.getData(ATTR_ID); boolean selected = Strings.nullToEmpty(current).equals(id); item.setSelection(selected); } } else { // Must be a separator, or a label (which we insert for nested widgets) assert (style & SWT.SEPARATOR) != 0 || !item.getText().isEmpty() : item; } } return true; }
/** Updates the layout contents based on the current selection */ void updateSelection() { NodeProxy parent = null; LayoutCanvas canvas = mEditor.getCanvasControl(); SelectionManager selectionManager = canvas.getSelectionManager(); List<SelectionItem> selections = selectionManager.getSelections(); if (selections.size() > 0) { // TODO: better handle multi-selection -- maybe we should disable it or // something. // What if you select children with different parents? Of different types? // etc. NodeProxy node = selections.get(0).getNode(); if (node != null && node.getParent() != null) { parent = (NodeProxy) node.getParent(); } } if (parent == null) { // Show the background's properties CanvasViewInfo root = canvas.getViewHierarchy().getRoot(); if (root == null) { return; } parent = canvas.getNodeFactory().create(root); selections = Collections.emptyList(); } RulesEngine engine = mEditor.getRulesEngine(); List<NodeProxy> selectedNodes = new ArrayList<NodeProxy>(); for (SelectionItem item : selections) { selectedNodes.add(item.getNode()); } List<RuleAction> actions = new ArrayList<RuleAction>(); engine.callAddLayoutActions(actions, parent, selectedNodes); // Place actions in the correct order (the actions may come from different // rules and should be merged properly via sorting keys) Collections.sort(actions); // Add in actions for the child as well, if there is exactly one. // These are not merged into the parent list of actions; they are appended // at the end. int index = -1; String label = null; if (selectedNodes.size() == 1) { List<RuleAction> itemActions = new ArrayList<RuleAction>(); NodeProxy selectedNode = selectedNodes.get(0); engine.callAddLayoutActions(itemActions, selectedNode, null); if (itemActions.size() > 0) { Collections.sort(itemActions); if (!(itemActions.get(0) instanceof RuleAction.Separator)) { actions.add(RuleAction.createSeparator(0)); } label = selectedNode.getStringAttr(ANDROID_URI, ATTR_ID); if (label != null) { label = BaseViewRule.stripIdPrefix(label); index = actions.size(); } actions.addAll(itemActions); } } if (!updateActions(actions)) { updateToolbar(actions, index, label); } mPrevActions = actions; }