/******************************************************************************* * Copyright (c) 2013 Arapiki Solutions Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * psmith - initial API and * implementation and/or initial documentation *******************************************************************************/ package com.buildml.eclipse.actions.dialogs; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; 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.Label; import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import com.buildml.eclipse.utils.BmlTitleAreaDialog; import com.buildml.model.IActionMgr; import com.buildml.model.IBuildStore; import com.buildml.model.types.ActionSet; /** * A dialog allowing the user to select a pattern that will be used to provide a list * of actions that match the pattern. The user must then select which of the matching * actions will be used in an operation (such as delete, or make atomic). * * @author Peter Smith <psmith@arapiki.com> */ public class MatchPatternSelectionDialog extends BmlTitleAreaDialog { /*=====================================================================================* * FIELDS/TYPES *=====================================================================================*/ /** The buildStore's action manager */ private IActionMgr actionMgr; /** The pattern (regular expression) that the user wants to match against */ private String patternString; /** Textual string showing what the operation is (e.g. "Delete" or "Make Atomic"). */ private String operation; /** The list box widget containing the matching actions */ private List resultsListBox; /** The Control where the user enters the match string */ private Text entryBox; /** The ActionMgr IDs of the actions being displayed in the resultsListBox */ private Integer matchingActions[]; /** The final set of selected actions - only valid after "OK" is pressed */ private ActionSet resultActionSet; /*=====================================================================================* * CONSTRUCTOR *=====================================================================================*/ /** * Create a new MatchPatternSelectionDialog. * * @param buildStore The IBuildStore that contains the actions. * @param initialPattern The action command string pattern (that the user may edit). * @param operation Displayable string explaining what will happen when the * user presses OK. For example, "Delete" or "Make Atomic". */ public MatchPatternSelectionDialog(IBuildStore buildStore, String initialPattern, String operation) { super(new Shell(), 0.3, 0.5, 0.5, 0); this.actionMgr = buildStore.getActionMgr(); this.patternString = initialPattern; this.operation = operation; } /*=====================================================================================* * PUBLIC METHODS *=====================================================================================*/ /** * Return the actions that have been selected. This method should only be called * after the "OK" (Delete, Make Atomic) button has been pressed. * * @return The set of actions that have been selected. */ public ActionSet getMatchingActions() { return resultActionSet; } /*=====================================================================================* * PROTECTED METHODS *=====================================================================================*/ /* (non-Javadoc) * @see com.buildml.eclipse.utils.BmlTitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite) */ @Override protected Control createDialogArea(Composite parent) { /* Create the main panel widget for the body of the dialog box */ Composite panel = new Composite(parent, SWT.NONE); panel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); GridLayout layout = new GridLayout(); layout.marginHeight = 10; layout.marginWidth = 20; layout.verticalSpacing = 10; layout.numColumns = 1; panel.setLayout(layout); /* * Introductory label */ new Label(panel, SWT.NONE).setText("Please specify a pattern to identify which actions " + "you wish to " + operation.toLowerCase() + ". Use * as a wildcard:"); /* * Text entry box (for specifying the pattern). We populate the entry box with the * initial pattern provided by our caller. */ Composite entryPanel = new Composite(panel, SWT.NONE); entryPanel.setLayout(new GridLayout(2, false)); entryPanel.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); entryBox = new Text(entryPanel, SWT.NONE); entryBox.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); entryBox.setText(patternString); entryBox.selectAll(); entryBox.setFocus(); /* * Create a "Match" button, which should only be enabled if the * pattern in the entry box is valid. Monitor when the list box * changes so that we can update the button's "enabled" status. */ final Button matchButton = new Button(entryPanel, SWT.PUSH); matchButton.setText("Match"); matchButton.setEnabled(isValidPattern(patternString)); entryBox.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { matchButton.setEnabled(isValidPattern(entryBox.getText())); } }); /* * Once the pattern is matched, the user must select which of the matching * actions are to be deleted. State this in a label. */ new Label(panel, SWT.NONE).setText("Select which of the matching actions you wish to " + operation.toLowerCase() + ":"); /* * A list box (which consumes the rest of the dialog box) shows all the matching * actions. The "OK" (Delete, Make Atomic) button is only enabled if at * least one action is highlighted. */ resultsListBox = new List(panel, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI); resultsListBox.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); resultsListBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { getButton(OK).setEnabled(resultsListBox.getSelectionIndices().length >= 1); } }); populateListWithMatches(patternString); /* * When the "Match" button is pressed, populate the list box. */ matchButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { populateListWithMatches(entryBox.getText()); } }); return parent; } /*-------------------------------------------------------------------------------------*/ /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#okPressed() */ @Override protected void okPressed() { /* compute the ActionSet of selected actions */ resultActionSet = new ActionSet(actionMgr); int[] selected = resultsListBox.getSelectionIndices(); for (int i = 0; i < selected.length; i++) { int actionId = matchingActions[selected[i]]; resultActionSet.add(actionId); } /* destroy the dialog and all Controls it contains */ super.okPressed(); } /*-------------------------------------------------------------------------------------*/ /* * (non-Javadoc) * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) */ @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setText("Select Actions by Pattern"); } /*-------------------------------------------------------------------------------------*/ /* (non-Javadoc) * @see org.eclipse.jface.dialogs.TrayDialog#createButtonBar(org.eclipse.swt.widgets.Composite) */ @Override protected Control createButtonBar(Composite parent) { Control result = super.createButtonBar(parent); /* until something is selected, the OK button is greyed out */ getButton(IDialogConstants.OK_ID).setEnabled(false); return result; } /*-------------------------------------------------------------------------------------*/ /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) */ @Override protected void createButtonsForButtonBar(Composite parent) { /* * Replace the standard "OK" label with the name of the operation we're performing * (e.g "Delete" or "Make Atomic". */ createButton(parent, IDialogConstants.OK_ID, operation, true); createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); } /*=====================================================================================* * PRIVATE METHODS *=====================================================================================*/ /** * When the user pressed the "Match" button, query the IBuildStore for matching actions, * then populate the list with the command strings. * * @param pattern The pattern to match against. */ private void populateListWithMatches(String pattern) { /* replace * with % - to satisfy the matching algorithm */ pattern = pattern.replace('*', '%'); /* search for matches */ matchingActions = actionMgr.getActionsWhereSlotIsLike(IActionMgr.COMMAND_SLOT_ID, pattern); /* add matches to results list box */ resultsListBox.removeAll(); for (int i = 0; i < matchingActions.length; i++) { String cmdString = (String) actionMgr.getSlotValue(matchingActions[i], IActionMgr.COMMAND_SLOT_ID); resultsListBox.add(cmdString); } } /*-------------------------------------------------------------------------------------*/ /** * Determine whether a pattern is "valid" (i.e. we're willing to search for actions * based on this pattern). * * @param pattern The pattern to be evaluated. * @return True if valid, else false. */ protected boolean isValidPattern(String pattern) { return pattern.length() >= 3; } /*-------------------------------------------------------------------------------------*/ }