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 node: docu) @@ -194,39 +194,39 @@ RudimentaryHTMLParser { continue; } - StringBuilder value = new StringBuilder(); - for (String segment: whitespaceSplit(node.value)) - { - boolean st = segment.startsWith(":"); + StringBuilder value = new StringBuilder(); + for (String segment: whitespaceSplit(node.value)) + { + boolean st = segment.startsWith(":"); boolean ed = segment.endsWith(":"); if (st && ed) { Tree text = new Tree(); - text.key = "text"; - text.value = empty(value); - returnee.add(text); + text.key = "text"; + text.value = empty(value); + returnee.add(text); Tree emoji = new Tree(); emoji.key = "emoji"; - emoji.value = segment; + emoji.value = segment; returnee.add(emoji); } - else - { - value.append(segment); - } - } - if (value.length() > 0) - { - Tree text = new Tree(); - text.key = "text"; - text.value = empty(value); - returnee.add(text); - } - } - return returnee; - } + else + { + value.append(segment); + } + } + if (value.length() > 0) + { + Tree text = new Tree(); + text.key = "text"; + text.value = empty(value); + returnee.add(text); + } + } + return returnee; + } private static String empty(StringBuilder b) @@ -236,25 +236,25 @@ RudimentaryHTMLParser { return s; } - private static List - whitespaceSplit(String text) - { - List returnee = new ArrayList<>(); - StringBuilder segment = new StringBuilder(); - boolean isWhitespace = false; - for (char c: text.toCharArray()) - { - boolean diff = isWhitespace ^ Character.isWhitespace(c); - if (diff) { - returnee.add(empty(segment)); - isWhitespace = !isWhitespace; - } - segment.append(c); - } - returnee.add(empty(segment)); + private static List + whitespaceSplit(String text) + { + List returnee = new ArrayList<>(); + StringBuilder segment = new StringBuilder(); + boolean isWhitespace = false; + for (char c: text.toCharArray()) + { + boolean diff = isWhitespace ^ Character.isWhitespace(c); + if (diff) { + returnee.add(empty(segment)); + isWhitespace = !isWhitespace; + } + segment.append(c); + } + returnee.add(empty(segment)); - return returnee; - } + return returnee; + } // ---%-@-%--- diff --git a/TimelineWindow.java b/TimelineWindow.java index 3d424c3..ca3fad5 100644 --- a/TimelineWindow.java +++ b/TimelineWindow.java @@ -90,9 +90,9 @@ implements ActionListener { openMessages, openLocal, openFederated, - openNotifications, - openOwnProfile, - openProfile, + openNotifications, + openOwnProfile, + openProfile, createPost, openAutoPostView, quit; @@ -117,101 +117,101 @@ implements ActionListener { this.page = page; List previews; - previews = display.getPostPreviews(); + previews = display.getPostPreviews(); - int available = page.posts.length; - int max = previews.size(); - assert available <= max; + int available = page.posts.length; + int max = previews.size(); + assert available <= max; - for (int o = 0; o < available; ++o) - { - PostPreviewComponent preview = previews.get(o); - Post post = page.posts[o]; + for (int o = 0; o < available; ++o) + { + PostPreviewComponent preview = previews.get(o); + Post post = page.posts[o]; preview.setTopLeft(post.author.name); - if (post.boostedPost != null) - { + if (post.boostedPost != null) + { String s = "boosted by " + post.author.name; - preview.setTopLeft(s); - post = post.boostedPost; - } + preview.setTopLeft(s); + post = post.boostedPost; + } - String flags = ""; - if (post.attachments.length > 0) flags += "a"; - post.resolveRelativeTime(); - preview.setTopRight(flags + " " + post.relativeTime); + String flags = ""; + if (post.attachments.length > 0) flags += "a"; + post.resolveRelativeTime(); + preview.setTopRight(flags + " " + post.relativeTime); - post.resolveApproximateText(); - if (post.contentWarning != null) - preview.setBottom("(" + post.contentWarning + ")"); + post.resolveApproximateText(); + if (post.contentWarning != null) + preview.setBottom("(" + post.contentWarning + ")"); else preview.setBottom(post.approximateText); - } + } for (int o = available; o < max; ++o) { previews.get(o).reset(); } - boolean full = !(available < PREVIEW_COUNT); - display.setNextPageAvailable(full); - display.setPreviousPageAvailable(true); - display.resetFocus(); + boolean full = !(available < PREVIEW_COUNT); + display.setNextPageAvailable(full); + display.setPreviousPageAvailable(true); + display.resetFocus(); } - public void - readEntity(Tree postEntityArray) - { + public void + readEntity(Tree postEntityArray) + { TimelinePage page = new TimelinePage(postEntityArray); page.type = this.page.type; page.accountNumId = this.page.accountNumId; page.listId = this.page.listId; use(page); - } + } - public void - refresh() - { + public void + refresh() + { String firstId = null; if (!showingLatest) { assert page.posts != null; assert page.posts.length != 0; firstId = page.posts[0].id; - } + } display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); api.getTimelinePage( page.type, - PREVIEW_COUNT, firstId, null, - page.accountNumId, page.listId, + PREVIEW_COUNT, firstId, null, + page.accountNumId, page.listId, new RequestListener() { public void connectionFailed(IOException eIo) { - JOptionPane.showMessageDialog( - TimelineWindow.this, - "Failed to fetch page.." - + "\n" + eIo.getMessage() - ); + JOptionPane.showMessageDialog( + TimelineWindow.this, + "Failed to fetch page.." + + "\n" + eIo.getMessage() + ); } public void requestFailed(int httpCode, Tree json) { JOptionPane.showMessageDialog( - TimelineWindow.this, - "Failed to fetch page.." - + "\n" + json.get("error").value - + "\n(HTTP code: " + httpCode + ")" - ); + TimelineWindow.this, + "Failed to fetch page.." + + "\n" + json.get("error").value + + "\n(HTTP code: " + httpCode + ")" + ); } public void requestSucceeded(Tree json) { - if (json.size() < PREVIEW_COUNT) - { + if (json.size() < PREVIEW_COUNT) + { showLatestPage(); return; } @@ -221,37 +221,37 @@ implements ActionListener { } ); display.setCursor(null); - } + } - public void + public void showLatestPage() { display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); api.getTimelinePage( page.type, - PREVIEW_COUNT, null, null, - page.accountNumId, page.listId, + PREVIEW_COUNT, null, null, + page.accountNumId, page.listId, new RequestListener() { public void connectionFailed(IOException eIo) { - JOptionPane.showMessageDialog( - TimelineWindow.this, - "Failed to fetch page.." - + "\n" + eIo.getMessage() - ); + JOptionPane.showMessageDialog( + TimelineWindow.this, + "Failed to fetch page.." + + "\n" + eIo.getMessage() + ); } public void requestFailed(int httpCode, Tree json) { JOptionPane.showMessageDialog( - TimelineWindow.this, - "Failed to fetch page.." - + "\n" + json.get("error").value - + "\n(HTTP code: " + httpCode + ")" - ); + TimelineWindow.this, + "Failed to fetch page.." + + "\n" + json.get("error").value + + "\n(HTTP code: " + httpCode + ")" + ); } public void @@ -274,32 +274,32 @@ implements ActionListener { assert page.posts.length != 0; String lastId = page.posts[page.posts.length - 1].id; - display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); + display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); api.getTimelinePage( page.type, - PREVIEW_COUNT, lastId, null, - page.accountNumId, page.listId, + PREVIEW_COUNT, lastId, null, + page.accountNumId, page.listId, new RequestListener() { public void connectionFailed(IOException eIo) { - JOptionPane.showMessageDialog( - TimelineWindow.this, - "Failed to fetch page.." - + "\n" + eIo.getMessage() - ); + JOptionPane.showMessageDialog( + TimelineWindow.this, + "Failed to fetch page.." + + "\n" + eIo.getMessage() + ); } public void requestFailed(int httpCode, Tree json) { JOptionPane.showMessageDialog( - TimelineWindow.this, - "Failed to fetch page.." - + "\n" + json.get("error").value - + "\n(HTTP code: " + httpCode + ")" - ); + TimelineWindow.this, + "Failed to fetch page.." + + "\n" + json.get("error").value + + "\n(HTTP code: " + httpCode + ")" + ); } public void @@ -312,7 +312,7 @@ implements ActionListener { // quietly cancel. return; } - readEntity(json); + readEntity(json); showingLatest = false; windowUpdater.remove(TimelineWindow.this); } @@ -332,36 +332,36 @@ implements ActionListener { display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); api.getTimelinePage( page.type, - PREVIEW_COUNT, null, firstId, - page.accountNumId, page.listId, + PREVIEW_COUNT, null, firstId, + page.accountNumId, page.listId, new RequestListener() { public void connectionFailed(IOException eIo) { - JOptionPane.showMessageDialog( - TimelineWindow.this, - "Failed to fetch page.." - + "\n" + eIo.getMessage() - ); + JOptionPane.showMessageDialog( + TimelineWindow.this, + "Failed to fetch page.." + + "\n" + eIo.getMessage() + ); } public void requestFailed(int httpCode, Tree json) { JOptionPane.showMessageDialog( - TimelineWindow.this, - "Failed to fetch page.." - + "\n" + json.get("error").value - + "\n(HTTP code: " + httpCode + ")" - ); + TimelineWindow.this, + "Failed to fetch page.." + + "\n" + json.get("error").value + + "\n(HTTP code: " + httpCode + ")" + ); } public void requestSucceeded(Tree json) { - if (json.size() < PREVIEW_COUNT) - { + if (json.size() < PREVIEW_COUNT) + { showLatestPage(); return; } @@ -386,12 +386,12 @@ implements ActionListener { setTitle(toString(type) + " timeline - JKomasto"); String f = type.toString().toLowerCase(); - display.setBackgroundImage(ImageApi.local(f)); - /* - * (注) Java's image renderer draws images with transparency - * darker than GIMP does. Overcompensate in lightening. - */ - display.repaint(); + display.setBackgroundImage(ImageApi.local(f)); + /* + * (注) Java's image renderer draws images with transparency + * darker than GIMP does. Overcompensate in lightening. + */ + display.repaint(); } public synchronized TimelineType @@ -410,9 +410,9 @@ implements ActionListener { display.repaint(); } - public synchronized void - openOwnProfile() - { + public synchronized void + openOwnProfile() + { display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); Tree accountDetails = api.getAccountDetails(); @@ -422,118 +422,118 @@ implements ActionListener { w.setVisible(true); display.setCursor(null); - } + } - public void - openProfile() - { - String query = JOptionPane.showInputDialog( - this, - "Whose account do you want to see?\n" - + "Type an account name with the instance,\n" - + "or a display name if you can't remember.\n", - "Profile search", - JOptionPane.PLAIN_MESSAGE - ); - if (query == null) return; + public void + openProfile() + { + String query = JOptionPane.showInputDialog( + this, + "Whose account do you want to see?\n" + + "Type an account name with the instance,\n" + + "or a display name if you can't remember.\n", + "Profile search", + JOptionPane.PLAIN_MESSAGE + ); + if (query == null) return; - class Handler implements RequestListener { + class Handler implements RequestListener { - public Tree - json; + public Tree + json; -// -=%=- +// -=%=- - public void - connectionFailed(IOException eIo) - { - JOptionPane.showMessageDialog( - TimelineWindow.this, - "Tried to fetch accounts, but it failed.." - + "\n" + eIo.getMessage() - ); - } + public void + connectionFailed(IOException eIo) + { + JOptionPane.showMessageDialog( + TimelineWindow.this, + "Tried to fetch accounts, but it failed.." + + "\n" + eIo.getMessage() + ); + } - public void - requestFailed(int httpCode, Tree json) - { - JOptionPane.showMessageDialog( - TimelineWindow.this, - "Tried to fetch accounts, but it failed.." - + "\n" + json.get("error").value - + "\n(HTTP code: " + httpCode + ")" - ); - } + public void + requestFailed(int httpCode, Tree json) + { + JOptionPane.showMessageDialog( + TimelineWindow.this, + "Tried to fetch accounts, but it failed.." + + "\n" + json.get("error").value + + "\n(HTTP code: " + httpCode + ")" + ); + } - public void - requestSucceeded(Tree json) { this.json = json; } + public void + requestSucceeded(Tree json) { this.json = json; } - } - // (知) Have to create a named class because - // it has to hold the variable. - Handler handler = new Handler(); - api.getAccounts(query, handler); - if (handler.json == null) return; + } + // (知) Have to create a named class because + // it has to hold the variable. + Handler handler = new Handler(); + api.getAccounts(query, handler); + if (handler.json == null) return; - if (handler.json.size() == 0) - { - JOptionPane.showMessageDialog( - this, - "There were no results from the query.. ☹️" - ); - return; - } + if (handler.json.size() == 0) + { + JOptionPane.showMessageDialog( + this, + "There were no results from the query.. ☹️" + ); + return; + } - Tree openee = null; - if (query.startsWith("@")) query = query.substring(1); + Tree openee = null; + if (query.startsWith("@")) query = query.substring(1); - List message = new ArrayList<>(); - message.add("Maybe one of these?"); - ButtonGroup selGroup = new ButtonGroup(); - for (Tree account: handler.json) - { - String dname = account.get("display_name").value; - String acct = account.get("acct").value; - if (query.equals(acct)) { + List message = new ArrayList<>(); + message.add("Maybe one of these?"); + ButtonGroup selGroup = new ButtonGroup(); + for (Tree account: handler.json) + { + String dname = account.get("display_name").value; + String acct = account.get("acct").value; + if (query.equals(acct)) { openee = account; - break; - } - JRadioButton b = new JRadioButton(); - b.setText(dname + " (" + acct + ")"); - selGroup.add(b); - message.add(b); - } - if (openee == null) - { - int response = JOptionPane.showConfirmDialog( - this, - message.toArray(), - "Search results", - JOptionPane.OK_CANCEL_OPTION - ); - if (response == JOptionPane.CANCEL_OPTION) return; - for (int o = 1; o < message.size(); ++o) - { - JRadioButton b = (JRadioButton)message.get(o); - if (selGroup.isSelected(b.getModel())) - { + break; + } + JRadioButton b = new JRadioButton(); + b.setText(dname + " (" + acct + ")"); + selGroup.add(b); + message.add(b); + } + if (openee == null) + { + int response = JOptionPane.showConfirmDialog( + this, + message.toArray(), + "Search results", + JOptionPane.OK_CANCEL_OPTION + ); + if (response == JOptionPane.CANCEL_OPTION) return; + for (int o = 1; o < message.size(); ++o) + { + JRadioButton b = (JRadioButton)message.get(o); + if (selGroup.isSelected(b.getModel())) + { openee = handler.json.get(o - 1); - break; - } - } - if (openee == null) return; - /* - * It seems like this can happen if someone - * presses escape out of the confirm dialog. - * I don't know why that doesn't map to cancel. - */ - } + break; + } + } + if (openee == null) return; + /* + * It seems like this can happen if someone + * presses escape out of the confirm dialog. + * I don't know why that doesn't map to cancel. + */ + } ProfileWindow w = new ProfileWindow(primaire); w.use(new Account(openee)); w.setLocationByPlatform(true); w.setVisible(true); - } + } // - -%- - @@ -577,13 +577,13 @@ implements ActionListener { setTimelineType(TimelineType.LOCAL); showLatestPage(); } - if (src == openOwnProfile) + if (src == openOwnProfile) { - openOwnProfile(); + openOwnProfile(); } - if (src == openProfile) + if (src == openProfile) { - openProfile(); + openProfile(); } if (src == createPost) { @@ -595,15 +595,15 @@ implements ActionListener { w.setLocation(getX() + 10 + getWidth(), getY()); w.setVisible(true); } - if (src == openNotifications) + if (src == openNotifications) { - NotificationsWindow w = + NotificationsWindow w = primaire.getNotificationsWindow(); - if (!w.isVisible()) - { - w.setLocationByPlatform(true); - w.setVisible(true); - } + if (!w.isVisible()) + { + w.setLocationByPlatform(true); + w.setVisible(true); + } } if (src == flipToNewestPost) { @@ -650,17 +650,17 @@ implements ActionListener { openHome = new JMenuItem("Open home timeline"); openFederated = new JMenuItem("Open federated timeline"); - openNotifications = new JMenuItem("Open notifications"); - openOwnProfile = new JMenuItem("Open own profile"); - openProfile = new JMenuItem("Open profile.."); + openNotifications = new JMenuItem("Open notifications"); + openOwnProfile = new JMenuItem("Open own profile"); + openProfile = new JMenuItem("Open profile.."); createPost = new JMenuItem("Create a post"); openAutoPostView = new JMenuItem("Open auto post view"); quit = new JMenuItem("Quit"); openHome.addActionListener(this); openFederated.addActionListener(this); - openNotifications.addActionListener(this); - openOwnProfile.addActionListener(this); - openProfile.addActionListener(this); + openNotifications.addActionListener(this); + openOwnProfile.addActionListener(this); + openProfile.addActionListener(this); createPost.addActionListener(this); openAutoPostView.addActionListener(this); quit.addActionListener(this); @@ -672,9 +672,9 @@ implements ActionListener { programMenu.setMnemonic(KeyEvent.VK_P); programMenu.add(openHome); programMenu.add(openFederated); - programMenu.add(openNotifications); - programMenu.add(openOwnProfile); - programMenu.add(openProfile); + programMenu.add(openNotifications); + programMenu.add(openOwnProfile); + programMenu.add(openProfile); programMenu.add(new JSeparator()); programMenu.add(createPost); programMenu.add(openAutoPostView); @@ -696,8 +696,8 @@ implements ActionListener { display.setPreviousPageAvailable(false); setContentPane(display); - setTimelineType(TimelineType.HOME); - setIconImage(primaire.getProgramIcon()); + setTimelineType(TimelineType.HOME); + setIconImage(primaire.getProgramIcon()); } } @@ -727,8 +727,8 @@ implements private boolean hoverSelect; - private Image - backgroundImage; + private Image + backgroundImage; // - -%- - @@ -759,46 +759,46 @@ implements public void setHoverSelect(boolean n) { hoverSelect = n; } - public void - setBackgroundImage(Image n) { backgroundImage = n; } + public void + setBackgroundImage(Image n) { backgroundImage = n; } - public void - resetFocus() { postPreviews.get(0).requestFocusInWindow(); } + public void + resetFocus() { postPreviews.get(0).requestFocusInWindow(); } // - -%- - - protected void - paintComponent(Graphics g) - { + protected void + paintComponent(Graphics g) + { int w = getWidth(), h = getHeight(); - g.clearRect(0, 0, w, h); + g.clearRect(0, 0, w, h); - if (backgroundImage != null) - { - int b = h * 5 / 10; - int iw = backgroundImage.getWidth(this); - int ih = backgroundImage.getHeight(this); - if (ih > iw) { - ih = ih * b / iw; - iw = b; - } - else { - iw = iw * b / ih; - ih = b; - } - int x = w - iw, y = h - ih; - g.drawImage(backgroundImage, x, y, iw, ih, this); - } + if (backgroundImage != null) + { + int b = h * 5 / 10; + int iw = backgroundImage.getWidth(this); + int ih = backgroundImage.getHeight(this); + if (ih > iw) { + ih = ih * b / iw; + iw = b; + } + else { + iw = iw * b / ih; + ih = b; + } + int x = w - iw, y = h - ih; + g.drawImage(backgroundImage, x, y, iw, ih, 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 + ); + } - private void - select(Object c) - { + private void + select(Object c) + { assert c instanceof PostPreviewComponent; for (PostPreviewComponent p: postPreviews) @@ -814,25 +814,25 @@ implements p.repaint(); } } - } + } - private void - deselect(Object c) - { + private void + deselect(Object c) + { assert c instanceof PostPreviewComponent; PostPreviewComponent p = (PostPreviewComponent)c; p.setSelected(false); p.repaint(); - } + } - private void - open(Object c) - { + private void + open(Object c) + { int o = postPreviews.indexOf(c); assert o != -1; primaire.previewOpened(1 + o); - } + } public void focusGained(FocusEvent eF) { select(eF.getSource()); } @@ -840,14 +840,14 @@ implements public void focusLost(FocusEvent eF) { deselect(eF.getSource()); } - public void + public void mouseClicked(MouseEvent eM) { if (eM.getClickCount() == 2) open(eM.getSource()); else select(eM.getSource()); } - public void + public void mouseEntered(MouseEvent eM) { if (!hoverSelect) return; @@ -968,8 +968,8 @@ PostPreviewComponent extends JComponent { private JLabel topLeft, topRight, bottom; - private boolean - selected; + private boolean + selected; // ---%-@-%--- @@ -982,7 +982,7 @@ PostPreviewComponent extends JComponent { public void setBottom(String text) { bottom.setText(text); } - public void + public void reset() { setTopLeft(" "); @@ -1001,11 +1001,11 @@ PostPreviewComponent extends JComponent { protected void paintComponent(Graphics g) { - if (selected) - { - g.setColor(new Color(0, 0, 0, 25)); - g.fillRect(0, 0, getWidth(), getHeight()); - } + if (selected) + { + g.setColor(new Color(0, 0, 0, 25)); + g.fillRect(0, 0, getWidth(), getHeight()); + } } // ---%-@-%--- @@ -1032,20 +1032,20 @@ PostPreviewComponent extends JComponent { top.add(Box.createGlue()); top.add(topRight); - bottom = new JLabel(); + bottom = new JLabel(); bottom.setFont(f3); bottom.setOpaque(false); - JPanel left = new JPanel(); - left.setOpaque(false); - left.setLayout(new BorderLayout()); + JPanel left = new JPanel(); + left.setOpaque(false); + left.setLayout(new BorderLayout()); left.add(top, BorderLayout.NORTH); left.add(bottom); setFocusable(true); setOpaque(false); - setLayout(new BorderLayout()); - add(left); + setLayout(new BorderLayout()); + add(left); } } diff --git a/TwoToggleButton.java b/TwoToggleButton.java index b3f4f9d..01684d3 100644 --- a/TwoToggleButton.java +++ b/TwoToggleButton.java @@ -56,10 +56,10 @@ implements KeyListener, MouseListener, FocusListener { primaryToggled = false, secondaryToggled = false; - private Image + private Image primaryToggledIcon, secondaryToggledIcon, - primaryUntoggledIcon, + primaryUntoggledIcon, secondaryUntoggledIcon; private int @@ -116,7 +116,7 @@ implements KeyListener, MouseListener, FocusListener { // - -%- - - private void + private void announce(String name, boolean toggled) { ActionEvent eA = new ActionEvent( @@ -134,17 +134,17 @@ implements KeyListener, MouseListener, FocusListener { g.drawImage(button, 0, 0, this); if (!isEnabled()) g.drawImage(disabledOverlay, 0, 0, this); - if (isFocusOwner()) + if (isFocusOwner()) g.drawImage(selectedOverlay, 0, 0, this); - if (secondaryToggled) - g.drawImage(secondaryToggledIcon, 0, 0, this); - else - g.drawImage(secondaryUntoggledIcon, 0, 0, this); - if (primaryToggled) - g.drawImage(primaryToggledIcon, 0, 0, this); - else - g.drawImage(primaryUntoggledIcon, 0, 0, this); + if (secondaryToggled) + g.drawImage(secondaryToggledIcon, 0, 0, this); + else + g.drawImage(secondaryUntoggledIcon, 0, 0, this); + if (primaryToggled) + g.drawImage(primaryToggledIcon, 0, 0, this); + else + g.drawImage(primaryUntoggledIcon, 0, 0, this); } @@ -176,11 +176,11 @@ implements KeyListener, MouseListener, FocusListener { requestFocusInWindow(); } - public void - focusGained(FocusEvent eF) { repaint(); } + public void + focusGained(FocusEvent eF) { repaint(); } - public void - focusLost(FocusEvent eF) { repaint(); } + public void + focusLost(FocusEvent eF) { repaint(); } public void @@ -214,8 +214,8 @@ implements KeyListener, MouseListener, FocusListener { this.secondaryName = secondaryName; setModel(new DefaultButtonModel()); - setFocusable(true); - setOpaque(false); + setFocusable(true); + setOpaque(false); int w = button.getWidth(null); int h = button.getHeight(null); @@ -224,7 +224,7 @@ implements KeyListener, MouseListener, FocusListener { this.addKeyListener(this); this.addMouseListener(this); - this.addFocusListener(this); + this.addFocusListener(this); } private void @@ -232,17 +232,17 @@ implements KeyListener, MouseListener, FocusListener { { String p1 = "graphics/" + primaryName + "Toggled.png"; String p2 = "graphics/" + secondaryName + "Toggled.png"; - String p3 = "graphics/" + primaryName + "Untoggled.png"; + String p3 = "graphics/" + primaryName + "Untoggled.png"; String p4 = "graphics/" + secondaryName + "Untoggled.png"; URL u1 = getClass().getResource(p1); URL u2 = getClass().getResource(p2); - URL u3 = getClass().getResource(p3); - URL u4 = getClass().getResource(p4); + URL u3 = getClass().getResource(p3); + URL u4 = getClass().getResource(p4); if (u1 == null) primaryToggledIcon = null; else primaryToggledIcon = new ImageIcon(u1).getImage(); if (u2 == null) secondaryToggledIcon = null; else secondaryToggledIcon = new ImageIcon(u2).getImage(); - if (u3 == null) primaryUntoggledIcon = null; + if (u3 == null) primaryUntoggledIcon = null; else primaryUntoggledIcon = new ImageIcon(u3).getImage(); if (u4 == null) secondaryUntoggledIcon = null; else secondaryUntoggledIcon = new ImageIcon(u4).getImage(); @@ -270,16 +270,16 @@ class RoundButton extends AbstractButton implements KeyListener, MouseListener, FocusListener { - private Image - image; + private Image + image; -// - -%- - +// - -%- - - private Image - copy, - scaled; + private Image + copy, + scaled; - private int + private int nextEventID = ActionEvent.ACTION_FIRST; // - -%- - @@ -289,99 +289,99 @@ implements KeyListener, MouseListener, FocusListener { selectedOverlay, disabledOverlay; - private static Shape - roundClip; + private static Shape + roundClip; // ---%-@-%--- - public void - setImage(Image n) - { - image = n; - copy = null; - scaled = null; + public void + setImage(Image n) + { + image = n; + copy = null; + scaled = null; - if (image != null) - { - image.flush(); - prepareImage(image, this); - } - } + if (image != null) + { + image.flush(); + prepareImage(image, this); + } + } -// - -%- - +// - -%- - - public boolean - imageUpdate(Image img, int f, int x, int y, int w, int h) - { - // AbstractButton overrode this to refuse updates for - // images that aren't the button's icon. We don't use - // the icon, so we're overriding it back. Also, we have - // some async work to do regarding the images. + public boolean + imageUpdate(Image img, int f, int x, int y, int w, int h) + { + // AbstractButton overrode this to refuse updates for + // images that aren't the button's icon. We don't use + // the icon, so we're overriding it back. Also, we have + // some async work to do regarding the images. - if ((f & (ABORT|ERROR)) != 0) return false; + if ((f & (ABORT|ERROR)) != 0) return false; - boolean all = (f & ALLBITS) != 0; - boolean frame = (f & FRAMEBITS) != 0; - boolean some = (f & SOMEBITS) != 0; + boolean all = (f & ALLBITS) != 0; + boolean frame = (f & FRAMEBITS) != 0; + boolean some = (f & SOMEBITS) != 0; - if (frame && img != this.image) return false; + if (frame && img != this.image) return false; - if (img == this.image && (all || frame)) - { - int ow = img.getWidth(null); - int oh = img.getHeight(null); + if (img == this.image && (all || frame)) + { + int ow = img.getWidth(null); + int oh = img.getHeight(null); - if (copy == null) - { - int type = BufferedImage.TYPE_INT_ARGB; - copy = new BufferedImage(ow, oh, type); - } + if (copy == null) + { + int type = BufferedImage.TYPE_INT_ARGB; + copy = new BufferedImage(ow, oh, type); + } - Graphics g = copy.getGraphics(); - g.drawImage(img, 0, 0, null); - g.dispose(); + Graphics g = copy.getGraphics(); + g.drawImage(img, 0, 0, null); + g.dispose(); - int algo = Image.SCALE_SMOOTH; - Rectangle b = roundClip.getBounds(); - int sw = ow > oh ? -1 : b.width; - int sh = oh > ow ? -1 : b.height; - scaled = copy.getScaledInstance(sw, sh, algo); - /* - * We create a scaled instance from a BufferedImage copy - * rather than this.image directly, to avoid a ClassCast - * Exception bug in the JDK, where ColorModel was - * incorrectly casting an int array of input data into - * a byte array. I'm not sure why that bug exists nor - * why they haven't noticed it, but. - */ - repaint(); - } - if (img == scaled && (some || all)) - { - repaint(); - } - return all ? false : true; - } + int algo = Image.SCALE_SMOOTH; + Rectangle b = roundClip.getBounds(); + int sw = ow > oh ? -1 : b.width; + int sh = oh > ow ? -1 : b.height; + scaled = copy.getScaledInstance(sw, sh, algo); + /* + * We create a scaled instance from a BufferedImage copy + * rather than this.image directly, to avoid a ClassCast + * Exception bug in the JDK, where ColorModel was + * incorrectly casting an int array of input data into + * a byte array. I'm not sure why that bug exists nor + * why they haven't noticed it, but. + */ + repaint(); + } + if (img == scaled && (some || all)) + { + repaint(); + } + return all ? false : true; + } protected void paintComponent(Graphics g) { - g.drawImage(button, 0, 0, this); + g.drawImage(button, 0, 0, this); if (!isEnabled()) g.drawImage(disabledOverlay, 0, 0, this); - if (isFocusOwner()) + if (isFocusOwner()) g.drawImage(selectedOverlay, 0, 0, this); - if (scaled == null) return; + if (scaled == null) return; - Rectangle b = roundClip.getBounds(); - Shape defaultClip = g.getClip(); - g.setClip(roundClip); - g.drawImage(scaled, b.x, b.y, this); - getParent().repaint(); - // I don't know why, but when we repaint ourselves, our - // parent doesn't repaint, so nothing seems to happen. - g.setClip(defaultClip); + Rectangle b = roundClip.getBounds(); + Shape defaultClip = g.getClip(); + g.setClip(roundClip); + g.drawImage(scaled, b.x, b.y, this); + getParent().repaint(); + // I don't know why, but when we repaint ourselves, our + // parent doesn't repaint, so nothing seems to happen. + g.setClip(defaultClip); } private void @@ -396,31 +396,31 @@ implements KeyListener, MouseListener, FocusListener { public void keyPressed(KeyEvent eK) { - if (eK.getKeyCode() != KeyEvent.VK_SPACE) return; - doClick(); + if (eK.getKeyCode() != KeyEvent.VK_SPACE) return; + doClick(); } - public void - mouseClicked(MouseEvent eM) { announce(); } + public void + mouseClicked(MouseEvent eM) { announce(); } - public void - focusGained(FocusEvent eF) { repaint(); } + public void + focusGained(FocusEvent eF) { repaint(); } - public void - focusLost(FocusEvent eF) { repaint(); } + public void + focusLost(FocusEvent eF) { repaint(); } - public void - mousePressed(MouseEvent eM) { } + public void + mousePressed(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 keyReleased(KeyEvent eK) { } @@ -437,16 +437,16 @@ implements KeyListener, MouseListener, FocusListener { if (button == null) loadCommonImages(); setModel(new DefaultButtonModel()); - setFocusable(true); - setOpaque(false); + setFocusable(true); + setOpaque(false); int w = button.getWidth(null); int h = button.getHeight(null); setPreferredSize(new Dimension(w, h)); this.addKeyListener(this); - this.addMouseListener(this); - this.addFocusListener(this); + this.addMouseListener(this); + this.addFocusListener(this); } // - -%- - @@ -463,13 +463,13 @@ implements KeyListener, MouseListener, FocusListener { disabledOverlay = new ImageIcon(u2).getImage(); selectedOverlay = new ImageIcon(u3).getImage(); - int radius = 6; - roundClip = new Ellipse2D.Float( - radius, - radius, - button.getWidth(null) - (2 * radius), - button.getHeight(null) - (2 * radius) - ); + int radius = 6; + roundClip = new Ellipse2D.Float( + radius, + radius, + button.getWidth(null) - (2 * radius), + button.getHeight(null) - (2 * radius) + ); } } diff --git a/WindowUpdater.java b/WindowUpdater.java index f2259fe..0b9f4c4 100644 --- a/WindowUpdater.java +++ b/WindowUpdater.java @@ -43,11 +43,11 @@ WindowUpdater { private List timelineWindows; - private List - notificationWindows; + private List + notificationWindows; - private Clip - notificationSound; + private Clip + notificationSound; private Connection publicConn, @@ -65,14 +65,14 @@ WindowUpdater { userConn.reevaluate(); } - public synchronized void - add(NotificationsWindow updatee) - { + public synchronized void + add(NotificationsWindow updatee) + { if (!notificationWindows.contains(updatee)) notificationWindows.add(updatee); - userConn.reevaluate(); - } + userConn.reevaluate(); + } public synchronized void remove(TimelineWindow updatee) @@ -82,7 +82,7 @@ WindowUpdater { userConn.reevaluate(); } - public synchronized void + public synchronized void remove(NotificationsWindow updatee) { notificationWindows.remove(updatee); @@ -144,21 +144,21 @@ WindowUpdater { stop() { stopping = true; - thread.interrupt(); - try - { + thread.interrupt(); + try + { thread.join(3000); /* * That thread should notice it is * interrupted ppromptly, and close. */ if (thread.isAlive()) printStackTrace(thread); - } - catch (InterruptedException eIt) - { + } + catch (InterruptedException eIt) + { assert false; - } - thread = null; + } + thread = null; } public void @@ -186,21 +186,21 @@ WindowUpdater { thread.notifyAll(); } event = new StringBuilder(); - data = new StringBuilder(); - api.monitorTimeline(type, this); - // monitorTimeline should not return until - // the connection is closed, or this thread - // is interrupted. + data = new StringBuilder(); + api.monitorTimeline(type, this); + // monitorTimeline should not return until + // the connection is closed, or this thread + // is interrupted. - System.err.println( + System.err.println( "Stopped monitoring." + thread + " " + Thread.currentThread() ); - if (thread == Thread.currentThread()) thread = null; - /* - * This isn't thread safe. But I'd like the - * restart after sleep mode, so. - */ + if (thread == Thread.currentThread()) thread = null; + /* + * This isn't thread safe. But I'd like the + * restart after sleep mode, so. + */ } public void @@ -209,7 +209,7 @@ WindowUpdater { if (line.startsWith(":")) return; if (line.isEmpty()) - { + { handle(event.toString(), data.toString()); event.delete(0, event.length()); data.delete(0, event.length()); @@ -299,38 +299,38 @@ WindowUpdater { this.api = primaire.getMastodonApi(); this.timelineWindows = new ArrayList<>(); - this.notificationWindows = new ArrayList<>(); + this.notificationWindows = new ArrayList<>(); - publicConn = new Connection(); - publicConn.type = TimelineType.FEDERATED; + publicConn = new Connection(); + publicConn.type = TimelineType.FEDERATED; - userConn = new Connection(); - userConn.type = TimelineType.HOME; + userConn = new Connection(); + userConn.type = TimelineType.HOME; - loadNotificationSound(); + loadNotificationSound(); } - void - loadNotificationSound() - { - URL url = getClass().getResource("KDE_Dialog_Appear.wav"); - try { - Clip clip = AudioSystem.getClip(); - clip.open(AudioSystem.getAudioInputStream(url)); - notificationSound = clip; - } - catch (LineUnavailableException eLu) { - assert false; - } - catch (UnsupportedAudioFileException eUa) { - assert false; - } - catch (IOException eIo) { - assert false; - } - catch (IllegalArgumentException eIa) { - assert false; - } - } + void + loadNotificationSound() + { + URL url = getClass().getResource("KDE_Dialog_Appear.wav"); + try { + Clip clip = AudioSystem.getClip(); + clip.open(AudioSystem.getAudioInputStream(url)); + notificationSound = clip; + } + catch (LineUnavailableException eLu) { + assert false; + } + catch (UnsupportedAudioFileException eUa) { + assert false; + } + catch (IOException eIo) { + assert false; + } + catch (IllegalArgumentException eIa) { + assert false; + } + } }