| /* |
| * Copyright (c) 2015 Ed Merks (Berlin, Germany) and others. |
| * 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: |
| * Ed Merks - initial API and implementation |
| */ |
| package org.eclipse.oomph.setup.presentation; |
| |
| import org.eclipse.oomph.internal.ui.UIPlugin; |
| import org.eclipse.oomph.preferences.PreferenceNode; |
| import org.eclipse.oomph.preferences.PreferencesFactory; |
| import org.eclipse.oomph.preferences.Property; |
| import org.eclipse.oomph.preferences.util.PreferencesUtil; |
| import org.eclipse.oomph.setup.CompoundTask; |
| import org.eclipse.oomph.setup.PreferenceTask; |
| import org.eclipse.oomph.setup.SetupTask; |
| import org.eclipse.oomph.setup.ui.recorder.RecorderTransaction; |
| import org.eclipse.oomph.util.IORuntimeException; |
| import org.eclipse.oomph.util.PropertiesUtil; |
| |
| import org.eclipse.emf.common.notify.AdapterFactory; |
| import org.eclipse.emf.common.util.AbstractTreeIterator; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.edit.provider.ItemProvider; |
| import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider; |
| import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; |
| |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.viewers.DoubleClickEvent; |
| import org.eclipse.jface.viewers.IDoubleClickListener; |
| import org.eclipse.jface.viewers.ILabelProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| 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.Display; |
| import org.eclipse.swt.widgets.FileDialog; |
| import org.eclipse.swt.widgets.Group; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.swt.widgets.Tree; |
| import org.eclipse.ui.dialogs.FilteredTree; |
| import org.eclipse.ui.dialogs.PatternFilter; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| 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; |
| |
| /** |
| * @author Ed Merks |
| */ |
| public class PreferenceCaptureDialog extends Dialog |
| { |
| private static final URI INSTANCE_URI = URI.createURI("//" + PreferencesUtil.INSTANCE_NODE); |
| |
| protected ILabelProvider labelProvider; |
| |
| protected FilteringAdapterFactoryContentProvider availablePreferencesContentProvider; |
| |
| protected FilteringAdapterFactoryContentProvider selectedPreferencesContentProvider; |
| |
| protected Set<Object> included = new HashSet<Object>(); |
| |
| protected boolean fromEclipsePreferenceFile; |
| |
| /** |
| * @since 2.6 |
| */ |
| public PreferenceCaptureDialog(Shell parent, AdapterFactory adapterFactory, boolean fromEclipsePreferenceFile) |
| { |
| super(parent); |
| |
| setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX); |
| |
| this.fromEclipsePreferenceFile = fromEclipsePreferenceFile; |
| |
| labelProvider = new AdapterFactoryLabelProvider(adapterFactory); |
| availablePreferencesContentProvider = new FilteringAdapterFactoryContentProvider(adapterFactory, false); |
| selectedPreferencesContentProvider = new FilteringAdapterFactoryContentProvider(adapterFactory, true); |
| } |
| |
| @Override |
| protected void configureShell(Shell shell) |
| { |
| super.configureShell(shell); |
| shell.setText(fromEclipsePreferenceFile ? "Import Preferences" : "Capture Preferences"); |
| shell.setImage(SetupEditorPlugin.INSTANCE.getSWTImage(fromEclipsePreferenceFile ? "preference_importer" : "preference_picker")); |
| } |
| |
| protected List<?> getAvailablePreferences() |
| { |
| PreferenceNode rootPreferenceNode = PreferencesUtil.getRootPreferenceNode(Collections.unmodifiableSet(new LinkedHashSet<String>( |
| Arrays.asList(new String[] { PreferencesUtil.BUNDLE_DEFAULTS_NODE, PreferencesUtil.DEFAULT_NODE, PreferencesUtil.INSTANCE_NODE }))), false); |
| |
| Map<URI, String> preferences = new HashMap<URI, String>(); |
| for (PreferenceNode preferenceNode : rootPreferenceNode.getChildren()) |
| { |
| traverse(preferences, preferenceNode); |
| } |
| |
| return RecorderTransaction.record(preferences); |
| } |
| |
| protected void traverse(Map<URI, String> preferences, PreferenceNode preferenceNode) |
| { |
| for (PreferenceNode childPreferenceNode : preferenceNode.getChildren()) |
| { |
| traverse(preferences, childPreferenceNode); |
| } |
| |
| for (Property property : preferenceNode.getProperties()) |
| { |
| preferences.put(INSTANCE_URI.appendSegments(property.getRelativePath().segments()), property.getValue()); |
| } |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) |
| { |
| final ItemProvider input = new ItemProvider(); |
| |
| Composite contents = (Composite)super.createDialogArea(parent); |
| |
| GridLayout contentsGridLayout = (GridLayout)contents.getLayout(); |
| contentsGridLayout.numColumns = 3; |
| |
| GridData contentsGridData = (GridData)contents.getLayoutData(); |
| contentsGridData.horizontalAlignment = SWT.FILL; |
| contentsGridData.verticalAlignment = SWT.FILL; |
| |
| Text preferenceFileText = null; |
| |
| if (fromEclipsePreferenceFile) |
| { |
| Group preferenceFileGroup = new Group(contents, SWT.NONE); |
| preferenceFileGroup.setText("Eclipse Preference File"); |
| preferenceFileGroup.setLayout(new GridLayout(2, false)); |
| preferenceFileGroup.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false, 3, 1)); |
| |
| final Text finalPreferenceFileText = preferenceFileText = new Text(preferenceFileGroup, SWT.BORDER); |
| preferenceFileText.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false, 1, 1)); |
| |
| Button preferenceFileBrowseButton = new Button(preferenceFileGroup, SWT.PUSH); |
| preferenceFileBrowseButton.setText("Browse..."); |
| preferenceFileBrowseButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| FileDialog dialog = new FileDialog(getShell(), SWT.OPEN | SWT.MULTI); |
| dialog.setFilterExtensions(new String[] { "*.epf" }); |
| String result = dialog.open(); |
| finalPreferenceFileText.setText(result); |
| } |
| }); |
| } |
| |
| Group filterGroupComposite = new Group(contents, SWT.NONE); |
| filterGroupComposite.setText("Filter Available Preferences"); |
| filterGroupComposite.setLayout(new GridLayout(1, false)); |
| filterGroupComposite.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false, 3, 1)); |
| |
| Composite availablePreferencesComposite = new Composite(contents, SWT.NONE); |
| { |
| GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); |
| data.horizontalAlignment = SWT.END; |
| availablePreferencesComposite.setLayoutData(data); |
| |
| GridLayout layout = new GridLayout(); |
| data.horizontalAlignment = SWT.FILL; |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| layout.numColumns = 1; |
| availablePreferencesComposite.setLayout(layout); |
| } |
| |
| Label availablePreferencesLabel = new Label(availablePreferencesComposite, SWT.NONE); |
| availablePreferencesLabel.setText("Available Preferences"); |
| GridData availablePreferencesLabelGridData = new GridData(); |
| availablePreferencesLabelGridData.verticalAlignment = SWT.FILL; |
| availablePreferencesLabelGridData.horizontalAlignment = SWT.FILL; |
| availablePreferencesLabel.setLayoutData(availablePreferencesLabelGridData); |
| |
| PatternFilter filter = new PatternFilter(); |
| filter.setIncludeLeadingWildcard(true); |
| final FilteredTree availablePreferencesTree = new FilteredTree(availablePreferencesComposite, SWT.MULTI | SWT.BORDER, filter, true); |
| GridData availablePreferencesTreeGridData = new GridData(); |
| availablePreferencesTreeGridData.widthHint = Display.getCurrent().getBounds().width / 5; |
| availablePreferencesTreeGridData.heightHint = Display.getCurrent().getBounds().height / 3; |
| availablePreferencesTreeGridData.verticalAlignment = SWT.FILL; |
| availablePreferencesTreeGridData.horizontalAlignment = SWT.FILL; |
| availablePreferencesTreeGridData.grabExcessHorizontalSpace = true; |
| availablePreferencesTreeGridData.grabExcessVerticalSpace = true; |
| availablePreferencesTree.setLayoutData(availablePreferencesTreeGridData); |
| |
| Control filterControl = availablePreferencesTree.getChildren()[0]; |
| filterControl.setParent(filterGroupComposite); |
| filterControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| |
| final TreeViewer availablePreferencesTreeViewer = availablePreferencesTree.getViewer(); |
| availablePreferencesTreeViewer.setContentProvider(availablePreferencesContentProvider); |
| availablePreferencesTreeViewer.setLabelProvider(labelProvider); |
| if (!fromEclipsePreferenceFile) |
| { |
| input.getChildren().addAll(getAvailablePreferences()); |
| } |
| |
| availablePreferencesTreeViewer.setInput(input); |
| |
| Composite controlButtons = new Composite(contents, SWT.NONE); |
| GridData controlButtonsGridData = new GridData(); |
| controlButtonsGridData.verticalAlignment = SWT.FILL; |
| controlButtonsGridData.horizontalAlignment = SWT.FILL; |
| controlButtons.setLayoutData(controlButtonsGridData); |
| |
| GridLayout controlsButtonGridLayout = new GridLayout(); |
| controlButtons.setLayout(controlsButtonGridLayout); |
| |
| new Label(controlButtons, SWT.NONE); |
| |
| final Button addButton = new Button(controlButtons, SWT.PUSH); |
| addButton.setText("Add"); |
| GridData addButtonGridData = new GridData(); |
| addButtonGridData.verticalAlignment = SWT.FILL; |
| addButtonGridData.horizontalAlignment = SWT.FILL; |
| addButton.setLayoutData(addButtonGridData); |
| |
| final Button removeButton = new Button(controlButtons, SWT.PUSH); |
| removeButton.setText("Remove"); |
| GridData removeButtonGridData = new GridData(); |
| removeButtonGridData.verticalAlignment = SWT.FILL; |
| removeButtonGridData.horizontalAlignment = SWT.FILL; |
| removeButton.setLayoutData(removeButtonGridData); |
| |
| Label spaceLabel = new Label(controlButtons, SWT.NONE); |
| GridData spaceLabelGridData = new GridData(); |
| spaceLabelGridData.verticalSpan = 2; |
| spaceLabel.setLayoutData(spaceLabelGridData); |
| |
| Composite selectedPreferencesComposite = new Composite(contents, SWT.NONE); |
| { |
| GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); |
| data.horizontalAlignment = SWT.END; |
| selectedPreferencesComposite.setLayoutData(data); |
| |
| GridLayout layout = new GridLayout(); |
| data.horizontalAlignment = SWT.FILL; |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| layout.numColumns = 1; |
| selectedPreferencesComposite.setLayout(layout); |
| } |
| |
| Label selectedPreferencesLabel = new Label(selectedPreferencesComposite, SWT.NONE); |
| selectedPreferencesLabel.setText("Selected Preferences"); |
| GridData selectedPreferencesLabelGridData = new GridData(); |
| selectedPreferencesLabelGridData.horizontalSpan = 2; |
| selectedPreferencesLabelGridData.horizontalAlignment = SWT.FILL; |
| selectedPreferencesLabelGridData.verticalAlignment = SWT.FILL; |
| selectedPreferencesLabel.setLayoutData(selectedPreferencesLabelGridData); |
| |
| final Tree selectedPreferencesTree = new Tree(selectedPreferencesComposite, SWT.MULTI | SWT.BORDER); |
| GridData selectedPreferencesTreeGridData = new GridData(); |
| selectedPreferencesTreeGridData.widthHint = Display.getCurrent().getBounds().width / 5; |
| selectedPreferencesTreeGridData.heightHint = Display.getCurrent().getBounds().height / 3; |
| selectedPreferencesTreeGridData.verticalAlignment = SWT.FILL; |
| selectedPreferencesTreeGridData.horizontalAlignment = SWT.FILL; |
| selectedPreferencesTreeGridData.grabExcessHorizontalSpace = true; |
| selectedPreferencesTreeGridData.grabExcessVerticalSpace = true; |
| selectedPreferencesTree.setLayoutData(selectedPreferencesTreeGridData); |
| |
| final TreeViewer selectedPreferencesTreeViewer = new TreeViewer(selectedPreferencesTree); |
| selectedPreferencesTreeViewer.setContentProvider(selectedPreferencesContentProvider); |
| selectedPreferencesTreeViewer.setLabelProvider(labelProvider); |
| selectedPreferencesTreeViewer.setInput(input); |
| |
| availablePreferencesTreeViewer.addDoubleClickListener(new IDoubleClickListener() |
| { |
| public void doubleClick(DoubleClickEvent event) |
| { |
| if (addButton.isEnabled()) |
| { |
| addButton.notifyListeners(SWT.Selection, null); |
| } |
| } |
| }); |
| |
| selectedPreferencesTreeViewer.addDoubleClickListener(new IDoubleClickListener() |
| { |
| public void doubleClick(DoubleClickEvent event) |
| { |
| if (removeButton.isEnabled()) |
| { |
| removeButton.notifyListeners(SWT.Selection, null); |
| } |
| } |
| }); |
| |
| addButton.addSelectionListener(new FilteringSelectionAdapter(selectedPreferencesTreeViewer, availablePreferencesTreeViewer, input, true)); |
| removeButton.addSelectionListener(new FilteringSelectionAdapter(selectedPreferencesTreeViewer, availablePreferencesTreeViewer, input, false)); |
| |
| if (preferenceFileText != null) |
| { |
| preferenceFileText.addModifyListener(new ModifyListener() |
| { |
| public void modifyText(ModifyEvent e) |
| { |
| included.clear(); |
| EList<Object> children = input.getChildren(); |
| children.clear(); |
| |
| try |
| { |
| Map<URI, String> preferences = new HashMap<URI, String>(); |
| Map<String, String> loadProperties = PropertiesUtil.loadProperties(new File(((Text)e.widget).getText())); |
| for (Map.Entry<String, String> entry : loadProperties.entrySet()) |
| { |
| String key = entry.getKey(); |
| if (key.startsWith("/")) |
| { |
| preferences.put(PreferencesFactory.eINSTANCE.createURI(key), entry.getValue()); |
| } |
| } |
| |
| List<SetupTask> availablePreferences = RecorderTransaction.record(preferences); |
| children.addAll(availablePreferences); |
| } |
| catch (IORuntimeException ex) |
| { |
| children.add(new ItemProvider(ex.getMessage(), UIPlugin.INSTANCE.getImage("error"))); |
| } |
| |
| availablePreferencesTreeViewer.refresh(); |
| selectedPreferencesTreeViewer.refresh(); |
| } |
| }); |
| } |
| |
| return contents; |
| } |
| |
| @Override |
| public boolean close() |
| { |
| availablePreferencesContentProvider.dispose(); |
| selectedPreferencesContentProvider.dispose(); |
| return super.close(); |
| } |
| |
| public Map<URI, String> getResult() |
| { |
| Map<URI, String> result = new HashMap<URI, String>(); |
| for (Object object : included) |
| { |
| PreferenceTask preferenceTask = (PreferenceTask)object; |
| result.put(PreferencesFactory.eINSTANCE.createURI(preferenceTask.getKey()), preferenceTask.getValue()); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @author Ed Merks |
| */ |
| private class FilteringSelectionAdapter extends SelectionAdapter |
| { |
| private final TreeViewer selectedPreferencesTreeViewer; |
| |
| private final TreeViewer availablePreferencesTreeViewer; |
| |
| private final ItemProvider input; |
| |
| private boolean add; |
| |
| private FilteringSelectionAdapter(TreeViewer selectedPreferencesTreeViewer, TreeViewer availablePreferencesTreeViewer, ItemProvider input, boolean add) |
| { |
| this.selectedPreferencesTreeViewer = selectedPreferencesTreeViewer; |
| this.availablePreferencesTreeViewer = availablePreferencesTreeViewer; |
| this.input = input; |
| this.add = add; |
| } |
| |
| @Override |
| public void widgetSelected(SelectionEvent event) |
| { |
| IStructuredSelection selection = (IStructuredSelection)(add ? availablePreferencesTreeViewer : selectedPreferencesTreeViewer).getSelection(); |
| List<Object> newSelection = new ArrayList<Object>(); |
| |
| for (Object object : selection.toArray()) |
| { |
| Object[] children = (add ? availablePreferencesContentProvider : selectedPreferencesContentProvider).getChildren(object); |
| if (children.length != 0) |
| { |
| List<Object> choices = Arrays.asList(children); |
| newSelection.addAll(choices); |
| } |
| else |
| { |
| newSelection.add(object); |
| } |
| } |
| |
| Set<Object> nonCandidates = new HashSet<Object>(newSelection); |
| Object candidate = null; |
| Object bestCandidate = null; |
| |
| for (TreeIterator<Object> it = (add ? availablePreferencesContentProvider : selectedPreferencesContentProvider).getAllContents(input, false); it |
| .hasNext();) |
| { |
| candidate = it.next(); |
| if (nonCandidates.remove(candidate)) |
| { |
| if (!(bestCandidate instanceof PreferenceTask)) |
| { |
| bestCandidate = null; |
| } |
| } |
| else |
| { |
| if (!(candidate instanceof CompoundTask)) |
| { |
| bestCandidate = candidate; |
| } |
| |
| if (nonCandidates.isEmpty()) |
| { |
| break; |
| } |
| } |
| } |
| |
| if (add) |
| { |
| included.addAll(newSelection); |
| } |
| else |
| { |
| included.removeAll(newSelection); |
| } |
| |
| for (Object object : input.getChildren()) |
| { |
| if (object instanceof CompoundTask) |
| { |
| CompoundTask compoundTask = (CompoundTask)object; |
| EList<SetupTask> setupTasks = compoundTask.getSetupTasks(); |
| if (newSelection.containsAll(setupTasks)) |
| { |
| newSelection.removeAll(setupTasks); |
| newSelection.add(compoundTask); |
| } |
| } |
| } |
| |
| selectedPreferencesTreeViewer.refresh(); |
| availablePreferencesTreeViewer.refresh(); |
| |
| (add ? selectedPreferencesTreeViewer : availablePreferencesTreeViewer).setSelection(new StructuredSelection(newSelection)); |
| |
| if (bestCandidate == null && candidate != null) |
| { |
| bestCandidate = candidate; |
| } |
| |
| if (bestCandidate != null) |
| { |
| (add ? availablePreferencesTreeViewer : selectedPreferencesTreeViewer).setSelection(new StructuredSelection(bestCandidate)); |
| } |
| } |
| } |
| |
| /** |
| * @author Ed Merks |
| */ |
| private final class FilteringAdapterFactoryContentProvider extends AdapterFactoryContentProvider |
| { |
| private boolean include; |
| |
| private FilteringAdapterFactoryContentProvider(AdapterFactory adapterFactory, boolean include) |
| { |
| super(adapterFactory); |
| this.include = include; |
| } |
| |
| public TreeIterator<Object> getAllContents(Object object, boolean includeRoot) |
| { |
| return new AbstractTreeIterator<Object>(object, includeRoot) |
| { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected Iterator<? extends Object> getChildren(Object object) |
| { |
| return Arrays.asList(object instanceof ItemProvider ? FilteringAdapterFactoryContentProvider.this.getElements(object) |
| : FilteringAdapterFactoryContentProvider.this.getChildren(object)).iterator(); |
| } |
| }; |
| } |
| |
| @Override |
| public Object[] getElements(Object object) |
| { |
| List<Object> elements = ((ItemProvider)object).getChildren(); |
| List<Object> result = new ArrayList<Object>(); |
| |
| for (Object element : elements) |
| { |
| if (include) |
| { |
| for (Object child : getChildren(element)) |
| { |
| if (included.contains(child)) |
| { |
| result.add(element); |
| break; |
| } |
| } |
| } |
| else if (element instanceof ItemProvider) |
| { |
| result.add(element); |
| } |
| else if (!included.containsAll(Arrays.asList(getChildren(element)))) |
| { |
| result.add(element); |
| } |
| } |
| |
| return result.toArray(); |
| } |
| |
| @Override |
| public Object[] getChildren(Object object) |
| { |
| Object[] children = super.getChildren(object); |
| List<Object> result = new ArrayList<Object>(); |
| |
| for (Object child : children) |
| { |
| if (included.contains(child) == include) |
| { |
| result.add(child); |
| } |
| } |
| |
| return result.toArray(); |
| } |
| } |
| } |