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.util; 26 27 import com.sun.javafx.geom.PickRay; 28 import com.sun.javafx.geom.Vec3d; 29 import com.sun.javafx.scene.input.PickResultChooser; 30 import java.util.AbstractMap; 31 import java.util.ArrayList; 32 import java.util.Collection; 33 import java.util.HashMap; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Map.Entry; 37 import javafx.event.ActionEvent; 38 import javafx.event.EventHandler; 39 import javafx.geometry.Orientation; 40 import javafx.geometry.Point2D; 41 import javafx.scene.Node; 42 import javafx.scene.Scene; 43 import javafx.scene.control.*; 44 import javafx.scene.control.test.ControlsTestBase; 45 import javafx.scene.control.test.utils.CommonPropertiesScene; 46 import javafx.scene.control.test.utils.ComponentsFactory.MultipleIndexFormComponent; 47 import javafx.scene.control.test.utils.ptables.AbstractApplicationPropertiesRegystry; 48 import javafx.scene.control.test.utils.ptables.AbstractEventsCounter; 49 import javafx.scene.control.test.utils.ptables.AbstractPropertiesTable; 50 import static javafx.scene.control.test.utils.ptables.AbstractPropertiesTable.BIDIR_PREFIX; 51 import static javafx.scene.control.test.utils.ptables.AbstractPropertiesTable.UNIDIR_PREFIX; 52 import javafx.scene.control.test.utils.ptables.AbstractPropertyController.SettingType; 53 import javafx.scene.control.test.utils.ptables.AbstractPropertyValueListener; 54 import static javafx.scene.control.test.utils.ptables.AbstractPropertyValueSetter.CONTROLLER_SUFFIX; 55 import static javafx.scene.control.test.utils.ptables.AbstractPropertyValueSetter.SET_PREFIX; 56 import javafx.scene.control.test.utils.ptables.AbstractStateCheckable.StateChangedException; 57 import static javafx.scene.control.test.utils.ptables.NodesChoserFactory.*; 58 import javafx.scene.control.test.utils.ptables.PropertiesTable; 59 import static javafx.scene.control.test.utils.ptables.PropertyValueListener.LISTENER_SUFFIX; 60 import static javafx.scene.control.test.utils.ptables.TabPaneWithControl.TAB_CONTENT_ID; 61 import static javafx.scene.control.test.utils.ptables.TabPaneWithControl.TAB_PANE_WITH_CONTROL_ID; 62 import static javafx.scene.control.test.utils.ptables.TextFieldEventsCounter.COUNTER_SUFFIX; 63 import static javafx.scene.control.test.utils.ptables.ToggleBindingSwitcher.BIND_BUTTON_SUFFIX; 64 import javafx.scene.input.ScrollEvent; 65 import javafx.scene.input.ScrollEvent.HorizontalTextScrollUnits; 66 import javafx.scene.input.ScrollEvent.VerticalTextScrollUnits; 67 import javafx.scene.text.Font; 68 import org.jemmy.Point; 69 import org.jemmy.Rectangle; 70 import org.jemmy.action.Action; 71 import org.jemmy.action.GetAction; 72 import org.jemmy.control.Wrap; 73 import org.jemmy.env.Timeout; 74 import org.jemmy.fx.ByID; 75 import org.jemmy.fx.NodeWrap; 76 import org.jemmy.fx.Root; 77 import org.jemmy.fx.control.TabPaneDock; 78 import static org.jemmy.fx.control.TextControlWrap.SELECTED_PROP_NAME; 79 import org.jemmy.input.AbstractScroll; 80 import org.jemmy.interfaces.Keyboard.KeyboardModifiers; 81 import org.jemmy.interfaces.Parent; 82 import org.jemmy.interfaces.Selectable; 83 import org.jemmy.interfaces.Text; 84 import org.jemmy.lookup.LookupCriteria; 85 import org.jemmy.timing.State; 86 import org.jemmy.timing.Waiter; 87 import static org.junit.Assert.*; 88 import test.javaclient.shared.TestUtil; 89 import test.javaclient.shared.Utils; 90 91 /** 92 * @author Alexander Kirov 93 * 94 * Used for many my tests. Don't touch it until you are sure, what you do. 95 */ 96 public class UtilTestFunctions extends ControlsTestBase { 97 98 protected static Parent<Node> parent; 99 protected static KeyboardModifiers CTRL_DOWN_MASK_OS; 100 protected static ChangingController defaultController; 101 protected static final int ITERATIONS = 3; 102 protected static final int SLEEP = 300; 103 protected static double ASSERT_CMP_PRECISION = 3.5; 104 protected static SettingOption currentSettingOption = SettingOption.PROGRAM; 105 private static Parent<Node> propertiesTableScrollPane = null; 106 private static final boolean useCaching = true; 107 private static String currentTabName = AbstractApplicationPropertiesRegystry.DEFAULT_DOMAIN_NAME; 108 private static final String CUSTOM_STYLE_CONST = "imagescomparator/custom_font.css"; 109 private String rememberedStylesheet; 110 111 static { 112 if (Utils.isMacOS()) { 113 CTRL_DOWN_MASK_OS = KeyboardModifiers.META_DOWN_MASK; 114 } else { 115 CTRL_DOWN_MASK_OS = KeyboardModifiers.CTRL_DOWN_MASK; 116 } 117 } 118 119 protected void initChangingController(Parent<Node> parent) { 120 defaultController = new ChangingController(parent); 121 } 122 123 /** 124 * Clicks toggle button with according id. 125 * 126 * @param toggleButtonId 127 */ 128 protected static void clickToggleButton(String toggleButtonId) { 129 findToggleButton(toggleButtonId).mouse().click(); 130 } 131 132 /** 133 * Checks, whether the toggle button has a toggled state as asked. 134 * 135 * @param toggleButtonId 136 * @param selectedExpected 137 */ 138 protected static void checkToggleButtonSelection(String toggleButtonId, boolean selectedExpected) { 139 findToggleButton(toggleButtonId).waitProperty(SELECTED_PROP_NAME, selectedExpected); 140 } 141 142 /** 143 * Change toggle button's state to value, with set id. 144 * 145 * @param buttonId 146 */ 147 protected static void setToggleButtonSelectedStateForTestPurpose(final String buttonId, final Boolean newValue) { 148 final Wrap<? extends ToggleButton> btnWrap = findToggleButton(buttonId); 149 Boolean curValue = new GetAction<Boolean>() { 150 @Override 151 public void run(Object... os) throws Exception { 152 setResult(btnWrap.getControl().isSelected()); 153 } 154 }.dispatch(Root.ROOT.getEnvironment()); 155 156 switch (currentSettingOption) { 157 case MANUAL: 158 if (curValue != newValue) { 159 clickToggleButtonByID(buttonId); 160 } 161 break; 162 case PROGRAM: 163 if (curValue != newValue) { 164 new GetAction() { 165 @Override 166 public void run(Object... os) throws Exception { 167 findToggleButton(buttonId).getControl().setSelected(newValue); 168 } 169 }.dispatch(Root.ROOT.getEnvironment()); 170 } 171 break; 172 } 173 } 174 175 /** 176 * Clicks button with set id. 177 * 178 * @param buttonId 179 */ 180 protected static void clickButtonForTestPurpose(final String buttonId) { 181 switch (currentSettingOption) { 182 case MANUAL: 183 clickButtonByID(buttonId); 184 break; 185 case PROGRAM: 186 new GetAction() { 187 @Override 188 public void run(Object... os) throws Exception { 189 Button btn = findButton(buttonId).getControl(); 190 EventHandler<ActionEvent> onAction = btn.getOnAction(); 191 if (null != onAction) { 192 onAction.handle(null); 193 } else { 194 System.err.format("onAction event handler is not set for [%s]%n", buttonId); 195 btn.fire(); 196 } 197 } 198 }.dispatch(Root.ROOT.getEnvironment()); 199 break; 200 default: 201 throw new IllegalStateException("Unknown option."); 202 } 203 } 204 205 protected static void clickToggleButtonByID(String buttonId) { 206 findToggleButton(buttonId).mouse().click(); 207 } 208 209 protected static void clickButtonByID(String buttonId) { 210 findButton(buttonId).mouse().click(); 211 } 212 213 /** 214 * Checks focused state of control. 215 * 216 * @param nodeId 217 * @param isFocused 218 */ 219 protected static void checkFocus(String nodeId, boolean isFocused) { 220 findControl(nodeId).waitProperty("isFocused", isFocused); 221 } 222 223 // Two functions clicking arrows of the scrollBar. 224 // This function make click over scrollBar (left or up arrow) 225 protected static void clickLess(Wrap<? extends ScrollBar> wrap) { 226 wrap.mouse().click(1, new Point(5, 5)); 227 } 228 229 // This function make click over scrollBar (right or down arrow) 230 protected static void clickMore(Wrap<? extends ScrollBar> wrap) { 231 wrap.mouse().click(1, new Point(wrap.getScreenBounds().width - 5, wrap.getScreenBounds().height - 5)); 232 } 233 234 /** 235 * ******************************************************************* 236 * 237 * SECTION OF MANUAL CONTROLING 238 * 239 ******************************************************************** 240 */ 241 // DIRECT PROPERTIES CONTROL 242 protected void requestFocusOnControl(final Wrap<? extends Node> control) { 243 new GetAction() { 244 @Override 245 public void run(Object... os) throws Exception { 246 control.getControl().requestFocus(); 247 } 248 }.dispatch(Root.ROOT.getEnvironment()); 249 } 250 251 protected static void setSliderPosition(String id, final double toPosition, SettingOption option) throws InterruptedException { 252 Thread.sleep(SLEEP); 253 setSliderPosition(findSlider(id), toPosition, option); 254 } 255 256 protected static void setSliderPosition(final Wrap<? extends Slider> propertySliderWrap, final double toPosition, SettingOption option) throws InterruptedException { 257 switch (option) { 258 case MANUAL: 259 AbstractScroll abstrScroll = propertySliderWrap.as(AbstractScroll.class); 260 abstrScroll.allowError(ASSERT_CMP_PRECISION / 4); 261 abstrScroll.caret().to(toPosition); 262 break; 263 case PROGRAM: 264 new GetAction<Point2D>() { 265 @Override 266 public void run(Object... os) throws Exception { 267 propertySliderWrap.getControl().setValue(toPosition); 268 } 269 }.dispatch(Root.ROOT.getEnvironment()); 270 Thread.sleep(SLEEP); 271 } 272 } 273 274 protected static void setChoiceBoxValue(String controlID, final Object value) { 275 switch (currentSettingOption) { 276 case MANUAL: 277 findChoiceBox(controlID).as(Selectable.class).selector().select(value); 278 //new org.jemmy.fx.control.ChoiceBoxDock(parent, controlID).asSelectable().selector().select(value); 279 //parent.lookup(ChoiceBox.class, new ByID<ChoiceBox>(getPrefix(type) + propType.toString().toUpperCase() + CHOICE_BOX_SUFFIX)).wrap().as(Selectable.class).selector().select(propValue.name()); 280 break; 281 case PROGRAM: 282 final Object actualValue = getChoiceBoxState(controlID); 283 if (!value.equals(actualValue)) { 284 final ChoiceBox cb = findChoiceBox(controlID).getControl(); 285 new GetAction() { 286 @Override 287 public void run(Object... os) throws Exception { 288 cb.setValue(value); 289 } 290 }.dispatch(Root.ROOT.getEnvironment()); 291 } 292 break; 293 } 294 } 295 296 protected static void changePropertyControlBindingToggleButtonState(SettingType type, Enum propType) { 297 changeToggleButtonState(getPrefix(type) + propType.toString().toUpperCase() + BIND_BUTTON_SUFFIX); 298 } 299 300 protected static void changeToggleButtonState(String controlID) { 301 switch (currentSettingOption) { 302 case MANUAL: 303 findToggleButton(controlID).mouse().click(); 304 break; 305 case PROGRAM: 306 final boolean selected = getToggleButtonState(controlID); 307 final ToggleButton tb = findToggleButton(controlID).getControl(); 308 new GetAction() { 309 @Override 310 public void run(Object... os) throws Exception { 311 tb.setSelected(!selected); 312 } 313 }.dispatch(Root.ROOT.getEnvironment()); 314 break; 315 } 316 } 317 318 protected static void changeTextFieldText(String controlID, final String newText) { 319 switch (currentSettingOption) { 320 case MANUAL: 321 Text text = findTextField(controlID).as(Text.class); 322 text.clear(); 323 text.type(newText); 324 break; 325 case PROGRAM: 326 final TextField tf = findTextField(controlID).getControl(); 327 new GetAction() { 328 @Override 329 public void run(Object... os) throws Exception { 330 tf.setText(newText); 331 } 332 }.dispatch(Root.ROOT.getEnvironment()); 333 break; 334 } 335 } 336 337 protected static void switchToPropertiesTab(final String tabName) { 338 if (useCaching) { 339 Cache.clear(); 340 } 341 final Wrap<? extends TabPane> tabPane = parent.lookup(TabPane.class, new ByID<TabPane>(TAB_PANE_WITH_CONTROL_ID)).wrap(); 342 switch (currentSettingOption) { 343 case MANUAL: 344 Tab tab = new GetAction<Tab>() { 345 @Override 346 public void run(Object... os) throws Exception { 347 for (Tab tab : tabPane.getControl().getTabs()) { 348 if (tab.getText().equals(tabName)) { 349 setResult(tab); 350 } 351 } 352 } 353 }.dispatch(Root.ROOT.getEnvironment()); 354 TabPaneDock dock = new TabPaneDock(tabPane); 355 dock.asSelectable().selector().select(tab); 356 break; 357 case PROGRAM: 358 new GetAction() { 359 @Override 360 public void run(Object... os) throws Exception { 361 Tab tabToSelect = null; 362 for (Tab tab : tabPane.getControl().getTabs()) { 363 if (tab.getText().equals(tabName)) { 364 tabToSelect = tab; 365 } 366 } 367 if (tabToSelect == null) { 368 throw new Exception("Tab with name <" + tabName + "> could not be found"); 369 } else { 370 tabPane.getControl().getSelectionModel().select(tabToSelect); 371 } 372 } 373 }.dispatch(Root.ROOT.getEnvironment()); 374 break; 375 } 376 377 //Wait, until content of according Tab (root item of tab is scrollPane, 378 //with preset Id), will be findable on the scene. 379 new Waiter(new Timeout("", TestUtil.isEmbedded() ? 20000 : 2000)).ensureState(new State() { 380 public Object reached() { 381 if (parent.lookup(ScrollPane.class, new ByID<ScrollPane>(tabName + TAB_CONTENT_ID)).size() == 1) { 382 return true; 383 } else { 384 return null; 385 } 386 } 387 }); 388 389 propertiesTableScrollPane = parent.lookup(ScrollPane.class, new ByID<ScrollPane>(tabName + javafx.scene.control.test.utils.ptables.TabPaneWithControl.TAB_CONTENT_ID)).wrap().as(Parent.class, Node.class); 390 currentTabName = tabName; 391 } 392 393 // WORKING WITH LISTENING TEXT FIELDS 394 protected static void checkText(String textFieldId, String expectedText) { 395 findTextField(textFieldId).waitProperty(Wrap.TEXT_PROP_NAME, expectedText); 396 } 397 398 protected static void checkTextFieldText(Enum propType, String expectedText) { 399 findTextField(propType.toString().toUpperCase() + LISTENER_SUFFIX).waitProperty(Wrap.TEXT_PROP_NAME, expectedText); 400 if (defaultController != null) { 401 defaultController.removeProperty(currentTabName, propType); 402 } 403 } 404 405 protected static void checkTextFieldTextContaining(final Enum propType, final String expectedContainedText) { 406 final TextField tf = findTextField(propType.toString().toUpperCase() + LISTENER_SUFFIX).getControl(); 407 new Waiter(new Timeout("", TestUtil.isEmbedded() ? 20000 : 2000)).ensureState(new State() { 408 public Object reached() { 409 if (tf.getText().contains(expectedContainedText)) { 410 return true; 411 } else { 412 return null; 413 } 414 } 415 }); 416 417 if (defaultController != null) { 418 defaultController.removeProperty(currentTabName, propType); 419 } 420 } 421 422 protected static void checkTextFieldValue(Enum propType, final double expectedValue) { 423 final Wrap<? extends TextField> tfwrap = findTextField(propType.toString().toUpperCase() + LISTENER_SUFFIX); 424 new Waiter(new Timeout("", TestUtil.isEmbedded() ? 20000 : 2000)).ensureState(new State() { 425 public Object reached() { 426 if (Math.abs(Double.parseDouble(tfwrap.getControl().getText()) - expectedValue) < ASSERT_CMP_PRECISION) { 427 return true; 428 } else { 429 return null; 430 } 431 } 432 }); 433 434 if (defaultController != null) { 435 defaultController.removeProperty(currentTabName, propType); 436 } 437 } 438 439 protected static void checkTextFieldValue(Enum propType, final int expectedValue, final double COMPARISON_DELTA) { 440 final Wrap<? extends TextField> tfwrap = findTextField(propType.toString().toUpperCase() + LISTENER_SUFFIX); 441 new Waiter(new Timeout("", TestUtil.isEmbedded() ? 20000 : 2000)).ensureState(new State() { 442 double actual; 443 444 public Object reached() { 445 actual = Double.parseDouble(tfwrap.getControl().getText()); 446 if (Math.abs(actual - expectedValue) <= COMPARISON_DELTA) { 447 return true; 448 } else { 449 return null; 450 } 451 } 452 453 @Override 454 public String toString() { 455 return String.format("[Expected:%d, got:%.6f, delta:%.6f]", 456 expectedValue, actual, COMPARISON_DELTA); 457 } 458 }); 459 460 if (defaultController != null) { 461 defaultController.removeProperty(currentTabName, propType); 462 } 463 } 464 465 protected static void checkTextFieldValue(Enum propType, int expectedValue) {//more strict for int values. 466 checkTextFieldValue(propType, expectedValue, ASSERT_CMP_PRECISION); 467 } 468 469 protected static void checkSimpleListenerValue(Enum propType, final int expectedValue) { 470 final Wrap<? extends TextField> tfwrap = findTextField(propType.toString().toUpperCase() + LISTENER_SUFFIX); 471 new Waiter(new Timeout("", TestUtil.isEmbedded() ? 20000 : 2000)).ensureState(new State() { 472 public Object reached() { 473 if (Math.abs(Double.parseDouble(tfwrap.getControl().getText()) - expectedValue) == 0) { 474 return true; 475 } else { 476 System.err.println("Diff : tfwrap.getControl().getText() = " + tfwrap.getControl().getText() + "; expectedValue = " + expectedValue); 477 return null; 478 } 479 } 480 }); 481 482 if (defaultController != null) { 483 defaultController.removeProperty(currentTabName, propType); 484 } 485 } 486 487 protected static void checkFontSize(Enum property, Double expectedSize) { 488 final Wrap<? extends TextField> tfwrap = findTextField(property.toString().toUpperCase() + LISTENER_SUFFIX); 489 String fontDescription = new GetAction<String>() { 490 @Override 491 public void run(Object... os) throws Exception { 492 setResult(tfwrap.getControl().getText()); 493 } 494 }.dispatch(Root.ROOT.getEnvironment()); 495 496 String fontSize = fontDescription.substring(fontDescription.indexOf("size=") + "size=".length(), fontDescription.indexOf(']', fontDescription.indexOf("size="))); 497 assertEquals(Double.parseDouble(fontSize), expectedSize, 0.5); 498 } 499 500 protected static void checkSimpleListenerValue(Enum propType, String expectedText) { 501 findTextField(propType.toString().toUpperCase() + LISTENER_SUFFIX).waitProperty(Wrap.TEXT_PROP_NAME, expectedText); 502 } 503 504 protected static void checkCounterValue(Enum propType, int expectedValue) { 505 checkCounterValue(propType.toString().toUpperCase(), expectedValue); 506 } 507 508 protected static void checkCounterValue(String counterName, final int expectedValue) { 509 final Wrap<? extends TextField> tfwrap = findTextField(counterName.toUpperCase() + COUNTER_SUFFIX); 510 new Waiter(new Timeout("", TestUtil.isEmbedded() ? 20000 : 5000)).ensureState(new State() { 511 public Object reached() { 512 if (Math.abs(Double.parseDouble(tfwrap.getControl().getText()) - expectedValue) == 0) { 513 return true; 514 } else { 515 return null; 516 } 517 } 518 519 @Override 520 public String toString() { 521 return String.format("Expected value: %d, actual: %f.2", expectedValue, Double.parseDouble(tfwrap.getControl().getText())); 522 } 523 }); 524 525 if (defaultController != null) { 526 defaultController.removeCounter(currentTabName, counterName); 527 } 528 } 529 530 // SEARCHERS 531 protected static Wrap<? extends ScrollBar> findScrollBar(final Parent<Node> parentWrap, final Orientation orientation, final Boolean visible) { 532 final LookupCriteria<ScrollBar> lc = new LookupCriteria<ScrollBar>() { 533 public boolean check(ScrollBar cntrl) { 534 return ((cntrl.isVisible() == visible) && (cntrl.getOrientation() == orientation)); 535 } 536 }; 537 538 try { 539 new Waiter(new Timeout("", TestUtil.isEmbedded() ? 20000 : 2000)).ensureState(new State() { 540 public Object reached() { 541 if (parentWrap.lookup(ScrollBar.class, lc).size() > 0) { 542 return true; 543 } else { 544 return null; 545 } 546 } 547 }); 548 } catch (Exception ex) { 549 return null; 550 } 551 552 return parentWrap.lookup(ScrollBar.class, lc).wrap(); 553 } 554 555 protected static Wrap<? extends ScrollBar> findScrollBar(Parent<Node> parentWrap, Orientation orientation) { 556 return findScrollBar(parentWrap, orientation, true); 557 } 558 559 protected static Wrap<? extends ScrollBar> findScrollBar(Parent<Node> parentWrap) { 560 Wrap<? extends ScrollBar> sb1, sb2; 561 sb1 = findScrollBar(parentWrap, Orientation.VERTICAL); 562 sb2 = findScrollBar(parentWrap, Orientation.HORIZONTAL); 563 if (sb1 != null) { 564 return sb1; 565 } else { 566 return sb2; 567 } 568 } 569 570 // CONTROL 571 protected static void setPropertyBySlider(SettingType type, Enum propType, double toPosition) throws InterruptedException { 572 if (type == SettingType.SETTER) { 573 switchOffBinding(SettingType.UNIDIRECTIONAL, propType); 574 setSliderPosition(getPrefix(SettingType.UNIDIRECTIONAL) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX, toPosition, currentSettingOption); 575 clickButtonForTestPurpose(SET_PREFIX + propType.toString().toUpperCase()); 576 } else { 577 switchOnBinding(type, propType); 578 setSliderPosition(getPrefix(type) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX, toPosition, currentSettingOption); 579 } 580 581 if (defaultController != null) { 582 defaultController.removeProperty(currentTabName, propType); 583 } 584 } 585 586 protected static void setPropertyByToggleClick(SettingType type, Enum propType) { 587 if (type == SettingType.SETTER) { 588 switchOffBinding(SettingType.UNIDIRECTIONAL, propType); 589 changeToggleButtonState(getPrefix(SettingType.UNIDIRECTIONAL) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX); 590 clickButtonForTestPurpose(SET_PREFIX + propType.toString().toUpperCase()); 591 } else { 592 switchOnBinding(type, propType); 593 changeToggleButtonState(getPrefix(type) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX); 594 } 595 596 if (defaultController != null) { 597 defaultController.removeProperty(currentTabName, propType); 598 } 599 } 600 601 protected static void setPropertyByToggleClick(SettingType type, Enum propType, Boolean newVal) { 602 603 if (type == SettingType.SETTER) { 604 String btnID = getPrefix(SettingType.UNIDIRECTIONAL) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX; 605 final Wrap<? extends ToggleButton> btnWrap = findToggleButton(btnID); 606 607 Boolean curVal = new GetAction<Boolean>() { 608 @Override 609 public void run(Object... os) throws Exception { 610 setResult(btnWrap.getControl().isSelected()); 611 } 612 }.dispatch(Root.ROOT.getEnvironment()); 613 614 switchOffBinding(SettingType.UNIDIRECTIONAL, propType); 615 if (curVal != newVal) { 616 setToggleButtonSelectedStateForTestPurpose(btnID, newVal); 617 } 618 clickButtonForTestPurpose(SET_PREFIX + propType.toString().toUpperCase()); 619 } else { 620 String btnID = getPrefix(type) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX; 621 setToggleButtonSelectedStateForTestPurpose(btnID, newVal); 622 switchOnBinding(type, propType); 623 } 624 625 if (defaultController != null) { 626 defaultController.removeProperty(currentTabName, propType); 627 } 628 } 629 630 protected static void setPropertyByChoiceBox(SettingType type, Object propValue, Enum propType) { 631 if (type == SettingType.SETTER) { 632 switchOffBinding(SettingType.UNIDIRECTIONAL, propType); 633 setChoiceBoxValue(getPrefix(SettingType.UNIDIRECTIONAL) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX, propValue); 634 clickButtonForTestPurpose(SET_PREFIX + propType.toString().toUpperCase()); 635 } else { 636 switchOnBinding(type, propType); 637 setChoiceBoxValue(getPrefix(type) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX, propValue); 638 } 639 640 if (defaultController != null) { 641 defaultController.removeProperty(currentTabName, propType); 642 } 643 } 644 645 protected static void setPropertyByTextField(SettingType type, Enum propType, String value) { 646 if (type == SettingType.SETTER) { 647 switchOffBinding(SettingType.UNIDIRECTIONAL, propType); 648 changeTextFieldText(getPrefix(SettingType.UNIDIRECTIONAL) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX, value); 649 clickButtonForTestPurpose(SET_PREFIX + propType.toString().toUpperCase()); 650 } else { 651 switchOnBinding(type, propType); 652 changeTextFieldText(getPrefix(type) + propType.toString().toUpperCase() + CONTROLLER_SUFFIX, value); 653 } 654 655 if (defaultController != null) { 656 defaultController.removeProperty(currentTabName, propType); 657 } 658 } 659 660 protected void selectControlFromFactory(final int index) { 661 final Wrap<? extends ChoiceBox> choice = (Wrap<? extends ChoiceBox>) findControl(NODE_CHOSER_CHOICE_BOX_ID); 662 new GetAction() { 663 @Override 664 public void run(Object... os) throws Exception { 665 choice.getControl().getSelectionModel().select(index); 666 } 667 }.dispatch(Root.ROOT.getEnvironment()); 668 } 669 670 protected void selectControlFromFactory(final Class controlClass) { 671 final Wrap<? extends ChoiceBox> choice = (Wrap<? extends ChoiceBox>) findControl(NODE_CHOSER_CHOICE_BOX_ID); 672 new GetAction() { 673 @Override 674 public void run(Object... os) throws Exception { 675 for (Object item : choice.getControl().getItems()) { 676 if (item.getClass() == controlClass) { 677 choice.getControl().getSelectionModel().select(item); 678 } 679 } 680 681 } 682 }.dispatch(Root.ROOT.getEnvironment()); 683 } 684 685 protected int controlsFactorySize() { 686 final Wrap<? extends ChoiceBox> choice = (Wrap<? extends ChoiceBox>) findControl(NODE_CHOSER_CHOICE_BOX_ID); 687 return new GetAction<Integer>() { 688 @Override 689 public void run(Object... os) throws Exception { 690 setResult(choice.getControl().getItems().size()); 691 } 692 }.dispatch(Root.ROOT.getEnvironment()); 693 } 694 695 /* 696 * This is complex method. It should be able to select different fonts, and 697 * different objects at all. So it will be executed always in a way, like 698 * "program" (not manual) execution done. 699 */ 700 protected static void selectObjectFromChoiceBox(SettingType settingType, Enum property, Object whichToChose) { 701 Wrap<? extends ChoiceBox> choice; 702 if (settingType == SettingType.SETTER) { 703 switchOffBinding(SettingType.UNIDIRECTIONAL, property); 704 choice = findChoiceBox(getPrefix(SettingType.UNIDIRECTIONAL) + property.toString().toUpperCase() + CONTROLLER_SUFFIX); 705 } else { 706 choice = findChoiceBox(getPrefix(settingType) + property.toString().toUpperCase() + CONTROLLER_SUFFIX); 707 } 708 709 selectObjectFromChoiceBox(choice, whichToChose); 710 711 if (settingType.equals(SettingType.SETTER)) { 712 clickButtonForTestPurpose(SET_PREFIX + property.toString().toUpperCase()); 713 } else { 714 switchOnBinding(settingType, property); 715 } 716 717 if (defaultController != null) { 718 defaultController.removeProperty(currentTabName, property); 719 } 720 } 721 722 protected static void selectObjectFromChoiceBox(Wrap<? extends ChoiceBox> choiceBox, final Object whatToChose) { 723 switch (currentSettingOption) { 724 case MANUAL: 725 choiceBox.as(Selectable.class).selector().select(whatToChose); 726 break; 727 case PROGRAM: 728 new GetAction<Object>() { 729 @Override 730 public void run(Object... os) throws Exception { 731 ChoiceBox choiceBox = (ChoiceBox) os[0]; 732 Collection allObjects = choiceBox.getItems(); 733 Object actualToChose = null; 734 735 if (whatToChose instanceof Font) { 736 737 for (Object font : allObjects) { 738 //Supposed - font are different in their color. 739 if ((font instanceof Font) && (((Font) font).getSize() == ((Font) whatToChose).getSize())) { 740 actualToChose = font; 741 } 742 } 743 } else { 744 for (Object obj : allObjects) { 745 if ((obj != null) && obj.getClass().equals(whatToChose)) { 746 actualToChose = obj; 747 } 748 if ((obj != null) && obj.equals(whatToChose)) { 749 actualToChose = obj; 750 } 751 } 752 if (actualToChose == null) { 753 System.out.println("Select NULL (Possibly, nothing found to select)."); 754 } 755 } 756 757 ChoiceBox choice = (ChoiceBox) os[0]; 758 if (actualToChose == null) { 759 choice.setValue(null); 760 } else { 761 choice.getSelectionModel().select(actualToChose); 762 } 763 } 764 }.dispatch(Root.ROOT.getEnvironment(), choiceBox.getControl()); 765 break; 766 } 767 } 768 769 /** 770 * Send ScrollEvent in the center of the control 771 * 772 * @param wrap Wrap, which will receive event 773 * @param scrollX Number of pixels to scroll by x coordinate 774 * @param scrollY Number of pixels to scroll by y coordinate 775 */ 776 protected static void sendScrollEvent(final Wrap<? extends Scene> scene, Wrap<? extends Node> wrap, double scrollX, double scrollY) { 777 double x = wrap.getScreenBounds().width / 4; 778 double y = wrap.getScreenBounds().height / 4; 779 sendScrollEvent(scene, wrap, scrollX, scrollY, HorizontalTextScrollUnits.NONE, scrollX, VerticalTextScrollUnits.NONE, scrollY, x, y, wrap.getScreenBounds().x + x, wrap.getScreenBounds().y + y); 780 } 781 782 protected static void sendScrollEvent(final Wrap<? extends Scene> scene, final Wrap<? extends Node> wrap, 783 double _scrollX, double _scrollY, 784 HorizontalTextScrollUnits _scrollTextXUnits, double _scrollTextX, 785 VerticalTextScrollUnits _scrollTextYUnits, double _scrollTextY, 786 double _x, double _y, 787 double _screenX, double _screenY) { 788 //For 2.1.0 : 789 //final ScrollEvent scrollEvent = ScrollEvent.impl_scrollEvent(_scrollX, _scrollY, _scrollTextXUnits, _scrollTextX, _scrollTextYUnits, _scrollTextY, _x, _y, _screenX, _screenY, false, false, false, false); 790 //For 2.2.0 : 791 //Interpretation: EventType<ScrollEvent> eventType, double _scrollX, double _scrollY, double _totalScrollX, double _totalScrollY, HorizontalTextScrollUnits _scrollTextXUnits, double _scrollTextX, VerticalTextScrollUnits _scrollTextYUnits, double _scrollTextY, int _touchPoints, double _x, double _y, double _screenX, double _screenY, boolean _shiftDown, boolean _controlDown, boolean _altDown, boolean _metaDown, boolean _direct, boolean _inertia) 792 //For 8.0 before b64 and RT-9383 793 //final ScrollEvent scrollEvent = new ScrollEvent.impl_scrollEvent(ScrollEvent.SCROLL, _scrollX, _scrollY, _scrollX, _scrollY, _scrollTextXUnits, _scrollTextX, _scrollTextYUnits, _scrollTextY, 0, _x, _y, _screenX, _screenY, false, false, false, false, false, false); 794 795 //new ScrollEvent(EventType<ScrollEvent> eventType, 796 //double x, double y, double screenX, double screenY, 797 //boolean shiftDown, boolean controlDown, boolean altDown, boolean metaDown, 798 //boolean direct, boolean inertia, double deltaX, double deltaY, double gestureDeltaX, double gestureDeltaY, 799 //ScrollEvent.HorizontalTextScrollUnits textDeltaXUnits, double textDeltaX, 800 //ScrollEvent.VerticalTextScrollUnits textDeltaYUnits, double textDeltaY, int touchCount) 801 final ScrollEvent scrollEvent = new ScrollEvent(ScrollEvent.SCROLL, 802 _x, _y, _screenX, _screenY, 803 false, false, false, false, 804 false, false, _scrollX, _scrollY, 0, 0, 805 _scrollTextXUnits, _scrollTextX, 806 _scrollTextYUnits, _scrollTextY, 0, null /* PickResult?*/); 807 808 wrap.getEnvironment().getExecutor().execute(wrap.getEnvironment(), true, new Action() { 809 @Override 810 public void run(Object... os) throws Exception { 811 Wrap<? extends Node> wrap = ((Wrap<? extends Node>) os[2]); 812 Point2D pointOnScene = new GetAction<Point2D>() { 813 @Override 814 public void run(Object... os) throws Exception { 815 setResult(((Node) os[0]).localToScene((Double) os[1], (Double) os[2])); 816 } 817 }.dispatch(Root.ROOT.getEnvironment(), wrap.getControl(), Double.valueOf(wrap.getScreenBounds().width / 4), Double.valueOf(wrap.getScreenBounds().height / 4)); 818 final PickResultChooser result = new PickResultChooser(); 819 820 //public PickRay(Vec3d origin, Vec3d direction, double nearClip, double farClip) { 821 (((Wrap<? extends Scene>) os[0]).getControl()).getRoot().impl_pickNode(new PickRay(new Vec3d(pointOnScene.getX(), pointOnScene.getY(), -10), new Vec3d(0, 0, 1), 1.0, 100), result); 822 Node node = result.getIntersectedNode(); 823 node.fireEvent(scrollEvent); 824 } 825 }, scene, scrollEvent, wrap); 826 } 827 828 protected static void switchOnBinding(SettingType type, Enum propType) { 829 if (!getToggleButtonState(getPrefix(type) + propType.toString().toUpperCase() + BIND_BUTTON_SUFFIX)) { 830 changePropertyControlBindingToggleButtonState(type, propType); 831 } 832 } 833 834 protected static void switchOffBinding(SettingType type, Enum propType) { 835 if (getToggleButtonState(getPrefix(type) + propType.toString().toUpperCase() + BIND_BUTTON_SUFFIX)) { 836 changePropertyControlBindingToggleButtonState(type, propType); 837 } 838 } 839 840 private static boolean getToggleButtonState(String controlID) { 841 final ToggleButton tb = findToggleButton(controlID).getControl(); 842 return new GetAction<Boolean>() { 843 @Override 844 public void run(Object... os) throws Exception { 845 setResult(tb.selectedProperty().getValue()); 846 } 847 }.dispatch(Root.ROOT.getEnvironment()); 848 } 849 850 private static Object getChoiceBoxState(String controlID) { 851 final ChoiceBox cb = findChoiceBox(controlID).getControl(); 852 return new GetAction<Object>() { 853 @Override 854 public void run(Object... os) throws Exception { 855 setResult(cb.valueProperty().getValue()); 856 } 857 }.dispatch(Root.ROOT.getEnvironment()); 858 } 859 860 private static String getPrefix(SettingType type) { 861 if (type == SettingType.BIDIRECTIONAL) { 862 return BIDIR_PREFIX; 863 } else { 864 return UNIDIR_PREFIX; 865 } 866 } 867 868 protected static void setText(final Wrap<? extends TextField> tf, final int value) { 869 setText(tf, String.valueOf(value)); 870 } 871 872 protected static void setText(final Wrap<? extends TextField> tf, final String value) { 873 new GetAction() { 874 @Override 875 public void run(Object... os) throws Exception { 876 tf.getControl().setText(value); 877 } 878 }.dispatch(Root.ROOT.getEnvironment()); 879 } 880 881 protected static void setCheckBoxState(String controlId, final boolean checked) { 882 final Wrap<? extends CheckBox> wrap = (Wrap<? extends CheckBox>) findControl(controlId); 883 new GetAction() { 884 @Override 885 public void run(Object... os) throws Exception { 886 wrap.getControl().setSelected(checked); 887 } 888 }.dispatch(Root.ROOT.getEnvironment()); 889 } 890 891 /* 892 * FINDERS. Needed for ControlTabs. The problem is with TabPane. Its content 893 * (tabs' content) is not removed from SceneGraph, but just made invisible. 894 * So there are many controls with the same id, because they correspond to 895 * the same properties (by name) of different controls of the same class. 896 * So, sometimes, we need to find them in scrollPane, which is inside some 897 * Tab and its ID corresponds to name of tab. 898 */ 899 protected static Wrap<? extends Button> findButton(String id) { 900 return (Wrap<? extends Button>) findControl(id); 901 } 902 903 protected static Wrap<? extends TextField> findTextField(String id) { 904 return (Wrap<? extends TextField>) findControl(id); 905 } 906 907 protected static Wrap<? extends Slider> findSlider(String id) { 908 return (Wrap<? extends Slider>) findControl(id); 909 } 910 911 protected static Wrap<? extends ToggleButton> findToggleButton(String id) { 912 return (Wrap<? extends ToggleButton>) findControl(id); 913 } 914 915 protected static Wrap<? extends ChoiceBox> findChoiceBox(String id) { 916 return (Wrap<? extends ChoiceBox>) findControl(id); 917 } 918 919 protected static Wrap<? extends CheckBox> findCheckBox(String id) { 920 return (Wrap<? extends CheckBox>) findControl(id); 921 } 922 923 protected static Wrap<? extends Control> findControl(String id) { 924 if (useCaching) { 925 Wrap cached = Cache.search(id); 926 if (cached != null) { 927 return cached; 928 } 929 } 930 if ((propertiesTableScrollPane != null) && (propertiesTableScrollPane.lookup(Control.class, new ByID(id)).size() > 0)) { 931 return propertiesTableScrollPane.lookup(Control.class, new ByID<Control>(id)).wrap(); 932 } else { 933 if (parent.lookup(Control.class, new ByID(id)).size() == 1) { 934 Wrap found = parent.lookup(Control.class, new ByID<Control>(id)).wrap(); 935 if (useCaching) { 936 if (Cache.search(id) != null) { 937 throw new IllegalStateException("We tried to lookup cached wrap. We shouldn't be here."); 938 } else { 939 Cache.add(id, found); 940 } 941 } 942 return found; 943 } else { 944 if (parent.lookup(Control.class, new ByID(id)).size() > 1) { 945 /** 946 * If you are here, possibly, you didn't call 947 * switchToPropertiesTab() before specifying a property 948 * value, which appears on several tabs. 949 */ 950 throw new RuntimeException("Not unique ID!!! (" + id + ")."); 951 } else { 952 throw new RuntimeException("Not found!!! (" + id + ")."); 953 } 954 } 955 } 956 } 957 958 protected double adjustValue(double min, double max, double value) { 959 if (min > max) { 960 throw new IllegalArgumentException("Min must be less then max: min=" + min + "; max=" + max); 961 } 962 963 if (value < min) { 964 return min; 965 } 966 967 if (value > max) { 968 return max; 969 } 970 971 return value; 972 } 973 974 protected void clearCache() { 975 Cache.clear(); 976 } 977 978 public static String convertMultiIndicesToString(int... indices) { 979 StringBuilder builder = new StringBuilder(); 980 for (int i : indices) { 981 builder.append(i); 982 builder.append(MultipleIndexFormComponent.INDICES_DELIMITER); 983 } 984 builder.delete(builder.length() - MultipleIndexFormComponent.INDICES_DELIMITER.length(), builder.length()); 985 return builder.toString(); 986 } 987 988 protected void provideSpaceForControl(int width, int height, boolean nonTestedControlsVisibility) { 989 Wrap<? extends Scene> scene = Root.ROOT.lookup().wrap(); 990 ((CommonPropertiesScene) scene.getControl()).setNonTestedContentVisibility(nonTestedControlsVisibility); 991 ((CommonPropertiesScene) scene.getControl()).setTestedControlContainerSize(width, height); 992 } 993 994 protected Wrap<? extends Node> getParentWrap(Wrap<? extends Node> node) { 995 final Node control = node.getControl(); 996 return new NodeWrap(node.getEnvironment(), new GetAction<Node>(){ 997 998 @Override 999 public void run(Object... os) throws Exception { 1000 setResult(control.getParent()); 1001 } 1002 }.dispatch(Root.ROOT.getEnvironment())); 1003 } 1004 1005 /** 1006 * Checks, that rec1 rel rec2. 1007 */ 1008 public static void checkRectanglesRelation(Rectangle rec1, RectanglesRelations rel, Rectangle rec2) { 1009 switch (rel) { 1010 case ABOVE: 1011 assertTrue(rec1.y + rec1.height <= rec2.y); 1012 break; 1013 case BELOW: 1014 assertTrue(rec1.y >= rec2.y + rec2.height); 1015 break; 1016 case CONTAINS: 1017 assertTrue(rec1.contains(rec2)); 1018 break; 1019 case ISCONTAINED: 1020 assertTrue(rec2.contains(rec1)); 1021 break; 1022 case RIGHTER: 1023 assertTrue(rec1.x >= rec2.x + rec2.width); 1024 break; 1025 case LEFTER: 1026 assertTrue(rec1.x + rec1.width <= rec2.x); 1027 break; 1028 case CENTERED_IN_HORIZONTAL: 1029 //Centered, relative to horizontal dimension. 1030 assertEquals(rec1.y + rec1.height / 2.0, rec2.y + rec2.height / 2.0, 1.0); 1031 break; 1032 case CENTERED_IN_VERTICAL: 1033 //Centered, relative to vertical dimension. 1034 assertEquals(rec1.x + rec1.width / 2.0, rec2.x + rec2.width / 2.0, 1.0); 1035 break; 1036 default: 1037 throw new IllegalStateException("No case provided!"); 1038 } 1039 } 1040 1041 protected void removeStylesheet() { 1042 new GetAction() { 1043 @Override 1044 public void run(Object... os) throws Exception { 1045 Scene scene = parent.lookup().wrap().getControl().getScene(); 1046 for (String str : scene.getStylesheets()) { 1047 if (str.contains(CUSTOM_STYLE_CONST)) { 1048 rememberedStylesheet = str; 1049 scene.getStylesheets().remove(str); 1050 return; 1051 } 1052 } 1053 } 1054 }.dispatch(Root.ROOT.getEnvironment()); 1055 } 1056 1057 protected void restoreStylesheet() { 1058 assertNotNull(rememberedStylesheet); 1059 new GetAction() { 1060 @Override 1061 public void run(Object... os) throws Exception { 1062 Scene scene = parent.lookup().wrap().getControl().getScene(); 1063 scene.getStylesheets().add(rememberedStylesheet); 1064 } 1065 }.dispatch(Root.ROOT.getEnvironment()); 1066 rememberedStylesheet = null; 1067 } 1068 1069 private static class Cache { 1070 1071 private static Map<String, Wrap> cache = new HashMap<String, Wrap>(); 1072 private static Parent<Node> parentUsedForCaching = null; 1073 1074 private static void add(String id, Wrap cachedValue) { 1075 if (parent.equals(parentUsedForCaching)) { 1076 cache.put(id, cachedValue); 1077 } else { 1078 cache.clear(); 1079 parentUsedForCaching = parent; 1080 cache.put(id, cachedValue); 1081 } 1082 } 1083 1084 private static Wrap search(String id) { 1085 if (parent.equals(parentUsedForCaching)) { 1086 return cache.get(id); 1087 } else { 1088 cache.clear(); 1089 parentUsedForCaching = parent; 1090 return null; 1091 } 1092 } 1093 1094 private static void clear() { 1095 cache.clear(); 1096 } 1097 } 1098 1099 /** 1100 * Use case: 1101 * 1102 * @Test public void testTest() throws InterruptedException { 1103 * initChangingController(parent); 1104 * defaultController.include().allTables().allProperties().allCounters().apply(); 1105 * defaultController.fixCurrentState(); 1106 * defaultController.provideInfoForCodeCompletion(TestBase.Properties.values(), 1107 * null); 1108 * 1109 * assertEquals((new Slider()).maxProperty().getValue(), 100, 1110 * ASSERT_CMP_PRECISION);//initial value 1111 * 1112 * setPropertyBySlider(AbstractPropertyController.SettingType.BIDIRECTIONAL, 1113 * TestBase.Properties.max, -10); 1114 * checkTextFieldValue(TestBase.Properties.value, -10); 1115 * checkTextFieldValue(TestBase.Properties.min, -10); 1116 * checkTextFieldValue(TestBase.Properties.max, -10); 1117 * 1118 * setPropertyBySlider(AbstractPropertyController.SettingType.BIDIRECTIONAL, 1119 * TestBase.Properties.max, 150); setSliderPosition(TESTED_SLIDER_ID, 130, 1120 * SettingOption.MANUAL); checkTextFieldValue(TestBase.Properties.value, 1121 * 130); 1122 * 1123 * testedControl.keyboard().pushKey(Keyboard.KeyboardButtons.END); 1124 * checkTextFieldValue(TestBase.Properties.value, 150); 1125 * 1126 * setPropertyBySlider(AbstractPropertyController.SettingType.UNIDIRECTIONAL, 1127 * TestBase.Properties.max, 30); 1128 * checkTextFieldValue(TestBase.Properties.min, -10); 1129 * checkTextFieldValue(TestBase.Properties.max, 30); 1130 * checkTextFieldValue(TestBase.Properties.value, 30); 1131 * 1132 * defaultController.check(); } Can be added into 1133 * javafx.scene.control.test.slider.SliderTest class. 1134 */ 1135 protected static class ChangingController { 1136 1137 //This variable can deactivate this class on failing tests, if occasionally it cannot be easily fixed. 1138 final private boolean FAIL_ON_ERROR_IN_NON_CHANGING_CHECKING = true; 1139 private Object[] propertiesEnum = null; 1140 private Object[] countersEnum = null; 1141 private Parent<Node> stageWithPropertiestables = null; 1142 private boolean codeCompletionInfoProvided = false; 1143 private boolean stateWasFixed = false; 1144 private boolean atLeastOneConfigDone = false; 1145 private String changingControllerVariableName; 1146 private List<Entry<AbstractPropertiesTable, String>> trackedProperties = new ArrayList<Entry<AbstractPropertiesTable, String>>(); 1147 private List<Entry<AbstractPropertiesTable, String>> trackedCounters = new ArrayList<Entry<AbstractPropertiesTable, String>>(); 1148 1149 private ChangingController(Parent<Node> parent) { 1150 if (parent == null) { 1151 throw new IllegalArgumentException("Stage for looking up the properties table cannot be null."); 1152 } 1153 this.stageWithPropertiestables = parent; 1154 } 1155 1156 public void provideInfoForCodeCompletion(Object[] propertiesEnum, Object[] countersEnum) { 1157 this.changingControllerVariableName = "defaultController"; 1158 // if (changingControllerVariableName == null) { 1159 // throw new IllegalArgumentException("Variable name cannot be null."); 1160 // } 1161 1162 if ((propertiesEnum == null) && (countersEnum == null)) { 1163 throw new IllegalArgumentException("Both enums cannot be null."); 1164 } 1165 codeCompletionInfoProvided = true; 1166 this.propertiesEnum = propertiesEnum; 1167 this.countersEnum = countersEnum; 1168 // this.changingControllerVariableName = changingControllerVariableName; 1169 } 1170 1171 public void fixCurrentState() { 1172 Exception ex = new GetAction<Exception>() { 1173 @Override 1174 public void run(Object... os) throws Exception { 1175 try { 1176 for (Entry<AbstractPropertiesTable, String> entry : trackedProperties) { 1177 for (AbstractPropertyValueListener listener : entry.getKey().getListeners()) { 1178 listener.rememberCurrentState(); 1179 } 1180 } 1181 1182 for (Entry<AbstractPropertiesTable, String> entry : trackedCounters) { 1183 for (AbstractEventsCounter counter : entry.getKey().getCounters()) { 1184 counter.rememberCurrentState(); 1185 } 1186 } 1187 } catch (Exception ex) { 1188 setResult(ex); 1189 } 1190 } 1191 }.dispatch(Root.ROOT.getEnvironment()); 1192 1193 if (ex != null) { 1194 System.err.println("Exception during state fixing happened : " + ex.getMessage()); 1195 ex.printStackTrace(System.err); 1196 } 1197 1198 stateWasFixed = true; 1199 } 1200 1201 public void check() { 1202 if (!atLeastOneConfigDone) { 1203 throw new IllegalStateException("No configs were done."); 1204 } 1205 if (!stateWasFixed) { 1206 throw new IllegalStateException("You need to call fixState() method, to fix the counters or properties."); 1207 } 1208 1209 final List<FailedItem> failedItems = new ArrayList<FailedItem>(); 1210 1211 Throwable ex = new GetAction<Throwable>() { 1212 @Override 1213 public void run(Object... os) throws Exception { 1214 try { 1215 1216 1217 for (Entry<AbstractPropertiesTable, String> entry : trackedProperties) { 1218 try { 1219 for (AbstractPropertyValueListener listener : entry.getKey().getListeners()) { 1220 if (listener.getPropertyName().toUpperCase().equals(entry.getValue().toUpperCase())) { 1221 listener.checkCurrentStateEquality(); 1222 } 1223 } 1224 } catch (StateChangedException exception) { 1225 failedItems.add(new FailedItem(FailedItem.FailedItemType.PROPERTY, entry.getKey().getDomainName(), entry.getValue(), exception)); 1226 } 1227 } 1228 1229 for (Entry<AbstractPropertiesTable, String> entry : trackedCounters) { 1230 try { 1231 for (AbstractEventsCounter counter : entry.getKey().getCounters()) { 1232 if (counter.getName().toUpperCase().equals(entry.getValue().toUpperCase())) { 1233 counter.checkCurrentStateEquality(); 1234 } 1235 } 1236 } catch (StateChangedException exception) { 1237 failedItems.add(new FailedItem(FailedItem.FailedItemType.COUNTER, entry.getKey().getDomainName(), entry.getValue(), exception)); 1238 } 1239 } 1240 } catch (Throwable ex) { 1241 setResult(ex); 1242 } 1243 } 1244 }.dispatch(Root.ROOT.getEnvironment()); 1245 1246 if (ex != null) { 1247 System.err.println("During checking an error occured : " + ex.getMessage()); 1248 ex.printStackTrace(System.err); 1249 } 1250 1251 if (codeCompletionInfoProvided) { 1252 generateCompletingCode(failedItems); 1253 } 1254 1255 fail(failedItems); 1256 } 1257 1258 public Config include() { 1259 if (stateWasFixed) { 1260 throw new IllegalStateException("Inclusion cannot be done, because fixing has been done."); 1261 } 1262 return new Config(this, true); 1263 } 1264 1265 public Config exclude() { 1266 return new Config(this, false); 1267 } 1268 1269 protected void removeProperty(String domainName, Enum propertyName) { 1270 new Config(this, false).table(domainName).property(propertyName).apply(); 1271 } 1272 1273 protected void removeCounter(String domainName, String counterName) { 1274 new Config(this, false).table(domainName).counter(counterName).apply(); 1275 } 1276 1277 final public void setPropertiesEnum(Object[] propertiesEnum) { 1278 this.propertiesEnum = propertiesEnum; 1279 } 1280 1281 final public void setCountersEnum(Object[] countersEnum) { 1282 this.countersEnum = countersEnum; 1283 } 1284 1285 private void generateCompletingCode(List<FailedItem> failedItems) { 1286 if (!failedItems.isEmpty()) { 1287 System.out.println("You can add this code to provide code completion : "); 1288 } 1289 1290 try { 1291 for (FailedItem failedItem : failedItems) { 1292 if (failedItem.getFailedItemType().equals(FailedItem.FailedItemType.COUNTER)) { 1293 if (countersEnum != null) { 1294 int index = findItemIndex(countersEnum, failedItem.getName()); 1295 if (index != -1) { 1296 System.out.println(changingControllerVariableName + ".exclude().table(" + failedItem.getDomainName() + ").counter(Counters." + countersEnum[index].toString() + ").apply();"); 1297 } 1298 } 1299 } 1300 1301 if (failedItem.getFailedItemType().equals(FailedItem.FailedItemType.PROPERTY)) { 1302 if (propertiesEnum != null) { 1303 int index = findItemIndex(propertiesEnum, failedItem.getName()); 1304 if (index != -1) { 1305 System.out.println(changingControllerVariableName + ".exclude().table(" + failedItem.getDomainName() + ").property(Properties." + propertiesEnum[index].toString() + ").apply();"); 1306 } 1307 } 1308 } 1309 } 1310 } catch (Exception ex) { 1311 System.err.println("During code generating an error has occured : " + ex.getMessage()); 1312 ex.printStackTrace(System.err); 1313 } 1314 } 1315 1316 private void fail(List<FailedItem> failedItems) { 1317 for (FailedItem failedItem : failedItems) { 1318 System.err.println("Failed on checking : " + failedItem); 1319 } 1320 1321 if (FAIL_ON_ERROR_IN_NON_CHANGING_CHECKING) { 1322 if (!failedItems.isEmpty()) { 1323 throw new IllegalStateException("Failures detected."); 1324 } 1325 } 1326 } 1327 1328 private int findItemIndex(Object[] enumm, String name) { 1329 for (int i = 0; i < enumm.length; i++) { 1330 if (enumm[i].toString().toUpperCase().equals(name.toUpperCase())) { 1331 return i; 1332 } 1333 } 1334 1335 return -1; 1336 } 1337 1338 protected void applyConfig(final Config config) { 1339 Throwable ex = new GetAction<Throwable>() { 1340 @Override 1341 public void run(Object... os) throws Exception { 1342 try { 1343 Map<String, AbstractPropertiesTable> currentlyExistingTables = searchForTables(); 1344 1345 List<String> listOfTables = new ArrayList<String>(); 1346 if (config.allTables) { 1347 for (AbstractPropertiesTable table : currentlyExistingTables.values()) { 1348 listOfTables.add(table.getDomainName()); 1349 } 1350 } else { 1351 listOfTables = config.tableNames; 1352 } 1353 1354 if (config.toInclude) { 1355 for (String domainName : listOfTables) { 1356 if (config.allCounters) { 1357 for (AbstractEventsCounter counter : currentlyExistingTables.get(domainName).getCounters()) { 1358 trackedCounters.add(new AbstractMap.SimpleEntry<AbstractPropertiesTable, String>(currentlyExistingTables.get(domainName), counter.getName())); 1359 } 1360 } else { 1361 for (String counterName : config.counterNames) { 1362 trackedCounters.add(new AbstractMap.SimpleEntry<AbstractPropertiesTable, String>(currentlyExistingTables.get(domainName), counterName)); 1363 } 1364 } 1365 1366 if (config.allProperties) { 1367 for (AbstractPropertyValueListener listener : currentlyExistingTables.get(domainName).getListeners()) { 1368 trackedProperties.add(new AbstractMap.SimpleEntry<AbstractPropertiesTable, String>(currentlyExistingTables.get(domainName), listener.getPropertyName())); 1369 } 1370 } else { 1371 for (Enum property : config.propertiesNames) { 1372 trackedProperties.add(new AbstractMap.SimpleEntry<AbstractPropertiesTable, String>(currentlyExistingTables.get(domainName), property.name())); 1373 } 1374 } 1375 } 1376 } else { //ToExclude 1377 for (String domainName : listOfTables) { 1378 if (config.allCounters) { 1379 List<Entry<AbstractPropertiesTable, String>> removeList = new ArrayList<Entry<AbstractPropertiesTable, String>>(); 1380 for (Entry<AbstractPropertiesTable, String> entry : trackedCounters) { 1381 if (entry.getKey().getDomainName().equals(domainName)) { 1382 removeList.add(entry); 1383 } 1384 } 1385 for (Entry<AbstractPropertiesTable, String> entry : removeList) { 1386 trackedCounters.remove(entry); 1387 } 1388 } else { 1389 List<Entry<AbstractPropertiesTable, String>> removeList = new ArrayList<Entry<AbstractPropertiesTable, String>>(); 1390 for (Entry<AbstractPropertiesTable, String> entry : trackedCounters) { 1391 for (String counterName : config.counterNames) { 1392 if (entry.getKey().getDomainName().equals(domainName) && entry.getValue().equalsIgnoreCase(counterName)) { 1393 removeList.add(entry); 1394 } 1395 } 1396 } 1397 for (Entry<AbstractPropertiesTable, String> entry : removeList) { 1398 trackedCounters.remove(entry); 1399 } 1400 } 1401 1402 if (config.allProperties) { 1403 List<Entry<AbstractPropertiesTable, String>> removeList = new ArrayList<Entry<AbstractPropertiesTable, String>>(); 1404 for (Entry<AbstractPropertiesTable, String> entry : trackedProperties) { 1405 if (entry.getKey().getDomainName().equals(domainName)) { 1406 removeList.add(entry); 1407 } 1408 } 1409 for (Entry<AbstractPropertiesTable, String> entry : removeList) { 1410 trackedProperties.remove(entry); 1411 } 1412 } else { 1413 List<Entry<AbstractPropertiesTable, String>> removeList = new ArrayList<Entry<AbstractPropertiesTable, String>>(); 1414 for (Entry<AbstractPropertiesTable, String> entry : trackedProperties) { 1415 for (Enum propertyName : config.propertiesNames) { 1416 if (entry.getKey().getDomainName().equals(domainName) && entry.getValue().equalsIgnoreCase(propertyName.name())) { 1417 removeList.add(entry); 1418 } 1419 } 1420 } 1421 for (Entry<AbstractPropertiesTable, String> entry : removeList) { 1422 trackedProperties.remove(entry); 1423 } 1424 } 1425 } 1426 } 1427 } catch (Throwable th) { 1428 setResult(th); 1429 } 1430 } 1431 }.dispatch(Root.ROOT.getEnvironment()); 1432 1433 if (ex != null) { 1434 ex.printStackTrace(System.err); 1435 } 1436 } 1437 1438 private Map<String, AbstractPropertiesTable> searchForTables() { 1439 List<AbstractPropertiesTable> foundTables = new ArrayList<AbstractPropertiesTable>(); 1440 1441 int found = stageWithPropertiestables.lookup(PropertiesTable.class).size(); 1442 for (int i = 0; i < found; i++) { 1443 foundTables.add(stageWithPropertiestables.lookup(PropertiesTable.class).wrap(i).getControl()); 1444 } 1445 1446 Map<String, AbstractPropertiesTable> tableToIdMathing = new HashMap<String, AbstractPropertiesTable>(); 1447 1448 for (final AbstractPropertiesTable table : foundTables) { 1449 String domainName = new GetAction<String>() { 1450 @Override 1451 public void run(Object... os) throws Exception { 1452 setResult(table.getDomainName()); 1453 } 1454 }.dispatch(Root.ROOT.getEnvironment()); 1455 tableToIdMathing.put(domainName, table); 1456 } 1457 1458 return tableToIdMathing; 1459 } 1460 1461 protected enum CHECKING_SET { 1462 1463 COUNTERS, PROPERTIES, STANDART_SET, ALL 1464 }; 1465 1466 private static class FailedItem { 1467 1468 final private FailedItemType failedItemType; 1469 final private String name; 1470 final private String domainName; 1471 final private Exception exception; 1472 1473 public FailedItem(FailedItemType failedItemType, String domainName, String name, Exception exception) { 1474 if (failedItemType == null) { 1475 throw new IllegalArgumentException("Failed item type cannot be null."); 1476 } 1477 if (name == null) { 1478 throw new IllegalArgumentException("Name cannot be null."); 1479 } 1480 if (domainName == null) { 1481 throw new IllegalArgumentException("Domain name cannot be null."); 1482 } 1483 if (exception == null) { 1484 throw new IllegalArgumentException("Create an exception."); 1485 } 1486 1487 this.failedItemType = failedItemType; 1488 this.name = name; 1489 this.domainName = domainName; 1490 this.exception = exception; 1491 } 1492 1493 public FailedItemType getFailedItemType() { 1494 return failedItemType; 1495 } 1496 1497 public String getName() { 1498 return name; 1499 } 1500 1501 public String getDomainName() { 1502 return domainName; 1503 } 1504 1505 public Exception getException() { 1506 return exception; 1507 } 1508 1509 public enum FailedItemType { 1510 1511 PROPERTY, COUNTER 1512 }; 1513 1514 @Override 1515 public String toString() { 1516 return "Failed <" + failedItemType.name() + "> with name <" + name + "> on table <" + domainName + "> with error : \n" + exception.getMessage(); 1517 } 1518 } 1519 1520 /** 1521 * The only applicable way of doing initialisation is : Create an 1522 * instance -> set tables -> set properties and counters in any order -> 1523 * apply. 1524 */ 1525 public static class Config { 1526 1527 private ConfigStage currentStage = ConfigStage.NOT_STARTED; 1528 private ChangingController controller = null; 1529 private List<String> tableNames = new ArrayList<String>(); 1530 private List<Enum> propertiesNames = new ArrayList<Enum>(); 1531 private List<String> counterNames = new ArrayList<String>(); 1532 private boolean allTables = false; 1533 private boolean allCounters = false; 1534 private boolean allProperties = false; 1535 private Boolean toInclude = null; 1536 1537 /** 1538 * @param controller that controller, which will receive this 1539 * config. 1540 * @param toInclude - true - to include, false - to exclude. 1541 */ 1542 private Config(ChangingController controller, boolean toInclude) { 1543 if (controller == null) { 1544 throw new IllegalArgumentException("Controller instance cannot be null."); 1545 } 1546 this.controller = controller; 1547 this.toInclude = toInclude; 1548 } 1549 1550 public Config table(String name) { 1551 if (name == null) { 1552 throw new IllegalStateException("Name cannot be null."); 1553 } 1554 checkNonInitialisedOrTablesSetStage(); 1555 tableNames.add(name); 1556 currentStage = ConfigStage.DOMAIN_SET; 1557 return this; 1558 } 1559 1560 public Config tables(String... names) { 1561 if (names == null) { 1562 throw new IllegalStateException("Names cannot be null."); 1563 } 1564 checkNonInitialisedOrTablesSetStage(); 1565 for (String name : names) { 1566 if (name == null) { 1567 throw new IllegalStateException("No one name can be null."); 1568 } 1569 tableNames.add(name); 1570 } 1571 currentStage = ConfigStage.DOMAIN_SET; 1572 return this; 1573 } 1574 1575 /** 1576 * You can write: tables("treeItem-<i>", 1, 4) to decribe such list 1577 * of items: "treeItem-1", "treeItem-2", "treeItem-3", "treeItem-4" 1578 * 1579 * @param pattern should contain <i> 1580 * @param start initial index. 1581 * @param end final index 1582 * @return self 1583 */ 1584 public Config tables(String pattern, int start, int end) { 1585 if (pattern == null) { 1586 throw new IllegalStateException("Names cannot be null."); 1587 } 1588 1589 if (pattern.indexOf("<i>") < 0) { 1590 throw new IllegalStateException("Patter should contain \"<i>\" substring."); 1591 } 1592 1593 checkNonInitialisedOrTablesSetStage(); 1594 for (int i = start; i <= end; i++) { 1595 this.table(pattern.replace("<i>", String.valueOf(i))); 1596 } 1597 currentStage = ConfigStage.DOMAIN_SET; 1598 return this; 1599 } 1600 1601 public Config allTables() { 1602 checkNonInitialisedOrTablesSetStage(); 1603 allTables = true; 1604 currentStage = ConfigStage.DOMAIN_SET; 1605 return this; 1606 } 1607 1608 public Config counter(String name) { 1609 if (name == null) { 1610 throw new IllegalStateException("Name cannot be null."); 1611 } 1612 checkCanSetPropertyOrCounterDetermined(); 1613 counterNames.add(name); 1614 currentStage = ConfigStage.PROPERTIES_OR_COUNTERS_SET; 1615 return this; 1616 } 1617 1618 public Config property(Enum name) { 1619 if (name == null) { 1620 throw new IllegalStateException("Name cannot be null."); 1621 } 1622 checkCanSetPropertyOrCounterDetermined(); 1623 propertiesNames.add(name); 1624 currentStage = ConfigStage.PROPERTIES_OR_COUNTERS_SET; 1625 return this; 1626 } 1627 1628 public Config counters(String... names) { 1629 if (names == null) { 1630 throw new IllegalStateException("Names cannot be null."); 1631 } 1632 checkCanSetPropertyOrCounterDetermined(); 1633 for (String name : names) { 1634 if (name == null) { 1635 throw new IllegalStateException("No one name can be null."); 1636 } 1637 counterNames.add(name); 1638 } 1639 currentStage = ConfigStage.PROPERTIES_OR_COUNTERS_SET; 1640 return this; 1641 } 1642 1643 public Config properties(Enum... names) { 1644 if (names == null) { 1645 throw new IllegalStateException("Names cannot be null."); 1646 } 1647 checkCanSetPropertyOrCounterDetermined(); 1648 for (Enum name : names) { 1649 if (name == null) { 1650 throw new IllegalStateException("No one name can be null."); 1651 } 1652 propertiesNames.add(name); 1653 } 1654 currentStage = ConfigStage.PROPERTIES_OR_COUNTERS_SET; 1655 return this; 1656 } 1657 1658 public Config allCounters() { 1659 checkCanSetPropertyOrCounterDetermined(); 1660 allCounters = true; 1661 currentStage = ConfigStage.PROPERTIES_OR_COUNTERS_SET; 1662 return this; 1663 } 1664 1665 public Config allProperties() { 1666 checkCanSetPropertyOrCounterDetermined(); 1667 allProperties = true; 1668 currentStage = ConfigStage.PROPERTIES_OR_COUNTERS_SET; 1669 return this; 1670 } 1671 1672 public void apply() { 1673 if (currentStage != ConfigStage.PROPERTIES_OR_COUNTERS_SET) { 1674 throw new IllegalStateException("Cannot be applied, when properties or counters are not determined."); 1675 } 1676 controller.atLeastOneConfigDone = true; 1677 controller.applyConfig(this); 1678 currentStage = ConfigStage.APPLIED; 1679 } 1680 1681 private void checkNonInitialisedOrTablesSetStage() { 1682 if (currentStage != ConfigStage.NOT_STARTED && currentStage != ConfigStage.DOMAIN_SET) { 1683 throw new IllegalStateException("Should be not initialised, or only tables initialised."); 1684 } 1685 } 1686 1687 private void checkCanSetPropertyOrCounterDetermined() { 1688 if (!((currentStage == ConfigStage.DOMAIN_SET) || (currentStage == ConfigStage.PROPERTIES_OR_COUNTERS_SET))) { 1689 throw new IllegalStateException(); 1690 } 1691 } 1692 1693 private static enum ConfigStage { 1694 1695 NOT_STARTED, DOMAIN_SET, PROPERTIES_OR_COUNTERS_SET, APPLIED 1696 }; 1697 } 1698 } 1699 1700 static protected enum SettingOption { 1701 1702 MANUAL, PROGRAM 1703 }; 1704 1705 static public enum RectanglesRelations { 1706 1707 BELOW, LEFTER, RIGHTER, ABOVE, ISCONTAINED, CONTAINS, CENTERED_IN_HORIZONTAL, CENTERED_IN_VERTICAL 1708 } 1709 }