Search code examples
javajtableclipboardpojo

Copy the list of pojo to clipboard


Lang: Java

We are trying to copy the list of pojo to the clipboard in the table format.

Bullet point: what we are trying to achieve here :

1. convert list of pojo into table format

2. If the user copy it in some excel sheet then the it should be copied easily or even if the user try to copy in notepad it should print in the table format.

3. Add some meta data to clipboard to determine the pojo when we will import the table again.

For converting the list of pojo to table format i have used the jtable but i am not able to export all the jtable content to clipboard.

can anyone suggest if i should follow the jtable approach and copy the table to clipboard or any other solution is also available.


Update: as suggested in the comment I tried using the flavours

public class ClipboardTest implements ClipboardOwner {
    public static void main(String[] args) {
        ClipboardTest clipboardTest = new ClipboardTest();
        clipboardTest.copyToClipboard();
        //clipboardTest.getFromClipboard();

    }

    public void copyToClipboard() {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        Pojo data = new Pojo("1", "2", "ame2", "2", "2");
        MyObjectSelection dataSelection = new MyObjectSelection(data);
        StringSelection selection = new StringSelection("testing string");
        clipboard.setContents(dataSelection, ClipboardTest.this);
        System.out.println("copied to clipboard");
    }

    public void getFromClipboard() {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        Transferable clipboardContent = clipboard.getContents(this);

        DataFlavor[] flavors = clipboardContent.getTransferDataFlavors();
        System.out.println("flavors.length = " + flavors.length);
        for (int i = 0; i < flavors.length; i++) {
            System.out.println("flavor[" + i + "] = " + flavors[i]);
        }
    }

    // ClipboardOwner implementation

    @Override
    public void lostOwnership(Clipboard clipboard, Transferable transferable) {
        System.out.println("ClipboardTest: Lost ownership");
    }

}


---
myobjectselection.java


public class MyObjectSelection implements Transferable, ClipboardOwner {
    private static DataFlavor dmselFlavor = new DataFlavor(Pojo.class,
            "Test data flavor");
    private Pojo selection;

    public MyObjectSelection(Pojo selection) {
        this.selection = selection;
    }

    // Transferable implementation

    @Override
    public DataFlavor[] getTransferDataFlavors() {
        System.out.println("getTransferDataFlavors");
        DataFlavor[] ret = { dmselFlavor };
        return ret;
    }

    @Override
    public boolean isDataFlavorSupported(DataFlavor flavor) {
        return dmselFlavor.equals(flavor);
    }

    @Override
    public synchronized Object getTransferData(DataFlavor flavor)
            throws UnsupportedFlavorException {
        if (isDataFlavorSupported(flavor)) {
            return this.selection;
        } else {
            throw new UnsupportedFlavorException(dmselFlavor);
        }
    }

    // ClipboardOwner implementation

    @Override
    public void lostOwnership(Clipboard clipboard, Transferable transferable) {
        System.out.println("MyObjectSelection: Lost ownership");
    }

}

-- pojo.java

public class Pojo  implements Serializable{
/**
     * 
     */
    private static final long serialVersionUID = 1L;
private String name;
private String name1;
private String name2;
private String name3;
    private String name4;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName1() {
        return name1;
    }

    public void setName1(String name1) {
        this.name1 = name1;
    }

    public String getName2() {
        return name2;
    }

    public void setName2(String name2) {
        this.name2 = name2;
    }

    public String getName3() {
        return name3;
    }

    public void setName3(String name3) {
        this.name3 = name3;
    }

    public String getName4() {
        return name4;
    }

    public void setName4(String name4) {
        this.name4 = name4;
    }

    public Pojo(String name, String name1, String name2, String name3,
            String name4) {
        super();
        this.name = name;
        this.name1 = name1;
        this.name2 = name2;
        this.name3 = name3;
        this.name4 = name4;
    }

}

When i am trying to copy the string value to clipboard it is working but when i am trying to copy the pojo then is it not working.


Solution

  • For every flavor you want to support, you must provide methods to encode the object in the specified format.

    This means you'll likely need to provide an encoder for plain text, html and CVS to cover the basics.

    So, based on your Pojo, I wrote a Transferable that supports:

    • List (of Pojos)
    • HTML
    • CVS
    • Plain text
    • And serialised (as an additional to List, but it's essentially the same)

    PojoTransferable

    public class PojoTransferable implements Transferable {
    
        public static final DataFlavor POJO_LIST_DATA_FLAVOR = new DataFlavor(List.class, "application/x-java-pojo-list;class=java.util.List");
        public static final DataFlavor HTML_DATA_FLAVOR = new DataFlavor("text/html", "HTML");
        public static final DataFlavor CSV_DATA_FLAVOR = new DataFlavor("text/csv", "CVS");
        public static final DataFlavor PLAIN_DATA_FLAVOR = new DataFlavor("text/plain", "Plain text");
        public static final DataFlavor SERIALIZED_DATA_FLAVOR = new DataFlavor(Pojo.class, "application/x-java-serialized-object; Pojo");
    
        private static String[] HEADERS = new String[]{"name", "name1", "name2", "name3", "name4"};
        private static Pojo POJO_HEADER = new Pojo("name", "name1", "name2", "name3", "name4");
    
        private List<Pojo> pojos;
    
        public PojoTransferable(List<Pojo> pojos) {
            this.pojos = pojos;
        }
    
        @Override
        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[]{POJO_LIST_DATA_FLAVOR, HTML_DATA_FLAVOR, CSV_DATA_FLAVOR, SERIALIZED_DATA_FLAVOR, PLAIN_DATA_FLAVOR};
        }
    
        @Override
        public boolean isDataFlavorSupported(DataFlavor flavor) {
            boolean supported = false;
            for (DataFlavor mine : getTransferDataFlavors()) {
                if (mine.equals(flavor)) {
                    supported = true;
                    break;
                }
            }
            return supported;
        }
    
        @Override
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            Object data = null;
            if (POJO_LIST_DATA_FLAVOR.equals(flavor)) {
                data = pojos;
            } else if (HTML_DATA_FLAVOR.equals(flavor)) {
                data = new ByteArrayInputStream(formatAsHTML().getBytes());
            } else if (SERIALIZED_DATA_FLAVOR.equals(flavor)) {
                data = pojos;
            } else if (CSV_DATA_FLAVOR.equals(flavor)) {
                data = new ByteArrayInputStream(formatAsCVS().getBytes());
            } else if (PLAIN_DATA_FLAVOR.equals(flavor)) {
                data = new ByteArrayInputStream(formatAsPlainText().getBytes());
            } else {
                throw new UnsupportedFlavorException(flavor);
            }
            return data;
        }
    
        protected String formatAsCVS(Pojo pojo) {
            StringJoiner sj = new StringJoiner(",");
            sj.add(pojo.getName());
            sj.add(pojo.getName2());
            sj.add(pojo.getName3());
            sj.add(pojo.getName4());
            return sj.toString();
        }
    
        public String formatAsCVS() {
            StringBuilder sb = new StringBuilder(128);
            sb.append(formatAsCVS(POJO_HEADER));
            for (Pojo pojo : pojos) {
                sb.append(formatAsCVS(pojo));
            }
            return "";
        }
    
        protected Map<Integer, Integer> columnWidthsFor(Pojo pojo) {
            Map<Integer, Integer> columnWidths = new HashMap<>();
            columnWidths.put(0, pojo.getName().length());
            columnWidths.put(1, pojo.getName1().length());
            columnWidths.put(2, pojo.getName2().length());
            columnWidths.put(3, pojo.getName3().length());
            columnWidths.put(4, pojo.getName4().length());
            return columnWidths;
        }
    
        protected void apply(Map<Integer, Integer> pojoWidths, Map<Integer, Integer> columnWidths) {
            for (int index = 0; index < 5; index++) {
                int currentWidth = 2;
                if (columnWidths.containsKey(index)) {
                    currentWidth = columnWidths.get(index);
                }
                int columnWidth = 2;
                if (pojoWidths.containsKey(index)) {
                    columnWidth = pojoWidths.get(index);
                }
                columnWidths.put(index, Math.max(currentWidth, columnWidth));
            }
        }
    
        protected String formatAsPlainText(Pojo pojo, String format) {
            return String.format(format, pojo.getName(), pojo.getName1(), pojo.getName2(), pojo.getName3(), pojo.getName4());
        }
    
        public static String fill(int padding) {
            return String.format("%" + padding + "s", "").replace(" ", "-");
        }
    
        public String formatAsPlainText() {
            Map<Integer, Integer> columnWidths = new HashMap<>();
    
            apply(columnWidthsFor(POJO_HEADER), columnWidths);
            for (Pojo pojo : pojos) {
                apply(columnWidthsFor(pojo), columnWidths);
            }
    
            StringJoiner sjFormat = new StringJoiner("|");
            StringJoiner sjSep = new StringJoiner("+");
            for (int index = 0; index < 5; index++) {
                int currentWidth = 0;
                if (columnWidths.containsKey(index)) {
                    currentWidth = columnWidths.get(index);
                }
                sjFormat.add(" %-" + currentWidth + "s ");
                sjSep.add(fill(currentWidth + 2));
            }
            sjFormat.add("%n");
            sjSep.add("\n");
    
            String seperator = sjSep.toString();
            String format = sjFormat.toString();
            StringBuilder sb = new StringBuilder(128);
            sb.append(formatAsPlainText(POJO_HEADER, format));
            for (Pojo pojo : pojos) {
                sb.append(seperator);
                sb.append(formatAsPlainText(pojo, format));
            }
            return sb.toString();
        }
    
        public String formatAsHTML() {
            StringBuilder sb = new StringBuilder(128);
            sb.append("<html><body>");
            sb.append("<table border='1'>");
            sb.append("<tr>");
            for (String header : HEADERS) {
                sb.append("<th>").append(header).append("</th>");
            }
            sb.append("</tr>");
            for (Pojo pojo : pojos) {
                sb.append("<tr>");
                sb.append("<td>").append(pojo.getName()).append("</td>");
                sb.append("<td>").append(pojo.getName1()).append("</td>");
                sb.append("<td>").append(pojo.getName2()).append("</td>");
                sb.append("<td>").append(pojo.getName3()).append("</td>");
                sb.append("<td>").append(pojo.getName4()).append("</td>");
                sb.append("</tr>");
            }
            sb.append("</table>");
    
            return sb.toString();
        }
    }
    

    Test...

    Then I wrote a really simple test...

    List<Pojo> pojos = new ArrayList<>(25);
    pojos.add(new Pojo("one", "two", "three", "four", "five"));
    
    PojoTransferable pt = new PojoTransferable(pojos);
    Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
    cb.setContents(pt, new ClipboardOwner() {
        @Override
        public void lostOwnership(Clipboard clipboard, Transferable contents) {
            System.out.println("Lost");
        }
    });
    try {
        Object data = cb.getData(PojoTransferable.POJO_LIST_DATA_FLAVOR);
        if (data instanceof List) {
            List listOfPojos = (List)data;
            System.out.println("listOfPojos contains " + listOfPojos.size());
            for (Object o : listOfPojos) {
                System.out.println(o);
            }
        }
    } catch (UnsupportedFlavorException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
    

    When I run it, it prints out...

    listOfPojos contains 1
    test.Pojo@5b480cf9
    

    which tells use that the List flavor worked (for our needs), but then I opened up a text edit, Word and Excel and pasted the contents into them...

    Plain TextExcelWord

    nb: Excel used the HTML formatting, go figure