/* ********************************************************************** ** ** Copyright notice ** ** ** ** (c) 2005-2009 RSSOwl Development Team ** ** http://www.rssowl.org/ ** ** ** ** All rights reserved ** ** ** ** This program and the accompanying materials are made available under ** ** the terms of the Eclipse Public License v1.0 which accompanies this ** ** distribution, and is available at: ** ** http://www.rssowl.org/legal/epl-v10.html ** ** ** ** A copy is found in the file epl-v10.html and important notices to the ** ** license from the team is found in the textfile LICENSE.txt distributed ** ** in this package. ** ** ** ** This copyright notice MUST APPEAR in all copies of the file! ** ** ** ** Contributors: ** ** RSSOwl Development Team - initial API and implementation ** ** ** ** ********************************************************************** */ package org.rssowl.ui.internal.util; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.ScrollBar; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.rssowl.ui.internal.Application; import java.util.ArrayList; import java.util.List; /** * A wrapper around <code>Tree</code> that allows to apply * <code>CTreeLayoutData</code> to Columns of the underlying Tree. The Wrapper * is making sure to avoid horizontal scrollbars if possible. * * @author bpasero */ public class CTree { /* ID to store Layout-Data with TreeColumns */ private static final String LAYOUT_DATA = "org.rssowl.ui.internal.CTreeLayoutData"; //$NON-NLS-1$ private Tree fTree; private List<TreeColumn> fCols = new ArrayList<TreeColumn>(); private boolean fIsFlat = true; /** * @param parent * @param style */ public CTree(Composite parent, int style) { fTree = new Tree(parent, style); parent.addListener(SWT.Resize, new Listener() { public void handleEvent(Event event) { onTreeResize(); } }); } /** * @return Tree */ public Tree getControl() { return fTree; } /** * @param isFlat set to <code>true</code> to indicate that this tree is * showing a list of elements or <code>false</code> to indicate that its * showing entries with child entries. */ public void setFlat(boolean isFlat) { fIsFlat = isFlat; } /** * @param col * @param layoutData * @param text * @param tooltip * @param image * @param moveable * @param resizable * @return TreeColumn */ public TreeColumn manageColumn(TreeColumn col, CColumnLayoutData layoutData, String text, String tooltip, Image image, boolean moveable, boolean resizable) { col.setData(LAYOUT_DATA, layoutData); col.setMoveable(moveable); col.setResizable(resizable); if (text != null) col.setText(text); if (tooltip != null) col.setToolTipText(tooltip); if (image != null) col.setImage(image); fCols.add(col); return col; } /** * @param col * @param visible * @param update */ public void setVisible(TreeColumn col, boolean visible, boolean update) { CColumnLayoutData data = (CColumnLayoutData) col.getData(LAYOUT_DATA); data.setHidden(!visible); if (update) onTreeResize(); } /** * Force layout of all columns. */ public void update() { onTreeResize(); } /** * Dispose and clear all columns. */ public void clear() { for (TreeColumn cols : fCols) { cols.dispose(); } fCols.clear(); } private void onTreeResize() { int totalWidth = fTree.getParent().getClientArea().width; totalWidth -= fTree.getBorderWidth() * 2; ScrollBar verticalBar = fTree.getVerticalBar(); if (verticalBar != null) { int barWidth = verticalBar.getSize().x; if (Application.IS_MAC && barWidth == 0) barWidth = 16; //Can be 0 on Mac totalWidth -= barWidth; } /* Bug on Mac: Width is too big */ if (Application.IS_MAC) { totalWidth -= 3; if (!fIsFlat) totalWidth -= 24; } /* Bug on Linux: Margin from Bar to TableItem not returned */ else if (Application.IS_LINUX) totalWidth -= 3; int freeWidth = totalWidth; int occupiedWidth = 0; /* Foreach TreeColumn */ int totalFillSum = 0; for (int i = 0; i < fCols.size(); i++) { TreeColumn column = fCols.get(i); CColumnLayoutData data = (CColumnLayoutData) column.getData(LAYOUT_DATA); /* Hide Column */ if (data.isHidden()) { column.setWidth(0); } /* Fixed with Default Width Hint */ else if (data.getSize() == CColumnLayoutData.Size.FIXED && data.getWidthHint() == CColumnLayoutData.DEFAULT) { column.pack(); int width = column.getWidth(); freeWidth -= width; occupiedWidth += width; } /* Fixed with actual Width Hint */ else if (data.getSize() == CColumnLayoutData.Size.FIXED) { int widthHint = data.getWidthHint(); /* Windows: First column in tree always needs extra space for expand/collapse */ if (Application.IS_WINDOWS && i == 0) { if (fIsFlat) widthHint += 25; else widthHint += 45; } /* Linux: First column in tree always needs extra space for expand/collapse */ else if (Application.IS_LINUX && i == 0) { if (fIsFlat) widthHint += 20; else widthHint += 40; } /* Mac: First column in tree always needs extra space for expand/collapse */ else if (Application.IS_MAC && i == 0) { widthHint += 20; } freeWidth -= widthHint; occupiedWidth += widthHint; /* Only apply if changed */ if (column.getWidth() != widthHint) column.setWidth(widthHint); } /* Sum up the fill ratios for later use */ else if (data.getSize() == CColumnLayoutData.Size.FILL) { totalFillSum += data.getWidthHint(); } } /* Foreach TreeColumn */ for (TreeColumn column : fCols) { CColumnLayoutData data = (CColumnLayoutData) column.getData(LAYOUT_DATA); /* Fill available space with ratio */ if (data.getSize() == CColumnLayoutData.Size.FILL) { int colWidth = (freeWidth * data.getWidthHint()) / totalFillSum; /* Trim if necessary */ if (occupiedWidth + colWidth >= totalWidth) colWidth = totalWidth - occupiedWidth; occupiedWidth += colWidth; /* Only apply if changed */ if (column.getWidth() != colWidth) column.setWidth(colWidth); } } } }