diff --git a/src/main/java/forge/gui/toolbox/FHyperlink.java b/src/main/java/forge/gui/toolbox/FHyperlink.java new file mode 100644 index 00000000000..50525855235 --- /dev/null +++ b/src/main/java/forge/gui/toolbox/FHyperlink.java @@ -0,0 +1,105 @@ +package forge.gui.toolbox; + +import java.awt.Cursor; +import java.awt.Desktop; +import java.awt.Toolkit; +import java.awt.datatransfer.StringSelection; +import java.net.URI; +import java.net.URISyntaxException; + +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; + +import forge.Command; + + + +@SuppressWarnings("serial") +public class FHyperlink extends FLabel { + public static class Builder extends FLabel.Builder { + private String bldUrl; + + public Builder() { + bldHoverable = true; + bldReactOnMouseDown = true; + bldCmd = null; + } + + public FHyperlink build() { + StringBuilder sb = new StringBuilder(); + sb.append(""); + sb.append((null == bldText || bldText.isEmpty()) ? bldUrl : bldText); + sb.append(""); + + final boolean browsingSupported = _isBrowsingSupported(); + if (browsingSupported) { + tooltip(bldUrl); + } else { + tooltip(bldUrl + " (click to copy to clipboard)"); + } + + final URI uri; + try { + uri = new URI(bldUrl); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + + // overwrite whatever command is there -- we could chain them if we wanted to, though + cmdClick(new Command() { + @Override + public void execute() { + if (browsingSupported) { + // open link in default browser + new _LinkRunner(uri).execute(); + } else { + // copy link to clipboard + StringSelection ss = new StringSelection(bldUrl); + try { + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null); + } catch (IllegalStateException ex) { + JOptionPane.showMessageDialog(null, + "Sorry, a problem occurred while copying this link to your system clipboard.", + "A problem occured", JOptionPane.ERROR_MESSAGE); + } + } + } + }); + + return new FHyperlink(this); + } + + public Builder url(String url) { bldUrl = url; return this; } + + private static boolean _isBrowsingSupported() { + if (!Desktop.isDesktopSupported()) { + return false; + } + return Desktop.getDesktop().isSupported(Desktop.Action.BROWSE); + } + } + + // Call this using FLabel.Builder()... + private FHyperlink(final Builder b) { + super(b); + + setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + + private static class _LinkRunner extends SwingWorker { + private final URI uri; + + private _LinkRunner(URI u) { + if (u == null) { + throw new NullPointerException(); + } + uri = u; + } + + @Override + protected Void doInBackground() throws Exception { + Desktop.getDesktop().browse(uri); + return null; + } + } +} diff --git a/src/main/java/forge/gui/toolbox/FLabel.java b/src/main/java/forge/gui/toolbox/FLabel.java index 6ac46273736..4f05e4679f7 100644 --- a/src/main/java/forge/gui/toolbox/FLabel.java +++ b/src/main/java/forge/gui/toolbox/FLabel.java @@ -65,18 +65,18 @@ public class FLabel extends JLabel implements ILocalRepaint { private int bldIconAlignX = SwingConstants.LEFT; private Point bldIconInsets = new Point(0, 0); - private boolean bldSelectable = false; - private boolean bldSelected = false; - protected boolean bldHoverable = false; - protected boolean bldOpaque = false; - private boolean bldIconInBackground = false; - private boolean bldIconScaleAuto = true; - private boolean reactOnMouseDown = false; + private boolean bldSelectable = false; + private boolean bldSelected = false; + protected boolean bldHoverable = false; + protected boolean bldOpaque = false; + private boolean bldIconInBackground = false; + private boolean bldIconScaleAuto = true; + protected boolean bldReactOnMouseDown = false; - private String bldText, bldToolTip; + protected String bldText, bldToolTip; private ImageIcon bldIcon; private int bldFontAlign; - private Command bldCmd; + protected Command bldCmd; // Build! /** @return {@link forge.gui.toolbox.FLabel} */ @@ -121,7 +121,7 @@ public class FLabel extends JLabel implements ILocalRepaint { /**@param b0   boolean that controls when the label responds to mouse events * @return {@link forge.gui.toolbox.Builder} */ - public Builder reactOnMouseDown(final boolean b0) { this.reactOnMouseDown = b0; return this; } + public Builder reactOnMouseDown(final boolean b0) { this.bldReactOnMouseDown = b0; return this; } public Builder reactOnMouseDown() { reactOnMouseDown(true); return this; } /**@param c0   {@link forge.Command} to execute if clicked @@ -173,11 +173,8 @@ public class FLabel extends JLabel implements ILocalRepaint { } //========== Constructors - /** Must have protected constructor to allow Builder to subclass. */ - protected FLabel() { } - // Call this using FLabel.Builder()... - private FLabel(final Builder b0) { + protected FLabel(final Builder b0) { super(b0.bldText); // Init fields from builder @@ -195,7 +192,7 @@ public class FLabel extends JLabel implements ILocalRepaint { this.setFontSize(b0.bldFontSize); this.setUnhoveredAlpha(b0.bldUnhoveredAlpha); this.setCommand(b0.bldCmd); - this.setReactOnMouseDown(b0.reactOnMouseDown); + this.setReactOnMouseDown(b0.bldReactOnMouseDown); this.setFontAlign(b0.bldFontAlign); this.setToolTipText(b0.bldToolTip); this.setHoverable(b0.bldHoverable); @@ -293,7 +290,7 @@ public class FLabel extends JLabel implements ILocalRepaint { private void _doMouseAction() { if (selectable) { setSelected(!selected); } - if (cmdClick != null && FLabel.this.isEnabled()) { + if (cmdClick != null && isEnabled()) { hovered = false; repaintSelf(); cmdClick.execute(); @@ -447,7 +444,7 @@ public class FLabel extends JLabel implements ILocalRepaint { /** Major performance kicker - won't repaint whole screen! */ @Override public void repaintSelf() { - final Dimension d = FLabel.this.getSize(); + final Dimension d = getSize(); repaint(0, 0, d.width, d.height); } @@ -546,7 +543,7 @@ public class FLabel extends JLabel implements ILocalRepaint { int w = (int) (h * iar); if (w == 0 || h == 0) { return; } - FLabel.super.setIcon(new ImageIcon(img.getScaledInstance(w, h, Image.SCALE_SMOOTH))); + super.setIcon(new ImageIcon(img.getScaledInstance(w, h, Image.SCALE_SMOOTH))); } } }