1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation. Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javafx.scene.control.test.tableview;
  26 
  27 import com.sun.javafx.scene.control.skin.TableColumnHeader;
  28 import java.util.ArrayList;
  29 import java.util.Collection;
  30 import java.util.Collections;
  31 import javafx.geometry.Orientation;
  32 import javafx.scene.Node;
  33 import javafx.scene.Scene;
  34 import javafx.scene.control.Button;
  35 import javafx.scene.control.CheckBox;
  36 import javafx.scene.control.Control;
  37 import javafx.scene.control.IndexedCell;
  38 import javafx.scene.control.Label;
  39 import javafx.scene.control.ScrollBar;
  40 import javafx.scene.control.TableCell;
  41 import javafx.scene.control.TableView;
  42 import javafx.scene.control.TextField;
  43 import javafx.scene.control.TreeTableCell;
  44 import javafx.scene.control.TreeTableView;
  45 import javafx.scene.control.test.treetable.TreeTableAsOldTableApp;
  46 import javafx.scene.control.test.util.MultipleSelectionHelper;
  47 import javafx.scene.control.test.util.UtilTestFunctions;
  48 import org.jemmy.Point;
  49 import org.jemmy.action.GetAction;
  50 import org.jemmy.control.Wrap;
  51 import org.jemmy.fx.ByID;
  52 import org.jemmy.fx.Root;
  53 import org.jemmy.interfaces.Drag;
  54 import org.jemmy.interfaces.Keyboard;
  55 import org.jemmy.interfaces.Parent;
  56 import org.jemmy.interfaces.Text;
  57 import org.jemmy.lookup.Lookup;
  58 import org.jemmy.lookup.LookupCriteria;
  59 import org.jemmy.timing.State;
  60 import org.junit.Before;
  61 import org.junit.BeforeClass;
  62 import test.javaclient.shared.Utils;
  63 import static javafx.commons.Consts.*;
  64 import javafx.scene.control.TableColumn;
  65 import java.util.Comparator;
  66 import java.util.concurrent.CountDownLatch;
  67 import javafx.application.Platform;
  68 import javafx.scene.control.TreeTableColumn;
  69 import org.jemmy.env.Timeout;
  70 import org.jemmy.timing.Waiter;
  71 
  72 /**
  73  * @author Alexander Kirov
  74  */
  75 public class TestBase extends UtilTestFunctions {
  76 
  77     protected static int DATA_ITEMS_NUM = 0;
  78     protected static int DATA_FIELDS_NUM = 0;
  79     protected static Wrap<? extends Control> testedControl; //ListView or TableView or TreeView
  80     protected static MultipleSelectionHelper selectionHelper;
  81     protected static Wrap<? extends Label> labelWrap;
  82     protected static Wrap<? extends Scene> sceneWrap;
  83     protected static Wrap<? extends Control> tableViewWrap;
  84     protected static Wrap<? extends Button> resetWrap;
  85     protected static Wrap<? extends TextField> selectedWrap;
  86     protected static Wrap<? extends CheckBox> multipleSelectionWrap;
  87     protected static Wrap<? extends CheckBox> singleCellSelectionWrap;
  88     protected static Wrap contentPane;
  89     protected static Wrap btnInsertItem;
  90     protected static Text txtItemInsertIndex;
  91     protected static Wrap btnRemoveItem;
  92     protected static Text txtItemRemoveIndex;
  93     protected static Wrap btnInsertColumn;
  94     protected static Text txtColumnInserIndex;
  95     protected static Wrap btnRemoveColumn;
  96     protected static Text txtColumnRemoveIndex;
  97     protected int pageWidthInCells;
  98     protected int pageHeightInCells;
  99     Wrap<? extends Node> headerWrap;
 100     protected static boolean isTableTests = true;
 101 
 102     private static int getColumnCount() {
 103         return isTableTests ? TableViewApp.DATA_FIELDS_NUM : TreeTableAsOldTableApp.DATA_FIELDS_NUM;
 104     }
 105 
 106     private static int getRowCount() {
 107         return isTableTests ? TableViewApp.DATA_ITEMS_NUM : TreeTableAsOldTableApp.DATA_ITEMS_NUM;
 108     }
 109 
 110     private static String getContentPaneID() {
 111         return TableViewApp.CONTENT_PANE_ID;
 112     }
 113 
 114     private static void initWrappers() {
 115         sceneWrap = Root.ROOT.lookup().wrap();
 116         parent = sceneWrap.as(Parent.class, Node.class);
 117         contentPane = parent.lookup(new ByID<Node>(getContentPaneID())).wrap();
 118         if (isTableTests) {
 119             tableViewWrap = parent.lookup(TableView.class).wrap();
 120         } else {
 121             tableViewWrap = parent.lookup(TreeTableView.class).wrap();
 122         }
 123         tableViewWrap.getEnvironment().setTimeout(Drag.IN_DRAG_TIMEOUT, 1);
 124 
 125         resetWrap = parent.lookup(Button.class, new ByID<Button>(RESET_BTN_ID)).wrap();
 126         selectedWrap = parent.lookup(TextField.class, new ByID<TextField>(SELECTED_ITEMS_ID)).wrap();
 127         multipleSelectionWrap = parent.lookup(CheckBox.class, new ByID<CheckBox>(ENABLE_MULTIPLE_SELECTION_ID)).wrap();
 128         btnInsertItem = parent.lookup(Button.class, new ByID<Button>(INSERT_ITEM_BTN_ID)).wrap();
 129         txtItemInsertIndex = (Text) parent.lookup(TextField.class, new ByID<TextField>(INSERT_ITEM_INDEX_ID)).wrap().as(Text.class);
 130         btnInsertColumn = parent.lookup(Button.class, new ByID<Button>(INSERT_COLUMN_BTN_ID)).wrap();
 131         txtColumnInserIndex = (Text) parent.lookup(TextField.class, new ByID<TextField>(INSERT_COLUMN_INDEX_ID)).wrap().as(Text.class);
 132         btnRemoveItem = parent.lookup(Button.class, new ByID<Button>(REMOVE_ITEM_BTN_ID)).wrap();
 133         txtItemRemoveIndex = (Text) parent.lookup(TextField.class, new ByID<TextField>(ITEM_INDEX_TO_REMOVE_ID)).wrap().as(Text.class);
 134         btnRemoveColumn = parent.lookup(Button.class, new ByID<Button>(REMOVE_COLUMN_BTN_ID)).wrap();
 135         txtColumnRemoveIndex = (Text) parent.lookup(TextField.class, new ByID<TextField>(COLUMN_INDEX_TO_REMOVE_ID)).wrap().as(Text.class);
 136 
 137         testedControl = tableViewWrap;
 138         setContentSize(getColumnCount(), getRowCount());
 139         if (isTableTests) {
 140             singleCellSelectionWrap = parent.lookup(CheckBox.class, new ByID<CheckBox>(TableViewApp.SINGLE_CELL_SELECTION_ID)).wrap();
 141         } else {
 142             singleCellSelectionWrap = parent.lookup(CheckBox.class, new ByID<CheckBox>(TreeTableAsOldTableApp.SINGLE_CELL_SELECTION_ID)).wrap();
 143         }
 144     }
 145 
 146     @BeforeClass
 147     public static void setUpClass() throws Exception {
 148         if (isTableTests) {
 149             System.out.println("Starting an old TableView application with simple controllers.");
 150             TableViewApp.main(null);
 151         } else {
 152             System.out.println("Starting a new TreeTable application created as an old TableView application.");
 153             TreeTableAsOldTableApp.main(null);
 154         }
 155         initWrappers();
 156     }
 157 
 158     @Before
 159     public void setUp() throws Exception {
 160         resetWrap.mouse().click();
 161         selectionHelper.setMultiple(false);
 162         selectionHelper.setSingleCell(false);
 163         pageWidthInCells = (int) (tableViewWrap.getScreenBounds().getWidth() / (TestBaseCommon.getCellWrap(testedControl, 1, 0).getScreenBounds().getX() - TestBaseCommon.getCellWrap(testedControl, 0, 0).getScreenBounds().getX()));
 164         pageHeightInCells = (int) ((tableViewWrap.getScreenBounds().getHeight() - TestBaseCommon.getHeaderWrap(tableViewWrap).getScreenBounds().getHeight()) / (TestBaseCommon.getCellWrap(testedControl, 0, 1).getScreenBounds().getY() - TestBaseCommon.getCellWrap(testedControl, 0, 0).getScreenBounds().getY()));
 165         headerWrap = TestBaseCommon.getHeaderWrap(tableViewWrap);
 166         selectionHelper.setPageHeight(pageHeightInCells);
 167         selectionHelper.setPageWidth(pageWidthInCells);
 168     }
 169 
 170     protected static void setContentSize(int x, int y) {
 171         DATA_FIELDS_NUM = x;
 172         DATA_ITEMS_NUM = y;
 173         selectionHelper = new MultipleSelectionHelper(DATA_FIELDS_NUM, DATA_ITEMS_NUM);
 174     }
 175 
 176     protected void selectionCycle(Keyboard.KeyboardButtons modifier) throws Throwable {
 177         if (Utils.isSmokeTesting()) {
 178             selectionCycle(0, 2, 0, 2, modifier);
 179         } else {
 180             selectionCycle(0, DATA_FIELDS_NUM, 0, DATA_ITEMS_NUM, modifier);
 181         }
 182         //selectionCycle(0, 3, 0, 3, modifier);
 183     }
 184 
 185     protected void selectionCycle(int first_column, int last_column, int first_row, int last_row, Keyboard.KeyboardButtons modifier) throws Throwable {
 186         if (modifier != null) {
 187             testedControl.keyboard().pressKey(modifier);
 188         }
 189         try {
 190             for (int j = first_column; j < last_column; j++) {
 191                 final int column = j;
 192                 for (int i = first_row; i < last_row; i++) {
 193                     final int row = i;
 194                     TestBaseCommon.scrollTo(testedControl, j, i);
 195                     TestBaseCommon.getCellWrap(testedControl, column, row).mouse().click();
 196                     selectionHelper.click(column, row, modifier);
 197                     checkSelection();
 198                 }
 199             }
 200         } catch (Throwable error) {
 201             throw error;
 202         } finally {
 203             if (modifier != null) {
 204                 testedControl.keyboard().releaseKey(modifier);
 205             }
 206         }
 207     }
 208 
 209     protected Lookup getScrollLookup(final Orientation orientation) {
 210         return parent.lookup(ScrollBar.class, new LookupCriteria<ScrollBar>() {
 211             public boolean check(ScrollBar cntrl) {
 212                 return (cntrl.getOrientation() == orientation) && cntrl.isVisible();
 213             }
 214         });
 215     }
 216 
 217     protected void insertAt(int pos) {
 218         txtItemInsertIndex.clear();
 219         txtItemInsertIndex.type(String.valueOf(pos));
 220         btnInsertItem.mouse().click();
 221     }
 222 
 223     protected void insertColumnAt(int pos) {
 224         txtColumnInserIndex.clear();
 225         txtColumnInserIndex.type(String.valueOf(pos));
 226         btnInsertColumn.mouse().click();
 227     }
 228 
 229     protected void removeAt(int pos) {
 230         txtItemRemoveIndex.clear();
 231         txtItemRemoveIndex.type(String.valueOf(pos));
 232         btnRemoveItem.mouse().click();
 233     }
 234 
 235     protected void removeColumnAt(int pos) {
 236         txtColumnRemoveIndex.clear();
 237         txtColumnRemoveIndex.type(String.valueOf(pos));
 238         btnRemoveColumn.mouse().click();
 239     }
 240 
 241     protected void keyboardCycle(int counter, Keyboard.KeyboardButtons btn, Keyboard.KeyboardModifiers modifier) {
 242         for (int i = 0; i < counter; i++) {
 243             tableViewWrap.keyboard().pushKey(btn, modifier);
 244         }
 245     }
 246 
 247     protected void keyboardSelectionCheckCycle(int counter, Keyboard.KeyboardButtons btn, Keyboard.KeyboardModifiers... modifier) {
 248         for (int i = 0; i < counter; i++) {
 249             keyboardCheck(btn, modifier);
 250         }
 251     }
 252 
 253     protected Wrap<? extends IndexedCell> getCellWrap(final int column, final int row) {
 254         return TestBaseCommon.getCellWrap(testedControl, column, row);
 255     }
 256 
 257     public static class ByPosition implements LookupCriteria<Node> {
 258 
 259         private int column, row;
 260 
 261         public ByPosition(int column, int row) {
 262             this.column = column;
 263             this.row = row;
 264         }
 265 
 266         public boolean check(Node control) {
 267             if (TableCell.class.isAssignableFrom(control.getClass())) {
 268                 return getColumnIndex((TableCell) control) == column
 269                         && getRowIndex((TableCell) control) == row;
 270             } else if (TreeTableCell.class.isAssignableFrom(control.getClass())) {
 271                 return getColumnIndex((TreeTableCell) control) == column
 272                         && getRowIndex((TreeTableCell) control) == row;
 273             } else {
 274                 return false;
 275             }
 276         }
 277     }
 278 
 279     protected static void switchOnMultiple() {
 280         new GetAction() {
 281             @Override
 282             public void run(Object... os) throws Exception {
 283                 multipleSelectionWrap.getControl().setSelected(true);
 284             }
 285         }.dispatch(Root.ROOT.getEnvironment());
 286     }
 287 
 288     protected void scrollTo(final int column, final int row) {
 289         TestBaseCommon.scrollTo(testedControl, column, row);
 290     }
 291 
 292     private static int getRowIndex(TableCell tableCell) {
 293         return TestBaseCommon.getRowIndex(tableCell);
 294     }
 295 
 296     private static int getRowIndex(TreeTableCell tableCell) {
 297         return TestBaseCommon.getRowIndex(tableCell);
 298     }
 299 
 300     private static int getColumnIndex(TableCell tableCell) {
 301         return TestBaseCommon.getColumnIndex(tableCell);
 302     }
 303 
 304     private static int getColumnIndex(TreeTableCell tableCell) {
 305         return TestBaseCommon.getColumnIndex(tableCell);
 306     }
 307 
 308     protected void checkSelection() {
 309         testedControl.waitState(new State() {
 310             Collection<Point> helper_selected;
 311             Collection<Point> selected;
 312             Point helperFocus;
 313             Point focus;
 314 
 315             public Object reached() {
 316                 helper_selected = selectionHelper.getSelected();
 317                 selected = TestBaseCommon.getSelected(testedControl);
 318                 helperFocus = selectionHelper.focus;
 319                 focus = TestBaseCommon.getSelectedItem(testedControl);
 320 
 321                 if (helper_selected.size() == selected.size()
 322                         && helper_selected.containsAll(selected)
 323                         && (focus.equals(helperFocus) || selectionHelper.ctrlA)) {
 324                     return true;
 325                 } else {
 326                     return null;
 327                 }
 328             }
 329 
 330             @Override
 331             public String toString() {
 332                 helper_selected = new ArrayList<Point>(helper_selected);
 333                 selected = new ArrayList<Point>(selected);
 334 
 335                 final Comparator<Point> comparator = new Comparator<Point>() {
 336                     public int compare(Point p1, Point p2) {
 337                         return p1.y - p2.y;
 338                     }
 339                 };
 340                 Collections.sort((ArrayList) helper_selected, comparator);
 341                 Collections.sort((ArrayList) selected, comparator);
 342 
 343                 StringBuilder sb;
 344                 sb = new StringBuilder("{")
 345                         .append("Helper selected : ").append(helper_selected).append("\n")
 346                         .append("Selected : ").append(selected).append("\n")
 347                         .append("Helper focus : ").append(helperFocus).append("\n")
 348                         .append("Contol focus : ").append(focus).append("}");
 349                 return sb.toString();
 350             }
 351         });
 352     }
 353 
 354     protected void keyboardCheck(Keyboard.KeyboardButtons btn, Keyboard.KeyboardModifiers... modifier) {
 355         if (btn == Keyboard.KeyboardButtons.PAGE_DOWN || btn == Keyboard.KeyboardButtons.PAGE_UP) {
 356             selectionHelper.setVisibleRange(TestBaseCommon.getVisibleRange(testedControl));
 357         }
 358         testedControl.keyboard().pushKey(btn, modifier);
 359         selectionHelper.push(btn, modifier);
 360         checkSelection();
 361     }
 362 
 363     protected String getControlName() {
 364         if (isTableTests) {
 365             return "TableView";
 366         } else {
 367             return "TreeTableView";
 368         }
 369     }
 370 
 371     Wrap scrollToColumnByIndexBtn;
 372     Text columnIndexToScroll;
 373 
 374     void scrollToColumnByIndex(final int index) {
 375         if (null == scrollToColumnByIndexBtn) {
 376             scrollToColumnByIndexBtn = parent.lookup(Button.class, new ByID<Button>(Table.SCROLL_TO_COLUMN_BTN_ID)).wrap();
 377         }
 378         if (null == columnIndexToScroll) {
 379             columnIndexToScroll = (Text) parent.lookup(TextField.class, new ByID<TextField>(Table.SCROLL_TO_COLUMN_INDEX_ID)).wrap().as(Text.class);
 380         }
 381 
 382         columnIndexToScroll.clear();
 383         columnIndexToScroll.type(String.valueOf(index));
 384         scrollToColumnByIndexBtn.mouse().click();
 385     }
 386 
 387     class Helper extends ApplicationInteractionFunctions {
 388 
 389         {
 390             testedControl = TestBase.testedControl;
 391         }
 392     }
 393 
 394     boolean isColumnHeaderVisible(final int index) {
 395 
 396         Boolean state = new Waiter(new Timeout("", 1000)).waitState(new State<Boolean>() {
 397             Helper helper = new Helper();
 398             Wrap<? extends TableColumnHeader> headerWrap;
 399 
 400             public Boolean reached() {
 401                 headerWrap = helper.getTableColumnHeaderWrap(getSimpleColumnHeaderText(index));
 402                 TableColumnHeader header = headerWrap.getControl();
 403                 if (header.isVisible()
 404                         && getSimpleColumnHeaderText(index).equals(header.getTableColumn().getText())
 405                         && testedControl.getScreenBounds().contains(headerWrap.getScreenBounds())) {
 406                     return Boolean.TRUE;
 407                 } else {
 408                     return null;
 409                 }
 410             }
 411         });
 412 
 413         return (null == state) ? false : true;
 414     }
 415 
 416     void scrollToColumn(final int index) {
 417         new GetAction<Void>() {
 418 
 419             @Override
 420             public void run(Object... parameters) throws Exception {
 421                 if (isTableTests) {
 422                     TableView tableView = (TableView) testedControl.getControl();
 423                     TableColumn col = (TableColumn) tableView.getColumns().get(index);
 424                     tableView.scrollToColumn(col);
 425                 } else {
 426 //                    TreeTableView treeTableView = (TreeTableView) testedControl.getControl();
 427 //                    TreeTableColumn col = (TreeTableColumn) treeTableView.getColumns().get(index);
 428 //                    treeTableView.scrollToColumn(col);
 429                     throw new RuntimeException("TreeTableView#scrollToColumn doesn't support TreeTableColumn type "
 430                             + "\nrefer: https://javafx-jira.kenai.com/browse/RT-31856");
 431                 }
 432             }
 433         }.dispatch(testedControl.getEnvironment());
 434     }
 435 
 436     void refill(final int cols, final int rows) {
 437 
 438         final String colsTextID = Table.COLUMNS_NUMBER_ID;
 439         final Text columnsText = (Text) parent.lookup(TextField.class, new ByID(colsTextID)).wrap().as(Text.class);
 440         columnsText.clear();
 441         columnsText.type(String.valueOf(cols));
 442 
 443         final String rowsTextID = Table.ROWS_NUMBER_ID;
 444         final Text rowsText = (Text) parent.lookup(TextField.class, new ByID(rowsTextID)).wrap().as(Text.class);
 445         rowsText.clear();
 446         rowsText.type(String.valueOf(rows));
 447 
 448         final String refillBtnID = Table.REFILL_BNT_ID;
 449         parent.lookup(Button.class, new ByID<Button>(refillBtnID)).wrap().mouse().click();
 450     }
 451 
 452     String getSimpleColumnHeaderText(final int index) {
 453         return "field " + index;
 454     }
 455 
 456     double getScrollBarValue(final Orientation orientation) {
 457         return new GetAction<Double>() {
 458 
 459             @Override
 460             public void run(Object... parameters) throws Exception {
 461                 Lookup hScrollBar = getScrollLookup(orientation);
 462                 setResult(((ScrollBar) hScrollBar.wrap().getControl()).getValue());
 463             }
 464         }.dispatch(testedControl.getEnvironment());
 465     }
 466 
 467     double getScrollBarMaxValue(final Orientation orientation) {
 468          return new GetAction<Double>() {
 469 
 470             @Override
 471             public void run(Object... parameters) throws Exception {
 472                 Lookup hScrollBar = getScrollLookup(orientation);
 473                 setResult(((ScrollBar) hScrollBar.wrap().getControl()).getMax());
 474             }
 475         }.dispatch(testedControl.getEnvironment());
 476     }
 477 
 478     double getScrollBarMinValue(final Orientation orientation) {
 479          return new GetAction<Double>() {
 480 
 481             @Override
 482             public void run(Object... parameters) throws Exception {
 483                 Lookup hScrollBar = getScrollLookup(orientation);
 484                 setResult(((ScrollBar) hScrollBar.wrap().getControl()).getMin());
 485             }
 486         }.dispatch(testedControl.getEnvironment());
 487     }
 488 
 489     void resizeColumn(final int index, final double delta) {
 490 
 491         final double initialWidth = getColumnWidth(index);
 492 
 493         new GetAction<Void>() {
 494             @Override
 495             public void run(Object... os) throws Exception {
 496                 if (isTableTests) {
 497                     TableView table = (TableView) testedControl.getControl();
 498                     table.resizeColumn((TableColumn) table.getColumns().get(index), delta);
 499                 } else {
 500                     TreeTableView treeTable = (TreeTableView) testedControl.getControl();
 501                     treeTable.resizeColumn((TreeTableColumn) treeTable.getColumns().get(index), delta);
 502                 }
 503             }
 504         }.dispatch(testedControl.getEnvironment());
 505 
 506         new Waiter(new Timeout("", 1000)).waitState(new State<Boolean>() {
 507             public Boolean reached() {
 508                 return (Math.abs(getColumnWidth(index) - initialWidth - delta) <= 1e-7) ? Boolean.TRUE : null;
 509             }
 510         });
 511     }
 512 
 513     protected void setColumnTextSync(final int index, final String text) {
 514     assert !Platform.isFxApplicationThread();
 515     CountDownLatch latch = new CountDownLatch(1);
 516         Platform.runLater(() -> {
 517                 if (isTableTests) {
 518                     TableView table = (TableView) testedControl.getControl();
 519                     ((TableColumn) table.getColumns().get(index)).setText(text);
 520                 } else {
 521                     TreeTableView treeTable = (TreeTableView) testedControl.getControl();
 522                     ((TreeTableColumn) treeTable.getColumns().get(index)).setText(text);
 523                 }
 524             latch.countDown();
 525         });
 526         try {
 527             latch.await();
 528         } catch (InterruptedException ex) {
 529             System.out.println("Exception while awaiting text to set: " + ex);
 530         }
 531     }
 532 
 533     protected String getColumnText(final int index) {
 534         if (isTableTests) {
 535             TableView table = (TableView) testedControl.getControl();
 536             return ((TableColumn) table.getColumns().get(index)).getText();
 537         } else {
 538             TreeTableView treeTable = (TreeTableView) testedControl.getControl();
 539             return ((TreeTableColumn) treeTable.getColumns().get(index)).getText();
 540         }
 541     }
 542 
 543     protected double getColumnWidth(final int index) {
 544         return new Helper().getCellWrap(index, 0).getScreenBounds().getWidth();
 545     }
 546 }