| /******************************************************************************* |
| * Copyright (c) 2010 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 |
| ******************************************************************************/ |
| package org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs; |
| |
| import java.text.BreakIterator; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map.Entry; |
| import org.eclipse.e4.tools.emf.ui.internal.Messages; |
| import org.eclipse.e4.tools.emf.ui.internal.StringMatcher; |
| import org.eclipse.e4.ui.model.application.impl.ApplicationPackageImpl; |
| 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.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.edit.command.SetCommand; |
| import org.eclipse.emf.edit.domain.EditingDomain; |
| import org.eclipse.jface.dialogs.TitleAreaDialog; |
| 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.ITreeContentProvider; |
| 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.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| 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; |
| |
| @SuppressWarnings("restriction") |
| public class FeatureSelectionDialog extends TitleAreaDialog { |
| private TreeViewer viewer; |
| private MStringModelFragment fragment; |
| private EditingDomain editingDomain; |
| |
| public FeatureSelectionDialog(Shell parentShell, EditingDomain editingDomain, MStringModelFragment fragment) { |
| super(parentShell); |
| this.fragment = fragment; |
| this.editingDomain = editingDomain; |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| getShell().setText(Messages.FeatureSelectionDialog_ShellTitle); |
| setTitle(Messages.FeatureSelectionDialog_DialogTitle); |
| setMessage(Messages.FeatureSelectionDialog_DialogMessage); |
| |
| |
| 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.gif")); //$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(new DisposeListener() { |
| |
| public void widgetDisposed(DisposeEvent e) { |
| packageImage.dispose(); |
| classImage.dispose(); |
| featureImage.dispose(); |
| newTitleImage.dispose(); |
| } |
| }); |
| |
| |
| Composite container = new Composite(composite, SWT.NONE); |
| container.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| container.setLayout(new GridLayout(2, false)); |
| |
| 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)); |
| |
| new Label(container, SWT.NONE); |
| viewer = new TreeViewer(container); |
| 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(new IDoubleClickListener() { |
| |
| public void doubleClick(DoubleClickEvent 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); |
| } |
| }); |
| |
| final ViewerFilterImpl filter = new ViewerFilterImpl(); |
| |
| viewer.addFilter(filter); |
| searchText.addModifyListener(new ModifyListener() { |
| public void modifyText(ModifyEvent e) { |
| filter.setPattern(searchText.getText()); |
| viewer.refresh(); |
| } |
| }); |
| |
| |
| viewer.setInput(loadPackages()); |
| |
| return composite; |
| } |
| |
| @Override |
| protected void okPressed() { |
| IStructuredSelection sel = (IStructuredSelection) viewer.getSelection(); |
| if( ! sel.isEmpty() && sel.getFirstElement().getClass() == InternalFeature.class ) { |
| InternalFeature f = (InternalFeature) sel.getFirstElement(); |
| Command cmd = SetCommand.create(editingDomain, fragment, FragmentPackageImpl.Literals.STRING_MODEL_FRAGMENT__FEATURENAME, f.feature.getName()); |
| |
| if( cmd.canExecute() ) { |
| editingDomain.getCommandStack().execute(cmd); |
| super.okPressed(); |
| } |
| } |
| } |
| |
| private static List<InternalPackage> loadPackages() { |
| List<InternalPackage> packs = new ArrayList<InternalPackage>(); |
| |
| for( Entry<String, Object> regEntry : EPackage.Registry.INSTANCE.entrySet() ) { |
| if( regEntry.getValue() instanceof EPackage ) { |
| EPackage ePackage = (EPackage) regEntry.getValue(); |
| InternalPackage iePackage = new InternalPackage(ePackage); |
| boolean found = false; |
| for( EClassifier cl : ePackage.getEClassifiers() ) { |
| if( cl instanceof EClass ) { |
| EClass eClass = (EClass) cl; |
| if( eClass.getEAllSuperTypes().contains(ApplicationPackageImpl.Literals.APPLICATION_ELEMENT) ) { |
| if( ! eClass.isInterface() && ! eClass.isAbstract() ) { |
| found = true; |
| InternalClass ieClass = new InternalClass(iePackage, eClass); |
| iePackage.classes.add(ieClass); |
| for( EReference f : eClass.getEAllReferences() ) { |
| ieClass.features.add(new InternalFeature(ieClass, f)); |
| } |
| } |
| } |
| } |
| } |
| if( found ) { |
| packs.add(iePackage); |
| } |
| } |
| } |
| |
| return packs; |
| } |
| |
| static class ContentProviderImpl implements ITreeContentProvider { |
| |
| public void dispose() { |
| |
| } |
| |
| public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { |
| |
| } |
| |
| public Object[] getElements(Object inputElement) { |
| return ((List<?>)inputElement).toArray(); |
| } |
| |
| public Object[] getChildren(Object parentElement) { |
| if( parentElement.getClass() == InternalPackage.class ) { |
| return ((InternalPackage)parentElement).classes.toArray(); |
| } else if( parentElement.getClass() == InternalClass.class ) { |
| return ((InternalClass)parentElement).features.toArray(); |
| } |
| return new Object[0]; |
| } |
| |
| 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; |
| } |
| |
| 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; |
| } |
| |
| public void update(final ViewerCell cell) { |
| if( cell.getElement().getClass() == InternalPackage.class ) { |
| InternalPackage o = (InternalPackage) cell.getElement(); |
| 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 ) { |
| InternalClass o = (InternalClass) cell.getElement(); |
| cell.setText(o.eClass.getName()); |
| cell.setImage(classImage); |
| } else { |
| InternalFeature o = (InternalFeature) cell.getElement(); |
| StyledString styledString = new StyledString(o.feature.getName()); |
| |
| 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); |
| } |
| } |
| |
| public Image getImage(Object element) { |
| return null; |
| } |
| |
| public String getText(Object element) { |
| if( element.getClass() == InternalPackage.class ) { |
| InternalPackage o = (InternalPackage) element; |
| return o.ePackage.getName(); |
| } else if( element.getClass() == InternalClass.class ) { |
| InternalClass o = (InternalClass) element; |
| return o.eClass.getName(); |
| } else { |
| InternalFeature o = (InternalFeature) element; |
| return o.feature.getName(); |
| } |
| } |
| } |
| |
| static class ViewerFilterImpl extends ViewerFilter { |
| private StringMatcher matcher; |
| |
| @Override |
| public boolean select(Viewer viewer, Object parentElement, Object element) { |
| |
| if( element.getClass() == InternalPackage.class ) { |
| ILabelProvider pv = (ILabelProvider) ((StructuredViewer)viewer).getLabelProvider(); |
| for( InternalClass c : ((InternalPackage)element).classes ) { |
| if( match(pv.getText(c)) ) { |
| return true; |
| } |
| } |
| return false; |
| } else if( element.getClass() == InternalPackage.class ) { |
| ILabelProvider pv = (ILabelProvider) ((StructuredViewer)viewer).getLabelProvider(); |
| 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 |
| String[] words = getWords(text); |
| for (int i = 0; i < words.length; i++) { |
| 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.equals("")) { //$NON-NLS-1$ |
| matcher = null; |
| } else { |
| String pattern = patternString + "*"; //$NON-NLS-1$ |
| // if (includeLeadingWildcard) { |
| // pattern = "*" + pattern; //$NON-NLS-1$ |
| // } |
| 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){ |
| List<String> words = new ArrayList<String>(); |
| // 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. |
| 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))) { |
| String word = text.substring(i, j); |
| words.add(word); |
| } |
| i = j; |
| } |
| return (String[]) words.toArray(new String[words.size()]); |
| } |
| } |
| |
| static class InternalPackage { |
| final EPackage ePackage; |
| List<InternalClass> classes = new ArrayList<InternalClass>(); |
| |
| public InternalPackage(EPackage ePackage) { |
| this.ePackage = ePackage; |
| } |
| |
| @Override |
| public String toString() { |
| return ePackage.toString(); |
| } |
| } |
| |
| static class InternalClass { |
| final InternalPackage pack; |
| final EClass eClass; |
| List<InternalFeature> features = new ArrayList<InternalFeature>(); |
| |
| public InternalClass(InternalPackage pack, EClass eClass) { |
| this.eClass = eClass; |
| this.pack = pack; |
| } |
| } |
| |
| static class InternalFeature { |
| final InternalClass clazz; |
| final EStructuralFeature feature; |
| |
| public InternalFeature(InternalClass clazz, EStructuralFeature feature) { |
| this.clazz = clazz; |
| this.feature = feature; |
| } |
| |
| } |
| } |