mirror of
https://gitlab.com/biskuteri-cafe/JKomasto2.git
synced 2024-11-20 06:24:50 +01:00
301 lines
7.0 KiB
Java
301 lines
7.0 KiB
Java
|
|
||
|
import javax.swing.JFrame;
|
||
|
import javax.swing.JPanel;
|
||
|
import javax.swing.JTree;
|
||
|
import javax.swing.JOptionPane;
|
||
|
import javax.swing.BorderFactory;
|
||
|
import javax.swing.tree.DefaultTreeModel;
|
||
|
import javax.swing.tree.TreeNode;
|
||
|
import javax.swing.tree.MutableTreeNode;
|
||
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||
|
import javax.swing.tree.DefaultTreeCellRenderer;
|
||
|
import javax.swing.tree.TreeSelectionModel;
|
||
|
import javax.swing.event.TreeSelectionListener;
|
||
|
import javax.swing.event.TreeSelectionEvent;
|
||
|
import java.awt.Dimension;
|
||
|
import java.awt.Cursor;
|
||
|
import java.awt.BorderLayout;
|
||
|
import java.util.Enumeration;
|
||
|
import cafe.biskuteri.hinoki.Tree;
|
||
|
import java.io.IOException;
|
||
|
|
||
|
class
|
||
|
RepliesWindow extends JFrame {
|
||
|
|
||
|
private JKomasto
|
||
|
primaire;
|
||
|
|
||
|
private MastodonApi
|
||
|
api;
|
||
|
|
||
|
private PostWindow
|
||
|
postWindow;
|
||
|
|
||
|
// - -%- -
|
||
|
|
||
|
private RepliesComponent
|
||
|
display;
|
||
|
|
||
|
// ---%-@-%---
|
||
|
|
||
|
public void
|
||
|
showFor(String postId)
|
||
|
{
|
||
|
display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||
|
Tree<String> thread = getThread(postId);
|
||
|
if (thread != null) display.showThread(thread);
|
||
|
display.setCursor(null);
|
||
|
if (thread == null) dispose();
|
||
|
}
|
||
|
|
||
|
// - -%- -
|
||
|
|
||
|
public void
|
||
|
postSelected(Tree<String> post)
|
||
|
{
|
||
|
postWindow.displayEntity(post);
|
||
|
}
|
||
|
|
||
|
private Tree<String>
|
||
|
getThread(String postId)
|
||
|
{
|
||
|
abstract class Handler implements RequestListener {
|
||
|
|
||
|
boolean
|
||
|
failed = false;
|
||
|
|
||
|
// -=%=-
|
||
|
|
||
|
public void
|
||
|
connectionFailed(IOException eIo)
|
||
|
{
|
||
|
JOptionPane.showMessageDialog(
|
||
|
RepliesWindow.this,
|
||
|
"Failed to fetch post context...."
|
||
|
+ "\n" + eIo.getMessage()
|
||
|
);
|
||
|
failed = true;
|
||
|
}
|
||
|
|
||
|
public void
|
||
|
requestFailed(int httpCode, Tree<String> json)
|
||
|
{
|
||
|
JOptionPane.showMessageDialog(
|
||
|
RepliesWindow.this,
|
||
|
"Failed to fetch post context...."
|
||
|
+ "\n" + json.get("error").value
|
||
|
+ "\n(HTTP code: " + httpCode + ")"
|
||
|
);
|
||
|
failed = true;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
class TopPostIdGetter extends Handler {
|
||
|
|
||
|
String
|
||
|
topPostId;
|
||
|
|
||
|
// -=%=-
|
||
|
|
||
|
public void
|
||
|
requestSucceeded(Tree<String> json)
|
||
|
{
|
||
|
Tree<String> ancestors = json.get("ancestors");
|
||
|
if (ancestors.size() == 0) topPostId = postId;
|
||
|
else topPostId = ancestors.get(0).get("id").value;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
class DescendantsGetter extends Handler {
|
||
|
|
||
|
Tree<String>
|
||
|
descendants;
|
||
|
|
||
|
// -=%=-
|
||
|
|
||
|
public void
|
||
|
requestSucceeded(Tree<String> json)
|
||
|
{
|
||
|
descendants = json.get("descendants");
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
class PostGetter extends Handler {
|
||
|
|
||
|
Tree<String>
|
||
|
post;
|
||
|
|
||
|
// -=%=-
|
||
|
|
||
|
public void
|
||
|
requestSucceeded(Tree<String> json)
|
||
|
{
|
||
|
post = json;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
TopPostIdGetter phase1 = new TopPostIdGetter();
|
||
|
api.getPostContext(postId, phase1);
|
||
|
if (phase1.failed) return null;
|
||
|
DescendantsGetter phase2 = new DescendantsGetter();
|
||
|
api.getPostContext(phase1.topPostId, phase2);
|
||
|
if (phase2.failed) return null;
|
||
|
PostGetter phase3 = new PostGetter();
|
||
|
api.getSpecificPost(phase1.topPostId, phase3);
|
||
|
if (phase3.failed) return null;
|
||
|
|
||
|
Tree<String> thread = new Tree<String>();
|
||
|
phase3.post.key = "top";
|
||
|
thread.add(phase3.post);
|
||
|
thread.add(phase2.descendants);
|
||
|
return thread;
|
||
|
}
|
||
|
|
||
|
// ---%-@-%---
|
||
|
|
||
|
RepliesWindow(JKomasto primaire, PostWindow postWindow)
|
||
|
{
|
||
|
super("Thread");
|
||
|
|
||
|
this.primaire = primaire;
|
||
|
this.api = primaire.getMastodonApi();
|
||
|
this.postWindow = postWindow;
|
||
|
|
||
|
display = new RepliesComponent(this);
|
||
|
setContentPane(display);
|
||
|
setSize(384, 224);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
class
|
||
|
RepliesComponent extends JPanel
|
||
|
implements TreeSelectionListener {
|
||
|
|
||
|
private RepliesWindow
|
||
|
primaire;
|
||
|
|
||
|
private Tree<String>
|
||
|
thread;
|
||
|
|
||
|
// - -%- -
|
||
|
|
||
|
private JTree
|
||
|
tree;
|
||
|
|
||
|
// ---%-@-%---
|
||
|
|
||
|
public void
|
||
|
showThread(Tree<String> thread)
|
||
|
{
|
||
|
Enumeration<TreeNode> e;
|
||
|
DefaultMutableTreeNode root;
|
||
|
TreeItem item;
|
||
|
item = new TreeItem(thread.get("top"));
|
||
|
root = new DefaultMutableTreeNode(item);
|
||
|
for (Tree<String> desc: thread.get("descendants"))
|
||
|
{
|
||
|
String target = desc.get("in_reply_to_id").value;
|
||
|
assert target != null;
|
||
|
|
||
|
DefaultMutableTreeNode p = null;
|
||
|
e = root.breadthFirstEnumeration();
|
||
|
while (e.hasMoreElements())
|
||
|
{
|
||
|
DefaultMutableTreeNode node;
|
||
|
node = (DefaultMutableTreeNode)e.nextElement();
|
||
|
item = (TreeItem)node.getUserObject();
|
||
|
|
||
|
String postId = item.post.get("id").value;
|
||
|
if (postId.equals(target))
|
||
|
{
|
||
|
p = node;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (p == null)
|
||
|
{
|
||
|
assert false;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
item = new TreeItem(desc);
|
||
|
p.add(new DefaultMutableTreeNode(item));
|
||
|
}
|
||
|
|
||
|
tree.setModel(new DefaultTreeModel(root));
|
||
|
}
|
||
|
|
||
|
// - -%- -
|
||
|
|
||
|
public void
|
||
|
valueChanged(TreeSelectionEvent eT)
|
||
|
{
|
||
|
Object selected = eT.getPath().getLastPathComponent();
|
||
|
assert selected instanceof DefaultMutableTreeNode;
|
||
|
|
||
|
TreeItem item = (TreeItem)
|
||
|
((DefaultMutableTreeNode)selected)
|
||
|
.getUserObject();
|
||
|
|
||
|
primaire.postSelected(item.post);
|
||
|
}
|
||
|
|
||
|
// ---%-@-%---
|
||
|
|
||
|
private static class
|
||
|
TreeItem {
|
||
|
|
||
|
public Tree<String>
|
||
|
post;
|
||
|
|
||
|
// -=%=-
|
||
|
|
||
|
public String
|
||
|
toString()
|
||
|
{
|
||
|
String html = post.get("content").value;
|
||
|
return TimelineComponent.textApproximation(html);
|
||
|
}
|
||
|
|
||
|
// -=%=-
|
||
|
|
||
|
TreeItem(Tree<String> post)
|
||
|
{
|
||
|
this.post = post;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// ---%-@-%---
|
||
|
|
||
|
RepliesComponent(RepliesWindow primaire)
|
||
|
{
|
||
|
this.primaire = primaire;
|
||
|
|
||
|
tree = new JTree();
|
||
|
tree.setBackground(null);
|
||
|
DefaultTreeCellRenderer renderer;
|
||
|
renderer = new DefaultTreeCellRenderer();
|
||
|
renderer.setBackgroundNonSelectionColor(null);
|
||
|
renderer.setOpenIcon(null);
|
||
|
renderer.setClosedIcon(null);
|
||
|
renderer.setLeafIcon(null);
|
||
|
tree.setCellRenderer(renderer);
|
||
|
int mode = TreeSelectionModel.SINGLE_TREE_SELECTION;
|
||
|
tree.getSelectionModel().setSelectionMode(mode);
|
||
|
tree.addTreeSelectionListener(this);
|
||
|
tree.setFont(tree.getFont().deriveFont(16f));
|
||
|
|
||
|
setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
||
|
|
||
|
setLayout(new BorderLayout());
|
||
|
add(tree);
|
||
|
}
|
||
|
|
||
|
}
|