| /******************************************************************************* |
| * Copyright (c) 2011-2014 EclipseSource Muenchen GmbH and others. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Eugen Neufeld - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.emf.ecp.view.spi.categorization.swt; |
| |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.databinding.observable.value.IObservableValue; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.databinding.EMFDataBindingContext; |
| import org.eclipse.emf.databinding.edit.EMFEditObservables; |
| import org.eclipse.emf.ecp.view.internal.categorization.swt.Activator; |
| import org.eclipse.emf.ecp.view.internal.categorization.swt.ValidationTabImageHelper; |
| import org.eclipse.emf.ecp.view.spi.categorization.model.VAbstractCategorization; |
| import org.eclipse.emf.ecp.view.spi.context.ViewModelContext; |
| import org.eclipse.emf.ecp.view.spi.model.VDiagnostic; |
| import org.eclipse.emf.ecp.view.spi.model.VElement; |
| import org.eclipse.emf.ecp.view.spi.model.VViewPackage; |
| import org.eclipse.emf.ecp.view.spi.model.reporting.StatusReport; |
| import org.eclipse.emf.ecp.view.spi.renderer.NoPropertyDescriptorFoundExeption; |
| import org.eclipse.emf.ecp.view.spi.renderer.NoRendererFoundException; |
| import org.eclipse.emf.ecp.view.template.model.VTStyleProperty; |
| import org.eclipse.emf.ecp.view.template.model.VTViewTemplateProvider; |
| import org.eclipse.emf.ecp.view.template.style.tab.model.VTTabStyleProperty; |
| import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; |
| import org.eclipse.emf.edit.domain.EditingDomain; |
| import org.eclipse.emfforms.common.Optional; |
| import org.eclipse.emfforms.spi.common.report.ReportService; |
| import org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer; |
| import org.eclipse.emfforms.spi.swt.core.EMFFormsNoRendererException; |
| import org.eclipse.emfforms.spi.swt.core.EMFFormsRendererFactory; |
| import org.eclipse.emfforms.spi.swt.core.SWTDataElementIdHelper; |
| import org.eclipse.emfforms.spi.swt.core.layout.GridDescriptionFactory; |
| import org.eclipse.emfforms.spi.swt.core.layout.SWTGridCell; |
| import org.eclipse.emfforms.spi.swt.core.layout.SWTGridDescription; |
| import org.eclipse.jface.databinding.swt.WidgetProperties; |
| import org.eclipse.jface.layout.GridDataFactory; |
| import org.eclipse.jface.layout.GridLayoutFactory; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.CTabFolder; |
| import org.eclipse.swt.custom.CTabItem; |
| import org.eclipse.swt.custom.ScrolledComposite; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| |
| /** |
| * Abstract class for a tab renderer. |
| * |
| * @author Eugen Neufeld |
| * @param <VELEMENT> the {@link VElement} |
| */ |
| public abstract class AbstractSWTTabRenderer<VELEMENT extends VElement> extends AbstractSWTRenderer<VELEMENT> { |
| |
| private final Map<CTabItem, VAbstractCategorization> itemToCategorizationMap = new LinkedHashMap<CTabItem, VAbstractCategorization>(); |
| private final Map<VAbstractCategorization, CTabItem> categorizationToItemMap = new LinkedHashMap<VAbstractCategorization, CTabItem>(); |
| private final Map<CTabItem, Composite> itemToCompositeMap = new LinkedHashMap<CTabItem, Composite>(); |
| |
| private final EMFFormsRendererFactory emfFormsRendererFactory; |
| private final EMFDataBindingContext dataBindingContext; |
| private final VTViewTemplateProvider viewTemplateProvider; |
| |
| private EMFFormsRendererFactory getEMFFormsRendererFactory() { |
| return emfFormsRendererFactory; |
| } |
| |
| /** |
| * Default constructor. |
| * |
| * @param vElement the view model element to be rendered |
| * @param viewContext the view context |
| * @param reportService the {@link ReportService} |
| * @param emfFormsRendererFactory The {@link EMFFormsRendererFactory} |
| * @param viewTemplateProvider the {@link VTViewTemplateProvider} |
| * @since 1.8 |
| */ |
| public AbstractSWTTabRenderer( |
| VELEMENT vElement, |
| ViewModelContext viewContext, |
| ReportService reportService, |
| EMFFormsRendererFactory emfFormsRendererFactory, |
| VTViewTemplateProvider viewTemplateProvider) { |
| super(vElement, viewContext, reportService); |
| this.emfFormsRendererFactory = emfFormsRendererFactory; |
| this.viewTemplateProvider = viewTemplateProvider; |
| dataBindingContext = new EMFDataBindingContext(); |
| } |
| |
| /** |
| * Returns the view template provider. |
| * |
| * @return the {@link VTViewTemplateProvider} |
| * @since 1.8 |
| */ |
| protected final VTViewTemplateProvider getViewTemplateProvider() { |
| return viewTemplateProvider; |
| } |
| |
| @Override |
| public SWTGridDescription getGridDescription(SWTGridDescription gridDescription) { |
| return GridDescriptionFactory.INSTANCE.createSimpleGrid(1, 1, this); |
| } |
| |
| @Override |
| protected Control renderControl(SWTGridCell cell, Composite parent) |
| throws NoRendererFoundException, NoPropertyDescriptorFoundExeption { |
| final boolean useScrolledContent = useScrolledContent(); |
| |
| final CTabFolder folder = new CTabFolder(parent, getTabFolderStyle()); |
| folder.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| itemSelected(folder.getSelection()); |
| } |
| }); |
| folder.setBackground(parent.getBackground()); |
| final EList<VAbstractCategorization> categorizations = getCategorizations(); |
| for (final VAbstractCategorization categorization : categorizations) { |
| final CTabItem item = new CTabItem(folder, SWT.NULL); |
| final Composite composite; |
| if (useScrolledContent) { |
| composite = new ScrolledComposite(folder, SWT.V_SCROLL | SWT.H_SCROLL); |
| } else { |
| composite = new Composite(folder, SWT.NONE); |
| GridLayoutFactory.fillDefaults().applyTo(composite); |
| } |
| |
| itemToCategorizationMap.put(item, categorization); |
| categorizationToItemMap.put(categorization, item); |
| itemToCompositeMap.put(item, composite); |
| |
| final EditingDomain editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(categorization); |
| final IObservableValue modelLabelValue = EMFEditObservables.observeValue( |
| editingDomain, |
| categorization, |
| VViewPackage.eINSTANCE.getElement_Label()); |
| final IObservableValue targetLabelValue = WidgetProperties.text().observe(item); |
| dataBindingContext.bindValue(targetLabelValue, modelLabelValue); |
| |
| final IObservableValue modelTooltipValue = EMFEditObservables.observeValue( |
| editingDomain, |
| categorization, |
| VViewPackage.eINSTANCE.getHasTooltip_Tooltip()); |
| final IObservableValue targetTooltipValue = WidgetProperties.tooltipText().observe(item); |
| dataBindingContext.bindValue(targetTooltipValue, modelTooltipValue); |
| |
| if (!renderLazy()) { |
| renderItem(item); |
| } |
| SWTDataElementIdHelper.setElementIdDataWithSubId(item, categorization, "tabitem", getViewModelContext()); //$NON-NLS-1$ |
| SWTDataElementIdHelper.setElementIdDataWithSubId(composite, categorization, "tabitem-composite", //$NON-NLS-1$ |
| getViewModelContext()); |
| } |
| if (folder.getItemCount() > 0) { |
| folder.setSelection(0); |
| itemSelected(folder.getSelection()); |
| } |
| SWTDataElementIdHelper.setElementIdDataWithSubId(folder, getVElement(), "tabfolder", getViewModelContext()); //$NON-NLS-1$ |
| return folder; |
| } |
| |
| private void renderItem(final CTabItem item) throws NoRendererFoundException, NoPropertyDescriptorFoundExeption { |
| if (!itemToCategorizationMap.containsKey(item)) { |
| return;/* already rendered or invalid state */ |
| } |
| |
| /* remove from the maps on first rendering */ |
| final VAbstractCategorization categorization = itemToCategorizationMap.remove(item); |
| final Composite composite = itemToCompositeMap.remove(item); |
| final boolean useScrolledContent = useScrolledContent(); |
| |
| AbstractSWTRenderer<VElement> renderer; |
| try { |
| renderer = getEMFFormsRendererFactory().getRendererInstance(categorization, getViewModelContext()); |
| } catch (final EMFFormsNoRendererException ex) { |
| getReportService().report( |
| new StatusReport( |
| new Status(IStatus.INFO, Activator.PLUGIN_ID, String.format( |
| "No Renderer for %s found.", categorization.eClass().getName(), ex)))); //$NON-NLS-1$ |
| return; |
| } |
| final SWTGridDescription gridDescription = renderer.getGridDescription(GridDescriptionFactory.INSTANCE |
| .createEmptyGridDescription()); |
| for (final SWTGridCell gridCell : gridDescription.getGrid()) { |
| final Control render = renderer.render(gridCell, composite); |
| GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true) |
| .applyTo(render); |
| if (useScrolledContent) { |
| final ScrolledComposite scrolledComposite = ScrolledComposite.class.cast(composite); |
| scrolledComposite.setExpandHorizontal(true); |
| scrolledComposite.setExpandVertical(true); |
| scrolledComposite.setContent(render); |
| scrolledComposite.setMinSize(render.computeSize(SWT.DEFAULT, SWT.DEFAULT)); |
| } |
| item.setControl(composite); |
| } |
| } |
| |
| /** |
| * This method gets called when a tab item was selected. Subclasses may call this method when programmatic selection |
| * changes have been made. |
| * |
| * @param selection the selected item |
| * |
| * @since 1.9 |
| */ |
| protected final void itemSelected(CTabItem selection) { |
| try { |
| renderItem(selection); |
| } catch (final NoRendererFoundException ex) { |
| getReportService().report( |
| new StatusReport( |
| new Status(IStatus.INFO, Activator.PLUGIN_ID, String.format( |
| "No Renderer for %s found.", selection.getText(), ex)))); //$NON-NLS-1$ |
| } catch (final NoPropertyDescriptorFoundExeption ex) { |
| getReportService().report( |
| new StatusReport( |
| new Status(IStatus.INFO, Activator.PLUGIN_ID, String.format( |
| "No Renderer for %s found.", selection.getText(), ex)))); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Whether a {@link ScrolledComposite} should be used as the item's content or not. |
| * |
| * @return <code>true</code> if pane should be scrollable, <code>false</code> otherwise |
| * @since 1.9 |
| */ |
| protected boolean useScrolledContent() { |
| return true; |
| } |
| |
| /** |
| * Whether to render all tab items immediately or on selection. |
| * |
| * @return <code>true</code> if the item UI will be rendered on first selection, <code>false</code> if all items |
| * will be rendered immediately |
| * @since 1.9 |
| */ |
| protected boolean renderLazy() { |
| return false; |
| } |
| |
| private Optional<VTTabStyleProperty> getTabStyle() { |
| if (getViewTemplateProvider() == null) { |
| return Optional.empty(); |
| } |
| final Set<VTStyleProperty> styleProperties = getViewTemplateProvider() |
| .getStyleProperties(getVElement(), getViewModelContext()); |
| for (final VTStyleProperty styleProperty : styleProperties) { |
| if (!VTTabStyleProperty.class.isInstance(styleProperty)) { |
| continue; |
| } |
| return Optional.of(VTTabStyleProperty.class.cast(styleProperty)); |
| } |
| return Optional.empty(); |
| } |
| |
| private int getTabFolderStyle() { |
| final Optional<VTTabStyleProperty> tabStyle = getTabStyle(); |
| if (!tabStyle.isPresent()) { |
| return getDefaultFolderStyle(); |
| } |
| final VTTabStyleProperty style = tabStyle.get(); |
| switch (style.getType()) { |
| case BOTTOM: |
| return SWT.BOTTOM; |
| case TOP: |
| return SWT.TOP; |
| default: |
| return getDefaultFolderStyle(); |
| } |
| } |
| |
| private int getDefaultFolderStyle() { |
| return SWT.BOTTOM; |
| } |
| |
| /** |
| * The list of categorizations to display in the tree. |
| * |
| * @return the list of {@link VAbstractCategorization} |
| */ |
| protected abstract EList<VAbstractCategorization> getCategorizations(); |
| |
| @Override |
| protected void applyValidation() { |
| super.applyValidation(); |
| for (final VAbstractCategorization categorization : getCategorizations()) { |
| final VDiagnostic diagnostic = categorization.getDiagnostic(); |
| Image image = null; |
| if (diagnostic != null) { |
| final int highestSeverity = diagnostic.getHighestSeverity(); |
| image = ValidationTabImageHelper.getValidationIcon(getTabStyle(), highestSeverity); |
| } |
| final CTabItem tabItem = categorizationToItemMap.get(categorization); |
| tabItem.setImage(image); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer#dispose() |
| */ |
| @Override |
| protected void dispose() { |
| dataBindingContext.dispose(); |
| super.dispose(); |
| } |
| |
| } |