Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.directory.studio.common.ui.widgets; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import org.apache.directory.studio.common.ui.AddEditDialog; import org.apache.directory.studio.common.ui.Messages; import org.apache.directory.studio.common.ui.TableDecorator; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; 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.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.Table; import org.eclipse.ui.forms.widgets.FormToolkit; /** * The TableWidget provides a table viewer to add/edit/remove an element. * * <pre> * +--------------------------------------+ * | Element 1 | (Add... ) * | Element 2 | (Edit...) * | | (Delete ) * +--------------------------------------+ * </pre> * * The elements are ordered. * * <pre> * Note : This class contain codes from the Apache PDF box project ('sort' method) * </pre> * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ public class TableWidget<E> extends AbstractWidget { /** The element list */ private List<E> elements = new ArrayList<E>(); /** The current selection index, if any */ private int currentSelection; /** A flag set to tell if we have a Edit button */ private boolean hasEdit; /** A flag set when the table is ordered (ie, it has a Up and Down buttons) */ private boolean isOrdered; /** A flag that says if teh table is enabled or disabled */ private boolean isEnabled = true; /** The flag set when the table is ordered */ private static final boolean ORDERED = true; /** The flag set when the table is not ordered */ private static final boolean UNORDERED = false; // UI widgets private Composite composite; private Table elementTable; private TableViewer elementTableViewer; // The buttons private Button addButton; private Button editButton; private Button deleteButton; private Button upButton; private Button downButton; /** The decorator */ private TableDecorator<E> decorator; // A listener on the Elements table, that modifies the button when an Element is selected private ISelectionChangedListener tableViewerSelectionChangedListener = new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { if (isEnabled) { int selectionLine = elementTableViewer.getTable().getSelectionIndex(); if (selectionLine == currentSelection) { // We have selected the line twice, deselect the line elementTableViewer.getTable().deselect(selectionLine); currentSelection = -1; } else { currentSelection = selectionLine; StructuredSelection selection = (StructuredSelection) elementTableViewer.getSelection(); if (hasEdit) { editButton.setEnabled(!selection.isEmpty()); } deleteButton.setEnabled(!selection.isEmpty()); if (isOrdered) { // We can't enable the UP button when we don't have any element in the table, // or when we have only one, or when the selection is the first one in the table upButton.setEnabled(!selection.isEmpty() && (elements.size() > 1) && (selectionLine > 0)); // We can't enable the DOWN button when we don't have any element in the table, // or when we have only one element, or when the selected element is the last one downButton.setEnabled(!selection.isEmpty() && (elements.size() > 1) && (selectionLine < elements.size() - 1)); } } } } }; // A listener on the Element table, that reacts to a doubleClick : it's opening the Element editor private IDoubleClickListener tableViewerDoubleClickListener = new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { if (isEnabled) { editElement(); } } }; // A listener on the Add button, which opens the Element addition editor private SelectionListener addButtonListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { addElement(); } }; // A listener on the Edit button, that open the Element editor private SelectionListener editButtonListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { editElement(); } }; // A listener on the Delete button, which delete the selected Element private SelectionListener deleteButtonListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { deleteElement(); } }; // A listener on the Up button, that move the selected elemnt up one position private SelectionListener upButtonListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { upElement(); } }; // A listener on the Down button, that move the selected element down one position private SelectionListener downButtonListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { downElement(); } }; /** * Creates a new instance of TableWidget. * * @param decorator the decorator to use, containing the Dialog comparator and labelProvider */ public TableWidget(TableDecorator<E> decorator) { this.decorator = decorator; currentSelection = -1; } /** * Creates the Table widget. It's a Table and three buttons : * <pre> * +--------------------------------------+ * | Element 1 | (Add... ) * | Element 2 | (Edit...) * | | (Delete ) * +--------------------------------------+ * </pre> * </pre> * * @param parent the parent * @param toolkit the toolkit */ public void createWidgetWithEdit(Composite parent, FormToolkit toolkit) { createWidget(parent, toolkit, true, UNORDERED); } /** * Creates the Table widget. It's a Table and two buttons : * <pre> * +--------------------------------------+ * | Element 1 | (Add... ) * | Element 2 | (Delete ) * | | * +--------------------------------------+ * </pre> * * @param parent the parent * @param toolkit the toolkit */ public void createWidgetNoEdit(Composite parent, FormToolkit toolkit) { createWidget(parent, toolkit, false, UNORDERED); } /** * Creates the ordered Table widget. It's a Table and five buttons : * <pre> * +--------------------------------------+ * | Element 1 | (Add... ) * | Element 2 | (Edit...) * | | (Delete ) * | | --------- * | | (Up... ) * | | (Down.. ) * +--------------------------------------+ * </pre> * The 'Up' and 'Down' buttons are used to order the elements. * * @param parent the parent * @param toolkit the toolkit */ public void createOrderedWidgetWithEdit(Composite parent, FormToolkit toolkit) { createWidget(parent, toolkit, true, ORDERED); } /** * Creates the Table widget. It's a Table and four buttons : * <pre> * +--------------------------------------+ * | Element 1 | (Add... ) * | Element 2 | (Delete ) * | | --------- * | | (Up... ) * | | (Down.. ) * +--------------------------------------+ * </pre> * The 'Up' and 'Down' buttons are used to order the elements. * * @param parent the parent * @param toolkit the toolkit */ public void createOrderedWidgetNoEdit(Composite parent, FormToolkit toolkit) { createWidget(parent, toolkit, true, ORDERED); } /** * Creates the Table widget. It's a Table and two or three button : * <pre> * +--------------------------------------+ * | Element 1 | (Add... ) * | Element 2 | (Edit...) * | | (Delete ) * +--------------------------------------+ * </pre> * or : * <pre> * +--------------------------------------+ * | Element 1 | (Add... ) * | Element 2 | (Delete ) * | | * +--------------------------------------+ * </pre> * * If the table is ordered, we have two additional buttons to re-organize * the elements at will : * <pre> * ... * | | --------- * | | (Up... ) * | | (Down.. ) * +--------------------------------------+ * </pre> * * @param parent the parent * @param toolkit the toolkit * @param hasEdit the flag set when the Edit button is present * @param isOrdered the flag set when we have the Up and Down buttons */ private void createWidget(Composite parent, FormToolkit toolkit, boolean hasEdit, boolean isOrdered) { this.hasEdit = hasEdit; this.isOrdered = isOrdered; // Composite if (toolkit != null) { composite = toolkit.createComposite(parent); } else { composite = new Composite(parent, SWT.NONE); } // First, define a grid of 3 columns (two for the table, one for the buttons) GridLayout compositeGridLayout = new GridLayout(2, false); compositeGridLayout.marginHeight = compositeGridLayout.marginWidth = 0; composite.setLayout(compositeGridLayout); // Create the Element Table and Table Viewer if (toolkit != null) { elementTable = toolkit.createTable(composite, SWT.NULL); } else { elementTable = new Table(composite, SWT.NULL); } // Define the table size and height. It will span on 3 to 5 lines, // depending on the number of buttons int nbLinesSpan = 3; if (isOrdered) { // If it's an ordered table, we add 3 line s: one for Up, one for Down and one for the separator nbLinesSpan += 3; } GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true, 1, nbLinesSpan); elementTable.setLayoutData(gd); // Create the index TableViewer elementTableViewer = new TableViewer(elementTable); elementTableViewer.setContentProvider(new ArrayContentProvider()); // The LabelProvider elementTableViewer.setLabelProvider(decorator); elementTableViewer.addSelectionChangedListener(tableViewerSelectionChangedListener); // Listeners : we want to catch changes and double clicks (if we have an edit button) if (hasEdit) { elementTableViewer.addDoubleClickListener(tableViewerDoubleClickListener); } // Inject the existing elements elementTableViewer.setInput(elements); GridData buttonGd = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1); buttonGd.widthHint = 60; // Create the Add Button and its listener if (toolkit != null) { addButton = toolkit.createButton(composite, Messages.getString("CommonUIWidgets.AddButton"), SWT.PUSH); addButton.setLayoutData(buttonGd); } else { addButton = BaseWidgetUtils.createButton(composite, Messages.getString("CommonUIWidgets.AddButton"), 1); addButton.setLayoutData(buttonGd); } addButton.setLayoutData(buttonGd); addButton.addSelectionListener(addButtonListener); // Create the Edit Button and its listener, if requested if (hasEdit) { if (toolkit != null) { editButton = toolkit.createButton(composite, Messages.getString("CommonUIWidgets.EditButton"), SWT.PUSH); } else { editButton = BaseWidgetUtils.createButton(composite, Messages.getString("CommonUIWidgets.EditButton"), SWT.PUSH); } // It's not enabled unless we have selected an element editButton.setEnabled(false); editButton.setLayoutData(buttonGd); editButton.addSelectionListener(editButtonListener); } // Create the Delete Button and its listener if (toolkit != null) { deleteButton = toolkit.createButton(composite, Messages.getString("CommonUIWidgets.DeleteButton"), SWT.PUSH); } else { deleteButton = BaseWidgetUtils.createButton(composite, Messages.getString("CommonUIWidgets.DeleteButton"), SWT.PUSH); } // It's not selected unless we have selected an index deleteButton.setEnabled(false); deleteButton.setLayoutData(buttonGd); deleteButton.addSelectionListener(deleteButtonListener); // Create the Up and Down button, if requested if (isOrdered) { Label separator = BaseWidgetUtils.createSeparator(composite, 1); separator.setLayoutData(new GridData(SWT.NONE, SWT.BEGINNING, false, false)); // Create the Up Button and its listener if (toolkit != null) { upButton = toolkit.createButton(composite, Messages.getString("CommonUIWidgets.UpButton"), SWT.PUSH); } else { upButton = BaseWidgetUtils.createButton(composite, Messages.getString("CommonUIWidgets.UpButton"), SWT.PUSH); } // It's not selected unless we have selected an index upButton.setEnabled(false); upButton.setLayoutData(buttonGd); //upButton.setLayoutData( new GridData( SWT.FILL, SWT.BEGINNING, false, false ) ); upButton.addSelectionListener(upButtonListener); // Create the Down Button and its listener if (toolkit != null) { downButton = toolkit.createButton(composite, Messages.getString("CommonUIWidgets.DownButton"), SWT.PUSH); } else { downButton = BaseWidgetUtils.createButton(composite, Messages.getString("CommonUIWidgets.DownButton"), SWT.PUSH); } // It's not selected unless we have selected an index downButton.setEnabled(false); downButton.setLayoutData(buttonGd); //downButton.setLayoutData( new GridData( SWT.FILL, SWT.BEGINNING, false, false ) ); downButton.addSelectionListener(downButtonListener); } } /** * Enable the table (Buttons will be active, except the Edit and Delete ones, actions on the table will be active) */ public void enable() { if (addButton != null) { addButton.setEnabled(true); } if (upButton != null) { upButton.setEnabled(true); } if (downButton != null) { downButton.setEnabled(true); } isEnabled = true; } /** * Disable the table (Buttons will be inactive, actions on the table will be inactive) */ public void disable() { if (addButton != null) { addButton.setEnabled(false); } if (deleteButton != null) { deleteButton.setEnabled(false); } if (editButton != null) { editButton.setEnabled(false); } if (upButton != null) { upButton.setEnabled(false); } if (downButton != null) { downButton.setEnabled(false); } isEnabled = false; } /** * Returns the primary control associated with this widget. * * @return the primary control associated with this widget. */ public Control getControl() { return composite; } /* --------------------------------------------------------------------------------------------------------------- */ /* Taken from the Apache PdfBox project, */ /* @author UWe Pachler */ /* --------------------------------------------------------------------------------------------------------------- */ /** * Sorts the given list using the given comparator. * * @param list list to be sorted * @param cmp comparator used to compare the object swithin the list */ public static <T> void sort(List<T> list, Comparator<T> cmp) { int size = list.size(); if (size < 2) { return; } quicksort(list, cmp, 0, size - 1); } private static <T> void quicksort(List<T> list, Comparator<T> cmp, int left, int right) { if (left < right) { int splitter = split(list, cmp, left, right); quicksort(list, cmp, left, splitter - 1); quicksort(list, cmp, splitter + 1, right); } } private static <T> void swap(List<T> list, int i, int j) { T tmp = list.get(i); list.set(i, list.get(j)); list.set(j, tmp); } private static <T> int split(List<T> list, Comparator<T> cmp, int left, int right) { int i = left; int j = right - 1; T pivot = list.get(right); do { while ((cmp.compare(list.get(i), pivot) <= 0) && (i < right)) { ++i; } while ((cmp.compare(pivot, list.get(j)) <= 0) && (j > left)) { --j; } if (i < j) { swap(list, i, j); } } while (i < j); if (cmp.compare(pivot, list.get(i)) < 0) { swap(list, i, right); } return i; } /* --------------------------------------------------------------------------------------------------------------- */ /* End of the QuickSort implementation taken from the Apache PdfBox project, */ /* --------------------------------------------------------------------------------------------------------------- */ /** * Sets the Elements. * * @param elements the elements */ public void setElements(List<E> elements) { this.elements.clear(); if ((elements != null) && (elements.size() > 0)) { sort(elements, decorator); this.elements.addAll(elements); } elementTableViewer.refresh(); } /** * Gets the elements. * * @return the elements */ public List<E> getElements() { if (elements != null) { List<E> copy = new ArrayList<E>(elements.size()); copy.addAll(elements); return copy; } return null; } /** * This method is called when the 'Add...' button is clicked. */ private void addElement() { AddEditDialog<E> dialog = decorator.getDialog(); dialog.setAdd(); dialog.addNewElement(); dialog.setElements(elements); // Inject the position if we have a selected value StructuredSelection selection = (StructuredSelection) elementTableViewer.getSelection(); int insertionPos = elements.size(); if (!selection.isEmpty()) { insertionPos = elementTableViewer.getTable().getSelectionIndex(); } // Open the Dialog, and process the addition if it went fine if (decorator.getDialog().open() == Dialog.OK) { E newElement = decorator.getDialog().getEditedElement(); if (!elements.contains(newElement)) { String elementStr = newElement.toString(); int pos = 0; if (isOrdered) { // The table is ordered, insert the element at the right position ((OrderedElement) newElement).setPrefix(insertionPos); elements.add(insertionPos, newElement); // Move up the following elements for (int i = insertionPos + 1; i < elements.size(); i++) { E element = elements.get(i); ((OrderedElement) element).incrementPrefix(); } } else { if (selection.isEmpty()) { // no selected element, add at the end pos = elements.size(); } else { pos = elementTableViewer.getTable().getSelectionIndex() + 1; } elements.add(pos, newElement); } elementTableViewer.refresh(); elementTableViewer.setSelection(new StructuredSelection(elementStr)); } notifyListeners(); } } /** * This method is called when the 'Edit...' button is clicked * or the table viewer is double-clicked. */ private void editElement() { StructuredSelection selection = (StructuredSelection) elementTableViewer.getSelection(); if (!selection.isEmpty()) { AddEditDialog<E> dialog = decorator.getDialog(); dialog.setEdit(); E selectedElement = (E) selection.getFirstElement(); int editPosition = elementTableViewer.getTable().getSelectionIndex(); dialog.setEditedElement(selectedElement); dialog.setSelectedPosition(editPosition); // Open the element dialog, with the selected index if (decorator.getDialog().open() == Dialog.OK) { E newElement = dialog.getEditedElement(); if (!isOrdered) { // Check to see if the modified element does not already exist if (elements.contains(newElement)) { // Remove the original element elements.remove(selectedElement); // Replace the existing element with the new one elements.remove(newElement); int pos = 0; for (E element : elements) { if (decorator.compare(element, newElement) > 0) { break; } else { pos++; } } elements.add(pos, newElement); } else { // We will remove the modified element, and replace it with the new element // Replace the old element by the new one elements.remove(editPosition); elements.add(editPosition, newElement); } } else { // Remove the original element elements.remove(selectedElement); elements.add(editPosition, newElement); } elementTableViewer.refresh(); elementTableViewer.setSelection(new StructuredSelection(newElement.toString())); notifyListeners(); } } } /** * This method is called when the 'Delete' button is clicked. */ private void deleteElement() { StructuredSelection selection = (StructuredSelection) elementTableViewer.getSelection(); if (!selection.isEmpty()) { // If the table is ordered, we need to decrement the prefix of all the following elements if (isOrdered) { int selectedPosition = elementTableViewer.getTable().getSelectionIndex(); for (int i = selectedPosition + 1; i < elements.size(); i++) { E nextElement = elements.get(i); ((OrderedElement) nextElement).decrementPrefix(); elements.set(i - 1, nextElement); } elements.remove(elements.size() - 1); } else { int selectedPosition = elementTableViewer.getTable().getSelectionIndex(); elements.remove(selectedPosition); } elementTableViewer.refresh(); notifyListeners(); } } /** * This method is called when the 'Up...' button is clicked */ private void upElement() { StructuredSelection selection = (StructuredSelection) elementTableViewer.getSelection(); if (!selection.isEmpty()) { // Get the line the selected element is in. We will move it up int selectionLine = elementTableViewer.getTable().getSelectionIndex(); // The selected element E selectedElement = (E) selection.getFirstElement(); // Decrease the prefix ((OrderedElement) selectedElement).decrementPrefix(); // Just swap the elements which is just before with the selected one E previousElement = getElements().get(selectionLine - 1); // Increase the prefix ((OrderedElement) previousElement).incrementPrefix(); elements.remove(selectionLine - 1); elements.add(selectionLine, previousElement); // Refresh the table now elementTableViewer.refresh(); elementTableViewer.setSelection(new StructuredSelection(selectedElement)); notifyListeners(); } } /** * This method is called when the 'Down...' button is clicked * or the table viewer is double-clicked. */ private void downElement() { StructuredSelection selection = (StructuredSelection) elementTableViewer.getSelection(); if (!selection.isEmpty()) { // Get the line the selected element is in. We will move it down int selectionLine = elementTableViewer.getTable().getSelectionIndex(); // The selected element E selectedElement = (E) selection.getFirstElement(); // Increase the prefix ((OrderedElement) selectedElement).incrementPrefix(); // Just swap the elements which is just after with the selected one E previousElement = getElements().get(selectionLine + 1); // Decrease the prefix ((OrderedElement) previousElement).decrementPrefix(); elements.remove(selectionLine + 1); elements.add(selectionLine, previousElement); // refresh the table now elementTableViewer.refresh(); elementTableViewer.setSelection(new StructuredSelection(selectedElement)); notifyListeners(); } } }