/******************************************************************************* * 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.utils.dialogs; import java.util.ArrayList; import org.eclipse.swt.SWT; 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.Combo; 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 com.buildml.eclipse.utils.BmlTitleAreaDialog; /** * A dialog allowing the user to select equal-sized subgroups of a list of items. * This class can be used for any list of textual items, where there's a need to * break those items into equal-sized subgroups. * * @author Peter Smith <psmith@arapiki.com> */ public class SubGroupSelectionDialog extends BmlTitleAreaDialog { /*=====================================================================================* * FIELDS/TYPES *=====================================================================================*/ /** The items to be grouped */ private String[] items; /** All the valid sub group sizes */ private ArrayList<Integer> validSizes; /** The chosen subgroup size */ private int chosenSize = 0; /*=====================================================================================* * CONSTRUCTOR *=====================================================================================*/ /** * Create a new {@link SubGroupSelectionDialog} * * @param items The list of String items to be grouped. */ public SubGroupSelectionDialog(String [] items) { super(new Shell(), 0.3, 0.5, 0.5, 0.5); this.items = items; /* compute the possible sub-group sizes */ this.validSizes = computeDivisors(items.length); } /*=====================================================================================* * PUBLIC METHODS *=====================================================================================*/ /** * Return the chosen subgroup size. This method should only be called after the "OK" * button has been pressed. * * @return The selected subgroup size, or 0 if no size was selected. */ public int getGroupSize() { return chosenSize; } /*=====================================================================================* * 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); /* * Is the size of the input list appropriate? That is, are there any valid sub-group * sizes that we can merge them into? */ if (validSizes.size() == 0) { setErrorMessage("Invalid number of items selected - can't divide into groups"); Label error = new Label(panel, SWT.WRAP); error.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); error.setText("To divide the selected items into smaller groups, " + "you must select an equally-divisable number of items. For example, " + "a multiple of 2, a multiple of 3, etc."); return parent; } /* * Informative message */ new Label(panel, SWT.WRAP).setText("Please select the number of items to appear " + "in each sub-group:"); /* * display the valid sizes in a pull-down list, and select the first size choice * as the default (often this is "2"). */ final Combo sizeSelector = new Combo(panel, SWT.READ_ONLY); for (int subGroupSize : validSizes) { sizeSelector.add("Group Size: " + subGroupSize); } sizeSelector.select(0); chosenSize = validSizes.get(0); /* * Display all the strings in a list box, with spaces between each sub-group */ final List itemList = new List(panel, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); itemList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); fillListBox(itemList, items, chosenSize); /* * If the user selects a different group size, redraw the content of the */ sizeSelector.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { chosenSize = validSizes.get(sizeSelector.getSelectionIndex()); fillListBox(itemList, items, chosenSize); } }); return parent; } /*-------------------------------------------------------------------------------------*/ /* * (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("Choose the Sub-Group Size"); } /*=====================================================================================* * PRIVATE METHODS *=====================================================================================*/ /** * Given the size of the input group, compute all the possible sub-group sizes that * evenly divide into the totalSize. For example, if totalSize is 10, then the valid * sub-group sizes are [2, 5]. * * @param totalSize The size of the whole input group. * @return An array of valid sub-group sizes. */ private ArrayList<Integer> computeDivisors(int totalSize) { ArrayList<Integer> results = new ArrayList<Integer>(); for (int i = 2; i <= totalSize / 2; i++) { if ((totalSize % i) == 0) { results.add(i); } } return results; } /*-------------------------------------------------------------------------------------*/ /** * Populate the List widget with the items to be divided into sub-groups. Based on the * specified sub-group size, insert a divider line. * * @param itemList List widget to display the items within. * @param items The items to be displayed. * @param subGroupSize The size of each sub-group (for displaying divider lines). */ private void fillListBox(List itemList, String[] items, Integer subGroupSize) { itemList.removeAll(); for (int i = 0; i < items.length; i++) { if ((i != 0) && (i % subGroupSize == 0)) { itemList.add(""); } itemList.add(items[i]); } } /*-------------------------------------------------------------------------------------*/ }