/*
* AceEditorMixins.java
*
* Copyright (C) 2009-17 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
package org.rstudio.studio.client.workbench.views.source.editors.text;
import org.rstudio.core.client.BrowseCap;
import org.rstudio.core.client.StringUtil;
import org.rstudio.studio.client.JavaScriptEventHistory;
import org.rstudio.studio.client.RStudioGinjector;
import org.rstudio.studio.client.JavaScriptEventHistory.EventData;
import org.rstudio.studio.client.application.Desktop;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.AceEditorNative;
import org.rstudio.studio.client.workbench.views.source.editors.text.events.AceSelectionChangedEvent;
import com.google.inject.Inject;
public class AceEditorMixins
{
public AceEditorMixins(AceEditor editor)
{
RStudioGinjector.INSTANCE.injectMembers(this);
editor_ = editor.getWidget().getEditor();
initializeMixins(editor_);
// on Linux, record whenever the user selects something in Ace
if (BrowseCap.isLinuxDesktop())
{
editor.addSelectionChangedHandler(new AceSelectionChangedEvent.Handler()
{
@Override
public void onSelectionChanged(AceSelectionChangedEvent event)
{
String selection = editor_.getSelectedText();
if (!StringUtil.isNullOrEmpty(selection))
Desktop.getFrame().setGlobalMouseSelection(selection);
}
});
}
}
@Inject
private void initialize(JavaScriptEventHistory history)
{
history_ = history;
}
private final native void initializeMixins(AceEditorNative editor)
/*-{
// store reference to mixins object
var self = this;
// override the 'onPaste()' method provided by the Editor prototype
editor.$onPaste = editor.onPaste;
editor.onPaste = $entry(function(text) {
// call mixins method
self.@org.rstudio.studio.client.workbench.views.source.editors.text.AceEditorMixins::onPaste(Lorg/rstudio/studio/client/workbench/views/source/editors/text/ace/AceEditorNative;Ljava/lang/String;)(this, text);
});
}-*/;
private final void onPaste(AceEditorNative editor, String text)
{
// detect whether this paste event is issued in response to a middle click
// -- in such cases, we want to paste using the global mouse selection
boolean useGlobalMouseSelection =
BrowseCap.isLinuxDesktop() &&
isPasteTriggeredByMiddleClick();
if (useGlobalMouseSelection)
text = Desktop.getFrame().getGlobalMouseSelection();
// normalize line endings (Ace expects only '\n' line endings based
// on how we initialize it, and '\r\n' line endings cause issues)
text = text.replaceAll("\r\n|\r", "\n");
// invoke paste handler
invokePasteHandler(editor, text);
}
private final boolean isPasteTriggeredByMiddleClick()
{
// find the first key or mouse event in the JS event history
EventData event = history_.findEvent(new JavaScriptEventHistory.Predicate()
{
@Override
public boolean accept(EventData event)
{
String type = event.getType();
for (String candidate : CANDIDATES)
if (type.contentEquals(candidate))
return true;
return false;
}
private final String[] CANDIDATES = new String[] {
"mousedown", "click", "mouseup",
"keydown", "keypress", "keyup"
};
});
// shouldn't happen, but guard against failure to find any
// associated event
if (event == null)
return false;
// check to see if the middle mouse button was associated with
// this event
int button = event.getButton();
if (button != EventData.BUTTON_MIDDLE)
return false;
// ensure that this was a click-related mouse event
// (be permissive as to what mouse even occurred)
String type = event.getType();
return
type.equals("mousedown") ||
type.equals("click") ||
type.equals("mouseup");
}
private static final native void invokePasteHandler(AceEditorNative editor, String text)
/*-{
editor.$onPaste(text);
}-*/;
private final AceEditorNative editor_;
// Injected ----
private static JavaScriptEventHistory history_;
}