Papyrus Banner

General Presentation

The Papyrus Table uses the NatTable widget. Its documentation is available http://eclipse.org/nattable/documentation.php?page=getting_started and http://eclipse.org/nattable/documentation.php?page=basics. This kind of table is available since the Papyrus Release 0.10 in June 2013. The NatTable source code can be downloaded with git ( http://git.eclipse.org/gitroot/nattable/org.eclipse.nebula.widgets.nattable.git).

Before continuing reading this document, we advise you to read the Table User documentation.

Papyrus provides tables to edit features of UML Elements. In general, UML Elements are displayed in rows and their features are displayed in columns. These tables can be flat or hierarchical, and they can be filled by the user or synchronized with the context of the table. The Papyrus integration should allow creating a Matrix, but Papyrus does not provide Matrix editors yet.

The Papyrus team created the nattable.ecore metamodel to describe the Tabular editor and to store it. This metamodel (also known as "the table metamodel") is provided by the plugin org.eclipse.papyrus.infra.nattable.model and declares all the elements used to manipulate the table concept. The next simplified diagram shows some key elements and relationships:

  1. NamedStyle
  2. StyledElement
  3. TableConfiguration
  4. Table
  5. IAxis

Table Editor API

In order to make easily the creation, destruction and search for table editors, Papyrus provides helpers to to that (since Papyrus 1.2/Eclispe Neon).

Table Creation

The class org.eclipse.papyrus.infra.nattable.common.api.TableEditorCreationHelper allows you to create a table editor easily, according to some required parameters:

Methods provided by this class :

Table destruction

The class org.eclipse.papyrus.infra.nattable.common.api.TableEditorDeleteHelper.TableEditorDeleteHelper(Table) allows you to create a table editor easily.

Methods provides by this class:

Find existing tables

The class org.eclipse.papyrus.infra.nattable.common.api.TableEditorFinderHelper allows you to find existing table easily. Intanciation of this class requires an EObject of the edited model. Several methods are provides to find a table using one or several of these values:

JUnits for this API

The facilities described previously are tested by the plugin org.eclipse.papyrus.infra.nattable.common.tests.

How to create your own table configuration to edit features of UML Elements

Introduction

This section describes how to create types of tables. We assume that developers have already a good knowledge of the EMF framework. During this tutorial the developer could use any of the two main editors:

We advice to use the Sample Reflective Model Editor because it allows you the load the UML Resource http://www.eclipse.org/uml2/5.0.0/UML which is required to create a new table configuration. However, there are two known problems with EMF editors that developers should keep in mind:

<ownedAxisConfigurations xsi:type="nattableaxisconfiguration:EStructuralFeatureValueFillingConfiguration">
         <listenFeature xsi:type="ecore:EReference" href="../../plugin/org.eclipse.uml2.uml/model/UML.ecore#//Namespace/ownedMember"/>
</ownedAxisConfigurations> 

instead of

<ownedAxisConfigurations xsi:type="nattableaxisconfiguration:EStructuralFeatureValueFillingConfiguration">
         <listenFeature xsi:type="ecore:EReference" href="http://www.eclipse.org/uml2/5.0.0/UML#//Namespace/ownedMember"/>
</ownedAxisConfigurations>

so you should think about checking the file in a Text Editor.

Goal

The aim of this topic is to provide a tutorial for customizing a UML table within Papyrus. The Papyrus Table can be synchronized or not and can be flat or hierarchical. In this tutorial, we will describe the creation of these 3 kinds of tables to edit SysML Block:

Create a new Table Configuration

For this step, first of all, you must to create a new Eclipse Plugin Project, called org.eclipse.papyrus.sysml.nattable.block for this example. In this one, you have to create a new Nattableconfiguration Model file.

As this tutorial is done to create three kinds of tables, please, create three files:

One way to create these files is to use a creation wizard.

Set the kind of table (Flat or Tree)

You must declare a Table Display Style as child of the Table Configuration.

Define the allowed creation context of the table

''Note: Since the implementation of the viewpoint, the tester is not yet called, but it could be better to continue to provide it!''

Click with the right mouse button on the Table Configuration item and create a New Child of type Java Table Tester.

Do these two first steps for each table that we are creating: UMLDnDBlockTable, UMLSynchronizedBlockTable and UMLSynchronizedBlockTreeTable.

 

/*****************************************************************************
 * Copyright (c) 2013 CEA LIST.
 *
 *
 * 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:
 *  Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
 *
 *****************************************************************************/
package org.eclipse.papyrus.sysml.nattable.block.tester;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.papyrus.infra.nattable.tester.ITableTester;
import org.eclipse.papyrus.sysml.blocks.BlocksPackage;
import org.eclipse.papyrus.sysml.nattable.block.Activator;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.util.UMLUtil;

/**
 * The tester used to know if we can create block table
 *
 * @author Vincent Lorenzo
 *
 */
public class BlockTableTester implements ITableTester {

	public IStatus isAllowed(Object context) {
		if (context instanceof Element) {
			Element el = (Element) context;
			boolean result = context instanceof Package ;
			if (result) {
				final String packageQN = UMLUtil.getProfile(BlocksPackage.eINSTANCE, el).getQualifiedName();
				result = result && el.getNearestPackage().getAppliedProfile(packageQN, true) != null;
				if (result) {
					return new Status(IStatus.OK, Activator.PLUGIN_ID, "The context allows to create a Block Table");
				} else {
					return new Status(IStatus.ERROR, Activator.PLUGIN_ID, String.format("The profile {0} is not applied on the model", packageQN));
				}
			}
		}
		return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "The context is not an UML Element");
	}

}

Define Row Header Axis Configuration

Create Row Header Axis Configuration

This object allows to:

Click with the right mouse button on the Table Configuration item and create a New Child of type Table Header Axis Configuration. Once added, define its properties:

Define Label Provider Configuration for Row Label

This object provides the configuration used to display Row Label in the Row Header Label Area. As the rows represent edited object, we will use an Object Label Provider Configuration.

Click with the right mouse button on your new created Table Header Axis Configuration item and create a New Child of type Object Label Provider Configuration. Once added, define its properties:

Add specific configurations

This is in this part than we will configure the paste and the synchronization of our tables.

Define the Paste Configuration

Create a new Paste EObject Configuration as children of your Table Header Axis Configuration. Once created define its properties PasteBlockConfiguration.png

These strings representing the element to paste do not come from the Eclipse UML2 Project. They are provided by Papyrus and used by the Papyrus Service Type. If you create your static profile, you can generate them and use them here. The generation of these elements is described in an other documentation page (TODO (not yet done)).

**********How to generate element id for a given profile**********

*******************************************************************
Paste Configuration for UMLDnDBlockTable and UMLSynchronizedBlockTable

There is nothing to add to the previous description. You should do it in the 2 nattableconfiguration file of these tables

Paste Configuration for UMLSynchronizedBlockTreeTable

The previous description will works fine in a Tree Table but with 2 restrictions :

So you need to complete the Table Header Axis Configuration in your file UMLSynchronizedBlockTreeTable.nattableconfiguration. You must create a new Paste Eobject Configuration for each category listen by the table. The configuration previously created to paste Block could be reused (but you can also duplicate it in your file), so you need to create 2 others Paste Eobject Configuration.

Set these values to paste UML Operation:

Set these values to paste UML Parameter:

Synchronization

In this section, we will describe how to configure the synchronization of your table with the context of the table

UMLDnDBlockTable

There is nothing to do, it is not a synchronized table.

UMLSynchronizedBlockTable

We need to provide a FillingConfiguration to know which feature to listen to fill the table. You must create an EStructural Feature Value Filling Configuration as child of the Table Header Axis Configuration

UMLSynchronizedBlockTreeTable

The Tree table listen several features (at least one be depth). Here, we call these features categories.

If required, you could create an Object Label Configuration instead, but you get less possibilities of configuration (only Display Label, restricited to the name of the object, and Display Icon) instead of the 6 degrees described below.

Create a Feature Label provider Configuration as child of Table Header Axis Configuration, then edit these properties:

This Feature Label Configuration will be referenced by all Tree Filling Configuration created in the next steps.

You must create an IAxis as child of each configuration. For this example, the IAxis must be an EStructural Feature Axis.

You should create one EStructural Feature Axis'' as child of each Tree Filling Configuration''' Once the Axis has been created, set these properties:

Define the Row Manager

Now you need to create an Axis Manager Representation for Rows. You can declare one or several axis manager representation. This element allows to declare the java class to used to manage rows in the table. Moreover, it references the configuration to use for the rows and declare the context of the label provider. Created an Axis Manager Representation item as child of your Table Header Axis Configuration. Once added, define its properties:

UMLDnDBlockTable

  1. Axis Manager Id: org.eclipse.papyrus.sysml.nattable.BlockAxisManager
  2. Header Label Configuration: Your must reference your Object Label Configuration
  3. Label Provider context: org.eclipse.papyrus.infra.nattable.header.labelprovider
  4. Specific Axis Configuration: you must reference your Paste EObject Configuration

Now, you need to create a java class called for example BlockAxisManager. This axis manager must implement org.eclipse.papyrus.infra.nattable.manager.axis.IAxisManager, but we advice you to extends org.eclipse.papyrus.uml.nattable.manager.axis.UMLElementAxisManager.

/*****************************************************************************
 * Copyright (c) 2013 CEA LIST.
 *
 *
 * 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:
 *  Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
 *
 *****************************************************************************/
package org.eclipse.papyrus.sysml.nattable.block.manager.axis;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.gmf.runtime.emf.type.core.IElementMatcher;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.ISpecializationType;
import org.eclipse.papyrus.uml.nattable.manager.axis.UMLElementAxisManager;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.papyrus.sysml.service.types.element.SysMLElementTypes;
import org.eclipse.papyrus.sysml.service.types.matcher.BlockMatcher;

public class BlockAxisManager extends UMLElementAxisManager{

	private static final IElementMatcher matcher = new BlockMatcher();
	
	/**
	 *
	 * @see org.eclipse.papyrus.infra.emf.nattable.manager.axis.EObjectAxisManager#isAllowedContents(java.lang.Object)
	 *
	 * @param object
	 * @return
	 */
	@Override
	public boolean isAllowedContents(Object object) {
		
		boolean res = super.isAllowedContents(object);//check if object is UML Element
		if(res){
			res = matcher.matches((Element)object);
		}
		return res;
	}

	/**
	 *
	 * @see org.eclipse.papyrus.infra.nattable.manager.axis.AbstractAxisManager#canCreateAxisElement(java.lang.String)
	 *
	 * @param elementId
	 * @return
	 */
	@Override
	public boolean canCreateAxisElement(String elementId) {
		return ((ISpecializationType) SysMLElementTypes.BLOCK).getId().equals(elementId);//only blocks can be created in this table
	}

}

Then you should register this class in your plugin.xml file using the extension point : org.eclipse.papyrus.infra.nattable.axismanager.

UMLSynchronizedBlockTable

  1. Axis Manager Id: org.eclipse.papyrus.sysml.nattable.BlockSynchronizedAxisManager
  2. Header Label Configuration: Your must reference your Object Label Configuration
  3. Label Provider context: org.eclipse.papyrus.infra.nattable.header.labelprovider
  4. Specific Axis Configuration: You must reference your EStructural Feature value Configuration and your Paste EObject Configuration.

Now, you need to create a java class, but before, you should add the following dependencies to your plugin (addapt bundle-version to your Papyrus version):

org.eclipse.emf.transaction;bundle-version="1.9.0", org.eclipse.nebula.widgets.nattable.core;bundle-version="1.3.0", org.eclipse.papyrus.infra.emf.nattable;bundle-version="1.1.3", org.eclipse.papyrus.infra.nattable;bundle-version="1.1.3", org.eclipse.papyrus.infra.nattable.model;bundle-version="1.1.3", org.eclipse.papyrus.infra.widgets;bundle-version="1.1.3", org.eclipse.papyrus.uml.nattable;bundle-version="1.1.3", ca.odell.glazedlists;bundle-version="1.9.0"

Now, you can create a java class, called for example BlockSynchronizedAxisManager. This axis manager must implement org.eclipse.papyrus.infra.nattable.manager.axis.IAxisManager, but we advice you to extends org.eclipse.papyrus.uml.nattable.manager.axis.AbstractStereotypedElementUMLSynchronizedOnFeatureAxisManager<T_StereotypeApplication>.

/*****************************************************************************
 * Copyright (c) 2013 CEA LIST.
 *
 *
 * 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:
 *  Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
 *
 *****************************************************************************/
package org.eclipse.papyrus.sysml.nattable.block.manager.axis;

import org.eclipse.gmf.runtime.emf.type.core.ISpecializationType;
import org.eclipse.papyrus.sysml.blocks.Block;
import org.eclipse.papyrus.sysml.blocks.BlocksPackage;
import org.eclipse.papyrus.sysml.service.types.element.SysMLElementTypes;
import org.eclipse.papyrus.uml.nattable.manager.axis.AbstractStereotypedElementUMLSynchronizedOnFeatureAxisManager;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.util.UMLUtil;

public class BlockSynchronizedAxisManager extends
		AbstractStereotypedElementUMLSynchronizedOnFeatureAxisManager<Block> {

	/**
	 *
	 * @see org.eclipse.papyrus.infra.nattable.manager.axis.AbstractAxisManager#canCreateAxisElement(java.lang.String)
	 *
	 * @param elementId
	 * @return
	 */
	@Override
	public boolean canCreateAxisElement(String elementId) {
		return ((ISpecializationType) SysMLElementTypes.BLOCK).getId().equals(elementId);
	}


	/**
	 *
	 * @see org.eclipse.papyrus.uml.nattable.manager.axis.AbstractStereotypedElementUMLSynchronizedOnFeatureAxisManager#getStereotypeApplication(org.eclipse.uml2.uml.Element)
	 *
	 * @param el
	 * @return
	 */
	@Override
	protected Block getStereotypeApplication(Element el) {
		return UMLUtil.getStereotypeApplication(el, Block.class);
	}

	/**
	 *
	 * @see org.eclipse.papyrus.uml.nattable.manager.axis.AbstractStereotypedElementUMLSynchronizedOnFeatureAxisManager#isInstanceOfRequiredStereotypeApplication(java.lang.Object)
	 *
	 * @param object
	 * @return
	 */
	@Override
	protected boolean isInstanceOfRequiredStereotypeApplication(final Object object) {
		return object instanceof Block;
	}

	/**
	 *
	 * @see org.eclipse.papyrus.uml.nattable.manager.axis.AbstractStereotypedElementUMLSynchronizedOnFeatureAxisManager#getStereotypeBaseElement(org.eclipse.emf.ecore.EObject)
	 *
	 * @param stereotypeApplication
	 * @return
	 */
	@Override
	protected Element getStereotypeBaseElement(final Block stereotypeApplication) {
		return stereotypeApplication.getBase_Class();
	}

	/**
	 *
	 * @see org.eclipse.papyrus.uml.nattable.manager.axis.AbstractStereotypedElementUMLSynchronizedOnFeatureAxisManager#isAllowedAsBaseElement(org.eclipse.uml2.uml.Element)
	 *
	 * @param element
	 * @return
	 */
	@Override
	protected boolean isAllowedAsBaseElement(final Element element) {
		return element instanceof  org.eclipse.uml2.uml.Class;
	}


	/**
	 *
	 * @see org.eclipse.papyrus.uml.nattable.manager.axis.AbstractStereotypedElementUMLSynchronizedOnFeatureAxisManager#getStereotypeApplicationBasePropertyName()
	 *
	 * @return
	 */
	@Override
	protected String getStereotypeApplicationBasePropertyName() {
		return BlocksPackage.eINSTANCE.getBlock_Base_Class().getName();
	}
}


Then you should register this class in your plugin.xml file using the extension point : org.eclipse.papyrus.infra.nattable.axismanager. See the description done for UMLDnDBlockTable

UMLSynchronizedBlockTreeTable

  1. Axis Manager Id: org.eclipse.papyrus.sysml.nattable.BlockTreeAxisManager
  2. Header Label Configuration: Your must reference your Object Label Configuration
  3. Label Provider context: org.eclipse.papyrus.infra.nattable.header.labelprovider
  4. Specific Axis Configuration : you must reference your Paste EObject Configuration allowing to paste Block and all your Tree Filling Configuration.

Now, you need to create a java class called for example BlockSynchronizedTreeAxisManager. This axis manager must implement org.eclipse.papyrus.infra.nattable.manager.axis.ITreeItemAxisManagerForEventList but we advice you to extend org.eclipse.papyrus.uml.nattable.manager.axis.UMLElementTreeAxisManagerForEventList

/*****************************************************************************
 * Copyright (c) 2013 CEA LIST.
 *
 *
 * 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:
 *  Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
 *
 *****************************************************************************/
package org.eclipse.papyrus.sysml.nattable.block.manager.axis;

import org.eclipse.gmf.runtime.emf.type.core.IElementMatcher;
import org.eclipse.papyrus.sysml.service.types.matcher.BlockMatcher;
import org.eclipse.papyrus.uml.nattable.manager.axis.UMLElementTreeAxisManagerForEventList;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.Property;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattableaxisconfiguration.TreeFillingConfiguration;

public class BlockTreeAxisManagerForEventList extends
		UMLElementTreeAxisManagerForEventList {

	private static final IElementMatcher matcher = new BlockMatcher();

	/**
	 * 
	 * @see org.eclipse.papyrus.uml.nattable.manager.axis.UMLElementTreeAxisManagerForEventList#isAllowedContents(java.lang.Object,
	 *      java.lang.Object,
	 *      org.eclipse.papyrus.infra.nattable.model.nattable.nattableaxisconfiguration.TreeFillingConfiguration,
	 *      int)
	 *
	 * @param objectToTest
	 * @param semanticParent
	 * @param conf
	 * @param depth
	 * @return
	 */
	@Override
	public boolean isAllowedContents(Object objectToTest,
			Object semanticParent, TreeFillingConfiguration conf, int depth) {
		if (!(objectToTest instanceof Element)) {
			return false;
		}

		if (depth == 0) {
			return matcher.matches((Element) objectToTest);
		}
		if (depth == 1) {
			return objectToTest instanceof Operation;
		}
		if (depth == 2) {
			return objectToTest instanceof Parameter;
		}

		return false;
	}

	@Override
	public boolean canCreateAxisElement(String elementId) {
		// currently, we can't filter create by level in the table -> it is a
		// bug...
		return super.canCreateAxisElement(elementId);
	}

}


Then you should register this class in your plugin.xml file using the extension point : org.eclipse.papyrus.infra.nattable.axismanager. See the description done for UMLDnDBlockTable

Define Column Header Axis Configuration

Create Column Header Axis Configuration

This step is the same to build the 3 tables : UMLDnDBlockTable, UMLSynchronizedBlockTable and UMLSynchronizedBlockTreeTable.

This object allows to:

Click with the right mouse button on the Table Configuration item and create a New Child of type Column Header Axis Configuration Table Header Axis Configuration. Once added, define its properties:

Define Label Provider Configuration for Column Label

This step is the same to build the 3 tables : UMLDnDBlockTable, UMLSynchronizedBlockTable and UMLSynchronizedBlockTreeTable.

This object provides the configuration used to display Column Label in the Column Header Label Area. As the rows represent edited object, we will use a Feature Label Provider Configuration. Click with the right mouse button on your new created Table Header Axis Configuration item and create a New Child of type Feature Label Provider Configuration. Once added, define its properties:

Define the Column Manager

This step is the same to build the 3 tables : UMLDnDBlockTable, UMLSynchronizedBlockTable and UMLSynchronizedBlockTreeTable.

This element allows to declare the java class to used to manage rows in the table. Moreover, it references the configuration to use for the columns and declare the context of the label provider. Here, you need to create two Axis Manager Representation to manage columns. The first one will be used to managed UML features and the second one will be used to manage properties of stereotypes applied on the row elements. Click with the right mouse button on your Table Header Axis Configuration item and create a New Child of type Axis Manager Representation. Once added, define its properties:

And again, create a second New Child of type Axis Manager Representation. Once added, define its properties:

Define Row Provider

This step is the same to build the 3 tables : UMLDnDBlockTable, UMLSynchronizedBlockTable and UMLSynchronizedBlockTreeTable.

The row provider is the object used to store the axis (here the rows) visible in the table. In case of synchronized table. It always be empty. It exists 2 kinds of provider : Master and Slave. For rows, we must take a Master. Click with the right mouse button on the Table Configuration item and create a New Child of type Row Axis Providers Master Object Axis Provider. Once added, define its properties:

Define Column Provider

This step is the same to build the 3 tables : UMLDnDBlockTable, UMLSynchronizedBlockTable and UMLSynchronizedBlockTreeTable.

The column provider is the object used to store the column axis visible in the table. Here, we will take a Slave Axis Provider. Click with the right mouse button on the Table Configuration item and create a New Child of type Column Axis Providers Slave Object Axis Provider. Once added, define its properties:

Define the default columns for your table

Now you should declare here the default columns for your table.

Define the Name Column

Click with the right mouse button on your new created Slave Object Axis Provider item and create a New Child of type EStructural Feature Axis to define. Once added, define its properties:

Define the IsEncapsulated Column

IsEncapsulated is a property of stereotype, so you can not reference directly it. The table framework allows you to reference it using its qualified name. Click with the right mouse button on your new created Slave Object Axis Provider item and create a New Child of type Feature Id Axis. Once added, define its properties:

Configure Table Configuration

This is the last step concerning the edition of the nattableconfiguration. Select the root of the model, that is to say the object Table Configuration, to set its properties:

UMLDnDBlockTable

UMLSynchronizedBlockTable

UMLSynchronizedBlockTreeTable

How to hide categories in the TableConfiguration File

Register your new table configuration into Papyrus framework

Register your nattable configuration file

Each Table Configuration File created previously must contribute to the Papyrus Extension Point org.eclipse.papyrus.infra.nattable.configuration. This extension point allows to contribute to the Table Configuration Catalogue provided by the Papyrus Framework.

UMLDnDBlockTable

UMLSynchronizedBlockTable

UMLSynchronizedBlockTreeTable

Contribute to Viewpoint Framework

Please, see Viewpoint documentation embedded in Eclipse.

This part is the same for the 3 kind of tables previously created. Here we choose to explain the viewpoint configuration for the UMLDnDBlockTable table. You should adapt this documentation to your usecase.

For this step, first of all, you have to create a new Viewpoints configuration in your plugin. Create the file UMLDnDBlockTableViewpoint.configuration.

Contribute to the Default Papyrus Viewpoint

Using this way, you will able to contribute to the default Papyrus Viewpoint.

Once you have finish to edit the configuration, you must register it using the extension point org.eclipse.papyrus.infra.viewpoints.policy.custom.

Contribute to a new Viewpoint for UML

Using this way, you will be able to create your own Viewpoint. This is basically the same things, excepted for these points:

  1. you must create your own stakeholder
  2. you must contribute to the extension point using configuration instead of contribution

Once you have finish to edit the configuration, you must register it using the extension point org.eclipse.papyrus.infra.viewpoints.policy.custom.

Once your new plugin deployed, in your >Eclipse Runtime, you must go into The Eclipse Preferences -> Papyrus -> Viewpoints Configuration

Result

Creating a new Block Table

You can create the Block Table directly under a package:

Synchronization between table and model

The illustration of the table sychronization when a block is added or removed:

After added Block2

Affter removed Block1

Contribute to creation menu with a new Papyrus Table (must be completed)

The contribution must be done using viewpoint with a file .configuration. The viewpoint metamodel provides 2 ways to register new tables. the first one used the Element Papyrus Sync Table. You must fill the field :

Then you can declare Rules to allow/forbid the creation of the table according to the selected element

The second way with viewpoint using Papyrus Table element In this case you must fill the field configuration with the path of your table configuration file.

Label Providers

For the label provider, we divided the tables into 2 areas :

  1. Headers
  2. Body

for each areas we declared a label provider context (using the Papyrus Label Provider extension point):

  1. org.eclipse.papyrus.infra.nattable.full.labelprovider : the context to use to find the label provider used in the table. This one calls the others label providers according to the region for which we are looking for the text/image to display.
  2. org.eclipse.papyrus.infra.nattable.body.labelprovider : the context to use to find the label provider used to get the text in the body of the table
  3. org.eclipse.papyrus.infra.nattable.header.labelprovider : the context to use to find the label provider used to get the text in the header of the table (display icon, display label)
  4. org.eclipse.papyrus.infra.nattable.header.feature.labelprovider : the context to use to find the label provider used to display feature in a header. This label provider allows to define the text to display according to the configuration of the axis ( display icon, display label, display multiciplicity, display type, display a "/" for the derived feature)

These contexts are declared into the plugin org.eclipse.papyrus.infra.nattable.

All label provider declared on these context must accept elements implementing ILabelProviderCellContextElement. This object encapsulate the cell for which we want display a text AND useful elements which can be used to define the text/image/color/... to display in the cell.

Papyrus Extension Point For Table :

  1. Axis Manager
  2. Cell Manager
  3. Cell Editor Configuration

Selection synchronization

Some changes have been applied to the code in order to allow a selection synchronization between the tables and the model explorer. The affected classes are the following :

<I>In these changes, IRevealSemanticElement and its associated method revealSemanticElement is at the core of the modifications. </I>

Modifying the graphical representation of the tables

Resizing Axis and Headers

Three listeners have been added to the AbstractNattableWidgetManager class in order to capture the graphical changes and edit the model.

  1. addAxisResizeListener(final BodyLayerStack bodyLayerStack) that listens to the BodyLayerStack
  2. addColumnHeaderResizeListener(final ColumnHeaderLayerStack columnHeaderLayerStack) that listens to the ColumnHeaderLayerStack
  3. addRowHeaderResizeListener(final RowHeaderLayerStack rowHeaderLayerStack) that listens to the RowHeaderLayerStack

Those methods verify the model in order to know if the graphical values are already present and if not create them and write them using a CompositeCommand and executing it.

The major change introduced in order to accomplish this is the modification of the table's model by adding new Styles, more particularly intValueStyles that are used to carry this specific information. These styles are introduced in the Axis elements, if the changes of size modify axis, or to a newly, or existing, LocalHeaderAxisConfiguration if the changes modify headers. Of course, both of them are now StyledElements and therefore can call on the method <I>getNamedStyle()</I>.

Two init methods will also be called when refreshing or opening the table in order to show the modified table.

  1. initTableAxis() that gets the list of the displayed axis and check their styles
  2. initTableHeaders() that gets the AbstractHeaderAxisConfigurationUsedInTable, allowing the method to get around the invertAxis configuration, and check their styles

Both have a default behavior, in case no styles were attached to an element, to apply its default size to its graphical representation.

Merging cells inside their Axis

The merge is based on nebula's <I>AutomaticSpanningDataProvider</I> (org.eclipse.nebula.widgets.nattable.data.AutomaticSpanningDataProvider) allowing us to apply a spanProvider to the table's BodyLayerStack and, with minor modification of the method <I>valuesNotEqual()</I>, triggering the desired span (i.e. merge) throughout the layer. It is to be noted that the cells are merged using their values and not their types.

To accomplish this four new merge handlers were created, piloted by a menu constituted of exclusive choices.

  1. org.eclipse.papyrus.infra.nattable.handler.MergeColumnsHandler
  2. org.eclipse.papyrus.infra.nattable.handler.MergeRowsHandler
  3. org.eclipse.papyrus.infra.nattable.handler.MergeSelectedRowsHandler
  4. org.eclipse.papyrus.infra.nattable.handler.MergeSelectedColumnsHandler

The handlers' model modification behavior are similar to the resize listeners' one, where the style's value is researched in the model and created, or modified, depending on the case, set inside a CompositeCommand and executed inside the core AbstractMergeHandler. The merge boolean will then be carried by the LocalHeaderAxisConfiguration if the user chose to merge all the columns/rows inside the table or by the Axis if the user chose to merge only selected Axis.

To access these handlers, new extensions have been added in the form of a new menu to call on the handlers and a property tester to check the availability of the menu's options or not depending on the merge state of the table; and to update the toggles of each menu, new <I>updateToggleCommandState()</I> have also been added to NattableModelManager, calling on the <I>getToggleState[...]()</I> methods in AbstractNattableManager.

One init method and two Listeners, one for the resourceSet and another for the Layer, are used to update the graphical view throughout the changes.

  1. initTableMerge() in wich the list of the displayed axis is obtained and their styles checked
  2. resourceSetListener inside the <I>updateCellMap()</I> method in which the notifications due to the modification of the resourceSet are filtered to keep the styles we want to apply or unapply, depending on the user's choices, and enable the use of the undo/redo behavior

Editing merged cells

A PapyrusSpanningDataLayer has been added and @Overrides the setDataValue of nebula's <I>org.eclipse.nebula.widgets.nattable.layer.SpanningDataLayer#setDataValue(int, int, java.lang.Object)</I> to allow the edition of multiple cells inside a merged selection.

The edition will then verify if the value to be inputted can indeed be, see <I>org.eclipse.papyrus.infra.nattable.manager.cell.AbstractCellManager.setValue()</I>, and edit the cell accordingly. Of course, the merge selection is updated after this so that, inside a previuosly merged selection, only the cells of equal values are still merged.

What is the difference between Slave and Master for AxisManager/AxisProvider

We decided to introduce a difference between the Axis Manager used in the Table. There is Slave and Master.

Master/Slave configuration

For the tables which present an axis with Object (Rows) and an Axis with Features (Columns), like in UML Generic Table, the row axis provider is a Master and the Column axis provider is the slave. Its means that the the column axis manager provides elements which depends on the elements provided by the rows axis. For UML Table, the columns axis provides the features for the object displayed as rows in the table.

As you can declare several AxisManagers for rows and several AxisManager for columns, we store them in CompositeAxisManager. So you must have a CompositeAxisManager Master for rows and a CompositeAxisManager slave for columns. You can mix Master and Slave Axis Manager in a CompositeAxisManager.

Master/Master configuration

In case of Matrix, the Rows and the Columns Axis Manager must be master, because the twice provide Object.

What is the difference between AxisManagerRepresentation and AxisManagerConfiguration?

AxisManagerRepresentation

The axis manager representation provide the default configuration for an axis manager in the TableConfiguration. This object contains the following field:

AxisManagerConfiguration

Filters

The filters are located at the bottom of the Column Header.

In Papyrus, you can get cells displaying N/A, it means than the columns is not available for the row element owning this cell. That's why declaring your own filter, you must think to manage this specific value. Moreover, if you declare a specific comparator in your filter configuration, it should returns the value org.eclipse.papyrus.infra.nattable.filter.FilterPreferences.INCONSISTENT_VALUE when the value in the cell is inconsistent vs the filter value. This specific returns will be used, according to the preference obtained with org.eclipse.papyrus.infra.nattable.filter.FilterPreferences.displayInconsistentValueWithFilter(Table) to show/hide the rows with inconsistent values.

How to activate filters

To activate filter by default for your table, in your nattableconfiguration file, you must select your Table Header Axis Configuration used for columns and set the value Display Filter to true.

How to declare your own filter

In your plugin.xml file, you must contribute to the Papyrus Extension Point org.eclipse.papyrus.infra.nattable.filter.configuration. You must fill the 2 fields of the extension:

The interface IFilterConfiguration provides 4 methods:

In the method configureFilter you can configure several elements, using these keys:

Example to filter EEnumLiteral

This example will allow you to filter EEnumLiteral ( http://www.eclipse.org/uml2/5.0.0/UML#//NamedElement/visibility for example)

/*****************************************************************************
 * Copyright (c) 2015 CEA LIST 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:
 *   CEA LIST - Initial API and implementation
 *   
 *****************************************************************************/

package org.eclipse.papyrus.infra.emf.nattable.filter.configuration;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.data.IColumnAccessor;
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor;
import org.eclipse.nebula.widgets.nattable.filterrow.combobox.FilterRowComboBoxCellEditor;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.papyrus.infra.nattable.dataprovider.ListComboBoxDataProvider;
import org.eclipse.papyrus.infra.nattable.filter.IFilterValueToMatchManager;
import org.eclipse.papyrus.infra.nattable.filter.IPapyrusMatcherEditorFactory;
import org.eclipse.papyrus.infra.nattable.filter.configuration.AbstractFilterValueToMatchManager;
import org.eclipse.papyrus.infra.nattable.filter.configuration.IFilterConfiguration;
import org.eclipse.papyrus.infra.nattable.manager.cell.ICellManager;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattableaxis.IAxis;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.NamedStyle;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.NattablestyleFactory;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.NattablestylePackage;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.StringListValueStyle;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.StringValueStyle;
import org.eclipse.papyrus.infra.nattable.utils.AxisUtils;
import org.eclipse.papyrus.infra.nattable.utils.NattableConfigAttributes;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.matchers.MatcherEditor;

/**
 * Filter configuration for eenum filter
 *
 */
public class EEnumFilterCellEditorFilterConfiguration implements IFilterConfiguration {

	/**
	 * the id of this editor
	 */
	private static final String ID = "org.eclipse.papyrus.infra.emf.nattable.eenum.checkboxcombo.with.NA";//$NON-NLS-1$

	/**
	 * @see org.eclipse.papyrus.infra.nattable.filter.configuration.IFilterConfiguration#handles(org.eclipse.nebula.widgets.nattable.config.IConfigRegistry, java.lang.Object)
	 *
	 * @param registry
	 * @param columnElement
	 * @return
	 */
	@Override
	public boolean handles(IConfigRegistry registry, Object columnElement) {
		Object representedElement = AxisUtils.getRepresentedElement(columnElement);
		if (representedElement instanceof EStructuralFeature) {
			EClassifier eType = ((EStructuralFeature) representedElement).getEType();
			return eType instanceof EEnum;
		}
		return false;
	}

	/**
	 * 
	 * @param axis
	 *            an axis
	 * @return
	 *         a list containing the possible Enumerator for the axis
	 */
	protected List<Enumerator> getLiteral(IConfigRegistry configRegistry, Object axis) {
		Object representedElement = AxisUtils.getRepresentedElement(axis);
		final List<Enumerator> literals = new ArrayList<Enumerator>();
		if (representedElement instanceof EStructuralFeature) {
			EClassifier eType = ((EStructuralFeature) representedElement).getEType();
			Assert.isTrue(eType instanceof EEnum);
			EEnum eenum = (EEnum) eType;
			for (EEnumLiteral current : eenum.getELiterals()) {
				literals.add(current.getInstance());
			}
		}
		return literals;
	}


	/**
	 * @see org.eclipse.papyrus.infra.nattable.filter.configuration.IFilterConfiguration#configureRegistry(org.eclipse.nebula.widgets.nattable.config.IConfigRegistry, java.lang.Object, java.lang.String)
	 *
	 * @param configRegistry
	 * @param columnElement
	 * @param configLabel
	 */
	@Override
	public void configureFilter(IConfigRegistry configRegistry, final Object columnElement, String configLabel) {
		List<Enumerator> literals = getLiteral(configRegistry, columnElement);
		final List<Object> valuesToProposed = new ArrayList<Object>(literals);

		valuesToProposed.add(0, ICellManager.NOT_AVALAIBLE);

		ICellEditor editor = new FilterRowComboBoxCellEditor(new ListComboBoxDataProvider(valuesToProposed));
		IPapyrusMatcherEditorFactory<Object> factory = new IPapyrusMatcherEditorFactory<Object>() {

			@Override
			public EventList<MatcherEditor<Object>> instantiateMatcherEditors(IColumnAccessor<Object> columnAccessor, Integer columnIndex, Object wantedValue, IConfigRegistry configRegistry) {
				EventList<MatcherEditor<Object>> list = new BasicEventList<MatcherEditor<Object>>();
				list.add(new EnumeratorMatcherEditor(columnAccessor, columnIndex, wantedValue, configRegistry));
				return list;
			}
		};

		configRegistry.registerConfigAttribute(NattableConfigAttributes.MATCHER_EDITOR_FACTORY, factory, DisplayMode.NORMAL, configLabel);
		configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, editor, DisplayMode.NORMAL, configLabel);
		configRegistry.registerConfigAttribute(NattableConfigAttributes.FILTER_VALUE_TO_MATCH_MANAGER, createFilterValueToMatchManager(getConfigurationId(), literals), DisplayMode.NORMAL, configLabel);

	}

	/**
	 * 
	 * @param filterConfiguration
	 *            the id of the filter configuration used for the managed axis
	 * @param literals
	 *            the available literals
	 * @return
	 *         the filter value manager for the managed axis
	 */
	protected IFilterValueToMatchManager createFilterValueToMatchManager(String filterConfiguration, List<Enumerator> literals) {
		return new EnumeratorFilterValueToMatchManager(filterConfiguration, literals);
	}

	/**
	 * 
	 * 
	 * @see org.eclipse.papyrus.infra.nattable.filter.configuration.IFilterConfiguration#getConfigurationId()
	 *
	 * @return
	 */
	@Override
	public String getConfigurationId() {
		return ID;
	}

	/**
	 * @see org.eclipse.papyrus.infra.nattable.filter.configuration.IFilterConfiguration#getConfigurationDescription()
	 *
	 * @return
	 */
	@Override
	public String getConfigurationDescription() {
		return "This configuration provides a combo with checkbox to filter EEnum, with N/A value"; //$NON-NLS-1$
	}

	/**
	 * 
	 * This class allows to save the state of the filter for column typed with enumeration
	 *
	 */
	public static class EnumeratorFilterValueToMatchManager extends AbstractFilterValueToMatchManager {
	
		/**
		 * a list with the available literal
		 */
		protected final List<Enumerator> literals;
	
		/**
		 * Constructor.
		 *
		 * @param filterConfigurationId
		 *            the id of the filter configuration used by the axis
		 * @param literals
		 *            the available literals
		 */
		public EnumeratorFilterValueToMatchManager(String filterConfigurationId, List<Enumerator> literals) {
			super(filterConfigurationId);
			this.literals = literals;
		}
	
	
		/**
		 * @see org.eclipse.papyrus.infra.nattable.filter.IFilterValueToMatchManager#getValueToMatch(org.eclipse.nebula.widgets.nattable.config.IConfigRegistry, java.lang.Object)
		 *
		 * @param configRegistry
		 * @param axis
		 * @return
		 */
		@Override
		public Object getValueToMatch(IConfigRegistry configRegistry, Object axis) {
			if (!(axis instanceof IAxis)) {
				return null;
			}
			IAxis iaxis = (IAxis) axis;
			NamedStyle style = getValueToMatchStyle(iaxis);
			if (style != null) {
				if (style instanceof StringListValueStyle) {
					List<Object> returnedValues = new ArrayList<Object>();
					Collection<String> coll = ((StringListValueStyle) style).getStringListValue();
					for (String string : coll) {
						if (string.equals(ICellManager.NOT_AVALAIBLE)) {
							returnedValues.add(ICellManager.NOT_AVALAIBLE);
						} else {
							for (Enumerator tmp : literals) {
								if (tmp.getName().equals(string)) {
									returnedValues.add(tmp);
									continue;
								}
							}
						}
					}
					return returnedValues;
				}
				if (style instanceof StringValueStyle) {
					String val = ((StringValueStyle) style).getStringValue();
					if (val.equals(ICellManager.NOT_AVALAIBLE)) {
						return ICellManager.NOT_AVALAIBLE;
					}
					for (Enumerator tmp : literals) {
						if (tmp.getName().equals(val)) {
							return tmp;
						}
					}
				}
			}
			return null;
		}
	
		/**
		 * @see org.eclipse.papyrus.infra.nattable.filter.configuration.AbstractFilterValueToMatchManager#getSaveValueToMatchCommand(org.eclipse.emf.transaction.TransactionalEditingDomain, org.eclipse.nebula.widgets.nattable.config.IConfigRegistry,
		 *      java.lang.Object, java.lang.Object)
		 *
		 * @param domain
		 * @param configRegistry
		 * @param axis
		 * @param newValue
		 * @return
		 */
		@Override
		protected Command getSaveValueToMatchCommand(TransactionalEditingDomain domain, IConfigRegistry configRegistry, Object axis, Object newValue) {
			if (!(axis instanceof IAxis)) {
				return null;
			}
			IAxis iaxis = (IAxis) axis;
			CompoundCommand cc = new CompoundCommand("Save Value To Match Command"); //$NON-NLS-1$
			NamedStyle keyStyle = getValueToMatchStyle(iaxis);
			if (newValue instanceof Collection<?>) {
				Collection<?> coll = (Collection<?>) newValue;
				// we need to update the keystyle
				if (keyStyle != null && !(keyStyle instanceof StringListValueStyle)) {
					// we need to destroy the previous keystyle
					Command cmd = getDestroyFilterValueToMatchCommand(domain, configRegistry, axis);
					if (cmd != null && cmd.canExecute()) {
						cc.append(cmd);
					}
				}
				if (keyStyle == null) {
					keyStyle = NattablestyleFactory.eINSTANCE.createStringListValueStyle();
					keyStyle.setName(FILTER_VALUE_TO_MATCH);
					cc.append(AddCommand.create(domain, iaxis, NattablestylePackage.eINSTANCE.getNamedStyle(), keyStyle));
				}
	
				List<String> values = new ArrayList<String>();
				for (Object tmp : coll) {
					Assert.isTrue(tmp instanceof Enumerator || ICellManager.NOT_AVALAIBLE.equals(tmp));
					if (tmp instanceof Enumerator) {
						values.add(((Enumerator) tmp).getName());
					} else {
						values.add(ICellManager.NOT_AVALAIBLE);
					}
				}
				cc.append(SetCommand.create(domain, keyStyle, NattablestylePackage.eINSTANCE.getStringListValueStyle_StringListValue(), values));
			} else {
				if (keyStyle != null && !(keyStyle instanceof StringValueStyle)) {
					// we need to destroy the previous keystyle
					Command cmd = getDestroyFilterValueToMatchCommand(domain, configRegistry, axis);
					if (cmd != null && cmd.canExecute()) {
						cc.append(cmd);
					}
				}
				if (keyStyle == null) {
					keyStyle = NattablestyleFactory.eINSTANCE.createEObjectValueStyle();
					keyStyle.setName(FILTER_VALUE_TO_MATCH);
					cc.append(AddCommand.create(domain, iaxis, NattablestylePackage.eINSTANCE.getNamedStyle(), keyStyle));
				}
				Assert.isTrue(newValue instanceof Enumerator || ICellManager.NOT_AVALAIBLE.equals(newValue));
				// we store the name of the literal and a reference to the literal, for 2 reasons :
				// - for static profile we get enumerator and not EEnumLiteral
				// - in case of redefinition of the profile, the reference would be not correct
				String name;
				if (newValue instanceof Enumerator) {
					name = ((Enumerator) newValue).getName();
				} else {
					name = ICellManager.NOT_AVALAIBLE;
				}
				cc.append(SetCommand.create(domain, keyStyle, NattablestylePackage.eINSTANCE.getStringValueStyle_StringValue(), name));
			}
			return cc;
		}
	
	}
}


In the previous class, we declare:

/*****************************************************************************
 * Copyright (c) 2015 CEA LIST 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:
 *   CEA LIST - Initial API and implementation
 *   
 *****************************************************************************/

package org.eclipse.papyrus.infra.emf.nattable.filter.configuration;

import java.util.Collection;

import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.data.IColumnAccessor;
import org.eclipse.papyrus.infra.nattable.filter.AbstractPapyrusMatcherEditor;
import org.eclipse.papyrus.infra.nattable.filter.AbstractSinglePapyrusMatcher;

import ca.odell.glazedlists.matchers.Matcher;

/**
 * Matcher Editor for UML Enumeration
 *
 */
public class EnumeratorMatcherEditor extends AbstractPapyrusMatcherEditor {

	/**
	 * 
	 * Constructor.
	 *
	 * @param columnAccesor
	 * @param columnIndex
	 * @param matchOn
	 * @param configRegistry
	 */
	public EnumeratorMatcherEditor(IColumnAccessor<Object> columnAccesor, int columnIndex, Object matchOn, IConfigRegistry configRegistry) {
		super(columnAccesor, columnIndex, matchOn, configRegistry);
	}

	/**
	 * @see org.eclipse.papyrus.infra.nattable.filter.AbstractPapyrusMatcherEditor#createMatcher(org.eclipse.nebula.widgets.nattable.data.IColumnAccessor, int, java.lang.Object, org.eclipse.nebula.widgets.nattable.config.IConfigRegistry)
	 *
	 * @param columnAccesor
	 * @param columnIndex
	 * @param matchOn
	 * @param configRegistry
	 * @return
	 */
	@Override
	protected Matcher<Object> createMatcher(IColumnAccessor<Object> columnAccesor, int columnIndex, Object matchOn, IConfigRegistry configRegistry) {
		return new EnumeratorMatcher(columnAccesor, matchOn, columnIndex, configRegistry);
	}

	/**
	 * This Matcher allows to know is an object is displayed in a cell
	 *
	 */
	public static class EnumeratorMatcher extends AbstractSinglePapyrusMatcher<Object> {

		/**
		 * Constructor.
		 *
		 * @param accessor
		 * @param wantedObject
		 * @param columnIndex
		 * @param configRegistry
		 */
		public EnumeratorMatcher(IColumnAccessor<Object> accessor, Object wantedObject, int columnIndex, IConfigRegistry configRegistry) {
			super(accessor, columnIndex, wantedObject, configRegistry);
		}

		/**
		 * Constructor.
		 *
		 * @param accessor
		 * @param wantedObject
		 * @param columnIndex
		 */
		public EnumeratorMatcher(IColumnAccessor<Object> accessor, Object wantedObject, int columnIndex) {
			super(accessor, columnIndex, wantedObject);
		}

		/**
		 * @see ca.odell.glazedlists.matchers.Matcher#matches(java.lang.Object)
		 *
		 * @param item
		 * @return
		 */
		@Override
		public boolean matches(Object item) {
			Object res = getColumnAccessor().getDataValue(item, getColumnIndex());
			if (res != null) {
				Object wantedObject = getObjectToMatch();
				String stringToMatch = null;
				if (wantedObject instanceof String) {
					stringToMatch = (String) wantedObject;
				} else {
					stringToMatch = ((Enumerator) wantedObject).getName();
				}
				if (res instanceof Collection<?>) {
					for (Object tmp : (Collection<?>) res) {
						if (tmp instanceof Enumerator) {
							Enumerator lit = (Enumerator) tmp;
							if (stringToMatch.equals(lit.getName())) {
								return true;
							}
						} else {
							if (stringToMatch.equals(tmp)) {
								return true;
							}
						}
					}
				}
				if (res instanceof Enumerator) {
					return stringToMatch.equals(((Enumerator) res).getName());
				}
				return stringToMatch.equals(res);
			}
			return false;
		}
	}

}


Available Filter cell Editors

You can declare several kinds of editors for filters:

So, to configure filter using a text cell editor, you should extends the class org.eclipse.papyrus.infra.nattable.filter.configuration.TextEditorFilterConfiguration. To configure integer comparison, with a text editor, you should look the class org.eclipse.papyrus.infra.nattable.filter.configuration.AbstractIntegerEditorFilterConfiguration. In this class and its subclasses, in the method org.eclipse.papyrus.infra.nattable.filter.configuration.TextEditorFilterConfiguration.configureFilter(IConfigRegistry, Object, String):

Comparator used by filter

If you need to declare your own comparator and you extend org.eclipse.papyrus.infra.nattable.filter.configuration.TextEditorFilterConfiguration.configureFilter(IConfigRegistry, Object, String), you should know these points.

Filter Strategy

How to define columns sorted by default

Since Papyrus 5.0, it is possible to define column which will be sorted by default. In order to do that, you must select the axis to sorted in your TableConfiguration file, then

Example

To sort the rows by alphabetic order according to the value of 2 columns A and B. You want to start the sort with the values of column A, then continuing the sort with the values of column B when the values of A are equals. To obtain this behavior, you need to define:

Sort configuration for column A

Sort configuration for column B

How does it works?

Cell Editor

Papyrus table provides several kinds of cell editors, for example, editors for ValueSpecification and UML NamedElement:

How to declare a new Cell Editor

In your plugin.xml file, you must contribute to the extension point org.eclipse.papyrus.infra.nattable.celleditor.configuration, providing a cellAxisConfiguration. Note: configuration is deprecated and must not be used. This extension point has two fields :

Now you should create the java class, 4 methods must be implemented :

you should add these dependencies in your Manifest (adapt bundle-version to your Papyrus version):

org.eclipse.papyrus.infra.nattable;bundle-version="1.2.0", org.eclipse.papyrus.infra.nattable.model;bundle-version="1.2.0", org.eclipse.nebula.widgets.nattable.core;bundle-version="1.3.0"

The only way to restrict your cell editor to a kind of table is your implementation of the method ICellAxisConfiguration#handles(Table table, Object axisElement). There is not yet a way to force the usage of given cell editor in a nattable configuration file.

Example of code used in Papyrus:

<source lang="java" collapse=true>

/*****************************************************************************

* Copyright © 2015 CEA LIST 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:
*   CEA LIST - Initial API and implementation
*   
*****************************************************************************/

package org.eclipse.papyrus.infra.emf.nattable.celleditor.config;

import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EEnum; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes; import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; import org.eclipse.nebula.widgets.nattable.data.convert.DisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.IDisplayConverter; import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes; import org.eclipse.nebula.widgets.nattable.edit.editor.ComboBoxCellEditor; import org.eclipse.nebula.widgets.nattable.painter.cell.ComboBoxPainter; import org.eclipse.nebula.widgets.nattable.style.DisplayMode; import org.eclipse.papyrus.infra.emf.nattable.dataprovider.EEnumComboBoxDataProvider; import org.eclipse.papyrus.infra.emf.providers.EMFLabelProvider; import org.eclipse.papyrus.infra.nattable.celleditor.config.ICellAxisConfiguration; import org.eclipse.papyrus.infra.nattable.model.nattable.Table; import org.eclipse.papyrus.infra.nattable.utils.AxisUtils;

/**

* @author MA244259
*
*/

public class SingleEEnumTypeCellEditorConfiguration implements ICellAxisConfiguration {

/** * the id of this editor */ private static final String ID = "org.eclipse.papyrus.infra.emf.nattable.celleditor.configuration.SingleEEnumTypeCellEditorConfiguration.ComboBox";//$NON-NLS-1$

/** * @see org.eclipse.papyrus.infra.nattable.configuration.IPapyrusNatTableConfiguration#getConfigurationId() * * @return */ @Override public String getConfigurationId() { return ID; }

/** * @see org.eclipse.papyrus.infra.nattable.configuration.IPapyrusNatTableConfiguration#getConfigurationDescription() * * @return */ @Override public String getConfigurationDescription() { return "This configuration provides a ComboBox editor for a single EEnum type"; //$NON-NLS-1$ }

/** * @see org.eclipse.papyrus.infra.emf.nattable.celleditor.configuration.ICellAxisEditorConfiguration#handles(org.eclipse.nebula.widgets.nattable.config.IConfigRegistry, java.lang.Object) * * @param table * @param axisElement * @return * true if axisElement is a {@link EEnum} {@link EStructuralFeature} */ @Override public boolean handles(Table table, Object axisElement) { Object representedElement = AxisUtils.getRepresentedElement(axisElement); if (representedElement instanceof EStructuralFeature) { EStructuralFeature feature = (EStructuralFeature) representedElement; if (!feature.isMany()) { EClassifier eType = feature.getEType(); return eType instanceof EEnum; } } return false; }

/** * @see org.eclipse.papyrus.infra.emf.nattable.celleditor.configuration.ICellAxisEditorConfiguration#configureCellEditor(org.eclipse.nebula.widgets.nattable.config.IConfigRegistry, java.lang.Object, java.lang.String) * * @param configRegistry * @param axis * @param configLabel */ @Override public void configureCellEditor(final IConfigRegistry configRegistry, Object axis, String configLabel) { Object representedElement = AxisUtils.getRepresentedElement(axis); EEnum eenum = (EEnum) ((EStructuralFeature) representedElement).getEType();

IDisplayConverter displayConverter = new DisplayConverter() {

@Override public Object displayToCanonicalValue(Object displayValue) { return null; }

@Override public Object canonicalToDisplayValue(Object canonicalValue) { // for others case // LabelProviderService service = configRegistry.getConfigAttribute(NattableConfigAttributes.LABEL_PROVIDER_SERVICE_CONFIG_ATTRIBUTE, DisplayMode.NORMAL, NattableConfigAttributes.LABEL_PROVIDER_SERVICE_ID); // return service.getLabelProvider(canonicalValue).getText(canonicalValue); //

return new EMFLabelProvider().getText(canonicalValue); } };

configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new ComboBoxPainter(), DisplayMode.EDIT, configLabel); configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new ComboBoxCellEditor(new EEnumComboBoxDataProvider(eenum)), DisplayMode.EDIT, configLabel); configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER, displayConverter, DisplayMode.EDIT, configLabel); } }

</source>

Table Selection

General presentation and TableSelectionProvider

The selection in table is managed by the org.eclipse.papyrus.infra.nattable.provider.TableSelectionProvider which manages the selection layer.

The table selection provider manage the selection as following specified:

Selection in table Selection managed by provider
None Table context (The selection must the the table context to manage the properties view)
Rows The rows elements, features or operations
Columns The columns elements, features or operations
Cells The cells values

This table selection provider manage the control and the shift mask and is managed by CellSelectionEvent, RowSelectionEvent or ColumnSelectionEvent.

TableStructuredSelection

The getSelection() managed in the NattableModelManager returns a TableStructuredSelection. This one contains a reference to the wrapper for the table selection: TableSelectionWrapper. To get this one: it is just needed to use the getAdapter(TableSelectionWrapper.class).

TableSelectionWrapper

The TableSelectionWrapper can allow to determine the selected cells, the selected rows and the selected columns. The rows and the columns selected only contains the entire rows or columns selected, not partial.

This can determine if the cells, rows or columns are continous or not.

Example of use

This is an example how to use the table selection (enable an action when only rows are selected:

 boolean canEnable = false;
 final INattableModelManager currentNattableModelManager = getCurrentNattableModelManager();
 if (null != currentNattableModelManager) {
  final ISelection currentSelection = ((NattableModelManager) currentNattableModelManager).getSelectionInTable();
  if (null == currentSelection) {
   canEnable = true;
  } else if (currentSelection instanceof TableStructuredSelection) {
   TableSelectionWrapper tableSelectionWrapper = (TableSelectionWrapper) ((TableStructuredSelection) currentSelection).getAdapter(TableSelectionWrapper.class);
   if (null != tableSelectionWrapper) {
    if (!tableSelectionWrapper.getFullySelectedRows().isEmpty()
     && tableSelectionWrapper.getFullySelectedCells().isEmpty() && tableSelectionWrapper.getFullySelectedColumns().isEmpty()) {
     canEnable = true;
    }
   }
  }
 }
 setEnable(canEnable);

Existing NamedStyle used in the table

NamedStyles are properties that the users can add to table configurations to provide values to tables. For example, "expandAll" is a BooleanValueStyle (i.e., a boolean NamedStyle) that expands all the rows in a tree table when its value is 'true'.

Name Type Where Usage
hiddenCategoriesByDepth IntListValueStyle child of Table or child of TableConfiguration hide the categories for a given depth
rowIndexWidth IntValueStyle child of RowHeaderAxisConfiguration determines the size of the row index
rowLabelWidth IntValueStyle child of RowHeaderAxisConfiguration determines the size of the first row label
rowPosition''X''LabelWidth IntValueStyle child of RowHeaderAxisConfiguration determines the size of the row label at position X
columnIndexHeight IntValueStyle child of ColumnHeaderAxisConfiguration determines the height of the column index
columnLabelHeight IntValueStyle child of ColumnHeaderAxisConfiguration determines the height of the column label
rowHeaderWidth IntValueStyle child of Table determines the width of the row header (for the slider composite)
expandAll BooleanValueStyle child of Tree Table Configuration determines if the rows will be expanded automatically when opening the table
fillColumnsSize (deprecated) BooleanValueStyle child of Tree Table Configuration determines if the columns must fill the parent composite space
dragRegions StringListValueStyle child of Table or child of TableConfiguration determines grid regions where the drag support is activate. Activate by default on row header. Can set with: "ROW_HEADER", "BODY", "COLUMN_HEADER". Limitations: when activate on column, reorder column dosn't work(see bug 508311 and bug 508313)
columnsWidthAsPercentage BooleanValueStyle child of Tree Table Configuration determines if the columns width are managed as percentage (in this case, all the possible width must be used)
saveColumnsWidth BooleanValueStyle child of Tree Table Configuration determines if the width must be saved (actually, the width are saved but just not used)
wrapText BooleanValueStyle child of Table determines if the text of cells will be wrapped when displaying the table
autoResizeCellHeight BooleanValueStyle child of Table determines if the cell height will be resized automatically when displaying the table
displayListOnSeparatedRows BooleanValueStyle child of Axis determines if the elements list of a fully selected column (or row in an invert table) is displayed on separated rows or single row

How many case should be managed to add/insert/paste (rows) axis in a table ?

The feature must be editable (not read-only). Moreover it will be better if the listen feature is not filtered (java class, queries (not yet implemented the 20th October 2015),...).

How to create your own label provider

//TODO

How to create your own cell manager

//TODO

How to create your own axis manager

Create a new axis manager will allow you to manipulate new kind of data. Create a new axis manager implies to create others objects too:

Introduction to create a new Axis Manager

It exists several possible combination of feature : flat/tree*synchronized/not synchronized*EObject/EstructuralFeature. We not yet implements all the possible cases, so here we will describe the more relevant ones. In all cases, your class must implements org.eclipse.papyrus.infra.nattable.manager.axis.IAxisManager. Each Axis has a way to reference the managed object.

Create an Axis Manager for EObject

Flat and not synchronized Axis Manager

Flat and Synchronized on a EStructural Feature Axis Manager

Create an Axis Manager for EStructuralFeature

Flat and not synchronized Axis Manager

Create Axis Manager for others kinds of objects/feature

Create a new Axis Manager

Now, you should know which class to extend and which kind of IAxis used to store axis provided by the axis manager (if the storage is required)

  1. Create a new plugin project with the required dependencies
  2. Create a new java class extenting the good class, we will complete it later
  3. Contribute to the papyrus extension point org.eclipse.papyrus.infra.nattable.axismanager
    1. id: a unique id for the axis axis manager
    2. class': the java class
  4. Open a file *.nattableconfiguration
    1. Modify existing table configuration in order to be able to get new axis in existing table. In general case, you will contribute to the column Axis Manager, where the index are displayed as Alphbetic. In the good one Table Header Axis Configuration (Numeric for rows and Alphabetic for Column)
    2. Create a new Label Provider Configuration (Feature or Operation or Object)
    3. Create a new Axis Manager Representation
      1. Axis Manager Id: the same value than in the plugin.xml
      2. Header Label Configuration: you must reference the Label Provider Configuration created previously.
      3. Label Provider Context: one of these three possibilities, according to your Header Label Configuration kind
        1. org.eclipse.papyrus.infra.nattable.header.feature.labelprovider
        2. org.eclipse.papyrus.infra.nattable.header.operation.labelprovider
        3. org.eclipse.papyrus.infra.nattable.header.object.labelprovider
      4. Specific Axis Configurations: nothing for this usecase
    4. Add new default axis provided by our new Axis Manager
      1. If you want that new table created by our user provides by default some columns managed by our Axis Manager, you must create new IAxis in one of the 2 Object Axis Provider. In the general case, there is a slave for columns and a master for rows, and the default axis are defined for columns. So probably in the Slave Object Axis Provider, you can create new IAxis, probably an IdAxis or a IdTreeItemAxis, for Object, Feature or Operation, then you must fill these fields:
        1. Alias: not mandatory, a name for the axis
        2. Element: the object referenced by the axis, probably a string if you use an IdAxis
        3. Manager: you must reference the Axis Manager Representation created previously

Create a new Cell Manager

It will allow you to get the contents of the cell and to save it after editing value.

  1. Create a new java class implementing org.eclipse.papyrus.infra.nattable.manager.cell.IUnsetValueCellManager or extending org.eclipse.papyrus.infra.nattable.manager.cell.AbstractCellManager or one of these subclasses and complete it.
  2. Register this class in the plugin.xml file, using the extension point org.eclipse.papyrus.infra.nattable.cellmanager.
    1. id: a unique id for your cell manager,
    2. manager: tha java class,
    3. order: an integer

Create a new CellEditor Configuration

It will allow you to edit the cell value.

  1. Create a new class implementing org.eclipse.papyrus.infra.nattable.celleditor.config.ICellAxisConfiguration or one of these subclasses and complete it.
  2. Register the class in the plugin.xml file, using the extension point org.eclipse.papyrus.infra.nattable.celleditor.configuration and the object cellAxisConfiguration. (FYI, configuration is deprecated since Eclipse Neon/Papyrus 1.2.0)
    1. class: the java class for the cell editor configuration,
    2. order: an integer.

Create a new Label Provider Configuration

It will allow you to display the contents of the cells returned by the CellManager. This steps is not mandatory, because it depends on the object displayed in our cells. Maybe your case is always managed by Papyrus, maybe not.

  1. Create a new class extending org.eclipse.papyrus.infra.nattable.provider.AbstractNattableCellLabelProvider or one of these subclasses and complete it.
    1. Warning, in the context of Papyrus table, you never receive directly the object displayed on the cell, but you will receive a wrapper implementing org.eclipse.papyrus.infra.nattable.utils.ILabelProviderContextElementWrapper
  2. Register your class in the plugin.xml file, using the extension point org.eclipse.papyrus.infra.services.labelprovider.labelProvider
    1. priority: an integer
    2. provider: the java class
  3. create a labelprovidercontext as child of the declared label provider. You must use one of these ones, depending on the table's region for which you want a custom label:
    1. org.eclipse.papyrus.infra.nattable.full.labelprovider: the labelprovider declared in this context dispatches to others labelproviders depending on the element's region for which we want a label,
    2. org.eclipse.papyrus.infra.nattable.header.labelprovider: the labelprovider declared in this context dispatches to others labelproviders declared on header, depending on the kind of the element (and sometimes of its place in the header (index layer, label layer, column/row, ...),
    3. org.eclipse.papyrus.infra.nattable.header.feature.labelprovider: this context is used to get the label for a feature displayed in the header of the table,
    4. org.eclipse.papyrus.infra.nattable.header.operation.labelprovider: this context is used to get the label for a feature displayed in the header of the table,
    5. org.eclipse.papyrus.infra.nattable.header.treefilling.feature.labelprovider: this context is used to get the label for a feature referenced by a TreeFillingConfiguration,
    6. org.eclipse.papyrus.infra.nattable.header.treefilling.operation.labelprovider: this context is used to get the label for an operation referenced by a TreeFillingConfiguration,
    7. org.eclipse.papyrus.infra.nattable.body.labelprovider: this context is used to get the label of the elements in the body of the table. Most of the time, you will contribute to this one.

Create a new Filter Configuration

This step is not mandatory, by default, the string filter will be used.

  1. Create a new class, implementing org.eclipse.papyrus.infra.nattable.filter.configuration.IFilterConfiguration or extending org.eclipse.papyrus.infra.nattable.filter.configuration.AbstractFilterConfiguration or one of these subclasses.
  2. Register your class in the plugin.xml file, using the extension point org.eclipse.papyrus.infra.nattable.filter.configuration
    1. class: the java class
    2. order: an integer

How to create your own post action for paste

//TODO

How to declare several axis configuration in the same table

//TODO

How to declare new actions in the Papyrus Table Context Menu

General Tricks about the menus in Eclipse

You can call the Eclipse Menu Service to fill your own MenuManager with contributions declared with the eclipse extension point org.eclipse.ui.menus. Here it is a code example for the Papyrus Table. (The final implementation doesn't use the IMenuService in the table, because it is already done upper in Papyrus Infra Core).

	final MenuManager menuManager =new MenuManager(POPUP, TABLE_POPUP_MENU_ID);
	menuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
	menuManager.setRemoveAllWhenShown(true);
	final Menu menu = menuManager.createContextMenu(this.natTable);
	this.natTable.setMenu(menu);
		/* This listener allows us to fill the popup menu using extension point contributing to the popup menu of the table */
		IMenuListener l = null;
		menuManager.addMenuListener(l=new IMenuListener() {

				/**
				 * 
				 * @see org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager)
				 *
				 * @param manager
				 */
				@Override
				public void menuAboutToShow(IMenuManager manager) {
					IMenuService menuService = site.getService(IMenuService.class);
					if (menuService != null) {
						menuService.populateContributionManager(menuManager, "popup:org.eclipse.papyrus.infra.nattable.widget.menu"); //$NON-NLS-1$
					}
				}
			});


Body Menu (Papyrus 1.2/Eclipse Neon)

These separators are declared in the file org.eclipse.papyrus.infra.nattable.menu.MenuConstants.

The menu displayed for Tree Table:

Body Popup Menu for the Tree Table

Body Menu (Papyrus 1.1/Eclipse Mars)

The result in the xml file will be something like that :

 <extension
       point="org.eclipse.ui.menus">
    <menuContribution
          allPopups="true"
          locationURI="popup:org.eclipse.ui.popup.any">
       <command
             commandId="org.eclipse.papyrus.infra.nattable.import.command"
             style="push">
          <visibleWhen>
                <with
                      variable="selection">
                   <test
                         forcePluginActivation="true"
                         property="org.eclipse.papyrus.infra.nattable.tester.isNattableWidget"
                         value="true">
                   </test>
                </with>
          </visibleWhen>
       </command>
    </menuContribution>
  </extension>

How to declare a menu action for a specific kind of table, using PropertyTester

We assume than you know how to declare a menu for all tables in Eclipse.

Here, we will give some explanations to create a property tester used to restrict actions in a menu, but the property tester can be used for handler enablement too, and in each expressions declared in a plugin.xml file

For further informations about PropertyTester and Command Core Expression, you can read these documentations :

We take as example the PropertyTester used for Papyrus Table Menu.

The PropertyTester can be used to define action visibility in the menu, handler enablement, handler activation, ... Your property tester can be used each time you wrote expressions in a plugin.xml file.

Here, it is the declaration of the property tester used to know is the current Papyrus Editor is a table editor. This property tester provides several properties:

<extension
       point="org.eclipse.core.expressions.propertyTesters">
    <propertyTester
          class="org.eclipse.papyrus.infra.nattable.utils.NattableWidgetPropertyTester"
          id="org.eclipse.papyrus.infra.nattable.tester"
          namespace="org.eclipse.papyrus.infra.nattable.tester"
          properties="isNattableWidget, hasFeatureRowHeaderConfiguration, hasFeatureColumnHeaderConfiguration, hasSlaveRowAxisProvider, hasSlaveColumnAxisProvider, canInvertAxis, isHierarchicTable"
          type="org.eclipse.jface.viewers.IStructuredSelection">
    </propertyTester>
 </extension>

Now, the java class implementing this property tester:

 

/*****************************************************************************
 * Copyright (c) 2012 CEA LIST.
 *
 *
 * 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:
 *  Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
 *
 *****************************************************************************/
package org.eclipse.papyrus.infra.nattable.utils;

import org.eclipse.core.expressions.PropertyTester;
import org.eclipse.papyrus.infra.nattable.manager.table.INattableModelManager;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattableaxisprovider.ISlaveAxisProvider;
import org.eclipse.papyrus.infra.nattable.model.nattable.nattablestyle.DisplayStyle;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;


public class NattableWidgetPropertyTester extends PropertyTester {

	public static final String IS_NATTABLE_WIDGET = "isNattableWidget"; //$NON-NLS-1$

	private static final String HAS_FEATURE_ROW_HEADER_CONFIGURATION = "hasFeatureRowHeaderConfiguration"; //$NON-NLS-1$

	private static final String HAS_FEATURE_COLUMN_HEADER_CONFIGURATION = "hasFeatureColumnHeaderConfiguration"; //$NON-NLS-1$

	private static final String HAS_SLAVE_ROWS_AXIS_PROVIDER = "hasSlaveRowAxisProvider"; //$NON-NLS-1$

	private static final String HAS_SLAVE_COLUMNS_AXIS_PROVIDER = "hasSlaveColumnAxisProvider"; //$NON-NLS-1$

	private static final String CAN_INVERT_AXIS = "canInvertAxis";//$NON-NLS-1$

	private static final String IS_HIERARCHIC_TABLE = "isHierarchicTable"; //$NON-NLS-1$

	@Override
	public boolean test(final Object receiver, final String property, final Object[] args, final Object expectedValue) {
		final INattableModelManager manager = getNattableModelManager();
		if (IS_NATTABLE_WIDGET.equals(property) && expectedValue instanceof Boolean) {
			return expectedValue.equals(manager != null);
		}
		if (manager != null && expectedValue instanceof Boolean) {
			if (HAS_FEATURE_ROW_HEADER_CONFIGURATION.equals(property)) {
				LabelConfigurationManagementUtils.getRowFeatureLabelConfigurationInTable(manager.getTable());
				return expectedValue.equals(LabelConfigurationManagementUtils.hasRowFeatureLabelConfiguration(manager.getTable()));
			} else if (HAS_FEATURE_COLUMN_HEADER_CONFIGURATION.equals(property)) {
				return expectedValue.equals(LabelConfigurationManagementUtils.hasColumnFeatureLabelConfiguration(manager.getTable()));
			} else if (HAS_SLAVE_COLUMNS_AXIS_PROVIDER.equals(property)) {
				return expectedValue.equals(AxisUtils.getAxisProviderUsedForColumns(manager) instanceof ISlaveAxisProvider);
			} else if (HAS_SLAVE_ROWS_AXIS_PROVIDER.equals(property)) {
				return expectedValue.equals(AxisUtils.getAxisProviderUsedForRows(manager) instanceof ISlaveAxisProvider);
			} else if (CAN_INVERT_AXIS.equals(property)) {
				return expectedValue.equals(manager.canInvertAxis());
			} else if (IS_HIERARCHIC_TABLE.equals(property)) {
				return expectedValue.equals(isHierarchicTable(manager));
			}
		}
		return false;
	}

	/**
	 * @param table
	 * @return
	 */
	public static final boolean isHierarchicTable(final INattableModelManager tableManager) {
		final DisplayStyle style = TableHelper.getTableDisplayStyle(tableManager);
		return (DisplayStyle.HIERARCHIC_SINGLE_TREE_COLUMN.equals(style) || DisplayStyle.HIERARCHIC_MULTI_TREE_COLUMN.equals(style));
	}

	/**
	 *
	 * @return
	 *         the current nattable model manager or <code>null</code> if not found
	 */
	protected INattableModelManager getNattableModelManager() {
		final IWorkbench workbench = PlatformUI.getWorkbench();
		IWorkbenchPart current = null;
		if (workbench != null) {
			final IWorkbenchWindow activeWorkbench = workbench.getActiveWorkbenchWindow();
			if (activeWorkbench != null) {
				final IWorkbenchPage activePage = activeWorkbench.getActivePage();
				if (activePage != null) {
					current = activePage.getActivePart();
				}
			}
		}

		if (current != null) {
			return (INattableModelManager) current.getAdapter(INattableModelManager.class);
		}
		return null;
	}
}

To use it, please read the example of the documentation Table Developer Documentation/Body Menu (Papyrus1.1/Eclipse Mars).

Row Header Menu and Column Header Menu (Eclipse Mars/Papyrus 1.1)

Of course, you should provide a java handler for your commands using the extension point mechanism.

Validation Markers in the table

Validation markers are available in the rows and columns header of the table since Papyrus 1.2/Eclipse Neon. It is an integration of the feature already existing in the Model Explorer View. For this integration, we changed these classes :

All these changes depends on the decoration service and not on the validation service because currently, validation marker are implemented as decorations. The validation menu is available in the table popup menu, but we do not provide specific handler for validation in table. We use the handlers defined by Papyrus in others plugins. The validation menu provides these actions (the same than in others views):

These actions works according to the table selection, with this behavior (Row, then Column, then Cell):

This order is given by the method calculating the selection of the table: org.eclipse.papyrus.infra.nattable.provider.TableSelectionProvider.calculateAndStoreNewSelection(ILayerEvent)

Matrix

The Papyrus tabular editor should allow to the developper to create matrix, we doesn't really try to do that. Here, we give some points which should allow you to create matrix :

  1. the column axis must manage object instead of manage features
  2. you must declare a cell manager specific to your table to get and edit the values in the cell
  3. you probably need to declare your own label provider
  4. others things to do?
  5. to conclude, don't forget to implements required methods to allow (or forbid) all features already supported by the table framework. The list of the supported feature is available here.

Which is the difference between TableHeaderAxisConfiguration and LocalTableHeaderAxisConfiguration

Table embedded in the Property View

The classes managing the NatTable widget in the property view are:

These tables have some custom behaviors:

org.eclipse.papyrus.uml.properties.widgets.NattablePropertyEditor.createTableURI(EObject, TableConfiguration) for further information.

What are the existing axis manager ?