Ask Reuben

Cut & Paste Tables into the Clipboard

When you right-click a TABLE during a DISPLAY ARRAY, you see options Copy Cell, Copy Visible Column, Copy Row, Copy Visible Table.

How can the end-user copy the entire table?

Prior to joining Four Js, I got in trouble with my manager of the time by describing the Copy Visible Table option that is available when you right-click on a TABLE in a DISPLAY ARRAY, in unprofessional language.  Why would a user want to copy just the visible rows? If they are going to copy rows, they are going to want to copy ALL rows, typically to paste into Excel and do some further analysis there.

The technical reason for Copy Visible Table is that the front-end client only has access to the rows that are currently displayed. If there are hundreds and thousands of rows in the array, only the tens of rows that are displayed are sent to the front-end client. As you scroll up/down, only then are additional rows sent to the front-end client as required to be displayed. So the front-end client isn’t able to add all the rows to the clipboard as it doesn’t know what they are.

I used to have a complex solution to copy ALL rows that involved reading the AUI Tree to get column and row mappings, and then iterating through the array to create a string that the user could then paste into Excel.  Fortunately I no longer need to use this function but if you are interested you can still see it here https://github.com/FourjsGenero/fgl_auitree/blob/master/arraycopy.4gl 

With the implementation of Multi Row Select functionality into Genero in 2.30 there is a much simpler solution.  Simply implement Multiple Row Selection in your DISPLAY ARRAY using … 

CALL DIALOG.setSelectionMode( "screen-record-name", TRUE )

… and the end-user can use standard front-end accelerator keys and mouse actions to select one, all or some combination or rows to paste to the clipboard.  So holding down the shift key when clicking to select a range of rows, or holding down the control key when clicking to select a non-contiguous range or rows.  To select ALL rows is a case of clicking the first row and then holding down shift when clicking the last row.

You can read more on multiple row selection here https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_prog_dialogs_multirange.html

It is possible to automate the selection of all rows using the setSelectionRange method e.g.

ON ACTION select_all 
  CALL DIALOG.setSelectionRange( "sr", 1, -1, TRUE)

https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_ClassDialog_setSelectionRange.html

I utilise this technique in fgl_zoom https://github.com/FourjsGenero/fgl_zoom to add a Copy All Rows option to my fgl_zoom example

Look for the ON ACTION copyall, that is in fgl_zoom.4gl. Below I will give a walkthrough of that code (search for the ON ACTION copyall line)…

Add your action …

ON ACTION copyall

The technique uses multi row select. If multi row selection is already enabled, make a copy of the currently selected rows so that they can be restored when we are finished

IF m_zoom.multiplerow THEN
    CALL l_selected.clear()
    FOR i = 1 TO l_row_count
        LET l_selected[i] = d_da.isRowSelected("data",i)
    END FOR
ELSE

Turn on multi row select if it is not turned on already

    CALL d_da.setSelectionMode("data",1)
END IF

Select all rows for multi row select

CALL d_da.setSelectionRange("data",1,-1,1)

Create a string from all the selected row

LET l_datatocopy =  d_da.selectionToString("data")

Set the clipboard to this string

        CALL ui.Interface.frontCall("standard","cbset",l_datatocopy,ok)

Note: With GBC, we can’t copy to clipboard via this front-call I will give a technique for this in a later ask-reuben

Now put the array back how it was. So unselect all the rows

CALL d_da.setSelectionRange("data",1,-1,0)

If there were previously selected rows, select them again

IF m_zoom.multiplerow THEN
    FOR i = 1 TO l_row_count
        CALL d_da.setSelectionRange("data",i,i,l_selected[i])
    END FOR
ELSE

otherwise disable multi row select

    CALL d_da.setSelectionMode("data",0)
END IF

Using this technique, users can copy entire arrays of data to the clipboard, where the most common usage is to then paste into Excel.

So in summary, enabling the user to copy all rows of a DISPLAY ARRAY + TABLE to the clipboard is as simple as enabling multiple row selection, and allowing the user to select one or more rows