/*******************************************************************************
* Copyright (c) 2011 Andrey Loskutov.
* All rights reserved. This program and the accompanying materials
* are 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
* Contributor: Andrey Loskutov - initial API and implementation
*******************************************************************************/
package de.loskutov.anyedit.actions.internal;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IExecutionListener;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.ICoolBarManager;
import org.eclipse.jface.action.ToolBarContributionItem;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.internal.WorkbenchWindow;
import org.eclipse.ui.menus.CommandContributionItem;
import de.loskutov.anyedit.AnyEditToolsPlugin;
import de.loskutov.anyedit.IAnyEditConstants;
import de.loskutov.anyedit.actions.Spaces;
import de.loskutov.anyedit.ui.editor.AbstractEditor;
import de.loskutov.anyedit.util.EclipseUtils;
/**
* @author Andrey
*/
public class StartupHelper2 {
private static final String FILE_SAVE_ALL = "org.eclipse.ui.file.saveAll";
private static final String FILE_SAVE = "org.eclipse.ui.file.save";
private static final class DummyAction extends Action {
public DummyAction(String actionId) {
setId(actionId);
}
}
/**
* Will be run after workbench is started and w.window is opened
*/
public StartupHelper2() {
super();
}
public void init() {
final IWorkbench workbench = PlatformUI.getWorkbench();
workbench.getDisplay().asyncExec(new DirtyHookRunnable());
}
/**
* Very dirty trick to get internal handle to WorkbenchWindowConfigurer.
* @param ww
*/
static IWorkbenchWindowConfigurer getWorkbenchWindowConfigurer(IWorkbenchWindow ww) {
if (!(ww instanceof WorkbenchWindow)) {
return null;
}
try {
Method method = WorkbenchWindow.class.getDeclaredMethod(
"getWindowConfigurer", null);
method.setAccessible(true);
Object object = method.invoke(ww, null);
if (object instanceof IWorkbenchWindowConfigurer) {
return (IWorkbenchWindowConfigurer) object;
}
} catch (Exception e) {
AnyEditToolsPlugin.logError(
"Can't get handle for WorkbenchWindowConfigurer", e); //$NON-NLS-1$
}
return null;
}
private void hookOnCommand(String commandId) {
ICommandService service = (ICommandService) PlatformUI.getWorkbench().getService(
ICommandService.class);
Command command = service.getCommand(commandId);
PreExecutionHandler listener = new PreExecutionHandler(commandId);
command.addExecutionListener(listener);
}
private static class PreExecutionHandler implements IExecutionListener {
final Spaces spacesAction;
final IAction spacesToTabs = new DummyAction(IAnyEditConstants.ACTION_ID_CONVERT_SPACES);
final IAction tabsToSpaces = new DummyAction(IAnyEditConstants.ACTION_ID_CONVERT_TABS);
final String commandId;
PreExecutionHandler(String commandId) {
this.commandId = commandId;
spacesAction = new Spaces(){
@Override
protected AbstractEditor createActiveEditorDelegate() {
// this just returns the editor instance we already know, see runSpecial()
return getEditor();
}
@Override
public void setEditor(AbstractEditor editor) {
if(editor == null && getEditor() != null){
getEditor().dispose();
}
this.editor = editor;
}
};
spacesAction.setUsedOnSave(true);
}
@Override
public void notHandled(String command, NotHandledException exception) {
//
}
@Override
public void postExecuteFailure(String command, ExecutionException exception) {
//
}
@Override
public void postExecuteSuccess(String command, Object returnValue) {
//
}
@Override
public void preExecute(String command, ExecutionEvent event) {
runBeforeSave(event);
}
/**
* Performs the 'convert spaces' action before the editor buffer is saved
*/
public void runBeforeSave(ExecutionEvent event) {
try {
if(FILE_SAVE.equals(commandId)) {
runSpecial(event);
} else {
runSpecial2(event);
}
} catch (Throwable e) {
// to avoid any problems with any possible environements
// we trying to catch all errors to allow perform base save action
AnyEditToolsPlugin.logError("Cannot perform custom pre-save action", e); //$NON-NLS-1$
} finally {
spacesAction.setEditor(null);
}
}
private void runSpecial(ExecutionEvent event) {
IEditorPart part = HandlerUtil.getActiveEditor(event);
if(part == null) {
// workaround for http://code.google.com/a/eclipselabs.org/p/anyedittools/issues/detail?id=73
part = EclipseUtils.getActiveEditor();
if(part == null) {
return;
}
}
spacesAction.setActiveEditor(null, part);
boolean trim = spacesAction.isSaveAndTrimEnabled();
boolean convert = spacesAction.isSaveAndConvertEnabled();
if(trim || convert){
if(EclipseUtils.matchFilter(part, spacesAction.getCombinedPreferences())){
return;
}
final IAction action;
if(spacesAction.isDefaultTabToSpaces()){
action = tabsToSpaces;
} else {
action = spacesToTabs;
}
spacesAction.run(action);
}
}
private void runSpecial2(ExecutionEvent event) {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
if (window == null) {
window = AnyEditToolsPlugin.getDefault().getWorkbench()
.getActiveWorkbenchWindow();
if(window == null) {
// action has been disposed
return;
}
}
IWorkbenchPage page = window.getActivePage();
final IEditorPart[] dirtyEditors = page.getDirtyEditors();
final int editorsCount = dirtyEditors.length;
if(editorsCount == 0) {
return;
}
IRunnableWithProgress runnable = new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
monitor.beginTask("Converting tabs <-> spaces before save", editorsCount);
try {
for (int i = 0; i < editorsCount; i++) {
if (monitor.isCanceled()) {
break;
}
monitor.worked(1);
IEditorPart part = dirtyEditors[i];
spacesAction.setActiveEditor(null, part);
boolean trim = spacesAction.isSaveAndTrimEnabled();
boolean convert = spacesAction.isSaveAndConvertEnabled();
if (trim || convert) {
if (EclipseUtils.matchFilter(part,
spacesAction.getCombinedPreferences())) {
continue;
}
monitor.subTask(part.getTitle());
final IAction action;
if (spacesAction.isDefaultTabToSpaces()) {
action = tabsToSpaces;
} else {
action = spacesToTabs;
}
spacesAction.run(action);
}
}
} finally {
monitor.done();
}
}
};
try {
PlatformUI.getWorkbench().getProgressService().run(false, true, runnable);
} catch (InvocationTargetException e) {
AnyEditToolsPlugin.logError("Error during custom pre-save action", e);
} catch (InterruptedException e) {
// user cancel
}
}
}
private final class DirtyHookRunnable implements Runnable {
private static final String PRINT_BUTTON_ID = "print";
private static final String FILE_TOOLBAR = "org.eclipse.ui.workbench.file";
private DirtyHookRunnable() {
super();
}
@Override
public void run() {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window == null) {
return;
}
try{
run(window);
} catch (Throwable t){
AnyEditToolsPlugin.logError("Can't run dirty code to replace default actions", t);
}
}
private void run(IWorkbenchWindow window) {
hookOnCommand(FILE_SAVE);
hookOnCommand(FILE_SAVE_ALL);
boolean removePrint = getPref(IAnyEditConstants.REMOVE_PRINT_FROM_TOOLBAR);
if (!removePrint) {
return;
}
IWorkbenchWindowConfigurer wwConf = getWorkbenchWindowConfigurer(window);
if (wwConf == null) {
return;
}
IActionBarConfigurer configurer = wwConf.getActionBarConfigurer();
configurer.getMenuManager();
// get "file" menu group
IContributionItem item;
ICoolBarManager coolBar = configurer.getCoolBarManager();
// get "file" toolbar group
item = coolBar.find(FILE_TOOLBAR);
if (item instanceof ToolBarContributionItem) {
ToolBarContributionItem item2 = (ToolBarContributionItem) item;
ToolBarManager manager = (ToolBarManager) item2.getToolBarManager();
remove(manager, PRINT_BUTTON_ID);
// to resize toolbars after changes...
coolBar.update(true);
}
}
}
private static void remove(IContributionManager manager, String id) {
IContributionItem[] items = manager.getItems();
for (int i = 0; i < items.length; i++) {
if (items[i].isSeparator() || items[i] instanceof ActionContributionItem
|| items[i] instanceof CommandContributionItem) {
if (id.equals(items[i].getId())) {
IContributionItem item = manager.remove(items[i]);
// refresh menu gui
manager.update(true);
if (item != null) {
item.dispose();
}
break;
}
}
}
}
private static boolean getPref(String prefkey) {
IPreferenceStore store = AnyEditToolsPlugin.getDefault().getPreferenceStore();
return store.getBoolean(prefkey);
}
}