Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeo Ufimtsev2018-03-02 12:07:39 -0500
committerLeo Ufimtsev2018-03-02 12:09:55 -0500
commit3a3c32da911e07e08f5ef2c42ab8859283d01108 (patch)
tree61d68eda436b49e889d0856b71554e49b0f78499
parented2e4fa0648abe16583fd105e408e48b9e0ad36b (diff)
downloadeclipse.platform.swt-3a3c32da911e07e08f5ef2c42ab8859283d01108.tar.gz
eclipse.platform.swt-3a3c32da911e07e08f5ef2c42ab8859283d01108.tar.xz
eclipse.platform.swt-3a3c32da911e07e08f5ef2c42ab8859283d01108.zip
Bug 531048 [GTK3] Large problems drawing ownerdraw tables (tests).
Adding manual JUnit tests to verify changes to table don't break table. Tests are aimed at verifying visual glitches (like cheese). Going through these is quite quick (F1=pass, F2=Fail, F3=Skip, ESC=Quit). A lot of the tests originate from snippets. Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=5310483 Change-Id: I3ad13abd45110e528987b04f1061435d38127fa7 Signed-off-by: Leo Ufimtsev <lufimtse@redhat.com>
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/MJ_Table.java1365
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/MJ_root.java105
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/README3
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/Template.java28
4 files changed, 1501 insertions, 0 deletions
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/MJ_Table.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/MJ_Table.java
new file mode 100644
index 0000000000..dc1a37c940
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/MJ_Table.java
@@ -0,0 +1,1365 @@
+package org.eclipse.swt.tests.manualJUnit;
+
+import java.text.Collator;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.TableEditor;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontMetrics;
+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.graphics.TextLayout;
+import org.eclipse.swt.graphics.TextStyle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+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.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.JVM) // To make it easier for human to go through the tests. Same order makes tests easier to recognize.
+public class MJ_Table extends MJ_root {
+
+ // Shared elements:
+ final Listener ownerDrawnListener = event -> {
+ final TableItem item = (TableItem)event.item;
+ Table table = item.getParent();
+ AtomicBoolean packpending = (AtomicBoolean) table.getData();
+ if (event.type == SWT.PaintItem) {
+ final String text1 = (String)item.getData();
+ if (event.index == 0) {
+ event.gc.drawText(text1, event.x, event.y, true);
+ }
+ }
+ if (event.type == SWT.MeasureItem) {
+ event.height = 50;
+ event.width = 100;
+ }
+ if (event.type == SWT.SetData) {
+ final int index = table.indexOf(item);
+ final String data = "Item " + index;
+ item.setData(data);
+ if (table.getColumnCount() > 1) {
+ for (int i = 1; i <= table.getColumnCount(); i++) {
+ item.setText(i, "Column: " + i + " " + data);
+ }
+ }
+
+ // BUG BREAKER.
+ if (packpending.get()) {
+ packpending.set(false);
+ display.asyncExec(() -> {
+ table.setRedraw(false);
+ for (TableColumn column : table.getColumns()) {
+ column.pack();
+ }
+ table.setRedraw(true);
+ });
+ }
+ }
+ };
+
+ @Test
+ public void basicTable_Snippet35() {
+ Shell shell = mkShell("Basic Table with a few items, no column, no headers");
+ shell.setLayout(new FillLayout());
+ Table table = new Table (shell, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+ for (int i=0; i<12; i++) {
+ TableItem item = new TableItem (table, 0);
+ item.setText ("Item " + i);
+ }
+ shell.setSize (SWIDTH, SHEIGHT);
+ shell.open ();
+ mainLoop(shell);
+ }
+
+ /**
+ * <a href="https://bugs.eclipse.org/bugs/attachment.cgi?id=272647">Screenshot </a>
+ */
+ @Test
+ public void ownerDrawn_cheese_single_column () {
+ Shell shell = mkShell("Expected: There should be no cheese in the items. Move over shouldn't cheese out. See javadoc for screenshot");
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+
+ final Table table = new Table(shell, SWT.VIRTUAL | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
+
+ AtomicBoolean packpending = new AtomicBoolean(true);
+ table.setData(packpending);
+
+ table.addListener(SWT.EraseItem, ownerDrawnListener);
+ table.addListener(SWT.SetData, ownerDrawnListener);
+ table.addListener(SWT.MeasureItem, ownerDrawnListener);
+ table.addListener(SWT.PaintItem, ownerDrawnListener);
+
+ final TableColumn tableColumn = new TableColumn(table, SWT.LEFT);
+ tableColumn.setText("First Left Column");
+ tableColumn.setMoveable(true);
+
+
+ for (int i = 0; i < 100; i++) {
+ TableItem item1 = new TableItem(table, SWT.NONE);
+ item1.setText("hello " + i);
+ }
+
+// for (int i = 0; i < 2; i++) {
+// table.getColumn(i).setWidth(1); // Setting width seems to fix issue.
+// table.getColumn(i).pack(); // table is empty on Gtk3. // packing doesn't fix issue.
+// }
+
+ shell.setSize(800, 600); // Shell size seems to have a litlte bit of an initial impact. (may show proper with some shell sizes, incorrectly for others).
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void ownerDrawn_cheese_multiple_columns() {
+ final Shell shell = mkShell("Expected: No cheese in multiple column, also mouse move over no cheese.");
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+ final Table table = new Table(shell, SWT.VIRTUAL | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
+
+ AtomicBoolean packpending = new AtomicBoolean(true);
+ table.setData(packpending);
+
+ table.addListener(SWT.EraseItem, ownerDrawnListener);
+ table.addListener(SWT.SetData, ownerDrawnListener);
+ table.addListener(SWT.MeasureItem, ownerDrawnListener);
+ table.addListener(SWT.PaintItem, ownerDrawnListener);
+
+ BiConsumer<Integer, String> createColCons = (colStyle, colName) -> {
+ final TableColumn tableColumn = new TableColumn(table, colStyle);
+ tableColumn.setText(colName);
+ tableColumn.setMoveable(true);
+ };
+
+ createColCons.accept(SWT.LEFT, "LEFT");
+ createColCons.accept(SWT.CENTER, "CENTER");
+ createColCons.accept(SWT.RIGHT, "RIGHT");
+
+ int ItemCount = 1000;
+ table.setItemCount(ItemCount);
+ table.setHeaderVisible(true);
+
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+
+ /**
+ * <a href="http://www.eclipse.org/articles/Article-CustomDrawingTableAndTreeItems/customDraw.htm#_example4"> Screenshot </a>
+ */
+ @Test
+ public void ownerDrawn_eraseItem_Snippet273() {
+ knownToBeBrokenGtk3("Test currently broken on Gtk3. See Comment#1 of Bug 531551");
+
+ final String[] MONTHS = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ final int[] HIGHS = {-7, -4, 1, 11, 18, 24, 26, 25, 20, 13, 5, -4};
+ final int[] LOWS = {-15, -13, -7, 1, 7, 13, 15, 14, 10, 4, -2, -11};
+ final int SCALE_MIN = -30; final int SCALE_MAX = 30;
+ final int SCALE_RANGE = Math.abs(SCALE_MIN - SCALE_MAX);
+
+ Shell shell = mkShell(" Gtk3:broken, no erasing (1st March 2018) Gtk2: Background is used as bar-chart of sort. See screenshot.");
+ final Color blue = display.getSystemColor(SWT.COLOR_BLUE);
+ final Color white = display.getSystemColor(SWT.COLOR_WHITE);
+ final Color red = display.getSystemColor(SWT.COLOR_RED);
+// final Image parliamentImage = new Image(display, "./parliament.jpg");
+ final Table table = new Table(shell, SWT.NONE);
+ table.setBounds(10,10,350,300);
+// table.setBackgroundImage(parliamentImage);
+ for (int i = 0; i < 12; i++) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setText(MONTHS[i] + " (" + LOWS[i] + "C..." + HIGHS[i] + "C)");
+ }
+ final int clientWidth = table.getClientArea().width;
+
+ /*
+ * NOTE: MeasureItem and EraseItem are called repeatedly. Therefore it is
+ * critical for performance that these methods be as efficient as possible.
+ */
+ table.addListener(SWT.MeasureItem, event -> {
+ int itemIndex = table.indexOf((TableItem)event.item);
+ int rightX = (HIGHS[itemIndex] - SCALE_MIN) * clientWidth / SCALE_RANGE;
+ event.width = rightX;
+ });
+ table.addListener(SWT.EraseItem, event -> {
+ int itemIndex = table.indexOf((TableItem)event.item);
+ int leftX = (LOWS[itemIndex] - SCALE_MIN) * clientWidth / SCALE_RANGE;
+ int rightX = (HIGHS[itemIndex] - SCALE_MIN) * clientWidth / SCALE_RANGE;
+ GC gc = event.gc;
+ Rectangle clipping = gc.getClipping();
+ clipping.x = leftX;
+ clipping.width = rightX - leftX;
+ gc.setClipping(clipping);
+ Color oldForeground = gc.getForeground();
+ Color oldBackground = gc.getBackground();
+ gc.setForeground(blue);
+ gc.setBackground(white);
+ gc.fillGradientRectangle(event.x, event.y, event.width / 2, event.height, false);
+ gc.setForeground(white);
+ gc.setBackground(red);
+ gc.fillGradientRectangle(
+ event.x + event.width / 2, event.y, event.width / 2, event.height, false);
+ gc.setForeground(oldForeground);
+ gc.setBackground(oldBackground);
+ event.detail &= ~SWT.BACKGROUND;
+ event.detail &= ~SWT.HOT;
+ });
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void ownerDrawn_icons_on_right_side_of_column_Snippet230() {
+ Shell shell = mkShell("Verify icons are visible on all columns on right side. (on gtk3, icons are cut off Bug 531882)");
+ knownToBeBrokenGtk3("On gtk3, icons in col 1 and 2 are cut off. Bug 531882");
+
+ final Image image = display.getSystemImage(SWT.ICON_INFORMATION);
+ shell.setLayout(new FillLayout ());
+ Table table = new Table(shell, SWT.MULTI | SWT.FULL_SELECTION);
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+ int columnCount = 3;
+ for (int i=0; i<columnCount; i++) {
+ TableColumn column = new TableColumn(table, SWT.NONE);
+ column.setText("Column " + i);
+ }
+ int itemCount = 8;
+ for(int i = 0; i < itemCount; i++) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"item "+i+" a", "item "+i+" b", "item "+i+" c"});
+ }
+
+ /*
+ * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly.
+ * Therefore, it is critical for performance that these methods be
+ * as efficient as possible.
+ */
+ Listener paintListener = event -> {
+ switch(event.type) {
+ case SWT.MeasureItem: {
+ Rectangle rect1 = image.getBounds();
+ event.width += rect1.width;
+ event.height = Math.max(event.height, rect1.height + 2);
+ break;
+ }
+ case SWT.PaintItem: {
+ int x = event.x + event.width;
+ Rectangle rect2 = image.getBounds();
+ int offset = Math.max(0, (event.height - rect2.height) / 2);
+ event.gc.drawImage(image, x, event.y + offset);
+ break;
+ }
+ }
+ };
+ table.addListener(SWT.MeasureItem, paintListener);
+ table.addListener(SWT.PaintItem, paintListener);
+
+ for(int i = 0; i < columnCount; i++) {
+ table.getColumn(i).pack();
+ }
+ shell.setSize (SWIDTH, SHEIGHT);
+ shell.open();
+ shell.addDisposeListener(e -> {
+ if(image != null) image.dispose();
+ });
+ mainLoop(shell);
+ }
+
+ @Test
+ public void ownerDrawn_barChart_Snippet228() {
+ Shell shell = mkShell("Ensure you see bar-charts in 2nd column and they resize with shell.");
+ shell.setLayout(new FillLayout());
+ final Table table = new Table(shell, SWT.BORDER);
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+ TableColumn column1 = new TableColumn(table, SWT.NONE);
+ column1.setText("Bug Status");
+ column1.setWidth(100);
+ final TableColumn column2 = new TableColumn(table, SWT.NONE);
+ column2.setText("Percent");
+ column2.setWidth(200);
+ String[] labels = new String[]{"Resolved", "New", "Won't Fix", "Invalid"};
+ for (int i=0; i<labels.length; i++) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setText(labels[i]);
+ }
+
+ /*
+ * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly.
+ * Therefore, it is critical for performance that these methods be
+ * as efficient as possible.
+ */
+ table.addListener(SWT.PaintItem, new Listener() {
+ int[] percents = new int[] {50, 30, 5, 15};
+ @Override
+ public void handleEvent(Event event) {
+ if (event.index == 1) {
+ GC gc = event.gc;
+ TableItem item = (TableItem)event.item;
+ int index = table.indexOf(item);
+ int percent = percents[index];
+ Color foreground = gc.getForeground();
+ Color background = gc.getBackground();
+ gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
+ gc.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
+ int width = (column2.getWidth() - 1) * percent / 100;
+ gc.fillGradientRectangle(event.x, event.y, width, event.height, true);
+ Rectangle rect2 = new Rectangle(event.x, event.y, width-1, event.height-1);
+ gc.drawRectangle(rect2);
+ gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ String text = percent+"%";
+ Point size = event.gc.textExtent(text);
+ int offset = Math.max(0, (event.height - size.y) / 2);
+ gc.drawText(text, event.x+2, event.y+offset, true);
+ gc.setForeground(background);
+ gc.setBackground(foreground);
+ }
+ }
+ });
+ shell.setSize (SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void ownerDrawn_textAlignment_Snippet231 () {
+ Shell shell = mkShell("Ensure there is no cheese, also when hoving over items");
+ final int COLUMN_COUNT = 4;
+ final int ITEM_COUNT = 8;
+ final int TEXT_MARGIN = 3;
+ shell.setLayout(new FillLayout());
+ final Table table = new Table(shell, SWT.FULL_SELECTION);
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+ for (int i = 0; i < COLUMN_COUNT; i++) {
+ new TableColumn(table, SWT.NONE);
+ }
+ for (int i = 0; i < ITEM_COUNT; i++) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ for (int j = 0; j < COLUMN_COUNT; j++) {
+ String string = "item " + i + " col " + j;
+ if ((i + j) % 3 == 1) {
+ string +="\nnew line1";
+ }
+ if ((i + j) % 3 == 2) {
+ string +="\nnew line1\nnew line2";
+ }
+ item.setText(j, string);
+ }
+ }
+
+ /*
+ * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly.
+ * Therefore, it is critical for performance that these methods be
+ * as efficient as possible.
+ */
+ table.addListener(SWT.MeasureItem, event -> {
+ TableItem item = (TableItem)event.item;
+ String text = item.getText(event.index);
+ Point size = event.gc.textExtent(text);
+ event.width = size.x + 2 * TEXT_MARGIN;
+ event.height = Math.max(event.height, size.y + TEXT_MARGIN);
+ });
+ table.addListener(SWT.EraseItem, event -> event.detail &= ~SWT.FOREGROUND);
+ table.addListener(SWT.PaintItem, event -> {
+ TableItem item = (TableItem)event.item;
+ String text = item.getText(event.index);
+ /* center column 1 vertically */
+ int yOffset = 0;
+ if (event.index == 1) {
+ Point size = event.gc.textExtent(text);
+ yOffset = Math.max(0, (event.height - size.y) / 2);
+ }
+ event.gc.drawText(text, event.x + TEXT_MARGIN, event.y + yOffset, true);
+ });
+
+ for (int i = 0; i < COLUMN_COUNT; i++) {
+ table.getColumn(i).pack();
+ }
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void ownerDrawn_multiColumn_gc_snippet239 () {
+ Shell shell = mkShell("Verify that text is correctly drawn across 2 columns");
+ shell.setText("Text spans two columns in a TableItem");
+ shell.setLayout (new FillLayout());
+ final Table table = new Table(shell, SWT.MULTI | SWT.FULL_SELECTION);
+ table.setHeaderVisible(true);
+ int columnCount = 4;
+ for (int i=0; i<columnCount; i++) {
+ TableColumn column = new TableColumn(table, SWT.NONE);
+ column.setText("Column " + i);
+ }
+ int itemCount = 8;
+ for (int i = 0; i < itemCount; i++) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setText(0, "item "+i+" a");
+ item.setText(3, "item "+i+" d");
+ }
+ /*
+ * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly.
+ * Therefore, it is critical for performance that these methods be
+ * as efficient as possible.
+ */
+ final String string = "text that spans two columns";
+ GC gc = new GC(table);
+ final Point extent = gc.stringExtent(string);
+ gc.dispose();
+ final Color red = display.getSystemColor(SWT.COLOR_RED);
+ Listener paintListener = event -> {
+ switch(event.type) {
+ case SWT.MeasureItem: {
+ if (event.index == 1 || event.index == 2) {
+ event.width = extent.x/2;
+ event.height = Math.max(event.height, extent.y + 2);
+ }
+ break;
+ }
+ case SWT.PaintItem: {
+ if (event.index == 1 || event.index == 2) {
+ int offset = 0;
+ if (event.index == 2) {
+ TableColumn column1 = table.getColumn(1);
+ offset = column1.getWidth();
+ }
+ event.gc.setForeground(red);
+ int y = event.y + (event.height - extent.y)/2;
+ event.gc.drawString(string, event.x - offset, y, true);
+ }
+ break;
+ }
+ }
+ };
+ table.addListener(SWT.MeasureItem, paintListener);
+ table.addListener(SWT.PaintItem, paintListener);
+ for (int i = 0; i < columnCount; i++) {
+ table.getColumn(i).pack();
+ }
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void ownerDrawn_CustomItemHeight () {
+ Shell shell = mkShell("Ensure Item 3 (yellow) is bigger than the other items");
+ int bigItem = 3;
+
+ shell.setLayout(new FillLayout());
+ shell.setSize (SWIDTH, SHEIGHT);
+ final Table table = new Table(shell, SWT.NONE);
+ table.setLinesVisible(true);
+
+
+ for (int i = 0; i < 5; i++) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ if (i == bigItem) {
+ item.setText("Item " + bigItem + " has bigger height");
+ item.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
+ }
+ else {
+ item.setText("item " + i);
+ item.setBackground(display.getSystemColor(SWT.COLOR_DARK_GRAY));
+ }
+ }
+
+ /*
+ * NOTE: MeasureItem is called repeatedly. Therefore it is critical
+ * for performance that this method be as efficient as possible.
+ */
+ table.addListener(SWT.MeasureItem, event -> {
+ int clientWidth = table.getClientArea().width;
+ event.height = event.gc.getFontMetrics().getHeight() * 2; // * table.indexOf((TableItem) event.item) to have different height rows.
+ event.width = clientWidth * 2;
+
+ if (table.indexOf((TableItem) event.item) == bigItem) {
+ event.height *= 2;
+ }
+ });
+
+ shell.open();
+ mainLoop(shell);
+ }
+
+
+ /**
+ * Snippet 144 modified to auto-populate items when shell is activated instead.
+ */
+ @Test
+ public void virtual_addManyItems_Snippet144 () {
+ final Shell shell = mkShell("Shell Should show and items should be populated in lazy way");
+ shell.setSize (SWIDTH, SHEIGHT);
+ final int COUNT = 100000;
+ shell.setLayout(new RowLayout(SWT.VERTICAL));
+ final Table table = new Table (shell, SWT.VIRTUAL | SWT.BORDER);
+ final Label label1 = new Label(shell, SWT.NONE);
+ table.addListener (SWT.SetData, event -> {
+ TableItem item = (TableItem) event.item;
+ int index = table.indexOf (item);
+ item.setText ("Item " + index);
+ label1.setText("Added " + item.getText());
+ });
+ table.setLayoutData (new RowData (shell.getBounds().width - 100, 400));
+ final Label label2 = new Label(shell, SWT.NONE);
+ shell.addShellListener( new ShellAdapter() {
+ @Override
+ public void shellActivated(ShellEvent e) {
+ System.out.println("activated");
+ long t1 = System.currentTimeMillis ();
+ table.setItemCount (COUNT);
+ long t2 = System.currentTimeMillis ();
+ label2.setText ("Items: " + COUNT + ", Time: " + (t2 - t1) + " (ms)");
+ shell.layout ();
+ }
+ });
+ shell.open ();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void column_headers_Snippet38() {
+ Shell shell = mkShell("Matrix with rows & columns and columns with description. (BUG gtk2/3 text seems slightly cut off, Bug 531875)");
+ knownToBeBrokenGtk("Text in column is cut off at the moment. See Bug 531875");
+
+ shell.setLayout(new GridLayout());
+ Table table = new Table (shell, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
+ table.setLinesVisible (true);
+ table.setHeaderVisible (true);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ data.heightHint = 200;
+ table.setLayoutData(data);
+ String[] titles = {" ", "C", "!", "Description", "Resource", "In Folder", "Location"};
+ for (int i=0; i<titles.length; i++) {
+ TableColumn column = new TableColumn (table, SWT.NONE);
+ column.setText (titles [i]);
+ }
+ int count = 128;
+ for (int i=0; i<count; i++) {
+ TableItem item = new TableItem (table, SWT.NONE);
+ item.setText (0, "x");
+ item.setText (1, "y");
+ item.setText (2, "!");
+ item.setText (3, "this stuff behaves the way I expect");
+ item.setText (4, "almost everywhere");
+ item.setText (5, "some.folder");
+ item.setText (6, "line " + i + " in nowhere");
+ }
+ for (int i=0; i<titles.length; i++) {
+ table.getColumn (i).pack ();
+ }
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open ();
+ mainLoop(shell);
+ }
+
+
+ // TODO - see how this behaves on windows.
+ @Test
+ public void column_noWidth_bug399522 () {
+ Shell shell = mkShell("Expected : (Not sure?) On Gtk/Cocoa no items are now shown till column width is actually specified or column is packed.");
+
+ final Table table = new Table(shell, SWT.BORDER);
+ table.setHeaderVisible(true);
+
+ new TableItem(table, SWT.NONE).setText("Item1");
+ TableColumn column1 = new TableColumn(table, SWT.NONE);
+// column1.setWidth(10); // Setting column width makes items visible.
+// column1.pack();
+
+ table.setSize(200, 200);
+ System.out.println(column1.handle);
+
+ shell.addListener(SWT.MouseDown, event -> System.out.println(table.computeSize(-1, -1)));
+
+ TableColumn col2 = new TableColumn(table, SWT.NONE);
+ System.out.println(col2.handle);
+
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+
+ @Test
+ public void column_header_icons_Snippet297() {
+ Display display = new Display ();
+ Image images[] = new Image[] {
+ display.getSystemImage(SWT.ICON_INFORMATION),
+ display.getSystemImage(SWT.ICON_ERROR),
+ display.getSystemImage(SWT.ICON_QUESTION),
+ display.getSystemImage(SWT.ICON_WARNING),
+ };
+ String[] titles = {"Information", "Error", "Question", "Warning"};
+ String[] questions = {"who?", "what?", "where?", "when?", "why?"};
+ Shell shell = new Shell (display);
+ shell.setLayout(new GridLayout());
+ Table table = new Table (shell, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
+ GridData data = new GridData (SWT.FILL, SWT.FILL, true, true);
+ data.heightHint = 200;
+ table.setLayoutData (data);
+ table.setLinesVisible (true);
+ table.setHeaderVisible (true);
+
+ for (int i=0; i<titles.length; i++) {
+ TableColumn column = new TableColumn (table, SWT.NONE);
+ column.setText (titles [i]);
+ column.setImage(images [i]);
+ }
+
+ int count = 128;
+ for (int i=0; i<count; i++) {
+ TableItem item = new TableItem (table, SWT.NONE);
+ item.setText (0, "some info");
+ item.setText (1, "error #" + i);
+ item.setText (2, questions [i % questions.length]);
+ item.setText (3, "look out!");
+ }
+ for (int i=0; i<titles.length; i++) {
+ table.getColumn (i).pack ();
+ }
+
+ table.setHeaderBackground(display.getSystemColor(SWT.COLOR_BLUE));
+ table.setHeaderForeground(display.getSystemColor(SWT.COLOR_RED));
+
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open ();
+ mainLoop(shell);
+ }
+
+ /**
+ * Based on Snippet 106 with some modificaitons.
+ */
+ @Test
+ public void column_dynamically_added_after_shellOpened_Snippet106() {
+ Shell shell = mkShell("Verify dynamic column (2) was added properly.");
+
+ final Table table = new Table (shell, SWT.BORDER | SWT.MULTI);
+ table.setHeaderVisible (true);
+ for (int i=0; i<4; i++) {
+ TableColumn column = new TableColumn (table, SWT.NONE);
+ column.setText ("Column " + i);
+ }
+ final TableColumn [] columns = table.getColumns ();
+ for (int i=0; i<12; i++) {
+ TableItem item = new TableItem (table, SWT.NONE);
+ for (int j=0; j<columns.length; j++) {
+ item.setText (j, "Item " + i);
+ }
+ }
+ for (int i=0; i<columns.length; i++) columns [i].pack ();
+ Button button = new Button (shell, SWT.PUSH);
+ final int index = 1;
+ button.setText ("Insert Column " + index + "a");
+ shell.addShellListener(new ShellAdapter() {
+ @Override
+ public void shellActivated(ShellEvent e) {
+ TableColumn column = new TableColumn (table, SWT.NONE, index);
+ column.setImage(display.getSystemImage(SWT.ICON_WARNING)); //added to make it easier to spot in a test.
+ column.setText ("Column " + index + " added after shellopen");
+ TableItem [] items = table.getItems ();
+ for (int i=0; i<items.length; i++) {
+ items [i].setText (index, "Item " + i + " added");
+ }
+ column.pack ();
+ }
+ });
+
+ shell.setSize (SWIDTH, SHEIGHT);
+ Rectangle shellClientArea = shell.getClientArea();
+ table.setSize(shellClientArea.width, shellClientArea.height);
+ shell.open ();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void column_dynamic_resize() {
+ Shell shell = mkShell("Try resizing shell. Columns should resize as you resize shell");
+ shell.setLayout(new FillLayout());
+
+ final Composite comp = new Composite(shell, SWT.NONE);
+ final Table table = new Table(comp, SWT.BORDER | SWT.V_SCROLL);
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+ final TableColumn column1 = new TableColumn(table, SWT.NONE);
+ column1.setText("Column 1");
+ final TableColumn column2 = new TableColumn(table, SWT.NONE);
+ column2.setText("Column 2");
+ for (int i = 0; i < 10; i++) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"item 0" + i, "item 1"+i});
+ }
+ comp.addControlListener(ControlListener.controlResizedAdapter(e -> {
+ Rectangle area = comp.getClientArea();
+ Point size = table.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+ ScrollBar vBar = table.getVerticalBar();
+ int width = area.width - table.computeTrim(0, 0, 0, 0).width - vBar.getSize().x;
+ if (size.y > area.height + table.getHeaderHeight()) {
+ // Subtract the scrollbar width from the total column width
+ // if a vertical scrollbar will be required
+ Point vBarSize = vBar.getSize();
+ width -= vBarSize.x;
+ }
+ Point oldSize = table.getSize();
+ if (oldSize.x > area.width) {
+ // table is getting smaller so make the columns
+ // smaller first and then resize the table to
+ // match the client area width
+ column1.setWidth(width / 3);
+ column2.setWidth(width - column1.getWidth());
+ table.setSize(area.width, area.height);
+ } else {
+ // table is getting bigger so make the table
+ // bigger first and then make the columns wider
+ // to match the client area width
+ table.setSize(area.width, area.height);
+ column1.setWidth(width / 3);
+ column2.setWidth(width - column1.getWidth());
+ }
+ }));
+
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void measureItem_custom_Column_width_onPack_Snippet272() {
+ Shell shell = mkShell("Double click on column boundary '|', observe column get's bigger");
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.setLayout(new FillLayout());
+ Table table = new Table(shell, SWT.NONE);
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+ final TableColumn column0 = new TableColumn(table, SWT.NONE);
+ column0.setWidth(110);
+ column0.setText("2x Click pipe ->");
+ final TableColumn column1 = new TableColumn(table, SWT.NONE);
+ column1.setWidth(110);
+ column0.addListener(SWT.Selection, event -> column0.pack());
+ column1.addListener(SWT.Selection, event -> column1.pack());
+ for (int i = 0; i < 5; i++) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setText(0, "item " + i + " col 0");
+ item.setText(1, "item " + i + " col 1");
+ }
+
+ /*
+ * NOTE: MeasureItem is called repeatedly. Therefore it is critical
+ * for performance that this method be as efficient as possible.
+ */
+ table.addListener(SWT.MeasureItem, event -> event.width *= 4); // This guy makes the difference.
+
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void checkBoxes() {
+ Shell shell = mkShell("You should see some checkboxes");
+ shell.setLayout(new FillLayout());
+ Table table = new Table (shell, SWT.CHECK | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+ for (int i=0; i<12; i++) {
+ TableItem item = new TableItem (table, SWT.NONE);
+ item.setText ("Item " + i);
+ }
+ Rectangle clientArea = shell.getClientArea ();
+ table.setBounds (clientArea.x, clientArea.y, 600, 500);
+
+ final Label label = new Label(shell, SWT.NONE);
+
+ table.addListener (SWT.Selection, event -> {
+ String string = event.detail == SWT.CHECK ? "Checked" : "Selected";
+ label.setText(event.item + " " + string);
+ });
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open ();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void color_singleColumn() {
+ Shell shell = mkShell("Header and content should be colored red and blue. Column header should be of a darker color.");
+ shell.setLayout(new FillLayout());
+
+ Table table = new Table (shell, SWT.None);
+ table.setHeaderVisible(true);
+ TableColumn column = new TableColumn(table, SWT.LEFT);
+ column.setText("Column header has darker colors.");
+ column.pack();
+
+ for (int i = 0; i < 200; i++) {
+ TableItem item = new TableItem(table, SWT.None);
+ item.setText("Item " + i);
+ }
+
+ table.setBackground(display.getSystemColor(SWT.COLOR_BLUE));
+ table.setForeground(display.getSystemColor(SWT.COLOR_RED));
+
+ table.setHeaderBackground(display.getSystemColor(SWT.COLOR_DARK_BLUE));
+ table.setHeaderForeground(display.getSystemColor(SWT.COLOR_DARK_RED));
+
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void color_MultipleColumn() {
+ Shell shell = mkShell("Header and content should be colored red and blue. Column header should be of a darker color.");
+ shell.setLayout(new FillLayout());
+
+ Table table = new Table (shell, SWT.None);
+ table.setHeaderVisible(true);
+ TableColumn column = new TableColumn(table, SWT.LEFT);
+ column.setText("Column 1");
+ column.pack();
+
+ TableColumn column2 = new TableColumn(table, SWT.LEFT);
+ column2.setText("Column 2");
+ column2.pack();
+
+ for (int i = 0; i < 200; i++) {
+ TableItem item = new TableItem(table, SWT.None);
+ item.setText(new String[] {"Item " + i, "Item col2: " + i});
+ }
+
+ table.setBackground(display.getSystemColor(SWT.COLOR_BLUE));
+ table.setForeground(display.getSystemColor(SWT.COLOR_RED));
+
+ table.setHeaderBackground(display.getSystemColor(SWT.COLOR_DARK_BLUE));
+ table.setHeaderForeground(display.getSystemColor(SWT.COLOR_DARK_RED));
+
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void color_differentCells_Snippet129 () {
+ Shell shell = mkShell("Table cells should be of different colors");
+
+ Color red = display.getSystemColor(SWT.COLOR_RED);
+ Color blue = display.getSystemColor(SWT.COLOR_BLUE);
+ Color white = display.getSystemColor(SWT.COLOR_WHITE);
+ Color gray = display.getSystemColor(SWT.COLOR_GRAY);
+ shell.setLayout(new FillLayout());
+ Table table = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
+ table.setBackground(gray);
+ TableColumn column1 = new TableColumn(table, SWT.NONE);
+ TableColumn column2 = new TableColumn(table, SWT.NONE);
+ TableColumn column3 = new TableColumn(table, SWT.NONE);
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"entire","row","red foreground"});
+ item.setForeground(red);
+ item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"entire","row","red background"});
+ item.setBackground(red);
+ item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"entire","row","white fore/red back"});
+ item.setForeground(white);
+ item.setBackground(red);
+ item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"normal","blue foreground","red foreground"});
+ item.setForeground(1, blue);
+ item.setForeground(2, red);
+ item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"normal","blue background","red background"});
+ item.setBackground(1, blue);
+ item.setBackground(2, red);
+ item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"white fore/blue back","normal","white fore/red back"});
+ item.setForeground(0, white);
+ item.setBackground(0, blue);
+ item.setForeground(2, white);
+ item.setBackground(2, red);
+
+ column1.pack();
+ column2.pack();
+ column3.pack();
+
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void programaticScrolling_Snippet52() {
+ Shell shell = mkShell("Table should be scrolled down to 100th item");
+ Table table = new Table (shell, SWT.BORDER | SWT.MULTI);
+ Rectangle clientArea = shell.getClientArea ();
+ table.setBounds (clientArea.x, clientArea.y,800, 600);
+ for (int i=0; i<128; i++) {
+ TableItem item = new TableItem (table, SWT.NONE);
+ item.setText ("Item " + i);
+ }
+ table.setSelection (100); // <<< This is what we're testing.
+ shell.pack ();
+ shell.open ();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void sort_by_column_Snippet2() {
+ Shell shell = mkShell("Click on columns to verify items are sorted properly");
+ shell.setLayout(new FillLayout());
+
+ final Table table = new Table(shell, SWT.BORDER);
+ table.setHeaderVisible(true);
+ final TableColumn column1 = new TableColumn(table, SWT.NONE);
+ column1.setText("Column 1");
+ final TableColumn column2 = new TableColumn(table, SWT.NONE);
+ column2.setText("Column 2");
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"a", "3"});
+ item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"b", "2"});
+ item = new TableItem(table, SWT.NONE);
+ item.setText(new String[] {"c", "1"});
+ column1.setWidth(100);
+ column2.setWidth(100);
+ Listener sortListener = e -> {
+ TableItem[] items = table.getItems();
+ Collator collator = Collator.getInstance(Locale.getDefault());
+ TableColumn column = (TableColumn)e.widget;
+ int index = column == column1 ? 0 : 1;
+ for (int i = 1; i < items.length; i++) {
+ String value1 = items[i].getText(index);
+ for (int j = 0; j < i; j++){
+ String value2 = items[j].getText(index);
+ if (collator.compare(value1, value2) < 0) {
+ String[] values = {items[i].getText(0), items[i].getText(1)};
+ items[i].dispose();
+ TableItem item1 = new TableItem(table, SWT.NONE, j);
+ item1.setText(values);
+ items = table.getItems();
+ break;
+ }
+ }
+ }
+ table.setSortColumn(column);
+ };
+ column1.addListener(SWT.Selection, sortListener);
+ column2.addListener(SWT.Selection, sortListener);
+ table.setSortColumn(column1);
+ table.setSortDirection(SWT.UP);
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void sort_by_columnt_virtual_Snippet192 () {
+ Shell shell = mkShell("Click on column heading to sort");
+ // initialize data with keys and random values
+ int size = 100;
+ Random random = new Random();
+ final int[][] data = new int[size][];
+ for (int i = 0; i < data.length; i++) {
+ data[i] = new int[] {i, random.nextInt()};
+ }
+ // create a virtual table to display data
+ shell.setLayout(new FillLayout());
+ final Table table = new Table(shell, SWT.VIRTUAL);
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+ table.setItemCount(size);
+ final TableColumn column1 = new TableColumn(table, SWT.NONE);
+ column1.setText("Key");
+ column1.setWidth(200);
+ final TableColumn column2 = new TableColumn(table, SWT.NONE);
+ column2.setText("Value");
+ column2.setWidth(200);
+ table.addListener(SWT.SetData, e -> {
+ TableItem item = (TableItem) e.item;
+ int index = table.indexOf(item);
+ int[] datum = data[index];
+ item.setText(new String[] {Integer.toString(datum[0]),
+ Integer.toString(datum[1]) });
+ });
+ // Add sort indicator and sort data when column selected
+ Listener sortListener = e -> {
+ // determine new sort column and direction
+ TableColumn sortColumn = table.getSortColumn();
+ TableColumn currentColumn = (TableColumn) e.widget;
+ int dir = table.getSortDirection();
+ if (sortColumn == currentColumn) {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ } else {
+ table.setSortColumn(currentColumn);
+ dir = SWT.UP;
+ }
+ // sort the data based on column and direction
+ final int index = currentColumn == column1 ? 0 : 1;
+ final int direction = dir;
+ Arrays.sort(data, (a, b) -> {
+ if (a[index] == b[index]) return 0;
+ if (direction == SWT.UP) {
+ return a[index] < b[index] ? -1 : 1;
+ }
+ return a[index] < b[index] ? 1 : -1;
+ });
+ // update data displayed in table
+ table.setSortDirection(dir);
+ table.clearAll();
+ };
+ column1.addListener(SWT.Selection, sortListener);
+ column2.addListener(SWT.Selection, sortListener);
+ table.setSortColumn(column1);
+ table.setSortDirection(SWT.UP);
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void icons_ofDiffSize_inItems_Snippet349() {
+ Shell shell = mkShell("Verify that items have icons of different sizes and icons are not cut off");
+
+ BiFunction<Integer, Integer, Image> createImage = (width, height) -> {
+ Image result = new Image(display, width, height);
+ GC gc = new GC(result);
+ for (int x = -height; x < width; x += 4) {
+ gc.drawLine(x, 0, x + height, height);
+ }
+ gc.dispose();
+ return result;
+ };
+
+ final int COLUMN_COUNT = 3;
+ final int TEXT_MARGIN = 3;
+ final String KEY_WIDTHS = "widths";
+ final String KEY_IMAGES = "images";
+
+ Image[] images = new Image[4];
+ images[0] = createImage.apply(16, 16);
+ images[1] = createImage.apply(32, 16);
+ images[2] = createImage.apply(48, 16);
+
+ shell.setLayout(new FillLayout());
+ Table table = new Table(shell, SWT.NONE);
+ for (int i = 0; i < COLUMN_COUNT; i++) {
+ new TableColumn(table, SWT.NONE);
+ }
+ for (int i = 0; i < 8; i++) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ Image[] itemImages = new Image[COLUMN_COUNT];
+ item.setData(KEY_IMAGES, itemImages);
+ for (int j = 0; j < COLUMN_COUNT; j++) {
+ item.setText(j, "item " + i + " col " + j);
+ itemImages[j] = images[(i * COLUMN_COUNT + j) % images.length];
+ }
+ }
+
+ /*
+ * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly.
+ * Therefore, it is critical for performance that these methods be
+ * as efficient as possible.
+ */
+ final int itemHeight = table.getItemHeight();
+ GC gc = new GC(table);
+ FontMetrics metrics = gc.getFontMetrics();
+ final int fontHeight = metrics.getHeight();
+ gc.dispose();
+ Listener paintListener = event -> {
+ switch (event.type) {
+ case SWT.MeasureItem: {
+ int column1 = event.index;
+ TableItem item1 = (TableItem)event.item;
+ Image[] images1 = (Image[])item1.getData(KEY_IMAGES);
+ Image image1 = images1[column1];
+ if (image1 == null) {
+ /* don't change the native-calculated event.width */
+ break;
+ }
+ int[] cachedWidths = (int[])item1.getData(KEY_WIDTHS);
+ if (cachedWidths == null) {
+ cachedWidths = new int[COLUMN_COUNT];
+ item1.setData(KEY_WIDTHS, cachedWidths);
+ }
+ if (cachedWidths[column1] == 0) {
+ int width = image1.getBounds().width + 2 * TEXT_MARGIN;
+ GC gc1 = new GC(item1.getParent());
+ width += gc1.stringExtent(item1.getText()).x;
+ gc1.dispose();
+ cachedWidths[column1] = width;
+ }
+ event.width = cachedWidths[column1];
+ break;
+ }
+ case SWT.EraseItem: {
+ int column2 = event.index;
+ TableItem item2 = (TableItem)event.item;
+ Image[] images2 = (Image[])item2.getData(KEY_IMAGES);
+ Image image2 = images2[column2];
+ if (image2 == null) {
+ break;
+ }
+ /* disable the native drawing of this item */
+ event.detail &= ~SWT.FOREGROUND;
+ break;
+ }
+ case SWT.PaintItem: {
+ int column3 = event.index;
+ TableItem item3 = (TableItem)event.item;
+ Image[] images3 = (Image[])item3.getData(KEY_IMAGES);
+ Image image3 = images3[column3];
+ if (image3 == null) {
+ /* this item is drawn natively, don't touch it*/
+ break;
+ }
+
+ int x = event.x;
+ event.gc.drawImage(image3, x, event.y + (itemHeight - image3.getBounds().height) / 2);
+ x += image3.getBounds().width + TEXT_MARGIN;
+ event.gc.drawString(item3.getText(column3), x, event.y + (itemHeight - fontHeight) / 2);
+ break;
+ }
+ }
+ };
+ table.addListener(SWT.MeasureItem, paintListener);
+ table.addListener(SWT.EraseItem, paintListener);
+ table.addListener(SWT.PaintItem, paintListener);
+
+ for (int i = 0; i < COLUMN_COUNT; i++) {
+ table.getColumn(i).pack();
+ }
+
+ shell.addDisposeListener(e -> {
+ for (int i = 0; i < images.length; i++) {
+ if (images[i] != null) {
+ images[i].dispose();
+ }
+ }
+ });
+
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+ @Test
+ public void styledItems_Snippet236() {
+ Shell shell = mkShell("Verify tableitems with custom styleText control looks proper & multiple items can be selected");
+ shell.setLayout(new FillLayout());
+ Table table = new Table(shell, SWT.MULTI | SWT.FULL_SELECTION);
+ table.setLinesVisible(true);
+ for(int i = 0; i < 10; i++) {
+ new TableItem(table, SWT.NONE);
+ }
+ final TextLayout textLayout = new TextLayout(display);
+ textLayout.setText("SWT: Standard Widget Toolkit");
+ Font font1 = new Font(display, "Tahoma", 14, SWT.BOLD);
+ Font font2 = new Font(display, "Tahoma", 10, SWT.NORMAL);
+ Font font3 = new Font(display, "Tahoma", 14, SWT.ITALIC);
+ TextStyle style1 = new TextStyle(font1, display.getSystemColor(SWT.COLOR_BLUE), null);
+ TextStyle style2 = new TextStyle(font2, display.getSystemColor(SWT.COLOR_MAGENTA), null);
+ TextStyle style3 = new TextStyle(font3, display.getSystemColor(SWT.COLOR_RED), null);
+ textLayout.setStyle(style1, 0, 0); textLayout.setStyle(style1, 5, 12);
+ textLayout.setStyle(style2, 1, 1); textLayout.setStyle(style2, 14, 19);
+ textLayout.setStyle(style3, 2, 2); textLayout.setStyle(style3, 21, 27);
+
+ /*
+ * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly.
+ * Therefore, it is critical for performance that these methods be
+ * as efficient as possible.
+ */
+ table.addListener(SWT.PaintItem, event -> textLayout.draw(event.gc, event.x, event.y));
+ final Rectangle textLayoutBounds = textLayout.getBounds();
+ table.addListener(SWT.MeasureItem, e -> {
+ e.width = textLayoutBounds.width + 2;
+ e.height = textLayoutBounds.height + 2;
+ });
+ shell.setSize (SWIDTH, SHEIGHT);
+ shell.open();
+ shell.addDisposeListener(e -> {
+ font1.dispose();
+ font2.dispose();
+ font3.dispose();
+ textLayout.dispose();
+ });
+ mainLoop(shell);
+ }
+
+ @Test
+ public void cout_visible_items_Snippet253 () {
+ final Shell shell = mkShell("Ensure correct item count is displayed in count. Try resizing shell to show 15 items, it should show 15. Gtk3 issues");
+ knownToBeBrokenGtk3("On gtk3, the measure is off, see bug 531884");
+
+ FillLayout layout = new FillLayout (SWT.VERTICAL);
+ shell.setLayout (layout);
+ final Table table = new Table (shell, SWT.NONE);
+ for (int i=0; i<32; i++) {
+ TableItem item = new TableItem (table, SWT.NONE);
+ item.setText ("Item " + (i+1) + " is quite long");
+ }
+ final Button button = new Button (shell, SWT.PUSH);
+
+ Runnable fixCount = () -> {
+ Rectangle rect = table.getClientArea ();
+ int itemHeight = table.getItemHeight ();
+ int headerHeight = table.getHeaderHeight ();
+ int visibleCount = (rect.height - headerHeight + itemHeight - 1) / itemHeight;
+ button.setText ("Visible Items [" + visibleCount + "]");
+ };
+
+ button.setText ("Visible Items []");
+ button.addListener (SWT.Selection, e -> {
+ fixCount.run();
+ });
+
+ shell.addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent e) {
+ fixCount.run();
+ }
+ });
+ shell.addShellListener(new ShellAdapter() {
+ @Override
+ public void shellActivated(ShellEvent e) {
+ fixCount.run();
+ }
+ });
+ // setSize(..)_ affects bug/snippet behaviour.
+ shell.setSize(1160, 820); //820 => ~15 items or so, depending on your theme.
+ shell.open();
+ mainLoop(shell);
+ }
+
+
+ /** Snippet 149 was modified.
+ * - No added columns.
+ * - Button instead of progress bar.
+ */
+ @Test
+ public void tableEditor_multiple_controls_Snippet149 () {
+ knownToBeBrokenGtk3("Snippet is broken on Gtk3. See Bug 531885");
+ Shell shell = mkShell("Items should be replaced with Buttons (broken on Gtk3, Bug 531885)");
+ shell.setLayout (new FillLayout ());
+ Table table = new Table (shell, SWT.BORDER);
+ for (int i = 0; i < 20; i++) {
+ TableItem item = new TableItem (table, SWT.NONE);
+ item.setText ("Task " + i);
+ Button button = new Button (table, SWT.NONE);
+ button.setText("hello world " + i);
+ button.setVisible(true);
+ button.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ System.out.println("Button pressed");
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+ TableEditor editor = new TableEditor (table);
+ editor.grabHorizontal = editor.grabVertical = true;
+ editor.setEditor (button, item, 0);
+ }
+ shell.setSize (SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+
+ @Test
+ public void tableEditor_dynamically_created_Snippet124() {
+ Shell shell = mkShell("Verify you can edit cells");
+ shell.setLayout (new FillLayout ());
+ final Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
+ table.setLinesVisible (true);
+ for (int i=0; i<3; i++) {
+ TableColumn column = new TableColumn (table, SWT.NONE);
+ column.setWidth(100);
+ }
+ for (int i=0; i<3; i++) {
+ TableItem item = new TableItem (table, SWT.NONE);
+ item.setText(new String [] {"" + i, "" + i , "" + i});
+ }
+ final TableEditor editor = new TableEditor (table);
+ editor.horizontalAlignment = SWT.LEFT;
+ editor.grabHorizontal = true;
+ table.addListener (SWT.MouseDown, event -> {
+ Rectangle clientArea = table.getClientArea ();
+ Point pt = new Point (event.x, event.y);
+ int index = table.getTopIndex ();
+ while (index < table.getItemCount ()) {
+ boolean visible = false;
+ final TableItem item = table.getItem (index);
+ for (int i=0; i<table.getColumnCount (); i++) {
+ Rectangle rect = item.getBounds (i);
+ if (rect.contains (pt)) {
+ final int column = i;
+ final Text text = new Text (table, SWT.NONE);
+ Listener textListener = e -> {
+ switch (e.type) {
+ case SWT.FocusOut:
+ item.setText (column, text.getText ());
+ text.dispose ();
+ break;
+ case SWT.Traverse:
+ switch (e.detail) {
+ case SWT.TRAVERSE_RETURN:
+ item.setText (column, text.getText ());
+ //FALL THROUGH
+ case SWT.TRAVERSE_ESCAPE:
+ text.dispose ();
+ e.doit = false;
+ }
+ break;
+ }
+ };
+ text.addListener (SWT.FocusOut, textListener);
+ text.addListener (SWT.Traverse, textListener);
+ editor.setEditor (text, item, i);
+ text.setText (item.getText (i));
+ text.selectAll ();
+ text.setFocus ();
+ return;
+ }
+ if (!visible && rect.intersects (clientArea)) {
+ visible = true;
+ }
+ }
+ if (!visible) return;
+ index++;
+ }
+ });
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open ();
+ mainLoop(shell);
+ }
+}
+
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/MJ_root.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/MJ_root.java
new file mode 100644
index 0000000000..6e18831b09
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/MJ_root.java
@@ -0,0 +1,105 @@
+package org.eclipse.swt.tests.manualJUnit;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+
+/**
+ * Some tests can't be automated and have to be tested manually by visual inspection.
+ *
+ * For example visual glitches in Tree/Table editing (aka cheese).
+ *
+ * MJ_root is designed to make this a fast(er) process by running multiple tests in sequence
+ * and allowing human tester to quickly validate via keyboard input:
+ * F1 - Pass
+ * F2 - Fail
+ * F3 - Skip
+ * Esc - Quit the test sequence, no more tests are ran.
+ *
+ * Each test is independent. Notes:
+ * - A new display is created for each one. (thus tests are a bit slow, but are more independent than creating/disposing shells).
+ * - To pass a test programmatically, dispose the display.
+ * - To fail a test programmatically, use fail()
+ *
+ * Shells are created by tests themselves, but 'mkShell(..)' is there for convenience.
+ */
+public class MJ_root {
+
+ /** Default Shell values */
+ final int SWIDTH = 1200;
+ final int SHEIGHT = 800;
+
+ Display display;
+ @Before //each test.
+ public void setUp() {
+ display = new Display();
+ display.addFilter(SWT.KeyDown, globalTestValidatorViaKeyboard);
+ }
+
+ @After
+ public void tearDown() {
+ if (!display.isDisposed()) { // pass = shell is disposed.
+ display.dispose();
+ }
+ }
+
+ /** Convenience method that sets the shell title to current test name + description */
+ public Shell mkShell(String testInstructions) {
+ Shell shell = new Shell(display);
+ shell.setText(getCurrentTestName() + " -- " + testInstructions);
+ return shell;
+ }
+
+ void mainLoop(Shell shell) {
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ }
+
+ Listener globalTestValidatorViaKeyboard = e -> {
+ switch (e.keyCode) {
+ case SWT.F1:
+ System.out.println("TEST_Passed:" + getCurrentTestName());
+ display.dispose();
+ break;
+ case SWT.F2:
+ System.out.println("TEST_Failed:" + getCurrentTestName());
+ fail();
+ break;
+ case SWT.F3:
+ System.out.println("TEST_Skipped:" + getCurrentTestName());
+ assumeTrue(false);
+ break;
+ case SWT.ESC:
+ System.out.println("TEST_Quit on:" + getCurrentTestName());
+ System.exit(0);
+ break;
+ }
+ };
+
+ @Rule
+ public TestName testName = new TestName();
+ private String getCurrentTestName() {
+ return testName.getMethodName ();
+ }
+
+
+ // Util functions.
+ public void knownToBeBrokenGtk3(String msg) {
+ System.err.println(" info:" + getCurrentTestName() + " is known to be broken at the moment. Additional info: " + msg);
+ }
+
+ public void knownToBeBrokenGtk(String msg) {
+ System.err.println(" info:" + getCurrentTestName() + " is known to be broken at the moment. Additional info: " + msg);
+ }
+
+}
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/README b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/README
new file mode 100644
index 0000000000..b8c51dfdfc
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/README
@@ -0,0 +1,3 @@
+ Some tests can't be automated and have to be tested manually by visual inspection.
+
+ See MJ_root's javadoc for detail. (MJ = manual JUnit). \ No newline at end of file
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/Template.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/Template.java
new file mode 100644
index 0000000000..32fed1a482
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/manualJUnit/Template.java
@@ -0,0 +1,28 @@
+package org.eclipse.swt.tests.manualJUnit;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Shell;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/** Convienience class for easy copy & paste */
+@FixMethodOrder(MethodSorters.JVM)
+public class Template extends MJ_root {
+
+ @Test
+ public void test_template() {
+ Shell shell = mkShell("Instructions: Pass:F1 Fail:F2 Skip:F3 Exit:Esc");
+
+ Button button = new Button(shell, SWT.PUSH);
+ button.setText("Hello World");
+ button.pack();
+ button.setLocation(10, 10);
+
+ shell.setSize(SWIDTH, SHEIGHT);
+ shell.open();
+ mainLoop(shell);
+ }
+
+}

Back to the top