/**
* This file Copyright (c) 2005-2008 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain other free and open source software ("FOSS") code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.editors.unified.actions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchWindow;
import com.aptana.ide.core.IdeLog;
import com.aptana.ide.editors.UnifiedEditorsPlugin;
import com.aptana.ide.editors.toolbar.IToolBarMember;
import com.aptana.ide.editors.toolbar.IToolbarContributionRegistry;
import com.aptana.ide.editors.toolbar.IToolbarRegistryContributor;
import com.aptana.ide.editors.toolbar.ToolBarContribution;
import com.aptana.ide.editors.unified.IUnifiedEditor;
import com.aptana.ide.editors.unified.InstanceCreator;
import com.aptana.ide.editors.unified.UnifiedConfiguration;
/**
* real implementation of {@link IToolBarContributionRegistry} lays here
* @author Pavel Petrochenko
*/
public final class ToolBarContributionRegistryImpl
{
private static final String TOOLBAR_ID = "com.aptana.ide.editors.toolbarContribution"; //$NON-NLS-1$
private static final Object TAG_ELEMENT = "element"; //$NON-NLS-1$
private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
private static final String ATTR_LANGUAGE = "language"; //$NON-NLS-1$
private static final Object TAG_CONTRIBUTOR = "contributor"; //$NON-NLS-1$
private static Map toolBarContributions = new HashMap();
private static Map toolBarContributionNames = new HashMap();
static WeakHashMap map = new WeakHashMap();
static WeakHashMap mapListener = new WeakHashMap();
private static IToolbarContributionRegistry toolbarContributionRegistry = new IToolbarContributionRegistry()
{
public void addContribution(String language, ToolBarContribution tc)
{
ToolBarContributionRegistryImpl.addContribution(language, tc);
}
public void removeContribution(String language, ToolBarContribution cont)
{
ToolBarContributionRegistryImpl.removeContribution(language, cont);
}
public List getContributions(String language)
{
return ToolBarContributionRegistryImpl.getContributions(language);
}
};
/**
* @return singleton instance of {@link IToolbarContributionRegistry}
*/
public static IToolbarContributionRegistry getInstance()
{
return toolbarContributionRegistry;
}
private static List getContributions(String language)
{
List list = (List) toolBarContributions.get(language);
if (list == null)
{
list = new ArrayList();
}
return list;
}
static
{
loadToolBarContributions();
}
/**
* @author Pavel Petrochenko
*/
private static final class ContextListener implements ISelectionChangedListener
{
private final IToolBarManager toolBarManager;
private final TextViewer tv;
private final IUnifiedEditor activeEditor;
private ContextListener(IToolBarManager toolBarManager, TextViewer tv, IUnifiedEditor activeEditor)
{
this.toolBarManager = toolBarManager;
this.tv = tv;
this.activeEditor = activeEditor;
}
/**
* @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
*/
public void selectionChanged(SelectionChangedEvent event)
{
ITextSelection ts = (ITextSelection) event.getSelection();
int offset = ts.getOffset();
try
{
String type = TextUtilities.getContentType(tv.getDocument(), UnifiedConfiguration.UNIFIED_PARTITIONING,
offset, true);
doUpdate(type);
}
catch (BadLocationException e)
{
return;
}
}
/**
* updates toolbar it it is needed
* @param chType
*/
public void updateIfNeeded(String chType)
{
if (tv.getTextWidget().isDisposed())
{
return;
}
ITextSelection ts = (ITextSelection) tv.getSelection();
int offset = ts.getOffset();
try
{
String type = TextUtilities.getContentType(tv.getDocument(), UnifiedConfiguration.UNIFIED_PARTITIONING,
offset, true);
if (chType.equals(type))
{
updateToolbar(toolBarManager, type, activeEditor);
toolBarManager.update(false);
}
}
catch (BadLocationException e)
{
return;
}
}
//real update
private void doUpdate(String type)
{
if (type != null && !type.equals(map.get(activeEditor)))
{
map.put(activeEditor, type);
updateToolbar(toolBarManager, type, activeEditor);
toolBarManager.update(false);
WorkbenchWindow activeWorkbenchWindow = (WorkbenchWindow) PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
// workarounding eclipse strange behavior
activeWorkbenchWindow.getCoolBarManager2().update(true);
}
}
}
private ToolBarContributionRegistryImpl()
{
}
/**
* @param activeEditor
* @param toolBarManager
*/
static void initToolBar(final IUnifiedEditor activeEditor, final IToolBarManager toolBarManager)
{
String defaultLanguage = activeEditor.getFileContext().getDefaultLanguage();
ISourceViewer viewer = activeEditor.getViewer();
String cLang = (String) map.get(activeEditor);
if (viewer instanceof TextViewer && cLang == null)
{
final TextViewer tv = (TextViewer) viewer;
map.put(activeEditor, defaultLanguage);
final ContextListener selectionChangedListener = new ContextListener(toolBarManager, tv, activeEditor);
tv.addPostSelectionChangedListener(selectionChangedListener);
mapListener.put(activeEditor, selectionChangedListener);
tv.getTextWidget().addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
tv.removePostSelectionChangedListener(selectionChangedListener);
mapListener.remove(activeEditor);
}
});
tv.getTextWidget().addFocusListener(new FocusListener()
{
public void focusGained(FocusEvent e)
{
map.remove(activeEditor);
selectionChangedListener.selectionChanged(new SelectionChangedEvent(tv, tv.getSelection()));
}
public void focusLost(FocusEvent e)
{
}
});
}
if (cLang != null)
{
defaultLanguage = cLang;
}
// activeEditor.getViewer().getTextWidget().getCaret().addListener(eventType, listener)
updateToolbar(toolBarManager, defaultLanguage, activeEditor);
}
private static void updateToolbar(final IToolBarManager toolBarManager, String defaultLanguage,
final IUnifiedEditor editor)
{
toolBarManager.removeAll();
ArrayList contributions = (ArrayList) toolBarContributions.get(defaultLanguage);
if (contributions != null)
{
for (Iterator iterator = contributions.iterator(); iterator.hasNext();)
{
final ToolBarContribution name = (ToolBarContribution) iterator.next();
Action action = new Action(name.getText(), Action.AS_PUSH_BUTTON)
{
public void run()
{
IToolBarMember member = (IToolBarMember) name.getInstance();
member.execute(editor, name.getText());
}
};
action.setImageDescriptor(name.getIcon());
action.setToolTipText(name.getTooltipText());
toolBarManager.add(action);
}
}
}
private static void loadToolBarContributions()
{
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint ep = registry.getExtensionPoint(TOOLBAR_ID);
if (ep != null)
{
IExtension[] extensions = ep.getExtensions();
for (int i = 0; i < extensions.length; i++)
{
IExtension extension = extensions[i];
IConfigurationElement[] elements = extension.getConfigurationElements();
// initialize contributors first
for (int j = 0; j < elements.length; j++)
{
try
{
IConfigurationElement element = elements[j];
String elementName = element.getName();
if (elementName.equals(TAG_CONTRIBUTOR))
{
IToolbarRegistryContributor contributor = (IToolbarRegistryContributor) element
.createExecutableExtension(ATTR_CLASS);
contributor.contributeToToolbarRegistry(toolbarContributionRegistry);
}
}
catch (Exception e)
{
IdeLog.log(UnifiedEditorsPlugin.getDefault(), IStatus.ERROR,
"Exception while initializing toolbar contribution registry", e); //$NON-NLS-1$
}
}
for (int j = 0; j < elements.length; j++)
{
IConfigurationElement element = elements[j];
String elementName = element.getName();
try
{
if (elementName.equals(TAG_ELEMENT))
{
String parserClass = element.getAttribute(ATTR_CLASS);
String language = element.getAttribute(ATTR_LANGUAGE);
String icon = element.getAttribute("icon"); //$NON-NLS-1$
String text = element.getAttribute("name"); //$NON-NLS-1$
String tooltip = element.getAttribute("tooltip"); //$NON-NLS-1$
InstanceCreator creator = null;
if (parserClass != null && language != null && language.length() > 0)
{
creator = new InstanceCreator(element, ATTR_CLASS);
}
String namespaceIdentifier = extension.getNamespaceIdentifier();
ImageDescriptor desc = null;
if (icon != null && icon.length() > 0)
{
desc = ImageDescriptor.createFromURL(Platform.getBundle(namespaceIdentifier).getEntry(
icon));
}
ToolBarContribution tc = new ToolBarContribution(text, tooltip, desc, creator);
addContribution(language, tc);
}
}
catch (Exception e)
{
IdeLog.log(UnifiedEditorsPlugin.getDefault(), IStatus.ERROR,
"Exception while initializing toolbar contribution registry", e); //$NON-NLS-1$
}
}
}
}
}
private static void addContribution(String language, ToolBarContribution tc)
{
HashSet set = (HashSet) toolBarContributionNames.get(language);
if (set == null)
{
set = new HashSet();
toolBarContributionNames.put(language, set);
}
if (set.contains(tc.getText()))
{
return;
}
set.add(tc.getText());
ArrayList list = (ArrayList) toolBarContributions.get(language);
if (list == null)
{
list = new ArrayList();
toolBarContributions.put(language, list);
}
list.add(tc);
update(language);
}
/**
* @param language
* @param cont
*/
private static void removeContribution(String language, ToolBarContribution cont)
{
ArrayList list = (ArrayList) toolBarContributions.get(language);
HashSet set = (HashSet) toolBarContributionNames.get(language);
if (list == null)
{
return;
}
boolean remove = list.remove(cont);
if (remove)
{
set.remove(cont.getText());
update(language);
}
}
private static void update(String language)
{
for (Iterator iterator = mapListener.values().iterator(); iterator.hasNext();)
{
ContextListener name = (ContextListener) iterator.next();
name.updateIfNeeded(language);
}
}
}