You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ClipboardDialog.java 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright (C) 2011-2014 Brian P. Hinz
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  17. * USA.
  18. */
  19. package com.tigervnc.vncviewer;
  20. import java.awt.*;
  21. import java.awt.event.*;
  22. import java.awt.datatransfer.*;
  23. import java.io.*;
  24. import java.nio.*;
  25. import javax.swing.*;
  26. import javax.swing.border.*;
  27. import javax.swing.event.*;
  28. import javax.swing.text.*;
  29. import com.tigervnc.rfb.LogWriter;
  30. import static com.tigervnc.vncviewer.Parameters.*;
  31. class ClipboardDialog extends Dialog {
  32. protected static class MyJTextArea extends JTextArea {
  33. private class VncTransferHandler extends TransferHandler {
  34. // Custom TransferHandler designed to limit the size of outbound
  35. // clipboard transfers to VncViewer.maxCutText.getValue() bytes.
  36. private LogWriter vlog = new LogWriter("VncTransferHandler");
  37. private long start;
  38. public void exportToClipboard(JComponent comp, Clipboard clip, int action)
  39. throws IllegalStateException {
  40. if (action != TransferHandler.COPY) return;
  41. if (start == 0)
  42. start = System.currentTimeMillis();
  43. StringSelection selection = new StringSelection(((JTextArea)comp).getText());
  44. try {
  45. clip.setContents(selection, selection);
  46. } catch(IllegalStateException e) {
  47. // something else has the clipboard, keep trying for at most 50ms
  48. if ((System.currentTimeMillis() - start) < 50)
  49. exportToClipboard(comp, clip, action);
  50. else
  51. vlog.info("Couldn't access system clipboard for > 50ms");
  52. }
  53. start = 0;
  54. }
  55. public boolean importData(JComponent c, Transferable t) {
  56. if (canImport(c, t.getTransferDataFlavors())) {
  57. try {
  58. DataFlavor VncFlavor = null;
  59. for (DataFlavor f : t.getTransferDataFlavors()) {
  60. if (f.isMimeTypeEqual("text/plain") &&
  61. f.isRepresentationClassInputStream()) {
  62. VncFlavor = f;
  63. break;
  64. }
  65. }
  66. if (VncFlavor == null) return false;
  67. CharBuffer cbuf =
  68. CharBuffer.allocate(maxCutText.getValue());
  69. Reader reader = (Reader)VncFlavor.getReaderForText(t);
  70. int n = reader.read(cbuf.array(), 0, cbuf.length());
  71. reader.close();
  72. // reader returns -1 (EOF) for empty clipboard
  73. cbuf.limit(n < 0 ? 0 : n);
  74. if (c instanceof JTextComponent)
  75. if (!cbuf.toString().equals(((JTextComponent)c).getText()))
  76. ((JTextComponent)c).setText(cbuf.toString());
  77. return true;
  78. } catch (OutOfMemoryError e) {
  79. vlog.error("ERROR: Too much data on local clipboard!");
  80. } catch (UnsupportedFlavorException e) {
  81. // Skip import
  82. vlog.info(e.toString());
  83. } catch (IOException e) {
  84. // Skip import
  85. vlog.info(e.toString());
  86. }
  87. }
  88. return false;
  89. }
  90. public boolean canImport(JComponent c, DataFlavor[] flavors) {
  91. for (DataFlavor f : flavors)
  92. if (f.isMimeTypeEqual("text/plain") &&
  93. f.isRepresentationClassReader())
  94. return true;
  95. return false;
  96. }
  97. }
  98. private class MyTextListener implements DocumentListener {
  99. public MyTextListener() { }
  100. public void changedUpdate(DocumentEvent e) { }
  101. public void insertUpdate(DocumentEvent e) {
  102. if (!listen) return;
  103. String text = textArea.getText();
  104. if (sendClipboard.getValue())
  105. VncViewer.cc.writeClientCutText(text, text.length());
  106. }
  107. public void removeUpdate(DocumentEvent e) { }
  108. }
  109. public MyJTextArea() {
  110. super();
  111. setTransferHandler(new VncTransferHandler());
  112. getDocument().addDocumentListener(new MyTextListener());
  113. // If the textArea can receive the focus, then text within the textArea
  114. // can be selected. On platforms that don't support separate selection
  115. // and clipboard buffers, this triggers a replacement of the textAra's
  116. // contents with the selected text.
  117. setFocusable(false);
  118. setLineWrap(false);
  119. setWrapStyleWord(true);
  120. }
  121. }
  122. public ClipboardDialog() {
  123. super(false);
  124. setTitle("VNC Clipboard Viewer");
  125. setPreferredSize(new Dimension(640, 480));
  126. addWindowFocusListener(new WindowFocusListener() {
  127. // Necessary to ensure that updates from the system clipboard
  128. // are propagated to the textArea when the dialog is visible.
  129. public void windowGainedFocus(WindowEvent e) {
  130. clientCutText();
  131. }
  132. public void windowLostFocus(WindowEvent e) { }
  133. });
  134. JScrollPane sp = new JScrollPane(textArea);
  135. getContentPane().add(sp, BorderLayout.CENTER);
  136. // button panel placed below the scrollpane
  137. JPanel pb = new JPanel();
  138. clearButton = new JButton("Clear");
  139. pb.add(clearButton);
  140. sendButton = new JButton("Send to VNC server");
  141. pb.add(sendButton);
  142. cancelButton = new JButton("Cancel");
  143. pb.add(cancelButton);
  144. getContentPane().add("South", pb);
  145. addListeners(this);
  146. pack();
  147. }
  148. public static void showDialog(Container c) {
  149. if (dialog == null)
  150. dialog = new ClipboardDialog();
  151. dialog.show(c);
  152. }
  153. public void show(Container c) {
  154. super.showDialog(c);
  155. }
  156. public void endDialog() {
  157. super.endDialog();
  158. dialog.dispose();
  159. }
  160. public static void serverCutText(String str) {
  161. if (textArea.getText().equals(str))
  162. return;
  163. // Update the text area with incoming serverCutText. We need to diable
  164. // the DocumentListener temporarily to prevent an clientCutText msg from
  165. // being sent back to the server when the textArea is updated.
  166. listen = false;
  167. textArea.setText(str);
  168. textArea.copy();
  169. listen = true;
  170. }
  171. public static void clientCutText() {
  172. // Update the textArea with the current contents of the system clipboard.
  173. // The TransferHandler ensures that the textArea's contents are only
  174. // changed when they differ from the clipboard's. If the textArea is
  175. // updated, the DocumentListener will trigger an RFB clientCutText msg.
  176. textArea.paste();
  177. textArea.setCaretPosition(0);
  178. }
  179. public void setSendingEnabled(boolean b) {
  180. sendButton.setEnabled(b);
  181. }
  182. public void actionPerformed(ActionEvent e) {
  183. Object s = e.getSource();
  184. if (s instanceof JButton && (JButton)s == clearButton) {
  185. serverCutText(new String(""));
  186. } else if (s instanceof JButton && (JButton)s == sendButton) {
  187. String text = textArea.getText();
  188. VncViewer.cc.writeClientCutText(text, text.length());
  189. endDialog();
  190. } else if (s instanceof JButton && (JButton)s == cancelButton) {
  191. endDialog();
  192. }
  193. }
  194. private JButton clearButton, sendButton, cancelButton;
  195. private static boolean listen = true;
  196. static ClipboardDialog dialog;
  197. static MyJTextArea textArea = new MyJTextArea();
  198. static LogWriter vlog = new LogWriter("ClipboardDialog");
  199. }