From 075459475fa1790748154e14cf8f2b270706ae19 Mon Sep 17 00:00:00 2001 From: sgoudham Date: Mon, 19 Jul 2021 23:58:07 +0100 Subject: [PATCH 1/9] Check updates to clipboard every 200ms --- .../java/me/goudham/ClipboardListener.java | 47 ++++++++++++++----- .../java/me/goudham/view/ClipboardView.java | 9 ++++ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/goudham/ClipboardListener.java b/src/main/java/me/goudham/ClipboardListener.java index efbf41d..eebf5f2 100644 --- a/src/main/java/me/goudham/ClipboardListener.java +++ b/src/main/java/me/goudham/ClipboardListener.java @@ -4,6 +4,7 @@ import me.goudham.listener.ClipboardEvent; import me.goudham.model.MyClipboardContent; import org.jetbrains.annotations.NotNull; +import java.awt.HeadlessException; import java.awt.Image; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; @@ -12,6 +13,9 @@ import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; public class ClipboardListener extends Thread implements ClipboardOwner { private final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); @@ -25,7 +29,8 @@ public class ClipboardListener extends Thread implements ClipboardOwner { public void lostOwnership(Clipboard oldClipboard, Transferable oldClipboardContents) { try { sleep(200); - } catch (InterruptedException ignored) { } + } catch (InterruptedException ignored) { + } Transferable newClipboardContents = oldClipboard.getContents(currentThread()); processContents(oldClipboard, newClipboardContents); @@ -37,13 +42,14 @@ public class ClipboardListener extends Thread implements ClipboardOwner { try { if (oldClipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) { - String stringContent = (String) newClipboardContents.getTransferData(DataFlavor.stringFlavor); - clipboardContent = new MyClipboardContent<>(stringContent); - } else if (oldClipboard.isDataFlavorAvailable(DataFlavor.imageFlavor)) { - Image imageContent = (Image) newClipboardContents.getTransferData(DataFlavor.imageFlavor); - clipboardContent = new MyClipboardContent<>(imageContent); - } - } catch (UnsupportedFlavorException | IOException ignored) { } + String stringContent = (String) newClipboardContents.getTransferData(DataFlavor.stringFlavor); + clipboardContent = new MyClipboardContent<>(stringContent); + } else if (oldClipboard.isDataFlavorAvailable(DataFlavor.imageFlavor)) { + Image imageContent = (Image) newClipboardContents.getTransferData(DataFlavor.imageFlavor); + clipboardContent = new MyClipboardContent<>(imageContent); + } + } catch (UnsupportedFlavorException | IOException ignored) { + } clipboardEvent.onCopy(clipboardContent); } @@ -53,9 +59,28 @@ public class ClipboardListener extends Thread implements ClipboardOwner { } public void run() { - Transferable currentClipboardContents = clipboard.getContents(currentThread()); - processContents(clipboard, currentClipboardContents); - regainOwnership(clipboard, currentClipboardContents); + Transferable currentClipboardContents = clipboard.getContents(null); + + final MyClipboardContent[] recentContent = new MyClipboardContent[]{new MyClipboardContent<>("")}; + try { + recentContent[0].setContent(currentClipboardContents.getTransferData(DataFlavor.stringFlavor)); + } catch (UnsupportedFlavorException | IOException e) { + e.printStackTrace(); + } + + ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + executor.scheduleAtFixedRate(() -> { + try { + Transferable newClipboard = clipboard.getContents(null); + String data = (String) newClipboard.getTransferData(DataFlavor.stringFlavor); + if (!data.equals(recentContent[0].getContent())) { + clipboardEvent.onCopy(new MyClipboardContent<>(data)); + recentContent[0].setContent(data); + } + } catch (HeadlessException | IOException | UnsupportedFlavorException e) { + e.printStackTrace(); + } + }, 0, 200, TimeUnit.MILLISECONDS); } public void setClipboardEvent(@NotNull ClipboardEvent clipboardEvent) { diff --git a/src/main/java/me/goudham/view/ClipboardView.java b/src/main/java/me/goudham/view/ClipboardView.java index 83fd33a..3756d81 100644 --- a/src/main/java/me/goudham/view/ClipboardView.java +++ b/src/main/java/me/goudham/view/ClipboardView.java @@ -4,15 +4,24 @@ import me.goudham.ClipboardListener; import me.goudham.listener.ClipboardEvent; import me.goudham.model.MyClipboardContent; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; +import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; +import javax.swing.KeyStroke; import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; public class ClipboardView implements ClipboardEvent { private JPanel Clipboard; From 79dc6e7afb8ca852c6a18eff5817091b3944a737 Mon Sep 17 00:00:00 2001 From: sgoudham Date: Wed, 21 Jul 2021 01:34:32 +0100 Subject: [PATCH 2/9] Update GUI --- .../java/me/goudham/view/ClipboardView.form | 88 +++++++++++++++++-- 1 file changed, 80 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/goudham/view/ClipboardView.form b/src/main/java/me/goudham/view/ClipboardView.form index 09368c1..44b95ad 100644 --- a/src/main/java/me/goudham/view/ClipboardView.form +++ b/src/main/java/me/goudham/view/ClipboardView.form @@ -20,13 +20,13 @@ - + - + @@ -59,7 +59,7 @@ - + @@ -67,27 +67,27 @@ - + - + - + - + @@ -96,7 +96,79 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1ef16260c819b7197f01a23179ebb7ba6442927d Mon Sep 17 00:00:00 2001 From: sgoudham Date: Wed, 21 Jul 2021 01:35:17 +0100 Subject: [PATCH 3/9] Add equals() & hashcode() methods --- .../me/goudham/model/MyClipboardContent.java | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/main/java/me/goudham/model/MyClipboardContent.java b/src/main/java/me/goudham/model/MyClipboardContent.java index 3a530b5..1bb0d3e 100644 --- a/src/main/java/me/goudham/model/MyClipboardContent.java +++ b/src/main/java/me/goudham/model/MyClipboardContent.java @@ -1,17 +1,32 @@ package me.goudham.model; +import java.util.Objects; + public class MyClipboardContent { - private T content; + private T content; + + public MyClipboardContent(T content) { + this.content = content; + } + + public void setContent(Object content) { + this.content = (T) content; + } - public MyClipboardContent(T content) { - this.content = content; - } + public T getContent() { + return content; + } - public void setContent(Object content) { - this.content = (T) content; - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MyClipboardContent that = (MyClipboardContent) o; + return Objects.equals(content, that.content); + } - public T getContent() { - return content; - } + @Override + public int hashCode() { + return Objects.hash(content); + } } From 2cb1997d95c5cd3530c9255c3352aa16c69a4d36 Mon Sep 17 00:00:00 2001 From: sgoudham Date: Wed, 21 Jul 2021 01:35:39 +0100 Subject: [PATCH 4/9] Add enum class for different DataFlavors --- src/main/java/me/goudham/util/Contents.java | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/main/java/me/goudham/util/Contents.java diff --git a/src/main/java/me/goudham/util/Contents.java b/src/main/java/me/goudham/util/Contents.java new file mode 100644 index 0000000..79b94ab --- /dev/null +++ b/src/main/java/me/goudham/util/Contents.java @@ -0,0 +1,37 @@ +package me.goudham.util; + +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; + +public enum Contents { + STRING(DataFlavor.stringFlavor) { + @Override + public boolean isAvailable(Clipboard clipboard) { + return clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor); + } + }, + IMAGE(DataFlavor.imageFlavor) { + @Override + public boolean isAvailable(Clipboard clipboard) { + return clipboard.isDataFlavorAvailable(DataFlavor.imageFlavor); + } + }, + FILELIST(DataFlavor.javaFileListFlavor) { + @Override + public boolean isAvailable(Clipboard clipboard) { + return clipboard.isDataFlavorAvailable(DataFlavor.javaFileListFlavor); + } + }; + + private final DataFlavor dataFlavor; + + Contents(DataFlavor dataFlavor) { + this.dataFlavor = dataFlavor; + } + + public DataFlavor getDataFlavor() { + return dataFlavor; + } + + public abstract boolean isAvailable(Clipboard clipboard); +} From bd57e1354a5b7210e86899a05447e7042de594b4 Mon Sep 17 00:00:00 2001 From: sgoudham Date: Wed, 21 Jul 2021 01:35:55 +0100 Subject: [PATCH 5/9] Add Utility class --- .../java/me/goudham/util/ClipboardUtils.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/main/java/me/goudham/util/ClipboardUtils.java diff --git a/src/main/java/me/goudham/util/ClipboardUtils.java b/src/main/java/me/goudham/util/ClipboardUtils.java new file mode 100644 index 0000000..71f274f --- /dev/null +++ b/src/main/java/me/goudham/util/ClipboardUtils.java @@ -0,0 +1,44 @@ +package me.goudham.util; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.image.BufferedImage; +import java.io.IOException; +import me.goudham.model.MyClipboardContent; + +import static me.goudham.util.Contents.IMAGE; +import static me.goudham.util.Contents.STRING; + +public class ClipboardUtils { + + public static MyClipboardContent getClipboardContents(Transferable contents, Clipboard clipboard) { + MyClipboardContent myClipboardContent = new MyClipboardContent<>(""); + + try { + if (STRING.isAvailable(clipboard)) { + myClipboardContent.setContent(contents.getTransferData(STRING.getDataFlavor())); + } else if (IMAGE.isAvailable(clipboard)) { + BufferedImage bufferedImage = convertToBufferedImage((Image) contents.getTransferData(IMAGE.getDataFlavor())); + myClipboardContent.setContent(new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight())); + } + } catch (UnsupportedFlavorException | IOException exp) { + exp.printStackTrace(); + } + + return myClipboardContent; + } + + public static BufferedImage convertToBufferedImage(Image image) { + BufferedImage newImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); + + Graphics2D graphics = newImage.createGraphics(); + graphics.drawImage(image, 0, 0, null); + graphics.dispose(); + + return newImage; + } +} From dff0e39fc07091b636b7610de1e23f7c064be06c Mon Sep 17 00:00:00 2001 From: sgoudham Date: Wed, 21 Jul 2021 01:36:12 +0100 Subject: [PATCH 6/9] Update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d51d460..ebac78e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ hs_err_pid* # User -.idea \ No newline at end of file +.idea +target \ No newline at end of file From 2ec0743cf2d95fe4c2b7c0cb3a41b00ae8054ec6 Mon Sep 17 00:00:00 2001 From: sgoudham Date: Wed, 21 Jul 2021 01:36:37 +0100 Subject: [PATCH 7/9] Separate events into String & Image --- src/main/java/me/goudham/listener/ClipboardEvent.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/goudham/listener/ClipboardEvent.java b/src/main/java/me/goudham/listener/ClipboardEvent.java index 2571716..02ac7ad 100644 --- a/src/main/java/me/goudham/listener/ClipboardEvent.java +++ b/src/main/java/me/goudham/listener/ClipboardEvent.java @@ -1,7 +1,8 @@ package me.goudham.listener; -import me.goudham.model.MyClipboardContent; +import java.awt.image.BufferedImage; public interface ClipboardEvent { - void onCopy(MyClipboardContent copiedContent); + void onCopyString(String stringContent); + void onCopyImage(BufferedImage imageContent); } From 36c53d91df7169f2e1c1c05fb13a14d95a068c3a Mon Sep 17 00:00:00 2001 From: sgoudham Date: Wed, 21 Jul 2021 01:42:28 +0100 Subject: [PATCH 8/9] Override onCopyString() & onCopyImage() and display to GUI --- .../java/me/goudham/view/ClipboardView.java | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/main/java/me/goudham/view/ClipboardView.java b/src/main/java/me/goudham/view/ClipboardView.java index 3756d81..2fce84f 100644 --- a/src/main/java/me/goudham/view/ClipboardView.java +++ b/src/main/java/me/goudham/view/ClipboardView.java @@ -1,38 +1,38 @@ package me.goudham.view; -import me.goudham.ClipboardListener; -import me.goudham.listener.ClipboardEvent; -import me.goudham.model.MyClipboardContent; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.ActionMap; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.image.BufferedImage; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; -import javax.swing.InputMap; +import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; -import javax.swing.KeyStroke; -import java.awt.Dimension; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; +import me.goudham.ClipboardListener; +import me.goudham.listener.ClipboardEvent; public class ClipboardView implements ClipboardEvent { private JPanel Clipboard; - private JButton copyButton; + private JButton copySelectedTextButton; private JList clipboardContentList; private final DefaultListModel listModel; private JLabel title; private JScrollPane scrollPane; private JPanel buttonPane; - private JButton clearButton; + private JButton clearAllHistoryButton; private JButton removeButton; + private JLabel imageIconLabel; + private JLabel textClipboardLabel; + private JButton copyImageBelowButton; + private JButton removeImageBelowButton; + private JPanel imageButtonPanel; + private JPanel imagePanel; + + private boolean resize = false; public ClipboardView() { scrollPane.setBorder(BorderFactory.createEmptyBorder()); @@ -90,15 +90,23 @@ public class ClipboardView implements ClipboardEvent { jFrame.setVisible(true); jFrame.setAlwaysOnTop(true); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - jFrame.setPreferredSize(new Dimension(1000, 680)); - jFrame.setMaximumSize(new Dimension(1000, 680)); + jFrame.setPreferredSize(new Dimension(1200, 900)); jFrame.setResizable(true); jFrame.pack(); jFrame.setLocationRelativeTo(null); } @Override - public void onCopy(MyClipboardContent copiedContent) { - listModel.add(0, copiedContent.getContent().toString()); + public void onCopyString(String stringContent) { + listModel.add(0, stringContent); + } + + @Override + public void onCopyImage(BufferedImage imageContent) { + if (imageContent.getWidth() > 1000 || imageContent.getHeight() > 500) { + imageIconLabel.setIcon(new ImageIcon(new ImageIcon(imageContent).getImage().getScaledInstance(1000, 300, Image.SCALE_SMOOTH))); + } else { + imageIconLabel.setIcon(new ImageIcon(imageContent)); + } } } From 1cebc941a4f1e53ea0efcadf63c65959394e9f40 Mon Sep 17 00:00:00 2001 From: sgoudham Date: Wed, 21 Jul 2021 01:43:13 +0100 Subject: [PATCH 9/9] Cleanup Code --- .../java/me/goudham/ClipboardListener.java | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/main/java/me/goudham/ClipboardListener.java b/src/main/java/me/goudham/ClipboardListener.java index eebf5f2..eeef9c2 100644 --- a/src/main/java/me/goudham/ClipboardListener.java +++ b/src/main/java/me/goudham/ClipboardListener.java @@ -1,10 +1,6 @@ package me.goudham; -import me.goudham.listener.ClipboardEvent; -import me.goudham.model.MyClipboardContent; -import org.jetbrains.annotations.NotNull; - -import java.awt.HeadlessException; +import java.awt.Dimension; import java.awt.Image; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; @@ -12,10 +8,18 @@ import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.image.BufferedImage; import java.io.IOException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import me.goudham.listener.ClipboardEvent; +import me.goudham.model.MyClipboardContent; +import me.goudham.util.ClipboardUtils; +import org.jetbrains.annotations.NotNull; + +import static me.goudham.util.Contents.IMAGE; +import static me.goudham.util.Contents.STRING; public class ClipboardListener extends Thread implements ClipboardOwner { private final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); @@ -51,7 +55,7 @@ public class ClipboardListener extends Thread implements ClipboardOwner { } catch (UnsupportedFlavorException | IOException ignored) { } - clipboardEvent.onCopy(clipboardContent); +// clipboardEvent.onCopy(clipboardContent); } public void regainOwnership(Clipboard clipboard, Transferable newClipboardContents) { @@ -59,28 +63,33 @@ public class ClipboardListener extends Thread implements ClipboardOwner { } public void run() { - Transferable currentClipboardContents = clipboard.getContents(null); - - final MyClipboardContent[] recentContent = new MyClipboardContent[]{new MyClipboardContent<>("")}; - try { - recentContent[0].setContent(currentClipboardContents.getTransferData(DataFlavor.stringFlavor)); - } catch (UnsupportedFlavorException | IOException e) { - e.printStackTrace(); - } + Transferable oldClipboardContents = clipboard.getContents(null); + final MyClipboardContent[] myOldClipboardContentsArray = new MyClipboardContent[]{ ClipboardUtils.getClipboardContents(oldClipboardContents, clipboard) }; ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); executor.scheduleAtFixedRate(() -> { + Transferable newClipboardContents = clipboard.getContents(null); + MyClipboardContent myNewClipboardContents = new MyClipboardContent<>(""); + try { - Transferable newClipboard = clipboard.getContents(null); - String data = (String) newClipboard.getTransferData(DataFlavor.stringFlavor); - if (!data.equals(recentContent[0].getContent())) { - clipboardEvent.onCopy(new MyClipboardContent<>(data)); - recentContent[0].setContent(data); + if (STRING.isAvailable(clipboard)) { + myNewClipboardContents.setContent(newClipboardContents.getTransferData(STRING.getDataFlavor())); + if (!myNewClipboardContents.getContent().equals(myOldClipboardContentsArray[0].getContent())) { + clipboardEvent.onCopyString((String) myNewClipboardContents.getContent()); + myOldClipboardContentsArray[0].setContent(myNewClipboardContents.getContent()); + } + } else if (IMAGE.isAvailable(clipboard)) { + BufferedImage bufferedImage = ClipboardUtils.convertToBufferedImage((Image) newClipboardContents.getTransferData(IMAGE.getDataFlavor())); + myNewClipboardContents.setContent(new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight())); + if (!myNewClipboardContents.getContent().equals(myOldClipboardContentsArray[0].getContent())) { + clipboardEvent.onCopyImage(bufferedImage); + myOldClipboardContentsArray[0].setContent(myNewClipboardContents.getContent()); + } } - } catch (HeadlessException | IOException | UnsupportedFlavorException e) { - e.printStackTrace(); + } catch (UnsupportedFlavorException | IOException exp) { + exp.printStackTrace(); } - }, 0, 200, TimeUnit.MILLISECONDS); + }, 0, 350, TimeUnit.MILLISECONDS); } public void setClipboardEvent(@NotNull ClipboardEvent clipboardEvent) {