/******************************************************************************* * Copyright (c) 2008 IBM Corporation and others. * 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.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.example; import java.text.MessageFormat; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.TextLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; /** * Owner draw in table with bold style ranges */ public class OwnerDrawTreeWithBoldStyles2 { public static void main(String[] args) { Display display= new Display(); Shell shell= new Shell(display); shell.setLayout(new GridLayout(1, false)); Composite composite= new Composite(shell, SWT.NONE); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); composite.setLayout(new GridLayout(1, false)); final Tree tree= new Tree(composite, SWT.MULTI); GridData layoutData= new GridData(SWT.FILL, SWT.FILL, true, true); layoutData.heightHint= 500; tree.setLayoutData(layoutData); tree.setLinesVisible(true); tree.setHeaderVisible(true); Color color= display.getSystemColor(SWT.COLOR_DARK_RED); FontData[] boldFontData= getModifiedFontData(tree.getFont().getFontData(), SWT.BOLD); Font boldFont = new Font(Display.getCurrent(), boldFontData); String itemBaseLabel= "MY_BIG_BOLD_ITEM"; for (int i= 0; i < 10000; i++) { TreeItem item= new TreeItem(tree, SWT.NONE); item.setText(0, MessageFormat.format("{0} {1}{1}{1}", new Object[] { itemBaseLabel, new Integer(i) })); StyleRange styleRange= new StyleRange(); styleRange.start= 0; styleRange.length= itemBaseLabel.length(); styleRange.font= boldFont; styleRange.foreground= color; TreeOwnerDrawSupport.storeStyleRanges(item, 0, new StyleRange[] { styleRange }); } TreeOwnerDrawSupport.install(tree); Button button= new Button(composite, SWT.PUSH); button.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); button.setText("Refresh"); button.addSelectionListener(new SelectionListener() { @Override public void widgetDefaultSelected(SelectionEvent e) { long start= System.currentTimeMillis(); TreeItem[] items= tree.getItems(); for (int i= 0; i < 5000; i++) { tree.setTopItem(items[i]); } long end= System.currentTimeMillis(); System.out.println(end - start); } @Override public void widgetSelected(SelectionEvent e) { widgetDefaultSelected(e); } }); shell.pack(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); boldFont.dispose(); } private static FontData[] getModifiedFontData(FontData[] originalData, int additionalStyle) { FontData[] styleData = new FontData[originalData.length]; for (int i = 0; i < styleData.length; i++) { FontData base = originalData[i]; styleData[i] = new FontData(base.getName(), base.getHeight(), base.getStyle() | additionalStyle); } return styleData; } private static class TreeOwnerDrawSupport implements Listener { private static final String STYLED_RANGES_KEY= "styled_ranges"; //$NON-NLS-1$ private TextLayout fLayout; public static void install(Tree table) { TreeOwnerDrawSupport listener= new TreeOwnerDrawSupport(table); table.addListener(SWT.Dispose, listener); table.addListener(SWT.MeasureItem, listener); table.addListener(SWT.EraseItem, listener); table.addListener(SWT.PaintItem, listener); } /** * Stores the styled ranges in the given table item. * * @param item table item * @param column the column index * @param ranges the styled ranges or null to remove them */ public static void storeStyleRanges(TreeItem item, int column, StyleRange[] ranges) { item.setData(STYLED_RANGES_KEY + column, ranges); } /** * Returns the styled ranges which are stored in the given table item. * * @param item table item * @param column the column index * @return the styled ranges */ private static StyleRange[] getStyledRanges(TreeItem item, int column) { return (StyleRange[])item.getData(STYLED_RANGES_KEY + column); } private TreeOwnerDrawSupport(Tree table) { int orientation= table.getStyle() & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); fLayout= new TextLayout(table.getDisplay()); fLayout.setOrientation(orientation); } /* * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event) */ public void handleEvent(Event event) { switch (event.type) { case SWT.MeasureItem: performMeasure(event); break; case SWT.EraseItem: performErase(event); break; case SWT.PaintItem: performPaint(event); break; case SWT.Dispose: widgetDisposed(); break; } } /** * Performs the measure operation. * * @param event the event */ private void performMeasure(Event event) { TreeItem item= (TreeItem) event.item; fLayout.setFont(item.getFont(event.index)); fLayout.setText(""); //$NON-NLS-1$ fLayout.setText(item.getText(event.index)); int originalTextWidth= fLayout.getBounds().width; boolean containsOtherFont= false; StyleRange[] ranges= getStyledRanges(item, event.index); if (ranges != null) { for (int i= 0; i < ranges.length; i++) { StyleRange curr= ranges[i]; if (curr.font != null) { containsOtherFont= true; } fLayout.setStyle(curr, curr.start, curr.start + curr.length - 1); } } if (containsOtherFont) { int textWidthDelta= fLayout.getBounds().width - originalTextWidth; event.width += textWidthDelta; } } /** * Performs the erase operation. * * @param event the event */ private void performErase(Event event) { event.detail &= ~SWT.FOREGROUND; } /** * Performs the paint operation. * * @param event the event */ private void performPaint(Event event) { TreeItem item= (TreeItem) event.item; GC gc= event.gc; boolean isSelected= (event.detail & SWT.SELECTED) != 0; // remember colors to restore the GC later Color oldForeground = gc.getForeground(); Color oldBackground = gc.getBackground(); if (!isSelected) { Color foreground= item.getForeground(event.index); gc.setForeground(foreground); Color background= item.getBackground(event.index); gc.setBackground(background); } Image image = item.getImage(event.index); if (image != null) { Rectangle imageBounds = item.getImageBounds(event.index); Rectangle bounds = image.getBounds(); int x = imageBounds.x + Math.max(0, (imageBounds.width - bounds.width) / 2); int y = imageBounds.y + Math.max(0, (imageBounds.height - bounds.height) / 2); gc.drawImage(image, x, y); } Rectangle textBounds = item.getTextBounds(event.index); if (textBounds != null) { // fLayout has already been configured in 'performMeasure()' if (isSelected) { StyleRange[] ranges= getStyledRanges(item, event.index); if (ranges != null) { for (int i= 0; i < ranges.length; i++) { StyleRange curr= ranges[i]; if (curr.background != null || curr.foreground != null) { curr= (StyleRange) curr.clone(); curr.background= null; curr.foreground= null; fLayout.setStyle(curr, curr.start, curr.start + curr.length - 1); } } } } Rectangle layoutBounds = fLayout.getBounds(); int x = textBounds.x; int y = textBounds.y + Math.max(0, (textBounds.height - layoutBounds.height) / 2); fLayout.draw(gc, x, y); } if ((event.detail & SWT.FOCUSED) != 0) { Rectangle focusBounds = item.getBounds(); gc.drawFocus(focusBounds.x, focusBounds.y, focusBounds.width, focusBounds.height); } if (!isSelected) { gc.setForeground(oldForeground); gc.setBackground(oldBackground); } } private void widgetDisposed() { fLayout.dispose(); } } }