/**
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * Copyright © 2009 Mindoo GmbH
 *
 * @author Tammo Riedinger
 *
 */
package com.mindoo.ec09.example4;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import org.eclipse.albireo.core.SwingControl;
import org.eclipse.core.internal.registry.ExtensionRegistry;
import org.eclipse.core.runtime.ContributorFactoryOSGi;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IContributor;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IRegistryChangeListener;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.RegistryFactory;
import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.part.ViewPart;
import org.osgi.framework.Bundle;

import com.mindoo.ec09.framework.actions.ActionManager;
import com.mindoo.ec09.legacy.AbstractLegacyApplication;

/**
 * This sample demonstrates a simple life-cycle of a Swing application being integrated as a single view
 * into the Lotus Notes client.<br>
 * Additionally in this sample, dynamically registered action-sets are shown/hidden according to some internal state
 * of the sample application.<br>
 * It also supports the dynamic window-menu with a pulldown-action.
 *  
 * @author Tammo Riedinger
 */
public class SampleView extends ViewPart {
	/**
	 * Member to hold a reference to the displayed control.
	 */
	private SwingControl control;
	/**
	 * Member to hold a reference to the application being generated.
	 * This reference is used to free any resources used by the application
	 * when the ViewPart is disposed.
	 * In this case, the application-reference can be regarded as a bridge to the running application.
	 */
	private AbstractLegacyApplication app;
	private BufferingActionSetManager m_actionSetManager;

	@Override
	public void createPartControl(final Composite parent) {
		// instantiate the manager for the actionsets that are to be displayed
		m_actionSetManager=new DynamicActionSetManager(this);

		// start of life-cycle
		// Initialize the application and reposition its main-component	
		// to the SwingControl (e.g. return the main-component in SwingControl#createSwingComponent()).
		control=new SwingControl(parent, SWT.NONE) {
			@Override
			protected JComponent createSwingComponent() {
				try {
					// initialize our legacy application while overriding some of its methods
					app=new AbstractLegacyApplication() {
						@Override
					    protected void installMenuBar(Component window, Container contentPane) {
							// do nothing
						}
						
						@Override
						protected void installContentPane(Component window, Container contentPane) {
							super.installContentPane(window, contentPane);
							
							if (window instanceof JPanel) {
								((JPanel)window).add(contentPane,BorderLayout.CENTER);
							}
							else
								throw new RuntimeException("Unknown type of application window");
						}

					    @Override
					    protected Component createWindow() {
					    	JPanel panel=new JPanel(new BorderLayout());
					    	
							return panel;
						}
					    
					    @Override
						protected void show(Component window) {
							// do nothing
						}

						@Override
						protected void hide(Component window) {
							// do nothing
						}
						
						@Override
						protected ActionManager createActionManager(Component window, Container contentPane) {
							return new ActionManager(null,null) {
								@Override
								public void registerAction(Action a, String setID, String menuName, String toolbarName) {
									if (EXIT_ACTION==a) // do not append the exit-action
										return;
									super.registerAction(a, setID, menuName, toolbarName);
								}
								
								@Override
								public void activate(final String... setIDs) {
									super.activate(setIDs);
									
									// report activation of actionsets
									Display.getDefault().asyncExec(new Runnable() {
										public void run() {
											m_actionSetManager.activate(toExternalIDs(setIDs));
										}
									});
								}
								
								@Override
								public void deActivate(final String... setIDs) {
									super.deActivate(setIDs);
									// report deactivation of actionsets
									Display.getDefault().asyncExec(new Runnable() {
										public void run() {
											m_actionSetManager.deActivate(toExternalIDs(setIDs));
										}
									});
								}
								
								/**
								 * Convert all internal ids to those that do not conflict with other plugins.<br>
								 * We achieve this by prepending the id of the plugin.
								 * 
								 * @param ids		the ids
								 * @return			the converted ids
								 */
								private String[] toExternalIDs(String... ids) {
									ArrayList<String> externalIDs=new ArrayList<String>(ids.length);
									
									for (int i=0;i<ids.length;i++)
										externalIDs.add(Activator.PLUGIN_ID + ":" + ids[i]);
									
									return externalIDs.toArray(new String[0]);
								}
							};
						};
					};

					app.launch();
				} catch (Throwable t) {
					throw new RuntimeException(t);
				}
				

				// return the content-pane of the applet to be displayed inside the Swing-Control
				return (JComponent)((app!=null) ? app.getWindow() : null);
			}
			
			@Override
		    protected void afterComponentCreatedSWTThread() {
		    	// eventually make sure the visible frame has the focus
		    }

			@Override
			public Composite getLayoutAncestor() {
				return parent;
			}
		};
	}

	@Override
	public void dispose() {
		if (m_actionSetManager!=null)
			m_actionSetManager.dispose();
		
		// shut-down the instance of your legacy-application, 
		// when the last related ViewPart
		// in this case we use one instance per ViewPart
		super.dispose();

		if (app!=null) {
			// shut-down the application
			app.exit();
		}
		// end of life-cycle
	}

	@Override
	public void setFocus() {
		// hand the focus over to the control, whenever the ViewPart receives the focus
		if (control!=null && !control.isDisposed())
			control.setFocus();
	}

	/**
	 * Method to find a Swing action with the given name for the current view.<br>
	 * Note: Call this method from the Swing-EDT.
	 * 
	 * @param name			name of the action
	 * @return				the action or <code>null</code>
	 */
	public Action swing_findAction(String name) {
		if (app!=null) {
			ActionManager am=app.getActionManager();
			for (String setID:am.getActiveSetIDs()) {
				Iterator<Action> actions=am.getActions(setID);
				
				if (actions!=null) {
					while (actions.hasNext()) {
						Action a=actions.next();
						
						if (name.equals(a.getValue(Action.NAME)))
							return a;
					}
				}
			}
		}
		
		return null;
	}
	
	/**
	 * Method to be called in order to run a Swing-action with the given name.<br>
	 * The action will only be run, if it is currently active.
	 * 
	 * @param name		the name of the action
	 */
	public void runSwingAction(final String name) {
		if (app!=null) {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					Action a=swing_findAction(name);
					if (a!=null && a.isEnabled()) {
						Object command=a.getValue(Action.ACTION_COMMAND_KEY);
						
						a.actionPerformed(new ActionEvent(app.getWindow(),0,(command!=null) ? command.toString() : ""));
					}
				}
			});
		}
	}
	
	/**
	 * Method to be called in order to run a Swing-action with the given name.<br>
	 * The action will only be run, if it is currently active.
	 * 
	 * @param name		the name of the action
	 */
	public void runSwingAction(final Action a) {
		if (app!=null && a!=null) {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					if (a.isEnabled()) {
						Object command=a.getValue(Action.ACTION_COMMAND_KEY);
						
						a.actionPerformed(new ActionEvent(app.getWindow(),0,(command!=null) ? command.toString() : ""));
					}
				}
			});
		}
	}
	
	/**
	 * ActionSetManager that will register actionsets dynamically when needed.
	 * 
	 * @author Tammo Riedinger
	 *
	 */
	private static class DynamicActionSetManager extends BufferingActionSetManager {
		/** map of not currently loading action sets */
		private HashMap<String,String> m_trackedActionSets=new HashMap<String,String>();
		/** map of not yet loaded action sets */
		private HashMap<String,String> m_actionSetDefinitions=new HashMap<String,String>();
		/** instance of the extension tracker for dynamic extensions */
		private IExtensionTracker m_extensionTracker;
		/** handler to track dynamic extensions */
		private IExtensionChangeHandler m_extensionChanges=new IExtensionChangeHandler() {
			public void addExtension(IExtensionTracker tracker, IExtension extension) {
				for (IConfigurationElement configElement:extension.getConfigurationElements()) {
					if ("actionSet".equals(configElement.getName()))
						actionSetRegistered(configElement.getAttribute("id"));
				}
			}

			public void removeExtension(IExtension extension, Object[] objects) { }
		};
		
		/**
		 * Dispose this class and its used resources.
		 */
		public void dispose() {
			super.dispose();
			
			if (m_extensionTracker!=null) {
				m_extensionTracker.close();
				m_extensionTracker=null;
			}
		}
		
		/**
		 * Creates an instance of this class.
		 * 
		 * @param part		the part being monitored
		 */
		public DynamicActionSetManager(IWorkbenchPart part) {
			super(part);
			
			// fill the hashmap with the actionsets - probably you would like to automatically generate
			// these definition by querying your application object or a configuration file in a real-life application

			StringBuffer b=new StringBuffer();
			
			b.append("<actionSet id=\"com.mindoo.ec09.example4:com.mindoo.ec09.legacy.AbstractLegacyApplication\"");
			b.append(" label=\"Global actions\">");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.windows\"");
			b.append(" label=\"Windows\"");
			b.append(" menubarPath=\"window/additions\"");
			b.append(" tooltip=\"Action to switch to a different internal window\"");
			b.append(" style=\"pulldown\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.general\"");
			b.append(" icon=\"images/tab_duplicate.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Windows\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.find_address\"");
			b.append(" label=\"Find address\"");
			b.append(" menubarPath=\"file/com.ibm.rcp.ui.openmenu/open.ext\"");
			b.append(" tooltip=\"Find an address within the WorldWind-globe\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.general\"");
			b.append(" icon=\"images/package_network.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Find address\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.open_url\"");
			b.append(" label=\"Open url\"");
			b.append(" menubarPath=\"file/com.ibm.rcp.ui.openmenu/open.ext\"");
			b.append(" tooltip=\"Loads a URL with the document viewer\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.general\"");
			b.append(" icon=\"images/network.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Load URL\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.open_graph\"");
			b.append(" label=\"Open chart\"");
			b.append(" menubarPath=\"file/com.ibm.rcp.ui.openmenu/open.ext\"");
			b.append(" tooltip=\"Opens a file with the chart viewer\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.general\"");
			b.append(" icon=\"images/kcmpartitions.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Open chart\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.open_picture\"");
			b.append(" label=\"Open picture\"");
			b.append(" menubarPath=\"file/com.ibm.rcp.ui.openmenu/open.ext\"");
			b.append(" tooltip=\"Opens a file with the picture viewer\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.general\"");
			b.append(" icon=\"images/thumbnail.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Open picture\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.open_document\"");
			b.append(" label=\"Open document\"");
			b.append(" menubarPath=\"file/com.ibm.rcp.ui.openmenu/open.ext\"");
			b.append(" tooltip=\"Opens a file with the document viewer\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.general\"");
			b.append(" icon=\"images/wordprocessing.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Open document\">");
			b.append("</action>");
			b.append("</actionSet>");

			m_actionSetDefinitions.put("com.mindoo.ec09.example4:com.mindoo.ec09.legacy.AbstractLegacyApplication", b.toString());

			
			b.setLength(0);
			b.append("<actionSet id=\"com.mindoo.ec09.example4:com.mindoo.ec09.legacy.PictureView\"");
			b.append(" label=\"PictureView actions\">");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.zoom_out\"");
			b.append(" label=\"Zoom out\"");
			b.append("  menubarPath=\"com.ibm.rcp.ui.viewmenu/additions\"");
			b.append(" tooltip=\"Zooms further out of the displayed content\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.pictureview.view\"");
			b.append(" icon=\"images/viewmag_out.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Zoom out\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.zoom_in\"");
			b.append(" label=\"Zoom in\"");
			b.append(" menubarPath=\"com.ibm.rcp.ui.viewmenu/additions\"");
			b.append(" tooltip=\"Zooms further into the displayed content\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.pictureview.view\"");
			b.append(" icon=\"images/viewmag_in.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Zoom in\">");
			b.append("</action>");
			b.append("</actionSet>");
			m_actionSetDefinitions.put("com.mindoo.ec09.example4:com.mindoo.ec09.legacy.PictureView", b.toString());

			
			b.setLength(0);

			b.append("<actionSet id=\"com.mindoo.ec09.example4:com.mindoo.ec09.legacy.ChartView\"");
			b.append(" label=\"ChartView actions\">");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.zoom_out\"");
			b.append(" label=\"Zoom out\"");
			b.append(" menubarPath=\"com.ibm.rcp.ui.viewmenu/additions\"");
			b.append(" tooltip=\"Zooms further out of the displayed content\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.chartview.view\"");
			b.append(" icon=\"images/viewmag_out.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Zoom out\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.zoom_in\"");
			b.append(" label=\"Zoom in\"");
			b.append(" menubarPath=\"com.ibm.rcp.ui.viewmenu/additions\"");
			b.append(" tooltip=\"Zooms further into the displayed content\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.chartview.view\"");
			b.append(" icon=\"images/viewmag_in.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Zoom in\">");
			b.append("</action>");
			b.append("</actionSet>");
			m_actionSetDefinitions.put("com.mindoo.ec09.example4:com.mindoo.ec09.legacy.ChartView", b.toString());
			
			b.setLength(0);

			b.append("<actionSet id=\"com.mindoo.ec09.example4:com.mindoo.ec09.legacy.worldwind.WorldWindView\"");
			b.append(" label=\"WorldWind actions\">");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.zoom_out\"");
			b.append(" label=\"Zoom out\"");
			b.append(" menubarPath=\"com.ibm.rcp.ui.viewmenu/additions\"");
			b.append(" tooltip=\"Zooms further out of the displayed content\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.worldwind.view\"");
			b.append(" icon=\"images/viewmag_out.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Zoom out\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.zoom_in\"");
			b.append(" label=\"Zoom in\"");
			b.append(" menubarPath=\"com.ibm.rcp.ui.viewmenu/additions\"");
			b.append(" tooltip=\"Zooms further into the displayed content\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.worldwind.view\"");
			b.append(" icon=\"images/viewmag_in.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Zoom in\">");
			b.append("</action>");
			b.append("</actionSet>");
			m_actionSetDefinitions.put("com.mindoo.ec09.example4:com.mindoo.ec09.legacy.worldwind.WorldWindView", b.toString());
			
			b.setLength(0);
			b.append("<actionSet id=\"com.mindoo.ec09.example4:com.mindoo.ec09.legacy.TextView\"");
			b.append(" label=\"TextView actions\">");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.paste\"");
			b.append(" label=\"Paste\"");
			b.append(" menubarPath=\"edit/editStart\"");
			b.append(" tooltip=\"Pastes text from the clipboard to the editor\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.textview.edit\"");
			b.append(" icon=\"images/editpaste.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Paste\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.copy\"");
			b.append(" label=\"Copy\"");
			b.append(" menubarPath=\"edit/editStart\"");
			b.append(" tooltip=\"Copies text from the editor to the clipboard\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.textview.edit\"");
			b.append(" icon=\"images/editcopy.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Copy\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.cut\"");
			b.append(" label=\"Cut\"");
			b.append(" menubarPath=\"edit/editStart\"");
			b.append(" tooltip=\"Cuts text from the editor and copies it to the clipboard\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.textview.edit\"");
			b.append(" icon=\"images/cut.png\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Cut\">");
			b.append("</action>");
			b.append("<action id=\"com.mindoo.ec09.example4.actionsactions.select_all\"");
			b.append(" label=\"Select all\"");
			b.append(" menubarPath=\"edit/editStart\"");
			b.append(" tooltip=\"Selects all text within the editor\"");
			b.append(" toolbarPath=\"com.mindoo.ec09.example4.toolbars.textview.edit\"");
			b.append(" class=\"com.mindoo.ec09.example4.actions.SwingActionDelegate:Select all\">");
			b.append("</action>");
			b.append("</actionSet>");
			m_actionSetDefinitions.put("com.mindoo.ec09.example4:com.mindoo.ec09.legacy.TextView", b.toString());

			// install a tracker for changes to the actionsets extension point
			IExtensionRegistry reg=Platform.getExtensionRegistry();
			m_extensionTracker=new ExtensionTracker(reg);
			
			m_extensionTracker.registerHandler(m_extensionChanges,
					ExtensionTracker.createExtensionPointFilter(new IExtensionPoint[] {
							reg.getExtensionPoint("org.eclipse.ui.actionSets")
					})
				);
		}
		
		/**
		 * Called when a new actionset has been registered.
		 * 
		 * @param actionSetID			the id of the set
		 */
		private void actionSetRegistered(final String actionSetID) {
			Display.getDefault().asyncExec(new Runnable() {
				public void run() {
					if (m_trackedActionSets.remove(actionSetID)!=null)
						DynamicActionSetManager.super.activate(new String[] {actionSetID});
				}
			});
		}
		
		@Override
		public void activate(String[] actionSetIDs) {
			ArrayList<String> registeredSets=new ArrayList<String>();
			
			ArrayList<String> actionSetDefinitions=new ArrayList<String>();
			// check whether each actionset has already been registered
			for (String id:actionSetIDs) {
				String actionSetDefinition=m_actionSetDefinitions.remove(id);
				if (actionSetDefinition!=null) {
					actionSetDefinitions.add(actionSetDefinition);
					
					m_trackedActionSets.put(id,id); // note them down for tracking
				}
				else
					registeredSets.add(id);
			}
			
			// first activate the already registered sets
			if (registeredSets.size()>0)
				super.activate(registeredSets.toArray(new String[0]));
			
			// dynamically register the actionsets that have not been registered yet
			if (actionSetDefinitions.size()>0) {
				StringBuffer extension=new StringBuffer();
				extension.append("<plugin>");
				extension.append("<extension point=\"org.eclipse.ui.actionSets\">");
				
				for (String actionSetDefinition:actionSetDefinitions)
					extension.append(actionSetDefinition);
					
				extension.append("</extension>");
				extension.append("</plugin>");
				try {
					addExtension(extension.toString());
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}
		}
		
		@Override
		public void deActivate(String[] actionSetIDs) {
			for (String id:actionSetIDs) // remember to stop tracking deactivated sets
				m_trackedActionSets.remove(id);

			super.deActivate(actionSetIDs);
		}
		
		/**
		 * Add an extension dynamically by providing an string being a complete and valid
		 * plugin.xml declaring an extension point, like the following that declares a toolbar action within an actionset:<br>
		 * <code>
		 * &lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>
		 * &lt;plugin&gt;<br>
		 * 		&nbsp;&lt;extension point="org.eclipse.ui.actionSets"&gt;<br>
		 * 			&nbsp;&nbsp;&lt;actionSet visible="false" label="ActionSet" id="com.app.actionsets"&gt;<br>
		 * 				&nbsp;&nbsp;&nbsp;&lt;action id="action.idn label="Action" icon="action_icon.png" toolbarPath="toolbar.main/group1" class="com.app.ActionDelegate"/&gt;<br>
		 * 			&nbsp;&nbsp;&lt;/actionSet&gt;<br>
		 * 		&nbsp;&lt;/extension&gt;<br>
		 * &lt;/plugin&gt;
		 * </code>
		 * Note: Contributing to the plugin-registry is performed asynchronous by the framework. Register an {@link IRegistryChangeListener}
		 * with the registry, in order to be informed about any changes.
		 * 
		 * @param xmlsrc							the xml
		 * @throws UnsupportedEncodingException		thrown if the encoding is not utf-8
		 */
		public static void addExtension(String xmlsrc) throws UnsupportedEncodingException {
			// use  Eclipse Dynamic Extension API
			IExtensionRegistry reg = RegistryFactory.getRegistry();
			Object key = ((ExtensionRegistry)reg).getTemporaryUserToken();
			Bundle bundle =Activator.getDefault().getBundle();
			IContributor contributor = ContributorFactoryOSGi.createContributor(bundle);
			ByteArrayInputStream is = new ByteArrayInputStream(xmlsrc.getBytes("UTF-8"));
			reg.addContribution(is, contributor, false, null, null, key);
		}
	}
	
	/**
	 * ActionSetManager implementation that is buffering the actionsets that are currently being displayed.<br>
	 * Use {@link #activate(String[])} and {@link #deActivate(String[])} respectively to show or hide actionsets.
	 * 
	 * @author Tammo Riedinger
	 */
	private static class BufferingActionSetManager extends ActionSetManager {
		/** map of active action sets */
		private HashMap<String,String> m_actionSetIds=new HashMap<String,String>();

		/**
		 * Creates an instance of this class.
		 * 
		 * @param part		part whose activation/deactivation is being monitored
		 */
		public BufferingActionSetManager(IWorkbenchPart part) {
			super(part);
		}

		
		@Override
		protected String[] getActiveActionSetIDs() {
			return m_actionSetIds.keySet().toArray(new String[0]);
		}
		
		/**
		 * Show the given actionsets.
		 * 
		 * @param actionSetIDs		ids of actionsets to be activated
		 */
		public void activate(String[] actionSetIDs) {
			for (String id:actionSetIDs)
				m_actionSetIds.put(id,id);
			
			update();
		}
		
		/**
		 * Hide the given actionsets.
		 * 
		 * @param actionSetIDs		ids of actionsets to be hidden
		 */
		public void deActivate(String[] actionSetIDs) {
			for (String id:actionSetIDs)
				m_actionSetIds.remove(id);
			
			update();
		}
	}
}