/******************************************************************************* * Copyright (C) 2003-2007, 2013, Guillaume Brocker * * 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: * Guillaume Brocker - Initial API and implementation * ******************************************************************************/ package eclox.ui.editor.editors; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Vector; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.ListViewer; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.forms.widgets.FormToolkit; import eclox.core.doxyfiles.Setting; /** * Implements a list setting editor. This class is abstract since it provides no way to * edit value compounds. See derived classes. * * @author gbrocker */ public abstract class ListEditor extends SettingEditor { /** * Implements the table viewer content provider. */ private class MyContentProvider implements IStructuredContentProvider { public Object[] getElements(Object inputElement) { Vector<?> compounds = (Vector<?>) inputElement; return compounds.toArray(); } public void dispose() {} public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {} } /** * Implements the table viewer label provider. */ private class MyLabelProvider extends LabelProvider { public String getText(Object element) { return new String( (String)element ); } } /** * Implements an open listener that will trigger the edition of the selected list viewer item. */ private class MyOpenListener implements IOpenListener { public void open(OpenEvent event) { editSelectedValueCompound(); } } /** * Implements a button selection listener. */ private class MyButtonSelectionListener implements SelectionListener { public void widgetDefaultSelected(SelectionEvent e) { widgetSelected( e ); } public void widgetSelected(SelectionEvent e) { if( e.widget == addButton ) { addValueCompound(); } else if( e.widget == removeButton ) { removeValueCompounds(); } else if( e.widget == upButton ) { moveValueCompoundsUp(); } else if( e.widget == downButton ) { moveValueCompoundsDown(); } else { // Unsuported widget. assert false; } } } /** * Implements a selection change listener to update the button states. */ private class MySelectionChangedListener implements ISelectionChangedListener { public void selectionChanged(SelectionChangedEvent event) { updateButtons(); } } private Vector<String> valueCompounds; ///< The collection of the setting's value compounds. private ListViewer listViewer; ///< the table viewer used to edit the managed setting private Button addButton; ///< the button allowing to trigger a new value addition private Button removeButton; ///< the button allowing to trigger the deletion of selected values private Button upButton; ///< the button allowing to move the selected values up private Button downButton; ///< the button allowing to move the selected values down /** * @see eclox.ui.editor.editors.IEditor#commit() */ public void commit() { if( hasInput() ) { getInput().setValue( valueCompounds ); fireEditorChanged(); } } /** * @see eclox.ui.editor.editors.IEditor#createContent(org.eclipse.swt.widgets.Composite, org.eclipse.ui.forms.widgets.FormToolkit) */ public void createContent(Composite parent, FormToolkit formToolkit) { // Pre-condition assert listViewer == null; // Activates border painting. formToolkit.paintBordersFor( parent ); // Installs the layout. FormLayout layout = new FormLayout(); layout.spacing = 2; parent.setLayout( layout ); // Creates the list viewer and installs it in the layout. FormData formData; listViewer = new ListViewer( parent, SWT.H_SCROLL | SWT.V_SCROLL ); formData = new FormData(); formData.top = new FormAttachment( 0, 2 ); formData.right = new FormAttachment( 85, -1 ); formData.bottom = new FormAttachment( 100, -2 ); formData.left = new FormAttachment( 0, 1 ); listViewer.getControl().setLayoutData( formData ); listViewer.getControl().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); // Initializes the list viewer. listViewer.setContentProvider( new MyContentProvider() ); listViewer.setLabelProvider( new MyLabelProvider() ); listViewer.addOpenListener( new MyOpenListener() ); // Creates various buttons and installs them in the layout. addButton = formToolkit.createButton( parent, "Add", 0 ); removeButton = formToolkit.createButton( parent, "Remove", 0 ); upButton = formToolkit.createButton( parent, "Up", 0 ); downButton = formToolkit.createButton( parent, "Down", 0 ); formData = new FormData(); formData.top = new FormAttachment( 0, 0 ); formData.right = new FormAttachment( 100, 0 ); formData.left = new FormAttachment( listViewer.getControl(), 2, SWT.RIGHT ); addButton.setLayoutData( formData ); formData = new FormData(); formData.top = new FormAttachment( addButton, 0, SWT.BOTTOM ); formData.right = new FormAttachment( 100, 0 ); formData.left = new FormAttachment( listViewer.getControl(), 2, SWT.RIGHT ); removeButton.setLayoutData( formData ); formData = new FormData(); formData.top = new FormAttachment( removeButton, 6, SWT.BOTTOM ); formData.right = new FormAttachment( 100, 0 ); formData.left = new FormAttachment( listViewer.getControl(), 2, SWT.RIGHT ); upButton.setLayoutData( formData ); formData = new FormData(); formData.top = new FormAttachment( upButton, 0, SWT.BOTTOM ); formData.right = new FormAttachment( 100, 0 ); formData.left = new FormAttachment( listViewer.getControl(), 2, SWT.RIGHT ); downButton.setLayoutData( formData ); // Assignes a selection listener to the managed buttons. MyButtonSelectionListener selectionListener = new MyButtonSelectionListener(); addButton.addSelectionListener( selectionListener ); removeButton.addSelectionListener( selectionListener ); upButton.addSelectionListener( selectionListener ); downButton.addSelectionListener( selectionListener ); // Adds a selection change listener to the list viewer and initializes the button states. listViewer.addPostSelectionChangedListener( new MySelectionChangedListener() ); updateButtons(); // Post-condition assert listViewer != null; } public boolean grabVerticalSpace() { return true; } public void dispose() { // Pre-condition assert listViewer != null; assert addButton != null; assert removeButton != null; assert upButton != null; assert downButton != null; listViewer.getControl().dispose(); listViewer = null; addButton.dispose(); addButton = null; removeButton.dispose(); removeButton = null; upButton.dispose(); upButton = null; downButton.dispose(); downButton = null; super.dispose(); // Post-condition assert listViewer == null; assert addButton == null; assert removeButton == null; assert upButton == null; assert downButton == null; } /** * @see eclox.ui.editor.editors.IEditor#setEnabled(boolean) */ public void setEnabled(boolean enabled) { // Pre-condition assert listViewer != null; assert addButton != null; assert removeButton != null; assert upButton != null; assert downButton != null; listViewer.getControl().setEnabled(enabled); addButton.setEnabled(enabled); removeButton.setEnabled(enabled); upButton.setEnabled(enabled); downButton.setEnabled(enabled); } /** * @see eclox.ui.editor.editors.IEditor#setFocus() */ public void setFocus() { // Pre-condition assert listViewer != null; listViewer.getControl().setFocus(); } /** * @see eclox.ui.editor.editors.IEditor#refresh() */ public void refresh() { // Pre-condition assert listViewer != null; if( hasInput() ) { valueCompounds = new Vector<String>(); getInput().getSplittedValue( valueCompounds ); listViewer.setInput(valueCompounds); updateButtons(); fireEditorChanged(); } } /** * @see eclox.ui.editor.editors.IEditor#isDirty() */ public boolean isDirty() { return false; } /** * @see eclox.ui.editor.editors.IEditor#isStale() */ public boolean isStale() { boolean result = false; if( hasInput() ) { Collection<String> values = new Vector<String>(); getInput().getSplittedValue(values); result = valueCompounds.equals(values) == false; } return result; } /** * Edits the given value compound and returns the new comound value. * Null is interpreted as a canceled edition. * * Sub classes have to implement this method to provide a dialog to the user to do * the value compund edition. * * @param parent the parent shell that implementors may use as parent window for any dialog * @param setting the setting begin edited (it is just given as information and should be edited directly) * @param compound the value compund to edit * * @return a string containing the new compund value or null */ abstract protected String editValueCompound( Shell parent, Setting setting, String compound ); /** * Adds a new value compound. */ private void addValueCompound() { // Pre-condition assert listViewer != null; assert valueCompounds != null; // Edits a new value. String newCompound = editValueCompound( listViewer.getControl().getShell(), getInput(), "new value" ); // Inserts the new compound if it has been validated. if( newCompound != null ) { valueCompounds.add( newCompound ); fireEditorChanged(); commit(); listViewer.refresh(); listViewer.setSelection( new StructuredSelection(new Integer(valueCompounds.size() -1)) ); } } /** * Edits the value compound that is selected in the list viewer. * * @return true when a compound has been modified, false otherwise */ private boolean editSelectedValueCompound() { // Pre-condition assert listViewer != null; assert valueCompounds != null; // Retrieves and handles the selection. IStructuredSelection selection = (IStructuredSelection) listViewer.getSelection(); String original = (String) selection.getFirstElement(); String edited = editValueCompound( listViewer.getControl().getShell(), getInput(), original ); // Processes the edited compound. if( edited != null ) { // Updates the setting. valueCompounds.set( valueCompounds.indexOf(original), edited ); fireEditorChanged(); // Commit changes and erstores the selection. listViewer.getControl().setRedraw( false ); commit(); listViewer.refresh(); listViewer.setSelection( new StructuredSelection(edited) ); listViewer.getControl().setRedraw( true ); // Job's done. return true; } else { return false; } } /** * Moves the value compounds corresponding to the current selection up. */ private void moveValueCompoundsUp() { // Pre-condition assert listViewer != null; assert valueCompounds != null; // Retrieves the current selection and skip if it is empty. IStructuredSelection selection = (IStructuredSelection) listViewer.getSelection(); if( selection.isEmpty() == true ) { return; } // Retrieves the list of the selected items. @SuppressWarnings("unchecked") Vector<Object> selected = new Vector<Object>(selection.toList()); Iterator<String> i = valueCompounds.iterator(); while( i.hasNext() == true && selected.isEmpty() == false ) { Object current = i.next(); if( current.equals(selected.get(0)) ) { int index = valueCompounds.indexOf(current); if( index > 0 ) { Collections.swap(valueCompounds, index, index-1); } else { break; } selected.remove(0); } } fireEditorChanged(); // Commits changes and reselected moved objects. listViewer.getControl().setRedraw( false ); commit(); listViewer.refresh(); listViewer.getControl().setRedraw( true ); } /** * Moves the value compounds corresponding to the current selection down. */ private void moveValueCompoundsDown() { // Pre-condition assert listViewer != null; assert valueCompounds != null; // Retrieves the current selection and skip if it is empty. IStructuredSelection selection = (IStructuredSelection) listViewer.getSelection(); if( selection.isEmpty() == true ) { return; } // Retrieves the list of the selected items. @SuppressWarnings("unchecked") Vector<?> selected = new Vector<Object>(selection.toList()); Collections.reverse( selected ); Collections.reverse(valueCompounds); // Retrieves the list of the selected items. Iterator<String> i = valueCompounds.iterator(); while( i.hasNext() == true && selected.isEmpty() == false ) { Object current = i.next(); if( current.equals(selected.get(0)) ) { int index = valueCompounds.indexOf(current); if( index > 0 ) { Collections.swap(valueCompounds, index, index-1); } else { break; } selected.remove(0); } } Collections.reverse(valueCompounds); fireEditorChanged(); // Commits changes and reselected moved objects. listViewer.getControl().setRedraw( false ); commit(); listViewer.refresh(); listViewer.getControl().setRedraw( true ); } /** * Removes the selected value compounds. */ private void removeValueCompounds() { // Pre-condition assert listViewer != null; assert valueCompounds != null; // Retrieves the current selection and skip if it is empty. IStructuredSelection selection = (IStructuredSelection) listViewer.getSelection(); if( selection.isEmpty() == true ) { return; } // Removes selected items from the value compounds. valueCompounds.removeAll( selection.toList() ); fireEditorChanged(); // Commits changes. commit(); listViewer.refresh(); } /** * Updates the state of some buttons. */ private void updateButtons() { // Pre-condition assert listViewer != null; assert removeButton != null; assert upButton != null; assert downButton != null; // Retrieves the selection emptiness and updates the buttons. boolean willBeEnabled = listViewer.getSelection().isEmpty() == false; removeButton.setEnabled( willBeEnabled ); upButton.setEnabled( willBeEnabled ); downButton.setEnabled( willBeEnabled ); } }