Modify DescriptionArea to make hyperlinks live. Hyperlinks other than jar

resources just get sent off to the browser; jar resources get extracted into
temporary files, and those files' URLs get sent off to the browser.

I don't really like the handling of exceptions here, but I don't see a better
way around it. Trying to just declare hyperlinkUpdate() as throwing exceptions
fails because I'm overriding an abstract method that doesn't throw exceptions.
So, I need to throw a runtime exception when an exception happens; the stack
trace in the bug report shows that as the location of the exception so I
didn't want to just wrap all the code in the method in one big try/catch as
that reduces the information about where things broke.  So, bunch of try/catch
blocks around related operations.
This commit is contained in:
JoePfeiffer 2022-02-04 10:14:09 -07:00
parent 7c8e8699ef
commit 4734ea5e85

View File

@ -1,16 +1,30 @@
package net.sf.openrocket.gui.components;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.net.URI;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.JEditorPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import net.sf.openrocket.util.BugException;
@SuppressWarnings("serial")
public class DescriptionArea extends JScrollPane {
@ -65,7 +79,71 @@ public class DescriptionArea extends JScrollPane {
Font font = editorPane.getFont();
editorPane.setFont(font.deriveFont(font.getSize2D() + size));
editorPane.setEditable(false);
editorPane.addHyperlinkListener(new HyperlinkListener() {
public void hyperlinkUpdate(HyperlinkEvent e) {
if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
URI uri = null;
try {
uri = e.getURL().toURI();
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
// If the uri scheme indicates this is a resource in a jar file,
// extract and write to a temporary file
if (uri.getScheme().equals("jar")) {
// get the resource
String uriString = uri.toString();
String resourceName = uriString.substring(uriString.indexOf("!") + 1);
final BufferedInputStream is = new BufferedInputStream(getClass().getResourceAsStream(resourceName));
// construct filename from resource name
String prefix = resourceName.substring(1);
String suffix = null;
final int dotIndex = prefix.lastIndexOf(".");
if (dotIndex > 0) {
prefix = resourceName.substring(0, dotIndex);
suffix = resourceName.substring(dotIndex+1);
}
// create temporary file and copy resource to it
File of = null;
BufferedOutputStream os = null;
try {
of = File.createTempFile(prefix, suffix);
os = new BufferedOutputStream(new FileOutputStream(of));
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
of.deleteOnExit();
uri = of.toURI();
try {
int avail = is.available();
while (avail > 0) {
byte buffer[] = new byte[avail];
int bytesread = is.read(buffer, 0, avail);
os.write(buffer, 0, bytesread);
avail = is.available();
}
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
try {
Desktop.getDesktop().browse(uri);
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
});
if (!opaque) {
Color bg = new JPanel().getBackground();
editorPane.setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue()));