diff --git a/BasicHTMLParser.java b/BasicHTMLParser.java
index bd106b8..386501d 100644
--- a/BasicHTMLParser.java
+++ b/BasicHTMLParser.java
@@ -29,308 +29,308 @@ import cafe.biskuteri.hinoki.Tree;
interface
BasicHTMLParser {
- public static Tree
- parse(String html)
- {
- List segments;
- segments = distinguishTagsFromPcdata(html);
+ public static Tree
+ parse(String html)
+ {
+ List segments;
+ segments = distinguishTagsFromPcdata(html);
- Tree document;
- document = toNodes(segments);
- document = splitText(document);
- document = evaluateHtmlEscapes(document);
- document = hierarchise(document);
+ Tree document;
+ document = toNodes(segments);
+ document = splitText(document);
+ document = evaluateHtmlEscapes(document);
+ document = hierarchise(document);
- return document;
- }
+ return document;
+ }
-// - -%- -
+// - -%- -
- private static List
- distinguishTagsFromPcdata(String html)
- {
- List returnee = new ArrayList<>();
- StringBuilder segment = new StringBuilder();
- boolean inTag = false;
- for (char c: html.toCharArray())
- {
- if (c == '<')
- {
- String addee = empty(segment);
- if (!addee.isEmpty()) returnee.add(addee);
- inTag = true;
- segment.append(c);
- }
- else if (c == '>')
- {
- assert inTag;
- assert segment.length() > 0;
- segment.append(c);
- returnee.add(empty(segment));
- inTag = false;
- }
- else
- {
- segment.append(c);
- }
- }
- String addee = empty(segment);
- if (!addee.isEmpty()) returnee.add(addee);
+ private static List
+ distinguishTagsFromPcdata(String html)
+ {
+ List returnee = new ArrayList<>();
+ StringBuilder segment = new StringBuilder();
+ boolean inTag = false;
+ for (char c: html.toCharArray())
+ {
+ if (c == '<')
+ {
+ String addee = empty(segment);
+ if (!addee.isEmpty()) returnee.add(addee);
+ inTag = true;
+ segment.append(c);
+ }
+ else if (c == '>')
+ {
+ assert inTag;
+ assert segment.length() > 0;
+ segment.append(c);
+ returnee.add(empty(segment));
+ inTag = false;
+ }
+ else
+ {
+ segment.append(c);
+ }
+ }
+ String addee = empty(segment);
+ if (!addee.isEmpty()) returnee.add(addee);
- return returnee;
- }
+ return returnee;
+ }
- private static Tree
- toNodes(List segments)
- {
- Tree returnee = new Tree();
+ private static Tree
+ toNodes(List segments)
+ {
+ Tree returnee = new Tree();
- for (String segment: segments)
- {
- boolean isTag = segment.startsWith("<");
- Tree node = new Tree();
+ for (String segment: segments)
+ {
+ boolean isTag = segment.startsWith("<");
+ Tree node = new Tree();
- if (!isTag)
- {
- node.key = "text";
- node.value = segment;
- returnee.add(node);
- continue;
- }
+ if (!isTag)
+ {
+ node.key = "text";
+ node.value = segment;
+ returnee.add(node);
+ continue;
+ }
- node.key = "tag";
+ node.key = "tag";
- String key = null, value = null;
- StringBuilder b = new StringBuilder();
- boolean inQuotes = false, inValue = false;
- char[] chars = segment.toCharArray();
- for (int o = 1; o < chars.length - 1; ++o)
- {
- char c = chars[o];
- if (c == '"')
- {
- inQuotes = !inQuotes;
- }
- else if (inQuotes)
- {
- b.append(c);
- }
- else if (c == '=')
- {
- assert b.length() > 0;
- key = empty(b);
- inValue = true;
- }
- else if (Character.isWhitespace(c))
- {
- if (b.length() > 0)
- {
- if (inValue) value = empty(b);
- else key = empty(b);
- Tree attr = new Tree();
- attr.key = key;
- attr.value = value;
- node.add(attr);
- }
- inValue = false;
- }
- else
- {
- b.append(c);
- }
- }
- if (b.length() > 0)
- {
- if (inValue) value = empty(b);
- else key = empty(b);
- Tree attr = new Tree();
- attr.key = key;
- attr.value = value;
- node.add(attr);
- }
+ String key = null, value = null;
+ StringBuilder b = new StringBuilder();
+ boolean inQuotes = false, inValue = false;
+ char[] chars = segment.toCharArray();
+ for (int o = 1; o < chars.length - 1; ++o)
+ {
+ char c = chars[o];
+ if (c == '"')
+ {
+ inQuotes = !inQuotes;
+ }
+ else if (inQuotes)
+ {
+ b.append(c);
+ }
+ else if (c == '=')
+ {
+ assert b.length() > 0;
+ key = empty(b);
+ inValue = true;
+ }
+ else if (Character.isWhitespace(c))
+ {
+ if (b.length() > 0)
+ {
+ if (inValue) value = empty(b);
+ else key = empty(b);
+ Tree attr = new Tree();
+ attr.key = key;
+ attr.value = value;
+ node.add(attr);
+ }
+ inValue = false;
+ }
+ else
+ {
+ b.append(c);
+ }
+ }
+ if (b.length() > 0)
+ {
+ if (inValue) value = empty(b);
+ else key = empty(b);
+ Tree attr = new Tree();
+ attr.key = key;
+ attr.value = value;
+ node.add(attr);
+ }
- returnee.add(node);
- }
+ returnee.add(node);
+ }
- return returnee;
- }
+ return returnee;
+ }
- private static Tree
- splitText(Tree nodes)
- {
- Tree returnee = new Tree<>();
+ private static Tree
+ splitText(Tree nodes)
+ {
+ Tree returnee = new Tree<>();
- for (Tree node: nodes)
- {
- if (node.key.equals("tag"))
- {
- returnee.add(node);
- continue;
- }
- assert node.key.equals("text");
+ for (Tree node: nodes)
+ {
+ if (node.key.equals("tag"))
+ {
+ returnee.add(node);
+ continue;
+ }
+ assert node.key.equals("text");
- StringBuilder b = new StringBuilder();
- boolean alnum = false, calnum;
- boolean space = false, cspace;
- boolean emoji = false;
- for (char c: node.value.toCharArray())
- {
- calnum = isMastodonAlnum(c);
- cspace = Character.isWhitespace(c);
+ StringBuilder b = new StringBuilder();
+ boolean alnum = false, calnum;
+ boolean space = false, cspace;
+ boolean emoji = false;
+ for (char c: node.value.toCharArray())
+ {
+ calnum = isMastodonAlnum(c);
+ cspace = Character.isWhitespace(c);
- if (c == ':' && !emoji)
- {
+ if (c == ':' && !emoji)
+ {
// See note on #isMastodonAlnum.
- if (b.length() > 0)
- {
- Tree addee = new Tree<>();
- addee.key = space ? "space" : "text";
- addee.value = empty(b);
- returnee.add(addee);
- }
- emoji = true;
- b.append(c);
- }
- else if (c == ':' && emoji)
- {
- assert !space;
- b.append(c);
- Tree addee = new Tree<>();
- addee.key = "emoji";
- addee.value = empty(b);
- returnee.add(addee);
- /*
- * Technically, addee.value.length()
- * could be zero, which probably means
- * someone just put two colons in a row,
- * maybe for Haskell source code. I'd
- * be surprised if Mastodon didn't escape
- * it. (If they did, the next step will
- * handle them.) Anyways treating it as
- * an empty emoji is the correct action.
- */
- emoji = false;
- calnum = false;
- }
- else if (cspace != space)
- {
if (b.length() > 0)
- {
- Tree addee = new Tree<>();
- addee.key = space ? "space" : "text";
- addee.value = empty(b);
- returnee.add(addee);
- }
- b.append(c);
- }
- else
- {
- b.append(c);
- }
- /*
- * We can specially handle special
- * characters like \n, but I'll opt not to.
- */
+ {
+ Tree addee = new Tree<>();
+ addee.key = space ? "space" : "text";
+ addee.value = empty(b);
+ returnee.add(addee);
+ }
+ emoji = true;
+ b.append(c);
+ }
+ else if (c == ':' && emoji)
+ {
+ assert !space;
+ b.append(c);
+ Tree addee = new Tree<>();
+ addee.key = "emoji";
+ addee.value = empty(b);
+ returnee.add(addee);
+ /*
+ * Technically, addee.value.length()
+ * could be zero, which probably means
+ * someone just put two colons in a row,
+ * maybe for Haskell source code. I'd
+ * be surprised if Mastodon didn't escape
+ * it. (If they did, the next step will
+ * handle them.) Anyways treating it as
+ * an empty emoji is the correct action.
+ */
+ emoji = false;
+ calnum = false;
+ }
+ else if (cspace != space)
+ {
+ if (b.length() > 0)
+ {
+ Tree addee = new Tree<>();
+ addee.key = space ? "space" : "text";
+ addee.value = empty(b);
+ returnee.add(addee);
+ }
+ b.append(c);
+ }
+ else
+ {
+ b.append(c);
+ }
+ /*
+ * We can specially handle special
+ * characters like \n, but I'll opt not to.
+ */
- alnum = calnum;
- space = cspace;
- }
- if (b.length() > 0)
- {
- Tree addee = new Tree<>();
- addee.key = space ? "space" : "text";
- addee.value = empty(b);
- returnee.add(addee);
- }
- }
+ alnum = calnum;
+ space = cspace;
+ }
+ if (b.length() > 0)
+ {
+ Tree addee = new Tree<>();
+ addee.key = space ? "space" : "text";
+ addee.value = empty(b);
+ returnee.add(addee);
+ }
+ }
- return returnee;
- }
+ return returnee;
+ }
- private static Tree
- evaluateHtmlEscapes(Tree nodes)
- {
- for (Tree node: nodes)
- {
- node.value = evaluateHtmlEscapes(node.value);
- for (Tree attr: node)
- {
- attr.key = evaluateHtmlEscapes(attr.key);
- attr.value = evaluateHtmlEscapes(attr.value);
- }
- }
+ private static Tree
+ evaluateHtmlEscapes(Tree nodes)
+ {
+ for (Tree node: nodes)
+ {
+ node.value = evaluateHtmlEscapes(node.value);
+ for (Tree attr: node)
+ {
+ attr.key = evaluateHtmlEscapes(attr.key);
+ attr.value = evaluateHtmlEscapes(attr.value);
+ }
+ }
- return nodes;
- }
+ return nodes;
+ }
- private static Tree
- hierarchise(Tree nodes)
- {
- Tree root = new Tree();
- root.key = "tag";
- root.add(new Tree<>("html", null));
- root.add(new Tree<>("children", null));
+ private static Tree
+ hierarchise(Tree nodes)
+ {
+ Tree root = new Tree();
+ root.key = "tag";
+ root.add(new Tree<>("html", null));
+ root.add(new Tree<>("children", null));
- Deque> parents = new LinkedList<>();
- parents.push(root);
- for (Tree node: nodes)
- {
- if (node.key.equals("tag"))
- {
- assert node.size() > 0;
- String tagName = node.get(0).key;
+ Deque> parents = new LinkedList<>();
+ parents.push(root);
+ for (Tree node: nodes)
+ {
+ if (node.key.equals("tag"))
+ {
+ assert node.size() > 0;
+ String tagName = node.get(0).key;
- assert node.get("children") == null;
- node.add(new Tree<>("children", null));
+ assert node.get("children") == null;
+ node.add(new Tree<>("children", null));
- boolean isClosing, selfClosing;
- isClosing = tagName.startsWith("/");
- selfClosing = node.get("/") != null;
- selfClosing |= tagName.equals("br");
- if (isClosing)
- {
- assert parents.size() > 1;
+ boolean isClosing, selfClosing;
+ isClosing = tagName.startsWith("/");
+ selfClosing = node.get("/") != null;
+ selfClosing |= tagName.equals("br");
+ if (isClosing)
+ {
+ assert parents.size() > 1;
- Tree parent, grandparent;
- parent = parents.pop();
- grandparent = parents.peek();
+ Tree parent, grandparent;
+ parent = parents.pop();
+ grandparent = parents.peek();
- String pTagName = parent.get(0).key;
- assert tagName.equals("/" + pTagName);
+ String pTagName = parent.get(0).key;
+ assert tagName.equals("/" + pTagName);
- grandparent.get("children").add(parent);
- }
- else if (selfClosing)
- {
- parents.peek().get("children").add(node);
- }
- else
- {
- parents.push(node);
- }
- }
- else
- {
- parents.peek().get("children").add(node);
- }
- }
+ grandparent.get("children").add(parent);
+ }
+ else if (selfClosing)
+ {
+ parents.peek().get("children").add(node);
+ }
+ else
+ {
+ parents.push(node);
+ }
+ }
+ else
+ {
+ parents.peek().get("children").add(node);
+ }
+ }
- assert parents.size() == 1;
- return parents.pop();
- }
+ assert parents.size() == 1;
+ return parents.pop();
+ }
- private static String
- empty(StringBuilder b)
- {
- String s = b.toString();
- b.delete(0, b.length());
- return s;
- }
+ private static String
+ empty(StringBuilder b)
+ {
+ String s = b.toString();
+ b.delete(0, b.length());
+ return s;
+ }
- private static boolean
- isMastodonAlnum(char c)
- {
+ private static boolean
+ isMastodonAlnum(char c)
+ {
return Character.isLetterOrDigit(c);
/*
* Not joking. Mastodon is using the POSIX :alnum: regex
@@ -343,44 +343,44 @@ BasicHTMLParser {
* by text, then try again with the same emoji also
* present elsewhere in the post at a valid position.)
*/
- }
+ }
- private static String
- evaluateHtmlEscapes(String string)
- {
- if (string == null) return string;
+ private static String
+ evaluateHtmlEscapes(String string)
+ {
+ if (string == null) return string;
- StringBuilder whole = new StringBuilder();
- StringBuilder part = new StringBuilder();
- boolean inEscape = false;
- for (char c: string.toCharArray())
- {
- if (inEscape && c == ';')
- {
- part.append(c);
- inEscape = false;
- String v = empty(part);
- if (v.equals("<")) part.append('<');
- if (v.equals(">")) part.append('>');
- if (v.equals("&")) part.append('&');
- if (v.equals(""")) part.append('"');
- if (v.equals("'")) part.append('\'');
- if (v.equals("'")) part.append('\'');
- }
- else if (!inEscape && c == '&')
- {
- String v = empty(part);
- if (!v.isEmpty()) whole.append(v);
- part.append(c);
- inEscape = true;
- }
- else
- {
- part.append(c);
- }
- }
- String v = empty(part);
- if (!v.isEmpty()) whole.append(v);
- return whole.toString();
- }
+ StringBuilder whole = new StringBuilder();
+ StringBuilder part = new StringBuilder();
+ boolean inEscape = false;
+ for (char c: string.toCharArray())
+ {
+ if (inEscape && c == ';')
+ {
+ part.append(c);
+ inEscape = false;
+ String v = empty(part);
+ if (v.equals("<")) part.append('<');
+ if (v.equals(">")) part.append('>');
+ if (v.equals("&")) part.append('&');
+ if (v.equals(""")) part.append('"');
+ if (v.equals("'")) part.append('\'');
+ if (v.equals("'")) part.append('\'');
+ }
+ else if (!inEscape && c == '&')
+ {
+ String v = empty(part);
+ if (!v.isEmpty()) whole.append(v);
+ part.append(c);
+ inEscape = true;
+ }
+ else
+ {
+ part.append(c);
+ }
+ }
+ String v = empty(part);
+ if (!v.isEmpty()) whole.append(v);
+ return whole.toString();
+ }
}
diff --git a/ClipboardApi.java b/ClipboardApi.java
index 07571eb..694cd2b 100644
--- a/ClipboardApi.java
+++ b/ClipboardApi.java
@@ -41,41 +41,41 @@ implements Transferable, ClipboardOwner {
{
assert string != null;
instance.string = string;
- Toolkit tk = Toolkit.getDefaultToolkit();
- Clipboard cb = tk.getSystemClipboard();
- cb.setContents(instance, instance);
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ Clipboard cb = tk.getSystemClipboard();
+ cb.setContents(instance, instance);
}
// - -%- -
- public String
- getTransferData(DataFlavor flavour)
- {
+ public String
+ getTransferData(DataFlavor flavour)
+ {
assert flavour == DataFlavor.stringFlavor;
return string;
- }
+ }
- public DataFlavor[]
- getTransferDataFlavors()
- {
- return new DataFlavor[] { DataFlavor.stringFlavor };
- /*
- * We should probably also support javaJVMLocalObjectMimeType,
- * so that the compose window can ask for the List.
- * Although also like, if we don't store emoji shortcodes in
- * the image segments, there is no point. Anyways, what is
- * important is the string format first, allowing us to
- * copy links or large lengths of text.
- */
- }
+ public DataFlavor[]
+ getTransferDataFlavors()
+ {
+ return new DataFlavor[] { DataFlavor.stringFlavor };
+ /*
+ * We should probably also support javaJVMLocalObjectMimeType,
+ * so that the compose window can ask for the List.
+ * Although also like, if we don't store emoji shortcodes in
+ * the image segments, there is no point. Anyways, what is
+ * important is the string format first, allowing us to
+ * copy links or large lengths of text.
+ */
+ }
- public boolean
- isDataFlavorSupported(DataFlavor flavour)
- {
- return flavour == DataFlavor.stringFlavor;
- }
+ public boolean
+ isDataFlavorSupported(DataFlavor flavour)
+ {
+ return flavour == DataFlavor.stringFlavor;
+ }
- public void
- lostOwnership(Clipboard clipboard, Transferable contents) { }
+ public void
+ lostOwnership(Clipboard clipboard, Transferable contents) { }
}
diff --git a/ComposeWindow.java b/ComposeWindow.java
index 9834c1d..02077f0 100644
--- a/ComposeWindow.java
+++ b/ComposeWindow.java
@@ -126,86 +126,86 @@ ComposeWindow extends JFrame {
if (composition.contentWarning != null)
assert !composition.contentWarning.trim().isEmpty();
- //tabs.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- /*
- * setCursor only works for components that are enabled.
- * I don't think there's any technical reason for this,
- * but it's what it is.. rely on the enablement visuals
- * or a statusbar to indicate to user.
- *
- * If we really wanted it, I suspect we could use a glass
- * pane (or a scroll pane with no scrolling) to have an
- * enabled pass-through on top.
- *
- * Technically contentsDisplay and attachmentsDisplay
- * themselves aren't disabled. But disabling the tab pane
- * covers both the tab area and content area. We can't
- * just the tab area, except maybe by disabling the
- * individual tabs.
- */
- tabs.setEnabled(false);
- tabs.setSelectedComponent(contentsDisplay);
- contentsDisplay.setSubmitting(true);
- tabs.paintImmediately(tabs.getBounds());
+ //tabs.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ /*
+ * setCursor only works for components that are enabled.
+ * I don't think there's any technical reason for this,
+ * but it's what it is.. rely on the enablement visuals
+ * or a statusbar to indicate to user.
+ *
+ * If we really wanted it, I suspect we could use a glass
+ * pane (or a scroll pane with no scrolling) to have an
+ * enabled pass-through on top.
+ *
+ * Technically contentsDisplay and attachmentsDisplay
+ * themselves aren't disabled. But disabling the tab pane
+ * covers both the tab area and content area. We can't
+ * just the tab area, except maybe by disabling the
+ * individual tabs.
+ */
+ tabs.setEnabled(false);
+ tabs.setSelectedComponent(contentsDisplay);
+ contentsDisplay.setSubmitting(true);
+ tabs.paintImmediately(tabs.getBounds());
- boolean uploadsOkay = true;
- for (Attachment a: composition.attachments)
- {
- if (a.id != null) continue;
- // Assume it had already been uploaded.
+ boolean uploadsOkay = true;
+ for (Attachment a: composition.attachments)
+ {
+ if (a.id != null) continue;
+ // Assume it had already been uploaded.
- api.uploadFile(
- a.uploadee, a.description,
- new RequestListener() {
+ api.uploadFile(
+ a.uploadee, a.description,
+ new RequestListener() {
- public void
- connectionFailed(IOException eIo)
- {
- JOptionPane.showMessageDialog(
+ public void
+ connectionFailed(IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
ComposeWindow.this,
"Tried to upload attachment, failed..."
+ "\n" + eIo.getMessage()
);
- }
+ }
- public void
- requestFailed(int httpCode, Tree json)
- {
- JOptionPane.showMessageDialog(
+ public void
+ requestFailed(int httpCode, Tree json)
+ {
+ JOptionPane.showMessageDialog(
ComposeWindow.this,
"Tried to upload attachment, failed..."
- + "\n" + json.get("error").value
+ + "\n" + json.get("error").value
+ "\n(HTTP code: " + httpCode + ")"
);
- }
+ }
- public void
- requestSucceeded(Tree json)
- {
- a.id = json.get("id").value;
- }
+ public void
+ requestSucceeded(Tree json)
+ {
+ a.id = json.get("id").value;
+ }
- });
- uploadsOkay &= a.id != null;
- }
+ });
+ uploadsOkay &= a.id != null;
+ }
- if (!uploadsOkay)
- {
- contentsDisplay.setSubmitting(false);
- tabs.setEnabled(true);
- //tabs.setCursor(null);
- return;
- }
+ if (!uploadsOkay)
+ {
+ contentsDisplay.setSubmitting(false);
+ tabs.setEnabled(true);
+ //tabs.setCursor(null);
+ return;
+ }
- int amt = composition.attachments.length;
- String[] mediaIDs = new String[amt];
- for (int o = 0; o < mediaIDs.length; ++o)
- mediaIDs[o] = composition.attachments[o].id;
+ int amt = composition.attachments.length;
+ String[] mediaIDs = new String[amt];
+ for (int o = 0; o < mediaIDs.length; ++o)
+ mediaIDs[o] = composition.attachments[o].id;
- api.submit(
+ api.submit(
composition.text, composition.visibility,
composition.replyToPostId, composition.contentWarning,
- mediaIDs,
+ mediaIDs,
new RequestListener() {
public void
@@ -239,8 +239,8 @@ ComposeWindow extends JFrame {
);
contentsDisplay.setSubmitting(false);
- tabs.setEnabled(true);
- tabs.setCursor(null);
+ tabs.setEnabled(true);
+ tabs.setCursor(null);
}
// - -%- -
@@ -254,14 +254,14 @@ ComposeWindow extends JFrame {
d1.setVisibility(stringFor(composition.visibility));
d1.setContentWarning(composition.contentWarning);
- AttachmentsComponent d2 = attachmentsDisplay;
- d2.setAttachments(composition.attachments);
+ AttachmentsComponent d2 = attachmentsDisplay;
+ d2.setAttachments(composition.attachments);
}
private synchronized void
syncCompositionToDisplay()
{
- Composition c = composition;
+ Composition c = composition;
ComposeComponent d1 = contentsDisplay;
c.text = d1.getText();
@@ -269,8 +269,8 @@ ComposeWindow extends JFrame {
c.replyToPostId = nonEmpty(d1.getReplyToPostId());
c.contentWarning = nonEmpty(d1.getContentWarning());
- AttachmentsComponent d2 = attachmentsDisplay;
- c.attachments = d2.getAttachments();
+ AttachmentsComponent d2 = attachmentsDisplay;
+ c.attachments = d2.getAttachments();
}
// - -%- -
@@ -509,18 +509,18 @@ implements ActionListener, CaretListener, KeyListener {
Border b3 = BorderFactory.createLineBorder(Color.GRAY);
Border bc = BorderFactory.createCompoundBorder(b3, b2);
- TextActionPopupMenu textActionPopup;
- textActionPopup = new TextActionPopupMenu();
+ TextActionPopupMenu textActionPopup;
+ textActionPopup = new TextActionPopupMenu();
reply = new JTextField();
JLabel replyLabel = new JLabel("In reply to: ");
replyLabel.setLabelFor(reply);
- reply.addMouseListener(textActionPopup);
+ reply.addMouseListener(textActionPopup);
contentWarning = new JTextField();
JLabel cwLabel = new JLabel("Content warning: ");
cwLabel.setLabelFor(contentWarning);
- contentWarning.addMouseListener(textActionPopup);
+ contentWarning.addMouseListener(textActionPopup);
JPanel top = new JPanel();
top.setOpaque(false);
@@ -560,7 +560,7 @@ implements ActionListener, CaretListener, KeyListener {
text.setBorder(bc);
text.addCaretListener(this);
text.addKeyListener(this);
- text.addMouseListener(textActionPopup);
+ text.addMouseListener(textActionPopup);
setLayout(new BorderLayout(0, 8));
add(top, BorderLayout.NORTH);
@@ -592,7 +592,7 @@ implements ComponentListener, ActionListener {
attachment2,
attachment3,
attachment4,
- selected;
+ selected;
private JButton
add;
@@ -607,83 +607,83 @@ implements ComponentListener, ActionListener {
private JTextArea
description;
- private JFileChooser
- chooser;
+ private JFileChooser
+ chooser;
- private UndoManager
- descriptionUndos;
+ private UndoManager
+ descriptionUndos;
// ---%-@-%---
- public void
- setAttachments(Attachment[] n)
- {
- working.clear();
- if (n != null) for (Attachment attachment: n)
- {
- working.add(attachment);
- }
- updateButtons();
- }
+ public void
+ setAttachments(Attachment[] n)
+ {
+ working.clear();
+ if (n != null) for (Attachment attachment: n)
+ {
+ working.add(attachment);
+ }
+ updateButtons();
+ }
- public Attachment[]
- getAttachments()
- {
- return working.toArray(new Attachment[0]);
- }
+ public Attachment[]
+ getAttachments()
+ {
+ return working.toArray(new Attachment[0]);
+ }
-// - -%- -
+// - -%- -
private void
updateButtons()
{
Dimension sz = add.getPreferredSize();
- selections.removeAll();
- selected = null;
+ selections.removeAll();
+ selected = null;
if (working.size() > 0)
- {
- selections.add(attachment1);
- Image i = working.get(0).image;
- attachment1.setIcon(new ImageIcon(i));
- }
- if (working.size() > 1)
- {
- selections.add(attachment2);
- Image i = working.get(1).image;
- attachment2.setIcon(new ImageIcon(i));
- }
- if (working.size() > 2)
- {
- selections.add(attachment3);
- Image i = working.get(2).image;
- attachment3.setIcon(new ImageIcon(i));
- }
+ {
+ selections.add(attachment1);
+ Image i = working.get(0).image;
+ attachment1.setIcon(new ImageIcon(i));
+ }
+ if (working.size() > 1)
+ {
+ selections.add(attachment2);
+ Image i = working.get(1).image;
+ attachment2.setIcon(new ImageIcon(i));
+ }
+ if (working.size() > 2)
+ {
+ selections.add(attachment3);
+ Image i = working.get(2).image;
+ attachment3.setIcon(new ImageIcon(i));
+ }
if (working.size() > 3)
- {
- selections.add(attachment4);
- Image i = working.get(3).image;
- attachment4.setIcon(new ImageIcon(i));
- }
- if (working.size() < 4) selections.add(add);
+ {
+ selections.add(attachment4);
+ Image i = working.get(3).image;
+ attachment4.setIcon(new ImageIcon(i));
+ }
+ if (working.size() < 4) selections.add(add);
- if (working.size() > 3) open(attachment4);
- else if (working.size() > 2) open(attachment3);
- else if (working.size() > 1) open(attachment2);
- else if (working.size() > 0) open(attachment1);
+ if (working.size() > 3) open(attachment4);
+ else if (working.size() > 2) open(attachment3);
+ else if (working.size() > 1) open(attachment2);
+ else if (working.size() > 0) open(attachment1);
- int bw = sz.width;
+ int bw = sz.width;
int hgap = 4;
int count = selections.getComponents().length;
int w = count * bw + (count - 1) * hgap;
int h = bw;
selections.setPreferredSize(new Dimension(w, h));
selections.setMaximumSize(new Dimension(w, h));
- selections.revalidate();
+ selections.revalidate();
- delete.setEnabled(selected != null);
- revert.setEnabled(selected != null);
- description.setEnabled(selected != null);
+ delete.setEnabled(selected != null);
+ revert.setEnabled(selected != null);
+ description.setEnabled(selected != null);
}
public void
@@ -693,34 +693,34 @@ implements ComponentListener, ActionListener {
if (src == add)
{
- int r = chooser.showOpenDialog(this);
- if (r != JFileChooser.APPROVE_OPTION) return;
+ int r = chooser.showOpenDialog(this);
+ if (r != JFileChooser.APPROVE_OPTION) return;
- File f = chooser.getSelectedFile();
+ File f = chooser.getSelectedFile();
- Attachment a = new Attachment();
- a.uploadee = f;
- a.description = "";
- a.type = "unknown";
+ Attachment a = new Attachment();
+ a.uploadee = f;
+ a.description = "";
+ a.type = "unknown";
- String mime = "", primary = "";
- try
- {
- mime = Files.probeContentType(f.toPath());
- primary = mime.split("/")[0];
- // Too lazy to instantiate a
- // javax.activation.MimeType.
- }
- catch (IOException eIo) { }
- if (primary.equals("image"))
- {
- String urlr = f.toURI().toString();
- a.image = ImageApi.remote(urlr);
- a.type = "image";
- }
+ String mime = "", primary = "";
+ try
+ {
+ mime = Files.probeContentType(f.toPath());
+ primary = mime.split("/")[0];
+ // Too lazy to instantiate a
+ // javax.activation.MimeType.
+ }
+ catch (IOException eIo) { }
+ if (primary.equals("image"))
+ {
+ String urlr = f.toURI().toString();
+ a.image = ImageApi.remote(urlr);
+ a.type = "image";
+ }
- if (selected != null) open(selected);
- // Save first before resetting
+ if (selected != null) open(selected);
+ // Save first before resetting
working.add(a);
updateButtons();
@@ -728,87 +728,87 @@ implements ComponentListener, ActionListener {
if (src == delete)
{
- assert selected != null;
- working.remove(getAttachmentFor(selected));
- updateButtons();
+ assert selected != null;
+ working.remove(getAttachmentFor(selected));
+ updateButtons();
return;
}
- if (src != add && selections.isAncestorOf((Component)src))
- {
- assert src instanceof JToggleButton;
- if (src == selected) preview(getAttachmentFor(src));
- else open((JToggleButton)src);
- return;
- }
+ if (src != add && selections.isAncestorOf((Component)src))
+ {
+ assert src instanceof JToggleButton;
+ if (src == selected) preview(getAttachmentFor(src));
+ else open((JToggleButton)src);
+ return;
+ }
if (src == revert)
{
- while (descriptionUndos.canUndo())
- descriptionUndos.undo();
- return;
+ while (descriptionUndos.canUndo())
+ descriptionUndos.undo();
+ return;
}
}
- private Attachment
- getAttachmentFor(Object button)
- {
- if (button == null) return null;
- assert button instanceof JToggleButton;
- assert selections.isAncestorOf((Component)button);
+ private Attachment
+ getAttachmentFor(Object button)
+ {
+ if (button == null) return null;
+ assert button instanceof JToggleButton;
+ assert selections.isAncestorOf((Component)button);
- int index = 0;
- if (button == attachment4) index = 4;
- if (button == attachment3) index = 3;
- if (button == attachment2) index = 2;
- if (button == attachment1) index = 1;
+ int index = 0;
+ if (button == attachment4) index = 4;
+ if (button == attachment3) index = 3;
+ if (button == attachment2) index = 2;
+ if (button == attachment1) index = 1;
- assert index != 0;
- assert index <= working.size();
- return working.get(index - 1);
- }
+ assert index != 0;
+ assert index <= working.size();
+ return working.get(index - 1);
+ }
- private void
- open(JToggleButton button)
- {
- assert selections.isAncestorOf(button);
+ private void
+ open(JToggleButton button)
+ {
+ assert selections.isAncestorOf(button);
- if (selected != null)
- {
- Attachment a = getAttachmentFor(selected);
- a.description = description.getText();
- selected.setSelected(false);
- }
+ if (selected != null)
+ {
+ Attachment a = getAttachmentFor(selected);
+ a.description = description.getText();
+ selected.setSelected(false);
+ }
- Attachment a = getAttachmentFor(button);
- description.setText(a.description);
- descriptionUndos.discardAllEdits();
- (selected = button).setSelected(true);
- }
+ Attachment a = getAttachmentFor(button);
+ description.setText(a.description);
+ descriptionUndos.discardAllEdits();
+ (selected = button).setSelected(true);
+ }
- public void
- componentHidden(ComponentEvent eC)
- {
- if (selected != null) open(selected);
- }
+ public void
+ componentHidden(ComponentEvent eC)
+ {
+ if (selected != null) open(selected);
+ }
- private void
- preview(Attachment a)
- {
- ImageWindow w = new ImageWindow();
- w.showAttachments(new Attachment[] { a } );
- w.setTitle("Attachment preview");
- w.setVisible(true);
- }
+ private void
+ preview(Attachment a)
+ {
+ ImageWindow w = new ImageWindow();
+ w.showAttachments(new Attachment[] { a } );
+ w.setTitle("Attachment preview");
+ w.setVisible(true);
+ }
- public void
- componentShown(ComponentEvent eC) { }
+ public void
+ componentShown(ComponentEvent eC) { }
- public void
- componentMoved(ComponentEvent eC) { }
+ public void
+ componentMoved(ComponentEvent eC) { }
- public void
- componentResized(ComponentEvent eC) { }
+ public void
+ componentResized(ComponentEvent eC) { }
// ---%-@-%---
@@ -824,15 +824,15 @@ implements ComponentListener, ActionListener {
Border bc1 = BorderFactory.createCompoundBorder(b3, b2);
Border bc2 = BorderFactory.createCompoundBorder(b4, b2);
- TextActionPopupMenu textActionPopup;
- textActionPopup = new TextActionPopupMenu();
+ TextActionPopupMenu textActionPopup;
+ textActionPopup = new TextActionPopupMenu();
- chooser = new JFileChooser();
+ chooser = new JFileChooser();
add = new JButton("+");
add.setPreferredSize(new Dimension(32, 32));
add.setMargin(new Insets(0, 0, 0, 0));
- add.addActionListener(this);
+ add.addActionListener(this);
attachment1 = new JToggleButton("1");
attachment2 = new JToggleButton("2");
attachment3 = new JToggleButton("3");
@@ -841,28 +841,28 @@ implements ComponentListener, ActionListener {
attachment2.setMargin(add.getMargin());
attachment3.setMargin(add.getMargin());
attachment4.setMargin(add.getMargin());
- attachment1.addActionListener(this);
- attachment2.addActionListener(this);
- attachment3.addActionListener(this);
- attachment4.addActionListener(this);
+ attachment1.addActionListener(this);
+ attachment2.addActionListener(this);
+ attachment3.addActionListener(this);
+ attachment4.addActionListener(this);
selections = new JPanel();
selections.setOpaque(false);
selections.setLayout(new GridLayout(1, 0, 4, 0));
working = new ArrayList();
- Box top = Box.createHorizontalBox();
+ Box top = Box.createHorizontalBox();
top.add(selections);
top.add(Box.createGlue());
delete = new JButton("Delete");
revert = new JButton("Revert");
- JButton ml = new JButton("←");
+ JButton ml = new JButton("←");
JButton mr = new JButton("→");
- delete.addActionListener(this);
+ delete.addActionListener(this);
revert.addActionListener(this);
- Box bottom = Box.createHorizontalBox();
+ Box bottom = Box.createHorizontalBox();
bottom.add(ml);
bottom.add(mr);
bottom.add(Box.createHorizontalStrut(8));
@@ -876,14 +876,14 @@ implements ComponentListener, ActionListener {
java.awt.Font f = description.getFont();
description.setFont(f.deriveFont(16f));
description.setBorder(bc1);
- description.addMouseListener(textActionPopup);
+ description.addMouseListener(textActionPopup);
descriptionLabel = new JLabel("Description");
descriptionLabel.setLabelFor(description);
- descriptionUndos = new UndoManager();
- description.getDocument().
- addUndoableEditListener(descriptionUndos);
+ descriptionUndos = new UndoManager();
+ description.getDocument().
+ addUndoableEditListener(descriptionUndos);
- updateButtons();
+ updateButtons();
JPanel row1 = new JPanel();
row1.setOpaque(false);
@@ -891,7 +891,7 @@ implements ComponentListener, ActionListener {
row1.add(descriptionLabel, BorderLayout.NORTH);
row1.add(description, BorderLayout.CENTER);
- Box centre = Box.createVerticalBox();
+ Box centre = Box.createVerticalBox();
centre.setBorder(b4);
centre.add(row1);
@@ -901,7 +901,7 @@ implements ComponentListener, ActionListener {
add(bottom, BorderLayout.SOUTH);
setBorder(b1);
- this.addComponentListener(this);
+ this.addComponentListener(this);
}
}
@@ -910,66 +910,66 @@ class
TextActionPopupMenu extends JPopupMenu
implements MouseListener, ActionListener {
- private JMenuItem
- copy,
- cut,
- paste;
+ private JMenuItem
+ copy,
+ cut,
+ paste;
- private long
- pressed;
+ private long
+ pressed;
-// ---%-@-%---
+// ---%-@-%---
- public void
- mousePressed(MouseEvent eM)
- {
- assert eM.getSource() instanceof JTextComponent;
- if (!eM.isPopupTrigger()) return;
- show((Component)eM.getSource(), eM.getX(), eM.getY());
- }
+ public void
+ mousePressed(MouseEvent eM)
+ {
+ assert eM.getSource() instanceof JTextComponent;
+ if (!eM.isPopupTrigger()) return;
+ show((Component)eM.getSource(), eM.getX(), eM.getY());
+ }
- public void
- mouseReleased(MouseEvent eM)
- {
- if (eM.getClickCount() == 0) setVisible(false);
- }
+ public void
+ mouseReleased(MouseEvent eM)
+ {
+ if (eM.getClickCount() == 0) setVisible(false);
+ }
- public void
- mouseClicked(MouseEvent eM) { }
+ public void
+ mouseClicked(MouseEvent eM) { }
- public void
- mouseEntered(MouseEvent eM) { }
+ public void
+ mouseEntered(MouseEvent eM) { }
- public void
- mouseExited(MouseEvent eM) { }
+ public void
+ mouseExited(MouseEvent eM) { }
- public void
- actionPerformed(ActionEvent eA)
- {
- assert getInvoker() instanceof JTextComponent;
- JTextComponent inv = (JTextComponent)getInvoker();
+ public void
+ actionPerformed(ActionEvent eA)
+ {
+ assert getInvoker() instanceof JTextComponent;
+ JTextComponent inv = (JTextComponent)getInvoker();
- if (eA.getSource() == copy) inv.copy();
- if (eA.getSource() == cut) inv.cut();
- if (eA.getSource() == paste) inv.paste();
- }
+ if (eA.getSource() == copy) inv.copy();
+ if (eA.getSource() == cut) inv.cut();
+ if (eA.getSource() == paste) inv.paste();
+ }
-// ---%-@-%---
+// ---%-@-%---
- public
- TextActionPopupMenu()
- {
- copy = new JMenuItem("Copy");
- cut = new JMenuItem("Cut");
- paste = new JMenuItem("Paste");
- copy.addActionListener(this);
- cut.addActionListener(this);
- paste.addActionListener(this);
+ public
+ TextActionPopupMenu()
+ {
+ copy = new JMenuItem("Copy");
+ cut = new JMenuItem("Cut");
+ paste = new JMenuItem("Paste");
+ copy.addActionListener(this);
+ cut.addActionListener(this);
+ paste.addActionListener(this);
- add(cut);
- add(copy);
- add(paste);
- }
+ add(cut);
+ add(copy);
+ add(paste);
+ }
}
diff --git a/ImageWindow.java b/ImageWindow.java
index 6ca472b..3aba5b6 100644
--- a/ImageWindow.java
+++ b/ImageWindow.java
@@ -41,303 +41,303 @@ import java.net.MalformedURLException;
class
ImageWindow extends JFrame {
- private Attachment[]
- attachments;
+ private Attachment[]
+ attachments;
- private int
- offset;
+ private int
+ offset;
-// - -%- -
+// - -%- -
- private ImageComponent
- display;
+ private ImageComponent
+ display;
-// ---%-@-%---
+// ---%-@-%---
- public synchronized void
- showAttachments(Attachment[] attachments)
- {
- this.attachments = attachments;
+ public synchronized void
+ showAttachments(Attachment[] attachments)
+ {
+ this.attachments = attachments;
- if (attachments.length == 0) {
- display.setImage(null);
- display.setNext(null);
- display.setPrev(null);
- display.repaint();
- return;
- }
+ if (attachments.length == 0) {
+ display.setImage(null);
+ display.setNext(null);
+ display.setPrev(null);
+ display.repaint();
+ return;
+ }
- toImage(offset = 0);
- }
+ toImage(offset = 0);
+ }
- public void
- toNextImage()
- {
- if (attachments.length == 0) return;
- assert offset < attachments.length - 1;
- toImage(++offset);
- }
+ public void
+ toNextImage()
+ {
+ if (attachments.length == 0) return;
+ assert offset < attachments.length - 1;
+ toImage(++offset);
+ }
- public void
- toPrevImage()
- {
- if (attachments.length == 0) return;
- assert offset > 0;
- toImage(--offset);
- }
+ public void
+ toPrevImage()
+ {
+ if (attachments.length == 0) return;
+ assert offset > 0;
+ toImage(--offset);
+ }
-// - -%- -
+// - -%- -
- private synchronized void
- toImage(int offset)
- {
- int last = attachments.length - 1;
- assert offset >= 0;
- assert offset < attachments.length;
+ private synchronized void
+ toImage(int offset)
+ {
+ int last = attachments.length - 1;
+ assert offset >= 0;
+ assert offset < attachments.length;
- Attachment prev, curr, next;
- curr = attachments[offset];
- next = offset < last ? attachments[offset + 1] : null;
- prev = offset > 0 ? attachments[offset - 1] : null;
+ Attachment prev, curr, next;
+ curr = attachments[offset];
+ next = offset < last ? attachments[offset + 1] : null;
+ prev = offset > 0 ? attachments[offset - 1] : null;
- display.setImage(curr.image);
- display.setNext(next != null ? next.image : null);
- display.setPrev(prev != null ? prev.image : null);
+ display.setImage(curr.image);
+ display.setNext(next != null ? next.image : null);
+ display.setPrev(prev != null ? prev.image : null);
- if (!curr.type.equals("image"))
- display.setToolTipText(
- display.getToolTipText()
- + "\n(Media is of type '" + curr.type + "')"
- );
+ if (!curr.type.equals("image"))
+ display.setToolTipText(
+ display.getToolTipText()
+ + "\n(Media is of type '" + curr.type + "')"
+ );
- repaint();
- }
+ repaint();
+ }
-// ---%-@-%---
+// ---%-@-%---
- ImageWindow()
- {
- setDefaultCloseOperation(DISPOSE_ON_CLOSE);
- setSize(600, 600);
+ ImageWindow()
+ {
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+ setSize(600, 600);
- display = new ImageComponent(this);
- showAttachments(new Attachment[0]);
- setContentPane(display);
- }
+ display = new ImageComponent(this);
+ showAttachments(new Attachment[0]);
+ setContentPane(display);
+ }
}
class
ImageComponent extends JPanel
implements
- ActionListener,
- MouseListener, MouseMotionListener, MouseWheelListener {
+ ActionListener,
+ MouseListener, MouseMotionListener, MouseWheelListener {
- private ImageWindow
- primaire;
+ private ImageWindow
+ primaire;
-// - -%- -
+// - -%- -
- private Image
- image, prevImage, nextImage;
+ private Image
+ image, prevImage, nextImage;
- private JPanel
- buttonArea;
+ private JPanel
+ buttonArea;
- private JButton
- prev, next, toggle;
+ private JButton
+ prev, next, toggle;
- private boolean
- scaleImage;
+ private boolean
+ scaleImage;
- private int
- xOffset, yOffset, zoomLevel;
+ private int
+ xOffset, yOffset, zoomLevel;
- private int
- dragX, dragY, xPOffset, yPOffset;
+ private int
+ dragX, dragY, xPOffset, yPOffset;
-// ---%-@-%---
+// ---%-@-%---
- public void
- setImage(Image image)
- {
- this.image = image;
- if (image != null) {
- Object p = image.getProperty("comment", this);
- String desc = p instanceof String ? (String)p : null;
- setToolTipText(desc);
- }
- xOffset = yOffset = xPOffset = yPOffset = 0;
- zoomLevel = 100;
- }
+ public void
+ setImage(Image image)
+ {
+ this.image = image;
+ if (image != null) {
+ Object p = image.getProperty("comment", this);
+ String desc = p instanceof String ? (String)p : null;
+ setToolTipText(desc);
+ }
+ xOffset = yOffset = xPOffset = yPOffset = 0;
+ zoomLevel = 100;
+ }
- public void
- setPrev(Image image)
- {
- prev.setEnabled(image != null);
- prev.setText(image == null ? "<" : "");
- prev.setIcon(toIcon(image));
- }
+ public void
+ setPrev(Image image)
+ {
+ prev.setEnabled(image != null);
+ prev.setText(image == null ? "<" : "");
+ prev.setIcon(toIcon(image));
+ }
- public void
- setNext(Image image)
- {
- next.setEnabled(image != null);
- next.setText(image == null ? ">" : "");
- next.setIcon(toIcon(image));
- }
+ public void
+ setNext(Image image)
+ {
+ next.setEnabled(image != null);
+ next.setText(image == null ? ">" : "");
+ next.setIcon(toIcon(image));
+ }
-// - -%- -
+// - -%- -
- public void
- actionPerformed(ActionEvent eA)
- {
- if (eA.getSource() == prev) primaire.toPrevImage();
- if (eA.getSource() == next) primaire.toNextImage();
- if (eA.getSource() == toggle) {
- scaleImage = !scaleImage;
- if (scaleImage) toggle.setText("Show unscaled");
- else toggle.setText("Show scaled to window");
- setImage(this.image);
- repaint();
- }
- }
+ public void
+ actionPerformed(ActionEvent eA)
+ {
+ if (eA.getSource() == prev) primaire.toPrevImage();
+ if (eA.getSource() == next) primaire.toNextImage();
+ if (eA.getSource() == toggle) {
+ scaleImage = !scaleImage;
+ if (scaleImage) toggle.setText("Show unscaled");
+ else toggle.setText("Show scaled to window");
+ setImage(this.image);
+ repaint();
+ }
+ }
- public void
- mousePressed(MouseEvent eM)
- {
- dragX = eM.getX();
- dragY = eM.getY();
- }
+ public void
+ mousePressed(MouseEvent eM)
+ {
+ dragX = eM.getX();
+ dragY = eM.getY();
+ }
- public void
- mouseDragged(MouseEvent eM)
- {
- int dx = eM.getX() - dragX;
- int dy = eM.getY() - dragY;
- xPOffset = dx;
- yPOffset = dy;
- repaint();
- }
+ public void
+ mouseDragged(MouseEvent eM)
+ {
+ int dx = eM.getX() - dragX;
+ int dy = eM.getY() - dragY;
+ xPOffset = dx;
+ yPOffset = dy;
+ repaint();
+ }
- public void
- mouseReleased(MouseEvent eM)
- {
- xOffset += xPOffset;
- yOffset += yPOffset;
- xPOffset = yPOffset = 0;
- }
+ public void
+ mouseReleased(MouseEvent eM)
+ {
+ xOffset += xPOffset;
+ yOffset += yPOffset;
+ xPOffset = yPOffset = 0;
+ }
- public void
- mouseWheelMoved(MouseWheelEvent eMw)
- {
- zoomLevel += 10 * -eMw.getUnitsToScroll();
- if (zoomLevel < 50) zoomLevel = 50;
- if (zoomLevel > 400) zoomLevel = 400;
- repaint();
- }
+ public void
+ mouseWheelMoved(MouseWheelEvent eMw)
+ {
+ zoomLevel += 10 * -eMw.getUnitsToScroll();
+ if (zoomLevel < 50) zoomLevel = 50;
+ if (zoomLevel > 400) zoomLevel = 400;
+ repaint();
+ }
- public void
- mouseEntered(MouseEvent eM) { }
+ public void
+ mouseEntered(MouseEvent eM) { }
- public void
- mouseExited(MouseEvent eM) { }
+ public void
+ mouseExited(MouseEvent eM) { }
- public void
- mouseClicked(MouseEvent eM) { }
+ public void
+ mouseClicked(MouseEvent eM) { }
- public void
- mouseMoved(MouseEvent eM) { }
+ public void
+ mouseMoved(MouseEvent eM) { }
-// - -%- -
+// - -%- -
- private static ImageIcon
- toIcon(Image image)
- {
- if (image == null) return null;
- return new ImageIcon(image);
- }
+ private static ImageIcon
+ toIcon(Image image)
+ {
+ if (image == null) return null;
+ return new ImageIcon(image);
+ }
-// ---%-@-%---
+// ---%-@-%---
- private class
- Painter extends JPanel {
+ private class
+ Painter extends JPanel {
- protected void
- paintComponent(Graphics g)
- {
- if (image == null)
- {
- String str =
+ protected void
+ paintComponent(Graphics g)
+ {
+ if (image == null)
+ {
+ String str =
"(There are no images being displayed.)";
- FontMetrics fm = g.getFontMetrics();
- int x = (getWidth() - fm.stringWidth(str)) / 2;
- int y = (getHeight() + fm.getHeight()) / 2;
- g.drawString(str, x, y);
- return;
- }
- int wo = image.getWidth(this);
- int ho = image.getHeight(this);
- int wn, hn;
- if (wo > ho) {
- wn = scaleImage ? getWidth() : wo;
- hn = ho * wn / wo;
- }
- else {
- hn = scaleImage ? getHeight() : ho;
- wn = wo * hn / ho;
- }
- wn = wn * zoomLevel / 100;
- hn = hn * zoomLevel / 100;
- int x = (getWidth() - wn) / 2;
- int y = (getHeight() - hn) / 2;
- x += xOffset + xPOffset;
- y += yOffset + yPOffset;
- g.drawImage(image, x, y, wn, hn, this);
- }
+ FontMetrics fm = g.getFontMetrics();
+ int x = (getWidth() - fm.stringWidth(str)) / 2;
+ int y = (getHeight() + fm.getHeight()) / 2;
+ g.drawString(str, x, y);
+ return;
+ }
+ int wo = image.getWidth(this);
+ int ho = image.getHeight(this);
+ int wn, hn;
+ if (wo > ho) {
+ wn = scaleImage ? getWidth() : wo;
+ hn = ho * wn / wo;
+ }
+ else {
+ hn = scaleImage ? getHeight() : ho;
+ wn = wo * hn / ho;
+ }
+ wn = wn * zoomLevel / 100;
+ hn = hn * zoomLevel / 100;
+ int x = (getWidth() - wn) / 2;
+ int y = (getHeight() - hn) / 2;
+ x += xOffset + xPOffset;
+ y += yOffset + yPOffset;
+ g.drawImage(image, x, y, wn, hn, this);
+ }
- }
+ }
-// ---%-@-%---
+// ---%-@-%---
- ImageComponent(ImageWindow primaire)
- {
- this.primaire = primaire;
+ ImageComponent(ImageWindow primaire)
+ {
+ this.primaire = primaire;
- Dimension BUTTON_SIZE = new Dimension(48, 48);
+ Dimension BUTTON_SIZE = new Dimension(48, 48);
- setOpaque(false);
- scaleImage = true;
- zoomLevel = 100;
+ setOpaque(false);
+ scaleImage = true;
+ zoomLevel = 100;
- prev = new JButton();
- toggle = new JButton("Show unscaled");
- next = new JButton();
- prev.setPreferredSize(BUTTON_SIZE);
- next.setPreferredSize(BUTTON_SIZE);
- prev.addActionListener(this);
- toggle.addActionListener(this);
- next.addActionListener(this);
+ prev = new JButton();
+ toggle = new JButton("Show unscaled");
+ next = new JButton();
+ prev.setPreferredSize(BUTTON_SIZE);
+ next.setPreferredSize(BUTTON_SIZE);
+ prev.addActionListener(this);
+ toggle.addActionListener(this);
+ next.addActionListener(this);
- buttonArea = new JPanel();
- buttonArea.setOpaque(false);
- buttonArea.add(prev);
- buttonArea.add(toggle);
- buttonArea.add(next);
+ buttonArea = new JPanel();
+ buttonArea.setOpaque(false);
+ buttonArea.add(prev);
+ buttonArea.add(toggle);
+ buttonArea.add(next);
- setPrev(null);
- setNext(null);
+ setPrev(null);
+ setNext(null);
- setLayout(new BorderLayout());
- add(buttonArea, BorderLayout.SOUTH);
- add(new Painter(), BorderLayout.CENTER);
+ setLayout(new BorderLayout());
+ add(buttonArea, BorderLayout.SOUTH);
+ add(new Painter(), BorderLayout.CENTER);
- addMouseListener(this);
- addMouseMotionListener(this);
- addMouseWheelListener(this);
- }
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ addMouseWheelListener(this);
+ }
}
diff --git a/JKomasto.java b/JKomasto.java
index 8643ca8..74cce76 100644
--- a/JKomasto.java
+++ b/JKomasto.java
@@ -60,20 +60,20 @@ JKomasto {
private LoginWindow
loginWindow;
- private ImageWindow
- mediaWindow;
+ private ImageWindow
+ mediaWindow;
- private NotificationsWindow
- notificationsWindow;
+ private NotificationsWindow
+ notificationsWindow;
- private WindowUpdater
- windowUpdater;
+ private WindowUpdater
+ windowUpdater;
private MastodonApi
api;
- private Image
- programIcon;
+ private Image
+ programIcon;
// ---%-@-%---
@@ -85,10 +85,10 @@ JKomasto {
{
timelineWindow.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- timelineWindow.showLatestPage();
+ timelineWindow.showLatestPage();
notificationsWindow.showLatestPage();
timelineWindow.setVisible(true);
- loginWindow.dispose();
+ loginWindow.dispose();
timelineWindow.setCursor(null);
}
@@ -99,83 +99,83 @@ JKomasto {
public ComposeWindow
getComposeWindow() { return composeWindow; }
- public ImageWindow
+ public ImageWindow
getMediaWindow() { return mediaWindow; }
- public NotificationsWindow
+ public NotificationsWindow
getNotificationsWindow() { return notificationsWindow; }
public WindowUpdater
getWindowUpdater() { return windowUpdater; }
- public Image
- getProgramIcon() { return programIcon; }
+ public Image
+ getProgramIcon() { return programIcon; }
// ---%-@-%---
- private static class
- MetalTheme extends OceanTheme {
+ private static class
+ MetalTheme extends OceanTheme {
- private ColorUIResource
- lightPink = new ColorUIResource(246, 240, 240),
- mildPink = new ColorUIResource(238, 233, 233),
- white = new ColorUIResource(250, 250, 250),
- darkPink = new ColorUIResource(242, 230, 230),
- veryDarkPink = new ColorUIResource(164, 160, 160);
+ private ColorUIResource
+ lightPink = new ColorUIResource(246, 240, 240),
+ mildPink = new ColorUIResource(238, 233, 233),
+ white = new ColorUIResource(250, 250, 250),
+ darkPink = new ColorUIResource(242, 230, 230),
+ veryDarkPink = new ColorUIResource(164, 160, 160);
-// -=%=-
+// -=%=-
- public ColorUIResource
- getPrimary2() { return darkPink; }
+ public ColorUIResource
+ getPrimary2() { return darkPink; }
- public ColorUIResource
- getSecondary2() { return white; }
+ public ColorUIResource
+ getSecondary2() { return white; }
- public ColorUIResource
- getSecondary3() { return mildPink; }
+ public ColorUIResource
+ getSecondary3() { return mildPink; }
- public ColorUIResource
- getSecondary1() { return veryDarkPink; }
+ public ColorUIResource
+ getSecondary1() { return veryDarkPink; }
- public ColorUIResource
- getPrimary1() { return veryDarkPink; }
+ public ColorUIResource
+ getPrimary1() { return veryDarkPink; }
- public void
- addCustomEntriesToTable(UIDefaults table)
- {
- super.addCustomEntriesToTable(table);
- table.put(
- "TabbedPane.tabAreaBackground",
- getPrimary1()
- );
- table.put(
- "TabbedPane.contentAreaColor",
- getSecondary3()
- );
- table.put(
- "TabbedPane.selected",
- getSecondary3()
- );
- table.put(
- "MenuBar.gradient",
- java.util.Arrays.asList(new Object[] {
- 1f, 0f,
- getWhite(),
- getSecondary3(),
- getSecondary1()
- })
- );
- }
+ public void
+ addCustomEntriesToTable(UIDefaults table)
+ {
+ super.addCustomEntriesToTable(table);
+ table.put(
+ "TabbedPane.tabAreaBackground",
+ getPrimary1()
+ );
+ table.put(
+ "TabbedPane.contentAreaColor",
+ getSecondary3()
+ );
+ table.put(
+ "TabbedPane.selected",
+ getSecondary3()
+ );
+ table.put(
+ "MenuBar.gradient",
+ java.util.Arrays.asList(new Object[] {
+ 1f, 0f,
+ getWhite(),
+ getSecondary3(),
+ getSecondary1()
+ })
+ );
+ }
- }
+ }
// ---%-@-%---
public static void
main(String... args)
{
- //System.setProperty("swing.boldMetal", "false");
- MetalLookAndFeel.setCurrentTheme(new MetalTheme());
+ //System.setProperty("swing.boldMetal", "false");
+ MetalLookAndFeel.setCurrentTheme(new MetalTheme());
new JKomasto().loginWindow.setVisible(true);
}
@@ -187,24 +187,24 @@ JKomasto {
{
api = new MastodonApi();
windowUpdater = new WindowUpdater(this);
- programIcon = ImageApi.local("kettle");
+ programIcon = ImageApi.local("kettle");
timelineWindow = new TimelineWindow(this);
composeWindow = new ComposeWindow(this);
autoViewWindow = new PostWindow(this);
loginWindow = new LoginWindow(this);
- mediaWindow = new ImageWindow();
- notificationsWindow = new NotificationsWindow(this);
+ mediaWindow = new ImageWindow();
+ notificationsWindow = new NotificationsWindow(this);
autoViewWindow.setTitle("Auto view - JKomasto");
composeWindow.dispose();
autoViewWindow.dispose();
timelineWindow.dispose();
- mediaWindow.dispose();
- notificationsWindow.dispose();
+ mediaWindow.dispose();
+ notificationsWindow.dispose();
- timelineWindow.setLocationByPlatform(true);
+ timelineWindow.setLocationByPlatform(true);
loginWindow.setLocationByPlatform(true);
}
@@ -236,13 +236,13 @@ TimelineType {
enum
NotificationType {
- MENTION,
- BOOST,
- FAVOURITE,
- FOLLOW,
- FOLLOWREQ,
- POLL,
- ALERT
+ MENTION,
+ BOOST,
+ FAVOURITE,
+ FOLLOW,
+ FOLLOWREQ,
+ POLL,
+ ALERT
}
@@ -257,8 +257,8 @@ TimelinePage {
public String
accountNumId, listId;
- public Post[]
- posts;
+ public Post[]
+ posts;
// ---%-@-%---
@@ -279,14 +279,14 @@ TimelinePage {
class
Notification {
- public NotificationType
- type;
+ public NotificationType
+ type;
- public String
- id;
+ public String
+ id;
- public String
- postId, postText, actorNumId, actorName;
+ public String
+ postId, postText, actorNumId, actorName;
}
@@ -348,35 +348,35 @@ Post {
assert text != null;
if (approximateText != null) return;
- Tree nodes;
- nodes = RudimentaryHTMLParser.depthlessRead(text);
- if (nodes.size() == 0)
- {
+ Tree nodes;
+ nodes = RudimentaryHTMLParser.depthlessRead(text);
+ if (nodes.size() == 0)
+ {
approximateText = "-";
return;
}
StringBuilder b = new StringBuilder();
- Tree first = nodes.get(0);
- for (Tree node: nodes)
- {
- if (node.key.equals("tag"))
- {
- if (node.get(0).key.equals("br"))
- b.append("; ");
- if (node.get(0).key.equals("p") && node != first)
- b.append("; ");
- }
- if (node.key.equals("emoji"))
- {
- b.append(":" + node.value + ":");
- }
- if (node.key.equals("text"))
- {
- b.append(node.value);
- }
- }
- approximateText = b.toString();
+ Tree first = nodes.get(0);
+ for (Tree node: nodes)
+ {
+ if (node.key.equals("tag"))
+ {
+ if (node.get(0).key.equals("br"))
+ b.append("; ");
+ if (node.get(0).key.equals("p") && node != first)
+ b.append("; ");
+ }
+ if (node.key.equals("emoji"))
+ {
+ b.append(":" + node.value + ":");
+ }
+ if (node.key.equals("text"))
+ {
+ b.append(node.value);
+ }
+ }
+ approximateText = b.toString();
}
public void
@@ -402,57 +402,57 @@ Post {
public
Post(Tree entity)
{
- id = entity.get("id").value;
+ id = entity.get("id").value;
- uri = entity.get("url").value;
- if (uri == null) uri = entity.get("uri").value;
+ uri = entity.get("url").value;
+ if (uri == null) uri = entity.get("uri").value;
- author = new Account(entity.get("account"));
+ author = new Account(entity.get("account"));
- String v = entity.get("visibility").value;
- boolean p = v.equals("public");
- boolean u = v.equals("unlisted");
- boolean f = v.equals("private");
- boolean m = v.equals("direct");
- if (p) visibility = PostVisibility.PUBLIC;
- if (u) visibility = PostVisibility.UNLISTED;
- if (f) visibility = PostVisibility.FOLLOWERS;
- if (m) visibility = PostVisibility.MENTIONED;
+ String v = entity.get("visibility").value;
+ boolean p = v.equals("public");
+ boolean u = v.equals("unlisted");
+ boolean f = v.equals("private");
+ boolean m = v.equals("direct");
+ if (p) visibility = PostVisibility.PUBLIC;
+ if (u) visibility = PostVisibility.UNLISTED;
+ if (f) visibility = PostVisibility.FOLLOWERS;
+ if (m) visibility = PostVisibility.MENTIONED;
- dateTime =
+ dateTime =
ZonedDateTime.parse(entity.get("created_at").value)
.withZoneSameInstant(ZoneId.systemDefault());
- date = DATE_FORMAT.format(dateTime);
- time = TIME_FORMAT.format(dateTime);
+ date = DATE_FORMAT.format(dateTime);
+ time = TIME_FORMAT.format(dateTime);
- text = entity.get("content").value;
- String st = entity.get("spoiler_text").value;
- contentWarning = st.trim().isEmpty() ? null : st;
+ text = entity.get("content").value;
+ String st = entity.get("spoiler_text").value;
+ contentWarning = st.trim().isEmpty() ? null : st;
- String favourited = entity.get("favourited").value;
- String boosted = entity.get("reblogged").value;
- this.favourited = favourited.equals("true");
- this.boosted = boosted.equals("true");
+ String favourited = entity.get("favourited").value;
+ String boosted = entity.get("reblogged").value;
+ this.favourited = favourited.equals("true");
+ this.boosted = boosted.equals("true");
- Tree media = entity.get("media_attachments");
- attachments = new Attachment[media.size()];
- for (int o = 0; o < attachments.length; ++o)
- {
+ Tree media = entity.get("media_attachments");
+ attachments = new Attachment[media.size()];
+ for (int o = 0; o < attachments.length; ++o)
+ {
attachments[o] = new Attachment(media.get(o));
}
- Tree emojis = entity.get("emojis");
- emojiUrls = new String[emojis.size()][];
- for (int o = 0; o < emojiUrls.length; ++o)
- {
- Tree emoji = emojis.get(o);
- String[] mapping = emojiUrls[o] = new String[2];
- mapping[0] = ":" + emoji.get("shortcode").value + ":";
- mapping[1] = emoji.get("url").value;
- }
+ Tree emojis = entity.get("emojis");
+ emojiUrls = new String[emojis.size()][];
+ for (int o = 0; o < emojiUrls.length; ++o)
+ {
+ Tree emoji = emojis.get(o);
+ String[] mapping = emojiUrls[o] = new String[2];
+ mapping[0] = ":" + emoji.get("shortcode").value + ":";
+ mapping[1] = emoji.get("url").value;
+ }
Tree boostedPost = entity.get("reblog");
- if (boostedPost.size() > 0)
+ if (boostedPost.size() > 0)
this.boostedPost = new Post(boostedPost);
Tree mentions = entity.get("mentions");
@@ -508,7 +508,7 @@ Account {
resolveFormattedName()
{
assert name != null;
- formattedName =
+ formattedName =
new RichTextPane.Builder().text(name).finish();
}
@@ -531,27 +531,27 @@ Account {
numId = entity.get("id").value;
id = entity.get("acct").value;
- String displayName = entity.get("display_name").value;
- String username = entity.get("username").value;
- name = displayName.isEmpty() ? username : displayName;
+ String displayName = entity.get("display_name").value;
+ String username = entity.get("username").value;
+ name = displayName.isEmpty() ? username : displayName;
- avatarUrl = entity.get("avatar").value;
+ avatarUrl = entity.get("avatar").value;
- creationDate =
+ creationDate =
ZonedDateTime.parse(entity.get("created_at").value)
.withZoneSameInstant(ZoneId.systemDefault());
- String c1 = entity.get("following_count").value;
- String c2 = entity.get("followers_count").value;
- String c3 = entity.get("statuses_count").value;
- try {
+ String c1 = entity.get("following_count").value;
+ String c2 = entity.get("followers_count").value;
+ String c3 = entity.get("statuses_count").value;
+ try {
followedCount = (int)Double.parseDouble(c1);
followerCount = (int)Double.parseDouble(c2);
postCount = (int)Double.parseDouble(c3);
- }
- catch (NumberFormatException eNf) {
+ }
+ catch (NumberFormatException eNf) {
assert false;
- }
+ }
Tree fs = entity.get("fields");
fields = new String[fs.size()][];
@@ -577,20 +577,20 @@ Attachment {
public String
id;
- public String
- type;
+ public String
+ type;
- public String
- url;
+ public String
+ url;
- public String
- description;
+ public String
+ description;
- public Image
- image;
+ public Image
+ image;
- public File
- uploadee;
+ public File
+ uploadee;
// ---%-@-%---
@@ -639,8 +639,8 @@ Composition {
public Attachment[]
attachments;
- private File
- uploadee;
+ private File
+ uploadee;
// ---%-@-%---
@@ -653,33 +653,33 @@ Composition {
Composition c = new Composition();
Tree boosted = entity.get("reblog");
- if (boosted.size() > 0) entity = boosted;
+ if (boosted.size() > 0) entity = boosted;
- String st = entity.get("spoiler_text").value;
- String ri = entity.get("id").value;
- c.contentWarning = st.trim().isEmpty() ? null : st;
- c.replyToPostId = ri.trim().isEmpty() ? null : ri;
+ String st = entity.get("spoiler_text").value;
+ String ri = entity.get("id").value;
+ c.contentWarning = st.trim().isEmpty() ? null : st;
+ c.replyToPostId = ri.trim().isEmpty() ? null : ri;
- Tree author = entity.get("account");
- String authorId = author.get("acct").value;
- String authorNumId = author.get("id").value;
- c.text = "";
- if (!authorNumId.equals(ownNumId))
+ Tree author = entity.get("account");
+ String authorId = author.get("acct").value;
+ String authorNumId = author.get("id").value;
+ c.text = "";
+ if (!authorNumId.equals(ownNumId))
c.text = "@" + authorId + " ";
- String visibility = entity.get("visibility").value;
- boolean p = visibility.equals("public");
- boolean u = visibility.equals("unlisted");
- boolean f = visibility.equals("private");
- boolean m = visibility.equals("direct");
- assert p || u || f || m;
- if (p) c.visibility = PostVisibility.PUBLIC;
- if (u) c.visibility = PostVisibility.UNLISTED;
- if (f) c.visibility = PostVisibility.FOLLOWERS;
- if (m) c.visibility = PostVisibility.MENTIONED;
- // Less eye strain arranged this way.
+ String visibility = entity.get("visibility").value;
+ boolean p = visibility.equals("public");
+ boolean u = visibility.equals("unlisted");
+ boolean f = visibility.equals("private");
+ boolean m = visibility.equals("direct");
+ assert p || u || f || m;
+ if (p) c.visibility = PostVisibility.PUBLIC;
+ if (u) c.visibility = PostVisibility.UNLISTED;
+ if (f) c.visibility = PostVisibility.FOLLOWERS;
+ if (m) c.visibility = PostVisibility.MENTIONED;
+ // Less eye strain arranged this way.
- return c;
+ return c;
}
public static Composition
@@ -693,17 +693,17 @@ Composition {
c.replyToPostId = entity.get("in_reply_to_id").value;
String visibility = entity.get("visibility").value;
- boolean p = visibility.equals("public");
- boolean u = visibility.equals("unlisted");
- boolean f = visibility.equals("private");
- boolean m = visibility.equals("direct");
- assert p || u || f || m;
- if (p) c.visibility = PostVisibility.PUBLIC;
- if (u) c.visibility = PostVisibility.UNLISTED;
- if (f) c.visibility = PostVisibility.FOLLOWERS;
- if (m) c.visibility = PostVisibility.MENTIONED;
+ boolean p = visibility.equals("public");
+ boolean u = visibility.equals("unlisted");
+ boolean f = visibility.equals("private");
+ boolean m = visibility.equals("direct");
+ assert p || u || f || m;
+ if (p) c.visibility = PostVisibility.PUBLIC;
+ if (u) c.visibility = PostVisibility.UNLISTED;
+ if (f) c.visibility = PostVisibility.FOLLOWERS;
+ if (m) c.visibility = PostVisibility.MENTIONED;
- return c;
+ return c;
}
public static Composition
@@ -712,9 +712,9 @@ Composition {
if (post.boostedPost != null) post = post.boostedPost;
Composition c = new Composition();
- c.replyToPostId = post.id;
+ c.replyToPostId = post.id;
c.visibility = post.visibility;
- c.contentWarning = post.contentWarning;
+ c.contentWarning = post.contentWarning;
StringBuilder text = new StringBuilder();
for (String id: post.mentions)
diff --git a/JKomasto2.jar b/JKomasto2.jar
index e693933..0519244 100644
Binary files a/JKomasto2.jar and b/JKomasto2.jar differ
diff --git a/LoginWindow.java b/LoginWindow.java
index 008ca89..483e83f 100644
--- a/LoginWindow.java
+++ b/LoginWindow.java
@@ -50,8 +50,8 @@ LoginWindow extends JFrame {
private JKomasto
primaire;
- private MastodonApi
- api;
+ private MastodonApi
+ api;
// - -%- -
@@ -62,7 +62,7 @@ LoginWindow extends JFrame {
serverContacted = false,
haveAppCredentials = false,
haveAccessToken = false,
- haveAccountDetails = false;
+ haveAccountDetails = false;
// ---%-@-%---
@@ -81,325 +81,325 @@ LoginWindow extends JFrame {
b.append(prefix4 + " Have account details\n");
display.setText(b.toString());
- display.paintImmediately(display.getBounds(null));
+ display.paintImmediately(display.getBounds(null));
}
- public void
- useCache()
- {
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- try
- {
- api.loadCache();
- haveAppCredentials = true;
- haveAccessToken = true;
- display.setInstanceUrl(api.getInstanceUrl());
- updateStatusDisplay();
- }
- catch (IOException eIo)
- {
- JOptionPane.showMessageDialog(
- this,
- "We couldn't get login details from the cache.."
- + "\n" + eIo.getClass() + ": " + eIo.getMessage()
- );
- display.setAutoLoginToggled(false);
- }
- display.setCursor(null);
- if (!haveAccessToken) return;
+ public void
+ useCache()
+ {
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ try
+ {
+ api.loadCache();
+ haveAppCredentials = true;
+ haveAccessToken = true;
+ display.setInstanceUrl(api.getInstanceUrl());
+ updateStatusDisplay();
+ }
+ catch (IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
+ this,
+ "We couldn't get login details from the cache.."
+ + "\n" + eIo.getClass() + ": " + eIo.getMessage()
+ );
+ display.setAutoLoginToggled(false);
+ }
+ display.setCursor(null);
+ if (!haveAccessToken) return;
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- api.getAccountDetails(new RequestListener() {
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ api.getAccountDetails(new RequestListener() {
- public void
- connectionFailed(IOException eIo)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to get account details, failed.."
- + "\n" + eIo.getMessage()
- );
- }
+ public void
+ connectionFailed(IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to get account details, failed.."
+ + "\n" + eIo.getMessage()
+ );
+ }
- public void
- requestFailed(int httpCode, Tree json)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to get account details, failed.."
- + "\n" + json.get("error").value
- + "\n(HTTP error code: " + httpCode + ")"
- );
- }
+ public void
+ requestFailed(int httpCode, Tree json)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to get account details, failed.."
+ + "\n" + json.get("error").value
+ + "\n(HTTP error code: " + httpCode + ")"
+ );
+ }
- public void
- requestSucceeded(Tree json)
- {
- api.setAccountDetails(json);
- serverContacted = true;
- haveAccountDetails = true;
- updateStatusDisplay();
- }
+ public void
+ requestSucceeded(Tree json)
+ {
+ api.setAccountDetails(json);
+ serverContacted = true;
+ haveAccountDetails = true;
+ updateStatusDisplay();
+ }
- });
- display.setCursor(null);
- if (!haveAccountDetails) return;
+ });
+ display.setCursor(null);
+ if (!haveAccountDetails) return;
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- try
- {
- api.saveToCache();
- }
- catch (IOException eIo)
- {
- JOptionPane.showMessageDialog(
- this,
- "We couldn't save login details into the cache.."
- + "\n" + eIo.getClass() + ": " + eIo.getMessage()
- );
- }
- display.setCursor(null);
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ try
+ {
+ api.saveToCache();
+ }
+ catch (IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
+ this,
+ "We couldn't save login details into the cache.."
+ + "\n" + eIo.getClass() + ": " + eIo.getMessage()
+ );
+ }
+ display.setCursor(null);
- primaire.finishedLogin();
- }
+ primaire.finishedLogin();
+ }
- public void
+ public void
useInstanceUrl()
{
if (display.isAutoLoginToggled()) { useCache(); return; }
- String url = display.getInstanceUrl();
- if (url.trim().isEmpty()) {
+ String url = display.getInstanceUrl();
+ if (url.trim().isEmpty()) {
// Should we show an error dialog..?
display.setInstanceUrl("");
return;
- }
- if (!hasProtocol(url)) {
- url = "https://" + url;
- display.setInstanceUrl(url);
- display.paintImmediately(display.getBounds(null));
- }
- serverContacted = false;
- haveAppCredentials = false;
- haveAccessToken = false;
- haveAccountDetails = false;
+ }
+ if (!hasProtocol(url)) {
+ url = "https://" + url;
+ display.setInstanceUrl(url);
+ display.paintImmediately(display.getBounds(null));
+ }
+ serverContacted = false;
+ haveAppCredentials = false;
+ haveAccessToken = false;
+ haveAccountDetails = false;
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- api.testUrlConnection(url, new RequestListener() {
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ api.testUrlConnection(url, new RequestListener() {
- public void
- connectionFailed(IOException eIo)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to connect to URL, failed.."
- + "\n" + eIo.getClass() + ": " + eIo.getMessage()
- );
- }
+ public void
+ connectionFailed(IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to connect to URL, failed.."
+ + "\n" + eIo.getClass() + ": " + eIo.getMessage()
+ );
+ }
- public void
- requestFailed(int httpCode, Tree response)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to connect to URL, failed.."
- + "\n" + response.get("body").value
- );
- }
+ public void
+ requestFailed(int httpCode, Tree response)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to connect to URL, failed.."
+ + "\n" + response.get("body").value
+ );
+ }
- public void
- requestSucceeded(Tree response)
- {
- serverContacted = true;
- updateStatusDisplay();
- }
+ public void
+ requestSucceeded(Tree response)
+ {
+ serverContacted = true;
+ updateStatusDisplay();
+ }
- });
- display.setCursor(null);
+ });
+ display.setCursor(null);
if (!serverContacted) return;
- api.setInstanceUrl(url);
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- api.getAppCredentials(new RequestListener() {
+ api.setInstanceUrl(url);
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ api.getAppCredentials(new RequestListener() {
- public void
- connectionFailed(IOException eIo)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to get app credentials, failed.."
- + "\n" + eIo.getMessage()
- );
- }
+ public void
+ connectionFailed(IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to get app credentials, failed.."
+ + "\n" + eIo.getMessage()
+ );
+ }
- public void
- requestFailed(int httpCode, Tree json)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to get app credentials, failed.."
- + "\n" + json.get("error").value
- + "\n(HTTP error code: " + httpCode + ")"
- );
- }
+ public void
+ requestFailed(int httpCode, Tree json)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to get app credentials, failed.."
+ + "\n" + json.get("error").value
+ + "\n(HTTP error code: " + httpCode + ")"
+ );
+ }
- public void
- requestSucceeded(Tree json)
- {
- api.setAppCredentials(json);
- haveAppCredentials = true;
- updateStatusDisplay();
- }
+ public void
+ requestSucceeded(Tree json)
+ {
+ api.setAppCredentials(json);
+ haveAppCredentials = true;
+ updateStatusDisplay();
+ }
- });
- display.setCursor(null);
+ });
+ display.setCursor(null);
if (!haveAppCredentials) return;
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- URI uri = api.getAuthorisationURL();
+ URI uri = api.getAuthorisationURL();
- final String MESSAGE1 =
+ final String MESSAGE1 =
"We will need you to login through a web browser,\n"
+ "and they will give you an authorisation code\n"
+ "that you will paste here. Sorry..!";
- boolean supported =
- Desktop.isDesktopSupported()
- && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE);
- if (supported)
- {
- JOptionPane.showMessageDialog(
+ boolean supported =
+ Desktop.isDesktopSupported()
+ && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE);
+ if (supported)
+ {
+ JOptionPane.showMessageDialog(
LoginWindow.this,
MESSAGE1,
"Authorisation code renewal",
JOptionPane.INFORMATION_MESSAGE
);
- try { Desktop.getDesktop().browse(uri); }
- catch (IOException eIo) { supported = false; }
- }
- if (!supported)
- {
- final String MESSAGE2 =
- "\nWe cannot use Desktop.browse(URI) on your\n"
- + "computer.. You'll have to open your web\n"
- + "browser yourself, and copy this URL in.";
+ try { Desktop.getDesktop().browse(uri); }
+ catch (IOException eIo) { supported = false; }
+ }
+ if (!supported)
+ {
+ final String MESSAGE2 =
+ "\nWe cannot use Desktop.browse(URI) on your\n"
+ + "computer.. You'll have to open your web\n"
+ + "browser yourself, and copy this URL in.";
- JTextField field = new JTextField();
- field.setText(uri.toString());
- field.setPreferredSize(new Dimension(120, 32));
- field.selectAll();
+ JTextField field = new JTextField();
+ field.setText(uri.toString());
+ field.setPreferredSize(new Dimension(120, 32));
+ field.selectAll();
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- new Object[] { MESSAGE1, MESSAGE2, field },
- "Authorisation code renewal",
- JOptionPane.INFORMATION_MESSAGE
- );
- }
- display.receiveAuthorisationCode();
- display.setCursor(null);
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ new Object[] { MESSAGE1, MESSAGE2, field },
+ "Authorisation code renewal",
+ JOptionPane.INFORMATION_MESSAGE
+ );
+ }
+ display.receiveAuthorisationCode();
+ display.setCursor(null);
}
- public void
- useAuthorisationCode()
- {
- String code = display.getAuthorisationCode();
+ public void
+ useAuthorisationCode()
+ {
+ String code = display.getAuthorisationCode();
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- api.getAccessToken(code, new RequestListener() {
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ api.getAccessToken(code, new RequestListener() {
- public void
- connectionFailed(IOException eIo)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to get app token, failed.."
- + "\n" + eIo.getMessage()
- );
- }
+ public void
+ connectionFailed(IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to get app token, failed.."
+ + "\n" + eIo.getMessage()
+ );
+ }
- public void
- requestFailed(int httpCode, Tree json)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to get app token, failed.."
- + "\n" + json.get("error").value
- + "\n(HTTP error code: " + httpCode + ")"
- );
- }
+ public void
+ requestFailed(int httpCode, Tree json)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to get app token, failed.."
+ + "\n" + json.get("error").value
+ + "\n(HTTP error code: " + httpCode + ")"
+ );
+ }
- public void
- requestSucceeded(Tree json)
- {
- api.setAccessToken(json);
- haveAccessToken = true;
- updateStatusDisplay();
- }
+ public void
+ requestSucceeded(Tree json)
+ {
+ api.setAccessToken(json);
+ haveAccessToken = true;
+ updateStatusDisplay();
+ }
- });
- display.setCursor(null);
- if (!haveAccessToken) return;
+ });
+ display.setCursor(null);
+ if (!haveAccessToken) return;
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- api.getAccountDetails(new RequestListener() {
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ api.getAccountDetails(new RequestListener() {
- public void
- connectionFailed(IOException eIo)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to get account details, failed.."
- + "\n" + eIo.getMessage()
- );
- }
+ public void
+ connectionFailed(IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to get account details, failed.."
+ + "\n" + eIo.getMessage()
+ );
+ }
- public void
- requestFailed(int httpCode, Tree json)
- {
- JOptionPane.showMessageDialog(
- LoginWindow.this,
- "Tried to get account details, failed.."
- + "\n" + json.get("error").value
- + "\n(HTTP error code: " + httpCode + ")"
- );
- }
+ public void
+ requestFailed(int httpCode, Tree json)
+ {
+ JOptionPane.showMessageDialog(
+ LoginWindow.this,
+ "Tried to get account details, failed.."
+ + "\n" + json.get("error").value
+ + "\n(HTTP error code: " + httpCode + ")"
+ );
+ }
- public void
- requestSucceeded(Tree json)
- {
- api.setAccountDetails(json);
- haveAccountDetails = true;
- updateStatusDisplay();
- }
+ public void
+ requestSucceeded(Tree json)
+ {
+ api.setAccountDetails(json);
+ haveAccountDetails = true;
+ updateStatusDisplay();
+ }
- });
- display.setCursor(null);
- if (!haveAccountDetails) return;
+ });
+ display.setCursor(null);
+ if (!haveAccountDetails) return;
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- try
- {
- api.saveToCache();
- }
- catch (IOException eIo)
- {
- JOptionPane.showMessageDialog(
- this,
- "We couldn't save login details into the cache.."
- + "\n" + eIo.getClass() + ": " + eIo.getMessage()
- );
- }
- display.setCursor(null);
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ try
+ {
+ api.saveToCache();
+ }
+ catch (IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
+ this,
+ "We couldn't save login details into the cache.."
+ + "\n" + eIo.getClass() + ": " + eIo.getMessage()
+ );
+ }
+ display.setCursor(null);
- primaire.finishedLogin();
- }
+ primaire.finishedLogin();
+ }
-// - -%- -
+// - -%- -
- public static boolean
- hasProtocol(String url) { return url.matches("^.+://.*"); }
+ public static boolean
+ hasProtocol(String url) { return url.matches("^.+://.*"); }
// ---%-@-%---
@@ -407,7 +407,7 @@ LoginWindow extends JFrame {
{
super("JKomasto - Login");
this.primaire = primaire;
- this.api = primaire.getMastodonApi();
+ this.api = primaire.getMastodonApi();
setLocationByPlatform(true);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
@@ -419,7 +419,7 @@ LoginWindow extends JFrame {
setContentPane(display);
pack();
- setIconImage(primaire.getProgramIcon());
+ setIconImage(primaire.getProgramIcon());
}
}
@@ -451,7 +451,7 @@ implements ActionListener {
private JPanel
labelArea,
forField,
- accountsPanel;
+ accountsPanel;
private JCheckBox
autoLoginToggle;
@@ -482,11 +482,11 @@ implements ActionListener {
statusDisplay.setText(status);
}
- public void
- setAutoLoginToggled(boolean a) { autoLoginToggle.setSelected(a); }
+ public void
+ setAutoLoginToggled(boolean a) { autoLoginToggle.setSelected(a); }
- public boolean
- isAutoLoginToggled() { return autoLoginToggle.isSelected(); }
+ public boolean
+ isAutoLoginToggled() { return autoLoginToggle.isSelected(); }
public void
actionPerformed(ActionEvent eA)
@@ -502,11 +502,11 @@ implements ActionListener {
{
labelArea.remove(authorisationCodeLabel);
forField.remove(authorisationCodeButton);
- accountsPanel.remove(authorisationCodeField);
+ accountsPanel.remove(authorisationCodeField);
labelArea.add(instanceUrlLabel, BorderLayout.NORTH);
forField.add(instanceUrlButton, BorderLayout.EAST);
- accountsPanel.add(instanceUrlField);
- revalidate();
+ accountsPanel.add(instanceUrlField);
+ revalidate();
}
public void
@@ -514,11 +514,11 @@ implements ActionListener {
{
labelArea.remove(instanceUrlLabel);
forField.remove(instanceUrlButton);
- accountsPanel.remove(instanceUrlField);
+ accountsPanel.remove(instanceUrlField);
labelArea.add(authorisationCodeLabel, BorderLayout.NORTH);
forField.add(authorisationCodeButton, BorderLayout.EAST);
- accountsPanel.add(authorisationCodeField);
- revalidate();
+ accountsPanel.add(authorisationCodeField);
+ revalidate();
}
// ---%-@-%---
@@ -595,7 +595,7 @@ implements ActionListener {
statusDisplay.setBorder(bi);
statusDisplay.setFont(f2);
- receiveInstanceUrl();
+ receiveInstanceUrl();
setLayout(new BorderLayout(0, 8));
add(accountsPanel, BorderLayout.NORTH);
diff --git a/MastodonApi.java b/MastodonApi.java
index d660bc0..e56da4b 100644
--- a/MastodonApi.java
+++ b/MastodonApi.java
@@ -295,7 +295,7 @@ MastodonApi {
submit(
String text, PostVisibility visibility,
String replyTo, String contentWarning,
- String[] mediaIDs,
+ String[] mediaIDs,
RequestListener handler)
{
String token = accessToken.get("access_token").value;
@@ -320,7 +320,7 @@ MastodonApi {
HttpURLConnection conn = cast(endpoint.openConnection());
String s1 = "Bearer " + token;
conn.setRequestProperty("Authorization", s1);
- String s2 = Integer.toString(handler.hashCode());
+ String s2 = Integer.toString(handler.hashCode());
conn.setRequestProperty("Idempotency-Key", s2);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
@@ -335,9 +335,9 @@ MastodonApi {
if (contentWarning != null) {
output.write("&spoiler_text=" + contentWarning);
}
- for (String mediaID: mediaIDs) {
- output.write("&media_ids[]=" + mediaID);
- }
+ for (String mediaID: mediaIDs) {
+ output.write("&media_ids[]=" + mediaID);
+ }
output.close();
@@ -457,77 +457,77 @@ MastodonApi {
uploadFile(File file, String alt, RequestListener handler)
{
assert file != null;
- assert alt != null;
+ assert alt != null;
assert file.canRead();
String bct =
- "multipart/form-data; "
- + "boundary=\"JKomastoFileUpload\"";
- String fsb = "--JKomastoFileUpload\r\n";
- String feb = "\r\n--JKomastoFileUpload--\r\n";
- String fcd =
- "Content-Disposition: form-data; "
- + "name=\"file\"; "
- + "filename=\"" + file.getName() + "\"\r\n";
- String fct = "Content-Type: image/png\r\n\r\n";
- int contentLength = 0;
- contentLength += fsb.length();
- contentLength += feb.length();
- contentLength += fcd.length();
- contentLength += fct.length();
- contentLength += file.length();
- /*
- * (知) This was an absurdity to debug. Contrary to
- * cURL, Java sets default values for some headers,
- * some of which are restricted, meaning you can't
- * arbitrarily change them. Content-Length is one
- * of them, set to 2^14-1 bytes. I'm pretty sure
- * the file I was uploading was under this, but
- * anyways one of the two parties was stopping me
- * from finishing transferring my form data.
- *
- * They didn't mention this in the Javadocs.
- * I noticed HttpURLConnection#setChunkedStreamingMode
- * and #setFixedLengthStreamingMode by accident.
- * Turns out, the latter is how I do what cURL and
- * Firefox are doing - precalculate the exact size
- * of the body and set the content length to it.
- * Unfortunately, this is not flexible, we have to
- * be exact. Thankfully, my answers pass..
- *
- * On the other side, Mastodon is obtuse as usual.
- * They had code that basically throws a generic 500
- * upon any sort of error from their library[1]. What
- * problem the library had with my requests, I could
- * never know. There is an undocumented requirement
- * that you must put a filename in the content
- * disposition. That one I found by guessing.
- *
- * I solved this with the help of -Djavax.net.debug,
- * which revealed to me how my headers and body
- * differed from cURL and Firefox. If this issue
- * happens again, I advise giving up.
- *
- * [1] app/controllers/api/v1/media_controller.rb
- * #create. 3 March 2022
- */
+ "multipart/form-data; "
+ + "boundary=\"JKomastoFileUpload\"";
+ String fsb = "--JKomastoFileUpload\r\n";
+ String feb = "\r\n--JKomastoFileUpload--\r\n";
+ String fcd =
+ "Content-Disposition: form-data; "
+ + "name=\"file\"; "
+ + "filename=\"" + file.getName() + "\"\r\n";
+ String fct = "Content-Type: image/png\r\n\r\n";
+ int contentLength = 0;
+ contentLength += fsb.length();
+ contentLength += feb.length();
+ contentLength += fcd.length();
+ contentLength += fct.length();
+ contentLength += file.length();
+ /*
+ * (知) This was an absurdity to debug. Contrary to
+ * cURL, Java sets default values for some headers,
+ * some of which are restricted, meaning you can't
+ * arbitrarily change them. Content-Length is one
+ * of them, set to 2^14-1 bytes. I'm pretty sure
+ * the file I was uploading was under this, but
+ * anyways one of the two parties was stopping me
+ * from finishing transferring my form data.
+ *
+ * They didn't mention this in the Javadocs.
+ * I noticed HttpURLConnection#setChunkedStreamingMode
+ * and #setFixedLengthStreamingMode by accident.
+ * Turns out, the latter is how I do what cURL and
+ * Firefox are doing - precalculate the exact size
+ * of the body and set the content length to it.
+ * Unfortunately, this is not flexible, we have to
+ * be exact. Thankfully, my answers pass..
+ *
+ * On the other side, Mastodon is obtuse as usual.
+ * They had code that basically throws a generic 500
+ * upon any sort of error from their library[1]. What
+ * problem the library had with my requests, I could
+ * never know. There is an undocumented requirement
+ * that you must put a filename in the content
+ * disposition. That one I found by guessing.
+ *
+ * I solved this with the help of -Djavax.net.debug,
+ * which revealed to me how my headers and body
+ * differed from cURL and Firefox. If this issue
+ * happens again, I advise giving up.
+ *
+ * [1] app/controllers/api/v1/media_controller.rb
+ * #create. 3 March 2022
+ */
- String token = accessToken.get("access_token").value;
+ String token = accessToken.get("access_token").value;
String url = instanceUrl + "/api/v1/media/";
try
{
- String s1 = "?description=" + encode(alt);
+ String s1 = "?description=" + encode(alt);
- URL endpoint = new URL(url + s1);
+ URL endpoint = new URL(url + s1);
HttpURLConnection conn = cast(endpoint.openConnection());
String s2 = "Bearer " + token;
conn.setRequestProperty("Authorization", s2);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
- conn.setFixedLengthStreamingMode(contentLength);
- conn.setRequestProperty("Content-Type", bct);
- conn.setRequestProperty("Accept", "*/*");
- conn.connect();
+ conn.setFixedLengthStreamingMode(contentLength);
+ conn.setRequestProperty("Content-Type", bct);
+ conn.setRequestProperty("Accept", "*/*");
+ conn.connect();
OutputStream ostream = conn.getOutputStream();
InputStream istream = new FileInputStream(file);
@@ -536,12 +536,12 @@ MastodonApi {
ostream.write(fcd.getBytes());
ostream.write(fct.getBytes());
- int c; while ((c = istream.read()) != -1)
- ostream.write(c);
+ int c; while ((c = istream.read()) != -1)
+ ostream.write(c);
ostream.write(feb.getBytes());
- istream.close();
- ostream.close();
+ istream.close();
+ ostream.close();
doStandardJsonReturn(conn, handler);
}
@@ -550,7 +550,7 @@ MastodonApi {
public void
monitorTimeline(
- TimelineType type, ServerSideEventsListener handler)
+ TimelineType type, ServerSideEventsListener handler)
{
String token = accessToken.get("access_token").value;
@@ -584,7 +584,7 @@ MastodonApi {
conn.setReadTimeout(500);
Reader input = ireader(conn.getInputStream());
BufferedReader br = new BufferedReader(input);
- Thread thread = Thread.currentThread();
+ Thread thread = Thread.currentThread();
while (true) try
{
String line = br.readLine();
@@ -629,7 +629,7 @@ MastodonApi {
int code = conn.getResponseCode();
if (code >= 300)
{
- Reader input = ireader(conn.getErrorStream());
+ Reader input = ireader(conn.getErrorStream());
Tree response = fromPlain(input);
input.close();
handler.requestFailed(code, response);
@@ -663,13 +663,13 @@ MastodonApi {
// - -%- -
- private static String
- deescape(String string)
- {
- if (string == null) return string;
- string = string.replaceAll("\n", "\\\\n");
- return string;
- }
+ private static String
+ deescape(String string)
+ {
+ if (string == null) return string;
+ string = string.replaceAll("\n", "\\\\n");
+ return string;
+ }
private static Tree
fromPlain(Reader r)
@@ -699,27 +699,27 @@ MastodonApi {
}
}
- private static HttpURLConnection
- cast(URLConnection conn)
- {
- return (HttpURLConnection)conn;
- }
+ private static HttpURLConnection
+ cast(URLConnection conn)
+ {
+ return (HttpURLConnection)conn;
+ }
- private static InputStreamReader
- ireader(InputStream is)
- throws IOException
- {
- assert is != null;
- return new InputStreamReader(is);
- }
+ private static InputStreamReader
+ ireader(InputStream is)
+ throws IOException
+ {
+ assert is != null;
+ return new InputStreamReader(is);
+ }
- private static OutputStreamWriter
- owriter(OutputStream os)
- throws IOException
- {
- assert os != null;
- return new OutputStreamWriter(os);
- }
+ private static OutputStreamWriter
+ owriter(OutputStream os)
+ throws IOException
+ {
+ assert os != null;
+ return new OutputStreamWriter(os);
+ }
// ---%-@-%---
diff --git a/NotificationsWindow.java b/NotificationsWindow.java
index 0465c67..37bc9d0 100644
--- a/NotificationsWindow.java
+++ b/NotificationsWindow.java
@@ -48,80 +48,80 @@ import java.awt.event.ComponentEvent;
class
NotificationsWindow extends JFrame {
- private JKomasto
- primaire;
+ private JKomasto
+ primaire;
- private List
- notifications;
+ private List
+ notifications;
- private MastodonApi
- api;
+ private MastodonApi
+ api;
-// - -%- -
+// - -%- -
- private NotificationsComponent
- display;
+ private NotificationsComponent
+ display;
- private boolean
- showingLatest;
+ private boolean
+ showingLatest;
-// - -%- -
+// - -%- -
- private static int
- ROW_COUNT = NotificationsComponent.ROW_COUNT;
+ private static int
+ ROW_COUNT = NotificationsComponent.ROW_COUNT;
-// ---%-@-%---
+// ---%-@-%---
- public synchronized void
- readEntity(Tree entity)
- {
- notifications = new ArrayList<>();
- for (Tree t: entity)
- {
- Notification n = new Notification();
+ public synchronized void
+ readEntity(Tree entity)
+ {
+ notifications = new ArrayList<>();
+ for (Tree t: entity)
+ {
+ Notification n = new Notification();
- n.id = t.get("id").value;
+ n.id = t.get("id").value;
- String type = t.get("type").value;
- if (type.equals("favourite"))
- n.type = NotificationType.FAVOURITE;
- else if (type.equals("reblog"))
- n.type = NotificationType.BOOST;
- else if (type.equals("mention"))
- n.type = NotificationType.MENTION;
- else if (type.equals("follow"))
- n.type = NotificationType.FOLLOW;
- else if (type.equals("follow_request"))
- n.type = NotificationType.FOLLOWREQ;
- else if (type.equals("poll"))
- n.type = NotificationType.POLL;
- else if (type.equals("status"))
- n.type = NotificationType.ALERT;
+ String type = t.get("type").value;
+ if (type.equals("favourite"))
+ n.type = NotificationType.FAVOURITE;
+ else if (type.equals("reblog"))
+ n.type = NotificationType.BOOST;
+ else if (type.equals("mention"))
+ n.type = NotificationType.MENTION;
+ else if (type.equals("follow"))
+ n.type = NotificationType.FOLLOW;
+ else if (type.equals("follow_request"))
+ n.type = NotificationType.FOLLOWREQ;
+ else if (type.equals("poll"))
+ n.type = NotificationType.POLL;
+ else if (type.equals("status"))
+ n.type = NotificationType.ALERT;
- Tree actor = t.get("account");
- String aid, aname, adisp;
- aid = actor.get("id").value;
- aname = actor.get("username").value;
- adisp = actor.get("display_name").value;
- if (!adisp.isEmpty()) n.actorName = adisp;
- else n.actorName = aname;
- n.actorNumId = aid;
+ Tree actor = t.get("account");
+ String aid, aname, adisp;
+ aid = actor.get("id").value;
+ aname = actor.get("username").value;
+ adisp = actor.get("display_name").value;
+ if (!adisp.isEmpty()) n.actorName = adisp;
+ else n.actorName = aname;
+ n.actorNumId = aid;
- if (n.type != NotificationType.FOLLOW)
- {
+ if (n.type != NotificationType.FOLLOW)
+ {
Post post = new Post(t.get("status"));
- post.resolveApproximateText();
- n.postId = post.id;
- n.postText = post.approximateText;
- }
+ post.resolveApproximateText();
+ n.postId = post.id;
+ n.postText = post.approximateText;
+ }
- notifications.add(n);
- }
- }
+ notifications.add(n);
+ }
+ }
- public void
- refresh()
- {
+ public void
+ refresh()
+ {
String firstId = null;
if (!showingLatest)
{
@@ -134,53 +134,53 @@ NotificationsWindow extends JFrame {
if (notifications.size() < ROW_COUNT) showLatestPage();
display.showNotifications(notifications);
display.repaint();
- }
- }
+ }
+ }
- public void
- showLatestPage()
- {
- if (fetchPage(null, null))
- {
+ public void
+ showLatestPage()
+ {
+ if (fetchPage(null, null))
+ {
display.showNotifications(notifications);
showingLatest = true;
primaire.getWindowUpdater().add(this);
}
- }
+ }
- public void
- showPrevPage()
- {
- assert !notifications.isEmpty();
- if (fetchPage(null, notifications.get(0).id))
- {
+ public void
+ showPrevPage()
+ {
+ assert !notifications.isEmpty();
+ if (fetchPage(null, notifications.get(0).id))
+ {
if (notifications.size() < ROW_COUNT) showLatestPage();
display.showNotifications(notifications);
showingLatest = false;
primaire.getWindowUpdater().remove(this);
- }
- }
+ }
+ }
- public void
- showNextPage()
- {
- assert !notifications.isEmpty();
- int last = notifications.size() - 1;
+ public void
+ showNextPage()
+ {
+ assert !notifications.isEmpty();
+ int last = notifications.size() - 1;
if (fetchPage(notifications.get(last).id, null))
{
display.showNotifications(notifications);
showingLatest = false;
primaire.getWindowUpdater().remove(this);
- }
- }
+ }
+ }
-// - -%- -
+// - -%- -
- private boolean
- fetchPage(String maxId, String minId)
- {
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- class Handler implements RequestListener {
+ private boolean
+ fetchPage(String maxId, String minId)
+ {
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ class Handler implements RequestListener {
boolean
succeeded = false;
@@ -207,31 +207,31 @@ NotificationsWindow extends JFrame {
}
}
Handler handler = new Handler();
- api.getNotifications(ROW_COUNT, maxId, minId, handler);
- display.setCursor(null);
- repaint();
- return handler.succeeded;
- }
+ api.getNotifications(ROW_COUNT, maxId, minId, handler);
+ display.setCursor(null);
+ repaint();
+ return handler.succeeded;
+ }
-// ---%-@-%---
+// ---%-@-%---
- NotificationsWindow(JKomasto primaire)
- {
- super("Notifications");
- this.primaire = primaire;
- this.api = primaire.getMastodonApi();
+ NotificationsWindow(JKomasto primaire)
+ {
+ super("Notifications");
+ this.primaire = primaire;
+ this.api = primaire.getMastodonApi();
- notifications = new ArrayList<>();
+ notifications = new ArrayList<>();
- display = new NotificationsComponent(this);
- display.setPreferredSize(new Dimension(256, 260));
- setContentPane(display);
- pack();
+ display = new NotificationsComponent(this);
+ display.setPreferredSize(new Dimension(256, 260));
+ setContentPane(display);
+ pack();
- setIconImage(primaire.getProgramIcon());
- setDefaultCloseOperation(DISPOSE_ON_CLOSE);
- setVisible(true);
- }
+ setIconImage(primaire.getProgramIcon());
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+ setVisible(true);
+ }
}
@@ -239,88 +239,88 @@ class
NotificationsComponent extends JPanel
implements ActionListener {
- private NotificationsWindow
- primaire;
+ private NotificationsWindow
+ primaire;
- private JButton
- prev, next;
+ private JButton
+ prev, next;
-// - -%- -
+// - -%- -
- private List
- rows;
+ private List
+ rows;
-// - -%- -
+// - -%- -
- static final int
- ROW_COUNT = 10;
+ static final int
+ ROW_COUNT = 10;
-// ---%-@-%---
+// ---%-@-%---
- public void
- showNotifications(List notifications)
- {
- assert notifications.size() == rows.size();
- for (int o = 0; o < rows.size(); ++o)
- {
- Notification n = notifications.get(o);
- NotificationComponent c = rows.get(o);
- c.setName(n.actorName);
- switch (n.type)
- {
- case MENTION: c.setType("mentioned"); break;
- case BOOST: c.setType("boosted"); break;
- case FAVOURITE: c.setType("favourited"); break;
- case FOLLOW: c.setType("followed"); break;
- case FOLLOWREQ: c.setType("req. follow"); break;
- case POLL: c.setType("poll ended"); break;
- case ALERT: c.setType("posted"); break;
- }
- c.setText(n.postText);
- }
- }
+ public void
+ showNotifications(List notifications)
+ {
+ assert notifications.size() == rows.size();
+ for (int o = 0; o < rows.size(); ++o)
+ {
+ Notification n = notifications.get(o);
+ NotificationComponent c = rows.get(o);
+ c.setName(n.actorName);
+ switch (n.type)
+ {
+ case MENTION: c.setType("mentioned"); break;
+ case BOOST: c.setType("boosted"); break;
+ case FAVOURITE: c.setType("favourited"); break;
+ case FOLLOW: c.setType("followed"); break;
+ case FOLLOWREQ: c.setType("req. follow"); break;
+ case POLL: c.setType("poll ended"); break;
+ case ALERT: c.setType("posted"); break;
+ }
+ c.setText(n.postText);
+ }
+ }
-// - -%- -
+// - -%- -
- public void
- actionPerformed(ActionEvent eA)
- {
- if (eA.getSource() == prev) primaire.showPrevPage();
- if (eA.getSource() == next) primaire.showNextPage();
- }
+ public void
+ actionPerformed(ActionEvent eA)
+ {
+ if (eA.getSource() == prev) primaire.showPrevPage();
+ if (eA.getSource() == next) primaire.showNextPage();
+ }
-// ---%-@-%---
+// ---%-@-%---
- NotificationsComponent(NotificationsWindow primaire)
- {
- this.primaire = primaire;
+ NotificationsComponent(NotificationsWindow primaire)
+ {
+ this.primaire = primaire;
- Border b = BorderFactory.createEmptyBorder(8, 8, 8, 8);
+ Border b = BorderFactory.createEmptyBorder(8, 8, 8, 8);
- rows = new ArrayList<>();
- for (int n = ROW_COUNT; n > 0; --n)
- rows.add(new NotificationComponent());
+ rows = new ArrayList<>();
+ for (int n = ROW_COUNT; n > 0; --n)
+ rows.add(new NotificationComponent());
- prev = new JButton("<");
- next = new JButton(">");
- prev.addActionListener(this);
- next.addActionListener(this);
+ prev = new JButton("<");
+ next = new JButton(">");
+ prev.addActionListener(this);
+ next.addActionListener(this);
- JPanel centre = new JPanel();
- centre.setLayout(new GridLayout(ROW_COUNT, 1));
- for (NotificationComponent c: rows) centre.add(c);
+ JPanel centre = new JPanel();
+ centre.setLayout(new GridLayout(ROW_COUNT, 1));
+ for (NotificationComponent c: rows) centre.add(c);
- Box bottom = Box.createHorizontalBox();
- bottom.add(Box.createGlue());
- bottom.add(prev);
- bottom.add(Box.createHorizontalStrut(8));
- bottom.add(next);
- bottom.setBorder(b);
+ Box bottom = Box.createHorizontalBox();
+ bottom.add(Box.createGlue());
+ bottom.add(prev);
+ bottom.add(Box.createHorizontalStrut(8));
+ bottom.add(next);
+ bottom.setBorder(b);
- setLayout(new BorderLayout());
- add(centre);
- add(bottom, BorderLayout.SOUTH);
- }
+ setLayout(new BorderLayout());
+ add(centre);
+ add(bottom, BorderLayout.SOUTH);
+ }
}
@@ -328,145 +328,145 @@ class
NotificationComponent extends JComponent
implements ComponentListener {
- private JLabel
- type;
+ private JLabel
+ type;
- private ImageComponent
- typeImg;
+ private ImageComponent
+ typeImg;
- private JLabel
- name, text;
+ private JLabel
+ name, text;
-// ---%-@-%---
+// ---%-@-%---
- public void
- setType(String n)
- {
- type.setText(n);
- typeImg.image = ImageApi.local(n + "Notification");
- }
+ public void
+ setType(String n)
+ {
+ type.setText(n);
+ typeImg.image = ImageApi.local(n + "Notification");
+ }
- public void
- setName(String n) { name.setText(n); }
+ public void
+ setName(String n) { name.setText(n); }
- public void
- setText(String n) { text.setText(n); }
+ public void
+ setText(String n) { text.setText(n); }
-// - -%- -
+// - -%- -
- public void
- doLayout()
- {
- int w = getWidth(), h = getHeight();
+ public void
+ doLayout()
+ {
+ int w = getWidth(), h = getHeight();
- int x0 = w * 0/20;
- int x1 = w * 7/20;
- int x2 = w * 13/20;
- int x3 = w * 15/20;
- int x4 = w * 20/20;
+ int x0 = w * 0/20;
+ int x1 = w * 7/20;
+ int x2 = w * 13/20;
+ int x3 = w * 15/20;
+ int x4 = w * 20/20;
- name.setLocation(x0 + 4, 0);
- name.setSize((x1 - 4) - (x0 + 4), h);
+ name.setLocation(x0 + 4, 0);
+ name.setSize((x1 - 4) - (x0 + 4), h);
- type.setLocation(x1 + 4, 0);
- type.setSize((x2 - 1) - (x1 + 4), h);
+ type.setLocation(x1 + 4, 0);
+ type.setSize((x2 - 1) - (x1 + 4), h);
- typeImg.setLocation((x2 + 1), 2);
- typeImg.setSize((x3 - 4) - (x2 + 1), (h - 2) - 2);
+ typeImg.setLocation((x2 + 1), 2);
+ typeImg.setSize((x3 - 4) - (x2 + 1), (h - 2) - 2);
- text.setLocation(x3 + 4, 0);
- text.setSize((x4 - 4) - (x3 + 4), h);
- }
+ text.setLocation(x3 + 4, 0);
+ text.setSize((x4 - 4) - (x3 + 4), h);
+ }
- public void
- componentResized(ComponentEvent eC) { doLayout(); }
+ public void
+ componentResized(ComponentEvent eC) { doLayout(); }
- public void
- componentShown(ComponentEvent eC) { }
+ public void
+ componentShown(ComponentEvent eC) { }
- public void
- componentHidden(ComponentEvent eC) { }
+ public void
+ componentHidden(ComponentEvent eC) { }
- public void
- componentMoved(ComponentEvent eC) { }
+ public void
+ componentMoved(ComponentEvent eC) { }
-// ---%-@-%---
+// ---%-@-%---
- private static class
- ImageComponent extends JComponent {
+ private static class
+ ImageComponent extends JComponent {
- private Image
- image,
- scaled;
+ private Image
+ image,
+ scaled;
- private boolean
- snapdown = false;
+ private boolean
+ snapdown = false;
-// -=%=-
+// -=%=-
- protected void
- paintComponent(Graphics g)
- {
- if (image == null) return;
- int w = getWidth(), h = getHeight();
+ protected void
+ paintComponent(Graphics g)
+ {
+ if (image == null) return;
+ int w = getWidth(), h = getHeight();
- int ow = image.getWidth(this);
- int oh = image.getHeight(this);
- int nh = h;
- int nw = ow * nh/oh;
- if (snapdown)
- {
- int sw, sh;
- for (sw = 1; sw < nw; sw *= 2);
- for (sh = 1; sh < nh; sh *= 2);
- nw = sw / 2;
- nh = sh / 2;
- }
+ int ow = image.getWidth(this);
+ int oh = image.getHeight(this);
+ int nh = h;
+ int nw = ow * nh/oh;
+ if (snapdown)
+ {
+ int sw, sh;
+ for (sw = 1; sw < nw; sw *= 2);
+ for (sh = 1; sh < nh; sh *= 2);
+ nw = sw / 2;
+ nh = sh / 2;
+ }
- if (scaled == null)
- scaled = image.getScaledInstance(
- nw, nh,
- Image.SCALE_SMOOTH
- );
- int x = (w - nw) / 2;
- int y = (h - nh) / 2;
- g.drawImage(scaled, x, y, this);
- }
+ if (scaled == null)
+ scaled = image.getScaledInstance(
+ nw, nh,
+ Image.SCALE_SMOOTH
+ );
+ int x = (w - nw) / 2;
+ int y = (h - nh) / 2;
+ g.drawImage(scaled, x, y, this);
+ }
- }
+ }
-// ---%-@-%---
+// ---%-@-%---
- NotificationComponent()
- {
- Font f = new Font("Dialog", Font.PLAIN, 12);
- Font f1 = f.deriveFont(Font.PLAIN, 14);
- Font f2 = f.deriveFont(Font.PLAIN, 11);
- Font f3 = f.deriveFont(Font.ITALIC, 14);
+ NotificationComponent()
+ {
+ Font f = new Font("Dialog", Font.PLAIN, 12);
+ Font f1 = f.deriveFont(Font.PLAIN, 14);
+ Font f2 = f.deriveFont(Font.PLAIN, 11);
+ Font f3 = f.deriveFont(Font.ITALIC, 14);
- Color c = new Color(0, 0, 0, 25);
- Border b1 = BorderFactory.createMatteBorder(0, 0, 1, 0, c);
+ Color c = new Color(0, 0, 0, 25);
+ Border b1 = BorderFactory.createMatteBorder(0, 0, 1, 0, c);
- name = new JLabel();
- name.setFont(f1);
+ name = new JLabel();
+ name.setFont(f1);
- type = new JLabel();
- type.setFont(f2);
- type.setHorizontalAlignment(JLabel.RIGHT);
+ type = new JLabel();
+ type.setFont(f2);
+ type.setHorizontalAlignment(JLabel.RIGHT);
- typeImg = new ImageComponent();
+ typeImg = new ImageComponent();
- text = new JLabel();
- text.setFont(f3);
+ text = new JLabel();
+ text.setFont(f3);
- setLayout(null);
- add(name);
- add(type);
- add(typeImg);
- add(text);
+ setLayout(null);
+ add(name);
+ add(type);
+ add(typeImg);
+ add(text);
- this.addComponentListener(this);
- setBorder(b1);
- }
+ this.addComponentListener(this);
+ setBorder(b1);
+ }
}
diff --git a/PostWindow.java b/PostWindow.java
index ce30b2e..3114c15 100644
--- a/PostWindow.java
+++ b/PostWindow.java
@@ -74,9 +74,9 @@ PostWindow extends JFrame {
private MastodonApi
api;
- private Post
- post,
- wrapperPost;
+ private Post
+ post,
+ wrapperPost;
// - -%- -
@@ -109,21 +109,21 @@ PostWindow extends JFrame {
}
display.setAuthorName(post.author.name);
- display.setAuthorId(post.author.id);
+ display.setAuthorId(post.author.id);
- String oid = api.getAccountDetails().get("id").value;
- String aid = post.author.numId;
- display.setDeleteEnabled(aid.equals(oid));
+ String oid = api.getAccountDetails().get("id").value;
+ String aid = post.author.numId;
+ display.setDeleteEnabled(aid.equals(oid));
- post.author.resolveAvatar();
- display.setAuthorAvatar(post.author.avatar);
+ post.author.resolveAvatar();
+ display.setAuthorAvatar(post.author.avatar);
display.setDate(post.date);
display.setTime(post.time);
- display.setEmojiUrls(post.emojiUrls);
+ display.setEmojiUrls(post.emojiUrls);
- display.setHtml(post.text);
+ display.setHtml(post.text);
display.setFavourited(post.favourited);
display.setBoosted(post.boosted);
@@ -137,29 +137,29 @@ PostWindow extends JFrame {
post.resolveApproximateText();
this.setTitle(post.approximateText);
- display.resetFocus();
+ display.resetFocus();
repaint();
}
- public void
- readEntity(Tree post)
- {
+ public void
+ readEntity(Tree post)
+ {
use(new Post(post));
}
public synchronized void
openAuthorProfile()
{
- ProfileWindow w = new ProfileWindow(primaire);
- w.use(post.author);
- w.setLocationRelativeTo(this);
- w.setVisible(true);
+ ProfileWindow w = new ProfileWindow(primaire);
+ w.use(post.author);
+ w.setLocationRelativeTo(this);
+ w.setVisible(true);
}
public synchronized void
favourite(boolean favourited)
{
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
display.setFavouriteBoostEnabled(false);
display.paintImmediately(display.getBounds());
RequestListener handler = new RequestListener() {
@@ -188,11 +188,11 @@ PostWindow extends JFrame {
public void
requestSucceeded(Tree json)
{
- PostWindow.this.post.favourited = favourited;
+ PostWindow.this.post.favourited = favourited;
}
};
- api.setPostFavourited(post.id, favourited, handler);
+ api.setPostFavourited(post.id, favourited, handler);
display.setCursor(null);
display.setFavouriteBoostEnabled(true);
display.repaint();
@@ -234,7 +234,7 @@ PostWindow extends JFrame {
}
};
- api.setPostBoosted(post.id, boosted, handler);
+ api.setPostBoosted(post.id, boosted, handler);
display.setCursor(null);
display.setFavouriteBoostEnabled(true);
display.repaint();
@@ -246,9 +246,9 @@ PostWindow extends JFrame {
String ownId = api.getAccountDetails().get("acct").value;
Composition c = Composition.reply(this.post, ownId);
ComposeWindow w = primaire.getComposeWindow();
- w.setComposition(c);
- if (!w.isVisible())
- {
+ w.setComposition(c);
+ if (!w.isVisible())
+ {
w.setLocation(getX(), getY() + 100);
w.setVisible(true);
}
@@ -271,62 +271,62 @@ PostWindow extends JFrame {
display.setCursor(null);
}
- public synchronized void
- deletePost(boolean redraft)
- {
- display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- display.setDeleteEnabled(false);
- display.paintImmediately(display.getBounds());
+ public synchronized void
+ deletePost(boolean redraft)
+ {
+ display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ display.setDeleteEnabled(false);
+ display.paintImmediately(display.getBounds());
- final String S1 =
+ final String S1 =
"Are you sure you'd like to delete this post?\n";
final String S2 =
"Are you sure you'd like to delete this post?\n"
+ "You are redrafting, so a composition window\n"
+ "should open with its contents filled.";
- JOptionPane dialog = new JOptionPane();
- dialog.setMessageType(JOptionPane.QUESTION_MESSAGE);
- dialog.setMessage(redraft ? S2 : S1);
- dialog.setOptions(new String[] { "No", "Yes" });
- String title = "Confirm delete";
- dialog.createDialog(this, title).setVisible(true);
- if (!dialog.getValue().equals("Yes"))
- {
+ JOptionPane dialog = new JOptionPane();
+ dialog.setMessageType(JOptionPane.QUESTION_MESSAGE);
+ dialog.setMessage(redraft ? S2 : S1);
+ dialog.setOptions(new String[] { "No", "Yes" });
+ String title = "Confirm delete";
+ dialog.createDialog(this, title).setVisible(true);
+ if (!dialog.getValue().equals("Yes"))
+ {
display.setCursor(null);
display.setDeleteEnabled(true);
display.paintImmediately(display.getBounds());
return;
- }
+ }
- api.deletePost(post.id, new RequestListener() {
+ api.deletePost(post.id, new RequestListener() {
- public void
- connectionFailed(IOException eIo)
- {
- JOptionPane.showMessageDialog(
- PostWindow.this,
- "Failed to delete post.."
- + "\n" + eIo.getMessage()
- );
- }
+ public void
+ connectionFailed(IOException eIo)
+ {
+ JOptionPane.showMessageDialog(
+ PostWindow.this,
+ "Failed to delete post.."
+ + "\n" + eIo.getMessage()
+ );
+ }
- public void
- requestFailed(int httpCode, Tree json)
- {
- JOptionPane.showMessageDialog(
- PostWindow.this,
- "Failed to delete post.."
- + "\n" + json.get("error").value
- + "\n(HTTP code: " + httpCode + ")"
- );
- }
+ public void
+ requestFailed(int httpCode, Tree json)
+ {
+ JOptionPane.showMessageDialog(
+ PostWindow.this,
+ "Failed to delete post.."
+ + "\n" + json.get("error").value
+ + "\n(HTTP code: " + httpCode + ")"
+ );
+ }
- public void
- requestSucceeded(Tree json)
- {
- setVisible(false);
+ public void
+ requestSucceeded(Tree json)
+ {
+ setVisible(false);
- if (redraft)
+ if (redraft)
{
Composition c = Composition.recover(json);
ComposeWindow w = new ComposeWindow(primaire);
@@ -334,36 +334,36 @@ PostWindow extends JFrame {
w.setLocation(getX(), getY() + 100);
w.setVisible(true);
}
- }
+ }
- });
+ });
- display.setCursor(null);
- display.setDeleteEnabled(true);
- display.paintImmediately(display.getBounds());
- if (!isVisible()) dispose();
- }
+ display.setCursor(null);
+ display.setDeleteEnabled(true);
+ display.paintImmediately(display.getBounds());
+ if (!isVisible()) dispose();
+ }
- public synchronized void
- copyPostId()
- {
+ public synchronized void
+ copyPostId()
+ {
ClipboardApi.serve(post.id);
- }
+ }
- public synchronized void
- copyPostLink()
- {
+ public synchronized void
+ copyPostLink()
+ {
ClipboardApi.serve(post.uri);
- }
+ }
- public synchronized void
- openReplies()
- {
+ public synchronized void
+ openReplies()
+ {
RepliesWindow w = new RepliesWindow(primaire, this);
w.showFor(post.id);
w.setLocation(getX(), getY() + 100);
w.setVisible(true);
- }
+ }
// ---%-@-%---
@@ -380,7 +380,7 @@ PostWindow extends JFrame {
display = new PostComponent(this);
setContentPane(display);
- setIconImage(primaire.getProgramIcon());
+ setIconImage(primaire.getProgramIcon());
}
}
@@ -396,23 +396,23 @@ implements ActionListener {
// - -%- -
- private List
- authorNameOr;
+ private List
+ authorNameOr;
- private RichTextPane
- authorName;
+ private RichTextPane
+ authorName;
- private RichTextPane3
- body;
+ private RichTextPane3
+ body;
- private JScrollPane
- bodyScrollPane;
+ private JScrollPane
+ bodyScrollPane;
- private JLabel
- authorId, time, date;
+ private JLabel
+ authorId, time, date;
- private String[][]
- emojiUrls;
+ private String[][]
+ emojiUrls;
private TwoToggleButton
favouriteBoost,
@@ -423,32 +423,32 @@ implements ActionListener {
profile,
media;
- private JPopupMenu
- miscMenu;
+ private JPopupMenu
+ miscMenu;
- private JMenuItem
- openReplies,
- copyPostId,
- copyPostLink,
- deletePost,
- redraftPost;
+ private JMenuItem
+ openReplies,
+ copyPostId,
+ copyPostLink,
+ deletePost,
+ redraftPost;
- private Image
- backgroundImage;
+ private Image
+ backgroundImage;
// ---%-@-%---
public void
setAuthorName(String n)
- {
- authorNameOr = new RichTextPane.Builder().text(n).finish();
- }
+ {
+ authorNameOr = new RichTextPane.Builder().text(n).finish();
+ }
public void
setAuthorId(String n) { authorId.setText(n); }
- public void
- setAuthorAvatar(Image n) { profile.setImage(n); }
+ public void
+ setAuthorAvatar(Image n) { profile.setImage(n); }
public void
setDate(String n) { date.setText(n); }
@@ -456,24 +456,24 @@ implements ActionListener {
public void
setTime(String n) { time.setText(n); }
- public void
- setEmojiUrls(String[][] n)
- {
+ public void
+ setEmojiUrls(String[][] n)
+ {
emojiUrls = n;
- Map emojis = new HashMap<>();
- for (String[] entry: n)
- {
- emojis.put(entry[0], ImageApi.remote(entry[1]));
- }
- body.setEmojis(emojis);
+ Map emojis = new HashMap<>();
+ for (String[] entry: n)
+ {
+ emojis.put(entry[0], ImageApi.remote(entry[1]));
+ }
+ body.setEmojis(emojis);
}
- public void
- setHtml(String n)
- {
+ public void
+ setHtml(String n)
+ {
body.setText(BasicHTMLParser.parse(n));
- }
+ }
public void
setFavourited(boolean a)
@@ -497,19 +497,19 @@ implements ActionListener {
favouriteBoost.setEnabled(a);
}
- public void
- setDeleteEnabled(boolean a)
- {
- deletePost.setEnabled(a);
- redraftPost.setEnabled(a);
- }
+ public void
+ setDeleteEnabled(boolean a)
+ {
+ deletePost.setEnabled(a);
+ redraftPost.setEnabled(a);
+ }
- public void
- setMediaPreview(Image n) { media.setImage(n); }
+ public void
+ setMediaPreview(Image n) { media.setImage(n); }
- public void
- resetFocus()
- {
+ public void
+ resetFocus()
+ {
media.requestFocusInWindow();
}
@@ -551,14 +551,14 @@ implements ActionListener {
}
else if (command.startsWith("reply"))
{
- primaire.reply();
+ primaire.reply();
+ }
+ else if (command.startsWith("misc"))
+ {
+ int rx = replyMisc.getWidth() / 2;
+ int ry = replyMisc.getHeight() - miscMenu.getHeight();
+ miscMenu.show(replyMisc, rx, ry);
}
- else if (command.startsWith("misc"))
- {
- int rx = replyMisc.getWidth() / 2;
- int ry = replyMisc.getHeight() - miscMenu.getHeight();
- miscMenu.show(replyMisc, rx, ry);
- }
return;
}
else miscMenu.setVisible(false);
@@ -567,14 +567,14 @@ implements ActionListener {
{
if (command.startsWith("next"))
{
- body.nextPage();
+ body.nextPage();
}
else
{
- body.previousPage();
+ body.previousPage();
}
- // First time an interactive element
- // doesn't call something in primaire..
+ // First time an interactive element
+ // doesn't call something in primaire..
return;
}
@@ -582,13 +582,13 @@ implements ActionListener {
{
primaire.openMedia();
return;
- }
+ }
- if (src == openReplies) primaire.openReplies();
- if (src == copyPostId) primaire.copyPostId();
- if (src == copyPostLink) primaire.copyPostLink();
- if (src == deletePost) primaire.deletePost(false);
- if (src == redraftPost) primaire.deletePost(true);
+ if (src == openReplies) primaire.openReplies();
+ if (src == copyPostId) primaire.copyPostId();
+ if (src == copyPostLink) primaire.copyPostLink();
+ if (src == deletePost) primaire.deletePost(false);
+ if (src == redraftPost) primaire.deletePost(true);
}
@@ -597,28 +597,28 @@ implements ActionListener {
{
g.clearRect(0, 0, getWidth(), getHeight());
- int w1 = authorName.getWidth();
- FontMetrics fm1 = getFontMetrics(authorName.getFont());
- List lay1;
- lay1 = RichTextPane.layout(authorNameOr, fm1, w1);
- authorName.setText(lay1);
+ int w1 = authorName.getWidth();
+ FontMetrics fm1 = getFontMetrics(authorName.getFont());
+ List lay1;
+ lay1 = RichTextPane.layout(authorNameOr, fm1, w1);
+ authorName.setText(lay1);
- if (backgroundImage != null)
- {
- int tw = backgroundImage.getWidth(this);
- int th = backgroundImage.getHeight(this);
- if (tw != -1)
- for (int y = 0; y < getHeight(); y += th)
- for (int x = 0; x < getWidth(); x += tw)
- {
- g.drawImage(backgroundImage, x, y, this);
- }
- }
+ if (backgroundImage != null)
+ {
+ int tw = backgroundImage.getWidth(this);
+ int th = backgroundImage.getHeight(this);
+ if (tw != -1)
+ for (int y = 0; y < getHeight(); y += th)
+ for (int x = 0; x < getWidth(); x += tw)
+ {
+ g.drawImage(backgroundImage, x, y, this);
+ }
+ }
- ((java.awt.Graphics2D)g).setRenderingHint(
- java.awt.RenderingHints.KEY_ANTIALIASING,
- java.awt.RenderingHints.VALUE_ANTIALIAS_ON
- );
+ ((java.awt.Graphics2D)g).setRenderingHint(
+ java.awt.RenderingHints.KEY_ANTIALIASING,
+ java.awt.RenderingHints.VALUE_ANTIALIAS_ON
+ );
}
// - -%- -
@@ -648,18 +648,18 @@ implements ActionListener {
{
this.primaire = primaire;
- emojiUrls = new String[0][];
+ emojiUrls = new String[0][];
Border b = BorderFactory.createEmptyBorder(10, 10, 10, 10);
- Font f1 = new Font("MotoyaLMaru", Font.PLAIN, 18);
+ Font f1 = new Font("MotoyaLMaru", Font.PLAIN, 18);
Font f2 = new Font("MotoyaLMaru", Font.PLAIN, 14);
- Font f3 = new Font("MotoyaLMaru", Font.PLAIN, 18);
+ Font f3 = new Font("MotoyaLMaru", Font.PLAIN, 18);
profile = new RoundButton();
- favouriteBoost = new TwoToggleButton("favourite", "boost");
- replyMisc = new TwoToggleButton("reply", "misc");
- nextPrev = new TwoToggleButton("next", "prev");
- media = new RoundButton();
+ favouriteBoost = new TwoToggleButton("favourite", "boost");
+ replyMisc = new TwoToggleButton("reply", "misc");
+ nextPrev = new TwoToggleButton("next", "prev");
+ media = new RoundButton();
profile.addActionListener(this);
favouriteBoost.addActionListener(this);
replyMisc.addActionListener(this);
@@ -669,22 +669,22 @@ implements ActionListener {
openReplies = new JMenuItem("Browse thread");
copyPostId = new JMenuItem("Copy post ID");
copyPostLink = new JMenuItem("Copy post link");
- deletePost = new JMenuItem("Delete post");
- redraftPost = new JMenuItem("Delete and redraft post");
- openReplies.addActionListener(this);
- copyPostId.addActionListener(this);
- copyPostLink.addActionListener(this);
- deletePost.addActionListener(this);
- redraftPost.addActionListener(this);
- miscMenu = new JPopupMenu();
- miscMenu.add(openReplies);
- miscMenu.add(new JSeparator());
- miscMenu.add(copyPostId);
- miscMenu.add(copyPostLink);
- miscMenu.add(new JSeparator());
- miscMenu.add(deletePost);
- miscMenu.add(new JSeparator());
- miscMenu.add(redraftPost);
+ deletePost = new JMenuItem("Delete post");
+ redraftPost = new JMenuItem("Delete and redraft post");
+ openReplies.addActionListener(this);
+ copyPostId.addActionListener(this);
+ copyPostLink.addActionListener(this);
+ deletePost.addActionListener(this);
+ redraftPost.addActionListener(this);
+ miscMenu = new JPopupMenu();
+ miscMenu.add(openReplies);
+ miscMenu.add(new JSeparator());
+ miscMenu.add(copyPostId);
+ miscMenu.add(copyPostLink);
+ miscMenu.add(new JSeparator());
+ miscMenu.add(deletePost);
+ miscMenu.add(new JSeparator());
+ miscMenu.add(redraftPost);
Box buttons = Box.createVerticalBox();
buttons.setOpaque(false);
@@ -702,59 +702,59 @@ implements ActionListener {
left.setOpaque(false);
left.add(buttons);
- authorId = new JLabel();
- authorName = new RichTextPane();
- time = new JLabel();
- date = new JLabel();
- authorId.setFont(f2);
- date.setFont(f2);
- authorName.setFont(f1);
- time.setFont(f1);
+ authorId = new JLabel();
+ authorName = new RichTextPane();
+ time = new JLabel();
+ date = new JLabel();
+ authorId.setFont(f2);
+ date.setFont(f2);
+ authorName.setFont(f1);
+ time.setFont(f1);
- JPanel top1 = new JPanel();
- top1.setOpaque(false);
- top1.setLayout(new BorderLayout(8, 0));
- top1.add(authorId);
- top1.add(date, BorderLayout.EAST);
- JPanel top2 = new JPanel();
- top2.setOpaque(false);
- top2.setLayout(new BorderLayout(8, 0));
- top2.add(authorName);
- top2.add(time, BorderLayout.EAST);
- Box top = Box.createVerticalBox();
- top.add(top1);
- top.add(Box.createVerticalStrut(2));
- top.add(top2);
+ JPanel top1 = new JPanel();
+ top1.setOpaque(false);
+ top1.setLayout(new BorderLayout(8, 0));
+ top1.add(authorId);
+ top1.add(date, BorderLayout.EAST);
+ JPanel top2 = new JPanel();
+ top2.setOpaque(false);
+ top2.setLayout(new BorderLayout(8, 0));
+ top2.add(authorName);
+ top2.add(time, BorderLayout.EAST);
+ Box top = Box.createVerticalBox();
+ top.add(top1);
+ top.add(Box.createVerticalStrut(2));
+ top.add(top2);
- body = new RichTextPane3();
- body.setFont(f3);
+ body = new RichTextPane3();
+ body.setFont(f3);
- /*
- bodyScrollPane = new JScrollPane(
- body,
- JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
- JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
- );
- JScrollBar vsb = bodyScrollPane.getVerticalScrollBar();
- vsb.setPreferredSize(new Dimension(0, 0));
- vsb.setUnitIncrement(16);
- bodyScrollPane.setBorder(null);
- bodyScrollPane.setFocusable(true);
- */
+ /*
+ bodyScrollPane = new JScrollPane(
+ body,
+ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
+ );
+ JScrollBar vsb = bodyScrollPane.getVerticalScrollBar();
+ vsb.setPreferredSize(new Dimension(0, 0));
+ vsb.setUnitIncrement(16);
+ bodyScrollPane.setBorder(null);
+ bodyScrollPane.setFocusable(true);
+ */
- JPanel centre = new JPanel();
- centre.setOpaque(false);
- centre.setLayout(new BorderLayout(0, 8));
- centre.add(top, BorderLayout.NORTH);
- centre.add(body);
+ JPanel centre = new JPanel();
+ centre.setOpaque(false);
+ centre.setLayout(new BorderLayout(0, 8));
+ centre.add(top, BorderLayout.NORTH);
+ centre.add(body);
setLayout(new BorderLayout(8, 0));
add(left, BorderLayout.WEST);
- add(centre);
+ add(centre);
- setBorder(b);
+ setBorder(b);
- backgroundImage = ImageApi.local("postWindow");
+ backgroundImage = ImageApi.local("postWindow");
}
}
diff --git a/ProfileWindow.java b/ProfileWindow.java
index 5e560b7..47902d1 100644
--- a/ProfileWindow.java
+++ b/ProfileWindow.java
@@ -123,7 +123,7 @@ ProfileWindow extends JFrame {
{
display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
- TimelineWindow w = new TimelineWindow(primaire);
+ TimelineWindow w = new TimelineWindow(primaire);
w.showAuthorPosts(account.numId);
w.showLatestPage();
w.setLocationRelativeTo(this);
@@ -269,9 +269,9 @@ implements ActionListener {
int acx = ax + (aw / 2);
int acy = ay + (ah / 2);
Shape defaultClip = g.getClip();
- g.setClip(new Ellipse2D.Float(ax, ay, aw, ah));
+ g.setClip(new Ellipse2D.Float(ax, ay, aw, ah));
g.drawImage(avatar, ax, ay, aw, ah, this);
- g.setClip(defaultClip);
+ g.setClip(defaultClip);
g.setColor(new Color(0, 0, 0, 50));
g.fillRect(0, acy - dy1, acx - dx1, 2);
diff --git a/RepliesWindow.java b/RepliesWindow.java
index 2763e76..0a649e6 100644
--- a/RepliesWindow.java
+++ b/RepliesWindow.java
@@ -189,7 +189,7 @@ RepliesWindow extends JFrame {
setContentPane(display);
setSize(384, 224);
- setIconImage(primaire.getProgramIcon());
+ setIconImage(primaire.getProgramIcon());
}
}
@@ -242,13 +242,13 @@ implements TreeSelectionListener {
if (p == null)
{
assert false;
- /*
- * Besides descendants possibly not being in order,
- * the top of the thread might be deleted and so
- * thread.top gets set to the given post. Which
- * sibling replies aren't replying to, resulting
- * in assertion failure.
- */
+ /*
+ * Besides descendants possibly not being in order,
+ * the top of the thread might be deleted and so
+ * thread.top gets set to the given post. Which
+ * sibling replies aren't replying to, resulting
+ * in assertion failure.
+ */
continue;
}
@@ -257,8 +257,8 @@ implements TreeSelectionListener {
}
tree.setModel(new DefaultTreeModel(root));
- for (int o = 0; o < tree.getRowCount(); ++o)
- tree.expandRow(o);
+ for (int o = 0; o < tree.getRowCount(); ++o)
+ tree.expandRow(o);
}
// - -%- -
diff --git a/RequestListener.java b/RequestListener.java
index fe1f115..37f096b 100644
--- a/RequestListener.java
+++ b/RequestListener.java
@@ -24,14 +24,14 @@ import java.io.IOException;
interface
RequestListener {
- void
- connectionFailed(IOException eIo);
+ void
+ connectionFailed(IOException eIo);
- void
- requestFailed(int httpCode, Tree json);
+ void
+ requestFailed(int httpCode, Tree json);
- void
- requestSucceeded(Tree json);
+ void
+ requestSucceeded(Tree json);
}
diff --git a/RichTextPane.java b/RichTextPane.java
index 0f84d5d..20f0829 100644
--- a/RichTextPane.java
+++ b/RichTextPane.java
@@ -38,396 +38,396 @@ class
RichTextPane extends JComponent
implements MouseListener, MouseMotionListener, KeyListener {
- private List
- text;
+ private List
+ text;
- private int
- selectionStart, selectionEnd;
+ private int
+ selectionStart, selectionEnd;
-// ---%-@-%---
+// ---%-@-%---
- public void
- setText(List text)
- {
- this.text = text;
- selectionStart = selectionEnd = -1;
- }
+ public void
+ setText(List text)
+ {
+ this.text = text;
+ selectionStart = selectionEnd = -1;
+ }
- public List
- getSelection()
- {
- List returnee = new LinkedList<>();
- if (selectionEnd == -1) return returnee;
+ public List
+ getSelection()
+ {
+ List returnee = new LinkedList<>();
+ if (selectionEnd == -1) return returnee;
- if (selectionEnd < selectionStart) {
- int t = selectionEnd;
- selectionEnd = selectionStart;
- selectionStart = t;
- }
- returnee.addAll(text.subList(selectionStart + 1, selectionEnd));
- return returnee;
- }
+ if (selectionEnd < selectionStart) {
+ int t = selectionEnd;
+ selectionEnd = selectionStart;
+ selectionStart = t;
+ }
+ returnee.addAll(text.subList(selectionStart + 1, selectionEnd));
+ return returnee;
+ }
- public void
- copySelection()
- {
+ public void
+ copySelection()
+ {
assert selectionEnd != -1;
- StringBuilder b = new StringBuilder();
- for (Segment segment: getSelection())
- {
- if (segment.link != null) b.append(segment.link);
- else if (segment.text != null) b.append(segment.text);
- }
- ClipboardApi.serve(b.toString());
- }
+ StringBuilder b = new StringBuilder();
+ for (Segment segment: getSelection())
+ {
+ if (segment.link != null) b.append(segment.link);
+ else if (segment.text != null) b.append(segment.text);
+ }
+ ClipboardApi.serve(b.toString());
+ }
-// - -%- -
+// - -%- -
- protected void
- paintComponent(Graphics g)
- {
- g.setFont(getFont());
- FontMetrics fm = g.getFontMetrics(getFont());
+ protected void
+ paintComponent(Graphics g)
+ {
+ g.setFont(getFont());
+ FontMetrics fm = g.getFontMetrics(getFont());
- if (isOpaque())
- g.clearRect(0, 0, getWidth(), getHeight());
+ if (isOpaque())
+ g.clearRect(0, 0, getWidth(), getHeight());
- ((java.awt.Graphics2D)g).setRenderingHint(
- java.awt.RenderingHints.KEY_TEXT_ANTIALIASING,
- java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON
- );
+ ((java.awt.Graphics2D)g).setRenderingHint(
+ java.awt.RenderingHints.KEY_TEXT_ANTIALIASING,
+ java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON
+ );
- int o = 0;
- for (Segment segment: text)
- {
- if (segment.image != null) {
- int ow = segment.image.getIconWidth();
- int oh = segment.image.getIconHeight();
- int h = fm.getAscent() + fm.getDescent();
- int w = h * ow / oh;
- int x = segment.x;
- int y = segment.y + fm.getDescent();
- // Interpret segment.y as specifying text baseline
- Image img = segment.image.getImage();
- g.drawImage(img, x, y - h, w, h, this);
- continue;
- }
+ int o = 0;
+ for (Segment segment: text)
+ {
+ if (segment.image != null) {
+ int ow = segment.image.getIconWidth();
+ int oh = segment.image.getIconHeight();
+ int h = fm.getAscent() + fm.getDescent();
+ int w = h * ow / oh;
+ int x = segment.x;
+ int y = segment.y + fm.getDescent();
+ // Interpret segment.y as specifying text baseline
+ Image img = segment.image.getImage();
+ g.drawImage(img, x, y - h, w, h, this);
+ continue;
+ }
- if (o > selectionStart && o < selectionEnd)
- {
- int dx = fm.stringWidth(segment.text);
- int dy1 = fm.getAscent();
- int dy2 = dy1 + fm.getDescent();
- g.setColor(new Color(0, 0, 0, 15));
- g.fillRect(segment.x, segment.y - dy1, dx, dy2);
- g.setColor(getForeground());
- }
+ if (o > selectionStart && o < selectionEnd)
+ {
+ int dx = fm.stringWidth(segment.text);
+ int dy1 = fm.getAscent();
+ int dy2 = dy1 + fm.getDescent();
+ g.setColor(new Color(0, 0, 0, 15));
+ g.fillRect(segment.x, segment.y - dy1, dx, dy2);
+ g.setColor(getForeground());
+ }
- if (segment.link != null) g.setColor(Color.BLUE);
- g.drawString(segment.text, segment.x, segment.y);
- g.setColor(getForeground());
+ if (segment.link != null) g.setColor(Color.BLUE);
+ g.drawString(segment.text, segment.x, segment.y);
+ g.setColor(getForeground());
- ++o;
- }
- }
+ ++o;
+ }
+ }
- public void
- mousePressed(MouseEvent eM)
- {
- requestFocusInWindow();
- selectionStart = identify(eM.getX(), eM.getY()) - 2;
- selectionEnd = -1;
- repaint();
- }
+ public void
+ mousePressed(MouseEvent eM)
+ {
+ requestFocusInWindow();
+ selectionStart = identify(eM.getX(), eM.getY()) - 2;
+ selectionEnd = -1;
+ repaint();
+ }
- public void
- mouseDragged(MouseEvent eM)
- {
- selectionEnd = identify(eM.getX(), eM.getY());
- repaint();
- }
+ public void
+ mouseDragged(MouseEvent eM)
+ {
+ selectionEnd = identify(eM.getX(), eM.getY());
+ repaint();
+ }
- private int
- identify(int x, int y)
- {
- FontMetrics fm = getFontMetrics(getFont());
- int iy = fm.getAscent();
- int lh = fm.getAscent() + fm.getDescent();
- y -= fm.getDescent();
- if (y <= iy) y = iy;
- else y += lh - ((y - iy) % lh);
- /*
- * Snaps y to the next baseline. Kind of obtuse,
- * but it wasn't randomly derived, anyways
- * you can test it for 13, 30, 47, etc.
- */
+ private int
+ identify(int x, int y)
+ {
+ FontMetrics fm = getFontMetrics(getFont());
+ int iy = fm.getAscent();
+ int lh = fm.getAscent() + fm.getDescent();
+ y -= fm.getDescent();
+ if (y <= iy) y = iy;
+ else y += lh - ((y - iy) % lh);
+ /*
+ * Snaps y to the next baseline. Kind of obtuse,
+ * but it wasn't randomly derived, anyways
+ * you can test it for 13, 30, 47, etc.
+ */
- int o = 0;
- for (Segment segment: text)
- {
- if (segment.y == y && segment.x > x) break;
- if (segment.y > y) break;
- ++o;
- }
- return o;
- }
+ int o = 0;
+ for (Segment segment: text)
+ {
+ if (segment.y == y && segment.x > x) break;
+ if (segment.y > y) break;
+ ++o;
+ }
+ return o;
+ }
- public void
- keyPressed(KeyEvent eK)
- {
- if (selectionEnd == -1) return;
- if (eK.getKeyCode() != KeyEvent.VK_C) return;
- if (!eK.isControlDown()) return;
- copySelection();
- }
+ public void
+ keyPressed(KeyEvent eK)
+ {
+ if (selectionEnd == -1) return;
+ if (eK.getKeyCode() != KeyEvent.VK_C) return;
+ if (!eK.isControlDown()) return;
+ copySelection();
+ }
- public void
- keyReleased(KeyEvent eK) { }
+ public void
+ keyReleased(KeyEvent eK) { }
- public void
- keyTyped(KeyEvent eK) { }
+ public void
+ keyTyped(KeyEvent eK) { }
- public void
- mouseClicked(MouseEvent eM) { }
+ public void
+ mouseClicked(MouseEvent eM) { }
- public void
- mouseReleased(MouseEvent eM) { }
+ public void
+ mouseReleased(MouseEvent eM) { }
- public void
- mouseEntered(MouseEvent eM) { }
+ public void
+ mouseEntered(MouseEvent eM) { }
- public void
- mouseExited(MouseEvent eM) { }
+ public void
+ mouseExited(MouseEvent eM) { }
- public void
- mouseMoved(MouseEvent eM) { }
+ public void
+ mouseMoved(MouseEvent eM) { }
-// - -%- -
+// - -%- -
- public static List
- layout(List text, FontMetrics fm, int width)
- {
- List copy = new LinkedList<>();
- for (Segment segment: text) copy.add(segment.clone());
- text = copy;
- ListIterator cursor = text.listIterator();
- int x = 0, y = fm.getAscent();
- int dy = fm.getAscent() + fm.getDescent();
- while (cursor.hasNext())
- {
- Segment curr = cursor.next();
+ public static List
+ layout(List text, FontMetrics fm, int width)
+ {
+ List copy = new LinkedList<>();
+ for (Segment segment: text) copy.add(segment.clone());
+ text = copy;
+ ListIterator cursor = text.listIterator();
+ int x = 0, y = fm.getAscent();
+ int dy = fm.getAscent() + fm.getDescent();
+ while (cursor.hasNext())
+ {
+ Segment curr = cursor.next();
- int dx;
- if (curr.image != null) {
- int ow = curr.image.getIconWidth();
- int oh = curr.image.getIconHeight();
- int nh = fm.getAscent() + fm.getDescent();
- dx = nh * ow / oh;
- }
- else if (curr.text != null) {
- dx = fm.stringWidth(curr.text);
- }
- else if (curr.link != null) {
- curr.text = curr.link;
- dx = fm.stringWidth(curr.link);
- }
- else {
- assert false;
- dx = 0;
- }
+ int dx;
+ if (curr.image != null) {
+ int ow = curr.image.getIconWidth();
+ int oh = curr.image.getIconHeight();
+ int nh = fm.getAscent() + fm.getDescent();
+ dx = nh * ow / oh;
+ }
+ else if (curr.text != null) {
+ dx = fm.stringWidth(curr.text);
+ }
+ else if (curr.link != null) {
+ curr.text = curr.link;
+ dx = fm.stringWidth(curr.link);
+ }
+ else {
+ assert false;
+ dx = 0;
+ }
- boolean fits = x + dx < width;
+ boolean fits = x + dx < width;
- if (fits || curr.spacer)
- {
- curr.x = x;
- curr.y = y;
- x += dx;
- if (curr.spacer && curr.text.equals("\n")) {
- y += dy;
- x = 0;
- }
- continue;
- }
+ if (fits || curr.spacer)
+ {
+ curr.x = x;
+ curr.y = y;
+ x += dx;
+ if (curr.spacer && curr.text.equals("\n")) {
+ y += dy;
+ x = 0;
+ }
+ continue;
+ }
- boolean tooLong = dx > width;
- boolean canFitChar = width >= fm.getMaxAdvance();
- boolean splittable = curr.image == null;
- /*
- * A bit of redundancy in my conditions, but the point is
- * to exactly express the triggers in my mental model.
- * The conditions should read more like English.
- */
+ boolean tooLong = dx > width;
+ boolean canFitChar = width >= fm.getMaxAdvance();
+ boolean splittable = curr.image == null;
+ /*
+ * A bit of redundancy in my conditions, but the point is
+ * to exactly express the triggers in my mental model.
+ * The conditions should read more like English.
+ */
- if (!tooLong || (tooLong && !splittable))
- {
- curr.x = 0;
- curr.y = y += dy;
- x = dx;
- continue;
- }
+ if (!tooLong || (tooLong && !splittable))
+ {
+ curr.x = 0;
+ curr.y = y += dy;
+ x = dx;
+ continue;
+ }
- assert tooLong && splittable;
+ assert tooLong && splittable;
- String s = curr.text;
- int splitOffset;
- for (splitOffset = 0; splitOffset < s.length(); ++splitOffset)
- {
- String substring = s.substring(0, splitOffset + 1);
- if (fm.stringWidth(substring) > width) break;
- }
- if (splitOffset == 0) splitOffset = 1;
- /*
- * I force a split even if our width supports no characters.
- * Because if I don't split, the only alternatives to infinitely
- * looping downwards is to emplace this segment or ignore it.
- */
- Segment fitted = new Segment();
- fitted.text = s.substring(0, splitOffset);
- fitted.link = curr.link;
- fitted.x = x;
- fitted.y = y;
- cursor.add(fitted);
- curr.text = s.substring(splitOffset);
- y += dy;
- x = 0;
- cursor.add(curr); cursor.previous();
- /*
- * I had to use a stack and return a new list because,
- * splitting can turn a long segment into several spread
- * over different lines. Here curr becomes the "after-split"
- * and I push it back to the stack.
- *
- * If #layout wasn't a separate method, but rather only for
- * graphical painting. Then I don't need a stack nor return
- * a new list. I iterate over the given one, filling the
- * nodes' geometric information, if a split occurs I save the
- * "after-split" in a variable, which in the next iteration
- * I use as curr instead of list.next(). The caller doesn't
- * need to know the geometry of these intermediate segments.
- */
- continue;
- }
+ String s = curr.text;
+ int splitOffset;
+ for (splitOffset = 0; splitOffset < s.length(); ++splitOffset)
+ {
+ String substring = s.substring(0, splitOffset + 1);
+ if (fm.stringWidth(substring) > width) break;
+ }
+ if (splitOffset == 0) splitOffset = 1;
+ /*
+ * I force a split even if our width supports no characters.
+ * Because if I don't split, the only alternatives to infinitely
+ * looping downwards is to emplace this segment or ignore it.
+ */
+ Segment fitted = new Segment();
+ fitted.text = s.substring(0, splitOffset);
+ fitted.link = curr.link;
+ fitted.x = x;
+ fitted.y = y;
+ cursor.add(fitted);
+ curr.text = s.substring(splitOffset);
+ y += dy;
+ x = 0;
+ cursor.add(curr); cursor.previous();
+ /*
+ * I had to use a stack and return a new list because,
+ * splitting can turn a long segment into several spread
+ * over different lines. Here curr becomes the "after-split"
+ * and I push it back to the stack.
+ *
+ * If #layout wasn't a separate method, but rather only for
+ * graphical painting. Then I don't need a stack nor return
+ * a new list. I iterate over the given one, filling the
+ * nodes' geometric information, if a split occurs I save the
+ * "after-split" in a variable, which in the next iteration
+ * I use as curr instead of list.next(). The caller doesn't
+ * need to know the geometry of these intermediate segments.
+ */
+ continue;
+ }
- return text;
- }
+ return text;
+ }
-// ---%-@-%---
+// ---%-@-%---
- public static class
- Segment {
+ public static class
+ Segment {
- public ImageIcon
- image;
+ public ImageIcon
+ image;
- public String
- link;
+ public String
+ link;
- public String
- text;
+ public String
+ text;
- public boolean
- spacer;
+ public boolean
+ spacer;
- public int
- x, y;
+ public int
+ x, y;
-// -=%=-
+// -=%=-
- public String
- toString()
- {
- StringBuilder b = new StringBuilder();
- b.append(getClass().getName() + "[");
- b.append("image=" + image);
- b.append(",link=" + link);
- b.append(",text=" + text);
- b.append(",x=" + x);
- b.append(",y=" + y);
- b.append("]");
- return b.toString();
- }
+ public String
+ toString()
+ {
+ StringBuilder b = new StringBuilder();
+ b.append(getClass().getName() + "[");
+ b.append("image=" + image);
+ b.append(",link=" + link);
+ b.append(",text=" + text);
+ b.append(",x=" + x);
+ b.append(",y=" + y);
+ b.append("]");
+ return b.toString();
+ }
- public Segment
- clone()
- {
- Segment segment = new Segment();
- segment.image = this.image;
- segment.link = this.link;
- segment.text = this.text;
- segment.spacer = this.spacer;
- segment.x = this.x;
- segment.y = this.y;
- return segment;
- }
+ public Segment
+ clone()
+ {
+ Segment segment = new Segment();
+ segment.image = this.image;
+ segment.link = this.link;
+ segment.text = this.text;
+ segment.spacer = this.spacer;
+ segment.x = this.x;
+ segment.y = this.y;
+ return segment;
+ }
- }
+ }
- public static class
- Builder {
+ public static class
+ Builder {
- private List
- returnee;
+ private List
+ returnee;
-// -=%=-
+// -=%=-
- public
- Builder() { returnee = new LinkedList<>(); }
+ public
+ Builder() { returnee = new LinkedList<>(); }
- public Builder
- image(ImageIcon image, String text)
- {
- Segment segment = new Segment();
- segment.image = image;
- segment.text = text;
- returnee.add(segment);
- return this;
- }
+ public Builder
+ image(ImageIcon image, String text)
+ {
+ Segment segment = new Segment();
+ segment.image = image;
+ segment.text = text;
+ returnee.add(segment);
+ return this;
+ }
- public Builder
- link(String link, String text)
- {
- Segment segment = new Segment();
- segment.link = link;
- segment.text = text;
- returnee.add(segment);
- return this;
- }
+ public Builder
+ link(String link, String text)
+ {
+ Segment segment = new Segment();
+ segment.link = link;
+ segment.text = text;
+ returnee.add(segment);
+ return this;
+ }
- public Builder
- text(String text)
- {
- Segment segment = new Segment();
- segment.text = text;
- returnee.add(segment);
- return this;
- }
+ public Builder
+ text(String text)
+ {
+ Segment segment = new Segment();
+ segment.text = text;
+ returnee.add(segment);
+ return this;
+ }
- public Builder
- spacer(String text)
- {
- Segment segment = new Segment();
- segment.text = text;
- segment.spacer = true;
- returnee.add(segment);
- return this;
- }
+ public Builder
+ spacer(String text)
+ {
+ Segment segment = new Segment();
+ segment.text = text;
+ segment.spacer = true;
+ returnee.add(segment);
+ return this;
+ }
- public List
- finish() { return returnee; }
+ public List
+ finish() { return returnee; }
- }
+ }
-// ---%-@-%---
+// ---%-@-%---
- RichTextPane()
- {
- text = new LinkedList<>();
+ RichTextPane()
+ {
+ text = new LinkedList<>();
- addMouseListener(this);
- addMouseMotionListener(this);
- addKeyListener(this);
- }
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ addKeyListener(this);
+ }
}
diff --git a/RichTextPane2.java b/RichTextPane2.java
index a3a8086..624d6eb 100644
--- a/RichTextPane2.java
+++ b/RichTextPane2.java
@@ -37,463 +37,463 @@ class
RichTextPane2 extends JComponent
implements ComponentListener {
- private AttributedString
- text;
+ private AttributedString
+ text;
-// ---%-@-%---
+// ---%-@-%---
- public void
- setText(Tree html, Tree emojiMap)
- {
- Tree commands = turnIntoCommands(html);
+ public void
+ setText(Tree html, Tree emojiMap)
+ {
+ Tree commands = turnIntoCommands(html);
- class AStrSegment {
- String text;
- int offset;
- Object[] values = new Object[Attribute.COUNT];
- /*
- {
- values[3] = (Boolean)true;
- values[4] = (Integer)0;
- values[5] = (Boolean)true;
- values[6] = (Boolean)false;
- }
- */
- }
- List segments = new ArrayList<>();
+ class AStrSegment {
+ String text;
+ int offset;
+ Object[] values = new Object[Attribute.COUNT];
+ /*
+ {
+ values[3] = (Boolean)true;
+ values[4] = (Integer)0;
+ values[5] = (Boolean)true;
+ values[6] = (Boolean)false;
+ }
+ */
+ }
+ List segments = new ArrayList<>();
- int offset = 0;
- for (Tree command: commands)
- {
- if (command.key.equals("text"))
- {
- StringBuilder b = new StringBuilder();
- Boolean cibl = null;
- Boolean cwhi = null;
- for (char c: command.value.toCharArray())
- {
- Boolean ibl = isBasicLatin(c);
- Boolean whi = Character.isWhitespace(c);
- if (!ibl.equals(cibl) || !whi.equals(cwhi))
- {
- if (b.length() > 0)
- {
- assert cibl != null && cwhi != null;
- AStrSegment s = new AStrSegment();
- s.offset = offset;
- s.text = b.toString();
- s.values[3] = cibl;
- s.values[6] = cwhi;
- segments.add(s);
- offset += s.text.length();
- b.delete(0, b.length());
- }
- cibl = ibl;
- cwhi = whi;
- }
+ int offset = 0;
+ for (Tree command: commands)
+ {
+ if (command.key.equals("text"))
+ {
+ StringBuilder b = new StringBuilder();
+ Boolean cibl = null;
+ Boolean cwhi = null;
+ for (char c: command.value.toCharArray())
+ {
+ Boolean ibl = isBasicLatin(c);
+ Boolean whi = Character.isWhitespace(c);
+ if (!ibl.equals(cibl) || !whi.equals(cwhi))
+ {
+ if (b.length() > 0)
+ {
+ assert cibl != null && cwhi != null;
+ AStrSegment s = new AStrSegment();
+ s.offset = offset;
+ s.text = b.toString();
+ s.values[3] = cibl;
+ s.values[6] = cwhi;
+ segments.add(s);
+ offset += s.text.length();
+ b.delete(0, b.length());
+ }
+ cibl = ibl;
+ cwhi = whi;
+ }
- b.append(c);
- }
- if (b.length() > 0)
- {
- AStrSegment s = new AStrSegment();
- s.offset = offset;
- s.text = b.toString();
- s.values[3] = cibl;
- s.values[6] = cwhi;
- segments.add(s);
- offset += s.text.length();
- }
- }
- else if (command.key.equals("emoji"))
- {
- AStrSegment s = new AStrSegment();
- s.offset = offset;
- s.values[3] = true;
- s.values[6] = false;
+ b.append(c);
+ }
+ if (b.length() > 0)
+ {
+ AStrSegment s = new AStrSegment();
+ s.offset = offset;
+ s.text = b.toString();
+ s.values[3] = cibl;
+ s.values[6] = cwhi;
+ segments.add(s);
+ offset += s.text.length();
+ }
+ }
+ else if (command.key.equals("emoji"))
+ {
+ AStrSegment s = new AStrSegment();
+ s.offset = offset;
+ s.values[3] = true;
+ s.values[6] = false;
- String shortcode = command.value;
- String url = null;
- Tree m = emojiMap.get(shortcode);
- if (m != null) url = m.value;
- Image img = ImageApi.remote(url);
- if (img != null)
- {
- s.text = " ";
- s.values[0] = img;
- s.values[1] = shortcode;
- segments.add(s);
- offset += 1;
- }
- else
- {
- s.text = shortcode;
- s.values[0] = null;
- s.values[1] = null;
- segments.add(s);
- offset += shortcode.length();
- }
- }
- else if (command.key.equals("link"))
- {
- AStrSegment s = new AStrSegment();
- s.offset = offset;
- s.text = command.value;
- s.values[2] = command.get("url").value;
- s.values[3] = true;
- s.values[6] = false;
- /*
- * Technically we're supposed to treat
- * the anchor text like a text node.
- * As in, it could be non-Basic-Latin..
- * I'll be Mastodon-specific again, and
- * assume it's a URL or some @ string.
- */
- }
- }
+ String shortcode = command.value;
+ String url = null;
+ Tree m = emojiMap.get(shortcode);
+ if (m != null) url = m.value;
+ Image img = ImageApi.remote(url);
+ if (img != null)
+ {
+ s.text = " ";
+ s.values[0] = img;
+ s.values[1] = shortcode;
+ segments.add(s);
+ offset += 1;
+ }
+ else
+ {
+ s.text = shortcode;
+ s.values[0] = null;
+ s.values[1] = null;
+ segments.add(s);
+ offset += shortcode.length();
+ }
+ }
+ else if (command.key.equals("link"))
+ {
+ AStrSegment s = new AStrSegment();
+ s.offset = offset;
+ s.text = command.value;
+ s.values[2] = command.get("url").value;
+ s.values[3] = true;
+ s.values[6] = false;
+ /*
+ * Technically we're supposed to treat
+ * the anchor text like a text node.
+ * As in, it could be non-Basic-Latin..
+ * I'll be Mastodon-specific again, and
+ * assume it's a URL or some @ string.
+ */
+ }
+ }
- AttributedString astr;
- StringBuilder b = new StringBuilder();
- for (AStrSegment segment: segments)
- {
- b.append(segment.text);
- }
- astr = new AttributedString(b.toString());
- for (AStrSegment segment: segments)
- {
- Object[] v = segment.values;
- astr.addAttribute(
- Attribute.IMAGE, segment.values[0],
- segment.offset,
- segment.offset + segment.text.length()
- );
- astr.addAttribute(
- Attribute.ALT, segment.values[1],
- segment.offset,
- segment.offset + segment.text.length()
- );
- astr.addAttribute(
- Attribute.LINK, segment.values[2],
- segment.offset,
- segment.offset + segment.text.length()
- );
- astr.addAttribute(
- Attribute.BASICLATIN, segment.values[3],
- segment.offset,
- segment.offset + segment.text.length()
- );
- astr.addAttribute(
- Attribute.Y, segment.values[4],
- segment.offset,
- segment.offset + segment.text.length()
- );
- astr.addAttribute(
- Attribute.OFFSCREEN, segment.values[5],
- segment.offset,
- segment.offset + segment.text.length()
- );
- astr.addAttribute(
- Attribute.WHITESPACE, segment.values[6],
- segment.offset,
- segment.offset + segment.text.length()
- );
- }
+ AttributedString astr;
+ StringBuilder b = new StringBuilder();
+ for (AStrSegment segment: segments)
+ {
+ b.append(segment.text);
+ }
+ astr = new AttributedString(b.toString());
+ for (AStrSegment segment: segments)
+ {
+ Object[] v = segment.values;
+ astr.addAttribute(
+ Attribute.IMAGE, segment.values[0],
+ segment.offset,
+ segment.offset + segment.text.length()
+ );
+ astr.addAttribute(
+ Attribute.ALT, segment.values[1],
+ segment.offset,
+ segment.offset + segment.text.length()
+ );
+ astr.addAttribute(
+ Attribute.LINK, segment.values[2],
+ segment.offset,
+ segment.offset + segment.text.length()
+ );
+ astr.addAttribute(
+ Attribute.BASICLATIN, segment.values[3],
+ segment.offset,
+ segment.offset + segment.text.length()
+ );
+ astr.addAttribute(
+ Attribute.Y, segment.values[4],
+ segment.offset,
+ segment.offset + segment.text.length()
+ );
+ astr.addAttribute(
+ Attribute.OFFSCREEN, segment.values[5],
+ segment.offset,
+ segment.offset + segment.text.length()
+ );
+ astr.addAttribute(
+ Attribute.WHITESPACE, segment.values[6],
+ segment.offset,
+ segment.offset + segment.text.length()
+ );
+ }
- this.text = astr;
- componentResized(null);
- }
+ this.text = astr;
+ componentResized(null);
+ }
-// - -%- -
+// - -%- -
- public void
- componentResized(ComponentEvent eC)
- {
- int w = getWidth(), h = getHeight();
+ public void
+ componentResized(ComponentEvent eC)
+ {
+ int w = getWidth(), h = getHeight();
- // We're going to evaluate the
- // line and off-screen attributes.
+ // We're going to evaluate the
+ // line and off-screen attributes.
- FontMetrics fm = getFontMetrics(getFont());
- Graphics g = getGraphics();
- int x = 0, y = fm.getAscent();
+ FontMetrics fm = getFontMetrics(getFont());
+ Graphics g = getGraphics();
+ int x = 0, y = fm.getAscent();
- AttributedCharacterIterator it;
- it = text.getIterator();
+ AttributedCharacterIterator it;
+ it = text.getIterator();
- while (it.getIndex() < it.getEndIndex())
- {
- int start = it.getIndex();
- int end = it.getRunLimit();
+ while (it.getIndex() < it.getEndIndex())
+ {
+ int start = it.getIndex();
+ int end = it.getRunLimit();
- Image img = (Image)
- it.getAttribute(Attribute.IMAGE);
- Boolean ibl = (Boolean)
- it.getAttribute(Attribute.BASICLATIN);
- Boolean whi = (Boolean)
- it.getAttribute(Attribute.WHITESPACE);
+ Image img = (Image)
+ it.getAttribute(Attribute.IMAGE);
+ Boolean ibl = (Boolean)
+ it.getAttribute(Attribute.BASICLATIN);
+ Boolean whi = (Boolean)
+ it.getAttribute(Attribute.WHITESPACE);
- assert ibl != null;
- assert whi != null;
+ assert ibl != null;
+ assert whi != null;
- if (img != null)
- {
- int ow = img.getWidth(this);
- int oh = img.getHeight(this);
- int nh = fm.getAscent() + fm.getDescent();
- int nw = ow * nh/oh;
- if (x + nw > w)
- {
- y += fm.getAscent() + fm.getDescent();
- x = nw;
- }
- text.addAttribute(
- Attribute.Y, (Integer)y,
- start, end
- );
- text.addAttribute(
- Attribute.OFFSCREEN, (Boolean)(y > h),
- start, end
- );
- it.setIndex(end);
- }
- else
- {
- int p, xOff = 0;
- for (p = end; p > start; --p)
- {
- Rectangle2D r;
- r = fm.getStringBounds(it, start, p, g);
- xOff = (int)r.getWidth();
- if (x + xOff < w) break;
- }
- if (p == end || whi)
- {
- x += xOff;
- text.addAttribute(
- Attribute.Y, (Integer)y,
- start, end
- );
- text.addAttribute(
- Attribute.OFFSCREEN, (Boolean)(y > h),
- start, end
- );
- it.setIndex(end);
- }
- else if (p <= start)
- {
- y += fm.getAscent() + fm.getDescent();
- x = xOff;
- text.addAttribute(
- Attribute.Y, (Integer)y,
- start, end
- );
- text.addAttribute(
- Attribute.OFFSCREEN, (Boolean)(y > h),
- start, end
- );
- it.setIndex(end);
- }
- else
- {
- text.addAttribute(
- Attribute.Y, (Integer)y,
- start, p
- );
- text.addAttribute(
- Attribute.OFFSCREEN, (Boolean)(y > h),
- start, p
- );
- y += fm.getAscent() + fm.getDescent();
- x = 0;
- it.setIndex(p);
- }
- }
- }
+ if (img != null)
+ {
+ int ow = img.getWidth(this);
+ int oh = img.getHeight(this);
+ int nh = fm.getAscent() + fm.getDescent();
+ int nw = ow * nh/oh;
+ if (x + nw > w)
+ {
+ y += fm.getAscent() + fm.getDescent();
+ x = nw;
+ }
+ text.addAttribute(
+ Attribute.Y, (Integer)y,
+ start, end
+ );
+ text.addAttribute(
+ Attribute.OFFSCREEN, (Boolean)(y > h),
+ start, end
+ );
+ it.setIndex(end);
+ }
+ else
+ {
+ int p, xOff = 0;
+ for (p = end; p > start; --p)
+ {
+ Rectangle2D r;
+ r = fm.getStringBounds(it, start, p, g);
+ xOff = (int)r.getWidth();
+ if (x + xOff < w) break;
+ }
+ if (p == end || whi)
+ {
+ x += xOff;
+ text.addAttribute(
+ Attribute.Y, (Integer)y,
+ start, end
+ );
+ text.addAttribute(
+ Attribute.OFFSCREEN, (Boolean)(y > h),
+ start, end
+ );
+ it.setIndex(end);
+ }
+ else if (p <= start)
+ {
+ y += fm.getAscent() + fm.getDescent();
+ x = xOff;
+ text.addAttribute(
+ Attribute.Y, (Integer)y,
+ start, end
+ );
+ text.addAttribute(
+ Attribute.OFFSCREEN, (Boolean)(y > h),
+ start, end
+ );
+ it.setIndex(end);
+ }
+ else
+ {
+ text.addAttribute(
+ Attribute.Y, (Integer)y,
+ start, p
+ );
+ text.addAttribute(
+ Attribute.OFFSCREEN, (Boolean)(y > h),
+ start, p
+ );
+ y += fm.getAscent() + fm.getDescent();
+ x = 0;
+ it.setIndex(p);
+ }
+ }
+ }
- text.addAttribute(TextAttribute.FONT, getFont());
+ text.addAttribute(TextAttribute.FONT, getFont());
- repaint();
- }
+ repaint();
+ }
- protected void
- paintComponent(Graphics g)
- {
- int w = getWidth(), h = getHeight();
- g.clearRect(0, 0, w, h);
+ protected void
+ paintComponent(Graphics g)
+ {
+ int w = getWidth(), h = getHeight();
+ g.clearRect(0, 0, w, h);
- FontMetrics fm = g.getFontMetrics();
+ FontMetrics fm = g.getFontMetrics();
- AttributedCharacterIterator it;
- it = text.getIterator();
+ AttributedCharacterIterator it;
+ it = text.getIterator();
- ((java.awt.Graphics2D)g).setRenderingHint(
- java.awt.RenderingHints.KEY_ANTIALIASING,
- java.awt.RenderingHints.VALUE_ANTIALIAS_ON
- );
+ ((java.awt.Graphics2D)g).setRenderingHint(
+ java.awt.RenderingHints.KEY_ANTIALIASING,
+ java.awt.RenderingHints.VALUE_ANTIALIAS_ON
+ );
- int x = 0, y = fm.getAscent();
- while (it.getIndex() < it.getEndIndex())
- {
- int start = it.getIndex();
- int end = it.getRunLimit();
+ int x = 0, y = fm.getAscent();
+ while (it.getIndex() < it.getEndIndex())
+ {
+ int start = it.getIndex();
+ int end = it.getRunLimit();
- Image img = (Image)
- it.getAttribute(Attribute.IMAGE);
- Boolean ibl = (Boolean)
- it.getAttribute(Attribute.BASICLATIN);
- Integer ny = (Integer)
- it.getAttribute(Attribute.Y);
+ Image img = (Image)
+ it.getAttribute(Attribute.IMAGE);
+ Boolean ibl = (Boolean)
+ it.getAttribute(Attribute.BASICLATIN);
+ Integer ny = (Integer)
+ it.getAttribute(Attribute.Y);
- if (ny > y)
- {
- y = ny;
- x = 0;
- }
+ if (ny > y)
+ {
+ y = ny;
+ x = 0;
+ }
- if (img != null)
- {
- int ow = img.getWidth(this);
- int oh = img.getHeight(this);
- int nh = fm.getAscent() + fm.getDescent();
- int nw = ow * nh/oh;
- int iy = y + fm.getDescent() - nh;
- g.drawImage(img, x, iy, nw, nh, this);
- x += nw;
- }
- else
- {
- Rectangle2D r;
- r = fm.getStringBounds(it, start, end, g);
- AttributedCharacterIterator sit;
- sit = text.getIterator(null, start, end);
- g.drawString(sit, x, y);
- x += (int)r.getWidth();
- }
- it.setIndex(end);
- }
- }
+ if (img != null)
+ {
+ int ow = img.getWidth(this);
+ int oh = img.getHeight(this);
+ int nh = fm.getAscent() + fm.getDescent();
+ int nw = ow * nh/oh;
+ int iy = y + fm.getDescent() - nh;
+ g.drawImage(img, x, iy, nw, nh, this);
+ x += nw;
+ }
+ else
+ {
+ Rectangle2D r;
+ r = fm.getStringBounds(it, start, end, g);
+ AttributedCharacterIterator sit;
+ sit = text.getIterator(null, start, end);
+ g.drawString(sit, x, y);
+ x += (int)r.getWidth();
+ }
+ it.setIndex(end);
+ }
+ }
- public void
- componentMoved(ComponentEvent eC) { }
+ public void
+ componentMoved(ComponentEvent eC) { }
- public void
- componentShown(ComponentEvent eC) { }
+ public void
+ componentShown(ComponentEvent eC) { }
- public void
- componentHidden(ComponentEvent eC) { }
+ public void
+ componentHidden(ComponentEvent eC) { }
-// - -%- -
+// - -%- -
- private static Boolean
- isBasicLatin(char c)
- {
- return true;
- }
+ private static Boolean
+ isBasicLatin(char c)
+ {
+ return true;
+ }
- private static String
- toText(Tree node)
- {
- Tree children = node.get("children");
- if (children == null)
- {
- boolean text = node.key.equals("text");
- boolean emoji = node.key.equals("emoji");
- assert text || emoji;
- return node.value;
- }
+ private static String
+ toText(Tree node)
+ {
+ Tree children = node.get("children");
+ if (children == null)
+ {
+ boolean text = node.key.equals("text");
+ boolean emoji = node.key.equals("emoji");
+ assert text || emoji;
+ return node.value;
+ }
- StringBuilder b = new StringBuilder();
- for (Tree child: children)
- {
- b.append(toText(child));
- }
- return b.toString();
- }
+ StringBuilder b = new StringBuilder();
+ for (Tree child: children)
+ {
+ b.append(toText(child));
+ }
+ return b.toString();
+ }
- private static Tree
- turnIntoCommands(Tree tag)
- {
- assert tag.key.equals("tag");
- Tree returnee = new Tree();
+ private static Tree
+ turnIntoCommands(Tree tag)
+ {
+ assert tag.key.equals("tag");
+ Tree returnee = new Tree();
- String tagName = tag.get(0).key;
- Tree children = tag.get("children");
+ String tagName = tag.get(0).key;
+ Tree children = tag.get("children");
- if (tagName.equals("a"))
- {
- String url = tag.get("href").value;
- Tree addee = new Tree<>();
- addee.key = "link";
- addee.value = toText(tag);
- addee.add(new Tree<>("url", url));
- returnee.add(addee);
- }
- else if (tagName.equals("span"))
- {
- Tree addee = new Tree<>();
- addee.key = "text";
- addee.value = toText(tag);
- returnee.add(addee);
- }
- else if (tagName.equals("br"))
- {
- returnee.add(new Tree<>("text", "\n"));
- }
- else
- {
- for (Tree child: children)
- {
- if (!child.key.equals("tag"))
- {
- returnee.add(child);
- continue;
- }
- child = turnIntoCommands(child);
- for (Tree command: child)
- {
- returnee.add(command);
- }
- }
- if (tagName.equals("p"))
- {
- returnee.add(new Tree<>("text", "\n"));
- returnee.add(new Tree<>("text", "\n"));
- }
- }
+ if (tagName.equals("a"))
+ {
+ String url = tag.get("href").value;
+ Tree addee = new Tree<>();
+ addee.key = "link";
+ addee.value = toText(tag);
+ addee.add(new Tree<>("url", url));
+ returnee.add(addee);
+ }
+ else if (tagName.equals("span"))
+ {
+ Tree addee = new Tree<>();
+ addee.key = "text";
+ addee.value = toText(tag);
+ returnee.add(addee);
+ }
+ else if (tagName.equals("br"))
+ {
+ returnee.add(new Tree<>("text", "\n"));
+ }
+ else
+ {
+ for (Tree child: children)
+ {
+ if (!child.key.equals("tag"))
+ {
+ returnee.add(child);
+ continue;
+ }
+ child = turnIntoCommands(child);
+ for (Tree command: child)
+ {
+ returnee.add(command);
+ }
+ }
+ if (tagName.equals("p"))
+ {
+ returnee.add(new Tree<>("text", "\n"));
+ returnee.add(new Tree<>("text", "\n"));
+ }
+ }
- return returnee;
- }
+ return returnee;
+ }
-// ---%-@-%---
+// ---%-@-%---
- public static class
- Attribute extends AttributedCharacterIterator.Attribute {
+ public static class
+ Attribute extends AttributedCharacterIterator.Attribute {
- public static final Attribute
- IMAGE = new Attribute("IMAGE"),
- ALT = new Attribute("ALT"),
- LINK = new Attribute("LINK"),
- BASICLATIN = new Attribute("BASICLATIN"),
- Y = new Attribute("Y"),
- OFFSCREEN = new Attribute("OFFSCREEN"),
- WHITESPACE = new Attribute("WHITESPACE");
+ public static final Attribute
+ IMAGE = new Attribute("IMAGE"),
+ ALT = new Attribute("ALT"),
+ LINK = new Attribute("LINK"),
+ BASICLATIN = new Attribute("BASICLATIN"),
+ Y = new Attribute("Y"),
+ OFFSCREEN = new Attribute("OFFSCREEN"),
+ WHITESPACE = new Attribute("WHITESPACE");
- public static final int
- COUNT = 7;
+ public static final int
+ COUNT = 7;
-// -=%=-
+// -=%=-
- private
- Attribute(String name) { super(name); }
+ private
+ Attribute(String name) { super(name); }
- }
+ }
-// ---%-@-%---
+// ---%-@-%---
- RichTextPane2()
- {
- this.addComponentListener(this);
- text = new AttributedString("");
- }
+ RichTextPane2()
+ {
+ this.addComponentListener(this);
+ text = new AttributedString("");
+ }
}
diff --git a/RichTextPane3.java b/RichTextPane3.java
index d5dacff..ef1eb81 100644
--- a/RichTextPane3.java
+++ b/RichTextPane3.java
@@ -45,232 +45,232 @@ implements
ComponentListener,
MouseListener, MouseMotionListener, KeyListener {
- private Tree
- html;
+ private Tree
+ html;
- private Map
- emojis;
+ private Map
+ emojis;
- private Map, Position>
- layout;
+ private Map, Position>
+ layout;
- private Tree
- layoutEnd, selStart, selEnd;
+ private Tree
+ layoutEnd, selStart, selEnd;
- private int
- startingLine, lastLine;
+ private int
+ startingLine, lastLine;
-// ---%-@-%---
+// ---%-@-%---
- public void
- setText(Tree html)
- {
+ public void
+ setText(Tree html)
+ {
assert html != null;
- this.html = html;
+ this.html = html;
- if (!isValid()) return;
+ if (!isValid()) return;
- assert html.key != null;
- assert html.key.equals("tag");
- assert html.get("children") != null;
+ assert html.key != null;
+ assert html.key.equals("tag");
+ assert html.get("children") != null;
- FontMetrics fm = getFontMetrics(getFont());
- Position cursor = new Position(0, 1);
+ FontMetrics fm = getFontMetrics(getFont());
+ Position cursor = new Position(0, 1);
- // Manually negate if first element is a break.
- Tree children = html.get("children");
- if (children.size() > 0)
- {
- Tree first = children.get(0);
- if (first.key.equals("tag"))
- {
- String tagName = first.get(0).key;
- if (tagName.equals("br")) cursor.line -= 1;
- if (tagName.equals("p")) cursor.line -= 2;
- }
- }
+ // Manually negate if first element is a break.
+ Tree children = html.get("children");
+ if (children.size() > 0)
+ {
+ Tree first = children.get(0);
+ if (first.key.equals("tag"))
+ {
+ String tagName = first.get(0).key;
+ if (tagName.equals("br")) cursor.line -= 1;
+ if (tagName.equals("p")) cursor.line -= 2;
+ }
+ }
- selStart = selEnd = null;
- layout.clear();
- startingLine = 1;
- layout(html, fm, cursor);
- layout.put(layoutEnd, cursor.clone());
- lastLine = cursor.line;
- repaint();
+ selStart = selEnd = null;
+ layout.clear();
+ startingLine = 1;
+ layout(html, fm, cursor);
+ layout.put(layoutEnd, cursor.clone());
+ lastLine = cursor.line;
+ repaint();
- int iy = fm.getAscent();
- int lh = fm.getAscent() + fm.getDescent();
- int h = snap2(cursor.line, iy, lh);
- h += fm.getDescent();
- setPreferredSize(new Dimension(1, h));
- }
+ int iy = fm.getAscent();
+ int lh = fm.getAscent() + fm.getDescent();
+ int h = snap2(cursor.line, iy, lh);
+ h += fm.getDescent();
+ setPreferredSize(new Dimension(1, h));
+ }
- public void
- setEmojis(Map emojis)
- {
- assert emojis != null;
- this.emojis = emojis;
- setText(html);
- }
+ public void
+ setEmojis(Map emojis)
+ {
+ assert emojis != null;
+ this.emojis = emojis;
+ setText(html);
+ }
- public void
- previousPage()
- {
- int advance = getHeightInLines();
- if (startingLine < advance) startingLine = 1;
- else startingLine -= advance;
- repaint();
- }
+ public void
+ previousPage()
+ {
+ int advance = getHeightInLines();
+ if (startingLine < advance) startingLine = 1;
+ else startingLine -= advance;
+ repaint();
+ }
- public void
- nextPage()
- {
- int advance = getHeightInLines();
- if (lastLine - startingLine < advance) return;
- else startingLine += advance;
- repaint();
- }
+ public void
+ nextPage()
+ {
+ int advance = getHeightInLines();
+ if (lastLine - startingLine < advance) return;
+ else startingLine += advance;
+ repaint();
+ }
-// - -%- -
+// - -%- -
- private void
- layout(Tree node, FontMetrics fm, Position cursor)
- {
+ private void
+ layout(Tree node, FontMetrics fm, Position cursor)
+ {
assert cursor != null;
- if (node.key.equals("space"))
- {
- int w = fm.stringWidth(node.value);
- if (cursor.x + w < getWidth())
- {
- layout.put(node, cursor.clone());
- cursor.x += w;
- }
- else
- {
- layout.put(node, cursor.clone());
- ++cursor.line;
- cursor.x = 0;
- }
- }
- else if (node.key.equals("text"))
- {
- int w = fm.stringWidth(node.value);
- if (cursor.x + w < getWidth())
- {
- layout.put(node, cursor.clone());
- cursor.x += w;
- }
- else if (w < getWidth())
- {
- ++cursor.line;
- cursor.x = 0;
- layout.put(node, cursor.clone());
- cursor.x += w;
- }
- else
- {
- StringBuilder rem = new StringBuilder();
- rem.append(node.value);
- int mw = getWidth();
- int aw = mw - cursor.x;
+ if (node.key.equals("space"))
+ {
+ int w = fm.stringWidth(node.value);
+ if (cursor.x + w < getWidth())
+ {
+ layout.put(node, cursor.clone());
+ cursor.x += w;
+ }
+ else
+ {
+ layout.put(node, cursor.clone());
+ ++cursor.line;
+ cursor.x = 0;
+ }
+ }
+ else if (node.key.equals("text"))
+ {
+ int w = fm.stringWidth(node.value);
+ if (cursor.x + w < getWidth())
+ {
+ layout.put(node, cursor.clone());
+ cursor.x += w;
+ }
+ else if (w < getWidth())
+ {
+ ++cursor.line;
+ cursor.x = 0;
+ layout.put(node, cursor.clone());
+ cursor.x += w;
+ }
+ else
+ {
+ StringBuilder rem = new StringBuilder();
+ rem.append(node.value);
+ int mw = getWidth();
+ int aw = mw - cursor.x;
- w = fm.charWidth(node.value.charAt(0));
- if (w >= aw)
- {
- ++cursor.line;
- cursor.x = 0;
- }
+ w = fm.charWidth(node.value.charAt(0));
+ if (w >= aw)
+ {
+ ++cursor.line;
+ cursor.x = 0;
+ }
- while (rem.length() > 0)
- {
- int l = 2;
- for (; l <= rem.length(); ++l)
- {
- String substr = rem.substring(0, l);
- w = fm.stringWidth(substr);
- if (w >= aw) break;
- }
- String substr = rem.substring(0, --l);
- w = fm.stringWidth(substr);
+ while (rem.length() > 0)
+ {
+ int l = 2;
+ for (; l <= rem.length(); ++l)
+ {
+ String substr = rem.substring(0, l);
+ w = fm.stringWidth(substr);
+ if (w >= aw) break;
+ }
+ String substr = rem.substring(0, --l);
+ w = fm.stringWidth(substr);
- Tree temp = new Tree<>();
- temp.key = node.key;
- temp.value = substr;
- layout.put(temp, cursor.clone());
+ Tree temp = new Tree<>();
+ temp.key = node.key;
+ temp.value = substr;
+ layout.put(temp, cursor.clone());
- rem.delete(0, l);
- boolean more = rem.length() != 0;
- if (more) ++cursor.line;
- cursor.x = more ? 0 : w;
- aw = mw;
- }
- }
- }
- else if (node.key.equals("emoji"))
- {
- Image image = emojis.get(node.value);
- int w; if (image != null)
- {
- int ow = image.getWidth(this);
- int oh = image.getHeight(this);
- int h = fm.getAscent() + fm.getDescent();
- w = ow * h/oh;
- }
- else
- {
- w = fm.stringWidth(node.value);
- }
+ rem.delete(0, l);
+ boolean more = rem.length() != 0;
+ if (more) ++cursor.line;
+ cursor.x = more ? 0 : w;
+ aw = mw;
+ }
+ }
+ }
+ else if (node.key.equals("emoji"))
+ {
+ Image image = emojis.get(node.value);
+ int w; if (image != null)
+ {
+ int ow = image.getWidth(this);
+ int oh = image.getHeight(this);
+ int h = fm.getAscent() + fm.getDescent();
+ w = ow * h/oh;
+ }
+ else
+ {
+ w = fm.stringWidth(node.value);
+ }
- if (cursor.x + w < getWidth())
- {
- layout.put(node, cursor.clone());
- cursor.x += w;
- }
- else
- {
- ++cursor.line;
- cursor.x = 0;
- layout.put(node, cursor.clone());
- cursor.x += w;
- }
- }
- else if (node.key.equals("tag"))
- {
- String tagName = node.get(0).key;
- Tree children = node.get("children");
+ if (cursor.x + w < getWidth())
+ {
+ layout.put(node, cursor.clone());
+ cursor.x += w;
+ }
+ else
+ {
+ ++cursor.line;
+ cursor.x = 0;
+ layout.put(node, cursor.clone());
+ cursor.x += w;
+ }
+ }
+ else if (node.key.equals("tag"))
+ {
+ String tagName = node.get(0).key;
+ Tree children = node.get("children");
- // We won't place tag nodes on the layout.
+ // We won't place tag nodes on the layout.
- if (tagName.equals("br"))
- {
- ++cursor.line;
- cursor.x = 0;
- }
- else if (tagName.equals("p"))
- {
- //cursor.line += 3/2;
- cursor.line += 2;
- // We don't have vertical cursor movement
- // other than the line. Maybe fix in the
- // future..?
- cursor.x = 0;
- }
+ if (tagName.equals("br"))
+ {
+ ++cursor.line;
+ cursor.x = 0;
+ }
+ else if (tagName.equals("p"))
+ {
+ //cursor.line += 3/2;
+ cursor.line += 2;
+ // We don't have vertical cursor movement
+ // other than the line. Maybe fix in the
+ // future..?
+ cursor.x = 0;
+ }
- for (Tree child: children)
- {
+ for (Tree child: children)
+ {
// Shallow copy this child node,
- Tree aug = new Tree<>();
+ Tree aug = new Tree<>();
aug.key = child.key;
aug.value = child.value;
for (Tree gc: child) aug.add(gc);
// Append all of our attributes. We'd like
- // those like href to end up at the text
- // nodes. This might collide with our
- // child node's attributes, for now I'll
- // assume that's not an issue.
+ // those like href to end up at the text
+ // nodes. This might collide with our
+ // child node's attributes, for now I'll
+ // assume that's not an issue.
for (int o = 1; o < node.size(); ++o)
{
Tree attr = node.get(o);
@@ -279,29 +279,29 @@ implements
}
layout(aug, fm, cursor);
- }
- }
- else assert false;
- }
+ }
+ }
+ else assert false;
+ }
- protected void
- paintComponent(Graphics g)
- {
+ protected void
+ paintComponent(Graphics g)
+ {
final Color LINK_COLOUR = Color.BLUE;
final Color PLAIN_COLOUR = getForeground();
final Color SEL_COLOUR = new Color(0, 0, 0, 25);
- g.setFont(getFont());
- FontMetrics fm = g.getFontMetrics();
- int iy = fm.getAscent();
- int lh = fm.getAscent() + fm.getDescent();
- int asc = fm.getAscent();
- int w = getWidth(), h = getHeight();
+ g.setFont(getFont());
+ FontMetrics fm = g.getFontMetrics();
+ int iy = fm.getAscent();
+ int lh = fm.getAscent() + fm.getDescent();
+ int asc = fm.getAscent();
+ int w = getWidth(), h = getHeight();
- if (isOpaque()) g.clearRect(0, 0, w, h);
+ if (isOpaque()) g.clearRect(0, 0, w, h);
- if (selEnd != null)
- {
+ if (selEnd != null)
+ {
Position ssp = layout.get(selStart);
assert ssp != null;
Position sep = layout.get(selEnd);
@@ -318,81 +318,81 @@ implements
sep = ssp;
}
- int ls = 1 + ssp.line - startingLine;
- int le = 1 + sep.line - startingLine;
- int ys = snap2(ls, iy, lh) - asc;
- int ye = snap2(le, iy, lh) - asc;
+ int ls = 1 + ssp.line - startingLine;
+ int le = 1 + sep.line - startingLine;
+ int ys = snap2(ls, iy, lh) - asc;
+ int ye = snap2(le, iy, lh) - asc;
- g.setColor(SEL_COLOUR);
+ g.setColor(SEL_COLOUR);
if (ssp.line == sep.line)
{
- g.fillRect(ssp.x, ys, sep.x - ssp.x, lh);
+ g.fillRect(ssp.x, ys, sep.x - ssp.x, lh);
}
else
{
- g.fillRect(ssp.x, ys, w - ssp.x, lh);
- for (int l = ls + 1; l < le; ++l)
+ g.fillRect(ssp.x, ys, w - ssp.x, lh);
+ for (int l = ls + 1; l < le; ++l)
{
- int y = snap2(l, iy, lh) - asc;
+ int y = snap2(l, iy, lh) - asc;
g.fillRect(0, y, w, lh);
}
- g.fillRect(0, ye, sep.x, lh);
+ g.fillRect(0, ye, sep.x, lh);
}
- }
+ }
- ((java.awt.Graphics2D)g).setRenderingHint(
- java.awt.RenderingHints.KEY_ANTIALIASING,
- java.awt.RenderingHints.VALUE_ANTIALIAS_ON
- );
+ ((java.awt.Graphics2D)g).setRenderingHint(
+ java.awt.RenderingHints.KEY_ANTIALIASING,
+ java.awt.RenderingHints.VALUE_ANTIALIAS_ON
+ );
- g.setColor(getForeground());
- for (Tree node: layout.keySet())
- {
- Position position = layout.get(node);
- int x = position.x;
- int line = 1 + position.line - startingLine;
- int y = snap2(line, iy, lh);
- if (y > h) continue;
+ g.setColor(getForeground());
+ for (Tree node: layout.keySet())
+ {
+ Position position = layout.get(node);
+ int x = position.x;
+ int line = 1 + position.line - startingLine;
+ int y = snap2(line, iy, lh);
+ if (y > h) continue;
- if (node.key.equals("text"))
- {
+ if (node.key.equals("text"))
+ {
boolean isLink = node.get("href") != null;
if (isLink) g.setColor(LINK_COLOUR);
- g.drawString(node.value, x, y);
- if (isLink) g.setColor(PLAIN_COLOUR);
- }
- else if (node.key.equals("emoji"))
- {
+ g.drawString(node.value, x, y);
+ if (isLink) g.setColor(PLAIN_COLOUR);
+ }
+ else if (node.key.equals("emoji"))
+ {
Image image = emojis.get(node.value);
- Image scaled = emojis.get(node.value + "_scaled");
- if (scaled != null)
- {
- y -= asc;
- g.drawImage(scaled, x, y, this);
- }
- else if (image != null)
- {
- scaled = image.getScaledInstance(
- -1, fm.getAscent() + fm.getDescent(),
- Image.SCALE_SMOOTH
- );
- // I hope #getScaledInstance knows how to
- // wait if the image is yet to be loaded.
- emojis.put(node.value + "_scaled", scaled);
- }
- else
- {
- g.drawString(node.value, x, y);
- }
- }
- else continue;
- }
- }
+ Image scaled = emojis.get(node.value + "_scaled");
+ if (scaled != null)
+ {
+ y -= asc;
+ g.drawImage(scaled, x, y, this);
+ }
+ else if (image != null)
+ {
+ scaled = image.getScaledInstance(
+ -1, fm.getAscent() + fm.getDescent(),
+ Image.SCALE_SMOOTH
+ );
+ // I hope #getScaledInstance knows how to
+ // wait if the image is yet to be loaded.
+ emojis.put(node.value + "_scaled", scaled);
+ }
+ else
+ {
+ g.drawString(node.value, x, y);
+ }
+ }
+ else continue;
+ }
+ }
public void
mousePressed(MouseEvent eM)
{
- if (eM.getButton() != MouseEvent.BUTTON1) return;
+ if (eM.getButton() != MouseEvent.BUTTON1) return;
selStart = identifyNodeAt(eM.getX(), eM.getY());
selEnd = null;
repaint();
@@ -408,71 +408,71 @@ implements
repaint();
}
- public void
+ public void
mouseMoved(MouseEvent eM)
- {
- Tree h = identifyNodeAt(eM.getX(), eM.getY());
- if (h == null || h.get("href") == null)
- {
- setToolTipText("");
- }
- else
- {
- setToolTipText(h.get("href").value);
- }
- }
+ {
+ Tree h = identifyNodeAt(eM.getX(), eM.getY());
+ if (h == null || h.get("href") == null)
+ {
+ setToolTipText("");
+ }
+ else
+ {
+ setToolTipText(h.get("href").value);
+ }
+ }
- private Tree
- identifyNodeAt(int x, int y)
- {
+ private Tree
+ identifyNodeAt(int x, int y)
+ {
FontMetrics fm = getFontMetrics(getFont());
int initial = fm.getAscent();
int advance = fm.getAscent() + fm.getDescent();
- int line = isnap2(y, initial, advance);
+ int line = isnap2(y, initial, advance);
Tree returnee = null;
- Position closest = new Position(0, 0);
- for (Tree node: layout.keySet())
+ Position closest = new Position(0, 0);
+ for (Tree node: layout.keySet())
{
Position position = layout.get(node);
assert position != null;
- if (position.line != line) continue;
+ if (position.line != line) continue;
if (position.x > x) continue;
if (position.x >= closest.x)
{
- returnee = node;
- closest = position;
+ returnee = node;
+ closest = position;
}
}
return returnee;
- }
+ }
- private Tree
- identifyNodeAfter(int x, int y)
- {
+ private Tree
+ identifyNodeAfter(int x, int y)
+ {
FontMetrics fm = getFontMetrics(getFont());
int initial = fm.getAscent();
int advance = fm.getAscent() + fm.getDescent();
- int line = isnap2(y, initial, advance);
+ int line = isnap2(y, initial, advance);
Tree returnee = null;
- Position closest = new Position(Integer.MAX_VALUE, 0);
- for (Tree node: layout.keySet())
+ Position closest = new Position(Integer.MAX_VALUE, 0);
+ for (Tree node: layout.keySet())
{
Position position = layout.get(node);
assert position != null;
- if (position.line != line) continue;
+ if (position.line != line) continue;
if (position.x < x) continue;
if (position.x < closest.x)
{
- returnee = node;
- closest = position;
+ returnee = node;
+ closest = position;
}
}
return returnee;
- }
+ }
public void
keyPressed(KeyEvent eK)
@@ -494,14 +494,14 @@ implements
}
private String
- getSelectedText()
- {
+ getSelectedText()
+ {
assert selStart != null && selEnd != null;
Position ssp = layout.get(selStart);
Position sep = layout.get(selEnd);
assert ssp != null && sep != null;
- if (ssp.compareTo(sep) > 0)
+ if (ssp.compareTo(sep) > 0)
{
Position temp = ssp;
ssp = sep;
@@ -515,8 +515,8 @@ implements
Position position = layout.get(node);
assert position != null;
- boolean after = position.compareTo(ssp) >= 0;
- boolean before = position.compareTo(sep) < 0;
+ boolean after = position.compareTo(ssp) >= 0;
+ boolean before = position.compareTo(sep) < 0;
if (!(after && before)) continue;
// Just throw them in a pile for now..
@@ -549,35 +549,35 @@ implements
boolean s = node.key.equals("space");
assert t || e || s;
b.append(node.value);
- /*
- * I actually want to copy the link if the node is
- * associated with one. However, a link has
- * multiple text nodes, so I'd end up copying
- * multiple times. The correct action is to
- * associate the nodes with the same link object,
- * then mark that as copied. Or, associate the
- * nodes with their superiors in the HTML, then
- * walk up until we find an anchor with a href.
- * Then again, have to mark that as copied too.
- *
- * I can also walk the HTML and copy any that are
- * in the selected region, careful to copy an
- * anchor's href in stead of the anchor contents.
- * I'd need a guarantee that my walking order is
- * the same as how they were rendered on the screen.
- */
+ /*
+ * I actually want to copy the link if the node is
+ * associated with one. However, a link has
+ * multiple text nodes, so I'd end up copying
+ * multiple times. The correct action is to
+ * associate the nodes with the same link object,
+ * then mark that as copied. Or, associate the
+ * nodes with their superiors in the HTML, then
+ * walk up until we find an anchor with a href.
+ * Then again, have to mark that as copied too.
+ *
+ * I can also walk the HTML and copy any that are
+ * in the selected region, careful to copy an
+ * anchor's href in stead of the anchor contents.
+ * I'd need a guarantee that my walking order is
+ * the same as how they were rendered on the screen.
+ */
}
return b.toString();
- }
+ }
- private int
- getHeightInLines()
- {
- FontMetrics fm = getFontMetrics(getFont());
+ private int
+ getHeightInLines()
+ {
+ FontMetrics fm = getFontMetrics(getFont());
int initial = fm.getAscent();
int advance = fm.getAscent() + fm.getDescent();
- return isnap2(getHeight(), initial, advance) - 1;
- }
+ return isnap2(getHeight(), initial, advance) - 1;
+ }
public void
keyReleased(KeyEvent eK) { }
@@ -597,107 +597,107 @@ implements
public void
mouseExited(MouseEvent eM) { }
- public void
- componentResized(ComponentEvent eC) { setText(html); }
+ public void
+ componentResized(ComponentEvent eC) { setText(html); }
- public void
- componentMoved(ComponentEvent eC) { }
+ public void
+ componentMoved(ComponentEvent eC) { }
- public void
- componentShown(ComponentEvent eC) { }
+ public void
+ componentShown(ComponentEvent eC) { }
- public void
- componentHidden(ComponentEvent eC) { }
+ public void
+ componentHidden(ComponentEvent eC) { }
// - -%- -
- private static int
- snap2(int blocks, int initial, int advance)
- {
- return initial + (blocks - 1) * advance;
- // If you'd like to go behind the first line 1,
- // note that the first negative line is 0.
- }
+ private static int
+ snap2(int blocks, int initial, int advance)
+ {
+ return initial + (blocks - 1) * advance;
+ // If you'd like to go behind the first line 1,
+ // note that the first negative line is 0.
+ }
- private static int
- isnap2(int units, int initial, int advance)
- {
- int offset = units - initial;
- return 2 + bfloor(offset - 1, advance);
- // Not yet sure how this behaves for negative numbers.
- }
+ private static int
+ isnap2(int units, int initial, int advance)
+ {
+ int offset = units - initial;
+ return 2 + bfloor(offset - 1, advance);
+ // Not yet sure how this behaves for negative numbers.
+ }
- private static int
- bfloor(int units, int block)
- {
- if (units < 0) return (units / block) - 1;
- else return units / block;
- }
+ private static int
+ bfloor(int units, int block)
+ {
+ if (units < 0) return (units / block) - 1;
+ else return units / block;
+ }
-// ---%-@-%---
+// ---%-@-%---
- private static class
- Position {
+ private static class
+ Position {
- int
- x, line;
+ int
+ x, line;
-// -=%=-
+// -=%=-
- public int
- compareTo(Position other)
- {
- if (line < other.line) return -1;
- if (line > other.line) return 1;
- if (x < other.x) return -1;
- if (x > other.x) return 1;
- return 0;
- }
+ public int
+ compareTo(Position other)
+ {
+ if (line < other.line) return -1;
+ if (line > other.line) return 1;
+ if (x < other.x) return -1;
+ if (x > other.x) return 1;
+ return 0;
+ }
- public String
- toString()
- {
+ public String
+ toString()
+ {
return "(" + x + "," + line + ")";
- }
+ }
-// -=%=-
+// -=%=-
- public
- Position(int x, int line)
- {
- this.x = x;
- this.line = line;
- }
+ public
+ Position(int x, int line)
+ {
+ this.x = x;
+ this.line = line;
+ }
- public Position
- clone()
- {
- return new Position(x, line);
- }
+ public Position
+ clone()
+ {
+ return new Position(x, line);
+ }
- }
+ }
-// ---%-@-%---
+// ---%-@-%---
- RichTextPane3()
- {
- layout = new HashMap<>();
- layoutEnd = new Tree<>("text", "");
- emojis = new HashMap<>();
+ RichTextPane3()
+ {
+ layout = new HashMap<>();
+ layoutEnd = new Tree<>("text", "");
+ emojis = new HashMap<>();
- Tree blank = new Tree<>();
- blank.key = "tag";
- blank.add(new Tree<>("html", null));
- blank.add(new Tree<>("children", null));
- setText(blank);
+ Tree blank = new Tree<>();
+ blank.key = "tag";
+ blank.add(new Tree<>("html", null));
+ blank.add(new Tree<>("children", null));
+ setText(blank);
- this.addComponentListener(this);
- this.addMouseListener(this);
- this.addMouseMotionListener(this);
- this.addKeyListener(this);
- setFocusable(true);
- // A keyboard user can still copy by tabbing in
- // and selecting all.
- }
+ this.addComponentListener(this);
+ this.addMouseListener(this);
+ this.addMouseMotionListener(this);
+ this.addKeyListener(this);
+ setFocusable(true);
+ // A keyboard user can still copy by tabbing in
+ // and selecting all.
+ }
}
diff --git a/RudimentaryHTMLParser.java b/RudimentaryHTMLParser.java
index f03c147..494113a 100644
--- a/RudimentaryHTMLParser.java
+++ b/RudimentaryHTMLParser.java
@@ -31,18 +31,18 @@ RudimentaryHTMLParser {
public static Tree
depthlessRead(String html)
{
- try {
- return pass3(pass2(pass1(html)));
- }
- catch (IOException eIo) {
- assert false;
- /*
- * We use only StringReaders, which only throw an
- * IOException when they are read after being closed.
- * And we don't close them.
- */
- return null;
- }
+ try {
+ return pass3(pass2(pass1(html)));
+ }
+ catch (IOException eIo) {
+ assert false;
+ /*
+ * We use only StringReaders, which only throw an
+ * IOException when they are read after being closed.
+ * And we don't close them.
+ */
+ return null;
+ }
}
// - -%- -
@@ -51,10 +51,10 @@ RudimentaryHTMLParser {
pass1(String html)
throws IOException
{
- Reader r = new StringReader(html);
+ Reader r = new StringReader(html);
Tree docu = new Tree();
StringBuilder text = new StringBuilder();
- StringBuilder emoji = new StringBuilder();
+ StringBuilder emoji = new StringBuilder();
StringBuilder htmlEscape = new StringBuilder();
boolean quoted = false, inEmoji = false;
int c; while ((c = r.read()) != -1)
@@ -110,7 +110,7 @@ RudimentaryHTMLParser {
continue;
}
}
- text.append((char)c);
+ text.append((char)c);
continue;
}
if (text.length() > 0)
@@ -181,9 +181,9 @@ RudimentaryHTMLParser {
return docu;
}
- private static Tree
- pass3(Tree docu)
- {
+ private static Tree
+ pass3(Tree docu)
+ {
Tree returnee = new Tree();
for (Tree