blob: 0b4908554f5ecf316cb083cb76d4cd50ff88ad74 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}
}