/******************************************************************************* * Copyright (c) 2007, 2011 Spring IDE Developers * 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: * Spring IDE Developers - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.webflow.ui.properties; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.ui.JavaElementLabelProvider; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; 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.dialogs.CheckedTreeSelectionDialog; import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; import org.eclipse.ui.model.WorkbenchContentProvider; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.views.navigator.ResourceSorter; import org.springframework.ide.eclipse.core.model.IModelElement; import org.springframework.ide.eclipse.ui.SpringUIUtils; import org.springframework.ide.eclipse.ui.viewers.JavaFileSuffixFilter; import org.springframework.ide.eclipse.webflow.core.internal.model.WebflowConfig; import org.springframework.ide.eclipse.webflow.core.internal.model.WebflowModelUtils; import org.springframework.ide.eclipse.webflow.core.model.IWebflowConfig; import org.springframework.ide.eclipse.webflow.core.model.IWebflowModelElement; import org.springframework.ide.eclipse.webflow.core.model.IWebflowProject; import org.springframework.ide.eclipse.webflow.ui.Activator; import org.springframework.ide.eclipse.webflow.ui.navigator.WebflowNavigatorLabelProvider; /** * @author Christian Dupuis * @author Leo Dos Santos * @since 2.0 */ @SuppressWarnings("deprecation") public class WebflowConfigTab { private static final int TABLE_WIDTH = 250; private static final String DESCRIPTION = "ConfigurationPropertyPage.tabConfigFiles.description"; private static final String ADD_BUTTON = "ConfigurationPropertyPage.tabConfigFiles.addButton"; private static final String REMOVE_BUTTON = "ConfigurationPropertyPage.tabConfigFiles.removeButton"; private static final String DIALOG_TITLE = "ConfigurationPropertyPage.tabConfigFiles.addConfigDialog.title"; private static final String DIALOG_MESSAGE = "ConfigurationPropertyPage.tabConfigFiles.addConfigDialog.message"; private static final String EDIT_BUTTON = "ConfigurationPropertyPage.tabConfigFiles.editButton"; private static final String SCAN_BUTTON = "ConfigurationPropertyPage.tabConfigFiles.scanButton"; private static final String SCAN_NOTE_LABEL = "ConfigurationPropertyPage.tabConfigFiles.scan.note.label"; private IAdaptable element; private Table configsTable; private TableViewer configsViewer; private Button addButton, removeButton, scanButton; private SelectionListener buttonListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { handleButtonPressed((Button) e.widget); } }; private boolean hasUserMadeChanges; private IWebflowProject project; private Set<IWebflowConfig> configFiles; private Map<IWebflowConfig, Set<IModelElement>> configFilesToBeansConfigs; private Map<IWebflowConfig, String> configFilesToNames; private IModelElement selectedElement; private Button editButton; public WebflowConfigTab(IWebflowProject project, IAdaptable element, IModelElement selectedModelElement) { this.project = project; this.element = element; this.configFiles = new LinkedHashSet<IWebflowConfig>(); this.configFilesToBeansConfigs = new HashMap<IWebflowConfig, Set<IModelElement>>(); this.configFilesToNames = new HashMap<IWebflowConfig, String>(); if (project.getConfigs() != null) { for (IWebflowConfig config : project.getConfigs()) { this.configFiles.add(config); this.configFilesToBeansConfigs.put(config, config.getBeansConfigs()); this.configFilesToNames.put(config, config.getName()); } } if (selectedModelElement != null) { for (IWebflowConfig config : configFiles) { if (config.getElementName().equals( selectedModelElement.getElementName())) { this.selectedElement = config; } } } } public boolean hasUserMadeChanges() { return hasUserMadeChanges; } public Control createControl(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); layout.marginHeight = 3; layout.marginWidth = 3; composite.setLayout(layout); composite.setLayoutData(new GridData(GridData.FILL_BOTH)); Label description = new Label(composite, SWT.WRAP); description.setText(Activator.getResourceString(DESCRIPTION)); description.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Composite tableAndButtons = new Composite(composite, SWT.NONE); tableAndButtons.setLayoutData(new GridData(GridData.FILL_BOTH)); layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; layout.numColumns = 2; tableAndButtons.setLayout(layout); // table and viewer for Spring bean configurations configsTable = new Table(tableAndButtons, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); GridData data = new GridData(GridData.FILL_BOTH); data.widthHint = TABLE_WIDTH; configsTable.setLayoutData(data); configsTable.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { handleTableSelectionChanged(); } }); configsViewer = new TableViewer(configsTable); configsViewer.setContentProvider(new ConfigFilesContentProvider( this.configFiles)); configsViewer.setLabelProvider(new WebflowNavigatorLabelProvider()); configsViewer.setInput(this.configFiles); // activate content provider configsViewer.setSorter(new ConfigFilesSorter()); configsViewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { handleDoubleClick(event); } }); if (this.selectedElement != null) { configsViewer.setSelection( new StructuredSelection(selectedElement), true); } // button area Composite buttonArea = new Composite(tableAndButtons, SWT.NONE); layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; buttonArea.setLayout(layout); buttonArea.setLayoutData(new GridData(GridData.FILL_VERTICAL)); addButton = SpringUIUtils.createButton(buttonArea, Activator.getResourceString(ADD_BUTTON), buttonListener, 0, true); editButton = SpringUIUtils.createButton(buttonArea, Activator.getResourceString(EDIT_BUTTON), buttonListener, 0, false); removeButton = SpringUIUtils.createButton(buttonArea, Activator.getResourceString(REMOVE_BUTTON), buttonListener, 0, false); scanButton = SpringUIUtils.createButton(buttonArea, Activator.getResourceString(SCAN_BUTTON), buttonListener, 0, true); handleTableSelectionChanged(); return composite; } private void handleDoubleClick(DoubleClickEvent event) { ISelection selection = event.getSelection(); if (selection instanceof IStructuredSelection) { Object elem = ((IStructuredSelection) selection).getFirstElement(); if (elem instanceof IWebflowConfig) { // Edit corresponding config handleEditButtonPressed(); } } } /** * The user has selected a different configuration in table. Update button * enablement. */ private void handleTableSelectionChanged() { IStructuredSelection selection = (IStructuredSelection) configsViewer .getSelection(); if (selection.isEmpty()) { removeButton.setEnabled(false); editButton.setEnabled(false); } else { removeButton.setEnabled(true); editButton.setEnabled(true); } } /** * One of the buttons has been pressed, act accordingly. * * @param button */ private void handleButtonPressed(Button button) { if (button == addButton) { handleAddButtonPressed(); } else if (button == removeButton) { handleRemoveButtonPressed(); } else if (button == editButton) { handleEditButtonPressed(); } else if (button == scanButton) { handleScanButtonPressed(); } handleTableSelectionChanged(); configsTable.setFocus(); } private void handleEditButtonPressed() { IStructuredSelection selection = (IStructuredSelection) configsViewer .getSelection(); if (!selection.isEmpty()) { IWebflowConfig file = (IWebflowConfig) selection.getFirstElement(); Set<IModelElement> configs = new HashSet<IModelElement>(); String name = file.getName(); List<String> names = new ArrayList<String>(); names.add(name); if (this.configFilesToBeansConfigs.containsKey(file)) { Set<IModelElement> oldConfigs = this.configFilesToBeansConfigs .get(file); configs.addAll(oldConfigs); } WebflowConfigDialog dialog = new WebflowConfigDialog(SpringUIUtils .getStandardDisplay().getActiveShell(), project.getProject(), configs, names, file.getResource()); if (dialog.open() == Dialog.OK) { this.configFilesToBeansConfigs.put(file, configs); this.configFilesToNames.put(file, names.get(0)); hasUserMadeChanges = true; } } this.configsViewer.refresh(); } /** * The user has pressed the add button. Opens the configuration selection * dialog and adds the selected configuration. */ private void handleAddButtonPressed() { ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog( SpringUIUtils.getStandardDisplay().getActiveShell(), new WorkbenchLabelProvider(), new WorkbenchContentProvider()); dialog.setTitle(Activator.getResourceString(DIALOG_TITLE)); dialog.setMessage(Activator.getResourceString(DIALOG_MESSAGE)); dialog.addFilter(new ConfigFileFilter(new String[] { "xml" })); dialog.setValidator(new FileSelectionValidator(true)); dialog.setInput(element); dialog.setSorter(new ResourceSorter(ResourceSorter.NAME)); if (dialog.open() == ElementTreeSelectionDialog.OK) { Object[] selection = dialog.getResult(); if (selection != null && selection.length > 0) { for (int i = 0; i < selection.length; i++) { IFile file = (IFile) selection[i]; IWebflowConfig config = new WebflowConfig(project); config.setResource(file); int j = file.getName().lastIndexOf('.'); if (j > 0) { config.setName(file.getName().substring(0, j)); } else { config.setName(file.getName()); } configFiles.add(config); } hasUserMadeChanges = true; configsViewer.refresh(); } } } /** * The user has pressed the remove button. Delete the selected * configuration. */ private void handleRemoveButtonPressed() { IStructuredSelection selection = (IStructuredSelection) configsViewer .getSelection(); if (!selection.isEmpty()) { Iterator elements = selection.iterator(); while (elements.hasNext()) { configFiles.remove((IWebflowConfig) elements.next()); } configsViewer.refresh(); hasUserMadeChanges = true; } } private void handleScanButtonPressed() { ScannedFilesContentProvider contentProvider = new ScannedFilesContentProvider( "xml"); CheckedTreeSelectionDialog dialog = new CheckedTreeSelectionDialog( SpringUIUtils.getStandardDisplay().getActiveShell(), new ScannedFilesLabelProvider(), contentProvider) { @Override protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super .createDialogArea(parent); Label note = new Label(composite, SWT.WRAP); note.setText(Activator.getResourceString(SCAN_NOTE_LABEL)); note.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); return composite; } }; dialog.setTitle(Activator.getResourceString(DIALOG_TITLE)); dialog.setMessage(Activator.getResourceString(DIALOG_MESSAGE)); dialog.addFilter(new ConfigFileFilter(new String[] { "xml" })); dialog.setValidator(new FileSelectionValidator(true)); dialog.setInput(element); dialog.setSorter(new ResourceSorter(ResourceSorter.NAME)); dialog.setInitialSelections(contentProvider.getElements(project .getProject())); if (dialog.open() == ElementTreeSelectionDialog.OK) { Object[] selection = dialog.getResult(); if (selection != null && selection.length > 0) { for (int i = 0; i < selection.length; i++) { IFile file = (IFile) selection[i]; IWebflowConfig config = new WebflowConfig(project); config.setResource(file); int j = file.getName().lastIndexOf('.'); if (j > 0) { config.setName(file.getName().substring(0, j)); } else { config.setName(file.getName()); } configFiles.add(config); } hasUserMadeChanges = true; configsViewer.refresh(); } } } private class ConfigFilesContentProvider implements IStructuredContentProvider { private Set<IWebflowConfig> files; public ConfigFilesContentProvider(Set<IWebflowConfig> files) { this.files = files; } public Object[] getElements(Object obj) { return files.toArray(); } public void inputChanged(Viewer arg0, Object arg1, Object arg2) { } public void dispose() { } } private class ConfigFilesSorter extends ViewerSorter { // Categories public static final int SUB_DIR = 0; public static final int ROOT_DIR = 1; public int category(Object element) { return (((IWebflowConfig) element).getResource().getName() .indexOf('/') == -1 ? ROOT_DIR : SUB_DIR); } } public Map<IWebflowConfig, Set<IModelElement>> getConfigFilesToBeansConfigs() { return configFilesToBeansConfigs; } public void setConfigFiles(Set<IWebflowConfig> configFiles) { this.configFiles = configFiles; } public Set<IWebflowConfig> getConfigFiles() { return configFiles; } public Map<IWebflowConfig, String> getConfigFilesToNames() { return this.configFilesToNames; } private static class ConfigFileFilter extends JavaFileSuffixFilter { public ConfigFileFilter(String[] allowedFileExtensions) { super(allowedFileExtensions); } @Override protected boolean selectFile(IFile element) { return !WebflowModelUtils.isWebflowConfig(element); } } private class ScannedFilesLabelProvider extends JavaElementLabelProvider { @Override public String getText(Object element) { if (element instanceof IFile) { return ((IFile) element).getProjectRelativePath().toString(); } return super.getText(element); } } private final class ScannedFilesContentProvider implements ITreeContentProvider { private Object[] scannedFiles = null; public ScannedFilesContentProvider(final String fileSuffixes) { final Set<IFile> files = new LinkedHashSet<IFile>(); IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { WebflowConfigLocator locator = new WebflowConfigLocator( fileSuffixes); files.addAll(locator.locateBeansConfigs( project.getProject(), monitor)); } }; try { IRunnableContext context = new ProgressMonitorDialog( SpringUIUtils.getStandardDisplay().getActiveShell()); context.run(true, true, runnable); } catch (InvocationTargetException e) { } catch (InterruptedException e) { } scannedFiles = files.toArray(); } public void dispose() { // TODO Auto-generated method stub } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // TODO Auto-generated method stub } public Object[] getElements(Object inputElement) { return scannedFiles; } public Object[] getChildren(Object parentElement) { return IWebflowModelElement.NO_CHILDREN; } public Object getParent(Object element) { return null; } public boolean hasChildren(Object element) { return false; } } }