📄 gcstringprinter.java
字号:
/* * JMule - Java file sharing client * Copyright (C) 2007-2008 JMule team ( jmule@jmule.org / http://jmule.org ) * * Any parts of this program derived from other projects, or contributed * by third-party developers are copyrighted by their respective authors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */package org.jmule.ui.swt.common;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.eclipse.swt.SWT;import org.eclipse.swt.graphics.Color;import org.eclipse.swt.graphics.GC;import org.eclipse.swt.graphics.Image;import org.eclipse.swt.graphics.Point;import org.eclipse.swt.graphics.Rectangle;/** * Created on Aug 22, 2008 * @author binary256 * @author Olivier Chalouhi * @author TuxPaper (rewrite) * @version $Revision: 1.2 $ * Last changed by $Author: binary256_ $ on $Date: 2008/10/16 18:20:01 $ */public class GCStringPrinter { private static final boolean DEBUG = false; private static final String GOOD_STRING = "(/|,jI~`gy"; private static final int FLAG_SKIPCLIP = 1; private static final int FLAG_FULLLINESONLY = 2; private static final int FLAG_NODRAW = 4; private static final int FLAG_KEEP_URL_INFO = 8; private static final Pattern patHREF = Pattern.compile( "<\\s*?a\\s.*?href\\s*?=\\s*?\"(.+?)\".*?>(.*?)<\\s*?/a\\s*?>", Pattern.CASE_INSENSITIVE); private static final Pattern patAHREF_TITLE = Pattern.compile( "title=\\\"([^\\\"]+)", Pattern.CASE_INSENSITIVE); private static final Pattern patAHREF_TARGET = Pattern.compile( "target=\\\"([^\\\"]+)", Pattern.CASE_INSENSITIVE); //private static final Pattern patOver1000 = Pattern.compile("[^\n]{1010,}"); // Limit word/line length as OSX crashes on stringExtent on very very long words private static final int MAX_LINE_LEN = 4000; // max Word length can be same as line length since words are auto-split // across lines private static final int MAX_WORD_LEN = 4000; private boolean cutoff; private GC gc; private String string; private Rectangle printArea; private int swtFlags; private int printFlags; private Point size; private Color urlColor; private List listUrlInfo; private Image[] images; private float[] imageScales; public static class URLInfo { public String url; public String text; public Color urlColor; int relStartPos; // We could use a region, but that uses a resource that requires disposal List hitAreas = null; int titleLength; public String fullString; public String title; public String target; // @see java.lang.Object#toString() public String toString() { return super.toString() + ": relStart=" + relStartPos + ";url=" + url + ";title=" + text + ";hit=" + (hitAreas == null ? 0 : hitAreas.size()); } } private class LineInfo { public int width; String originalLine; String lineOutputed; int excessPos; public int relStartPos; public int height; public int imageIndexes[]; public LineInfo(String originalLine, int relStartPos) { this.originalLine = originalLine; this.relStartPos = relStartPos; } // @see java.lang.Object#toString() public String toString() { return super.toString() + ": relStart=" + relStartPos + ";xcess=" + excessPos + ";orig=" + originalLine + ";output=" + lineOutputed; } } public static boolean printString(GC gc, String string, Rectangle printArea) { return printString(gc, string, printArea, false, false); } public static boolean printString(GC gc, String string, Rectangle printArea, boolean skipClip, boolean fullLinesOnly) { return printString(gc, string, printArea, skipClip, fullLinesOnly, SWT.WRAP | SWT.TOP); } /** * * @param gc GC to print on * @param string Text to print * @param printArea Area of GC to print text to * @param skipClip Don't set any clipping on the GC. Text may overhang * printArea when this is true * @param fullLinesOnly If bottom of a line will be chopped off, do not display it * @param swtFlags SWT flags. SWT.CENTER, SWT.BOTTOM, SWT.TOP, SWT.WRAP * @return whether it fit */ public static boolean printString(GC gc, String string, Rectangle printArea, boolean skipClip, boolean fullLinesOnly, int swtFlags) { try { GCStringPrinter sp = new GCStringPrinter(gc, string, printArea, skipClip, fullLinesOnly, swtFlags); return sp.printString(); } catch (Exception e) { e.printStackTrace(); } return false; } /** * @param gc * @param string * @param printArea * @param printFlags * @param swtFlags * @return * * @since 3.0.4.3 */ private boolean _printString() { size = new Point(0, 0); if (string == null) { return false; } if (printArea == null || printArea.isEmpty()) { return false; } ArrayList lines = new ArrayList(); while (string.indexOf('\t') >= 0) { string = string.replace('\t', ' '); } boolean fullLinesOnly = (printFlags & FLAG_FULLLINESONLY) > 0; boolean skipClip = (printFlags & FLAG_SKIPCLIP) > 0; boolean noDraw = (printFlags & FLAG_NODRAW) > 0; boolean wrap = (swtFlags & SWT.WRAP) > 0; if ((printFlags & FLAG_KEEP_URL_INFO) == 0) { Matcher htmlMatcher = patHREF.matcher(string); boolean hasURL = htmlMatcher.find(); if (hasURL) { listUrlInfo = new ArrayList(1); while (hasURL) { URLInfo urlInfo = new URLInfo(); // Store the full ahref string once, then use substring which doesn't // create real strings :) urlInfo.fullString = htmlMatcher.group(); urlInfo.relStartPos = htmlMatcher.start(0); urlInfo.url = string.substring(htmlMatcher.start(1), htmlMatcher.end(1)); urlInfo.text = string.substring(htmlMatcher.start(2), htmlMatcher.end(2)); urlInfo.titleLength = urlInfo.text.length(); Matcher matcherTitle = patAHREF_TITLE.matcher(urlInfo.fullString); if (matcherTitle.find()) { urlInfo.title = string.substring(urlInfo.relStartPos + matcherTitle.start(1), urlInfo.relStartPos + matcherTitle.end(1)); } Matcher matcherTarget = patAHREF_TARGET.matcher(urlInfo.fullString); if (matcherTarget.find()) { urlInfo.target = string.substring(urlInfo.relStartPos + matcherTarget.start(1), urlInfo.relStartPos + matcherTarget.end(1)); } //System.out.println("URLINFO! " + urlInfo.fullString // + "\ntarget=" // + urlInfo.target + "\ntt=" + urlInfo.title + "\nurl=" // + urlInfo.url + "\ntext=" + urlInfo.text + "\n\n"); string = htmlMatcher.replaceFirst(urlInfo.text.replaceAll("\\$", "\\\\\\$")); listUrlInfo.add(urlInfo); htmlMatcher = patHREF.matcher(string); hasURL = htmlMatcher.find(urlInfo.relStartPos); } } } else { Matcher htmlMatcher = patHREF.matcher(string); string = htmlMatcher.replaceAll("$2"); } Rectangle rectDraw = new Rectangle(printArea.x, printArea.y, printArea.width, printArea.height); Rectangle oldClipping = null; try { if (!skipClip && !noDraw) { oldClipping = gc.getClipping(); // Protect the GC from drawing outside the drawing area gc.setClipping(printArea); } // Process string line by line int iCurrentHeight = 0; int currentCharPos = 0; int pos1 = string.indexOf('\n'); int pos2 = string.indexOf('\r'); if (pos2 == -1) { pos2 = pos1; } int posNewLine = Math.min(pos1, pos2); if (posNewLine < 0) { posNewLine = string.length(); } int posLastNewLine = 0; while (posNewLine >= 0 && posLastNewLine < string.length()) { String sLine = string.substring(posLastNewLine, posNewLine); do { LineInfo lineInfo = new LineInfo(sLine, currentCharPos); lineInfo = processLine(gc, lineInfo, printArea, wrap, fullLinesOnly, false); String sProcessedLine = (String) lineInfo.lineOutputed; if (sProcessedLine != null && sProcessedLine.length() > 0) { if (lineInfo.width == 0 || lineInfo.height == 0) { Point gcExtent = gc.stringExtent(sProcessedLine); if (lineInfo.width == 0) { lineInfo.width = gcExtent.x; } if (lineInfo.height == 0) { lineInfo.height = gcExtent.y; } } Point extent = new Point(lineInfo.width, lineInfo.height); iCurrentHeight += extent.y; boolean isOverY = iCurrentHeight > printArea.height; if (DEBUG) { System.out.println("Adding Line: [" + sProcessedLine + "]" + sProcessedLine.length() + "; h=" + iCurrentHeight + "(" + printArea.height + "). fullOnly?" + fullLinesOnly + ". Excess: " + lineInfo.excessPos); } if (isOverY && !fullLinesOnly) { //fullLinesOnly = true; // <-- don't know why we needed this lines.add(lineInfo); } else if (isOverY && fullLinesOnly) { String excess = lineInfo.excessPos >= 0 ? sLine.substring(lineInfo.excessPos) : null; if (excess != null) { if (fullLinesOnly) { if (lines.size() > 0) { lineInfo = (LineInfo) lines.remove(lines.size() - 1); sProcessedLine = lineInfo.originalLine.length() > MAX_LINE_LEN ? lineInfo.originalLine.substring(0, MAX_LINE_LEN) : lineInfo.originalLine; //sProcessedLine = ((LineInfo) lines.remove(lines.size() - 1)).originalLine; extent = gc.stringExtent(sProcessedLine); } else { if (DEBUG) { System.out.println("No PREV!?"); } return false; } } else { sProcessedLine = sProcessedLine.length() > MAX_LINE_LEN ? sProcessedLine.substring(0, MAX_LINE_LEN) : sProcessedLine; } if (excess.length() > MAX_LINE_LEN) { excess = excess.substring(0, MAX_LINE_LEN); } StringBuffer outputLine = new StringBuffer(sProcessedLine); lineInfo.width = extent.x; int newExcessPos = processWord(gc, sProcessedLine, " " + excess, printArea, false, lineInfo, outputLine, new StringBuffer()); if (DEBUG) { System.out.println(" with word [" + excess + "] len is " + lineInfo.width + "(" + printArea.width + ") w/excess " + newExcessPos);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -