⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 contenthelper.java

📁 java写的qq代码实现qq的部分功能
💻 JAVA
字号:
/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 luma <stubma@163.com>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.tsinghua.lumaqq.widgets.rich;

import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;

/**
 * 提供一些帮助方法
 * 
 * @author luma
 */
public class ContentHelper {
    private IRichContent content;
    private ILineStyler styler;
    private ImageResolver resolver;
    
    // 行高数组
    private int[] lineHeight;
    
    public ContentHelper(IRichContent content, ImageResolver resolver) {
        this.resolver = resolver;
        this.content = content;
        this.styler = content.getLineStyler();
        lineHeight = new int[10];
    }
        
    /**
     * 成倍扩展行高数组
     */
    public void expandLineHeightDouble() {
        int[] newLineHeight = new int[lineHeight.length << 1];
        System.arraycopy(lineHeight, 0, newLineHeight, 0, lineHeight.length);
        lineHeight = newLineHeight;
    }
    
    /**
     * 给定一行的行号和行内偏移,计算这个偏移的X坐标,比如这个偏移是1,那么就是这一行
     * 第一个字符的宽度
     * 
     * @param gc
     * 		GC
     * @param lineIndex
     * 		行号
     * @param offsetInLine
     * 		行内偏移
     * @return
     */
    public int getXAtOffset(GC gc, int lineIndex, int offsetInLine) {
        StringBuffer sb = new StringBuffer(content.getLine(lineIndex).substring(0, offsetInLine));
        return getWidth(gc, sb, lineIndex);
    }    
    
    /**
     * 得到一个字符串的宽度,使用lineIndex行的style来检查
     * 
     * @param gc
     * 		GC
     * @param line
     * 		字符串缓冲区
     * @param lineIndex
     * 		行号
     * @return
     * 		宽度
     */
    public int getWidth(GC gc, StringBuffer line, int lineIndex) {
        int width = 0;
		int i = 0;
		int j = findNextImage(line, 0);
		for (; j != -1; i = j, j = findNextImage(line, i)) {
			Image image = resolver.getImage(line.charAt(j), line.charAt(j + 1));
			width += image.getBounds().width;
			line.delete(j, j + 2);
		}
		Font oldFont = gc.getFont();
		gc.setFont(styler.getLineFont(lineIndex));
		width += gc.textExtent(line.toString()).x;
		gc.setFont(oldFont);
		return width;
    }
    
    /**
     * 得到x象素位置在某行中的偏移,然后再得到绝对偏移
     * 
     * @param gc
     * 		GC
     * @param lineIndex
     * 		行号
     * @param x
     * 		x象素位置
     * @return
     * 		字符绝对偏移
     */
    public int getOffsetAtX(GC gc, int lineIndex, int x) {
        int lineOffset = content.getLineStartOffset(lineIndex);
        // 先检查x是否小于0
        if(x < 0)
            return lineOffset;
        else {
            x++;
            
            // 得到行长度,如果x大于行长,直接返回
            char[] c = content.getLine(lineIndex).toCharArray();
            StringBuffer sb = new StringBuffer();
            sb.append(c);
            int len = getWidth(gc, sb, lineIndex);
            if(x >= len)
                return lineOffset + c.length;
            else {
                // 先模糊定位到一个偏移附近再查找
                int referenceOffset = c.length * x / len;
                if(referenceOffset > 0)
                    referenceOffset--;
                if(content.isImageTag(lineOffset + referenceOffset - 1))
                    referenceOffset++;
                sb.delete(0, sb.length());
                sb.append(c, 0, referenceOffset);
                len = getWidth(gc, sb, lineIndex);
                boolean iniFlag = x > len;
                boolean flag = iniFlag;
                while(flag == iniFlag) {
                    if(x > len) {
                        if(content.isImageTag(lineOffset + referenceOffset))
                            referenceOffset += 2;
                        else
                            referenceOffset++;
                    } else {
                        if(content.isImageTag(lineOffset + referenceOffset - 2))
                            referenceOffset -= 2;
                        else
                            referenceOffset--;
                    }
                    sb.delete(0, sb.length());
                    sb.append(c, 0, referenceOffset);
                    len = getWidth(gc, sb, lineIndex);
                    flag = x > len;
                }
                if(iniFlag) {
                    referenceOffset--;
                    if(content.isImageTag(lineOffset + referenceOffset - 1))
                        referenceOffset--;
                }
                return lineOffset + referenceOffset;
            }
        }
    }
    
	/**
	 * 找寻下一个图片tag的开始位置
	 * 
	 * @param line
	 * 		行
	 * @param fromIndex
	 * 		从何处开始搜索
	 * @return
	 * 		tag索引位置,或者-1表示没有了
	 */
	public int findNextImage(StringBuffer line, int fromIndex) {
	    int len = line.length();
	    for(int i = fromIndex; i < len; i++) {
	        char c = line.charAt(i);
	        if(c == IRichContent.DEFAULT_FACE_TAG ||
	                c == IRichContent.CUSTOM_FACE_TAG)
	            return i;
	    }
	    return -1;
	}
	
	/**
	 * 找寻下一个图片tag的开始位置
	 * 
	 * @param line
	 * 		行
	 * @param fromIndex
	 * 		从何处开始搜索
	 * @return
	 * 		tag索引位置,或者-1表示没有了
	 */
	public int findNextImage(String line, int fromIndex) {
	    int len = line.length();
	    for(int i = fromIndex; i < len; i++) {
	        char c = line.charAt(i);
	        if(c == IRichContent.DEFAULT_FACE_TAG ||
	                c == IRichContent.CUSTOM_FACE_TAG)
	            return i;
	    }
	    return -1;
	}
	
	/**
	 * 找寻上一个图片tag的开始位置
	 * 
	 * @param line
	 * @param fromIndex
	 * @return
	 */
	public int findPreviousImage(String line, int fromIndex) {
	    for(int i = fromIndex; i >= 0; i--) {
	        char c = line.charAt(i);
	        if(c == IRichContent.DEFAULT_FACE_TAG ||
	                c == IRichContent.CUSTOM_FACE_TAG)
	            return i;
	    }
	    return -1;
	}
    
    /**
     * 清空行高缓存数据
     */
    public void clearLineHeightCache() {
        for(int i = 0; i < lineHeight.length; i++)
            lineHeight[i] = 0;
    }
    
    /**
     * 清楚某一行的行高缓存
     * 
     * @param lineIndex
     * 		行号
     */
    public void clearLineHeightCache(int lineIndex) {
        lineHeight[lineIndex] = 0;
    }
    
    /**
     * 清楚start行到end行的行高数据,用在行删除时
     * 
     * @param start
     * 		开始行号
     * @param length
     * 		要删除的行数
     */
    public void removeLineHeight(int start, int length) {
        if(start + length < lineHeight.length)
            System.arraycopy(lineHeight, start + length, lineHeight, start, lineHeight.length - start - length);
    }
    
    /**
     * 插入一些行高数据空间
     * 
     * @param startIndex
     * 		插入的起始位置
     * @param numLines
     * 		要插入的行数
     * @param oldLineCount
     * 		没插入前的行数
     */
    public void insertLineHeight(int startIndex, int numLines, int oldLineCount) {
        while(oldLineCount + numLines > lineHeight.length)
            expandLineHeightDouble();
        System.arraycopy(lineHeight, startIndex, lineHeight, startIndex + numLines, oldLineCount - startIndex);
        for(int i = startIndex; i < startIndex + numLines; i++)
            lineHeight[i] = 0;
    }
    
    /**
     * 给出绝对y偏移,得到y所在的行数
     * 
     * @param gc
     * 		GC
     * @param y
     * 		y偏移
     * @return
     * 		行号
     */
    public int getLineAtY(GC gc, int y) {
        int i;
        int lineCount = content.getLineCount();
        for(i = 0; i < lineCount && y > 0; i++)
            y -= getLineHeight(gc, i);       
        return (i == 0) ? 0 : (i - 1);
    }

    /**
     * 得到从startLine开始,endLine结束的行的总高度(不包括endLine)
     * 
     * @param gc
     * 		GC
     * @param startLine
     * 		开始行号
     * @param endLine
     * 		结束行号
     * @return
     * 		总高度
     */
    public int getHeightOfLines(GC gc, int startLine, int endLine) {
        int h = 0;
        for(int i = startLine; i < endLine; i++)
            h += getLineHeight(gc, i);
        return h;
    }
    
    /**
     * 得到某行的起始绝对Y偏移
     * 
     * @param gc
     * 		GC
     * @param lineIndex
     * 		行号
     * @return
     * 		绝对Y
     */
    public int getYOfLine(GC gc, int lineIndex) {
        if(lineIndex > content.getLineCount())
            lineIndex = content.getLineCount();
        int y = 0;
        for(int i = 0; i < lineIndex; i++)
            y += getLineHeight(gc, i);
        return y;
    }
    
    /**
     * 得到某行的高度
     * 
     * @param gc
     * 		GC
     * @param lineIndex
     * 		行号
     * @return
     * 		高度, in pixel
     */
    public int getLineHeight(GC gc, int lineIndex) {
        while(lineIndex >= lineHeight.length)
            expandLineHeightDouble();
        
        if(lineHeight[lineIndex] == 0) {
	        String line = content.getLine(lineIndex);
	        Font oldFont = gc.getFont();
	        Font lineFont = styler.getLineFont(lineIndex);
	        gc.setFont(lineFont);
	        int faceHeight = getMaxFaceHeight(IRichContent.CUSTOM_FACE_TAG, line);
            faceHeight = Math.max(faceHeight, getMaxFaceHeight(IRichContent.DEFAULT_FACE_TAG, line));
	        int h = Math.max(faceHeight, gc.textExtent(line).y);
	        gc.setFont(oldFont);
	        lineHeight[lineIndex] = h;
	        return h;            
        } else
            return lineHeight[lineIndex];
    }
    
    /**
     * 检查行中是否包含有指定类型的图片
     * 
     * @param tag
     * 		图片类型标识
     * @param line
     * 		行
     * @return
     * 		true表示有
     */
    private boolean hasFace(int tag, String line) {
        return line.indexOf((char)tag) != -1;
    }
    
    /**
     * 在一行中寻找图片的最大高度
     * 
     * @param line
     * @return
     */
    public int getMaxFaceHeight(int tag, String line) {
        int maxHeight = 0;
        int i = line.indexOf(tag);
        for(; i != -1; i = line.indexOf(tag, i + 1)) {
            int fIndex = line.charAt(i + 1);
            Image face = resolver.getImage(tag, fIndex);
            if(face != null)
                maxHeight = Math.max(maxHeight, face.getBounds().height);
        }
        return maxHeight;
    }

    /**
     * 根据一个最大宽度把一行划分成多行
     * 
     * @param gc
     * 		GC
     * @param width
     * 		最大行宽
     * @param lineIndex
     * 		要划分的行号
     * @return
     * 		各个行的绝对起始偏移
     */
    public int[] splitLine(GC gc, int width, int lineIndex) {
        int lineStartOffset = content.getLineStartOffset(lineIndex);
        int lineWidth = getLineWidth(gc, lineIndex);
        if(width >= lineWidth)
            return new int[] { lineStartOffset };
        
        int offsetCount = 0;
        int[] offsets = new int[lineWidth / width + 1];
        offsets[offsetCount++] = lineStartOffset;
        int w = width;
        while(w < lineWidth) {
            int offset = getOffsetAtX(gc, lineIndex, w);
            if(offset <= offsets[offsetCount - 1]) {
                if(content.isImageTag(offset))
	                offset++;
                offset++;
            }
            if(offsetCount >= offsets.length)
                offsets = expandIntArray(offsets);
            offsets[offsetCount++] = offset;
            w = getXAtOffset(gc, lineIndex, offset - lineStartOffset) + width;
        }
        
        if(offsetCount == offsets.length)
            return offsets;
        else {
            int[] ret = new int[offsetCount];
            System.arraycopy(offsets, 0, ret, 0, offsetCount);
            return ret;
        }
    }
    
    /**
     * 扩展行数组
     * 
     * @param array
     * @return
     */
    private int[] expandIntArray(int[] array) {
        int[] newArray;
        if(array.length > 5)
            newArray = new int[array.length + 5];
        else
            newArray = new int[array.length << 1];
        System.arraycopy(array, 0, newArray, 0, array.length);
        return newArray;
    }
    
    /**
     * 得到某一行的宽度
     * 
     * @param gc
     * 		GC
     * @param lineIndex
     * 		行号
     * @return
     * 		宽度
     */
    public int getLineWidth(GC gc, int lineIndex) {
        StringBuffer sb = new StringBuffer(content.getLine(lineIndex));
        return getWidth(gc, sb, lineIndex);
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -