/** * Aptana Studio * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). * Please see the license.html included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package com.aptana.ruby.internal.rake.actions; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.expressions.IEvaluationContext; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.ContributionItem; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.ISources; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.menus.IWorkbenchContribution; import org.eclipse.ui.services.IEvaluationService; import org.eclipse.ui.services.IServiceLocator; import com.aptana.ruby.rake.IRakeHelper; import com.aptana.ruby.rake.RakePlugin; public class RakeTasksContributionItem extends ContributionItem implements IWorkbenchContribution { static final String RAKE_NAMESPACE_DELIMETER = ":"; //$NON-NLS-1$ private Map<String, MenuManager> fNamespaces; private IServiceLocator serviceLocator; public RakeTasksContributionItem() { } public RakeTasksContributionItem(String id) { super(id); } @Override public void fill(Menu menu, int index) { IProject project = getProject(); if (project == null) { return; } Map<String, String> tasks = getRakeHelper().getTasks(project, new NullProgressMonitor()); fNamespaces = new HashMap<String, MenuManager>(); // Please note that tehre's a lot of code mixed up in here to ensure that the menus, items and sub-menus all // appear alphabetically List<String> values = new ArrayList<String>(tasks.keySet()); Collections.sort(values); for (String task : values) { String[] paths = task.split(RAKE_NAMESPACE_DELIMETER); if (paths.length == 1) { IAction action = new RunRakeAction(project, task, tasks.get(task)); ActionContributionItem item = new ActionContributionItem(action); item.fill(menu, -1); } else { MenuManager manager = getOrCreate(paths); manager.add(new RunRakeAction(project, task, tasks.get(task))); } } values = new ArrayList<String>(fNamespaces.keySet()); Collections.sort(values); Collections.reverse(values); for (String path : values) { MenuManager manager = fNamespaces.get(path); String[] parts = path.split(RAKE_NAMESPACE_DELIMETER); if (parts.length == 1) { int index2 = getInsertIndex(menu, manager); manager.fill(menu, index2); } else { MenuManager parent = getParent(parts); if (parent != null) { int index2 = getInsertIndex(parent, manager); parent.insert(index2, manager); } else { int index2 = getInsertIndex(menu, manager); manager.fill(menu, index2); } } } } private IProject getProject() { IResource resource = getSelectedResource(); if (resource == null) { return null; } return resource.getProject(); } private IResource getSelectedResource() { IEvaluationService evalService = (IEvaluationService) serviceLocator.getService(IEvaluationService.class); if (evalService != null) { IEvaluationContext context = evalService.getCurrentState(); IWorkbenchPart activePart = (IWorkbenchPart) context.getVariable(ISources.ACTIVE_PART_NAME); if (activePart instanceof IEditorPart) { IEditorInput input = (IEditorInput) context.getVariable(ISources.ACTIVE_EDITOR_INPUT_NAME); return (IResource) input.getAdapter(IResource.class); } ISelection selection = (ISelection) context.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME); if (selection instanceof IStructuredSelection) { IStructuredSelection struct = (IStructuredSelection) selection; Object firstElement = struct.getFirstElement(); if (firstElement instanceof IResource) { return (IResource) firstElement; } else if (firstElement instanceof IAdaptable) { IAdaptable adaptable = (IAdaptable) firstElement; return (IResource) adaptable.getAdapter(IResource.class); } } } return null; } /** * For inserting submenus under submenus * * @param parent * @param item * @return */ private int getInsertIndex(MenuManager parent, MenuManager item) { if (parent == null || item == null) { return 0; } String text = item.getMenuText(); if (text == null) { return 0; } IContributionItem[] items = parent.getItems(); if (items == null) { return 0; } int index = 0; for (int i = 0; i < items.length; i++) { if (items[i] == null) continue; if (items[i] instanceof ActionContributionItem) { ActionContributionItem actionItem = (ActionContributionItem) items[i]; IAction action = actionItem.getAction(); if (action == null) continue; String other = action.getText(); if (text.compareTo(other) >= 0) { index = i + 1; } else { break; } } } return index; } /** * For inserting submenus at first level. * * @param parent * @param item * @return */ private int getInsertIndex(Menu parent, MenuManager item) { String text = item.getMenuText(); MenuItem[] items = parent.getItems(); int index = 0; for (int i = 0; i < items.length; i++) { String other = items[i].getText(); if (text.compareTo(other) >= 0) { index = i + 1; } else { break; } } return index; } protected IRakeHelper getRakeHelper() { return RakePlugin.getDefault().getRakeHelper(); } private MenuManager getParent(String[] parts) { String[] part = stripLastItem(parts); return fNamespaces.get(join(part)); } private String join(String[] part) { StringBuilder buffer = new StringBuilder(); for (int i = 0; i < part.length; i++) { if (i != 0) { buffer.append(RAKE_NAMESPACE_DELIMETER); } buffer.append(part[i]); } return buffer.toString(); } private MenuManager getOrCreate(String[] paths) { String[] part = stripLastItem(paths); MenuManager manager = fNamespaces.get(join(part)); if (manager == null) { manager = new MenuManager(part[part.length - 1]); fNamespaces.put(join(part), manager); } return manager; } private String[] stripLastItem(String[] paths) { String[] part = new String[paths.length - 1]; System.arraycopy(paths, 0, part, 0, part.length); return part; } public void initialize(IServiceLocator serviceLocator) { this.serviceLocator = serviceLocator; } }