blob: dce020786d0bcfb5e6ec66a5d8c91c96d2a0dd9b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2015 Formal Mind GmbH, University of Duesseldorf and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Michael Jastram - initial API and implementation
*******************************************************************************/
package org.eclipse.rmf.reqif10.pror.editor.propertiesview;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TreeMap;
import java.util.TreeSet;
import org.agilemore.agilegrid.AbstractContentProvider;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.emf.edit.provider.ItemPropertyDescriptor.PropertyValueWrapper;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
import org.eclipse.rmf.reqif10.AttributeDefinition;
import org.eclipse.rmf.reqif10.AttributeValue;
import org.eclipse.rmf.reqif10.ReqIF10Package;
import org.eclipse.rmf.reqif10.SpecElementWithAttributes;
import org.eclipse.rmf.reqif10.SpecHierarchy;
import org.eclipse.rmf.reqif10.common.util.ReqIF10Util;
import org.eclipse.rmf.reqif10.pror.util.ProrUtil;
/**
* The agile grid content provider for the properties view. Internally, it
* manages a List of PropertyRows. These represent Categories and Descriptors
* (for AttributeValues and EMF Values)
*
* @author Lukas Ladenberger
* @author Michael Jastram
*
*/
public class ProrPropertyContentProvider extends AbstractContentProvider {
// Special categories that should be ordered differently
public static String SPEC_HIERARCHY_NAME = "Spec Hierarchy";
public static String SPEC_OBJECT_NAME = "Spec Object";
public static String SPEC_RELATION_NAME = "Spec Relation";
public static String SPECIFICATION_NAME = "Specification";
public static String RELATION_GROUP_NAME = "Relation Group";
// Only access via getRows(), to ensure it's not null.
private List<PropertyRow> rows;
// The Object whose properties are shown.
private Object content;
// Whether to show all properties or not
private boolean showAllProps;
private AdapterFactory adapterFactory;
public ProrPropertyContentProvider(AdapterFactory adapterFactory,
boolean showAllProps) {
this.adapterFactory = adapterFactory;
this.showAllProps = showAllProps;
}
@Override
public Object doGetContentAt(int row, int col) {
return getRows().get(row).getContent(col);
}
/**
* This is the object for which this contentProvider manges the properties.
* It is either a {@link SpecElementWithAttributes} or a
* {@link SpecHierarchy}.
*/
Object getElement() {
return content;
}
@Override
public void doSetContentAt(int row, int col, Object value) {
// We don't need this method, cause an automatic refresh of the agile
// grid after editing a cell
// Fix of 378041:
// needed to inform ProrPropertyControl of property change.
// firePropertyChange is never called from
// AbstractContentProvider.setContentAt(..)
// because oldValue is equal to newValue (value already updated
// somewhere else?)
super.firePropertyChange("", null, null);
}
public PropertyRow getRowContent(int row) {
if (row >= getRowCount())
return null;
return getRows().get(row);
}
public void setContent(Object content) {
this.content = content;
rows = null;
}
public int getRowCount() {
return getRows().size();
}
/**
* Lazily builds a list of {@link PropertyRow}s, representing either
* {@link Category}s or {@link PropertyRow}s. These are properly ordered.
*
* @return
*/
private List<PropertyRow> getRows() {
// Use cached version if it exists.
if (rows != null)
return rows;
// We get the provider, which may be null.
rows = new ArrayList<PropertyRow>();
ItemProviderAdapter provider = ProrUtil.getItemProvider(adapterFactory,
content);
if (provider == null)
return rows;
// To ensure ordering by category and then alphabetically, we build a
// map of sets.
// As Descriptors are Comparable, they are properly ordered.
TreeMap<String, TreeSet<Descriptor>> categoryMap = new TreeMap<String, TreeSet<Descriptor>>();
for (IItemPropertyDescriptor prop : provider
.getPropertyDescriptors(content)) {
if (!showAllProps && isAdvancedProperty(prop))
continue;
String categoryName = prop.getCategory(content);
if (categoryName == null) {
categoryName = "Misc";
}
TreeSet<Descriptor> categorySet = categoryMap.get(categoryName);
if (categorySet == null) {
categorySet = new TreeSet<Descriptor>();
categoryMap.put(categoryName, categorySet);
}
categorySet.add(new Descriptor(prop));
}
// To ensure user-relevant ordering, we add the following categories in
// this order...
addCategoryAndRemoveFromMap(categoryMap, SPEC_OBJECT_NAME);
addCategoryAndRemoveFromMap(categoryMap, SPEC_RELATION_NAME);
addCategoryAndRemoveFromMap(categoryMap, SPEC_HIERARCHY_NAME);
addCategoryAndRemoveFromMap(categoryMap, SPECIFICATION_NAME);
addCategoryAndRemoveFromMap(categoryMap, RELATION_GROUP_NAME);
// ... and insert all other categories before.
for (String categoryName : categoryMap.keySet()) {
rows.add(0, new Category(categoryName));
rows.addAll(1, categoryMap.get(categoryName));
}
return rows;
}
private void addCategoryAndRemoveFromMap(
TreeMap<String, TreeSet<Descriptor>> categoryMap,
String categoryName) {
if (categoryMap.containsKey(categoryName)) {
rows.add(new Category(categoryName));
rows.addAll(categoryMap.get(categoryName));
categoryMap.remove(categoryName);
}
}
/**
* Return true if this is one of the special properties that should only be
* shown on the advanced property panel.
*
* @param prop
*/
private boolean isAdvancedProperty(IItemPropertyDescriptor prop) {
String name = prop.getId(content);
String category = prop.getCategory(content);
// Special case: Datatype Dialog
if (category == null && "identifier".equals(name)
|| "desc".equals(name) || "lastChange".equals(name)) {
return true;
}
// Only hide properties that belong to the standard categories
if (!(SPEC_HIERARCHY_NAME.equals(category)
|| SPEC_RELATION_NAME.equals(category)
|| SPEC_OBJECT_NAME.equals(category)
|| SPECIFICATION_NAME.equals(category) || RELATION_GROUP_NAME
.equals(category))) {
return false;
}
// These are the attributes that shall be hidden.
if ("identifier".equals(name) || "desc".equals(name)
|| "lastChange".equals(name) || "editable".equals(name)
|| "longName".equals(name) || "tableInternal".equals(name)
|| "object".equals(name) || "editableAtts".equals(name)) {
return true;
}
return false;
}
/**
* Three implementations of this interface are provided to represent the
* rows of the Property View.
*/
interface PropertyRow extends Comparable<PropertyRow> {
Object getContent(int column);
}
/**
* Rows representing a Category
*/
class Category implements PropertyRow {
String name;
public Category(String name) {
this.name = name;
}
public Object getContent(int column) {
return column == 0 ? name : null;
}
public int compareTo(PropertyRow that) {
return name.compareTo(((Category) that).name);
}
@Override
public boolean equals(Object that) {
if (!(that instanceof Category))
return false;
return compareTo((PropertyRow) that) == 0;
}
@Override
public int hashCode() {
return name.hashCode();
}
}
/**
* Rows representing an {@link IItemPropertyDescriptor}. This can one that
* is RMF-Specific or EMF-Specific.
*/
class Descriptor implements PropertyRow {
IItemPropertyDescriptor descriptor;
AttributeValue attributeValue;
public Descriptor(IItemPropertyDescriptor descriptor) {
this.descriptor = descriptor;
}
public IItemPropertyDescriptor getItemPropertyDescriptor() {
return descriptor;
}
public boolean isRMFSpecific() {
Object feature = descriptor.getFeature(content);
return feature == ReqIF10Package.Literals.SPEC_ELEMENT_WITH_ATTRIBUTES__VALUES
|| descriptor.getFeature(content) == ReqIF10Package.Literals.ATTRIBUTE_VALUE_BOOLEAN__THE_VALUE
|| descriptor.getFeature(content) == ReqIF10Package.Literals.ATTRIBUTE_VALUE_DATE__THE_VALUE
|| descriptor.getFeature(content) == ReqIF10Package.Literals.ATTRIBUTE_VALUE_ENUMERATION__VALUES
|| descriptor.getFeature(content) == ReqIF10Package.Literals.ATTRIBUTE_VALUE_INTEGER__THE_VALUE
|| descriptor.getFeature(content) == ReqIF10Package.Literals.ATTRIBUTE_VALUE_REAL__THE_VALUE
|| descriptor.getFeature(content) == ReqIF10Package.Literals.ATTRIBUTE_VALUE_STRING__THE_VALUE
|| descriptor.getFeature(content) == ReqIF10Package.Literals.ATTRIBUTE_VALUE_XHTML__THE_VALUE;
}
public Object getContent(int column) {
return column == 0 ? descriptor.getDisplayName(content)
: descriptor.getPropertyValue(content);
}
public int compareTo(PropertyRow that) {
return descriptor.getDisplayName(content).compareTo(
((Descriptor) that).descriptor.getDisplayName(content));
}
/**
* Returns the string content from the descriptor. However, we have to extract
* the string differently for {@link GregorianCalendar}.
*/
@Override
public String toString() {
PropertyValueWrapper propertyValueWrapper = (PropertyValueWrapper) descriptor
.getPropertyValue(content);
if (propertyValueWrapper != null) {
Object editableValue = propertyValueWrapper.getEditableValue(content);
if (editableValue instanceof GregorianCalendar) {
GregorianCalendar cal = (GregorianCalendar) editableValue;
Date date = cal.getTime();
return DateFormat.getDateTimeInstance().format(date);
} else {
return propertyValueWrapper
.getText(content);
}
}
return "";
}
@Override
public boolean equals(Object that) {
if (!(that instanceof Descriptor))
return false;
return compareTo((Descriptor) that) == 0;
}
@Override
public int hashCode() {
return descriptor.hashCode();
}
/**
* It is quite possible that the AttributeValue does not exist yet. In
* that case, a new AttributeValue is created and returned, but not
* connected to the parent object (i.e. EObject#eContainer() returns
* null).
*/
public AttributeValue getAttributeValue() {
if (!isRMFSpecific())
return null;
// Find the SpecElement
SpecElementWithAttributes specElement = null;
if (content instanceof SpecElementWithAttributes) {
specElement = (SpecElementWithAttributes) content;
} else if (content instanceof SpecHierarchy) {
specElement = ((SpecHierarchy) content).getObject();
} else if (content instanceof AttributeValue) {
return (AttributeValue) content;
}
// Could also be a default value
if (specElement == null) {
if (content instanceof AttributeDefinition) {
AttributeDefinition ad = (AttributeDefinition) content;
EStructuralFeature defaultValueFeature = ReqIF10Util.getDefaultValueFeature(ad);
return (AttributeValue) ((AttributeDefinition) content).eGet(defaultValueFeature);
}
}
return ReqIF10Util.getAttributeValueForLabel(specElement,
descriptor.getDisplayName(specElement));
}
}
}