/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.ui.search; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.dialogs.AbstractElementListSelectionDialog; import org.eclipse.ui.dialogs.SelectionStatusDialog; import org.teiid.core.designer.util.StringConstants; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.search.ModelWorkspaceSearch; import org.teiid.designer.core.search.runtime.ResourceObjectRecord; import org.teiid.designer.runtime.spi.ITeiidVdb; import org.teiid.designer.ui.UiConstants; /** * ModelObjectSelectionDialog Adapted from the eclipse class TwoPaneElementSelector, because that class had the functionality but * lacked extensibility. * * @since 8.0 */ public class ModelObjectSelectionDialog extends AbstractElementListSelectionDialog implements StringConstants { private static final String TITLE = UiConstants.Util.getString("ModelObjectSelectionDialog.title"); //$NON-NLS-1$ private static final String TEXT_ENTRY_LABEL_TEXT = UiConstants.Util.getString("ModelObjectSelectionDialog.textEntryLabel.text"); //$NON-NLS-1$ private static final String UPPER_TABLE_LABEL_TEXT = UiConstants.Util.getString("ModelObjectSelectionDialog.upperTableLabel.text"); //$NON-NLS-1$ private static final String LOWER_TABLE_LABEL_TEXT = UiConstants.Util.getString("ModelObjectSelectionDialog.lowerTableLabel.text"); //$NON-NLS-1$ private static final String DOT = "."; //$NON-NLS-1$ private HashMap hmUniqueNames; private String sSelectedObject; private String sSelectedPath; private String fUpperListLabel; private String fLowerListLabel; ILabelProvider fQualifierRenderer; private Object[] fElements = new Object[0]; private Table fLowerList; private Object[] fQualifierElements; private boolean bUserCancelledDuringLoad = false; /** * @param parent * @since 4.2 */ public ModelObjectSelectionDialog( Shell parent ) { super(parent, new FindObjectLabelProvider(FindObjectLabelProvider.OBJECT)); fQualifierRenderer = new FindObjectLabelProvider(FindObjectLabelProvider.CONTAINER); setSize(200, 300); setAllowDuplicates(false); setTitle(TITLE); setMessage(TEXT_ENTRY_LABEL_TEXT); setUpperListLabel(UPPER_TABLE_LABEL_TEXT); setLowerListLabel(LOWER_TABLE_LABEL_TEXT); doLoadObjects(parent); } /** * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) */ private void doLoadObjects(Shell shell ) { final WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override public void execute( IProgressMonitor theMonitor ) { loadObjects(theMonitor); theMonitor.done(); } }; ProgressMonitorDialog dlg = null; try { dlg = new ProgressMonitorDialog(shell); //Display.getCurrent().getActiveShell()); dlg.run(true, true, op); if (dlg.getProgressMonitor().isCanceled()) { bUserCancelledDuringLoad = true; } else { // finish it all at the end dlg.getProgressMonitor().worked(1); } } catch (InterruptedException e) { bUserCancelledDuringLoad = true; } catch (InvocationTargetException e) { UiConstants.Util.log(e.getTargetException()); } } public boolean userCancelledDuringLoad() { return bUserCancelledDuringLoad; } void loadObjects( IProgressMonitor monitor ) { ModelWorkspaceSearch mwssSearch = new ModelWorkspaceSearch(monitor); Collection colRecordObjects = mwssSearch.getAllModelObjectRecords(); if (colRecordObjects == null) { return; } // create a data structure to relate the names to their URI(s) (could be dupes). hmUniqueNames = new HashMap(); Iterator it = colRecordObjects.iterator(); while (it.hasNext()) { ResourceObjectRecord ror = (ResourceObjectRecord)it.next(); // skip entries that have no name if (ror.getName().trim().equals("")) { //$NON-NLS-1$ continue; } // add named entries if (hmUniqueNames.containsKey(ror.getName())) { // if key already exists, add to its ArrayList ArrayList aryl = (ArrayList)hmUniqueNames.get(ror.getName()); aryl.add(ror); } else { // if key does not exist, create new ArrayList and add ror to it ArrayList aryl2 = new ArrayList(); aryl2.add(ror); hmUniqueNames.put(ror.getName(), aryl2); } } // load the dialog setElements(getElementsFromSource()); } private Object[] getElementsFromSource() { // The elements are the first entries in each ArrayList stored as a value // in the HashMap. They are ResourceObjectRecord s. ArrayList arylElements = new ArrayList(hmUniqueNames.values().size()); Iterator it = hmUniqueNames.values().iterator(); while (it.hasNext()) { ArrayList arylTemp = (ArrayList)it.next(); arylElements.add(arylTemp.get(0)); } return arylElements.toArray(); } public EObject getSelectedEObject() { // 1. get the string in the selected upper table row String sName = sSelectedObject; // 2. use the string to get the 'dupes' from the hashmap ArrayList aryl = (ArrayList)hmUniqueNames.get(sName); Iterator it = aryl.iterator(); ResourceObjectRecord rorSelected = null; // walk the 'folded' entries, looking for a match with the pathname // the user selected in the 'qualifier' table (lower table) while (it.hasNext()) { ResourceObjectRecord rorTemp = (ResourceObjectRecord)it.next(); if (sSelectedPath.equals(getFullPathForRecord(rorTemp))) { rorSelected = rorTemp; break; } } return getEObjectForRecord(rorSelected); } public EObject getEObjectForRecord( ResourceObjectRecord ror ) { EObject eObj = null; if(ror!=null) { try { URI uri = URI.createURI(ror.getObjectURI()); if (uri.fragment() != null) eObj = ModelerCore.getModelContainer().getEObject(uri, true); } catch (CoreException ce) { ModelerCore.Util.log(IStatus.ERROR, ce, ce.getMessage()); } } return eObj; } @Override public Object[] getFoldedElements( int index ) { // 1. get the string in the selected upper table row String sName = null; Object[] oArySelection = fFilteredList.getSelection(); if (oArySelection.length > 0) { sName = ((ResourceObjectRecord)oArySelection[0]).getName(); } // 2. use the string to get the 'dupes' from the hashmap ArrayList aryl = (ArrayList)hmUniqueNames.get(sName); Object[] oAry = new Object[aryl.size()]; Iterator it = aryl.iterator(); int ix = 0; while (it.hasNext()) { ResourceObjectRecord rorTemp = (ResourceObjectRecord)it.next(); oAry[ix++] = rorTemp; } return oAry; } /** * Sets the upper list label. If the label is <code>null</code> (default), no label is created. */ public void setUpperListLabel( String label ) { fUpperListLabel = label; } /** * Sets the lower list label. If the label is <code>null</code> (default), no label is created. */ public void setLowerListLabel( String label ) { fLowerListLabel = label; } /** * Sets the elements to be displayed. * * @param elements the elements to be displayed. */ public void setElements( Object[] elements ) { fElements = elements; } /* * @see Dialog#createDialogArea(Composite) */ @Override public Control createDialogArea( final Composite parent ) { // add the rest of the components: Composite contents = (Composite)super.createDialogArea(parent); createMessageArea(contents); createFilterText(contents); createLabel(contents, fUpperListLabel); Control listCtrl = createFilteredList(contents); final GridData gdlc = (GridData)listCtrl.getLayoutData(); gdlc.heightHint = convertHeightInCharsToPixels(18); gdlc.widthHint = 300; createLabel(contents, fLowerListLabel); createLowerList(contents); setListElements(fElements); List initialSelections = getInitialElementSelections(); if (!initialSelections.isEmpty()) { Object element = initialSelections.get(0); setSelection(new Object[] {element}); setLowerSelectedElement(element); } return contents; } /** * Creates a label if name was not <code>null</code>. * * @param parent the parent composite. * @param name the name of the label. * @return returns a label if a name was given, <code>null</code> otherwise. */ protected Label createLabel( Composite parent, String name ) { if (name == null) return null; Label label = new Label(parent, SWT.NONE); label.setText(name); label.setFont(parent.getFont()); return label; } /** * Creates the list widget and sets layout data. * * @param parent the parent composite. * @return returns the list table widget. */ protected Table createLowerList( Composite parent ) { Table list = new Table(parent, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); list.addListener(SWT.Selection, new Listener() { @Override public void handleEvent( Event evt ) { handleLowerSelectionChanged(); } }); list.addListener(SWT.MouseDoubleClick, new Listener() { @Override public void handleEvent( Event evt ) { handleDefaultSelected(); } }); list.addDisposeListener(new DisposeListener() { @Override public void widgetDisposed( DisposeEvent e ) { fQualifierRenderer.dispose(); } }); GridData data = new GridData(); data.heightHint = convertHeightInCharsToPixels(8); data.grabExcessVerticalSpace = true; data.grabExcessHorizontalSpace = true; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; list.setLayoutData(data); list.setFont(parent.getFont()); fLowerList = list; return list; } /** * @see SelectionStatusDialog#computeResult() */ @Override protected void computeResult() { Object[] results = new Object[] {getLowerSelectedElement()}; setResult(Arrays.asList(results)); } /** * @see AbstractElementListSelectionDialog#handleDefaultSelected() */ @Override protected void handleDefaultSelected() { handleUpperSelectionChanged(); if (validateCurrentSelection() && (getLowerSelectedElement() != null)) buttonPressed(IDialogConstants.OK_ID); } /** * @see AbstractElementListSelectionDialog#handleSelectionChanged() */ @Override protected void handleSelectionChanged() { super.handleSelectionChanged(); handleUpperSelectionChanged(); handleLowerSelectionChanged(); } void handleUpperSelectionChanged() { int index = getSelectionIndex(); fLowerList.removeAll(); if (index < 0) return; fQualifierElements = getFoldedElements(index); if (fQualifierElements == null) updateLowerListWidget(new Object[] {}); else updateLowerListWidget(fQualifierElements); updateOkState(); // capture the selection in the upper list if (getSelectedElements()[0] != null) { Object[] oArySelection = fFilteredList.getSelection(); if (oArySelection.length > 0) { sSelectedObject = ((ResourceObjectRecord)oArySelection[0]).getName(); } } } void handleLowerSelectionChanged() { updateOkState(); // capture the selection in the lower list if (getLowerSelectedElement() != null) { ResourceObjectRecord rorSelected = (ResourceObjectRecord)getLowerSelectedElement(); sSelectedPath = getFullPathForRecord(rorSelected); } } private String getFullPathForRecord( ResourceObjectRecord ror ) { String sPath = ""; //$NON-NLS-1$ EObject eo = getEObjectForRecord(ror); if (eo != null) { IPath path = ModelerCore.getModelEditor().getModelRelativePath(eo); sPath = ror.getResourcePath() + path.makeAbsolute().toString(); } else { sPath = ror.getResourcePath(); } return sPath; } /** * Selects an element in the lower pane. */ protected void setLowerSelectedElement( Object element ) { if (fQualifierElements == null) return; // find matching index int i; for (i = 0; i != fQualifierElements.length; i++) if (fQualifierElements[i].equals(element)) break; // set selection if (i != fQualifierElements.length) fLowerList.setSelection(i); } /** * Returns the selected element from the lower pane. */ protected Object getLowerSelectedElement() { int index = fLowerList.getSelectionIndex(); if (index >= 0) return fQualifierElements[index]; return null; } private void updateLowerListWidget( Object[] elements ) { int length = elements.length; String[] qualifiers = new String[length]; for (int i = 0; i != length; i++) qualifiers[i] = fQualifierRenderer.getText(elements[i]); TwoArrayQuickSorter sorter = new TwoArrayQuickSorter(isCaseIgnored()); sorter.sort(qualifiers, elements); for (int i = 0; i != length; i++) { TableItem item = new TableItem(fLowerList, SWT.NONE); item.setText(qualifiers[i]); item.setImage(fQualifierRenderer.getImage(elements[i])); } if (fLowerList.getItemCount() > 0) fLowerList.setSelection(0); } /* * @see AbstractElementListSelectionDialog#handleEmptyList() */ @Override protected void handleEmptyList() { super.handleEmptyList(); fLowerList.setEnabled(false); } @Override protected void updateOkState() { super.updateOkState(); // if we pass other OK tests, check to see that the Container does not end // in 'xmi', which indicates an incomplete path. In that case disable OK. Button okButton = getOkButton(); if (okButton!=null && okButton.isEnabled()) { Object oSelected = getLowerSelectedElement(); String sContainerLabel = fQualifierRenderer.getText(oSelected); String sContainerLabelLowerCase = sContainerLabel.toLowerCase(); if (sContainerLabelLowerCase.endsWith(DOT_XMI) || sContainerLabelLowerCase.endsWith(DOT_XML) || sContainerLabelLowerCase.endsWith(DOT_XSD) || sContainerLabelLowerCase.endsWith(ITeiidVdb.VDB_DOT_EXTENSION)) { getOkButton().setEnabled(false); } } } }