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

📄 qitem.java

📁 lumaQQ的源文件
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
* 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.qstyle;

import static edu.tsinghua.lumaqq.widgets.qstyle.QTree.*;
import static java.lang.Math.max;

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;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;

/**
 * QTree的item
 * 
 * @author luma
 */
public class QItem extends Item {	
    static final String ELLIPSIS = "...";
	static final int MAX_ATTACHMENT = 4;
	static final int ATTACHMENT_SPACING = 3;
	static final Rectangle DUMMY_BOUND = new Rectangle(0, 0, 0, 0);
	
	private QTree parent;
	private QItem parentItem;
	
	private QItem[] items;
	private int itemCount;
	
	private boolean expanded;
	private int level;
	private Color foreground;
	
	private boolean mouseOnIcon;
	private int mouseOnAttachment;
	private boolean mouseOnText;
	private int textWidth;
	
	boolean needRedraw;
	
	boolean animating;
	IEffect effect;
	
	// 装饰图标,装饰图标是指位于原始图标边框范围之内,一般放置于右下角的小图片
	private Image decorationImage;
	// 附件,附件不和原始图标重合,而是显示在其他地方,做为对原始图标的补充
	private Image[] attachment;
	private Rectangle[] attachmentBound;
	// 前缀,放在图标的前面,可以用来放置如加号减号表示展开收起
	private Image prefix;
	// 主图标边框
	Rectangle imageBound;
	
	/**
	 * 创建一个新的QTree根节点
	 * 
	 * @param parent
	 * 		QTree
	 * @param style
	 * 		样式
	 */
	public QItem(QTree parent, int style) {
		super(parent, style);
		this.parent = parent;
		this.parentItem = null;
		this.level = 0;
		this.itemCount = 0;
		this.items = new QItem[16];
		this.expanded = false;
		this.attachment = new Image[MAX_ATTACHMENT];
		this.attachmentBound = new Rectangle[MAX_ATTACHMENT];
		this.prefix = null;
		this.mouseOnIcon = false;
		this.needRedraw = false;
		this.mouseOnAttachment = -1;
		this.mouseOnText = false;
		this.animating = false;
		this.textWidth = 0;
		this.imageBound = (getImage() == null) ? DUMMY_BOUND : getImage().getBounds();
		
		parent.addItem(this);
	}
	
	/**
	 * 创建一个新的QTree子项
	 * 
	 * @param parentItem
	 * 		父item
	 * @param style
	 * 		样式
	 */
	public QItem(QItem parentItem, int style) {
		super(checkNull(parentItem).parent, style);
		this.parent = parentItem.parent;
		this.parentItem = parentItem;
		this.level = parentItem.getLevel() + 1;
		this.itemCount = 0;
		this.items = new QItem[16];
		this.expanded = false;
		this.attachment = new Image[MAX_ATTACHMENT];
		this.attachmentBound = new Rectangle[MAX_ATTACHMENT];
		this.prefix = null;
		this.mouseOnIcon = false;
		this.mouseOnAttachment = -1;
		this.animating = false;
		this.imageBound = (getImage() == null) ? DUMMY_BOUND : getImage().getBounds();
		
		parentItem.addItem(this);		
	}
	
	/**
	 * 添加一个子item
	 * 
	 * @param item
	 */
	private void addItem(QItem item) {
		internalAddItem(item);
	}

	/**
	 * 检查是否为空
	 * 
	 * @param item
	 * 		QItem
	 * @return
	 * 		如果不为空,返回被检查的对象
	 * @exception SWTException <ul>
	 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
	 * </ul>
	 */
	static QItem checkNull(QItem item) {
		if (item == null) 
			SWT.error(SWT.ERROR_NULL_ARGUMENT);
		return item;
	}
	
	/**
	 * 画item
	 * 
	 * @param gc
	 * 		GC对象
	 * @param y
	 * 		item左上角y坐标,相对于父控件来说
	 * @param frame
	 * 		帧数,动画状态时才有意义
	 */
	void onPaint(GC gc, int y, int frame) {		
		textWidth = gc.textExtent(getText()).x;
		ItemLayout layout = parent.getLevelLayout(level);
		
		if(animating && effect != null)
			effect.onPaint(this, gc, layout, y, frame);
		else {
			switch(layout) {
				case HORIZONTAL:	
					paintHorizontal(gc, y);
					break;
				case VERTICAL:
					paintVertical(gc, y);
					break;
				default:
					SWT.error(SWT.ERROR_INVALID_RANGE);
					break;
			}			
		}		
	}
	
	/**
	 * 画垂直样式的item
	 * 
	 * @param gc
	 * 		GC
	 * @param y 
	 * 		item边框左上角y坐标 
	 */
	void paintVertical(GC gc, int y) {
		int size = parent.getLevelImageSize(level);
		int x = parent.getItemIndent(level);
		int itemHeight = parent.getItemHeight(level);
		int itemWidth = parent.getItemWidth(level);
		int imageX = x + (max(0, itemWidth - size) >>> 1);
		int imageY = y + ITEM_TOP_MARGIN;
		int prefixX = 0;
		int prefixY = 0;
		if(prefix != null) {
			Rectangle prefixBound = prefix.getBounds();
			prefixX = imageX - PREFIX_ICON_SPACING - prefixBound.width;
			prefixY = imageY + ((size - prefixBound.height) >> 1);
		}
		
		// 画前缀
		if(prefix != null) 
			paintPrefix(gc, getPrefix(), prefixX, prefixY);
		
		// 画图标
		paintIcon(gc, getImage(), imageBound, imageX, imageY, size);
		
		// 画文本
		paintVerticalText(gc, x, y, itemWidth, itemHeight, foreground);

		// 画附件
		paintVerticalAttachment(gc, x, y, itemWidth, itemHeight, imageX, imageY, size);
	}

	/**
	 * 画水平样式的item
	 * 
	 * @param gc
	 * 		GC
	 * @param y 
	 * 		item边框左上角y坐标 
	 */
	void paintHorizontal(GC gc, int y) {
		int size = parent.getLevelImageSize(level);
		int x = parent.getItemIndent(level);
		int itemHeight = parent.getItemHeight(level);
		int itemWidth = parent.getItemWidth(level);
		int imageX = x + ITEM_LEFT_MARING;
		int imageY = y + (max(0, itemHeight - size) >>> 1);
		int prefixX = 0;
		int prefixY = 0;
		if(prefix != null) {
			Rectangle prefixBound = prefix.getBounds();
			prefixX = imageX;
			prefixY = imageY + ((itemHeight - prefixBound.height) >> 1);
			imageX += prefixBound.width + PREFIX_ICON_SPACING;
		}
		
		// 画前缀
		if(prefix != null)
			paintPrefix(gc, getPrefix(), prefixX, prefixY);
		
		// 画图标
		paintIcon(gc, getImage(), imageBound, imageX, imageY, size);	
		
		// 画文本
		paintHorizontalText(gc, x, y, itemWidth, itemHeight, foreground);
		
		// 画附件
		paintHorizontalAttachment(gc, x, y, itemWidth, itemHeight, imageX, imageY, size);
	}		

	/**
	 * 画前缀图标
	 * 
	 * @param gc
	 * @param image
	 * @param prefixX
	 * @param prefixY
	 */
	void paintPrefix(GC gc, Image image, int prefixX, int prefixY) {
		if(image != null)
			gc.drawImage(image, prefixX, prefixY);
	}

	/**
	 * 画垂直模式时的文本
	 * 
	 * @param gc
	 * 		GC
	 * @param x
	 * 		item左上角x坐标
	 * @param y
	 * 		item左上角y坐标
	 * @param itemWidth
	 * 		item宽度
	 * @param itemHeight
	 * 		item高度
	 * @param fg
	 * 		前景色
	 */
	void paintVerticalText(GC gc, int x, int y, int itemWidth, int itemHeight, Color fg) {
		if(getText() != null) {
			// 调整文本的宽度
			String text = getText();
			Color oldForeground = gc.getForeground();
			if(fg != null)
				gc.setForeground(fg);
			gc.drawString(text,
					Math.max(5, (itemWidth - textWidth) >> 1),
					y + ITEM_TOP_MARGIN + parent.getLevelImageSize(level) + ITEM_IMAGE_TEXT_SPACING,
					true);
			gc.setForeground(oldForeground);			
		}
	}
	
	/**
	 * 画水平模式时的文本
	 * 
	 * @param gc
	 * 		GC
	 * @param x
	 * 		item左上角x坐标
	 * @param y
	 * 		item左上角y坐标
	 * @param itemWidth
	 * 		item宽度
	 * @param itemHeight
	 * 		item高度
	 * @param fg
	 * 		前景色
	 */
	void paintHorizontalText(GC gc, int x, int y, int itemWidth, int itemHeight, Color fg) {
		if(getText() != null) {
			// 调整文本的宽度
			int textX = x + ITEM_LEFT_MARING + parent.getLevelImageSize(level) + ITEM_IMAGE_TEXT_SPACING;
			if(prefix != null)
				textX += PREFIX_ICON_SPACING + prefix.getBounds().width;
			String text = getText();
			Color oldForeground = gc.getForeground();
			if(fg != null)
				gc.setForeground(fg);
			gc.drawString(text, 
					textX,
					y + ((itemHeight - parent.fontHeight) >>> 1),
					true);
			gc.setForeground(oldForeground);			
		}
	}

	/**
	 * 画主图标
	 * 
	 * @param gc
	 * 		GC
	 * @param imgBound	
	 * 		主图标矩形
	 * @param imageX
	 * 		主图标左上角
	 * @param imageY
	 * 		主图标右上角
	 * @param size
	 * 		图标实际尺寸
	 */
	 void paintIcon(GC gc, Image image, Rectangle imgBound, int imageX, int imageY, int size) {
		// 画图标
		if(image != null) {
			gc.drawImage(image, 
					0, 
					0, 
					imgBound.width, 
					imgBound.height, 
					imageX, 
					imageY, 
					size, 
					size);
			paintDecoration(gc, imgBound, imageX, imageY, size);			
		}
		// 画图标边框
		if(parent.isEnableIconHover() && mouseOnIcon)
			paintHoverBorder(gc, imageX - 1, imageY - 1, size + 1, size + 1);
	}

	/**
	 * 画附件图标
	 * 
	 * @param gc
	 * 		GC
	 * @param x	
	 * 		item的左上角x坐标
	 * @param y
	 * 		item的左上角y坐标
	 * @param itemWidth
	 * 		item的宽度
	 * @param itemHeight
	 * 		item的高度
	 * @param imageX
	 * 		图标的x位置
	 * @param imageY
	 * 		图标的y位置
	 * @param size
	 * 		最终的图标大小
	 */
	void paintHorizontalAttachment(GC gc, int x, int y, int itemWidth, int itemHeight, int imageX, int imageY, int size) {
		int attX = x + itemWidth - ITEM_RIGHT_MARGIN;
		for(int i = 0; i < MAX_ATTACHMENT; i++) {
			if(attachment[i] == null)
				continue;
			
			// 计算附件图标的位置
			int attY = y + ((itemHeight - attachmentBound[i].height) >>> 1);
			attX -= attachmentBound[i].width;
			// 如果附件图标和原始图标出现了重叠,不再画
			if(attX < imageX + size)
				break;
			
			// 画附件
			gc.drawImage(attachment[i], 
					0, 
					0, 
					attachmentBound[i].width,
					attachmentBound[i].height,
					attX,
					attY,
					attachmentBound[i].width,
					attachmentBound[i].height);
			// 画边框
			if(mouseOnAttachment == i)
				paintHoverBorder(gc, attX - 1, attY - 1, attachmentBound[i].width + 1, attachmentBound[i].height + 1);
			
			attX -= ATTACHMENT_SPACING;
		}
	}	

	/**
	 * 画附件图标
	 * 
	 * @param gc
	 * 		GC
	 * @param x	
	 * 		item的左上角x坐标
	 * @param y
	 * 		item的左上角y坐标
	 * @param itemWidth
	 * 		item的宽度
	 * @param itemHeight
	 * 		item的高度
	 * @param imageX
	 * 		图标的x位置
	 * @param imageY
	 * 		图标的y位置
	 * @param size
	 * 		最终的图标大小
	 */
	void paintVerticalAttachment(GC gc, int x, int y, int itemWidth, int itemHeight, int imageX, int imageY, int size) {
		int evenX = imageX - ATTACHMENT_SPACING;
		int oddX = imageX + size + ATTACHMENT_SPACING;
		for(int i = 0; i < MAX_ATTACHMENT; i++) {
			if(attachment[i] == null)
				continue;
			
			// 计算附件图标的位置
			int attX, attY;
			if(i % 2 == 0) {
				evenX -= attachmentBound[i].width;
				attX = evenX;
			} else {
				attX = oddX;
				oddX += attachmentBound[i].width + ATTACHMENT_SPACING;
			}
			attY = imageY + size - attachmentBound[i].height;
			
			// 画附件
			gc.drawImage(attachment[i], 
					0, 
					0, 
					attachmentBound[i].width,
					attachmentBound[i].height,
					attX,
					attY,
					attachmentBound[i].width,
					attachmentBound[i].height);
			// 画边框
			if(mouseOnAttachment == i)
				paintHoverBorder(gc, attX - 1, attY - 1, attachmentBound[i].width + 1, attachmentBound[i].height + 1);
		}
	}

	/**
	 * 画装饰图标
	 * 
	 * @param gc
	 * 		GC
	 * @param imgBound
	 * 		原始图标尺寸
	 * @param imageX
	 * 		实际图标x位置
	 * @param imageY
	 * 		实际图标y位置
	 * @param size
	 * 		实际图标尺寸
	 */
	void paintDecoration(GC gc, Rectangle imgBound, int imageX, int imageY, int size) {
		if(decorationImage == null)
			return;
		
		Rectangle decorationBound = decorationImage.getBounds();
		int visualWidth, visualHeight;
		if(decorationBound.width > size || decorationBound.height > size) {
			visualWidth = decorationBound.width * size / imgBound.width;
			visualHeight = decorationBound.height * size / imgBound.height;			
		} else {
			visualWidth = decorationBound.width;
			visualHeight = decorationBound.height;
		}
		int decorationX = imageX + size - visualWidth;
		int decorationY = imageY + size - visualHeight;
		gc.drawImage(decorationImage, 
				0, 
				0, 
				decorationBound.width, 
				decorationBound.height,
				decorationX,
				decorationY,
				visualWidth,
				visualHeight);
	}

	/**
	 * 得到某个子item的索引
	 * 
	 * @param item
	 * 		子item对象
	 * @return
	 * 		索引
	 */
	public int indexOf(QItem item) {
		checkWidget();		
		for(int i = 0; i < itemCount; i++) {
			if(items[i] == item)
				return i;
		}
		return -1;
	}
	
	/**
	 * @return Returns the parent.
	 */
	public QTree getParent() {
		return parent;
	}

	/**
	 * @return Returns the parentItem.
	 */
	public QItem getParentItem() {
		return parentItem;
	}

	/**
	 * @return
	 * 		true表示这个item处于一个可见状态,可见状态也就是指它的
	 * 		所有父节点都是展开的
	 */
	boolean isLogicalVisible() {
		QItem item = parentItem;
		while(item != null) {
			if(!item.isExpanded())
				return false;
			item = item.getParentItem();
		}
		return true;
	}
	
	/**
	 * @return Returns the expanded.
	 */
	public boolean isExpanded() {
		checkWidget();
		return expanded;
	}

	/**
	 * 改变item的展开状态
	 * 
	 * @param expanded
	 * 		true表示展开item
	 */
	public void setExpanded(boolean expanded) {
		setExpanded(expanded, true);
	}
	
	/**
	 * 改变item的展开状态
	 * 
	 * @param expanded
	 * 		true表示展开item
	 * @param redraw
	 * 		true表示立刻重画
	 */
	public void setExpanded(boolean expanded, boolean redraw) {
		checkWidget();
		if(this.expanded != expanded) {
			this.expanded = expanded;
			if(redraw)
				parent.updateExpanded(this);
		}		
	}

⌨️ 快捷键说明

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