Skip to content

Content of file AbstractSWTTabRenderer.java

/*******************************************************************************
 * Copyright (c) 2011-2019 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
 * Christian W. Damus - bugs 548592, 552852
 ******************************************************************************/
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); renderer.finalizeRendering(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(); } /** * Reveal the control that renders the given {@code categorization}. * * @param categorization a categorization to reveal * @return whether the {@code categorization} was successfully revealed * * @since 1.22 */ public boolean showCategorization(VAbstractCategorization categorization) { final CTabItem item = categorizationToItemMap.get(categorization); final boolean result = item != null; if (result) { item.getParent().setSelection(item); itemSelected(item); } return result; } }