Add support for application snippets
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java
index 42e3378..3b0e083 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java
@@ -48,6 +48,7 @@
 	public String ApplicationEditor_Windows;
 	public String ApplicationEditor_Addons;
 	public String ApplicationEditor_MenuContributions;
+	public String ApplicationEditor_Snippets;
 	public String ApplicationEditor_ToolBarContributions;
 	public String ApplicationEditor_TrimContributions;
 	public String ApplicationEditor_RootContexts;
@@ -426,6 +427,8 @@
 	public String VPartDescriptor_Descriptors;
 	public String VPartDescriptor_AddPartDescriptor;
 
+	public String VSnippetsEditor_Snippets;
+
 	public String VToolBarContributionsEditor_Contributions;
 	public String VToolBarContributionsEditor_TreeLabelDescription;
 	public String VToolBarContributionsEditor_TreeLabel;
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties
index 41dbdad..27b4e90 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties
@@ -45,6 +45,7 @@
 ApplicationEditor_Windows=Windows
 ApplicationEditor_Addons=Addons
 ApplicationEditor_MenuContributions=Menu Contributions
+ApplicationEditor_Snippets=Snippets
 ApplicationEditor_ToolBarContributions=Toolbar Contributions
 ApplicationEditor_TrimContributions=Trim Contributions
 ApplicationEditor_RootContexts=Binding Contexts
@@ -425,6 +426,8 @@
 VPartDescriptor_Descriptors=Descriptors
 VPartDescriptor_AddPartDescriptor=Descriptor
 
+VSnippetsEditor_Snippets=Snippets;
+
 VToolBarContributionsEditor_TreeLabel=ToolBar Contributions
 VToolBarContributionsEditor_TreeLabelDescription=ToolBar Contributions Bla Bla Bla Bla Bla
 VToolBarContributionsEditor_Contributions=ToolBar Contributions
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java
index 381dd8b..730a1f2 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java
@@ -113,6 +113,7 @@
 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPerspectiveControlEditor;
 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPerspectiveWindowsEditor;
 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VRootBindingContexts;
+import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VSnippetsEditor;
 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VToolBarContributionsEditor;
 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VTrimContributionsEditor;
 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VWindowControlEditor;
@@ -236,6 +237,7 @@
 	public static final String VIRTUAL_MENUELEMENTS = ModelEditor.class.getName() + ".VIRTUAL_MENUELEMENTS"; //$NON-NLS-1$
 	public static final String VIRTUAL_ROOT_CONTEXTS = ModelEditor.class.getName() + ".VIRTUAL_ROOT_CONTEXTS"; //$NON-NLS-1$
 	public static final String VIRTUAL_PERSPECTIVE_CONTROLS = ModelEditor.class.getName() + "VIRTUAL_PERSPECTIVE_CONTROLS"; //$NON-NLS-1$
+	public static final String VIRTUAL_SNIPPETS = ModelEditor.class.getName() + "VIRTUAL_SNIPPETS"; //$NON-NLS-1$
 
 	private static final int VERTICAL_RULER_WIDTH = 20;
 
@@ -880,6 +882,7 @@
 		registerVirtualEditor(VIRTUAL_PARAMETERS, ContextInjectionFactory.make(VItemParametersEditor.class, context));
 		registerVirtualEditor(VIRTUAL_ROOT_CONTEXTS, ContextInjectionFactory.make(VRootBindingContexts.class, context));
 		registerVirtualEditor(VIRTUAL_PERSPECTIVE_CONTROLS, ContextInjectionFactory.make(VPerspectiveControlEditor.class, context));
+		registerVirtualEditor(VIRTUAL_SNIPPETS, ContextInjectionFactory.make(VSnippetsEditor.class, context));
 	}
 
 	private void registerVirtualEditor(String id, AbstractComponentEditor editor) {
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ApplicationEditor.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ApplicationEditor.java
index 846494b..b567574 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ApplicationEditor.java
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ApplicationEditor.java
@@ -95,6 +95,7 @@
 	private IListProperty MENU_CONTRIBUTIONS = EMFProperties.list(MenuPackageImpl.Literals.MENU_CONTRIBUTIONS__MENU_CONTRIBUTIONS);
 	private IListProperty TOOLBAR_CONTRIBUTIONS = EMFProperties.list(MenuPackageImpl.Literals.TOOL_BAR_CONTRIBUTIONS__TOOL_BAR_CONTRIBUTIONS);
 	private IListProperty TRIM_CONTRIBUTIONS = EMFProperties.list(MenuPackageImpl.Literals.TRIM_CONTRIBUTIONS__TRIM_CONTRIBUTIONS);
+	private IListProperty APPLICATION__SNIPPETS = EMFProperties.list(UiPackageImpl.Literals.SNIPPET_CONTAINER__SNIPPETS);
 	private IListProperty APPLICATION__CATEGORIES = EMFProperties.list(ApplicationPackageImpl.Literals.APPLICATION__CATEGORIES);
 
 	private IListProperty BINDING_TABLE_CONTAINER__ROOT_CONTEXT = EMFProperties.list(CommandsPackageImpl.Literals.BINDING_TABLE_CONTAINER__ROOT_CONTEXT);
@@ -311,6 +312,12 @@
 				return true;
 			}
 		});
+		list.add(new VirtualEntry<Object>(ModelEditor.VIRTUAL_SNIPPETS, APPLICATION__SNIPPETS, element, Messages.ApplicationEditor_Snippets) {
+			@Override
+			protected boolean accepted(Object o) {
+				return true;
+			}
+		});
 		//
 		// MApplication application = (MApplication) element;
 		// if (application.getRootContext() != null) {
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/virtual/VSnippetsEditor.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/virtual/VSnippetsEditor.java
new file mode 100644
index 0000000..1932fa0
--- /dev/null
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/virtual/VSnippetsEditor.java
@@ -0,0 +1,321 @@
+package org.eclipse.e4.tools.emf.ui.internal.common.component.virtual;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.e4.tools.emf.ui.common.Util;
+import org.eclipse.e4.tools.emf.ui.common.component.AbstractComponentEditor;
+import org.eclipse.e4.tools.emf.ui.internal.ResourceProvider;
+import org.eclipse.e4.tools.emf.ui.internal.common.ComponentLabelProvider;
+import org.eclipse.e4.tools.emf.ui.internal.common.VirtualEntry;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.impl.AdvancedPackageImpl;
+import org.eclipse.e4.ui.model.application.ui.basic.impl.BasicPackageImpl;
+import org.eclipse.e4.ui.model.application.ui.impl.UiPackageImpl;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.databinding.EMFDataBindingContext;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.edit.command.AddCommand;
+import org.eclipse.emf.edit.command.RemoveCommand;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+
+public class VSnippetsEditor extends AbstractComponentEditor {
+	private Composite composite;
+	private EMFDataBindingContext context;
+	private TableViewer viewer;
+	private List<Action> actions = new ArrayList<Action>();
+	private EStructuralFeature targetFeature;
+
+	public VSnippetsEditor() {
+		super();
+		this.targetFeature = UiPackageImpl.Literals.SNIPPET_CONTAINER__SNIPPETS;
+	}
+
+	@PostConstruct
+	void init() {
+		actions.add(new Action(Messages.VWindowEditor_AddTrimmedWindow, createImageDescriptor(ResourceProvider.IMG_Window)) {
+			@Override
+			public void run() {
+				handleAdd(BasicPackageImpl.Literals.TRIMMED_WINDOW);
+			}
+		});
+		actions.add(new Action(Messages.VWindowEditor_AddWindow, createImageDescriptor(ResourceProvider.IMG_Window)) {
+			@Override
+			public void run() {
+				handleAdd(BasicPackageImpl.Literals.WINDOW);
+			}
+		});
+		actions.add(new Action(Messages.VWindowControlEditor_AddPerspectiveStack, createImageDescriptor(ResourceProvider.IMG_PerspectiveStack)) {
+			@Override
+			public void run() {
+				handleAdd(AdvancedPackageImpl.Literals.PERSPECTIVE_STACK);
+			}
+		});
+		actions.add(new Action(Messages.PerspectiveStackEditor_AddPerspective, createImageDescriptor(ResourceProvider.IMG_Perspective)) {
+			@Override
+			public void run() {
+				handleAdd(AdvancedPackageImpl.Literals.PERSPECTIVE);
+			}
+		});
+
+		actions.add(new Action(Messages.VWindowControlEditor_AddPartSashContainer, createImageDescriptor(ResourceProvider.IMG_PartSashContainer_vertical)) {
+			@Override
+			public void run() {
+				handleAdd(BasicPackageImpl.Literals.PART_SASH_CONTAINER);
+			}
+		});
+
+		actions.add(new Action(Messages.VWindowControlEditor_AddPartStack, createImageDescriptor(ResourceProvider.IMG_PartStack)) {
+			@Override
+			public void run() {
+				handleAdd(BasicPackageImpl.Literals.PART_STACK);
+			}
+		});
+
+		actions.add(new Action(Messages.VWindowControlEditor_AddPart, createImageDescriptor(ResourceProvider.IMG_Part)) {
+			@Override
+			public void run() {
+				handleAdd(BasicPackageImpl.Literals.PART);
+			}
+		});
+
+		actions.add(new Action(Messages.VWindowControlEditor_AddInputPart, createImageDescriptor(ResourceProvider.IMG_Part)) {
+			@Override
+			public void run() {
+				handleAdd(BasicPackageImpl.Literals.INPUT_PART);
+			}
+		});
+
+		actions.add(new Action(Messages.VWindowControlEditor_AddArea, createImageDescriptor(ResourceProvider.IMG_Area_vertical)) {
+			@Override
+			public void run() {
+				handleAdd(AdvancedPackageImpl.Literals.AREA);
+			}
+		});
+		actions.add(new Action(Messages.VWindowTrimEditor_AddWindowTrim, createImageDescriptor(ResourceProvider.IMG_WindowTrim)) {
+			@Override
+			public void run() {
+				handleAdd(BasicPackageImpl.Literals.TRIM_BAR);
+			}
+		});
+		actions.add(new Action(Messages.VTrimContributionsEditor_AddTrimContribution, createImageDescriptor(ResourceProvider.IMG_TrimContribution)) {
+			@Override
+			public void run() {
+				handleAdd(BasicPackageImpl.Literals.TRIM_ELEMENT);
+			}
+		});
+
+	}
+
+	@Override
+	public Image getImage(Object element, Display display) {
+		return null;
+	}
+
+	@Override
+	public String getLabel(Object element) {
+		return Messages.VWindowControlEditor_TreeLabel;
+	}
+
+	@Override
+	public String getDetailLabel(Object element) {
+		return null;
+	}
+
+	@Override
+	public String getDescription(Object element) {
+		return Messages.VWindowControlEditor_TreeLabelDescription;
+	}
+
+	@Override
+	public Composite doGetEditor(Composite parent, Object object) {
+		if (composite == null) {
+			context = new EMFDataBindingContext();
+			composite = createForm(parent, context, getMaster());
+		}
+		VirtualEntry<?> o = (VirtualEntry<?>) object;
+		viewer.setInput(o.getList());
+		getMaster().setValue(o.getOriginalParent());
+		return composite;
+	}
+
+	private Composite createForm(Composite parent, EMFDataBindingContext context, WritableValue master) {
+		CTabFolder folder = new CTabFolder(parent, SWT.BOTTOM);
+
+		CTabItem item = new CTabItem(folder, SWT.NONE);
+		item.setText(Messages.ModelTooling_Common_TabDefault);
+
+		parent = createScrollableContainer(folder);
+		item.setControl(parent.getParent());
+
+		Label l = new Label(parent, SWT.NONE);
+		l.setText(Messages.VSnippetsEditor_Snippets);
+		l.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
+
+		viewer = new TableViewer(parent);
+		ObservableListContentProvider cp = new ObservableListContentProvider();
+		viewer.setContentProvider(cp);
+		viewer.setLabelProvider(new ComponentLabelProvider(getEditor(), Messages));
+		GridData gd = new GridData(GridData.FILL_BOTH);
+		viewer.getControl().setLayoutData(gd);
+
+		Composite buttonComp = new Composite(parent, SWT.NONE);
+		buttonComp.setLayoutData(new GridData(GridData.FILL, GridData.END, false, false));
+		GridLayout gl = new GridLayout(2, false);
+		gl.marginLeft = 0;
+		gl.marginRight = 0;
+		gl.marginWidth = 0;
+		gl.marginHeight = 0;
+		buttonComp.setLayout(gl);
+
+		Button b = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
+
+		b.setText(Messages.ModelTooling_Common_Up);
+		b.setImage(createImage(ResourceProvider.IMG_Obj16_arrow_up));
+		b.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1));
+		b.addSelectionListener(new SelectionAdapter() {
+			@SuppressWarnings("unchecked")
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (!viewer.getSelection().isEmpty()) {
+					IStructuredSelection s = (IStructuredSelection) viewer.getSelection();
+					if (s.size() == 1) {
+						Object obj = s.getFirstElement();
+						EObject container = (EObject) getMaster().getValue();
+						List<Object> l = (List<Object>) container.eGet(targetFeature);
+						int idx = l.indexOf(obj) - 1;
+						if (idx >= 0) {
+							if (Util.moveElementByIndex(getEditingDomain(), (MUIElement) obj, getEditor().isLiveModel(), idx, targetFeature)) {
+								viewer.setSelection(new StructuredSelection(obj));
+							}
+						}
+
+					}
+				}
+			}
+		});
+
+		b = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
+		b.setText(Messages.ModelTooling_Common_Down);
+		b.setImage(createImage(ResourceProvider.IMG_Obj16_arrow_down));
+		b.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1));
+		b.addSelectionListener(new SelectionAdapter() {
+			@SuppressWarnings("unchecked")
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (!viewer.getSelection().isEmpty()) {
+					IStructuredSelection s = (IStructuredSelection) viewer.getSelection();
+					if (s.size() == 1) {
+						Object obj = s.getFirstElement();
+						EObject container = (EObject) getMaster().getValue();
+						List<Object> l = (List<Object>) container.eGet(targetFeature);
+						int idx = l.indexOf(obj) + 1;
+						if (idx < l.size()) {
+							if (Util.moveElementByIndex(getEditingDomain(), (MUIElement) obj, getEditor().isLiveModel(), idx, targetFeature)) {
+								viewer.setSelection(new StructuredSelection(obj));
+							}
+						}
+					}
+				}
+			}
+		});
+
+		final ComboViewer childrenDropDown = new ComboViewer(buttonComp);
+		childrenDropDown.getControl().setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+		childrenDropDown.setContentProvider(new ArrayContentProvider());
+		childrenDropDown.setLabelProvider(new LabelProvider() {
+			@Override
+			public String getText(Object element) {
+				EClass eclass = (EClass) element;
+				return eclass.getName();
+			}
+		});
+		childrenDropDown.setInput(new EClass[] { BasicPackageImpl.Literals.TRIMMED_WINDOW, BasicPackageImpl.Literals.WINDOW, AdvancedPackageImpl.Literals.PERSPECTIVE_STACK, AdvancedPackageImpl.Literals.PERSPECTIVE, AdvancedPackageImpl.Literals.AREA, BasicPackageImpl.Literals.PART_SASH_CONTAINER, BasicPackageImpl.Literals.PART_STACK, BasicPackageImpl.Literals.PART, BasicPackageImpl.Literals.INPUT_PART, BasicPackageImpl.Literals.TRIM_BAR, BasicPackageImpl.Literals.TRIM_ELEMENT, });
+		childrenDropDown.setSelection(new StructuredSelection(AdvancedPackageImpl.Literals.PERSPECTIVE));
+
+		b = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
+		b.setImage(createImage(ResourceProvider.IMG_Obj16_table_add));
+		b.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false));
+		b.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				EClass eClass = (EClass) ((IStructuredSelection) childrenDropDown.getSelection()).getFirstElement();
+				handleAdd(eClass);
+			}
+		});
+
+		b = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
+		b.setText(Messages.ModelTooling_Common_Remove);
+		b.setImage(createImage(ResourceProvider.IMG_Obj16_table_delete));
+		b.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1));
+		b.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (!viewer.getSelection().isEmpty()) {
+					List<?> windows = ((IStructuredSelection) viewer.getSelection()).toList();
+					MElementContainer<?> container = (MElementContainer<?>) getMaster().getValue();
+					Command cmd = RemoveCommand.create(getEditingDomain(), container, targetFeature, windows);
+					if (cmd.canExecute()) {
+						getEditingDomain().getCommandStack().execute(cmd);
+						if (container.getChildren().size() > 0) {
+							viewer.setSelection(new StructuredSelection(container.getChildren().get(0)));
+						}
+					}
+				}
+			}
+		});
+
+		folder.setSelection(0);
+
+		return folder;
+	}
+
+	@Override
+	public IObservableList getChildList(Object element) {
+		return null;
+	}
+
+	@Override
+	public List<Action> getActions(Object element) {
+		ArrayList<Action> l = new ArrayList<Action>(super.getActions(element));
+		l.addAll(actions);
+		return l;
+	}
+
+	protected void handleAdd(EClass eClass) {
+		EObject handler = EcoreUtil.create(eClass);
+		setElementId(handler);
+
+		Command cmd = AddCommand.create(getEditingDomain(), getMaster().getValue(), targetFeature, handler);
+
+		if (cmd.canExecute()) {
+			getEditingDomain().getCommandStack().execute(cmd);
+			getEditor().setSelection(handler);
+		}
+	}
+}
\ No newline at end of file