sclass JFastLogView_noWrap extends JComponent implements Scrollable { LS lines = syncList(); bool endsWithNewLine, verbose; public Dimension getPreferredScrollableViewportSize() { ret getPreferredSize(); } public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { return 20; } public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { ret (direction == SwingConstants.HORIZONTAL ? visibleRect.width : visibleRect.height)*5/6; } public bool getScrollableTracksViewportWidth() { false; } public bool getScrollableTracksViewportHeight() { false; } public void paint(Graphics g) { //if (verbose) _print("JFastLogView_noWrap painting"); int w = getWidth(), h = getHeight(); g.setColor(getBackground()); g.fillRect(0, 0, w, h); g.setColor(getForeground()); FontMetrics fm = componentFontMetrics(this); int fh = fm.getHeight(); Rectangle clip = g.getClipBounds(); int start, end; if (clip == null) { start = 0; end = l(lines); } else { start = max(0, clip.y/fh); end = min(l(lines), idiv_ceil(clip.y+clip.height, fh)); } //printVars(+start, +end); int y = fm.getAscent()+start*fh; for (int i = start; i < end; i++) { S s = get(lines, i); if (s != null) g.drawString(s, 0, y); y += fh; } //if (verbose) _print("JFastLogView_noWrap painted"); } public Dimension getPreferredSize() { FontMetrics fm = componentFontMetrics(this); if (fm == null) ret new Dimension(50, 50); // not renderable yet int fh = fm.getHeight(); int w = 0; for i over lines: { S s = get(lines, i); w = max(w, fm.stringWidth(unnull(s))); // TODO: just count chars } ret new Dimension(w, fh*l(lines)); } *() {} *(S text) { setText(text); } { componentPopupMenuItem(this, "Copy full text", r copyFullText); } // API // returns true if changed bool setLines(Collection lines) { LS newList = asSyncList(lines); if (eq(this.lines, newList)) false; this.lines = newList; _revalidate(this); true; } // returns true if changed bool setText(S text) { endsWithNewLine = endsWithNewLine(text); ret setLines(lines(text)); } void append(S text) { if (nempty(text)) setText(getText() + text); } S getText() { ret lines_rtrimIf(!endsWithNewLine, cloneList(lines)); } void copyFullText { copyTextToClipboard(getText()); } }