/*
* Copyright 2010 The Rabbit Eclipse Plug-in Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package rabbit.ui.internal.dialogs;
import rabbit.ui.internal.util.ICategory;
import com.google.common.collect.Lists;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.forms.FormDialog;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
// TODO test
/**
* Dialog to allow user to structure how they want the data to be structured and
* displayed.
*/
public class GroupByDialog extends FormDialog {
/** Table viewer containing list of available categories. */
private TableViewer availableCategoriesViewer;
/** Tree viewer containing list of selected categories. */
private TreeViewer selectedCategoriesViewer;
private Button removeButton;
private Button addButton;
private Button downButton;
private Button upButton;
/** List of available categories. */
private List<ICategory> availableCategories;
/** List of selected categories. */
private List<ICategory> selectedCategories;
/**
* Content provider for {@link #availableCategoriesViewer}, always return the
* elements of {@link #availableCategories}.
*/
private IStructuredContentProvider availableCatContentProvider = new IStructuredContentProvider() {
@Override
public void dispose() {
}
@Override
public Object[] getElements(Object inputElement) {
return availableCategories.toArray();
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
};
/**
* Content provider for {@link #selectedCategoriesViewer}, always return the
* elements of {@link #selectedCategories}.
*/
private ITreeContentProvider selectedCatContentProvider = new ITreeContentProvider() {
@Override
public void dispose() {
}
@Override
public Object[] getChildren(Object element) {
int index = selectedCategories.indexOf(element);
if (index < 0 || index >= selectedCategories.size() - 1) {
return new Object[0];
}
return new Object[] { selectedCategories.get(index + 1) };
}
@Override
public Object[] getElements(Object inputElement) {
return (selectedCategories.isEmpty()) ? new Object[0]
: new Object[] { selectedCategories.get(0) };
}
@Override
public Object getParent(Object element) {
return null;
}
@Override
public boolean hasChildren(Object element) {
int index = selectedCategories.indexOf(element);
return (index > -1) && (index < selectedCategories.size() - 1);
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
};
@Override
public int open() {
refreshViewers();
return super.open();
}
/**
* Constructor.
*
* @param shell The parent shell.
*/
public GroupByDialog(Shell shell) {
super(shell);
availableCategories = Lists.newLinkedList();
selectedCategories = Lists.newLinkedList();
}
/**
* Gets the user selected categories. This method should be call after this
* dialog is closed.
*
* @return The user selected categories.
*/
public ICategory[] getSelectedCategories() {
return selectedCategories.toArray(new ICategory[selectedCategories.size()]);
}
/**
* Sets the elements to be displayed as available (not currently enabled).
* This method should be called before this dialog is made visible.
*
* @param categories The elements.
*/
public void setUnSelectedCategories(Collection<ICategory> categories) {
availableCategories.clear();
availableCategories.addAll(categories);
}
/**
* Sets the elements to be displayed as selected (currently enabled). This
* method should be called before this dialog is made visible.
*
* @param categories The elements.
*/
public void setSelectedCategories(List<ICategory> categories) {
selectedCategories.clear();
selectedCategories.addAll(categories);
}
@Override
protected void createFormContent(IManagedForm mform) {
setHelpAvailable(false);
getShell().setText("Grouping");
FormToolkit toolkit = mform.getToolkit();
Form form = mform.getForm().getForm();
form.setMessage("Specify how the elements should be structured",
IMessageProvider.INFORMATION);
toolkit.decorateFormHeading(form);
form.getBody().setLayout(new GridLayout());
Section section = toolkit.createSection(form.getBody(), Section.TITLE_BAR);
section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
section.setText("Groups");
Composite parent = toolkit.createComposite(section);
parent.setLayout(new GridLayout(3, false));
section.setClient(parent);
// The labels at the top:
toolkit.createLabel(parent, "Available Groups:");
toolkit.createLabel(parent, "");
toolkit.createLabel(parent, "Selected Groups:");
createAvailableCategoriesViewer(parent);
Composite buttonsComposite = toolkit.createComposite(parent);
createButtons(buttonsComposite, toolkit);
createSelectedCategoriesViewer(parent);
}
/**
* Creates the table viewer showing the list of available categories.
*/
private void createAvailableCategoriesViewer(Composite parent) {
availableCategoriesViewer = new TableViewer(parent, SWT.BORDER | SWT.MULTI);
availableCategoriesViewer.setContentProvider(availableCatContentProvider);
availableCategoriesViewer.setLabelProvider(new CategoryLabelProvider());
availableCategoriesViewer.getTable().setLayoutData(
new GridData(SWT.FILL, SWT.FILL, true, true));
// Enable/disable buttons when selection changes:
availableCategoriesViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
addButton.setEnabled(!event.getSelection().isEmpty());
}
});
// Adds element to selected viewer when double clicked:
availableCategoriesViewer
.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
if (!event.getSelection().isEmpty()) {
handleAddEvent();
}
}
});
// Sets the input only once, call refresh when changes made to the list:
availableCategoriesViewer.setInput(availableCategories);
}
/**
* Creates the buttons for selecting/moving elements between the viewers.
*/
private void createButtons(Composite parent, FormToolkit toolkit) {
RowLayout layout = new RowLayout(SWT.VERTICAL);
layout.fill = true;
parent.setLayout(layout);
SelectionListener listener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Object source = e.getSource();
if (source == addButton)
handleAddEvent();
else if (source == removeButton)
handleRemoveEvent();
else if (source == upButton)
handleMoveUpEvent();
else if (source == downButton)
handleMoveDownEvent();
}
};
addButton = toolkit.createButton(parent, "-->", SWT.PUSH);
addButton.addSelectionListener(listener);
addButton.setEnabled(false);
removeButton = toolkit.createButton(parent, "<--", SWT.PUSH);
removeButton.addSelectionListener(listener);
removeButton.setEnabled(false);
upButton = toolkit.createButton(parent, "Up", SWT.PUSH);
upButton.addSelectionListener(listener);
upButton.setEnabled(false);
downButton = toolkit.createButton(parent, "Down", SWT.PUSH);
downButton.addSelectionListener(listener);
downButton.setEnabled(false);
}
/**
* Creates the tree viewer for show the selection categories.
*/
private void createSelectedCategoriesViewer(Composite parent) {
selectedCategoriesViewer = new TreeViewer(parent, SWT.BORDER | SWT.MULTI);
selectedCategoriesViewer.setContentProvider(selectedCatContentProvider);
selectedCategoriesViewer.setLabelProvider(new CategoryLabelProvider());
selectedCategoriesViewer.getTree().setLayoutData(
new GridData(SWT.FILL, SWT.FILL, true, true));
// Enable/disable buttons when selection changes:
selectedCategoriesViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
removeButton.setEnabled(!selection.isEmpty());
if (selection.isEmpty()) {
upButton.setEnabled(false);
downButton.setEnabled(false);
} else {
// Disables move up button if selection index == 0:
IStructuredSelection structured = (IStructuredSelection) selection;
Object element = structured.getFirstElement();
upButton.setEnabled(selectedCategories.indexOf(element) > 0);
// Disables move down button last element is selection:
Object[] array = structured.toArray();
element = array[array.length - 1];
int index = selectedCategories.indexOf(element);
if (index == selectedCategories.size() - 1) {
downButton.setEnabled(false);
} else {
downButton.setEnabled(true);
}
}
}
});
// Double click to remove elements:
selectedCategoriesViewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
if (!event.getSelection().isEmpty()) {
handleRemoveEvent();
}
}
});
// Sets the input only once, call refresh when changes made to the list:
selectedCategoriesViewer.setInput(selectedCategories);
selectedCategoriesViewer.expandAll();
}
/**
* Adds the selected elements from {@link #availableCategoriesViewer} to
* {@link #selectedCategoriesViewer}, if any.
*/
private void handleAddEvent() {
ISelection selection = availableCategoriesViewer.getSelection();
if (selection.isEmpty()) {
return;
}
for (Object element : ((IStructuredSelection) selection).toArray()) {
availableCategories.remove(element);
selectedCategories.add((ICategory) element);
}
refreshViewers();
}
/**
* Moves the selected elements in {@link #selectedCategoriesViewer} down a
* level, if possible.
*/
private void handleMoveDownEvent() {
ISelection selection = selectedCategoriesViewer.getSelection();
if (selection.isEmpty()) {
return;
}
IStructuredSelection structure = (IStructuredSelection) selection;
for (Object element : structure.toArray()) {
int index = selectedCategories.indexOf(element);
if (index <= selectedCategories.size() - 2) {
Collections.swap(selectedCategories, index, index + 1);
}
}
refreshViewers();
}
/**
* Moves the selected elements in {@link #selectedCategoriesViewer} up a
* level, if possible.
*/
private void handleMoveUpEvent() {
ISelection selection = selectedCategoriesViewer.getSelection();
if (selection.isEmpty()) {
return;
}
IStructuredSelection structure = (IStructuredSelection) selection;
if (selectedCategories.indexOf(structure.getFirstElement()) <= 0) {
return;
}
for (Object element : structure.toArray()) {
int index = selectedCategories.indexOf(element);
Collections.swap(selectedCategories, index, index - 1);
}
refreshViewers();
}
/**
* Removes the selected elements from {@link #selectedCategoriesViewer} to
* {@link #availableCategoriesViewer}, if any.
*/
private void handleRemoveEvent() {
ISelection selection = selectedCategoriesViewer.getSelection();
if (selection.isEmpty()) {
return;
}
for (Object element : ((IStructuredSelection) selection).toArray()) {
selectedCategories.remove(element);
availableCategories.add((ICategory) element);
}
refreshViewers();
}
/**
* Refreshes the viewers when the underlying models change.
*/
private void refreshViewers() {
ISelection selection = availableCategoriesViewer.getSelection();
availableCategoriesViewer.refresh();
availableCategoriesViewer.setSelection(selection, true);
selection = selectedCategoriesViewer.getSelection();
selectedCategoriesViewer.refresh();
selectedCategoriesViewer.expandAll();
selectedCategoriesViewer.setSelection(selection, true);
}
}