How to script Copy Paste Clipboard right mouse click

What is the best way to allow users to copy and paste to and from Ignition client text fields? The keyboard shortcuts Ctrl+C and Ctrl+V work fine but some people like using a mouse :unamused: .

I found this code from Carl in the forums but it has a select-all effect after the script executes on mouseReleased and creates some issues with overwriting.

What do you guys use?

[code]def doCut(event):
from java.awt.event import ActionEvent
action = event.source.actionMap.get(“cut”)
action.actionPerformed(ActionEvent(event.source, ActionEvent.ACTION_PERFORMED, action.getValue(action.ACTION_COMMAND_KEY)))

def doCopy(event):
from java.awt.event import ActionEvent
action = event.source.actionMap.get(“copy”)
action.actionPerformed(ActionEvent(event.source, ActionEvent.ACTION_PERFORMED, action.getValue(action.ACTION_COMMAND_KEY)))

def doPaste(event):
from java.awt.event import ActionEvent
action = event.source.actionMap.get(“paste”)
action.actionPerformed(ActionEvent(event.source, ActionEvent.ACTION_PERFORMED, action.getValue(action.ACTION_COMMAND_KEY)))

menu = fpmi.gui.createPopupMenu([“Cut”,“Copy”,“Paste”], [doCut, doCopy,doPaste])

menu.show(event)
[/code]

I don’t know that it’s the best way but we have several components that can be double-clicked to copy their values to the clipboard. To let the user know that the double-click was successful I briefly change the cursor to the “busy” cursor and then back again. That script is on a timer on each page that has double-click copy enabled.

This is the script in the change cursor timer.

event.source.running = 0
c_code = event.source.parent.cursorCode
event.source.parent.cursorCode = 3

def delay(event=event,c_code=c_code):
	import time
	import system
	time.sleep(.5)
	
	def finished(event=event):
		event.source.parent.cursorCode = c_code
	
	system.util.invokeLater(finished)

system.util.invokeAsynchronous(delay)

The script that we use for the actual copy to clipboard is:

from java.awt import Toolkit
from java.awt.datatransfer import StringSelection
	
clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
clipboard.setContents(StringSelection(text_to_copy), None)

The script is inside a function that takes the text of the component (text_to_copy) as a parameter.

4 Likes

That’s a cool idea with the double-click copy. For our particular Project, our users will be copying data from an application outside of Ignition and pasting it into the Ignition Project.

Do you do any pasting into Ignition with your projects after the double-click copy?

There is only one place in the project that data can be pasted in. For that I am using a TextArea to accept text in a specific csv format that gets parsed and put into a table so the user can verify the import and edit any data as needed before the data is processed.

Can you export the data from your other application into files and then use file functions to read the data in and parse it?

I’m not understanding what issues you are experiencing when people paste data into your text fields.

Basically, our Ignition Project requires users to type “Comments” into a Text Field and another into a Text Area.

Most of the time, they’ll grab these random strings of comments from an email (Microsoft Outlook) or from a non-Ignition HTML web page and want to paste them into the Ignition Text Field and/or Text Area instead of re-typing them.

Ctrl+C, Ctrl+V works fine but they insist on using right-mouse clicks. The problem is that you cannot right-click and paste into Ignition projects like you can with all other Microsoft-based applications. Actually, you can…but you need to build the functionality into your Project manually with Java. And I’m not a great Java developer.

My first code snippet above from Carl works with Text Fields (even though it has a weird select-all effect which we can live with). However, we just found out that it does NOT work with Text Areas…ugh. I understand Java scripting is super powerful but sometimes it’s frustrating when I need what seems to be a simple solution on the surface.

I am by no means a competent Java developer but I was able to get the following script to work with text areas.

from java.awt import Toolkit
from java.awt.datatransfer import DataFlavor
   
clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
contents = clipboard.getContents(None)
if contents is not None and contents.isDataFlavorSupported(DataFlavor.stringFlavor):
	text = contents.getTransferData(DataFlavor.stringFlavor) 
	event.source.parent.getComponent('Text Area').text = text

You could probably expand on this and check on a right click event to see if there is string data on the clipboard and if not then disable the Paste menu item.

1 Like

[quote=“JGJohnson”]I am by no means a competent Java developer …[/quote]I’m not so sure about that :slight_smile:
Anyways, tickled my “that’s interesting!” neurons and got me to extend your suggestion as this shared script:[code]def textPopup(event):
if event.popupTrigger:
menunames = []
menufuncs = []
if event.source.selectionStart != event.source.selectionEnd:
menunames.append(“cut”)
def cuttext(ev = event):
ev.source.cut()
menufuncs.append(cuttext)
menunames.append(“copy”)
def copytext(ev = event):
ev.source.copy()
menufuncs.append(copytext)

from java.awt import Toolkit
from java.awt.datatransfer import DataFlavor

clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
contents = clipboard.getContents(None)
if contents is not None and contents.isDataFlavorSupported(DataFlavor.stringFlavor):
  menunames.append("paste")
  def pastetext(ev = event):
    ev.source.paste()
  menufuncs.append(pastetext)
if len(menunames)>0:
  menu = system.gui.createPopupMenu(menunames, menufuncs)
  menu.show(event)[/code]... and then put the following in each component's mousePressed() and mouseReleased() events:[code]shared.cliphelp.textPopup(event)[/code]Applying the built-in cut(), copy(), and paste() methods like this might be enough for you.

Thanks for posting that shared script. I haven’t used shared scripts before so I learned how it’s very powerful to only have to maintain it in one location! Very clean and scalable.

Unfortunately, I can’t get it to work with a Text Area. It works perfectly with Text Fields. The error is:

AttributeError: 'com.inductiveautomation.factorypmi.application.com' object has no attribute 'selectionStart'

I’ve been trying to learn about the event object and why selectionStart doesn’t exist for Text Areas but I’m not having any luck.

Hmmm. Ok, I poked around inside the text area component (using shared.inspect.introspect()) and noted that the JTextArea that has the necessary methods is nested in the viewport of a JScrollPane. So, you need another shared script:[code]def textAreaPopup(event):
if event.popupTrigger:
menunames = []
menufuncs = []
if event.source.viewport.view.selectionStart != event.source.viewport.view.selectionEnd:
menunames.append(“cut”)
def cuttext(ev = event):
ev.source.viewport.view.cut()
menufuncs.append(cuttext)
menunames.append(“copy”)
def copytext(ev = event):
ev.source.viewport.view.copy()
menufuncs.append(copytext)

from java.awt import Toolkit
from java.awt.datatransfer import DataFlavor

clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
contents = clipboard.getContents(None)
if contents is not None and contents.isDataFlavorSupported(DataFlavor.stringFlavor):
  menunames.append("paste")
  def pastetext(ev = event):
    ev.source.viewport.view.paste()
  menufuncs.append(pastetext)
if len(menunames)>0:
  menu = system.gui.createPopupMenu(menunames, menufuncs)
  menu.show(event)[/code]and change the mousePressed() and mouseReleased() code to[code]shared.cliphelp.textAreaPopup(event)[/code]Note: [b]untested![/b]

Phil,
That worked perfectly! I created both shared scripts and tried them on two different projects and all was great. Thank you so much. :smiley:

I also checked out your introspect() function inductiveautomation.com/forum/v … 70&t=13566 and will try to use this in the future to find methods.

I’ve got so much to learn with Python but having this forum is a great resource.

Hi,

Thanks for this script,

I was able to get this script to copy to the clipboard when I ran it from the script console,
But when I tried it on a perspective component event script, it didn’t work.

Should this script work from a perspective session (currently using Microsoft Edge as the browser)?

The original discussion long predates the existence of Perspective, so it can only be Vision. Perspective isn't Java Swing like Vision, so anything you find that invokes Swing methods and components certainly won't apply.

Perspective doesn't expose clipboard operations yet, IIRC, so I wouldn't expect to find any variation on this that works.

Ah ok, that’s unfortunate,

Thanks for the quick response!