/**
* Copyright (c) 2009, 2014 Mark Feber, MulgaSoft
*
* 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
*/
package com.mulgasoft.emacsplus.commands;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.ui.texteditor.ITextEditor;
import com.mulgasoft.emacsplus.EmacsPlusUtils;
import com.mulgasoft.emacsplus.IEmacsPlusCommandDefinitionIds;
import com.mulgasoft.emacsplus.execute.KbdMacroSupport;
import com.mulgasoft.emacsplus.execute.KbdMacroSupport.IKbdExecutionListener;
/**
* Start defining a keyboard macro
*
* If called with ^U, append keys to the last keyboard macro after re-executing it.
* If called with ^U ^U, append keys to the last keyboard macro without re-executing it.
*
* @author Mark Feber - initial API and implementation
*/
public class KbdMacroStartHandler extends EmacsPlusCmdHandler {
private static String KBD_START_MSG = "KbdMacro_Start"; //$NON-NLS-1$
private static String KBD_APPEND_MSG = "KbdMacro_Append"; //$NON-NLS-1$
protected static final String NO_MACRO_ERROR = "KbdMacro_No_Error"; //$NON-NLS-1$
private final static int WAIT_TIME = 5000;
private final static int SLEEP_TIME = 500;
public Object execute(final ExecutionEvent event) throws ExecutionException {
final ITextEditor editor = getTextEditor(event);
if (editor != null) {
final int uArg = this.extractUniversalCount(event);
if (uArg > 1 && (!KbdMacroSupport.getInstance().hasKbdMacro() || KbdMacroSupport.getInstance().isBusy())) {
beep();
asyncShowMessage(editor, NO_MACRO_ERROR, true);
} else if (uArg > 1 && uArg < 16) {
// pre-execute the current macro before continuing with the definition
new Thread(new Runnable() {
// do this in a separate thread, so the ui thread can complete the macro before we queue the start
public void run() {
final CountDownLatch latch = new CountDownLatch(1);
try {
// give time for fingers to leave the keyboard and any key up events to come through
Thread.sleep(SLEEP_TIME);
// register for execution completion before queue
KbdMacroExecuteHandler.addExecutionListener(new IKbdExecutionListener() {
public void executionDone() {
latch.countDown();
}
});
EmacsPlusUtils.asyncUiRun(new Runnable() {
public void run() {
try {
KbdMacroStartHandler.this.executeCommand(IEmacsPlusCommandDefinitionIds.KBDMACRO_EXECUTE, null, editor);
} catch (Exception e) { e.printStackTrace();}
}
});
latch.await(WAIT_TIME,TimeUnit.MILLISECONDS);
} catch (Exception e) {e.printStackTrace();}
queueStart(editor,uArg);
}
}).start();
} else {
queueStart(editor,uArg);
}
}
return null;
}
/**
* Queue the definition start
*
* @param editor
* @param uArg
*/
private void queueStart(final ITextEditor editor, final int uArg) {
// queue the definition
EmacsPlusUtils.asyncUiRun(new Runnable() {
public void run() {
KbdMacroSupport.getInstance().startKbdMacro(editor, uArg > 1);
KbdMacroStartHandler.this.asyncShowMessage(editor, (uArg > 1) ? KBD_APPEND_MSG : KBD_START_MSG, false);
}
});
}
/**
* @see com.mulgasoft.emacsplus.commands.EmacsPlusCmdHandler#transform(ITextEditor, IDocument, ITextSelection, ExecutionEvent)
*/
@Override
protected int transform(ITextEditor editor, IDocument document,
ITextSelection currentSelection, ExecutionEvent event)
throws BadLocationException {
return NO_OFFSET;
}
@Override
protected boolean isLooping() {
return false;
}
}