| /******************************************************************************* |
| * Copyright (c) 2010, 2017 BestSolution.at 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: |
| * Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation |
| * Andrej ten Brummelhuis <andrejbrummelhuis@gmail.com> - Bug 395283 |
| * Patrik Suzzi <psuzzi@gmail.com> - Bug 467262 |
| ******************************************************************************/ |
| package org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs; |
| |
| import java.text.BreakIterator; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.e4.tools.emf.ui.common.Util; |
| import org.eclipse.e4.tools.emf.ui.common.Util.InternalClass; |
| import org.eclipse.e4.tools.emf.ui.common.Util.InternalFeature; |
| import org.eclipse.e4.tools.emf.ui.common.Util.InternalPackage; |
| import org.eclipse.e4.tools.emf.ui.internal.Messages; |
| import org.eclipse.e4.tools.emf.ui.internal.StringMatcher; |
| import org.eclipse.e4.ui.model.fragment.MStringModelFragment; |
| import org.eclipse.e4.ui.model.fragment.impl.FragmentPackageImpl; |
| import org.eclipse.e4.ui.model.internal.ModelUtils; |
| import org.eclipse.emf.common.command.Command; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.edit.command.SetCommand; |
| import org.eclipse.emf.edit.domain.EditingDomain; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.viewers.ILabelProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.ITreeContentProvider; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.StructuredViewer; |
| import org.eclipse.jface.viewers.StyledCellLabelProvider; |
| import org.eclipse.jface.viewers.StyledString; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.viewers.ViewerCell; |
| import org.eclipse.jface.viewers.ViewerComparator; |
| import org.eclipse.jface.viewers.ViewerFilter; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Image; |
| 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.Shell; |
| import org.eclipse.swt.widgets.Text; |
| |
| public class FeatureSelectionDialog extends SaveDialogBoundsSettingsDialog { |
| private TreeViewer viewer; |
| private final MStringModelFragment fragment; |
| private final EditingDomain editingDomain; |
| private final Messages Messages; |
| private ViewerFilterImpl filter; |
| private final EClass userSelectedContainer; |
| |
| public FeatureSelectionDialog(Shell parentShell, EditingDomain editingDomain, MStringModelFragment fragment, |
| Messages Messages, EClass userSelectedContainer) { |
| super(parentShell); |
| this.fragment = fragment; |
| this.editingDomain = editingDomain; |
| this.Messages = Messages; |
| this.userSelectedContainer = userSelectedContainer; |
| } |
| |
| @Override |
| protected boolean isResizable() { |
| return true; |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| getShell().setText(Messages.FeatureSelectionDialog_ShellTitle); |
| setTitle(Messages.FeatureSelectionDialog_DialogTitle); |
| setMessage(Messages.FeatureSelectionDialog_DialogMessage); |
| |
| final Composite composite = (Composite) super.createDialogArea(parent); |
| |
| final Image packageImage = new Image(getShell().getDisplay(), getClass().getClassLoader().getResourceAsStream( |
| "/icons/full/obj16/EPackage.gif")); //$NON-NLS-1$ |
| final Image classImage = new Image(getShell().getDisplay(), getClass().getClassLoader().getResourceAsStream( |
| "/icons/full/obj16/class_obj.png")); //$NON-NLS-1$ |
| final Image featureImage = new Image(getShell().getDisplay(), getClass().getClassLoader().getResourceAsStream( |
| "/icons/full/obj16/field_public_obj.gif")); //$NON-NLS-1$ |
| final Image newTitleImage = new Image(getShell().getDisplay(), getClass().getClassLoader().getResourceAsStream( |
| "/icons/full/wizban/fieldrefact_wiz.png")); //$NON-NLS-1$ |
| |
| setTitleImage(newTitleImage); |
| |
| composite.addDisposeListener(e -> { |
| packageImage.dispose(); |
| classImage.dispose(); |
| featureImage.dispose(); |
| newTitleImage.dispose(); |
| }); |
| |
| final Composite container = new Composite(composite, SWT.NONE); |
| container.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| container.setLayout(new GridLayout(2, false)); |
| |
| final Label l = new Label(container, SWT.NONE); |
| l.setText(Messages.FeatureSelectionDialog_Filter); |
| |
| final Text searchText = new Text(container, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH); |
| searchText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| |
| searchText.addModifyListener(e -> { |
| if (filter != null) { |
| filter.setPattern(searchText.getText()); |
| if (viewer != null) { |
| viewer.refresh(); |
| if (searchText.getText().length() > 0) { |
| viewer.expandAll(); |
| } else { |
| viewer.collapseAll(); |
| } |
| } |
| } |
| }); |
| new Label(container, SWT.NONE); |
| viewer = new TreeViewer(container); |
| final GridData gd = new GridData(GridData.FILL_BOTH); |
| gd.heightHint = 200; |
| viewer.getControl().setLayoutData(gd); |
| viewer.setContentProvider(new ContentProviderImpl()); |
| viewer.setLabelProvider(new LabelProviderImpl(packageImage, classImage, featureImage)); |
| viewer.addDoubleClickListener(event -> okPressed()); |
| viewer.setComparator(new ViewerComparator() { |
| @Override |
| public int compare(Viewer viewer, Object e1, Object e2) { |
| if (e1.getClass() == InternalPackage.class) { |
| return ((InternalPackage) e1).ePackage.getNsURI().compareTo( |
| ((InternalPackage) e2).ePackage.getNsURI()); |
| } else if (e1.getClass() == InternalClass.class) { |
| return ((InternalClass) e1).eClass.getName().compareTo(((InternalClass) e2).eClass.getName()); |
| } else if (e1.getClass() == InternalFeature.class) { |
| return ((InternalFeature) e1).feature.getName().compareTo(((InternalFeature) e2).feature.getName()); |
| } |
| return super.compare(viewer, e1, e2); |
| } |
| }); |
| viewer.addSelectionChangedListener(event -> { |
| final IStructuredSelection selection = (IStructuredSelection) event.getSelection(); |
| final Button buttonOk = getButton(IDialogConstants.OK_ID); |
| if (!selection.isEmpty() && selection.getFirstElement().getClass() == InternalFeature.class) { |
| buttonOk.setEnabled(true); |
| } else { |
| buttonOk.setEnabled(false); |
| } |
| }); |
| |
| filter = new ViewerFilterImpl(); |
| |
| viewer.addFilter(filter); |
| |
| viewer.setInput(Util.loadPackages()); |
| |
| return composite; |
| } |
| |
| @Override |
| protected void createButtonsForButtonBar(Composite parent) { |
| super.createButtonsForButtonBar(parent); |
| // selection has influence on buttons |
| selectTreeElement(); |
| } |
| |
| /** selects a tree element if userselected container is not null */ |
| private void selectTreeElement() { |
| if (userSelectedContainer == null) { |
| return; |
| } |
| // loop through the children of parent element of tree viewer |
| for (final Object item : ((ITreeContentProvider) viewer.getContentProvider()).getElements(viewer.getInput())) { |
| // loop through the chidren of incoming parent element |
| final Object[] contents = ((ITreeContentProvider) viewer.getContentProvider()).getChildren(item); |
| for (final Object content : contents) { |
| if (content instanceof InternalClass) { |
| final EClass eClass = ((InternalClass) content).eClass; |
| // checks with my overrided equals method\ |
| if (eClass.equals(userSelectedContainer)) { |
| // expand the particular child |
| viewer.setSelection(new StructuredSelection(content)); |
| viewer.reveal(content); |
| viewer.expandToLevel(content, 1); |
| return; |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void okPressed() { |
| final IStructuredSelection sel = (IStructuredSelection) viewer.getSelection(); |
| if (!sel.isEmpty() && sel.getFirstElement().getClass() == InternalFeature.class) { |
| final InternalFeature f = (InternalFeature) sel.getFirstElement(); |
| final Command cmd = SetCommand.create(editingDomain, fragment, |
| FragmentPackageImpl.Literals.STRING_MODEL_FRAGMENT__FEATURENAME, f.feature.getName()); |
| |
| if (cmd.canExecute()) { |
| editingDomain.getCommandStack().execute(cmd); |
| super.okPressed(); |
| } |
| } |
| } |
| |
| static class ContentProviderImpl implements ITreeContentProvider { |
| |
| @Override |
| public void dispose() { |
| |
| } |
| |
| @Override |
| public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { |
| |
| } |
| |
| @Override |
| public Object[] getElements(Object inputElement) { |
| return ((List<?>) inputElement).toArray(); |
| } |
| |
| @Override |
| public Object[] getChildren(Object parentElement) { |
| if (parentElement.getClass() == InternalPackage.class) { |
| // Must keep only classes that are usable in a fragment... |
| ArrayList<InternalClass> result = new ArrayList<>(); |
| for (InternalClass ic : ((InternalPackage) parentElement).classes) { |
| if (Util.canBeExtendedInAFragment(ic.eClass)) { |
| result.add(ic); |
| } |
| } |
| return result.toArray(); |
| } else if (parentElement.getClass() == InternalClass.class) { |
| ArrayList<InternalFeature> result = new ArrayList<>(); |
| for (InternalFeature intf : ((InternalClass) parentElement).features) |
| { |
| if ((intf.feature instanceof EReference) && |
| Util.referenceIsModelFragmentCompliant((EReference)intf.feature)) |
| { |
| result.add(intf); |
| } |
| } |
| return result.toArray(); |
| } |
| return new Object[0]; |
| } |
| |
| @Override |
| public Object getParent(Object element) { |
| if (element.getClass() == InternalFeature.class) { |
| return ((InternalFeature) element).clazz; |
| } else if (element.getClass() == InternalClass.class) { |
| return ((InternalClass) element).pack; |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean hasChildren(Object element) { |
| return getChildren(element).length > 0; |
| } |
| |
| } |
| |
| static class LabelProviderImpl extends StyledCellLabelProvider implements ILabelProvider { |
| private final Image packageImage; |
| private final Image classImage; |
| private final Image featureImage; |
| |
| public LabelProviderImpl(Image packageImage, Image classImage, Image featureImage) { |
| this.packageImage = packageImage; |
| this.classImage = classImage; |
| this.featureImage = featureImage; |
| } |
| |
| @Override |
| public void update(final ViewerCell cell) { |
| if (cell.getElement().getClass() == InternalPackage.class) { |
| final InternalPackage o = (InternalPackage) cell.getElement(); |
| final StyledString styledString = new StyledString(o.ePackage.getName()); |
| styledString.append(" - " + o.ePackage.getNsURI(), StyledString.DECORATIONS_STYLER); //$NON-NLS-1$ |
| cell.setText(styledString.getString()); |
| cell.setStyleRanges(styledString.getStyleRanges()); |
| cell.setImage(packageImage); |
| } else if (cell.getElement().getClass() == InternalClass.class) { |
| final InternalClass o = (InternalClass) cell.getElement(); |
| cell.setText(o.eClass.getName()); |
| cell.setImage(classImage); |
| } else { |
| final InternalFeature o = (InternalFeature) cell.getElement(); |
| final StyledString styledString = new StyledString(o.feature.getName()); |
| |
| final EClassifier type = ModelUtils.getTypeArgument(o.clazz.eClass, o.feature.getEGenericType()); |
| if (o.feature.isMany()) { |
| styledString.append(" : List<" + type.getName() + ">", StyledString.DECORATIONS_STYLER); //$NON-NLS-1$ //$NON-NLS-2$ |
| } else { |
| styledString.append(" : " + type.getName(), StyledString.DECORATIONS_STYLER); //$NON-NLS-1$ |
| } |
| |
| cell.setText(styledString.getString()); |
| cell.setStyleRanges(styledString.getStyleRanges()); |
| cell.setImage(featureImage); |
| } |
| } |
| |
| @Override |
| public Image getImage(Object element) { |
| return null; |
| } |
| |
| @Override |
| public String getText(Object element) { |
| if (element.getClass() == InternalPackage.class) { |
| final InternalPackage o = (InternalPackage) element; |
| return o.ePackage.getName(); |
| } else if (element.getClass() == InternalClass.class) { |
| final InternalClass o = (InternalClass) element; |
| return o.eClass.getName(); |
| } else { |
| final InternalFeature o = (InternalFeature) element; |
| return o.feature.getName(); |
| } |
| } |
| } |
| |
| static class ViewerFilterImpl extends ViewerFilter { |
| private static final String WILDCARD = "*"; //$NON-NLS-1$ |
| private StringMatcher matcher; |
| |
| @Override |
| public boolean select(Viewer viewer, Object parentElement, Object element) { |
| final ILabelProvider pv = (ILabelProvider) ((StructuredViewer) viewer).getLabelProvider(); |
| |
| if (element.getClass() == InternalPackage.class) { |
| for (final InternalClass c : ((InternalPackage) element).classes) { |
| if (match(pv.getText(c))) { |
| return true; |
| } |
| for (final InternalFeature f : c.features) { |
| if (match(pv.getText(f))) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } else if (element.getClass() == InternalClass.class) { |
| if (match(pv.getText(element))) { |
| return true; |
| } |
| for (final InternalFeature f : ((InternalClass) element).features) { |
| if (match(pv.getText(f))) { |
| return true; |
| } |
| } |
| return false; |
| } else if (element.getClass() == InternalFeature.class) { |
| return match(pv.getText(element)); |
| } |
| return true; |
| } |
| |
| protected boolean wordMatches(String text) { |
| if (text == null) { |
| return false; |
| } |
| |
| // If the whole text matches we are all set |
| if (match(text)) { |
| return true; |
| } |
| |
| // Otherwise check if any of the words of the text matches |
| final String[] words = getWords(text); |
| for (int i = 0; i < words.length; i++) { |
| final String word = words[i]; |
| if (match(word)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Answers whether the given String matches the pattern. |
| * |
| * @param string |
| * the String to test |
| * |
| * @return whether the string matches the pattern |
| */ |
| private boolean match(String string) { |
| if (matcher == null) { |
| return true; |
| } |
| return matcher.match(string); |
| } |
| |
| /** |
| * The pattern string for which this filter should select elements in |
| * the viewer. |
| * |
| * @param patternString |
| */ |
| public void setPattern(String patternString) { |
| |
| if (patternString == null || patternString.length() == 0) { |
| matcher = null; |
| } else { |
| String pattern = patternString + WILDCARD; |
| if (!pattern.startsWith(WILDCARD)) { |
| pattern = WILDCARD + pattern; |
| } |
| matcher = new StringMatcher(pattern, true, false); |
| } |
| } |
| |
| /** |
| * Take the given filter text and break it down into words using a |
| * BreakIterator. |
| * |
| * @param text |
| * @return an array of words |
| */ |
| private String[] getWords(String text) { |
| final List<String> words = new ArrayList<>(); |
| // Break the text up into words, separating based on whitespace and |
| // common punctuation. |
| // Previously used String.split(..., "\\W"), where "\W" is a regular |
| // expression (see the Javadoc for class Pattern). |
| // Need to avoid both String.split and regular expressions, in order |
| // to |
| // compile against JCL Foundation (bug 80053). |
| // Also need to do this in an NL-sensitive way. The use of |
| // BreakIterator |
| // was suggested in bug 90579. |
| final BreakIterator iter = BreakIterator.getWordInstance(); |
| iter.setText(text); |
| int i = iter.first(); |
| while (i != java.text.BreakIterator.DONE && i < text.length()) { |
| int j = iter.following(i); |
| if (j == java.text.BreakIterator.DONE) { |
| j = text.length(); |
| } |
| // match the word |
| if (Character.isLetterOrDigit(text.charAt(i))) { |
| final String word = text.substring(i, j); |
| words.add(word); |
| } |
| i = j; |
| } |
| return words.toArray(new String[words.size()]); |
| } |
| } |
| } |