/* * 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.views; import java.util.EventObject; import java.util.Stack; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.edit.provider.INotifyChangedListener; import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.xsd.XSDFacet; import org.eclipse.xsd.XSDPackage; import org.eclipse.xsd.XSDSimpleTypeDefinition; import org.eclipse.xsd.XSDTypeDefinition; import org.eclipse.xsd.provider.XSDSemanticItemProviderAdapterFactory; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.event.EventObjectListener; import org.teiid.core.designer.event.EventSourceException; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.notification.util.NotificationUtilities; import org.teiid.designer.ui.UiConstants; import org.teiid.designer.ui.UiPlugin; import org.teiid.designer.ui.common.eventsupport.CompositeNotifyChangeListener; import org.teiid.designer.ui.common.eventsupport.SelectionUtilities; import org.teiid.designer.ui.common.widget.AbstractTableLabelProvider; import org.teiid.designer.ui.common.widget.DefaultContentProvider; import org.teiid.designer.ui.event.ModelResourceEvent; import org.teiid.designer.ui.viewsupport.DatatypeHierarchyTreeViewer; import org.teiid.designer.ui.viewsupport.ModelUtilities; /** * DatatypeHierarchyView is the ViewPart to display Datatypes in the Modeler. * * @since 8.0 */ public class DatatypeHierarchyView extends ModelerView { private static final int NAME_COLUMN = 0; private static final int VALUE_COLUMN = 1; private static final int TYPE_COLUMN = 2; private static final String LABEL_DETAILS = UiConstants.Util.getString("DatatypeHierarchyView.details"); //$NON-NLS-1$ private static final String LABEL_NAME = UiConstants.Util.getString("DatatypeHierarchyView.name"); //$NON-NLS-1$ private static final String LABEL_VALUE = UiConstants.Util.getString("DatatypeHierarchyView.value"); //$NON-NLS-1$ private static final String LABEL_TYPE = UiConstants.Util.getString("DatatypeHierarchyView.type"); //$NON-NLS-1$ TreeViewer typeTree; TableViewer detailsTable; private CompositeNotifyChangeListener notifyListener; private EventObjectListener modelResourceListener; /** * Construct a DatatypeHierarchyView for the Modeler * * @since 4.0 */ public DatatypeHierarchyView() { super(); } public void revealType( XSDTypeDefinition type ) { if (typeTree != null) { // gather a list of all parents. Use a stack so we can process in reverse: Stack s = new Stack(); try { Object root = ModelerCore.getBuiltInTypesManager().getAnyType(); XSDTypeDefinition parent = type.getBaseType(); while (parent != root) { s.push(parent); parent = parent.getBaseType(); } // endwhile } catch (ModelerCoreException err) { UiConstants.Util.log(err); } // endtry // make sure all parents are opened: while (!s.isEmpty()) { Object element = s.pop(); typeTree.setExpandedState(element, true); } // endwhile typeTree.setSelection(new StructuredSelection(type)); typeTree.reveal(type); } // endif } /** * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) * @since 4.0 */ @Override public void createPartControl( final Composite parent ) { super.createPartControl(parent); // create components: SashForm sf = new SashForm(parent, SWT.VERTICAL); // upper tree: typeTree = new DatatypeHierarchyTreeViewer(sf); // lower portion: Group lowerComp = new Group(sf, SWT.NONE); lowerComp.setText(LABEL_DETAILS); lowerComp.setLayout(new FillLayout()); // create details table: detailsTable = new TableViewer(lowerComp); detailsTable.setContentProvider(new DefaultContentProvider() { @Override public Object[] getElements( Object inputElement ) { return ((XSDSimpleTypeDefinition)inputElement).getFacets().toArray(); } }); // endanon detailsTable.setLabelProvider(new DetailsTableLabelProvider()); // set up table component: Table table = detailsTable.getTable(); table.setHeaderVisible(true); table.setLinesVisible(false); // set up columns: TableColumn col = new TableColumn(table, SWT.RIGHT); col.setText(LABEL_NAME); col = new TableColumn(table, SWT.LEFT); col.setText(LABEL_VALUE); col = new TableColumn(table, SWT.LEFT); col.setText(LABEL_TYPE); // pack the columns to get them to show up: packColumns(); sf.setWeights(new int[] {3, 1}); // set up view part: setPartName(UiConstants.Util.getString("DatatypeHierarchyView.title")); //$NON-NLS-1$ // hook up this view's selection provider to this site getViewSite().setSelectionProvider(typeTree); // set up listeners notifyListener = new CompositeNotifyChangeListener(); ModelUtilities.addNotifyChangedListener(notifyListener); notifyListener.addNotifyChangeListener(new DatatypeHierarchyNotificationHandler()); // hook up our status bar manager for EObject selection inside this view typeTree.addSelectionChangedListener(new ISelectionChangedListener() { private Object lastSelected; @Override public void selectionChanged( SelectionChangedEvent event ) { ISelection sel = event.getSelection(); if (!sel.isEmpty()) { Object selectedObject = SelectionUtilities.getSelectedObject(sel); if (lastSelected != selectedObject) { // selection is different: lastSelected = selectedObject; detailsTable.setInput(selectedObject); packColumns(); } // endif } // endif } }); typeTree.addSelectionChangedListener(getStatusBarListener()); // Hook up this view to listen for resource change events. Basically need to refresh the tree whenever an XSD file is // being opened or closed? modelResourceListener = new EventObjectListener() { @Override public void processEvent( EventObject obj ) { ModelResourceEvent event = (ModelResourceEvent)obj; final IResource file = event.getResource(); // defect 16898 - since we now get notifications for projects, // the extension may be null. String fileExtension = file.getFileExtension(); if (fileExtension != null && fileExtension.equalsIgnoreCase("xsd")) { //$NON-NLS-1$ int type = event.getType(); if (type == ModelResourceEvent.CLOSED || type == ModelResourceEvent.RELOADED || type == ModelResourceEvent.ADDED || type == ModelResourceEvent.REMOVED || type == ModelResourceEvent.CHANGED) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (!typeTree.getTree().isDisposed()) { typeTree.refresh(); } } }); } } } }; try { UiPlugin.getDefault().getEventBroker().addListener(ModelResourceEvent.class, modelResourceListener); } catch (EventSourceException e) { UiConstants.Util.log(IStatus.ERROR, e, e.getMessage()); } typeTree.expandToLevel(2); } void packColumns() { Table table = detailsTable.getTable(); for (int i = 0; i < table.getColumnCount(); i++) { TableColumn col = table.getColumn(i); col.pack(); if (col.getWidth() > 200) { col.setWidth(200); } // endif } // endfor } /** * @see org.eclipse.ui.IWorkbenchPart#setFocus() * @since 4.0 */ @Override public void setFocus() { if (typeTree != null && !typeTree.getTree().isDisposed()) { typeTree.getTree().setFocus(); } } /* (non-Javadoc) * @see org.eclipse.ui.IWorkbenchPart#dispose() */ @Override public void dispose() { super.dispose(); if (notifyListener != null) { ModelUtilities.removeNotifyChangedListener(notifyListener); } if (modelResourceListener != null) { try { UiPlugin.getDefault().getEventBroker().removeListener(modelResourceListener); } catch (EventSourceException e) { UiConstants.Util.log(IStatus.ERROR, e, e.getMessage()); } } } /** * DatatypeHierarchyNotificationHandler is the notification handler for the Datatype viewer. */ class DatatypeHierarchyNotificationHandler implements INotifyChangedListener { /* (non-Javadoc) * @see org.eclipse.emf.edit.provider.INotifyChangedListener#notifyChanged(org.eclipse.emf.common.notify.Notification) */ @Override public void notifyChanged( Notification notification ) { if (typeTree != null && !typeTree.getTree().isDisposed()) { EObject obj = NotificationUtilities.getEObject(notification); if (obj instanceof XSDSimpleTypeDefinition) { XSDSimpleTypeDefinition std = (XSDSimpleTypeDefinition)obj; switch (notification.getEventType()) { case Notification.ADD: case Notification.ADD_MANY: typeTree.refresh(std.getBaseTypeDefinition()); break; case Notification.REMOVE: case Notification.REMOVE_MANY: typeTree.remove(std); break; case Notification.SET: // A change; we need to update tree and details: int feature = NotificationUtilities.getFeatureChanged(notification); switch (feature) { case XSDPackage.XSD_SIMPLE_TYPE_DEFINITION__BASE_TYPE: case XSDPackage.XSD_SIMPLE_TYPE_DEFINITION__BASE_TYPE_DEFINITION: // need to refresh old and new parents and their kids: Object oldParent = notification.getOldValue(); Object newParent = notification.getNewValue(); typeTree.refresh(oldParent); typeTree.refresh(newParent); break; case XSDPackage.XSD_SIMPLE_TYPE_DEFINITION__NAME: // need to refresh this tree node, not kids: typeTree.update(std, null); break; default: // need to refresh details info: if (std == SelectionUtilities.getSelectedObject(typeTree.getSelection())) { detailsTable.setInput(std); packColumns(); } // endif } // endswitch -- feature id changed break; default: // we should not care about any other kinds of notifications... break; } // endswitch -- notification type } // endif -- on a type } // endif -- tree available } } // endclass DatatypeHierarchyNotificationHandler class DetailsTableLabelProvider extends AbstractTableLabelProvider { private AdapterFactoryLabelProvider labelProv = new AdapterFactoryLabelProvider( new XSDSemanticItemProviderAdapterFactory()); @Override public String getColumnText( Object element, int columnIndex ) { if (element instanceof XSDFacet) { XSDFacet f = (XSDFacet)element; switch (columnIndex) { case NAME_COLUMN: return f.getFacetName(); case VALUE_COLUMN: return f.getLexicalValue(); case TYPE_COLUMN: XSDSimpleTypeDefinition std = f.getSimpleTypeDefinition(); if (detailsTable.getInput() == std) { return ""; //$NON-NLS-1$ } // endif return labelProv.getText(std); default: // ignore } // endswitch } // endif return null; } } }