| /******************************************************************************* |
| * Copyright (c) 2010 SAP AG. |
| * 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: |
| * Emil Simeonov - initial API and implementation. |
| * Dimitar Donchev - initial API and implementation. |
| * Dimitar Tenev - initial API and implementation. |
| * Nevena Manova - initial API and implementation. |
| * Georgi Konstantinov - initial API and implementation. |
| * Richard Birenheide - initial API and implementation. |
| *******************************************************************************/ |
| package org.eclipse.wst.sse.sieditor.ui.v2.common;
|
|
|
| import java.text.MessageFormat;
|
| import java.util.ArrayList;
|
| import java.util.HashMap;
|
| import java.util.Iterator;
|
| import java.util.List;
|
| import java.util.Locale;
|
| import java.util.regex.Matcher;
|
| import java.util.regex.Pattern;
|
|
|
| import org.eclipse.core.resources.IFile;
|
| import org.eclipse.core.resources.IResource;
|
| import org.eclipse.jface.action.MenuManager;
|
| import org.eclipse.jface.dialogs.Dialog;
|
| import org.eclipse.jface.dialogs.IDialogConstants;
|
| import org.eclipse.jface.viewers.DoubleClickEvent;
|
| import org.eclipse.jface.viewers.IDoubleClickListener;
|
| import org.eclipse.jface.viewers.ILabelProvider;
|
| import org.eclipse.jface.viewers.ISelectionChangedListener;
|
| import org.eclipse.jface.viewers.IStructuredSelection;
|
| import org.eclipse.jface.viewers.ITreeContentProvider;
|
| import org.eclipse.jface.viewers.LabelProvider;
|
| import org.eclipse.jface.viewers.SelectionChangedEvent;
|
| 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.custom.CLabel;
|
| import org.eclipse.swt.custom.ViewForm;
|
| import org.eclipse.swt.events.FocusEvent;
|
| import org.eclipse.swt.events.FocusListener;
|
| import org.eclipse.swt.events.ModifyEvent;
|
| import org.eclipse.swt.events.ModifyListener;
|
| import org.eclipse.swt.events.SelectionEvent;
|
| import org.eclipse.swt.events.SelectionListener;
|
| 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.Display;
|
| import org.eclipse.swt.widgets.Group;
|
| import org.eclipse.swt.widgets.Label;
|
| import org.eclipse.swt.widgets.Shell;
|
| import org.eclipse.swt.widgets.Table;
|
| import org.eclipse.swt.widgets.TableItem;
|
| import org.eclipse.swt.widgets.Text;
|
| import org.eclipse.swt.widgets.ToolBar;
|
| import org.eclipse.swt.widgets.ToolItem;
|
|
|
| import org.eclipse.wst.sse.sieditor.model.api.IModelObject;
|
| import org.eclipse.wst.sse.sieditor.model.wsdl.api.IDescription;
|
| import org.eclipse.wst.sse.sieditor.model.xsd.api.ISchema;
|
| import org.eclipse.wst.sse.sieditor.model.xsd.api.ISimpleType;
|
| import org.eclipse.wst.sse.sieditor.model.xsd.api.IStructureType;
|
| import org.eclipse.wst.sse.sieditor.model.xsd.api.IType;
|
| import org.eclipse.wst.sse.sieditor.model.xsd.impl.Schema;
|
| import org.eclipse.wst.sse.sieditor.ui.Activator;
|
| import org.eclipse.wst.sse.sieditor.ui.i18n.Messages;
|
| import org.eclipse.wst.sse.sieditor.ui.v2.UIConstants;
|
|
|
| /**
|
| * Types Search Dialog
|
| */
|
| public class TypeSearchDialog extends Dialog implements SelectionListener {
|
| protected final int TEXT_TYPED_DELAY = 400;
|
|
|
| private String dialogTitle;
|
|
|
| private ArrayList<IType> typesTableViewerInput;
|
| protected List<IType> masterTypeList;
|
|
|
| protected Button all, inlineType, primitiveType;
|
| protected HashMap<String, Integer> tableDecoratorTrackingTool = new HashMap<String, Integer>();
|
| // widgets
|
| protected Composite topComposite;
|
| protected Composite bottomComposite;
|
| protected Text textFilter;
|
| protected TableViewer typesTableViewer;
|
|
|
| protected ViewForm fileLocationView;
|
| protected CLabel locationLabel;
|
| // keep track of the item previously selected in the table
|
|
|
| protected Object typeSelection;
|
| protected Object qualifierTextSelection;
|
|
|
| protected ToolBar filterToolBar;
|
| protected ToolItem toolItem;
|
| protected MenuManager fMenuManager;
|
|
|
| protected TypesLableProvider lableProvider;
|
|
|
| public TypeSearchDialog(Shell shell, String dialogTitle) {
|
| super(shell);
|
| setShellStyle(getShellStyle() | SWT.RESIZE);
|
| this.dialogTitle = dialogTitle;
|
| typesTableViewerInput = new ArrayList<IType>();
|
| masterTypeList = new ArrayList<IType>();
|
| }
|
|
|
| /*
|
| * (non-Javadoc)
|
| *
|
| * @see org.eclipse.jface.dialogs.Dialog#create()
|
| */
|
| @Override
|
| public void create() {
|
| super.create();
|
| getButton(IDialogConstants.OK_ID).setEnabled(false);
|
|
|
| }
|
|
|
| @Override
|
| protected Control createDialogArea(Composite parent) {
|
|
|
| getShell().setText(dialogTitle);
|
|
|
| Composite mainComposite = (Composite) super.createDialogArea(parent);
|
| GridData gData = (GridData) mainComposite.getLayoutData();
|
| gData.heightHint = 400;
|
| gData.widthHint = 270;
|
|
|
| Composite filterLabelAndText = new Composite(mainComposite, SWT.NONE);
|
| GridLayout layoutFilterLabelAndText = new GridLayout(2, false);
|
| layoutFilterLabelAndText.marginWidth = 0;
|
| layoutFilterLabelAndText.marginHeight = 5;
|
| filterLabelAndText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
| filterLabelAndText.setLayout(layoutFilterLabelAndText);
|
|
|
| // Create Text textFilter
|
|
|
| Label filterLabel = new Label(filterLabelAndText, SWT.LEFT);
|
| filterLabel.setText(Messages.TypeSearchDialog_filter_filter_label);
|
| GridData filterLabelData = new GridData();
|
| filterLabelData.horizontalSpan = 4;
|
| filterLabelData.horizontalAlignment = 4;
|
| filterLabelData.grabExcessHorizontalSpace = true;
|
| filterLabel.setLayoutData(filterLabelData);
|
|
|
| textFilter = new Text(filterLabelAndText, SWT.SINGLE | SWT.BORDER);
|
| textFilter.setText(Messages.TypeSearchDialog_filter_text_text);
|
| textFilter.addModifyListener(new TextFilterModifyAdapter());
|
| textFilter.addFocusListener(new FocusListener() {
|
|
|
| public void focusGained(FocusEvent e) {
|
| if (textFilter.getText().equals(Messages.TypeSearchDialog_filter_text_text)) {
|
| textFilter.setText(UIConstants.EMPTY_STRING);
|
| }
|
|
|
| }
|
|
|
| public void focusLost(FocusEvent e) {
|
|
|
| }
|
|
|
| });
|
| textFilter.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
| GridData textFilterData = new GridData();
|
| textFilterData.horizontalSpan = 4;
|
| textFilterData.horizontalAlignment = GridData.FILL;
|
| textFilterData.grabExcessHorizontalSpace = true;
|
| textFilter.setLayoutData(textFilterData);
|
|
|
| Group optionsComposite = new Group(mainComposite, SWT.NONE);
|
| optionsComposite.setText(Messages.TypeSearchDialog_filter_scope_label);
|
| GridLayout layoutOptions = new GridLayout(4, false);
|
| layoutOptions.marginWidth = 20;
|
| layoutOptions.marginHeight = 10;
|
| optionsComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
| optionsComposite.setLayout(layoutOptions);
|
|
|
| all = new Button(optionsComposite, SWT.RADIO);
|
| all.setText(Messages.TypeSearchDialog_all_label);
|
| all.setSelection(true);
|
| all.addSelectionListener(this);
|
|
|
| inlineType = new Button(optionsComposite, SWT.RADIO);
|
| inlineType.setText(Messages.TypeSearchDialog_inline_label);
|
| inlineType.addSelectionListener(this);
|
| primitiveType = new Button(optionsComposite, SWT.RADIO);
|
| primitiveType.addSelectionListener(this);
|
| primitiveType.setText(Messages.TypeSearchDialog_primitive_label);
|
|
|
| createTypesTableViewer(mainComposite);
|
|
|
| // Populate the Component TableViewer via the provider
|
| typesTableViewer.setContentProvider(new TypesTableContentProvider());
|
| lableProvider = new TypesLableProvider();
|
| typesTableViewer.setLabelProvider(lableProvider);
|
| typesTableViewer.setSorter(new ViewerSorter());
|
| populateMasterTypeList();
|
| typesTableViewer.setInput(typesTableViewerInput);
|
|
|
| refreshTableViewer(null, ""); //$NON-NLS-1$
|
|
|
| return mainComposite;
|
| }
|
|
|
| /*
|
| * Creates the Table TableViewer.
|
| */
|
| private void createTypesTableViewer(Composite base) {
|
| typesTableViewer = createFiltersWithdTableViewer(base);
|
|
|
| typesTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
|
| public void selectionChanged(SelectionChangedEvent event) {
|
| updateCanFinish();
|
| }
|
| });
|
|
|
| typesTableViewer.addDoubleClickListener(new IDoubleClickListener() {
|
|
|
| public void doubleClick(DoubleClickEvent event) {
|
| okPressed();
|
| }
|
|
|
| });
|
| }
|
|
|
| protected TableViewer createFiltersWithdTableViewer(Composite comp) {
|
| Composite labelAndFilter = new Composite(comp, SWT.NONE);
|
| labelAndFilter.setLayoutData(new GridData(GridData.FILL_BOTH));
|
| GridLayout layout = new GridLayout();
|
| layout.numColumns = 2;
|
| layout.marginWidth = 0;
|
| layout.marginHeight = 0;
|
| labelAndFilter.setLayout(layout);
|
|
|
| labelAndFilter.setLayout(layout);
|
| Label tableLabel = new Label(labelAndFilter, SWT.NONE);
|
|
|
| tableLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
| tableLabel.setText(Messages.TypeSearchDialog_types_table_label);
|
|
|
| TableViewer tableViewer = new TableViewer(new Table(labelAndFilter, SWT.SINGLE | SWT.BORDER));
|
| Control TableWidget = tableViewer.getTable();
|
| GridData gd = new GridData(GridData.FILL_BOTH);
|
| gd.horizontalSpan = 2;
|
| TableWidget.setLayoutData(gd);
|
| return tableViewer;
|
| }
|
|
|
| /**
|
| * Looking at each item in the Table. If there are other items with same
|
| * name , then add extra info (namespace, file) into the the text label of
|
| * all these duplicated items. - This should be called everytime the Table
|
| * viewer is refreshed..
|
| */
|
| protected void decorateTable() {
|
| tableDecoratorTrackingTool.clear();
|
|
|
| // init the name-duplicates counter
|
| if (null != typesTableViewerInput) {
|
| for (int i = 0; i < typesTableViewerInput.size(); i++) {
|
| Object currentItem = typesTableViewerInput.get(i);
|
| String name = lableProvider.getName(currentItem);
|
| Integer count = tableDecoratorTrackingTool.get(name);
|
| if (count == null) {
|
| tableDecoratorTrackingTool.put(name, Integer.valueOf(1));
|
| } else {
|
| tableDecoratorTrackingTool.put(name, Integer.valueOf(count.intValue() + 1));
|
| }
|
| }
|
|
|
| // Modify/decorate those items in the Table that have duplicated
|
| // name
|
| TableItem[] items = typesTableViewer.getTable().getItems();
|
| for (int i = 0; i < items.length; i++) {
|
| Object currentItem = items[i].getData();
|
| Integer count = tableDecoratorTrackingTool.get(lableProvider.getName(currentItem));
|
| if (count != null && count.intValue() > 1) {
|
| String fileName = null;
|
| if (currentItem instanceof IType) {
|
| IModelObject root = ((IType) currentItem).getRoot();
|
| if (root != null) {
|
| if (root instanceof ISchema) {
|
| fileName = getFileName(((ISchema) root).getLocation());
|
| } else if (root instanceof IDescription) {
|
| fileName = getFileName(((IDescription) root).getLocation());
|
| }
|
| }
|
| }
|
| if (fileName != null)
|
| items[i].setText(lableProvider.getName(currentItem) + " - " + fileName); //$NON-NLS-1$
|
| else
|
| items[i].setText(lableProvider.getName(currentItem));
|
| }
|
| }
|
| }
|
| }
|
|
|
| private String getFileName(String filePath) {
|
| if (filePath == null)
|
| return null;
|
| if (filePath.lastIndexOf('/') != -1)
|
| return filePath.substring(filePath.lastIndexOf('/') + 1);
|
| return null;
|
| }
|
|
|
| /*
|
| * Returns the processed filter text for the Text field. Inserts a "."
|
| * before each supported meta-character.
|
| */
|
| protected String getProcessedFilterString() {
|
| return processFilterString(textFilter.getText());
|
| }
|
|
|
| /*
|
| * If supported metacharacters are used in the filter string, we need to
|
| * insert a "." before each metacharacter.
|
| */
|
| private String processFilterString(String inputString) {
|
| if (!(inputString.equals(""))) { //$NON-NLS-1$
|
| inputString = insertString("*", ".", inputString); //$NON-NLS-1$ //$NON-NLS-2$
|
| inputString = insertString("?", ".", inputString); //$NON-NLS-1$ //$NON-NLS-2$
|
| inputString = inputString + ".*"; //$NON-NLS-1$
|
| } else {
|
| inputString = ".*"; //$NON-NLS-1$
|
| }
|
|
|
| return inputString.toLowerCase(Locale.ENGLISH);
|
| }
|
|
|
| /*
|
| * Helper method to insert a "." before each metacharacter in the
|
| * search/filter string.
|
| */
|
| private String insertString(String target, String newString, String string) {
|
| StringBuffer stringBuffer = new StringBuffer(string);
|
|
|
| int index = stringBuffer.indexOf(target);
|
| while (index != -1) {
|
| stringBuffer = stringBuffer.insert(index, newString);
|
| index = stringBuffer.indexOf(target, index + newString.length() + target.length());
|
| }
|
|
|
| return stringBuffer.toString();
|
| }
|
|
|
| /*
|
| * Listens to changes made in the text filter widget
|
| */
|
| private class TextFilterModifyAdapter implements ModifyListener {
|
| public void modifyText(ModifyEvent e) {
|
| if (e.widget == textFilter) {
|
| if (delayedEvent != null) {
|
| delayedEvent.CANCEL = true;
|
| }
|
|
|
| delayedEvent = new DelayedEvent();
|
|
|
| Display.getCurrent().timerExec(TEXT_TYPED_DELAY, delayedEvent);
|
| }
|
| }
|
| }
|
|
|
| // TODO... do we really need one instance?
|
| private DelayedEvent delayedEvent;
|
| private IResource currentResource;
|
|
|
| /*
|
| * Update the Type TableViewer when the text filter is modified. Use a
|
| * DelayedEvent so we don't update on every keystroke.
|
| */
|
| private class DelayedEvent implements Runnable {
|
| public boolean CANCEL = false;
|
|
|
| public void run() {
|
| if (!CANCEL) {
|
| populateTableWithTypes();
|
| }
|
| }
|
| }
|
|
|
| /*
|
| * Populate the Types TreeViewer with items.
|
| */
|
| protected void populateMasterTypeList() {
|
|
|
| masterTypeList.clear();
|
|
|
| List<IType> primitiveList = new ArrayList<IType>(Schema.getSchemaForSchema().getAllContainedTypes());
|
| if (!primitiveList.isEmpty()) {
|
| masterTypeList.addAll(primitiveList);
|
| }
|
|
|
| List<IType> inlinetypes = TypesDialogCreator.getInstance().getInlineTypes();
|
| if (inlinetypes != null && !inlinetypes.isEmpty())
|
| masterTypeList.addAll(inlinetypes);
|
| }
|
|
|
| protected void refreshTableViewer(List<IType> typeList, String filterText) {
|
| if (typeList == null)
|
| return;
|
| typesTableViewerInput.clear();
|
| Pattern regex = Pattern.compile(filterText);
|
| Iterator<IType> it = typeList.iterator();
|
| while (it.hasNext()) {
|
| Object item = it.next();
|
| String itemString = lableProvider.getText(item);
|
| Matcher m = regex.matcher(itemString.toLowerCase(Locale.ENGLISH));
|
| if (itemString.toLowerCase(Locale.ENGLISH).startsWith(filterText) || m.matches()) {
|
| typesTableViewerInput.add((IType) item);
|
| }
|
| }
|
| typesTableViewer.refresh();
|
| decorateTable();
|
|
|
| }
|
|
|
| /*
|
| * If there is a selection in the ComponentTreeViewer, enable OK
|
| */
|
| protected void updateCanFinish() {
|
| IStructuredSelection selection = (IStructuredSelection) typesTableViewer.getSelection();
|
| if (selection.getFirstElement() != null) {
|
| getButton(IDialogConstants.OK_ID).setEnabled(true);
|
| } else {
|
| getButton(IDialogConstants.OK_ID).setEnabled(false);
|
| }
|
| }
|
|
|
| @Override
|
| protected void okPressed() {
|
| IStructuredSelection selection = (IStructuredSelection) typesTableViewer.getSelection();
|
| typeSelection = selection.getFirstElement();
|
|
|
| super.okPressed();
|
| }
|
|
|
| // return you the selected type.
|
| public IType getTypeSelection() {
|
| IType type = (IType) typeSelection;
|
| return type;
|
| }
|
|
|
| private static class TypesTableContentProvider implements ITreeContentProvider {
|
| public Object[] getChildren(Object parentElement) {
|
| if (parentElement instanceof List<?>) {
|
| return ((List<?>) parentElement).toArray();
|
| }
|
| return new Object[0];
|
| }
|
|
|
| public Object[] getElements(Object inputElement) {
|
| return getChildren(inputElement);
|
| }
|
|
|
| public Object getParent(Object element) {
|
| return null;
|
| }
|
|
|
| public boolean hasChildren(Object element) {
|
| if (getChildren(element).length > 0) {
|
| return true;
|
| }
|
| return false;
|
| }
|
|
|
| public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
| }
|
|
|
| public void dispose() {
|
| }
|
| }
|
|
|
| private static class TypesLableProvider extends LabelProvider implements ILabelProvider {
|
|
|
| TypesLableProvider() {
|
| }
|
|
|
| public IFile getFile(Object component) {
|
| return null;
|
| }
|
|
|
| public ILabelProvider getLabelProvider() {
|
| return this;
|
| }
|
|
|
| public String getName(Object dataType) {
|
| if (dataType instanceof IType) {
|
|
|
| IType type = (IType) dataType;
|
|
|
| String namespace = null;
|
| if (type.getNamespace() == null)
|
| namespace = MessageFormat.format(Messages.TypeSearchDialog_msg_emtpy_namespace_container, new String[]{Messages.TypeSearchDialog_msg_empty_namespace});
|
| else
|
| namespace = type.getNamespace();
|
|
|
| String tableString = type.getName() + " - " + namespace; //$NON-NLS-1$
|
|
|
| if (!tableString.trim().equals(UIConstants.EMPTY_STRING))
|
| return tableString;
|
| }
|
|
|
| return UIConstants.EMPTY_STRING;
|
| }
|
|
|
| @Override
|
| public String getText(Object element) {
|
| return getName(element);
|
| }
|
|
|
| @Override
|
| public Image getImage(Object dataType) {
|
| if (dataType instanceof ISimpleType) {
|
| return Activator.getDefault().getImage(Activator.NODE_SIMPLE_TYPE);
|
| } else if (dataType instanceof IStructureType) {
|
| if (((IStructureType) dataType).isElement())
|
| return Activator.getDefault().getImage(Activator.NODE_ELEMENT);
|
| return Activator.getDefault().getImage(Activator.NODE_STRUCTURE_TYPE);
|
| } else if (dataType instanceof IType) {
|
| return Activator.getDefault().getImage(Activator.NODE_PRIMITIVE);
|
| }
|
| return null;
|
| }
|
| }
|
|
|
| public IResource getCurrentResource() {
|
| return currentResource;
|
| }
|
|
|
| public void setCurrentResource(IResource currentResource) {
|
| this.currentResource = currentResource;
|
| }
|
|
|
| public void widgetDefaultSelected(SelectionEvent e) {
|
|
|
| }
|
|
|
| public void widgetSelected(SelectionEvent e) {
|
| populateTableWithTypes();
|
| }
|
|
|
| private void populateTableWithTypes() {
|
| if (null != typesTableViewerInput)
|
| typesTableViewerInput.clear();
|
| List<IType> typesList = null;
|
| if (all.getSelection()) {
|
| populateMasterTypeList();
|
| typesList = new ArrayList<IType>(masterTypeList);
|
| populateTableWithTypes(typesList);
|
| }
|
| if (inlineType.getSelection()) {
|
| typesList = new ArrayList<IType>(TypesDialogCreator.getInstance().getInlineTypes());
|
| populateTableWithTypes(typesList);
|
| }
|
| if (primitiveType.getSelection()) {
|
| typesList = new ArrayList<IType>(Schema.getSchemaForSchema().getAllContainedTypes());
|
| populateTableWithTypes(typesList);
|
| }
|
| }
|
|
|
| private void populateTableWithTypes(List<IType> typesList) {
|
| if (textFilter.getText() != null && !UIConstants.EMPTY_STRING.equals(textFilter.getText().trim())) {
|
| filterTypes(typesList);
|
| } else {
|
| typesTableViewerInput = (ArrayList<IType>) typesList;
|
| typesTableViewer.setInput(typesTableViewerInput);
|
| typesTableViewer.refresh();
|
| decorateTable();
|
| }
|
| }
|
|
|
| private void filterTypes(List<IType> typesList) {
|
| refreshTableViewer(typesList, getProcessedFilterString());
|
| // Select first match
|
| if (typesTableViewer.getTable().getItemCount() > 0) {
|
| TableItem item = typesTableViewer.getTable().getItems()[0];
|
| TableItem items[] = new TableItem[1];
|
| items[0] = item;
|
| typesTableViewer.getTable().setSelection(items);
|
| }
|
| updateCanFinish();
|
| }
|
| }
|