eclipse RCP 模仿win7资源管理器地址栏功能

本文实现效果及其工具下载地址:http://sourceforge.net/projects/filetools/

 

windows7/8的资源管理器个人觉得比较便利的还属地址栏,在定位资源位置时非常方面。见下图:


eclipse RCP 模仿win7资源管理器地址栏功能_第1张图片
 

当窗口大小改变,或地址栏的长度过长时,地址栏会自动隐藏头部。这是一个优点,但同时也是一个缺点。大多数时候,我们需要点击多次才能回到地址头部。而显示出来的那一部分,恰恰是不经常使用的。所以,我想对其进行改进,使地址栏可以达到:

  • 能够显示全部地址栏信息,在长度大导致空间不足时显示尽量多的位置信息,可以隐藏文本信息,但应该显示相应标志指示父文件夹和根目录;

初步实现的效果如图:

 
eclipse RCP 模仿win7资源管理器地址栏功能_第2张图片

 

实现这个效果并不困难。第一种方法是是通过layout来实现。在swt中,常见的rowlayout实现的就是类似的效果,我们可以通过修改rowlayout来达到目的,并达到支持水平和垂直布局。第二种方法是调用jdt里面的BreadcrumbView,做适当修改就可以。

第一种方法的实现(详见附件,里面有源码和测试代码):

/* AutoAdjustRowLayout.java 
 * Copyright (c) 2013 by Brook Tran
 * All rights reserved.
 * 
 * The copyright of this software is own by the authors.
 * You may not use, copy or modify this software, except
 * in accordance with the license agreement you entered into 
 * with the copyright holders. For details see accompanying license
 * terms.
 */
package org.jeelee.filemanager.ui.breadcrumb;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;

/**
 * <B>AutoAdjustRowLayout</B>
 * extends from {@link org.eclipse.swt.layout.RowLayout} 
 * @author Brook Tran. Email: <a href="mailto:[email protected]">[email protected]</a>
 * @since org.jeelee.filemanager 2013-1-9 created
 */
public class BreadcrumbLayout extends Layout{

	/**
	 * type specifies whether the layout places controls in rows or 
	 * columns.
	 * 
	 * The default value is HORIZONTAL.
	 * 
	 * Possible values are: <ul>
	 *    <li>HORIZONTAL: Position the controls horizontally from left to right</li>
	 *    <li>VERTICAL: Position the controls vertically from top to bottom</li>
	 * </ul>
	 * 
	 * @since 2.0
	 */
	public int type = SWT.HORIZONTAL | SWT.RIGHT_TO_LEFT;
	
	/**
	 * marginWidth specifies the number of pixels of horizontal margin
	 * that will be placed along the left and right edges of the layout.
	 *
	 * The default value is 0.
	 * 
	 * @since 3.0
	 */
 	public int marginWidth = 0;
 	
	/**
	 * marginHeight specifies the number of pixels of vertical margin
	 * that will be placed along the top and bottom edges of the layout.
	 *
	 * The default value is 0.
	 * 
	 * @since 3.0
	 */
 	public int marginHeight = 0;

	/**
	 * spacing specifies the number of pixels between the edge of one cell
	 * and the edge of its neighbouring cell.
	 *
	 * The default value is 3.
	 */
	public int spacing = 3;
	 		
	/**
	 * pack specifies whether all controls in the layout take
	 * their preferred size.  If pack is false, all controls will 
	 * have the same size which is the size required to accommodate the 
	 * largest preferred height and the largest preferred width of all 
	 * the controls in the layout.
	 *
	 * The default value is true.
	 */
	public boolean pack = true;
	
	/**
	 * fill specifies whether the controls in a row should be
	 * all the same height for horizontal layouts, or the same
	 * width for vertical layouts.
	 *
	 * The default value is false.
	 * 
	 * @since 3.0
	 */
	public boolean fill = false;


	/**
	 * marginLeft specifies the number of pixels of horizontal margin
	 * that will be placed along the left edge of the layout.
	 *
	 * The default value is 3.
	 */
	public int marginLeft = 3;

	/**
	 * marginTop specifies the number of pixels of vertical margin
	 * that will be placed along the top edge of the layout.
	 *
	 * The default value is 3.
	 */
	public int marginTop = 3;

	/**
	 * marginRight specifies the number of pixels of horizontal margin
	 * that will be placed along the right edge of the layout.
	 *
	 * The default value is 3.
	 */
	public int marginRight = 3;

	/**
	 * marginBottom specifies the number of pixels of vertical margin
	 * that will be placed along the bottom edge of the layout.
	 *
	 * The default value is 3.
	 */
	public int marginBottom = 3;

	
	public BreadcrumbLayout() {
	}
	
	public BreadcrumbLayout (int type) {
		this.type = type;
	}
	@Override
	protected void layout (Composite composite, boolean flushCache) {
		Rectangle clientArea = composite.getClientArea ();
		if ((type & SWT.HORIZONTAL) == SWT.HORIZONTAL) {
			layoutHorizontal (composite, true,  clientArea.width, flushCache);
		} else {
			layoutVertical (composite, true, clientArea.height, flushCache);
		}
	}
	@Override
	protected Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache) {
		Point extent;
		if ((type & SWT.HORIZONTAL) == SWT.HORIZONTAL) {
			extent = layoutHorizontal (composite, false,  wHint, flushCache);
		} else {
			extent = layoutVertical (composite, false,  hHint, flushCache);
		}
		if (wHint != SWT.DEFAULT) {
			extent.x = wHint;
		}
		if (hHint != SWT.DEFAULT) {
			extent.y = hHint;
		}
		return extent;
	}
	
	Point layoutHorizontal (Composite composite, boolean move, int width, boolean flushCache) {
		Control [] children = composite.getChildren ();
		int count = 0;
		for (int i=0; i<children.length; i++) {
			Control control = children [i];
			RowData data = (RowData) control.getLayoutData ();
			if (data == null || !data.exclude) {
				children [count++] = children [i];
			} 
		}
		if (count == 0) {
			return new Point (marginLeft + marginWidth * 2 + marginRight, marginTop + marginHeight * 2 + marginBottom);
		}
		

		
		int startIndex = 0;
		if( ( type & SWT.RIGHT_TO_LEFT) == SWT.RIGHT_TO_LEFT){
			startIndex = count;
			int maxWidth = marginLeft + marginWidth + marginRight + marginWidth;
//			marginRight + marginLeft +marginWidth  ;
			while(startIndex>0 && maxWidth<width){
				Control child = children [startIndex-1];
				Point size = computeSize (child, flushCache);
				maxWidth += size.x +spacing  + marginWidth;
				startIndex--;
			}
			startIndex = adjust(move, children, count, startIndex);
		}
			
		int childWidth = 0, childHeight = 0, maxHeight = 0;
		// get max width & height
		if (!pack) {
			for (int i=startIndex; i<count; i++) {
				Control child = children [i];
				Point size = computeSize (child, flushCache);
				childWidth = Math.max (childWidth, size.x);
				childHeight = Math.max (childHeight, size.y);
			}
			maxHeight = childHeight;
		}
		
		int clientX = 0, clientY = 0;
		if (move) {
			Rectangle rect = composite.getClientArea ();
			clientX = rect.x;
			clientY = rect.y;
		}
		
		Rectangle [] bounds = null;
		if (move && (fill )) {
			bounds = new Rectangle [count];
		}
		int maxX = 0, x = marginLeft + marginWidth, y = marginTop + marginHeight;
		
		
		for (int i=startIndex; i<count; i++) {
			Control child = children [i];
			if (pack) {
				Point size = computeSize (child, flushCache);
				childWidth = size.x;
				childHeight = size.y;
			}
			if (pack || fill ) {
				maxHeight = Math.max (maxHeight, childHeight);
			}
			if (move) {
				int childX = x + clientX, childY = y + clientY;
				if ( fill ) {
					bounds [i] = new Rectangle (childX, childY, childWidth, childHeight);
				} else {
					child.setBounds (childX, childY, childWidth, childHeight);
				}
			}
			x += spacing + childWidth;
			maxX = Math.max (maxX, x);
		}
		maxX = Math.max (clientX + marginLeft + marginWidth, maxX - spacing);
			maxX += marginRight + marginWidth;
		if (move && (fill)) {
			for (int i=startIndex; i<count; i++) {
					if (fill) {
						bounds [i].height = maxHeight;
					} 
				children [i].setBounds (bounds [i]);
			}
		}
		return new Point (maxX, y + maxHeight + marginBottom + marginHeight);
	}

	Point layoutVertical (Composite composite, boolean move,int height, boolean flushCache) {
		Control [] children = composite.getChildren ();
		int count = 0;
		for (int i=0; i<children.length; i++) {
			Control control = children [i];
			RowData data = (RowData) control.getLayoutData ();
			if (data == null || !data.exclude) {
				children [count++] = children [i];
			} 
		}
		if (count == 0) {
			return new Point (marginLeft + marginWidth * 2 + marginRight, marginTop + marginHeight * 2 + marginBottom);
		}
		

		int startIndex = 0;
		if( ( type & SWT.RIGHT_TO_LEFT) == SWT.RIGHT_TO_LEFT){
			startIndex = count;
			int maxHeight = marginTop + marginHeight+ marginBottom +marginHeight  ;
			while(startIndex>0 && maxHeight<height){
				Control child = children [startIndex-1];
				Point size = computeSize (child, flushCache);
				maxHeight += size.y +spacing + marginTop +marginHeight;
				startIndex--;
			}
			startIndex = adjust(move, children, count, startIndex);
		}
		
		
		
		int childWidth = 0, childHeight = 0, maxWidth = 0;
		if (!pack) {
			for (int i=startIndex; i<count; i++) {
				Control child = children [i];
				Point size = computeSize (child, flushCache);
				childWidth = Math.max (childWidth, size.x);
				childHeight = Math.max (childHeight, size.y);
			}
			maxWidth = childWidth;
		}
		int clientX = 0, clientY = 0;
		if (move) {
			Rectangle rect = composite.getClientArea ();
			clientX = rect.x;
			clientY = rect.y;
		}
		Rectangle [] bounds = null;
		if (move && (fill)) {
			bounds = new Rectangle [count];
		}
		int maxY = 0, x = marginLeft + marginWidth, y = marginTop + marginHeight;
		for (int i=startIndex; i<count; i++) {
			Control child = children [i];
			if (pack) {
				Point size = computeSize (child, flushCache);
				childWidth = size.x;
				childHeight = size.y;
			}
			if (pack || fill ) {
				maxWidth = Math.max (maxWidth, childWidth);
			}
			if (move) {
				int childX = x + clientX, childY = y + clientY;
				if ( fill ) {
					bounds [i] = new Rectangle (childX, childY, childWidth, childHeight);
				} else {
					child.setBounds (childX, childY, childWidth, childHeight);
				}
			}
			y += spacing + childHeight;
			maxY = Math.max (maxY, y);
		}
		maxY = Math.max (clientY + marginTop + marginHeight, maxY - spacing);
		if (move && (fill )) {
			for (int i=startIndex; i<count; i++) {
				children [i].setBounds (bounds [i]);
			}
		}
		return new Point (x + maxWidth + marginRight + marginWidth, maxY);
	}

	private int adjust(boolean move, Control[] children, int count,
			int startIndex) {
		if (startIndex > 0) {
			startIndex++;
		}
		if(startIndex > count){
			startIndex--;
		}
		
		if(move){
			Rectangle hide = new Rectangle(0, 0, 0, 0);
			for(int i=0;i<startIndex;i++){
//				children[i].setVisible(false);
				children[i].setBounds(hide);
			}
		}
		return startIndex;
	}


	Point computeSize (Control control, boolean flushCache) {
		int wHint = SWT.DEFAULT, hHint = SWT.DEFAULT;
		RowData data = (RowData) control.getLayoutData ();
		if (data != null) {
			wHint = data.width;
			hHint = data.height;
		}
		return control.computeSize (wHint, hHint, flushCache);
	}
	
	
	
	@Override
	protected boolean flushCache (Control control) {
		return true;
	}

	String getName () {
		String string = getClass ().getName ();
		int index = string.lastIndexOf ('.');
		if (index == -1) {
			return string;
		}
		return string.substring (index + 1, string.length ());
	}
	@Override
	public String toString () {
	 	String string = getName ()+" {";
	 	string += "type="+((type != SWT.HORIZONTAL) ? "SWT.VERTICAL" : "SWT.HORIZONTAL")+" ";
	 	if (marginWidth != 0) {
			string += "marginWidth="+marginWidth+" ";
		}
	 	if (marginHeight != 0) {
			string += "marginHeight="+marginHeight+" ";
		}
	 	if (marginLeft != 0) {
			string += "marginLeft="+marginLeft+" ";
		}
	 	if (marginTop != 0) {
			string += "marginTop="+marginTop+" ";
		}
	 	if (marginRight != 0) {
			string += "marginRight="+marginRight+" ";
		}
	 	if (marginBottom != 0) {
			string += "marginBottom="+marginBottom+" ";
		}
	 	if (spacing != 0) {
			string += "spacing="+spacing+" ";
		}
		string += "pack="+pack+" ";
		string += "fill="+fill+" ";
		string = string.trim();
		string += "}";
	 	return string;
	}
	
}

 
 实现效果见下图。其中,第一栏是地址栏的模拟实现,这个会隐藏根目录和父级目录,只显示最多子节点。
eclipse RCP 模仿win7资源管理器地址栏功能_第3张图片


 第二种方法相对比较简单,像使用普通view一样调用BreadcrumbView,设置LabelProvider和ContentProvider就可以了。

	class FilePathBreadcrumViewer extends BreadcrumbViewer{
		private FileFilterDelegate fFilter;
		public FilePathBreadcrumViewer(FileFilterDelegate fileFilter,
				Composite parent, int style) {
			super(parent, style);
			fFilter=fileFilter;
		}

		@Override
		protected void configureDropDownViewer(TreeViewer viewer, Object input) {
			viewer.setLabelProvider(new FileDelegateLableProvider());
			viewer.setContentProvider(new FileDelegateTreeContentProvider(fFilter));
		}
	}

 

 实现的效果:

 
eclipse RCP 模仿win7资源管理器地址栏功能_第4张图片
 

 

 

你可能感兴趣的:(eclipse,RCP)