https://bugs.eclipse.org/bugs/show_bug.cgi?id=378259 - adds a Namespaces
table to the Definitions tab
diff --git a/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/model/Bpmn2ModelerResourceImpl.java b/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/model/Bpmn2ModelerResourceImpl.java
index 6f29a8d..8a86234 100644
--- a/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/model/Bpmn2ModelerResourceImpl.java
+++ b/org.eclipse.bpmn2.modeler.core/src/org/eclipse/bpmn2/modeler/core/model/Bpmn2ModelerResourceImpl.java
@@ -250,6 +250,7 @@
 

 		public Bpmn2ModelerXMLSave(XMLHelper helper) {

 			super(helper);

+			helper.getPrefixToNamespaceMap().clear();

 		}

 

 		@Override

diff --git a/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/AbstractBpmn2PropertiesComposite.java b/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/AbstractBpmn2PropertiesComposite.java
index 0fd7616..f158199 100644
--- a/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/AbstractBpmn2PropertiesComposite.java
+++ b/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/AbstractBpmn2PropertiesComposite.java
@@ -234,6 +234,9 @@
 	 * @return the Composite root for the current selection's EAttributes

 	 */

 	public Composite getAttributesParent() {

+		if (getParent() instanceof Section)

+			return this;

+		

 		if (attributesSection==null || attributesSection.isDisposed()) {

 

 			if (objectStack.peek()==be)

diff --git a/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/AbstractBpmn2TableComposite.java b/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/AbstractBpmn2TableComposite.java
index 6b62251..4541d36 100644
--- a/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/AbstractBpmn2TableComposite.java
+++ b/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/AbstractBpmn2TableComposite.java
@@ -118,7 +118,7 @@
 	// widgets

 	SashForm sashForm;

 	Section tableSection;

-	Section detailSection;

+	protected Section detailSection;

 	

 	Table table;

 	TableViewer tableViewer;

@@ -426,10 +426,10 @@
 		if (!(theobject.eGet(thefeature) instanceof EList<?>)) {

 			return;

 		}

-		Class<?> clazz = thefeature.getEType().getInstanceClass();

-		if (!EObject.class.isAssignableFrom(clazz)) {

-			return;

-		}

+//		Class<?> clazz = thefeature.getEType().getInstanceClass();

+//		if (!EObject.class.isAssignableFrom(clazz)) {

+//			return;

+//		}

 

 		final BPMN2Editor bpmn2Editor = getDiagramEditor();

 		

@@ -443,25 +443,8 @@
 		////////////////////////////////////////////////////////////

 		// Collect columns to be displayed and build column provider

 		////////////////////////////////////////////////////////////

-		columnProvider = getColumnProvider(theobject, thefeature);

-		// remove disabled columns

-		List<TableColumn> removed = new ArrayList<TableColumn>();

-		for (TableColumn tc : (List<TableColumn>)columnProvider.getColumns()) {

-			if (tc.feature!=null) {

-				if (!"id".equals(tc.feature.getName())) {

-					if (!modelEnablement.isEnabled(listItemClass, tc.feature)) {

-						removed.add(tc);

-					}

-				}

-			}

-		}

-		if (removed.size()>0) {

-			for (TableColumn tc : removed)

-				columnProvider.remove(tc);

-		}

-		if (columnProvider.getColumns().size()==0) {

+		if (createColumnProvider(theobject, thefeature) <= 0)

 			return;

-		}

 

 		////////////////////////////////////////////////////////////

 		// SashForm contains the table section and a possible

@@ -484,38 +467,32 @@
 			tableComposite.setLayout(new GridLayout(3, false));

 			createTableAndButtons(tableComposite,style);

 			

-			detailSection = toolkit.createSection(sashForm,

-					ExpandableComposite.TWISTIE |

-					ExpandableComposite.EXPANDED |

-					ExpandableComposite.TITLE_BAR);

-			detailSection.setText(ModelUtil.toDisplayName(listItemClass.getName()) + " Details");

+			if ((style & SHOW_DETAILS)!=0) {

+				detailSection = toolkit.createSection(sashForm,

+						ExpandableComposite.TWISTIE |

+						ExpandableComposite.EXPANDED |

+						ExpandableComposite.TITLE_BAR);

+				detailSection.setText(ModelUtil.toDisplayName(listItemClass.getName()) + " Details");

 

-//			detailComposite = createDetailComposite(detailSection, listItemClass.getInstanceClass());

-//			if (detailComposite!=null) {

-//				detailSection.setClient(detailComposite);

-//				toolkit.adapt(detailComposite);

-////				detailComposite.setPropertySection(propertySection);

-//			}

-			detailSection.setVisible(false);

+				detailSection.setVisible(false);

 

-			tableSection.addExpansionListener(new IExpansionListener() {

-

-				@Override

-				public void expansionStateChanging(ExpansionEvent e) {

-					if (!e.getState() && detailSection!=null) {

-						detailSection.setVisible(false);

+				tableSection.addExpansionListener(new IExpansionListener() {

+	

+					@Override

+					public void expansionStateChanging(ExpansionEvent e) {

+						if (!e.getState() && detailSection!=null) {

+							detailSection.setVisible(false);

+						}

 					}

-				}

-

-				@Override

-				public void expansionStateChanged(ExpansionEvent e) {

-					preferenceStore.setValue("table."+listItemClass.getName()+".expanded", e.getState());

-					redrawPage();

-				}

-				

-			});

+	

+					@Override

+					public void expansionStateChanged(ExpansionEvent e) {

+						preferenceStore.setValue("table."+listItemClass.getName()+".expanded", e.getState());

+						redrawPage();

+					}

+					

+				});

 			

-			if (detailSection!=null) {

 				detailSection.addExpansionListener(new IExpansionListener() {

 	

 					@Override

@@ -530,9 +507,10 @@
 						redrawPage();

 					}

 				});

+				sashForm.setWeights(new int[] { 1, 2 });

 			}					

-			

-			sashForm.setWeights(new int[] { 1, 2 });

+			else

+				sashForm.setWeights(new int[] { 1 });

 		}

 		else {

 			createTableAndButtons(this,style);

@@ -597,10 +575,11 @@
 							detailSection.setClient(detailComposite);

 							toolkit.adapt(detailComposite);

 

-							detailSection.setText(ModelUtil.toDisplayName(o.eClass().getName()) + " Details");

+							if (detailSection.getText().isEmpty())

+								detailSection.setText(ModelUtil.toDisplayName(o.eClass().getName()) + " Details");

 							((AbstractBpmn2PropertiesComposite)detailComposite).setEObject(bpmn2Editor,o);

+							enable = detailComposite.getChildren().length>0;

 						}

-						enable = detailComposite.getChildren().length>0;

 					}

 					detailSection.setVisible(enable);

 					detailSection.setExpanded(enable);

@@ -732,6 +711,34 @@
 			tableSection.setExpanded(true);

 	}

 	

+	/**

+	 * @param theobject

+	 * @param thefeature

+	 * @return

+	 */

+	protected int createColumnProvider(EObject theobject, EStructuralFeature thefeature) {

+		if (columnProvider==null) {

+			EClass listItemClass = getListItemClass(theobject,thefeature);

+			columnProvider = getColumnProvider(theobject, thefeature);

+			// remove disabled columns

+			List<TableColumn> removed = new ArrayList<TableColumn>();

+			for (TableColumn tc : (List<TableColumn>)columnProvider.getColumns()) {

+				if (tc.feature!=null) {

+					if (!"id".equals(tc.feature.getName())) {

+						if (!modelEnablement.isEnabled(listItemClass, tc.feature)) {

+							removed.add(tc);

+						}

+					}

+				}

+			}

+			if (removed.size()>0) {

+				for (TableColumn tc : removed)

+					columnProvider.remove(tc);

+			}

+		}

+		return columnProvider.getColumns().size();

+	}

+

 	protected void redrawPage() {

 		if (propertySection!=null)

 			propertySection.layout();

@@ -867,7 +874,9 @@
 		

 		@Override

 		public String getHeaderText() {

-			return ModelUtil.toDisplayName(feature.getName());

+			if (feature!=null)

+				return ModelUtil.toDisplayName(feature.getName());

+			return "";

 		}

 

 		@Override

diff --git a/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/diagrams/DefinitionsPropertyComposite.java b/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/diagrams/DefinitionsPropertyComposite.java
index b3ab645..4f127fe 100644
--- a/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/diagrams/DefinitionsPropertyComposite.java
+++ b/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/diagrams/DefinitionsPropertyComposite.java
@@ -1,20 +1,34 @@
 package org.eclipse.bpmn2.modeler.ui.property.diagrams;

 

+import java.util.ArrayList;

+import java.util.List;

+import java.util.Map;

+

+import org.eclipse.bpmn2.Bpmn2Package;

 import org.eclipse.bpmn2.Definitions;

+import org.eclipse.bpmn2.DocumentRoot;

 import org.eclipse.bpmn2.Import;

 import org.eclipse.bpmn2.impl.DefinitionsImpl;

 import org.eclipse.bpmn2.modeler.core.ModelHandler;

 import org.eclipse.bpmn2.modeler.core.utils.NamespaceUtil;

+import org.eclipse.bpmn2.modeler.ui.property.AbstractBpmn2PropertiesComposite;

 import org.eclipse.bpmn2.modeler.ui.property.AbstractBpmn2PropertySection;

 import org.eclipse.bpmn2.modeler.ui.property.AbstractBpmn2TableComposite;

 import org.eclipse.bpmn2.modeler.ui.property.DefaultPropertiesComposite;

+import org.eclipse.bpmn2.modeler.ui.property.dialogs.NamespacesEditingDialog;

 import org.eclipse.bpmn2.modeler.ui.property.dialogs.SchemaImportDialog;

+import org.eclipse.bpmn2.modeler.ui.property.editors.ObjectEditor;

 import org.eclipse.bpmn2.modeler.ui.property.editors.TextAndButtonObjectEditor;

+import org.eclipse.bpmn2.modeler.ui.property.editors.TextObjectEditor;

+import org.eclipse.bpmn2.modeler.ui.util.PropertyUtil;

 import org.eclipse.emf.common.util.EList;

 import org.eclipse.emf.ecore.EAttribute;

 import org.eclipse.emf.ecore.EClass;

 import org.eclipse.emf.ecore.EObject;

 import org.eclipse.emf.ecore.EStructuralFeature;

+import org.eclipse.emf.ecore.util.EcoreEMap;

+import org.eclipse.emf.transaction.RecordingCommand;

+import org.eclipse.emf.transaction.TransactionalEditingDomain;

 import org.eclipse.jface.dialogs.IInputValidator;

 import org.eclipse.jface.dialogs.InputDialog;

 import org.eclipse.jface.window.Window;

@@ -30,7 +44,8 @@
 	}

 

 	private AbstractPropertiesProvider propertiesProvider;

-

+	private NamespacesTable namespacesTable;

+	

 	/**

 	 * @param section

 	 */

@@ -63,6 +78,19 @@
 	}

 

 	@Override

+	public void createBindings(EObject be) {

+		super.createBindings(be);

+		if (namespacesTable!=null)

+			namespacesTable.dispose();

+		

+		namespacesTable = new NamespacesTable(propertySection);

+		DefinitionsImpl definitions = (DefinitionsImpl)getEObject();

+		DocumentRoot root = (DocumentRoot) definitions.eContainer();

+		namespacesTable.bindList(root, Bpmn2Package.eINSTANCE.getDocumentRoot_XMLNSPrefixMap());

+		namespacesTable.setTitle("Namespaces");

+	}

+

+	@Override

 	protected void bindList(EObject object, EStructuralFeature feature) {

 		if (modelEnablement.isEnabled(object.eClass(), feature)) {

 			if ("imports".equals(feature.getName())) {

@@ -79,6 +107,167 @@
 		}

 	}

 

+	public class NamespacesTable extends AbstractBpmn2TableComposite {

+		

+		public NamespacesTable(AbstractBpmn2PropertySection section) {

+			super(section, ADD_BUTTON | REMOVE_BUTTON | SHOW_DETAILS);

+		}

+

+		

+		@Override

+		protected EObject addListItem(EObject object, EStructuralFeature feature) {

+			DocumentRoot root = (DocumentRoot)object;

+			Map<String,String> map = root.getXMLNSPrefixMap();

+			NamespacesEditingDialog dialog = new NamespacesEditingDialog(getShell(), "Create New Namespace", map, "","");

+			if (dialog.open() == Window.OK) {

+				System.out.println(dialog.getPrefix()+" : "+dialog.getNamespace());

+				map.put(dialog.getPrefix(), dialog.getNamespace());

+			}

+			return null;

+		}

+

+		@Override

+		protected Object removeListItem(EObject object, EStructuralFeature feature, int index) {

+			DocumentRoot root = (DocumentRoot)object;

+			Map<String,String> map = root.getXMLNSPrefixMap();

+			for ( Map.Entry<String, String> entry : map.entrySet() ) {

+				if (index-- == 0) {

+					map.remove( entry.getKey() );

+					break;

+				}

+			}

+			return null;

+		}

+

+		@Override

+		public AbstractBpmn2PropertiesComposite createDetailComposite(final Composite parent, Class eClass) {

+			detailSection.setText("Namespace Details");

+			AbstractBpmn2PropertiesComposite composite = new DefaultPropertiesComposite(parent, SWT.NONE) {

+				

+				@Override

+				protected void bindAttribute(Composite parent, EObject object, EAttribute attribute, String label) {

+					if (attribute.getName().equals("key")) {

+						ObjectEditor editor = new TextAndButtonObjectEditor(this,be,attribute) {

+

+							@Override

+							protected void buttonClicked() {

+								Map.Entry<String, String> entry = (Map.Entry<String, String>)object;

+								DocumentRoot root = (DocumentRoot)object.eContainer();

+								Map<String, String> map = (Map<String, String>)root.getXMLNSPrefixMap();

+								NamespacesEditingDialog dialog = new NamespacesEditingDialog(getShell(), "Change Namespace Prefix", map, entry.getKey(),null);

+								if (dialog.open() == Window.OK) {

+									updateObject(dialog.getPrefix());

+								}

+							}

+							

+							@Override

+							protected boolean updateObject(final Object result) {

+								// we can't just change the key because the map that contains it

+								// needs to be updated, so remove old key, then add new.

+								if (result instanceof String && !((String)result).isEmpty() ) {

+									final Map.Entry<String, String> entry = (Map.Entry<String, String>)object;

+									final String oldKey = entry.getKey();

+									TransactionalEditingDomain domain = getDiagramEditor().getEditingDomain();

+									domain.getCommandStack().execute(new RecordingCommand(domain) {

+										@Override

+										protected void doExecute() {

+											DocumentRoot root = (DocumentRoot)object.eContainer();

+											Map<String, String> map = (Map<String, String>)root.getXMLNSPrefixMap();

+											String value = map.remove(oldKey);

+											map.put((String)result, value);

+										}

+									});

+									return true;

+								}

+								text.setText(PropertyUtil.getText(object, feature));

+								return false;

+							}

+						};

+						editor.createControl(parent,"Prefix",SWT.NONE);

+					}

+					else {

+						ObjectEditor editor = new TextObjectEditor(this,be,attribute);

+						editor.createControl(parent,"Namespace",SWT.NONE);

+					}

+				}

+			};

+			return composite;

+		}

+

+		@Override

+		public TableContentProvider getContentProvider(EObject object, EStructuralFeature feature, EList<EObject>list) {

+			if (contentProvider==null) {

+				contentProvider = new TableContentProvider(object, feature, list) {

+

+					@Override

+					public Object[] getElements(Object inputElement) {

+						List<Object> elements = new ArrayList<Object>();

+						EcoreEMap<String,String> map = (EcoreEMap<String,String>)inputElement;

+						for ( Map.Entry<String, String> entry : map.entrySet() ) {

+							elements.add(entry);

+						}

+						return elements.toArray(new EObject[elements.size()]);

+					}

+

+				};

+			}

+			return contentProvider;

+		}

+		

+		@Override

+		protected int createColumnProvider(EObject theobject, EStructuralFeature thefeature) {

+			if (columnProvider==null) {

+				columnProvider = getColumnProvider(theobject, thefeature);

+			}

+			return columnProvider.getColumns().size();

+		}

+		

+		@Override

+		public AbstractTableColumnProvider getColumnProvider(EObject object, EStructuralFeature feature) {

+			if (columnProvider==null) {

+				columnProvider = new AbstractTableColumnProvider() {

+					@Override

+					public boolean canModify(EObject object, EStructuralFeature feature, EObject item) {

+						return false;

+					}

+				};

+				columnProvider.add(new NamespacesTableColumn(object, 0));

+				columnProvider.add(new NamespacesTableColumn(object, 1));

+			}

+			return columnProvider;

+		}

+		

+		public class NamespacesTableColumn extends TableColumn {

+			

+			int columnIndex;

+			

+			public NamespacesTableColumn(EObject object, int columnIndex) {

+				super(object,null);

+				this.columnIndex = columnIndex;

+			}

+

+			@Override

+			public String getProperty() {

+				return getHeaderText();

+			}

+

+			@Override

+			public String getHeaderText() {

+				if (columnIndex==0)

+					return "Prefix";

+				return "Namespace";

+			}

+

+			@Override

+			public String getText(Object element) {

+				Map.Entry<String, String> entry = (Map.Entry<String, String>)element;

+				if (columnIndex==0)

+					return entry.getKey();

+				return entry.getValue();

+			}

+		}

+	}

+	

 	public class ImportsTable extends AbstractBpmn2TableComposite {

 

 		/**

diff --git a/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/dialogs/NamespacesEditingDialog.java b/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/dialogs/NamespacesEditingDialog.java
new file mode 100644
index 0000000..57ac457
--- /dev/null
+++ b/org.eclipse.bpmn2.modeler.ui/src/org/eclipse/bpmn2/modeler/ui/property/dialogs/NamespacesEditingDialog.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Red Hat, Inc.
+ *  All rights reserved.
+ * This program is 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:
+ * Red Hat, Inc. - initial API and implementation
+ *
+ * @author Bob Brodt
+ ******************************************************************************/
+
+package org.eclipse.bpmn2.modeler.ui.property.dialogs;
+
+import java.util.Map;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @author Bob Brodt
+ *
+ */
+public class NamespacesEditingDialog extends InputDialog {
+	
+	Text namespaceText;
+	String namespace;
+	Text namespaceErrorText;
+	Map<String,String> map;
+	
+	public NamespacesEditingDialog(Shell shell, String title, final Map<String,String> map, final String prefix, String namespace) {
+		super(
+			shell,
+			title,
+			"Prefix",
+			prefix,
+			new IInputValidator() {
+
+				@Override
+				public String isValid(String newText) {
+					if (newText==null || newText.isEmpty())
+						return "Prefix can not be empty";
+					if (newText.equals(prefix))
+						return null;
+					if (map.containsKey(newText))
+						return "The prefix '"+newText+"' is already defined.";
+					return null;
+				}
+			}
+		);
+		this.namespace = namespace;
+		this.map = map;
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite composite = (Composite)super.createDialogArea(parent);
+		composite.getChildren();
+		if (namespace!=null) {
+            Label label = new Label(composite, SWT.WRAP);
+            label.setText("Namespace");
+	            GridData data = new GridData(GridData.GRAB_HORIZONTAL
+	                    | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL
+	                    | GridData.VERTICAL_ALIGN_CENTER);
+	            data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
+	            label.setLayoutData(data);
+	            label.setFont(parent.getFont());
+
+		        namespaceText = new Text(composite, getInputTextStyle());
+		        namespaceText.setText(namespace);
+		        namespaceText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
+		                | GridData.HORIZONTAL_ALIGN_FILL));
+		        namespaceText.addModifyListener(new ModifyListener() {
+		            public void modifyText(ModifyEvent e) {
+		                validateInput();
+		            }
+		        });
+		        
+		        namespaceErrorText = new Text(composite, SWT.READ_ONLY | SWT.WRAP);
+		        namespaceErrorText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
+		                | GridData.HORIZONTAL_ALIGN_FILL));
+		        namespaceErrorText.setBackground(namespaceErrorText.getDisplay()
+		                .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+		        
+			}				
+			return composite;
+		}
+	
+		protected void validateInput() {
+			super.validateInput();
+			if (namespaceText!=null) {
+				String msg = null;
+				String ns = namespaceText.getText();
+				if (ns==null || ns.isEmpty())
+					msg = "Namespace can not be empty";
+				try {
+					URI uri = URI.createURI(ns);
+				}
+				catch (Exception e) {
+					msg = "Namespace is not a valid URI";
+				}
+				namespaceErrorText.setText(msg == null ? "" : msg);
+	    		Control button = getButton(IDialogConstants.OK_ID);
+	    		if (button != null) {
+	    			if (button.isEnabled())
+	    				button.setEnabled(msg == null);
+	    		}
+			}
+		}
+		
+		@Override
+	    protected void buttonPressed(int buttonId) {
+	        if (buttonId == IDialogConstants.OK_ID) {
+	            namespace = namespaceText.getText();
+	        } else {
+	            namespace = null;
+	        }
+	        super.buttonPressed(buttonId);
+	    }
+
+	    public String getPrefix() {
+	    	return getValue();
+	    }
+	    
+		public String getNamespace() {
+			return namespace;
+		}
+	}