mirror of
https://gitlab.com/biskuteri-cafe/JKomasto2.git
synced 2024-11-20 05:24:50 +01:00
Added attempt at using AttributedString.
Somewhat works now, but I think we'll abandon it..
This commit is contained in:
parent
71b9c496c4
commit
e4f13ad8c8
@ -15,10 +15,10 @@ BasicHTMLParser {
|
|||||||
{
|
{
|
||||||
List<String> segments;
|
List<String> segments;
|
||||||
segments = distinguishTagsFromPcdata(html);
|
segments = distinguishTagsFromPcdata(html);
|
||||||
segments = evaluateHtmlEscapes(segments);
|
|
||||||
|
|
||||||
Tree<String> document;
|
Tree<String> document;
|
||||||
document = toNodes(segments);
|
document = toNodes(segments);
|
||||||
|
document = evaluateHtmlEscapes(document);
|
||||||
document = distinguishEmojisFromText(document);
|
document = distinguishEmojisFromText(document);
|
||||||
document = hierarchise(document);
|
document = hierarchise(document);
|
||||||
|
|
||||||
@ -61,51 +61,6 @@ BasicHTMLParser {
|
|||||||
return returnee;
|
return returnee;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String>
|
|
||||||
evaluateHtmlEscapes(List<String> strings)
|
|
||||||
{
|
|
||||||
List<String> returnee = new ArrayList<>();
|
|
||||||
|
|
||||||
for (String string: strings)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
returnee.add(empty(whole));
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnee;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Tree<String>
|
private static Tree<String>
|
||||||
toNodes(List<String> segments)
|
toNodes(List<String> segments)
|
||||||
{
|
{
|
||||||
@ -181,6 +136,22 @@ BasicHTMLParser {
|
|||||||
return returnee;
|
return returnee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Tree<String>
|
||||||
|
evaluateHtmlEscapes(Tree<String> nodes)
|
||||||
|
{
|
||||||
|
for (Tree<String> node: nodes)
|
||||||
|
{
|
||||||
|
node.value = evaluateHtmlEscapes(node.value);
|
||||||
|
for (Tree<String> attr: node)
|
||||||
|
{
|
||||||
|
attr.key = evaluateHtmlEscapes(attr.key);
|
||||||
|
attr.value = evaluateHtmlEscapes(attr.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
private static Tree<String>
|
private static Tree<String>
|
||||||
distinguishEmojisFromText(Tree<String> nodes)
|
distinguishEmojisFromText(Tree<String> nodes)
|
||||||
{
|
{
|
||||||
@ -233,8 +204,8 @@ BasicHTMLParser {
|
|||||||
hierarchise(Tree<String> nodes)
|
hierarchise(Tree<String> nodes)
|
||||||
{
|
{
|
||||||
Tree<String> root = new Tree<String>();
|
Tree<String> root = new Tree<String>();
|
||||||
root.add(new Tree<>("attributes", null));
|
root.key = "tag";
|
||||||
root.get(0).add(new Tree<>("html", null));
|
root.add(new Tree<>("html", null));
|
||||||
root.add(new Tree<>("children", null));
|
root.add(new Tree<>("children", null));
|
||||||
|
|
||||||
Deque<Tree<String>> parents = new LinkedList<>();
|
Deque<Tree<String>> parents = new LinkedList<>();
|
||||||
@ -246,6 +217,9 @@ BasicHTMLParser {
|
|||||||
assert node.size() > 0;
|
assert node.size() > 0;
|
||||||
String tagName = node.get(0).key;
|
String tagName = node.get(0).key;
|
||||||
|
|
||||||
|
assert node.get("children") == null;
|
||||||
|
node.add(new Tree<>("children", null));
|
||||||
|
|
||||||
boolean isClosing, selfClosing;
|
boolean isClosing, selfClosing;
|
||||||
isClosing = tagName.startsWith("/");
|
isClosing = tagName.startsWith("/");
|
||||||
selfClosing = node.get("/") != null;
|
selfClosing = node.get("/") != null;
|
||||||
@ -258,30 +232,18 @@ BasicHTMLParser {
|
|||||||
parent = parents.pop();
|
parent = parents.pop();
|
||||||
grandparent = parents.peek();
|
grandparent = parents.peek();
|
||||||
|
|
||||||
assert tagName.equals(
|
String pTagName = parent.get(0).key;
|
||||||
"/"
|
assert tagName.equals("/" + pTagName);
|
||||||
+ parent.get("attributes").get(0).key
|
|
||||||
);
|
|
||||||
|
|
||||||
grandparent.get("children").add(parent);
|
grandparent.get("children").add(parent);
|
||||||
}
|
}
|
||||||
else if (selfClosing)
|
else if (selfClosing)
|
||||||
{
|
{
|
||||||
Tree<String> elem = new Tree<String>();
|
parents.peek().get("children").add(node);
|
||||||
node.key = "attributes";
|
|
||||||
elem.add(node);
|
|
||||||
elem.add(new Tree<>("children", null));
|
|
||||||
|
|
||||||
parents.peek().get("children").add(elem);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Tree<String> elem = new Tree<String>();
|
parents.push(node);
|
||||||
node.key = "attributes";
|
|
||||||
elem.add(node);
|
|
||||||
elem.add(new Tree<>("children", null));
|
|
||||||
|
|
||||||
parents.push(elem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -325,4 +287,42 @@ BasicHTMLParser {
|
|||||||
return returnee;
|
return returnee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
0
ClipboardApi.java
Executable file → Normal file
0
ClipboardApi.java
Executable file → Normal file
0
ComposeWindow.java
Executable file → Normal file
0
ComposeWindow.java
Executable file → Normal file
0
ImageApi.java
Executable file → Normal file
0
ImageApi.java
Executable file → Normal file
0
ImageWindow.java
Executable file → Normal file
0
ImageWindow.java
Executable file → Normal file
0
JKomasto.java
Executable file → Normal file
0
JKomasto.java
Executable file → Normal file
0
KDE_Dialog_Appear.wav
Executable file → Normal file
0
KDE_Dialog_Appear.wav
Executable file → Normal file
0
LoginWindow.java
Executable file → Normal file
0
LoginWindow.java
Executable file → Normal file
12
MastodonApi.java
Executable file → Normal file
12
MastodonApi.java
Executable file → Normal file
@ -581,15 +581,23 @@ MastodonApi {
|
|||||||
debugPrint(Tree<String> tree, String prefix)
|
debugPrint(Tree<String> tree, String prefix)
|
||||||
{
|
{
|
||||||
System.err.print(prefix);
|
System.err.print(prefix);
|
||||||
System.err.print(tree.key);
|
System.err.print(deescape(tree.key));
|
||||||
System.err.print(": ");
|
System.err.print(": ");
|
||||||
System.err.println(tree.value);
|
System.err.println(deescape(tree.value));
|
||||||
for (Tree<String> child: tree)
|
for (Tree<String> child: tree)
|
||||||
debugPrint(child, prefix + " ");
|
debugPrint(child, prefix + " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// - -%- -
|
// - -%- -
|
||||||
|
|
||||||
|
private static String
|
||||||
|
deescape(String string)
|
||||||
|
{
|
||||||
|
if (string == null) return string;
|
||||||
|
string = string.replaceAll("\n", "\\\\n");
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
private static Tree<String>
|
private static Tree<String>
|
||||||
fromPlain(Reader r)
|
fromPlain(Reader r)
|
||||||
throws IOException
|
throws IOException
|
||||||
|
0
NotificationsWindow.java
Executable file → Normal file
0
NotificationsWindow.java
Executable file → Normal file
27
PostWindow.java
Executable file → Normal file
27
PostWindow.java
Executable file → Normal file
@ -58,6 +58,9 @@ PostWindow extends JFrame {
|
|||||||
private PostComponent
|
private PostComponent
|
||||||
display;
|
display;
|
||||||
|
|
||||||
|
private static JFrame
|
||||||
|
temp;
|
||||||
|
|
||||||
// - -%- -
|
// - -%- -
|
||||||
|
|
||||||
private static final DateTimeFormatter
|
private static final DateTimeFormatter
|
||||||
@ -98,6 +101,28 @@ PostWindow extends JFrame {
|
|||||||
|
|
||||||
display.setEmojiUrls(post.emojiUrls);
|
display.setEmojiUrls(post.emojiUrls);
|
||||||
|
|
||||||
|
{
|
||||||
|
Tree<String> html = BasicHTMLParser.parse(post.text);
|
||||||
|
Tree<String> emojiMap = new Tree<>();
|
||||||
|
for (String[] m: post.emojiUrls)
|
||||||
|
{
|
||||||
|
emojiMap.add(new Tree<>(m[0], m[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp == null)
|
||||||
|
{
|
||||||
|
temp = new JFrame();
|
||||||
|
temp.setSize(256, 256);
|
||||||
|
temp.setLocationByPlatform(true);
|
||||||
|
temp.setVisible(true);
|
||||||
|
RichTextPane2 pane = new RichTextPane2();
|
||||||
|
pane.setFont(new Font("Dialog", Font.PLAIN, 18));
|
||||||
|
temp.setContentPane(pane);
|
||||||
|
}
|
||||||
|
((RichTextPane2)temp.getContentPane())
|
||||||
|
.setText(html, emojiMap);
|
||||||
|
}
|
||||||
|
|
||||||
display.setHtml(post.text);
|
display.setHtml(post.text);
|
||||||
display.setFavourited(post.favourited);
|
display.setFavourited(post.favourited);
|
||||||
display.setBoosted(post.boosted);
|
display.setBoosted(post.boosted);
|
||||||
@ -428,8 +453,6 @@ implements ActionListener {
|
|||||||
public void
|
public void
|
||||||
setHtml(String n)
|
setHtml(String n)
|
||||||
{
|
{
|
||||||
BasicHTMLParser.parse(n);
|
|
||||||
|
|
||||||
RichTextPane.Builder b = new RichTextPane.Builder();
|
RichTextPane.Builder b = new RichTextPane.Builder();
|
||||||
Tree<String> nodes = RudimentaryHTMLParser.depthlessRead(n);
|
Tree<String> nodes = RudimentaryHTMLParser.depthlessRead(n);
|
||||||
for (Tree<String> node: nodes)
|
for (Tree<String> node: nodes)
|
||||||
|
0
ProfileWindow.java
Executable file → Normal file
0
ProfileWindow.java
Executable file → Normal file
0
RepliesWindow.java
Executable file → Normal file
0
RepliesWindow.java
Executable file → Normal file
0
RequestListener.java
Executable file → Normal file
0
RequestListener.java
Executable file → Normal file
0
RichTextPane.java
Executable file → Normal file
0
RichTextPane.java
Executable file → Normal file
480
RichTextPane2.java
Normal file
480
RichTextPane2.java
Normal file
@ -0,0 +1,480 @@
|
|||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import java.text.AttributedString;
|
||||||
|
import java.text.AttributedCharacterIterator;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.font.TextAttribute;
|
||||||
|
import java.awt.event.ComponentListener;
|
||||||
|
import java.awt.event.ComponentEvent;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import cafe.biskuteri.hinoki.Tree;
|
||||||
|
|
||||||
|
class
|
||||||
|
RichTextPane2 extends JComponent
|
||||||
|
implements ComponentListener {
|
||||||
|
|
||||||
|
private AttributedString
|
||||||
|
text;
|
||||||
|
|
||||||
|
// ---%-@-%---
|
||||||
|
|
||||||
|
public void
|
||||||
|
setText(Tree<String> html, Tree<String> emojiMap)
|
||||||
|
{
|
||||||
|
Tree<String> 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<AStrSegment> segments = new ArrayList<>();
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (Tree<String> 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;
|
||||||
|
|
||||||
|
String shortcode = command.value;
|
||||||
|
String url = null;
|
||||||
|
Tree<String> 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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.text = astr;
|
||||||
|
componentResized(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - -%- -
|
||||||
|
|
||||||
|
public void
|
||||||
|
componentResized(ComponentEvent eC)
|
||||||
|
{
|
||||||
|
int w = getWidth(), h = getHeight();
|
||||||
|
|
||||||
|
// We're going to evaluate the
|
||||||
|
// line and off-screen attributes.
|
||||||
|
|
||||||
|
FontMetrics fm = getFontMetrics(getFont());
|
||||||
|
Graphics g = getGraphics();
|
||||||
|
int x = 0, y = fm.getAscent();
|
||||||
|
|
||||||
|
AttributedCharacterIterator it;
|
||||||
|
it = text.getIterator();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text.addAttribute(TextAttribute.FONT, getFont());
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void
|
||||||
|
paintComponent(Graphics g)
|
||||||
|
{
|
||||||
|
int w = getWidth(), h = getHeight();
|
||||||
|
g.clearRect(0, 0, w, h);
|
||||||
|
|
||||||
|
FontMetrics fm = g.getFontMetrics();
|
||||||
|
|
||||||
|
AttributedCharacterIterator it;
|
||||||
|
it = text.getIterator();
|
||||||
|
|
||||||
|
((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();
|
||||||
|
|
||||||
|
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 (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
|
||||||
|
componentShown(ComponentEvent eC) { }
|
||||||
|
|
||||||
|
public void
|
||||||
|
componentHidden(ComponentEvent eC) { }
|
||||||
|
|
||||||
|
// - -%- -
|
||||||
|
|
||||||
|
private static Boolean
|
||||||
|
isBasicLatin(char c)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String
|
||||||
|
toText(Tree<String> node)
|
||||||
|
{
|
||||||
|
Tree<String> 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<String> child: children)
|
||||||
|
{
|
||||||
|
b.append(toText(child));
|
||||||
|
}
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Tree<String>
|
||||||
|
turnIntoCommands(Tree<String> tag)
|
||||||
|
{
|
||||||
|
assert tag.key.equals("tag");
|
||||||
|
Tree<String> returnee = new Tree<String>();
|
||||||
|
|
||||||
|
String tagName = tag.get(0).key;
|
||||||
|
Tree<String> children = tag.get("children");
|
||||||
|
|
||||||
|
if (tagName.equals("a"))
|
||||||
|
{
|
||||||
|
String url = tag.get("href").value;
|
||||||
|
Tree<String> 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<String> 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<String> child: children)
|
||||||
|
{
|
||||||
|
if (!child.key.equals("tag"))
|
||||||
|
{
|
||||||
|
returnee.add(child);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
child = turnIntoCommands(child);
|
||||||
|
for (Tree<String> command: child)
|
||||||
|
{
|
||||||
|
returnee.add(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tagName.equals("p"))
|
||||||
|
{
|
||||||
|
returnee.add(new Tree<>("text", "\n"));
|
||||||
|
returnee.add(new Tree<>("text", "\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnee;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---%-@-%---
|
||||||
|
|
||||||
|
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 int
|
||||||
|
COUNT = 7;
|
||||||
|
|
||||||
|
// -=%=-
|
||||||
|
|
||||||
|
private
|
||||||
|
Attribute(String name) { super(name); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---%-@-%---
|
||||||
|
|
||||||
|
RichTextPane2()
|
||||||
|
{
|
||||||
|
this.addComponentListener(this);
|
||||||
|
text = new AttributedString("");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
0
RudimentaryHTMLParser.java
Executable file → Normal file
0
RudimentaryHTMLParser.java
Executable file → Normal file
0
TimelineWindow.java
Executable file → Normal file
0
TimelineWindow.java
Executable file → Normal file
0
TwoToggleButton.java
Executable file → Normal file
0
TwoToggleButton.java
Executable file → Normal file
0
WindowUpdater.java
Executable file → Normal file
0
WindowUpdater.java
Executable file → Normal file
0
notifOptions.txt
Executable file → Normal file
0
notifOptions.txt
Executable file → Normal file
0
notifOptions.txt~
Executable file → Normal file
0
notifOptions.txt~
Executable file → Normal file
7
run
7
run
@ -1,13 +1,14 @@
|
|||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
CLASSPATH=.:../Hinoki:/usr/share/java/javax.json.jar
|
CLASSPATH=.:../Hinoki:/usr/share/java/javax.json.jar
|
||||||
OPTIONS=
|
COMPILE_OPTIONS=-Xlint:deprecation
|
||||||
|
RUNTIME_OPTIONS=-ea
|
||||||
|
|
||||||
c:
|
c:
|
||||||
javac -cp $(CLASSPATH) $(OPTIONS) *.java
|
javac -cp $(CLASSPATH) $(COMPILE_OPTIONS) *.java
|
||||||
|
|
||||||
r:
|
r:
|
||||||
java -cp $(CLASSPATH) $(OPTIONS) -ea JKomasto
|
java -cp $(CLASSPATH) $(RUNTIME_OPTIONS) JKomasto
|
||||||
|
|
||||||
cr: c r
|
cr: c r
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user