/******************************************************************************* * Copyright 2013 Geoscience Australia * * 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 au.gov.ga.earthsci.discovery.ui.preferences; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ICheckStateProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; 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.Event; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import au.gov.ga.earthsci.common.ui.dialogs.StackTraceDialog; import au.gov.ga.earthsci.common.ui.preferences.PreferencePage; import au.gov.ga.earthsci.discovery.DiscoveryServiceManager; import au.gov.ga.earthsci.discovery.IDiscoveryService; import au.gov.ga.earthsci.discovery.IDiscoveryServiceProperty; import au.gov.ga.earthsci.discovery.ui.Activator; import au.gov.ga.earthsci.discovery.ui.ILayoutConstants; import au.gov.ga.earthsci.discovery.ui.Messages; /** * PreferencePage for editing discovery services. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class DiscoveryServicesPreferencePage extends PreferencePage { private Table table; private CheckboxTableViewer viewer; private DiscoveryServiceComparator comparator = new DiscoveryServiceComparator(); private final Set<IDiscoveryService> stagingSet = new HashSet<IDiscoveryService>(); private final Map<IDiscoveryService, Boolean> originalEnablement = new HashMap<IDiscoveryService, Boolean>(); private Button addButton; private Button editButton; private Button removeButton; private Button disableButton; private Button selectAllButton; private Button exportButton; public DiscoveryServicesPreferencePage() { noDefaultAndApplyButton(); setTitle(Messages.DiscoveryServicesPreferencePage_Title); setDescription(Messages.DiscoveryServicesPreferencePage_Description); } @Override protected Control createContents(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); composite.setLayoutData(gd); GridLayout layout = new GridLayout(); layout.numColumns = 2; layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); composite.setLayout(layout); table = new Table(composite, SWT.CHECK | SWT.MULTI | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); data.widthHint = convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_TABLE_WIDTH); data.heightHint = convertHeightInCharsToPixels(ILayoutConstants.DEFAULT_TABLE_HEIGHT); table.setLayoutData(data); viewer = new CheckboxTableViewer(table); // Key listener for delete table.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.keyCode == SWT.DEL) { removeSelected(); } } }); setTableColumns(); viewer.setComparator(comparator); viewer.setContentProvider(new ArrayContentProvider()); viewer.setLabelProvider(new DiscoveryServiceLabelProvider()); stagingSet.clear(); stagingSet.addAll(DiscoveryServiceManager.getServices()); viewer.setInput(stagingSet); viewer.setCellModifier(new ICellModifier() { @Override public boolean canModify(Object element, String property) { return element instanceof IDiscoveryService; } @Override public Object getValue(Object element, String property) { String name = ((IDiscoveryService) element).getName(); return name != null ? name : ""; //$NON-NLS-1$ } @Override public void modify(Object element, String prop, Object value) { if (value != null && value.toString().length() >= 0) { IDiscoveryService service; if (element instanceof Item) { service = (IDiscoveryService) ((Item) element).getData(); } else if (element instanceof IDiscoveryService) { service = (IDiscoveryService) element; } else { return; } if (!value.toString().equals(service.getName())) { Map<IDiscoveryServiceProperty<?>, Object> propertyValues = new HashMap<IDiscoveryServiceProperty<?>, Object>(); IDiscoveryServiceProperty<?>[] properties = service.getProvider().getProperties(); if (properties != null) { for (IDiscoveryServiceProperty<?> property : properties) { propertyValues.put(property, property.getValue(service)); } } IDiscoveryService replacement = service.getProvider().createService(value.toString(), service.getServiceURL(), propertyValues); replacement.setEnabled(service.isEnabled()); stagingSet.remove(service); stagingSet.add(replacement); viewer.refresh(); } } } }); viewer.setColumnProperties(new String[] { "name" }); //$NON-NLS-1$ viewer.setCellEditors(new CellEditor[] { new TextCellEditor(table) }); viewer.setCheckStateProvider(new ICheckStateProvider() { @Override public boolean isChecked(Object element) { return ((IDiscoveryService) element).isEnabled(); } @Override public boolean isGrayed(Object element) { return false; } }); viewer.addCheckStateListener(new ICheckStateListener() { @Override public void checkStateChanged(CheckStateChangedEvent event) { IDiscoveryService service = (IDiscoveryService) event.getElement(); if (!originalEnablement.containsKey(service)) { originalEnablement.put(service, service.isEnabled()); } service.setEnabled(event.getChecked()); viewer.refresh(); validateButtons(); } }); viewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { validateButtons(); } }); Composite verticalButtonBar = createVerticalButtonBar(composite); data = new GridData(SWT.FILL, SWT.FILL, false, false); data.verticalAlignment = SWT.TOP; data.verticalIndent = 0; verticalButtonBar.setLayoutData(data); validateButtons(); return composite; } private void setTableColumns() { table.setHeaderVisible(true); DiscoveryServiceViewerColumn[] columns = DiscoveryServiceViewerColumn.values(); for (int i = 0; i < columns.length; i++) { final DiscoveryServiceViewerColumn column = columns[i]; TableColumn tc = new TableColumn(table, SWT.NONE, i); tc.setResizable(true); tc.setText(column.getLabel()); if (column == DiscoveryServiceViewerColumn.ENABLED) { tc.setWidth(convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_SMALL_COLUMN_WIDTH)); tc.setAlignment(SWT.CENTER); } else if (column == DiscoveryServiceViewerColumn.URL) { tc.setWidth(convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_PRIMARY_COLUMN_WIDTH)); } else { tc.setWidth(convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_COLUMN_WIDTH)); } tc.addSelectionListener(new SelectionListener() { @Override public void widgetDefaultSelected(SelectionEvent e) { columnSelected((TableColumn) e.widget, column); } @Override public void widgetSelected(SelectionEvent e) { columnSelected((TableColumn) e.widget, column); } }); // First column only if (i == 0) { table.setSortColumn(tc); table.setSortDirection(SWT.UP); comparator.setColumn(column); } } } private void columnSelected(TableColumn tc, DiscoveryServiceViewerColumn column) { if (comparator.getColumn() == column) { comparator.setDescending(!comparator.isDescending()); table.setSortDirection(comparator.isDescending() ? SWT.DOWN : SWT.UP); } else { comparator.setColumn(column); comparator.setDescending(false); table.setSortColumn(tc); table.setSortDirection(SWT.UP); } viewer.refresh(); } private IDiscoveryService[] getSelected() { IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); List<IDiscoveryService> list = new ArrayList<IDiscoveryService>(); for (Object selected : selection.toList()) { if (selected instanceof IDiscoveryService) { list.add((IDiscoveryService) selected); } } return list.toArray(new IDiscoveryService[list.size()]); } private Composite createVerticalButtonBar(Composite parent) { // Create composite. Composite composite = new Composite(parent, SWT.NONE); initializeDialogUnits(composite); // create a layout with spacing and margins appropriate for the font // size. GridLayout layout = new GridLayout(); layout.numColumns = 1; layout.marginWidth = 5; layout.marginHeight = 0; layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); composite.setLayout(layout); createVerticalButtons(composite); return composite; } private void createVerticalButtons(Composite parent) { addButton = createVerticalButton(parent, Messages.DiscoveryServicesPreferencePage_AddButton, false); addButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { addService(); } }); editButton = createVerticalButton(parent, Messages.DiscoveryServicesPreferencePage_EditButton, false); editButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { editSelected(); } }); removeButton = createVerticalButton(parent, Messages.DiscoveryServicesPreferencePage_RemoveButton, false); removeButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { removeSelected(); } }); disableButton = createVerticalButton(parent, Messages.DiscoveryServicesPreferencePage_DisableButton, false); disableButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { toggleSelected(); } }); selectAllButton = createVerticalButton(parent, Messages.DiscoveryServicesPreferencePage_SelectAllButton, false); selectAllButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { selectAll(); } }); Button button = createVerticalButton(parent, Messages.DiscoveryServicesPreferencePage_ImportButton, false); button.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { importServices(); } }); exportButton = createVerticalButton(parent, Messages.DiscoveryServicesPreferencePage_ExportButton, false); exportButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { exportServices(); } }); } private Button createVerticalButton(Composite parent, String label, boolean defaultButton) { Button button = new Button(parent, SWT.PUSH); button.setText(label); GridData data = setVerticalButtonLayoutData(button); data.horizontalAlignment = GridData.FILL; button.setToolTipText(label); if (defaultButton) { Shell shell = parent.getShell(); if (shell != null) { shell.setDefaultButton(button); } } return button; } private GridData setVerticalButtonLayoutData(Button button) { GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL); int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH); Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); data.widthHint = Math.max(widthHint, minSize.x); button.setLayoutData(data); return data; } private void validateButtons() { IDiscoveryService[] selected = getSelected(); exportButton.setEnabled(selected.length > 0); removeButton.setEnabled(selected.length > 0); disableButton.setEnabled(selected.length > 0); selectAllButton.setEnabled(table.getItemCount() > 0); editButton.setEnabled(selected.length == 1); if (selected.length >= 1 && toggleMeansDisable(selected)) { disableButton.setText(Messages.DiscoveryServicesPreferencePage_Disable); } else { disableButton.setText(Messages.DiscoveryServicesPreferencePage_Enable); } } private boolean toggleMeansDisable(IDiscoveryService[] elements) { int count = 0; for (int i = 0; i < elements.length; i++) { if (elements[i].isEnabled()) { count++; } } return count * 2 >= elements.length; } private void addService() { EditDiscoveryServiceDialog dialog = new EditDiscoveryServiceDialog(getShell()); dialog.setTitle(Messages.DiscoveryServicesPreferencePage_AddDialogTitle); if (dialog.open() == Window.OK) { IDiscoveryService service = dialog.getService(); if (service != null) { service.setEnabled(true); stagingSet.add(service); viewer.refresh(); validateButtons(); } } } private void editSelected() { IDiscoveryService[] selected = getSelected(); if (selected.length != 1) { return; } IDiscoveryService oldService = selected[0]; EditDiscoveryServiceDialog dialog = new EditDiscoveryServiceDialog(getShell()); dialog.setTitle(Messages.DiscoveryServicesPreferencePage_EditDialogTitle); dialog.setService(oldService); if (dialog.open() == Window.OK) { IDiscoveryService newService = dialog.getService(); if (newService != null) { newService.setEnabled(oldService.isEnabled()); stagingSet.remove(oldService); stagingSet.add(newService); viewer.refresh(); viewer.setSelection(new StructuredSelection(newService)); validateButtons(); } } } private void removeSelected() { IDiscoveryService[] selected = getSelected(); for (IDiscoveryService s : selected) { stagingSet.remove(s); } viewer.refresh(); validateButtons(); } private void toggleSelected() { IDiscoveryService[] selected = getSelected(); boolean enabled = !toggleMeansDisable(selected); for (IDiscoveryService s : selected) { s.setEnabled(enabled); } viewer.refresh(); validateButtons(); } private void selectAll() { table.setSelection(0, table.getItemCount() - 1); validateButtons(); } private void importServices() { FileDialog dialog = new FileDialog(getShell(), SWT.OPEN); dialog.setFilterExtensions(new String[] { "*.xml", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$ String filename = dialog.open(); if (filename != null) { File file = new File(filename); try { List<IDiscoveryService> services = DiscoveryServiceManager.loadServices(file); stagingSet.addAll(services); } catch (Exception e) { IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e); StackTraceDialog.openError(getShell(), Messages.DiscoveryServicesPreferencePage_Error, Messages.DiscoveryServicesPreferencePage_ImportError, status); } viewer.refresh(); validateButtons(); } } private void exportServices() { FileDialog dialog = new FileDialog(getShell(), SWT.SAVE); dialog.setFilterExtensions(new String[] { "*.xml", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$ String filename = dialog.open(); if (filename != null) { File file = new File(filename); try { DiscoveryServiceManager.saveServices(stagingSet, file); } catch (Exception e) { IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e); StackTraceDialog.openError(getShell(), Messages.DiscoveryServicesPreferencePage_Error, Messages.DiscoveryServicesPreferencePage_ExportError, status); } } } @Override public boolean performOk() { //create a copy to prevent modification during iteration: Set<IDiscoveryService> services = new HashSet<IDiscoveryService>(DiscoveryServiceManager.getServices()); for (IDiscoveryService existingService : services) { if (!stagingSet.contains(existingService)) { DiscoveryServiceManager.removeService(existingService); } } for (IDiscoveryService newService : stagingSet) { if (!services.contains(newService)) { DiscoveryServiceManager.addService(newService); } } return super.performOk(); } @Override public boolean performCancel() { //revert enablement changes: for (Entry<IDiscoveryService, Boolean> entry : originalEnablement.entrySet()) { entry.getKey().setEnabled(entry.getValue()); } return super.performCancel(); } }