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