316 lines
9.4 KiB
Java
316 lines
9.4 KiB
Java
// Copyright (C) 2009 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package com.google.gwtexpui.clippy.client;
|
|
|
|
import com.google.gwt.core.client.Scheduler;
|
|
import com.google.gwt.dom.client.Element;
|
|
import com.google.gwt.dom.client.Style.Display;
|
|
import com.google.gwt.event.dom.client.BlurEvent;
|
|
import com.google.gwt.event.dom.client.BlurHandler;
|
|
import com.google.gwt.event.dom.client.ClickEvent;
|
|
import com.google.gwt.event.dom.client.ClickHandler;
|
|
import com.google.gwt.event.dom.client.KeyPressEvent;
|
|
import com.google.gwt.event.dom.client.KeyPressHandler;
|
|
import com.google.gwt.event.dom.client.KeyUpEvent;
|
|
import com.google.gwt.event.dom.client.KeyUpHandler;
|
|
import com.google.gwt.event.dom.client.MouseOutEvent;
|
|
import com.google.gwt.event.dom.client.MouseOutHandler;
|
|
import com.google.gwt.http.client.URL;
|
|
import com.google.gwt.user.client.Command;
|
|
import com.google.gwt.user.client.DOM;
|
|
import com.google.gwt.user.client.ui.Button;
|
|
import com.google.gwt.user.client.ui.Composite;
|
|
import com.google.gwt.user.client.ui.FlowPanel;
|
|
import com.google.gwt.user.client.ui.HasText;
|
|
import com.google.gwt.user.client.ui.InlineLabel;
|
|
import com.google.gwt.user.client.ui.Label;
|
|
import com.google.gwt.user.client.ui.TextBox;
|
|
import com.google.gwtexpui.safehtml.client.SafeHtml;
|
|
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
|
import com.google.gwtexpui.user.client.Tooltip;
|
|
import com.google.gwtexpui.user.client.UserAgent;
|
|
|
|
/**
|
|
* Label which permits the user to easily copy the complete content.
|
|
*
|
|
* <p>If the Flash plugin is available a "movie" is embedded that provides one-click copying of the
|
|
* content onto the system clipboard. The label (if visible) can also be clicked, switching from a
|
|
* label to an input box, allowing the user to copy the text with a keyboard shortcut.
|
|
*/
|
|
public class CopyableLabel extends Composite implements HasText {
|
|
private static final int SWF_WIDTH = 110;
|
|
private static final int SWF_HEIGHT = 14;
|
|
private static boolean flashEnabled = true;
|
|
|
|
static {
|
|
ClippyResources.I.css().ensureInjected();
|
|
}
|
|
|
|
public static boolean isFlashEnabled() {
|
|
return flashEnabled;
|
|
}
|
|
|
|
public static void setFlashEnabled(boolean on) {
|
|
flashEnabled = on;
|
|
}
|
|
|
|
private static String swfUrl() {
|
|
return ClippyResources.I.swf().getSafeUri().asString();
|
|
}
|
|
|
|
private final FlowPanel content;
|
|
private String text;
|
|
private int visibleLen;
|
|
private Label textLabel;
|
|
private TextBox textBox;
|
|
private Button copier;
|
|
private Element swf;
|
|
|
|
public CopyableLabel() {
|
|
this("");
|
|
}
|
|
|
|
/**
|
|
* Create a new label
|
|
*
|
|
* @param str initial content
|
|
*/
|
|
public CopyableLabel(String str) {
|
|
this(str, true);
|
|
}
|
|
|
|
/**
|
|
* Create a new label
|
|
*
|
|
* @param str initial content
|
|
* @param showLabel if true, the content is shown, if false it is hidden from view and only the
|
|
* copy icon is displayed.
|
|
*/
|
|
public CopyableLabel(String str, boolean showLabel) {
|
|
content = new FlowPanel();
|
|
initWidget(content);
|
|
|
|
text = str;
|
|
visibleLen = text.length();
|
|
|
|
if (showLabel) {
|
|
textLabel = new InlineLabel(getText());
|
|
textLabel.setStyleName(ClippyResources.I.css().label());
|
|
textLabel.addClickHandler(
|
|
new ClickHandler() {
|
|
@Override
|
|
public void onClick(ClickEvent event) {
|
|
showTextBox();
|
|
}
|
|
});
|
|
content.add(textLabel);
|
|
}
|
|
|
|
if (UserAgent.hasJavaScriptClipboard()) {
|
|
copier =
|
|
new Button(
|
|
new SafeHtmlBuilder()
|
|
.openElement("img")
|
|
.setAttribute("src", ClippyResources.I.clipboard().getSafeUri().asString())
|
|
.setWidth(14)
|
|
.setHeight(14)
|
|
.closeSelf());
|
|
copier.setStyleName(ClippyResources.I.css().copier());
|
|
Tooltip.addStyle(copier);
|
|
Tooltip.setLabel(copier, CopyableLabelText.I.tooltip());
|
|
copier.addClickHandler(
|
|
new ClickHandler() {
|
|
@Override
|
|
public void onClick(ClickEvent event) {
|
|
copy();
|
|
}
|
|
});
|
|
copier.addMouseOutHandler(
|
|
new MouseOutHandler() {
|
|
@Override
|
|
public void onMouseOut(MouseOutEvent event) {
|
|
Tooltip.setLabel(copier, CopyableLabelText.I.tooltip());
|
|
}
|
|
});
|
|
|
|
FlowPanel p = new FlowPanel();
|
|
p.getElement().getStyle().setDisplay(Display.INLINE_BLOCK);
|
|
p.add(copier);
|
|
content.add(p);
|
|
} else {
|
|
embedMovie();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Change the text which is displayed in the clickable label.
|
|
*
|
|
* @param text the new preview text, should be shorter than the original text which would be
|
|
* copied to the clipboard.
|
|
*/
|
|
public void setPreviewText(String text) {
|
|
if (textLabel != null) {
|
|
textLabel.setText(text);
|
|
}
|
|
}
|
|
|
|
private void embedMovie() {
|
|
if (copier == null && flashEnabled && !text.isEmpty() && UserAgent.Flash.isInstalled()) {
|
|
final String flashVars = "text=" + URL.encodeQueryString(getText());
|
|
final SafeHtmlBuilder h = new SafeHtmlBuilder();
|
|
|
|
h.openElement("div");
|
|
h.setStyleName(ClippyResources.I.css().swf());
|
|
|
|
h.openElement("object");
|
|
h.setWidth(SWF_WIDTH);
|
|
h.setHeight(SWF_HEIGHT);
|
|
h.setAttribute("classid", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000");
|
|
h.paramElement("movie", swfUrl());
|
|
h.paramElement("FlashVars", flashVars);
|
|
|
|
h.openElement("embed");
|
|
h.setWidth(SWF_WIDTH);
|
|
h.setHeight(SWF_HEIGHT);
|
|
h.setAttribute("wmode", "transparent");
|
|
h.setAttribute("type", "application/x-shockwave-flash");
|
|
h.setAttribute("src", swfUrl());
|
|
h.setAttribute("FlashVars", flashVars);
|
|
h.closeSelf();
|
|
|
|
h.closeElement("object");
|
|
h.closeElement("div");
|
|
|
|
if (swf != null) {
|
|
getElement().removeChild(swf);
|
|
}
|
|
DOM.appendChild(getElement(), swf = SafeHtml.parse(h));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String getText() {
|
|
return text;
|
|
}
|
|
|
|
@Override
|
|
public void setText(String newText) {
|
|
text = newText;
|
|
visibleLen = newText.length();
|
|
|
|
if (textLabel != null) {
|
|
textLabel.setText(getText());
|
|
}
|
|
if (textBox != null) {
|
|
textBox.setText(getText());
|
|
textBox.selectAll();
|
|
}
|
|
embedMovie();
|
|
}
|
|
|
|
private void showTextBox() {
|
|
if (textBox == null) {
|
|
textBox = new TextBox();
|
|
textBox.setText(getText());
|
|
textBox.setVisibleLength(visibleLen);
|
|
textBox.setReadOnly(true);
|
|
textBox.addKeyPressHandler(
|
|
new KeyPressHandler() {
|
|
@Override
|
|
public void onKeyPress(KeyPressEvent event) {
|
|
if (event.isControlKeyDown() || event.isMetaKeyDown()) {
|
|
switch (event.getCharCode()) {
|
|
case 'c':
|
|
case 'x':
|
|
textBox.addKeyUpHandler(
|
|
new KeyUpHandler() {
|
|
@Override
|
|
public void onKeyUp(KeyUpEvent event) {
|
|
Scheduler.get()
|
|
.scheduleDeferred(
|
|
new Command() {
|
|
@Override
|
|
public void execute() {
|
|
hideTextBox();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
textBox.addBlurHandler(
|
|
new BlurHandler() {
|
|
@Override
|
|
public void onBlur(BlurEvent event) {
|
|
hideTextBox();
|
|
}
|
|
});
|
|
content.insert(textBox, 1);
|
|
}
|
|
|
|
textLabel.setVisible(false);
|
|
textBox.setVisible(true);
|
|
Scheduler.get()
|
|
.scheduleDeferred(
|
|
new Command() {
|
|
@Override
|
|
public void execute() {
|
|
textBox.selectAll();
|
|
textBox.setFocus(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void hideTextBox() {
|
|
if (textBox != null) {
|
|
textBox.removeFromParent();
|
|
textBox = null;
|
|
}
|
|
textLabel.setVisible(true);
|
|
}
|
|
|
|
private void copy() {
|
|
TextBox t = new TextBox();
|
|
try {
|
|
t.setText(getText());
|
|
content.add(t);
|
|
t.setFocus(true);
|
|
t.selectAll();
|
|
|
|
boolean ok = execCommand("copy");
|
|
Tooltip.setLabel(copier, ok ? CopyableLabelText.I.copied() : CopyableLabelText.I.failed());
|
|
if (!ok) {
|
|
// Disable JavaScript clipboard and try flash movie in another instance.
|
|
UserAgent.disableJavaScriptClipboard();
|
|
}
|
|
} finally {
|
|
t.removeFromParent();
|
|
}
|
|
}
|
|
|
|
private static boolean execCommand(String command) {
|
|
try {
|
|
return nativeExec(command);
|
|
} catch (Exception e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static native boolean nativeExec(String c) /*-{ return !! $doc.execCommand(c) }-*/;
|
|
}
|