/******************************************************************************* * 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. *******************************************************************************/ 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(); } }