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

📄 qtreeviewer.java

📁 lumaQQ的源文件
💻 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.qstyle;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Composite;

/**
 * QTree的包装类,提供一个MVC形式的组件,类似TreeViewer和Tree的关系
 * 
 * @author luma
 */
public class QTreeViewer<E> {
	private QTree tree;
	private IQTreeContentProvider<E> contentProvider;
	private IQTreeLabelProvider<E> labelProvider;
	private Object input;
	
	private Map<E, QItem> registry;
	
	private Comparator<E> sorter;
	private IFilter<E> filter;
	
	private List<E> temp;
	
	private Map<E, Animation> animateCache;
	private List<E> expandedCache;
	
	/**
	 * 创建一个Viewer
	 * 
	 * @param parent
	 * 		父容器
	 */
	public QTreeViewer(Composite parent) {
		tree = new QTree(parent);
		registry = new HashMap<E, QItem>();
		temp = new ArrayList<E>();
	}
	
	/**
	 * 释放组件资源
	 */
	public void dispose() {
		tree.dispose();
	}
	
	/**
	 * @return
	 * 		true表示已经释放
	 */
	public boolean isDisposed() {
		return tree.isDisposed();
	}
	
	/**
	 * 展开一个item
	 * 
	 * @param model		
	 * 		model对象
	 */
	public void expandItem(E model) {
		QItem item = getItem(model);
		if(item == null)
			return;
		
		item.setExpanded(true);
	}
	
	/**
	 * 收起一个item
	 * 
	 * @param model		
	 * 		model对象
	 */
	public void collapseItem(E model) {
		QItem item = getItem(model);
		if(item == null)
			return;
		
		item.setExpanded(false);
	}
	
	/**
	 * 为QTree添加拖动支持
	 * 
	 * @param operations
	 *            a bitwise OR of the supported drag and drop operation types (
	 *            <code>DROP_COPY</code>,<code>DROP_LINK</code>, and
	 *            <code>DROP_MOVE</code>)
	 * @param transferTypes
	 *            the transfer types that are supported by the drag operation
	 * @param listener
	 *            the callback that will be invoked to set the drag data and to
	 *            cleanup after the drag and drop operation finishes
	 * @see org.eclipse.swt.dnd.DND
	 */
	public void addDragSupport(int operations, Transfer[] transferTypes, DragSourceListener listener) {
		DragSource dragSource = new DragSource(tree, operations);
		dragSource.setTransfer(transferTypes);
		dragSource.addDragListener(listener);
	}
	
	/**
	 * 为QTree添加拖放支持
	 * 
	 * @param operations
	 *            a bitwise OR of the supported drag and drop operation types (
	 *            <code>DROP_COPY</code>,<code>DROP_LINK</code>, and
	 *            <code>DROP_MOVE</code>)
	 * @param transferTypes
	 *            the transfer types that are supported by the drop operation
	 * @param listener
	 *            the callback that will be invoked after the drag and drop
	 *            operation finishes
	 * @see org.eclipse.swt.dnd.DND
	 */
	public void addDropSupport(int operations, Transfer[] transferTypes, DropTargetListener listener) {
		DropTarget dropTarget = new DropTarget(tree, operations);
		dropTarget.setTransfer(transferTypes);
		dropTarget.addDropListener(listener);
	}
	
	/**
	 * 展开所有根节点
	 */
	public void expandAll() {
		for(E e : registry.keySet()) {
			labelProvider.setExpanded(e, true);
			registry.get(e).setExpanded(true, false);
			doUpdateItem(e, false);
		}
		tree.redraw();
	}
	
	/**
	 * 收起所有根节点
	 */
	public void collapseAll() {
		for(E e : registry.keySet()) {
			labelProvider.setExpanded(e, false);
			registry.get(e).setExpanded(false, false);
			doUpdateItem(e, false);
		}
		tree.redraw();
	}
	
	/**
	 * 编辑文本
	 * 
	 * @param model
	 * 		model对象
	 */
	public void editText(E model) {
		QItem item = getItem(model);
		if(item == null)
			return;
		
		tree.editItemText(item);
	}
	
	/**
	 * 保存当前的根节点展开状态
	 */
	public void saveExpandStatus() {
		if(expandedCache == null)
			expandedCache = new ArrayList<E>();
		expandedCache.clear();
		for(E e : registry.keySet()) {
			if(labelProvider.isExpaned(e))
				expandedCache.add(e);
		}
	}
	
	/**
	 * 恢复根节点的张开状态
	 */
	public void restoreExpandStatus() {
		if(expandedCache == null)
			return;
		for(E e : registry.keySet()) {
			labelProvider.setExpanded(e, false);
			registry.get(e).setExpanded(false, false);
		}
		for(E e : expandedCache) {
			labelProvider.setExpanded(e, true);			
			registry.get(e).setExpanded(true, true);
		}
		tree.redraw();
	}
	
	/**
	 * 刷新全部  
	 */
	public void refresh() {
		saveAnimationStatus();
		tree.stopAllAnimation();
		E[] roots = contentProvider.getElements(input);
		roots = filterModels(roots);
		if(sorter != null)
			Arrays.sort(roots, sorter);
		doUpdateRoot(roots, false);
		for(int i = 0; i < roots.length; i++) 
			doUpdateChildren(roots[i], false, true);
		tree.refresh();
		restoreAnimationStatus();
	}
	
	/**
	 * 刷新一个item的显示,不刷新子item。如果这个model没有对应的item,则不操作
	 * 
	 * @param model
	 * 		model对象
	 */
	public void refresh(E model) {
		refresh(model, false);
	}
	
	/**
	 * 刷新一个item的显示。如果这个model没有对应的item,则不操作
	 * 
	 * @param model
	 * 		model对象
	 * @param includeChildren
	 * 		true表示也刷新其子item
	 */
	public void refresh(E model, boolean includeChildren) {
		QItem item = registry.get(model);
		if(item == null)
			return;
		
		if(includeChildren)
			refreshChildren(contentProvider.getParent(model));
		doUpdateItem(model, true);
	}
	
	/**
	 * 刷新子item,不刷新自己
	 * 
	 * @param model
	 */
	public void refreshChildren(E model) {
		QItem item = registry.get(model);
		if(item == null)
			return;
		
		saveAnimationStatus();
		tree.stopAllAnimation();
		doUpdateChildren(model, true);
		restoreAnimationStatus();
	}
	
	/**
	 * 刷新子节点
	 * 
	 * @param model
	 * 		父节点对象
	 * @param redraw
	 * 		是否重画
	 * @param includeSub
	 * 		true表示刷新父节点下的所有层
	 */
	private void doUpdateChildren(E model, boolean redraw, boolean includeSub) {
		if(includeSub) {
			doUpdateChildren(model, false);
			E[] children = contentProvider.getChildren(model);
			children = filterModels(children);
			for(int i = 0; i < children.length; i++) {
				doUpdateChildren(children[i], false, true);
			}
			if(redraw)
				tree.refresh();
		} else
			doUpdateChildren(model, redraw);
	}
	
	/**
	 * 刷新子节点,只刷新一层子节点
	 * 
	 * @param model
	 * 		父对象
	 * @param redraw
	 * 		true更新后重画
	 */
	private void doUpdateChildren(E model, boolean redraw) {		
		QItem parentItem = registry.get(model);		
		QItem[] childrenItem = parentItem.getItems();
		E[] modelChildren = contentProvider.getChildren(model);		
		modelChildren = filterModels(modelChildren);
		if(sorter != null)
			Arrays.sort(modelChildren, sorter);
		for(int i = 0; i < modelChildren.length; i++) {
			if(i < childrenItem.length) {
				// 重用已有的item
				childrenItem[i].effect = null;
				registry.put(modelChildren[i], childrenItem[i]);
				doUpdateItem(childrenItem[i], modelChildren[i], false);
			} else {
				// 添加新的item
				QItem child = new QItem(parentItem, SWT.NONE);
				registry.put(modelChildren[i], child);
				doUpdateItem(child, modelChildren[i], false);
			}
		}
		// 删除多余的item
		if(modelChildren.length < childrenItem.length)
			parentItem.removeItemFrom(modelChildren.length);
		// 重画
		if(redraw)
			tree.refresh();
	} 
	
	/**
	 * 刷新根节点
	 * 
	 * @param rootModels
	 * 		根节点model
	 * @param redraw
	 * 		是否重画
	 */
	private void doUpdateRoot(E[] rootModels, boolean redraw) {
		QItem[] roots = tree.getItems();
		for(int i = 0; i < rootModels.length; i++) {
			if(i < roots.length) {
				// 重用已有的item
				roots[i].effect = null;
				registry.put(rootModels[i], roots[i]);
				doUpdateItem(roots[i], rootModels[i], false);
			} else {
				// 添加新的item
				QItem child = new QItem(tree, SWT.NONE);
				registry.put(rootModels[i], child);
				doUpdateItem(child, rootModels[i], false);
			}
		}
		// 删除多余的item
		if(rootModels.length < roots.length)
			tree.removeItemFrom(rootModels.length);
		// 重画
		if(redraw)
			tree.redraw();
	}
	
	/**
	 * 更新一个item,这个item一定要存在。这个方法不检查其存在性
	 * 
	 * @param model
	 * 		model对象
	 * @param redraw
	 * 		是否重画
	 */
	private void doUpdateItem(E model, boolean redraw) {
		QItem item = registry.get(model);
		doUpdateItem(item, model, redraw);
	}
	
	/**
	 * 更新一个item,item是指定的,model也是指定的
	 * 
	 * @param item
	 * 		QItem
	 * @param model
	 * 		model对象
	 * @param redraw
	 * 		是否重画
	 */
	private void doUpdateItem(QItem item, E model, boolean redraw) {
		item.setData(model);
		for(int i = 0; i < QItem.MAX_ATTACHMENT; i++)
			item.addAttachment(i, labelProvider.getAttachment(model, i), false);
		item.setForeground(labelProvider.getForeground(model), false);
		item.setDecorationImage(labelProvider.getDecoration(model), false);
		item.setImage(labelProvider.getImage(model), false);
		item.setExpanded(labelProvider.isExpaned(model), false);
		item.setPrefix(labelProvider.getPrefix(model), false);
		item.setText(labelProvider.getText(model), redraw);
	}
	
	/**
	 * 过滤model
	 * 
	 * @param models
	 * 		model数组
	 * @return
	 * 		已过滤的数组
	 */
	@SuppressWarnings("unchecked")
	private E[] filterModels(E[] models) {
		if(filter == null)
			return models;
		temp.clear();
		for(int i = 0; i < models.length; i++) {
			if(filter.select(models[i]))
				temp.add(models[i]);
		}
		return (E[])temp.toArray();
	}
	
	/**
	 * @param model
	 * @return
	 * 		true表示目前有一个动画在进行
	 */
	public boolean hasAnimation(E model) {
		QItem item = getItem(model);
		if(item == null)
			return false;
		
		return tree.hasAnimation(item);
	}
	
	/**
	 * 得到model对应的item
	 * 
	 * @param model
	 * 		model对象
	 * @return
	 * 		QItem对象,如果没有,返回null
	 */
	public QItem getItem(E model) {
		return registry.get(model);
	}

	/**
	 * @return
	 * 		实际的QTree控件
	 */
	public QTree getQTree() {
		return tree;
	}

	/**
	 * @return Returns the contentProvider.
	 */
	public IQTreeContentProvider<E> getContentProvider() {
		return contentProvider;
	}

	/**
	 * @param contentProvider The contentProvider to set.
	 */
	public void setContentProvider(IQTreeContentProvider<E> contentProvider) {
		this.contentProvider = contentProvider;
	}

	/**
	 * @return Returns the lableProvider.
	 */
	public IQTreeLabelProvider<E> getLabelProvider() {
		return labelProvider;
	}

	/**
	 * @param lableProvider The lableProvider to set.
	 */
	public void setLabelProvider(IQTreeLabelProvider<E> lableProvider) {
		this.labelProvider = lableProvider;
	}

	/**
	 * @return Returns the input.
	 */
	public Object getInput() {
		return input;
	}

	/**
	 * @param input The input to set.
	 */
	public void setInput(Object input) {
		this.input = input;
		refresh();
	}

	/**
	 * @return Returns the sorter.
	 */
	public Comparator<E> getSorter() {
		return sorter;
	}

	/**
	 * @param sorter The sorter to set.
	 */
	public void setSorter(Comparator<E> sorter) {
		this.sorter = sorter;
	}

	/**
	 * @return Returns the filter.
	 */
	public IFilter<E> getFilter() {
		return filter;
	}

	/**
	 * @param filter The filter to set.
	 */
	public void setFilter(IFilter<E> filter) {
		this.filter = filter;
	}
	
	/**
	 * 开始一个动画
	 * 
	 * @param model
	 * @param type
	 */
	public void startAnimation(E model, Animation type) {
		QItem item = getItem(model);
		if(item == null)
			return;
		
		tree.startAnimation(item, type);
	}
	
	/**
	 * 停止一个动画
	 * 
	 * @param model
	 */
	public void stopAnimation(E model) {
		QItem item = getItem(model);
		if(item == null)
			return;
		
		tree.stopAnimation(item);
	}
	
	/**
	 * 保存动画状态
	 */
	@SuppressWarnings("unchecked")
	public void saveAnimationStatus() {
		if(animateCache == null)
			animateCache = new HashMap<E, Animation>();
		animateCache.clear();
		
		synchronized(tree.animateList) {
			for(QItem item : tree.animateList) {
				animateCache.put((E)item.getData(), Animation.valueOf(item.effect));
			}
		}
	}
	
	/**
	 * 恢复动画状态
	 */
	public void restoreAnimationStatus() {
		for(E model : animateCache.keySet()) {
			startAnimation(model, animateCache.get(model));
		}
	}
	
	/**
	 * @return
	 * 		true表示所有的根节点都是收起的
	 */
	public boolean isAllRootCollapsed() {
		E[] roots = contentProvider.getElements(input);
		for(E e : roots) {
			if(labelProvider.isExpaned(e))
				return false;
		}
		return true;
	}
}

⌨️ 快捷键说明

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