├── repo └── .project.local ├── .gitattributes ├── launch.sh ├── launch.cmd ├── screenshots ├── config.png ├── form.png ├── capture1.png ├── capture2.png ├── capture3.png ├── capture4.png ├── codegen.png ├── breadcumps.png ├── exception.png ├── swd_table.png ├── swet_javafx.png ├── config_browse.png ├── confirm_close.png ├── exported_flow.png ├── open_sesssion.png ├── firefox_vesion.png ├── tip_of_the_day.png ├── exit_confirmation.png ├── table_editor_view.png ├── config_browse_result.png ├── exception_app_cersion.png ├── ctrl_right_button_bw_32.png ├── ctrl_right_button_bw_36.png ├── ctrl_right_button_bw_48.png ├── capture_run_complexformex.png ├── init_with_custom_arguments.png └── error_invalid_template_format.png ├── src ├── test │ ├── resources │ │ ├── question.png │ │ ├── ElementSearch.html │ │ └── log4j_test.xml │ └── java │ │ └── com │ │ └── github │ │ └── sergueik │ │ └── swet │ │ ├── RenderTemplateTest.java │ │ ├── Log4j2Test.java │ │ ├── InstalledBrowsersTest.java │ │ ├── Log4jTest.java │ │ ├── SwetImmutableListCopyOfExcerptionTest.java │ │ ├── PropertiesTest.java │ │ ├── EscapeUtilTest.java │ │ ├── WriteScriptFileTest.java │ │ ├── BrowserDiscoveryTest.java │ │ ├── TestConfigurationParserTest.java │ │ ├── AWTTest.java │ │ ├── OSUtilsAndWinRegistryTest.java │ │ └── ExcelWriterTest.java └── main │ ├── resources │ ├── images │ │ ├── demo.png │ │ ├── find.png │ │ ├── open.png │ │ ├── page.png │ │ ├── quit.png │ │ ├── save.png │ │ ├── stop.gif │ │ ├── arrow.png │ │ ├── demo_36.png │ │ ├── down_sm.png │ │ ├── find_32.png │ │ ├── find_36.png │ │ ├── gear_36.png │ │ ├── help_32.png │ │ ├── launch.png │ │ ├── light1.png │ │ ├── open_32.png │ │ ├── open_36.png │ │ ├── quit_32.png │ │ ├── save_32.png │ │ ├── save_36.png │ │ ├── start.gif │ │ ├── browsers.png │ │ ├── code_128.png │ │ ├── facepalm.png │ │ ├── find2_36.png │ │ ├── find_2_32.png │ │ ├── flowchart.png │ │ ├── launch_32.png │ │ ├── launch_36.png │ │ ├── right_sm.png │ │ ├── wrench_36.png │ │ ├── browsers_32.png │ │ ├── codegen_32.png │ │ ├── codegen_36.png │ │ ├── excel_gen_32.png │ │ ├── flowchart_32.png │ │ ├── preferences.png │ │ ├── arrow_expanded.png │ │ ├── o3_calc_app_32.png │ │ ├── preferences_32.png │ │ ├── document_wrench_bw.png │ │ ├── document_wrench_color.ico │ │ ├── document_wrench_color.png │ │ └── document_wrench_color_36.png │ ├── templates │ │ ├── aftertest.twig │ │ ├── initObjects.twig │ │ ├── example1.twig │ │ ├── example_broken.twig │ │ ├── beforeTest.twig │ │ ├── importList.twig │ │ ├── core_selenium_csharp.twig │ │ ├── core_selenium_java.twig │ │ ├── core_selenium_linq_csharp.twig │ │ ├── basic_page_objects_java.twig │ │ ├── core_selenium_java8_streams.twig │ │ ├── core_selenium_python.twig │ │ ├── core_selenium_ruby.twig │ │ └── core_selenium_with_wait_java.twig │ ├── test.configuration │ ├── blankpage.html │ ├── config.properties │ ├── application.properties │ ├── internalConfiguration.yaml │ ├── help.yaml │ ├── log4j.xml │ ├── sample.yaml │ ├── sampleTest.json │ └── log4j2.xml │ └── java │ ├── org │ ├── mihalis │ │ └── opal │ │ │ └── multi │ │ │ ├── MultiChoiceLabelProvider.java │ │ │ ├── MultiChoiceDefaultLabelProvider.java │ │ │ ├── SimpleSelectionAdapter.java │ │ │ └── MultiChoiceSelectionListener.java │ └── passer │ │ └── ChoiceItem.java │ ├── custom │ └── swt │ │ └── widgets │ │ ├── SimpleFuture.java │ │ ├── Container.java │ │ ├── InfoPopup.java │ │ ├── ImageLabel.java │ │ ├── MultilineButton.java │ │ ├── MultiSelectCombo.java │ │ └── SWTUtil.java │ └── com │ └── github │ └── sergueik │ └── swet │ ├── ConfigDataSerializer.java │ ├── BrowserConfiguration.java │ ├── ChoiceDialogEx.java │ ├── BusyIndicatorEx.java │ ├── PropertiesParser.java │ ├── ConfigData.java │ ├── ListJavaFonts.java │ ├── JavaHotkeyManager.java │ ├── Configuration.java │ ├── TestConfigurationParser.java │ ├── BatchPipeRun.java │ ├── SystemTrayEx.java │ ├── JavaScanner.java │ ├── UtilExtensions.java │ ├── MouseEventDemo.java │ ├── ExceptionDialogEx.java │ ├── ButtonSizeEx.java │ ├── YamlHelper.java │ ├── RenderTemplate.java │ ├── User32WakeupTest.java │ └── TemplateCache.java ├── get.ps1 ├── .gitignore ├── LICENSE ├── launch.ps1 ├── run2.sh ├── run.sh ├── MouseEventDemo.java ├── run.cmd └── run2.cmd /repo/.project.local: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.cmd eol=crlf 2 | *.ps1 eol=crlf 3 | *.sh eol=lf 4 | -------------------------------------------------------------------------------- /launch.sh: -------------------------------------------------------------------------------- 1 | export SKIP_BUILD=true 2 | $(dirname $0)/run.sh $* 3 | -------------------------------------------------------------------------------- /launch.cmd: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | set SKIP_BUILD=true 3 | call run %* 4 | set SKIP_BUILD= -------------------------------------------------------------------------------- /screenshots/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/config.png -------------------------------------------------------------------------------- /screenshots/form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/form.png -------------------------------------------------------------------------------- /screenshots/capture1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/capture1.png -------------------------------------------------------------------------------- /screenshots/capture2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/capture2.png -------------------------------------------------------------------------------- /screenshots/capture3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/capture3.png -------------------------------------------------------------------------------- /screenshots/capture4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/capture4.png -------------------------------------------------------------------------------- /screenshots/codegen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/codegen.png -------------------------------------------------------------------------------- /screenshots/breadcumps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/breadcumps.png -------------------------------------------------------------------------------- /screenshots/exception.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/exception.png -------------------------------------------------------------------------------- /screenshots/swd_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/swd_table.png -------------------------------------------------------------------------------- /screenshots/swet_javafx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/swet_javafx.png -------------------------------------------------------------------------------- /screenshots/config_browse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/config_browse.png -------------------------------------------------------------------------------- /screenshots/confirm_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/confirm_close.png -------------------------------------------------------------------------------- /screenshots/exported_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/exported_flow.png -------------------------------------------------------------------------------- /screenshots/open_sesssion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/open_sesssion.png -------------------------------------------------------------------------------- /screenshots/firefox_vesion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/firefox_vesion.png -------------------------------------------------------------------------------- /screenshots/tip_of_the_day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/tip_of_the_day.png -------------------------------------------------------------------------------- /src/test/resources/question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/test/resources/question.png -------------------------------------------------------------------------------- /screenshots/exit_confirmation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/exit_confirmation.png -------------------------------------------------------------------------------- /screenshots/table_editor_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/table_editor_view.png -------------------------------------------------------------------------------- /src/main/resources/images/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/demo.png -------------------------------------------------------------------------------- /src/main/resources/images/find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/find.png -------------------------------------------------------------------------------- /src/main/resources/images/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/open.png -------------------------------------------------------------------------------- /src/main/resources/images/page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/page.png -------------------------------------------------------------------------------- /src/main/resources/images/quit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/quit.png -------------------------------------------------------------------------------- /src/main/resources/images/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/save.png -------------------------------------------------------------------------------- /src/main/resources/images/stop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/stop.gif -------------------------------------------------------------------------------- /screenshots/config_browse_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/config_browse_result.png -------------------------------------------------------------------------------- /screenshots/exception_app_cersion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/exception_app_cersion.png -------------------------------------------------------------------------------- /src/main/resources/images/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/arrow.png -------------------------------------------------------------------------------- /src/main/resources/images/demo_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/demo_36.png -------------------------------------------------------------------------------- /src/main/resources/images/down_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/down_sm.png -------------------------------------------------------------------------------- /src/main/resources/images/find_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/find_32.png -------------------------------------------------------------------------------- /src/main/resources/images/find_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/find_36.png -------------------------------------------------------------------------------- /src/main/resources/images/gear_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/gear_36.png -------------------------------------------------------------------------------- /src/main/resources/images/help_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/help_32.png -------------------------------------------------------------------------------- /src/main/resources/images/launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/launch.png -------------------------------------------------------------------------------- /src/main/resources/images/light1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/light1.png -------------------------------------------------------------------------------- /src/main/resources/images/open_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/open_32.png -------------------------------------------------------------------------------- /src/main/resources/images/open_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/open_36.png -------------------------------------------------------------------------------- /src/main/resources/images/quit_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/quit_32.png -------------------------------------------------------------------------------- /src/main/resources/images/save_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/save_32.png -------------------------------------------------------------------------------- /src/main/resources/images/save_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/save_36.png -------------------------------------------------------------------------------- /src/main/resources/images/start.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/start.gif -------------------------------------------------------------------------------- /src/main/resources/templates/aftertest.twig: -------------------------------------------------------------------------------- 1 | @AfterTest 2 | public void tearDown() { 3 | driver.quit(); 4 | } 5 | -------------------------------------------------------------------------------- /screenshots/ctrl_right_button_bw_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/ctrl_right_button_bw_32.png -------------------------------------------------------------------------------- /screenshots/ctrl_right_button_bw_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/ctrl_right_button_bw_36.png -------------------------------------------------------------------------------- /screenshots/ctrl_right_button_bw_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/ctrl_right_button_bw_48.png -------------------------------------------------------------------------------- /src/main/resources/images/browsers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/browsers.png -------------------------------------------------------------------------------- /src/main/resources/images/code_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/code_128.png -------------------------------------------------------------------------------- /src/main/resources/images/facepalm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/facepalm.png -------------------------------------------------------------------------------- /src/main/resources/images/find2_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/find2_36.png -------------------------------------------------------------------------------- /src/main/resources/images/find_2_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/find_2_32.png -------------------------------------------------------------------------------- /src/main/resources/images/flowchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/flowchart.png -------------------------------------------------------------------------------- /src/main/resources/images/launch_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/launch_32.png -------------------------------------------------------------------------------- /src/main/resources/images/launch_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/launch_36.png -------------------------------------------------------------------------------- /src/main/resources/images/right_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/right_sm.png -------------------------------------------------------------------------------- /src/main/resources/images/wrench_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/wrench_36.png -------------------------------------------------------------------------------- /screenshots/capture_run_complexformex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/capture_run_complexformex.png -------------------------------------------------------------------------------- /screenshots/init_with_custom_arguments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/init_with_custom_arguments.png -------------------------------------------------------------------------------- /src/main/resources/images/browsers_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/browsers_32.png -------------------------------------------------------------------------------- /src/main/resources/images/codegen_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/codegen_32.png -------------------------------------------------------------------------------- /src/main/resources/images/codegen_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/codegen_36.png -------------------------------------------------------------------------------- /src/main/resources/images/excel_gen_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/excel_gen_32.png -------------------------------------------------------------------------------- /src/main/resources/images/flowchart_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/flowchart_32.png -------------------------------------------------------------------------------- /src/main/resources/images/preferences.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/preferences.png -------------------------------------------------------------------------------- /src/main/resources/images/arrow_expanded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/arrow_expanded.png -------------------------------------------------------------------------------- /src/main/resources/images/o3_calc_app_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/o3_calc_app_32.png -------------------------------------------------------------------------------- /src/main/resources/images/preferences_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/preferences_32.png -------------------------------------------------------------------------------- /screenshots/error_invalid_template_format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/screenshots/error_invalid_template_format.png -------------------------------------------------------------------------------- /src/main/resources/templates/initObjects.twig: -------------------------------------------------------------------------------- 1 | private Log log; 2 | private WebDriver driver; 3 | private SeleniumKeywords seleniumKeywords; 4 | -------------------------------------------------------------------------------- /src/main/resources/images/document_wrench_bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/document_wrench_bw.png -------------------------------------------------------------------------------- /src/main/resources/images/document_wrench_color.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/document_wrench_color.ico -------------------------------------------------------------------------------- /src/main/resources/images/document_wrench_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/document_wrench_color.png -------------------------------------------------------------------------------- /src/main/resources/images/document_wrench_color_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sergueik/SWET/HEAD/src/main/resources/images/document_wrench_color_36.png -------------------------------------------------------------------------------- /src/main/resources/test.configuration: -------------------------------------------------------------------------------- 1 | # examples of configurations 2 | column1|column2|column3 3 | A1|A2|A3 4 | B1 B2 B3 5 | C1,C2,C3 6 | D1;D2;D3 7 | 8 | -------------------------------------------------------------------------------- /src/main/java/org/mihalis/opal/multi/MultiChoiceLabelProvider.java: -------------------------------------------------------------------------------- 1 | package org.mihalis.opal.multi; 2 | 3 | public interface MultiChoiceLabelProvider { 4 | String getText(Object element); 5 | } -------------------------------------------------------------------------------- /get.ps1: -------------------------------------------------------------------------------- 1 | $s1 = [xml]$raw_data 2 | $s1.'rawdata'.'div'.'div'.'ul'.'li'.'div'.'h3'.'a' | ForEach-Object { 3 | Write-Output ($_.GetAttribute('title')) 4 | Write-Output ($_.GetAttribute('href')) 5 | $_ | Get-Member | Out-Null 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/blankpage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Blank page 4 | 5 | 6 | 7 |

8 | Blank Page 9 |

10 |
Keymaster is being injected by WebDriver
11 | 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/bin/** 2 | **/.settings 3 | **/.classpath 4 | **/.project 5 | **/.gitignore 6 | **/work/** 7 | **/target/** 8 | **/*.log 9 | **/src/**/*.jar 10 | **/build/** 11 | **/test-output/** 12 | /pom.xml.releaseBackup 13 | /release.properties 14 | /settings.xml 15 | *.unc-backup~ 16 | *.uncrustify 17 | *~ 18 | -------------------------------------------------------------------------------- /src/main/resources/templates/example1.twig: -------------------------------------------------------------------------------- 1 | {% if (useCss) %} 2 | driver.findElement(By.cssSelector("{{ ElementCssSelector }}"); 3 | {% elseif (useXPath) %} 4 | driver.findElement(By.cssSelector("{{ ElementXPath }}"); 5 | {% elseif (useId)%} 6 | driver.findElement(By.Id("{{ ElementId }}"); 7 | {% else %} 8 | {% endif %} -------------------------------------------------------------------------------- /src/main/java/org/mihalis/opal/multi/MultiChoiceDefaultLabelProvider.java: -------------------------------------------------------------------------------- 1 | package org.mihalis.opal.multi; 2 | 3 | public class MultiChoiceDefaultLabelProvider 4 | implements MultiChoiceLabelProvider { 5 | 6 | @Override 7 | public String getText(final Object element) { 8 | return element == null ? "" : element.toString(); 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /src/main/resources/templates/example_broken.twig: -------------------------------------------------------------------------------- 1 | {% if (ElementSelectedBy == 'ElementCssSelector') -%} 2 | driver.findElement(By.cssSelector("{{ ElementCssSelector }}"); 3 | {% elseif (ElementSelectedBy == 'ElementXPath') -%} 4 | driver.findElement(By.Xpath("{{ ElementXPath }}"); 5 | {% else= 'ElementId') -%} 6 | driver.findElement(By.Id("{{ ElementId }}"); 7 | {% else -%} 8 | {% endif -%} 9 | -------------------------------------------------------------------------------- /src/main/resources/templates/beforeTest.twig: -------------------------------------------------------------------------------- 1 | @Parameters({"browser", "URL"}) 2 | @BeforeTest 3 | public void setUp(String browser, String URL) throws Exception { 4 | log = Utils.createLog(this.getClass().getSimpleName()); 5 | driver = WebDriverManager.createWebDriver(browser, log); 6 | seleniumKeywords = new SeleniumKeywords(driver, log); 7 | seleniumKeywords.open_Url(URL); 8 | } -------------------------------------------------------------------------------- /src/test/resources/ElementSearch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Element Search 4 | 5 | 6 | 7 |

8 | Element Search 9 |

10 |
11 | 12 | ask a question 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/resources/templates/importList.twig: -------------------------------------------------------------------------------- 1 | import libs.WebDriverUtils.SeleniumKeywords; 2 | import libs.WebDriverUtils.WebDriverManager; 3 | 4 | import org.openqa.selenium.WebDriver; 5 | 6 | import org.testng.annotations.AfterTest; 7 | import org.testng.annotations.BeforeTest; 8 | import org.testng.annotations.Parameters; 9 | import org.testng.annotations.Test; 10 | 11 | import utils.Logs.Log; 12 | import utils.Utility; 13 | -------------------------------------------------------------------------------- /src/main/resources/config.properties: -------------------------------------------------------------------------------- 1 | chromeDriverPath=D:\\Books\\SourceCode\\seleniumDriver\\chromedriver.exe 2 | firefoxDriverPath=D:\\Books\\SourceCode\\seleniumDriver\\geckodriver.exe 3 | ieDriverPath=D:\\Books\\SourceCode\\seleniumDriver\\IEDriverServer.exe 4 | selenium.getLink=Go to URL 5 | selenium.click=Click 6 | selenium.type_Text=Write Text 7 | selenium.selectDropDownListOptionByLabel=Select Option 8 | selenium.verifyElementTextEqual=checkValue 9 | selenium.verifyElementTextContains=CheckContainsValue -------------------------------------------------------------------------------- /src/main/java/custom/swt/widgets/SimpleFuture.java: -------------------------------------------------------------------------------- 1 | package custom.swt.widgets; 2 | 3 | public class SimpleFuture { 4 | 5 | I value; 6 | boolean aborted; 7 | 8 | public synchronized void abort() { 9 | aborted = true; 10 | notifyAll(); 11 | } 12 | 13 | public synchronized void put(I value) { 14 | this.value = value; 15 | notifyAll(); 16 | } 17 | 18 | public synchronized I get() throws InterruptedException { 19 | while (value == null && !aborted) 20 | wait(); 21 | return value; 22 | } 23 | 24 | public synchronized I peek() { 25 | return value; 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/resources/templates/core_selenium_csharp.twig: -------------------------------------------------------------------------------- 1 | {# 2 | template: Core Selenium C# 3 | #} 4 | 5 | // {{ ElementCodeName }} 6 | {% if (ElementText != '') -%} 7 | // {{ ElementText }} 8 | {% endif -%} 9 | IWebElement button = driver.FindElement( 10 | {% if (ElementSelectedBy == 'ElementCssSelector') -%} 11 | By.CssSelector("{{ ElementCssSelector }}") 12 | {% elseif (ElementSelectedBy == 'ElementXPath') -%} 13 | By.XPath("{{ ElementXPath }}") 14 | {% elseif (ElementSelectedBy == 'ElementId') -%} 15 | By.Id("{{ ElementId }}") 16 | {% elseif (ElementSelectedBy == 'ElementText') -%} 17 | By.XPath("//{{ ElementTagName }}[contains(normalize-space(text()), '{{ ElementText }}')]") 18 | {% endif -%} 19 | ) 20 | -------------------------------------------------------------------------------- /src/main/resources/templates/core_selenium_java.twig: -------------------------------------------------------------------------------- 1 | {# 2 | template: Core Selenium Java 3 | #} 4 | 5 | // {{ ElementCodeName }} 6 | {% if (ElementText != '') -%} 7 | // {{ ElementText }} 8 | {% endif -%} 9 | WebElement element = driver.findElement( 10 | {% if (ElementSelectedBy == 'ElementCssSelector') -%} 11 | By.cssSelector("{{ ElementCssSelector }}") 12 | {% elseif (ElementSelectedBy == 'ElementXPath') -%} 13 | By.xpath("{{ ElementXPath }}") 14 | {% elseif (ElementSelectedBy == 'ElementId') -%} 15 | By.id("{{ ElementId }}") 16 | {% elseif (ElementSelectedBy == 'ElementText') -%} 17 | By.xpath("//{{ ElementTagName }}[contains(normalize-space(text()), '{{ ElementText }}')]") 18 | {% endif -%} 19 | ) 20 | -------------------------------------------------------------------------------- /src/main/java/org/mihalis/opal/multi/SimpleSelectionAdapter.java: -------------------------------------------------------------------------------- 1 | package org.mihalis.opal.multi; 2 | 3 | import org.eclipse.swt.events.SelectionEvent; 4 | import org.eclipse.swt.events.SelectionListener; 5 | 6 | public abstract class SimpleSelectionAdapter implements SelectionListener { 7 | 8 | // see 9 | // org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) 10 | 11 | @Override 12 | public void widgetDefaultSelected(final SelectionEvent e) { 13 | this.handle(e); 14 | 15 | } 16 | 17 | @Override 18 | public void widgetSelected(final SelectionEvent e) { 19 | this.handle(e); 20 | 21 | } 22 | 23 | public abstract void handle(SelectionEvent e); 24 | 25 | } -------------------------------------------------------------------------------- /src/main/resources/templates/core_selenium_linq_csharp.twig: -------------------------------------------------------------------------------- 1 | {# 2 | template: Selenium with LINQ C# 3 | #} 4 | 5 | // {{ ElementCodeName }} 6 | {% if (ElementText != '') -%} 7 | // {{ ElementText }} 8 | {% endif -%} 9 | IWebElement element = 10 | {% if (ElementSelectedBy == 'ElementText') -%} 11 | driver.FindElements(By.TagName("{{ ElementTagName }}")) 12 | .First(o => String.Compare("{{ElementText}}", o.Text, StringComparison.InvariantCulture) == 0); 13 | {% else -%} 14 | driver.FindElement( 15 | {% if (ElementSelectedBy == 'ElementCssSelector') -%} 16 | By.CssSelector("{{ ElementCssSelector }}") 17 | {% elseif (ElementSelectedBy == 'ElementXPath') -%} 18 | By.XPath("{{ ElementXPath }}") 19 | {% elseif (ElementSelectedBy == 'ElementId') -%} 20 | By.Id("{{ ElementId }}") 21 | {% endif -%} 22 | ) 23 | {% endif -%} 24 | ) 25 | -------------------------------------------------------------------------------- /src/main/resources/templates/basic_page_objects_java.twig: -------------------------------------------------------------------------------- 1 | {# 2 | template: Basic Page Objects Java 3 | } 4 | class TestPage (Page) { 5 | // {{ ElementText }} 6 | {% if (ElementSelectedBy == 'ElementCssSelector') -%} 7 | @FindBy( how = How.CSS, using = "{{ ElementCssSelector }}" ) 8 | {% elseif (ElementSelectedBy == 'ElementXPath') -%} 9 | @FindBy( how = How.XPATH, using = "{{ ElementXPath }}" ) 10 | {% elseif (ElementSelectedBy == 'ElementId') -%} 11 | @FindBy( how = How.ID, using = "{{ ElementId }}" ) 12 | {% elseif (ElementSelectedBy == 'ElementText') -%} 13 | @FindBy( how = How.XPATH, using = "//{{ ElementTagName }}[contains(normalize-space(text()), '{{ ElementText }}')]" ) #} 14 | {% endif -%} 15 | {% if (ElementVariable != '') -%} 16 | private WebElement {{ ElementVariable }}; 17 | {% else -%} 18 | private WebElement element; 19 | {% endif -%} -------------------------------------------------------------------------------- /src/main/resources/templates/core_selenium_java8_streams.twig: -------------------------------------------------------------------------------- 1 | {# 2 | template: Core Selenium Java8 / Streams 3 | #} 4 | // {{ ElementCodeName }} 5 | {% if (ElementText != '') -%} 6 | // Text: {{ ElementText }} 7 | {% endif -%} 8 | {% if (ElementSelectedBy == 'ElementText') -%} 9 | WebElement element = driver.findElements( By.tagName("{{ ElementTagName }}" 10 | .stream().filter(o -> { 11 | return (Boolean) (o.getText().contains("{{ ElementText }}")); 12 | }).findFirst(); 13 | {% else -%} 14 | WebElement element = driver.findElement( 15 | {% if (ElementSelectedBy == 'ElementCssSelector') -%} 16 | By.cssSelector("{{ ElementCssSelector }}") 17 | {% elseif (ElementSelectedBy == 'ElementXPath') -%} 18 | By.xpath("{{ ElementXPath }}") 19 | {% elseif (ElementSelectedBy == 'ElementId') -%} 20 | By.id("{{ ElementId }}") 21 | {% endif -%} 22 | ) 23 | {% endif -%} 24 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # username / password not currently used - reserved for Sauce Labs or browserStack 2 | username: username 3 | password: password 4 | # no quotes should be put around paths. Trailing whitespace is ok 5 | # use the following syntax for environment variables: ${USERPROFILE}\\desktop\\chromedriver.exe 6 | chromeDriverPath: ${USERPROFILE}\\Downloads\\chromedriver.exe 7 | # chromeDriverPath: ${HOME}/Downloads/chromedriver 8 | geckoDriverPath: c:/java/selenium/geckodriver.exe 9 | firefoxBrowserPath: C:/Program Files (x86)/Mozilla Firefox/firefox.exe 10 | # firefoxBrowserPath: /Applications/Firefox.app/Contents/MacOS/firefox 11 | geckoDriverPath: c:/java/selenium/geckodriver.exe 12 | # geckoDriverPath: ${HOME}/Downloads/geckodriver 13 | ieDriverPath: c:/java/selenium/IEDriverServer.exe 14 | edgeDriverPath: C:/Program Files (x86)/Microsoft Web Driver/MicrosoftWebDriver.exe 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/templates/core_selenium_python.twig: -------------------------------------------------------------------------------- 1 | {# 2 | template: Core Selenium Python 3 | #} 4 | 5 | from selenium import webdriver 6 | driver = webdriver.Chrome() 7 | 8 | def locate_{{ ElementCodeName }}(): 9 | {% if (ElementText != '') -%} 10 | # {{ ElementText }} 11 | {% endif -%} 12 | {% if (ElementSelectedBy == 'ElementCssSelector') -%} 13 | return driver.find_element_by_css('{{ ElementCssSelector }}'); 14 | 15 | {% elseif (ElementSelectedBy == 'ElementXPath') -%} 16 | return driver.find_element_by_xpath('{{ ElementXPath }}'); 17 | 18 | {% elseif (ElementSelectedBy == 'ElementId') -%} 19 | return driver.find_element_by_id('{{ ElementId }}'); 20 | 21 | {% elseif (ElementSelectedBy == 'ElementText') -%} 22 | return driver.find_element_by_xpath("//{{ ElementTagName }}[contains(normalize-space(text()), '{{ ElementText }}')]") 23 | 24 | {% endif -%} 25 | 26 | # TODO: preserve whitespace 27 | -------------------------------------------------------------------------------- /src/main/resources/templates/core_selenium_ruby.twig: -------------------------------------------------------------------------------- 1 | {# 2 | template: Core Selenium Ruby 3 | #} 4 | 5 | require 'selenium-webdriver' 6 | 7 | class PageElement 8 | 9 | def initialize(url) 10 | @driver=Selenium::WebDriver.for :chrome 11 | @driver.manage.window.maximize 12 | @driver.navigate.to url 13 | end 14 | def close_browser() 15 | @driver.quit 16 | end 17 | def locate_{{ ElementCodeName }}() 18 | {% if (ElementText != '') -%} 19 | # {{ ElementText }} 20 | {% endif -%} 21 | @driver.find_element( 22 | {% if (ElementSelectedBy == 'ElementCssSelector') -%} 23 | :css, '{{ ElementCssSelector }}' 24 | {% elseif (ElementSelectedBy == 'ElementXPath') -%} 25 | :xpath,'{{ ElementXPath }}' 26 | {% elseif (ElementSelectedBy == 'ElementId') -%} 27 | :id,'{{ ElementId }}' 28 | {% elseif (ElementSelectedBy == 'ElementText') -%} 29 | :xpath, "//{{ ElementTagName }}[contains(normalize-space(text()), '{{ ElementText }}')]" 30 | {% endif -%} 31 | ) 32 | end 33 | end -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/RenderTemplateTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import java.io.File; 7 | import java.util.HashMap; 8 | 9 | import org.junit.Test; 10 | 11 | import com.github.sergueik.swet.Utils; 12 | import com.github.sergueik.swet.RenderTemplate; 13 | 14 | public class RenderTemplateTest { 15 | 16 | private String templateAbsolutePath = System.getProperty("user.dir") 17 | + File.separator + "src\\main\\resources\\templates" ; 18 | 19 | @Test 20 | public void renderTest() { 21 | String templatePath = System.getProperty("user.dir") + File.separator 22 | + "src\\main\\resources\\templates\\core_selenium_csharp.twig"; 23 | RenderTemplate renderTemplate = new RenderTemplate(); 24 | System.err 25 | .println(String.format("Reading template from %s ...", templatePath)); 26 | renderTemplate.setTemplateAbsolutePath( 27 | templatePath.replace("\\\\", "\\").replace("\\", "/")); 28 | String output = renderTemplate.renderTest(); 29 | System.err.println("Rendered: " + output); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014,2017 Serguei Kouzmine 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/org/passer/ChoiceItem.java: -------------------------------------------------------------------------------- 1 | package org.passer; 2 | 3 | /******************************************************************************* 4 | * Copyright (c) 2015 Fabian Prasser 5 | *******************************************************************************/ 6 | 7 | /** 8 | * Item for the choices dialog 9 | * @author Fabian Prasser 10 | */ 11 | public class ChoiceItem { 12 | 13 | private String text; 14 | private String tooltipText; 15 | 16 | public ChoiceItem(String text, String tooltipText) { 17 | checkNull(text); 18 | checkNull(tooltipText); 19 | this.text = text; 20 | this.tooltipText = tooltipText; 21 | } 22 | 23 | public String getText() { 24 | return text; 25 | } 26 | 27 | public String getTooltipText() { 28 | return tooltipText; 29 | } 30 | 31 | public void setText(String data) { 32 | checkNull(data); 33 | this.text = data; 34 | } 35 | 36 | public void setTooltipText(String data) { 37 | checkNull(tooltipText); 38 | this.tooltipText = data; 39 | } 40 | 41 | private void checkNull(Object object) { 42 | if (object == null) { 43 | throw new IllegalArgumentException("Null is not a valid argument"); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/resources/internalConfiguration.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | Keywords: 3 | CLEAR_TEXT: clearText 4 | SWITCH_FRAME: switchFrame 5 | SET_TEXT: enterText 6 | CLICK_CHECKBOX: clickCheckBox 7 | SEND_KEYS: enterText 8 | VERIFY_TEXT: verifyText 9 | CLICK_RADIO: clickRadioButton 10 | GET_ATTR: getElementAttribute 11 | CLICK_LINK: clickLink 12 | GET_TEXT: getElementText 13 | ELEMENT_PRESENT: elementPresent 14 | GOTO_URL: navigateTo 15 | CLICK_BUTTON: clickButton 16 | CLOSE_BROWSER: closeBrowser 17 | CREATE_BROWSER: openBrowser 18 | VERIFY_ATTR: verifyAttribute 19 | CLICK: clickButton 20 | WAIT: wait 21 | SELECT_OPTION: selectDropDown 22 | SWDSelectors: 23 | ElementCssSelector: cssSelector 24 | ElementTagName: tagName 25 | ElementText: text 26 | ElementId: id 27 | ElementLinkText: linkText 28 | ElementXPath: xpath 29 | 'Column Headers': 30 | - 'Element' 31 | - 'Action Keyword' 32 | - 'Selector Choice' 33 | - 'Selector Value' 34 | - 'Param 1' 35 | - 'Param 2' 36 | - 'Param 3' 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/main/resources/help.yaml: -------------------------------------------------------------------------------- 1 | 'Testsuite Program creation': "You can generate a program in Java , C#, Ruby or other language. Few templates are embedded. 2 | You can provide your own using http://jtwig.org/ syntax:
3 |
{% if (ElementText != '') -%}
4 | // Text: {{ ElementText }}
5 | {% endif -%}
" 6 | 7 | 'Keyword-driven Framework flow creation': 'You can generate and export it as an Excel file 8 | a Keyword-driven Framework http://toolsqa.com/selenium-webdriver/keyword-driven-framework 9 | test flow' 10 | 11 | 'Saving and restoring sessions': "You can save the recording session to continue later.. 12 | Recording will be written in YAML format and will contain all element attributes 13 | (including the deselected ones) of all recorder elements:
14 |     ElementCssSelector: img.site-header-logo
15 | ElementSelectedBy: ElementCssSelector
16 | ElementCodeName: logo
17 | ElementPageURL: https://coderanch.com/c/java
18 | ElementTagName: IMG
19 | ElementStepNumber: 1
20 | ElementText: ''
21 | ElementId: ''
22 | ElementXPath: /html/body/header[1]/div[2]/div[1]/span[1]/img 23 |
" -------------------------------------------------------------------------------- /src/main/java/org/mihalis/opal/multi/MultiChoiceSelectionListener.java: -------------------------------------------------------------------------------- 1 | package org.mihalis.opal.multi; 2 | 3 | import org.eclipse.swt.events.SelectionEvent; 4 | import org.eclipse.swt.events.SelectionListener; 5 | import org.eclipse.swt.widgets.Button; 6 | import org.eclipse.swt.widgets.Shell; 7 | 8 | public abstract class MultiChoiceSelectionListener 9 | implements SelectionListener { 10 | private final MultiChoiceEx parent; 11 | 12 | public MultiChoiceSelectionListener(final MultiChoiceEx parent) { 13 | this.parent = parent; 14 | } 15 | 16 | // see 17 | // org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) 18 | @Override 19 | public final void widgetSelected(final SelectionEvent e) { 20 | final Button button = (Button) e.widget; 21 | handle(parent, parent.getLastModified(), button.getSelection(), 22 | parent.getPopup()); 23 | } 24 | 25 | // see 26 | // org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) 27 | @Override 28 | public final void widgetDefaultSelected(final SelectionEvent inutile) { 29 | } 30 | 31 | public abstract void handle(MultiChoiceEx parent, T receiver, 32 | boolean selected /* was the check box checked */, Shell popup); 33 | } -------------------------------------------------------------------------------- /launch.ps1: -------------------------------------------------------------------------------- 1 | [System.Environment]::SetEnvironmentVariable('SKIP_BUILD', 'true', [System.EnvironmentVariableTarget]::User) 2 | ./run.ps1 $args 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/test/resources/log4j_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/resources/templates/core_selenium_with_wait_java.twig: -------------------------------------------------------------------------------- 1 | {# 2 | template: Core Selenium with wait / Java 3 | #} 4 | // {{ ElementCodeName }} 5 | {% if (ElementText != '') -%} 6 | // {{ ElementText }} 7 | WebElement element = 8 | {% endif -%} 9 | {% if (ElementSelectedBy == 'ElementText') -%} 10 | wait.until( new ExpectedCondition(){ 11 | @Override 12 | public WebElement apply(WebDriver _driver) { 13 | Iterator _elements = _driver 14 | .findElements( 15 | By.XPath("//{{ ElementTagName }}[contains(normalize-space(text()), '{{ ElementText }}')]")) 16 | .iterator(); 17 | WebElement result = null; 18 | Pattern pattern = Pattern.compile("^ *" + Pattern.quote("{{ ElementText }}"), 19 | Pattern.CASE_INSENSITIVE); 20 | while (_elements.hasNext()) { 21 | WebElement _element = (WebElement) _elements.next(); 22 | Matcher matcher = pattern.matcher(_element.getText); 23 | if (matcher.find()) { 24 | result = _element; 25 | break; 26 | } 27 | } 28 | return result; 29 | } 30 | }); 31 | {% else -%} 32 | WebElement element = wait.until(ExpectedConditions.visibilityOf(driver.findElement( 33 | {% if (ElementSelectedBy == 'ElementCssSelector') -%} 34 | By.cssSelector("{{ ElementCssSelector }}") 35 | {% elseif (ElementSelectedBy == 'ElementXPath') -%} 36 | By.Xpath("{{ ElementXPath }}") 37 | {% elseif (ElementSelectedBy == 'ElementId') -%} 38 | By.Id("{{ ElementId }}") 39 | {% endif -%} 40 | ))); 41 | {% endif -%} 42 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/ConfigDataSerializer.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | import java.lang.reflect.Type; 4 | 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonObject; 7 | import com.google.gson.JsonPrimitive; 8 | import com.google.gson.JsonSerializationContext; 9 | import com.google.gson.JsonSerializer; 10 | 11 | // https://stackoverflow.com/questions/11038553/serialize-java-object-with-gson 12 | public class ConfigDataSerializer implements JsonSerializer { 13 | @Override 14 | public JsonElement serialize(final ConfigData configData, final Type type, 15 | final JsonSerializationContext context) { 16 | JsonObject result = new JsonObject(); 17 | String id = configData.getId(); 18 | if (id != null && !id.isEmpty()) { 19 | result.add("id", new JsonPrimitive(id)); 20 | } 21 | result.add("browser", new JsonPrimitive(configData.getBrowser())); 22 | result.add("templateName", new JsonPrimitive(configData.getTemplateName())); 23 | String templateDirectory = configData.getTemplateDirectory(); 24 | if (templateDirectory != null && !templateDirectory.isEmpty()) { 25 | result.add("templateDirectory", new JsonPrimitive(templateDirectory)); 26 | } 27 | String templatePath = configData.getTemplatePath(); 28 | if (templatePath != null && !templatePath.isEmpty()) { 29 | result.add("templatePath", new JsonPrimitive(templatePath)); 30 | } 31 | /* 32 | Template template = configData.getTemplate(); 33 | if (template != null) { 34 | result.add("template", new JsonPrimitive(template.getId())); 35 | } 36 | */ 37 | return result; 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/custom/swt/widgets/Container.java: -------------------------------------------------------------------------------- 1 | package custom.swt.widgets; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.SWTException; 5 | import org.eclipse.swt.graphics.Image; 6 | import org.eclipse.swt.graphics.Point; 7 | import org.eclipse.swt.layout.GridData; 8 | import org.eclipse.swt.layout.GridLayout; 9 | import org.eclipse.swt.widgets.Button; 10 | import org.eclipse.swt.widgets.Composite; 11 | import org.eclipse.swt.widgets.Control; 12 | import org.eclipse.swt.widgets.Dialog; 13 | import org.eclipse.swt.widgets.Display; 14 | import org.eclipse.swt.widgets.Event; 15 | import org.eclipse.swt.widgets.Label; 16 | import org.eclipse.swt.widgets.Listener; 17 | import org.eclipse.swt.widgets.ProgressBar; 18 | import org.eclipse.swt.widgets.ScrollBar; 19 | import org.eclipse.swt.widgets.Shell; 20 | import org.eclipse.swt.widgets.Text; 21 | import org.eclipse.swt.graphics.Rectangle; 22 | 23 | import org.eclipse.swt.graphics.Point; 24 | import org.eclipse.swt.widgets.Composite; 25 | 26 | public class Container extends Composite { 27 | 28 | public Container(Composite parent, int style) { 29 | super(parent, style); 30 | /* 31 | setLayout(new LayoutDelegate().layout(this::onLayout) 32 | .computeSize(this::onComputeSize)); 33 | */ 34 | } 35 | 36 | protected void onLayout(Composite composite, boolean flushCache) { 37 | 38 | } 39 | 40 | protected Point onComputeSize(Composite composite, int wHint, int hHint, 41 | boolean flushCache) { 42 | return new Point(0, 0); 43 | } 44 | 45 | public void dispose() { 46 | if (isDisposed()) 47 | return; 48 | 49 | super.dispose(); 50 | onDisposed(); 51 | } 52 | 53 | protected void onDisposed() { 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/Log4j2Test.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | // for jvm arguments. Must have "-DAPP_LOG_ROOT=c:/temp" 7 | // can also assert if the -Dfile.encoding=UTF-8 argument is passed into surefile plugin properly 8 | import java.lang.management.ManagementFactory; 9 | import java.lang.management.RuntimeMXBean; 10 | 11 | import java.util.List; 12 | 13 | import org.apache.logging.log4j.LogManager; 14 | import org.apache.logging.log4j.Logger; 15 | 16 | import org.junit.After; 17 | import org.junit.AfterClass; 18 | import org.junit.Before; 19 | import org.junit.BeforeClass; 20 | import org.junit.Ignore; 21 | import org.junit.Test; 22 | 23 | /** 24 | * Common utilities for separate patterns, files for Logging info, error and debug to console and file logging for Selenium WebDriver Elementor Tool (SWET) 25 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 26 | */ 27 | 28 | // based on: https://github.com/hmeclazcke/log4j2-example 29 | public class Log4j2Test { 30 | // This example must run with -DAPP_LOG_ROOT=c:/temp 31 | private static final Logger LOGGER = LogManager 32 | .getLogger(Log4j2Test.class.getName()); 33 | 34 | @Test 35 | public void sampleLog4Jtest() { 36 | 37 | // Prints the jvm arguments. Must have "-DAPP_LOG_ROOT=c:/temp" --> location 38 | // of the logs.- 39 | RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); 40 | List jvmArgs = runtimeMXBean.getInputArguments(); 41 | System.out.println("jvm arguments: " + jvmArgs); 42 | 43 | LOGGER.debug("Debug debugging message"); 44 | LOGGER.info("Info information message"); 45 | LOGGER.error("Error Message Logged !!!", new Exception("excepition")); 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/InstalledBrowsersTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | import static java.lang.System.err; 4 | import static java.lang.System.out; 5 | 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import static org.junit.Assert.*; 11 | // [WARNING] No processor claimed any of these annotations: org.junit.AfterClass,org.junit.BeforeClass,org.junit.Ignore,org.junit.After,org.junit.Test,org.junit.Before 12 | 13 | import org.junit.Test; 14 | 15 | import com.github.sergueik.swet.Utils; 16 | import com.github.sergueik.swet.OSUtils; 17 | 18 | public class InstalledBrowsersTest { 19 | 20 | private static Map browserNames = new HashMap<>(); 21 | static { 22 | browserNames.put("chrome.exe", "Google Chrome"); 23 | browserNames.put("iexplore.exe", "Internet Explorer"); 24 | browserNames.put("firefox.exe", "Mozilla Firefox"); 25 | } 26 | private static Utils utils = Utils.getInstance(); 27 | private static String result = null; 28 | private static final boolean debug = true; 29 | 30 | @Test 31 | public void test() { 32 | utils.setDebug(debug); 33 | List browsers = OSUtils.getInstalledBrowsers(); 34 | assertTrue(browsers.size() > 0); 35 | out.println("Your browsers: " + browsers); 36 | 37 | for (String browserName : browserNames.keySet()) { 38 | if (browsers.contains(browserName)) { 39 | assertTrue(OSUtils.isInstalled(browserName)); 40 | assertTrue(OSUtils.getMajorVersion(browserName) > 0); 41 | out.println(String.format("%s version: %s", 42 | browserNames.get(browserName), OSUtils.getVersion(browserName))); 43 | } else { 44 | assertFalse(OSUtils.isInstalled(browserName)); 45 | assertTrue(OSUtils.getMajorVersion(browserName) == 0); 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/BrowserConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import static java.lang.String.format; 7 | 8 | /** 9 | * Browser Configuration Serializer class for Selenium WebDriver Elementor Tool (SWET) 10 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 11 | */ 12 | 13 | public final class BrowserConfiguration { 14 | public String name; 15 | public String platform; 16 | public String driverPath; 17 | public String driverVersion; 18 | public String version; 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String data) { 25 | this.name = data; 26 | } 27 | 28 | public String getDriverVersion() { 29 | return driverVersion; 30 | } 31 | 32 | public void setDriverVersion(String data) { 33 | this.driverVersion = data; 34 | } 35 | 36 | public String getVersion() { 37 | return version; 38 | } 39 | 40 | public void setVersion(String data) { 41 | this.version = data; 42 | } 43 | 44 | public String getPlatform() { 45 | return platform; 46 | } 47 | 48 | public void setPlatform(String data) { 49 | this.platform = data; 50 | } 51 | 52 | public String getDriverPath() { 53 | return driverPath; 54 | } 55 | 56 | public void setDriverPath(String data) { 57 | this.driverPath = data; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return String.format("Browser '%s' version '%s'%s on '%s'%s", getName(), 63 | getVersion(), 64 | (getDriverVersion() == null) ? "" 65 | : String.format(", driver version '%s'", getDriverVersion()), 66 | getPlatform(), 67 | (getDriverPath() == null) ? "" 68 | : String.format(", with path to driver set to '%s'", 69 | getDriverPath())); 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/resources/sample.yaml: -------------------------------------------------------------------------------- 1 | !!com.github.sergueik.swet.Configuration 2 | browserConfiguration: null 3 | browsers: null 4 | created: null 5 | elements: 6 | 0b55bdd1-b5df-4558-9bcf-94ef9f216395: 7 | ElementCssSelector: div#hplogo > canvas 8 | ElementSelectedBy: ElementCssSelector 9 | ElementCodeName: logo 10 | Command: AddElement 11 | Caller: addElement 12 | ElementPageURL: https://www.google.com/ 13 | ElementTagName: CANVAS 14 | CommandId: 0b55bdd1-b5df-4558-9bcf-94ef9f216395 15 | ElementStepNumber: '0' 16 | ElementText: '' 17 | ElementId: '' 18 | ElementXPath: id("hplogo")/canvas[1] 19 | e0b7030a-0030-4136-a81a-8070a48fa585: 20 | ElementCssSelector: form#tsf > div.tsf-p > div.jsb > center > input 21 | ElementSelectedBy: ElementCssSelector 22 | ElementCodeName: search button 23 | Command: AddElement 24 | Caller: addElement 25 | ElementPageURL: https://www.google.com/ 26 | ElementTagName: INPUT 27 | CommandId: e0b7030a-0030-4136-a81a-8070a48fa585 28 | ElementStepNumber: '2' 29 | ElementText: '' 30 | ElementId: '' 31 | ElementXPath: //input[@name="btnK"] 32 | a6d566be-a0fd-4b31-929a-52b370746680: 33 | ElementCssSelector: div#gbw > div > div.gb_kb.gb_Dg.gb_R.gb_Cg.gb_Hg.gb_T > div.gb_je.gb_R.gb_Dg.gb_ug 34 | > div.gb_Q.gb_R > a.gb_P[ href = "https://mail.google.com/mail/?tab=wm" ] 35 | ElementSelectedBy: ElementCssSelector 36 | ElementCodeName: gmail link 37 | Command: AddElement 38 | Caller: addElement 39 | ElementPageURL: https://www.google.com/ 40 | ElementTagName: A 41 | CommandId: a6d566be-a0fd-4b31-929a-52b370746680 42 | ElementStepNumber: '1' 43 | ElementText: Gmail 44 | ElementId: '' 45 | ElementXPath: id("gbw")/div[1]/div[1]/div[1]/div[1]/a[ @href = "https://mail.google.com/mail/?tab=wm" 46 | ] 47 | plugins: null 48 | seleniumVersion: null 49 | updated: 2017-12-31T05:00:00Z 50 | version: null 51 | -------------------------------------------------------------------------------- /run2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # based on: 4 | # https://www.cyberforum.ru/shell/thread2822786.html 5 | 6 | get_text() { 7 | 8 | TAG=${1:-version} 9 | PROJECT_FILE=${2:-pom.xml} 10 | 11 | if [[ "$DEBUG" = 'true' ]]; then 12 | 1>&2 printf "started get_text() with TAG=%s PROJECT_FILE=%s\n" $TAG $PROJECT_FILE 13 | fi 14 | RESULT='' 15 | PRINTED='false' 16 | IN_PROJECT='false' 17 | IN_DEPENDENCIES='false' 18 | while read LINE; 19 | do 20 | if [[ "$LINE" =~ '' ]]; then 21 | IN_PROJECT='true' 22 | RESULT='' 23 | PRINTED='false' 24 | fi 25 | if [ $(expr match "$LINE" '' ]]; then 29 | IN_PROJECT='false' 30 | fi 31 | # TODO: exclude scanning etc. 32 | if [ $(expr match "$LINE" '") != '0' ]; then 39 | 40 | RESULT=$(echo $LINE | sed "s/<\\/\\{0,1\\}${TAG}>//g") 41 | if [[ "$DEBUG" = 'true' ]]; then 42 | 1>&2 printf "Found result:%s\n" $RESULT 43 | fi 44 | # return result immediately 45 | echo $RESULT 46 | return 47 | fi 48 | fi 49 | done <$PROJECT_FILE 50 | } 51 | 52 | PROJECT_FILE=${1:-pom.xml} 53 | if [[ "$DEBUG" = 'true' ]]; then 54 | 1>&2 echo 'Started.' 55 | fi 56 | TAG='version' 57 | APP_VERSION=$(get_text $TAG $PROJECT_FILE) 58 | echo "APP_VERSION=${APP_VERSION}" 59 | 60 | TAG='groupId' 61 | PACKAGE=$(get_text $TAG $PROJECT_FILE) 62 | echo "PACKAGE=${PACKAGE}" 63 | 64 | TAG='artifactId' 65 | APP_NAME=$(get_text $TAG $PROJECT_FILE) 66 | echo "APP_NAME=${APP_NAME}" 67 | 68 | TAG='mainClass' 69 | DEFAULT_MAIN_CLASS=$(get_text $TAG $PROJECT_FILE) 70 | echo "DEFAULT_MAIN_CLASS=${DEFAULT_MAIN_CLASS}" 71 | 72 | if [[ "$DEBUG" = 'true' ]]; then 73 | 1>&2 echo 'Done.' 74 | fi 75 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/ChoiceDialogEx.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019,2021 Serguei Kouzmine 4 | */ 5 | 6 | import org.eclipse.swt.SWT; 7 | import org.eclipse.swt.widgets.Display; 8 | import org.eclipse.swt.widgets.Shell; 9 | 10 | import org.passer.ChoiceItem; 11 | import org.passer.ChoicesDialog; 12 | 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import java.io.FileInputStream; 17 | import java.io.IOException; 18 | import java.util.Formatter; 19 | import java.util.Locale; 20 | import java.util.Properties; 21 | 22 | public class ChoiceDialogEx { 23 | 24 | private static Display display; 25 | private static Shell shell; 26 | private static StringBuilder loggingSb = new StringBuilder(); 27 | private static Formatter formatter = new Formatter(loggingSb, Locale.US); 28 | private static Utils utils = Utils.getInstance(); 29 | 30 | private static final Logger logger = LoggerFactory 31 | .getLogger(ChoiceDialogEx.class); 32 | 33 | @SuppressWarnings("unused") 34 | public static void main(String[] args) { 35 | // Create choices 36 | utils.initializeLogger(); 37 | logger.info("Initialized logger."); 38 | display = new Display(); 39 | shell = new Shell(display); 40 | ChoiceItem[] items = new ChoiceItem[] { 41 | new ChoiceItem("Exit and save my project", 42 | "Save your work in progress and exit the program"), 43 | new ChoiceItem("Exit and don't save", 44 | "Exit the program without saving your project"), 45 | new ChoiceItem("Don't exit", "Return to the program"), }; 46 | 47 | ChoicesDialog dialog = new ChoicesDialog(shell, SWT.APPLICATION_MODAL); 48 | 49 | dialog.setTitle("Exit"); 50 | dialog.setMessage("Do you really want to exit?"); 51 | dialog.setImage(Display.getCurrent().getSystemImage(SWT.ICON_QUESTION)); 52 | dialog.setChoices(items); 53 | dialog.setDefaultChoice(items[2]); 54 | dialog.setShowArrows(false); 55 | 56 | int choice = dialog.open(); 57 | logger.info("Choice: " + choice); 58 | if (choice == -1) { 59 | // Choice selected, will be one of {0,1,2} 60 | } else { 61 | 62 | } 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/BusyIndicatorEx.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | /** 4 | * Copyright 2018 Serguei Kouzmine 5 | */ 6 | 7 | import static java.lang.String.format; 8 | 9 | import java.util.Date; 10 | import java.util.List; 11 | import java.util.Map; 12 | import org.eclipse.swt.*; 13 | import org.eclipse.swt.custom.*; 14 | import org.eclipse.swt.events.*; 15 | import org.eclipse.swt.layout.*; 16 | import org.eclipse.swt.widgets.*; 17 | 18 | /** 19 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 20 | * 21 | */ 22 | // Demo of toggle to a Busy Cursor 23 | // during a long running process 24 | // using org.eclipse.swt.custom.BusyIndicator . 25 | 26 | // based on: 27 | // http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/DemonstratesBusyIndicator.htm 28 | 29 | final class BusyIndicatorEx { 30 | private static final int SLEEP_TIME = 3000; 31 | 32 | private void run() { 33 | 34 | Display display = new Display(); 35 | Shell shell = new Shell(display); 36 | shell.setText("Busy Indicator Test"); 37 | createContents(shell); 38 | shell.pack(); 39 | shell.open(); 40 | while (!shell.isDisposed()) { 41 | if (!display.readAndDispatch()) { 42 | display.sleep(); 43 | } 44 | } 45 | display.dispose(); 46 | } 47 | 48 | private void createContents(Shell shell) { 49 | shell.setLayout(new FillLayout()); 50 | final Button button = new Button(shell, SWT.PUSH); 51 | button.setText("Press to Start"); 52 | button.addSelectionListener(new SelectionAdapter() { 53 | public void widgetSelected(SelectionEvent event) { 54 | button.setText("Running..."); 55 | BusyIndicator.showWhile(button.getDisplay(), 56 | new SleepThread(SLEEP_TIME)); 57 | button.setText("Press to Start"); 58 | } 59 | }); 60 | } 61 | 62 | // dummy worker 63 | static private class SleepThread extends Thread { 64 | private long ms; 65 | 66 | public SleepThread(long ms) { 67 | this.ms = ms; 68 | } 69 | 70 | public void run() { 71 | try { 72 | sleep(ms); 73 | } catch (InterruptedException e) { 74 | } 75 | } 76 | } 77 | 78 | public static void main(String[] args) { 79 | new BusyIndicatorEx().run(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/PropertiesParser.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.IOException; 9 | import java.util.Enumeration; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Properties; 13 | 14 | /** 15 | * Common configuration / properties file parsers for Selenium WebDriver Elementor Tool (SWET) 16 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 17 | */ 18 | 19 | public class PropertiesParser { 20 | 21 | /* 22 | 23 | private static String propertiesFileName = "test.properties"; 24 | Map propertiesMap = PropertiesParser 25 | .getProperties(String.format("%s/src/main/resources/%s", 26 | System.getProperty("user.dir"), propertiesFileName)); 27 | String username = propertiesMap.get("username"); 28 | String password = propertiesMap.get("password"); 29 | StringBuilder loggingSb = new StringBuilder(); 30 | Formatter formatter = new Formatter(loggingSb, Locale.US); 31 | */ 32 | 33 | public static Map getProperties(final String fileName) { 34 | Properties p = new Properties(); 35 | Map propertiesMap = new HashMap<>(); 36 | // System.err.println(String.format("Reading properties file: '%s'", 37 | // fileName)); 38 | try { 39 | p.load(new FileInputStream(fileName)); 40 | @SuppressWarnings("unchecked") 41 | Enumeration e = (Enumeration) p.propertyNames(); 42 | for (; e.hasMoreElements();) { 43 | String key = e.nextElement(); 44 | String val = p.get(key).toString(); 45 | System.out.println(String.format("Reading: '%s' = '%s'", key, val)); 46 | propertiesMap.put(key, Utils.resolveEnvVars(val)); 47 | } 48 | 49 | } catch (FileNotFoundException e) { 50 | System.err.println( 51 | String.format("Properties file was not found: '%s'", fileName)); 52 | e.printStackTrace(); 53 | } catch (IOException e) { 54 | System.err.println( 55 | String.format("Properties file is not readable: '%s'", fileName)); 56 | e.printStackTrace(); 57 | } 58 | return (propertiesMap); 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/custom/swt/widgets/InfoPopup.java: -------------------------------------------------------------------------------- 1 | package custom.swt.widgets; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.graphics.Color; 5 | import org.eclipse.swt.graphics.Point; 6 | import org.eclipse.swt.layout.GridLayout; 7 | import org.eclipse.swt.widgets.Composite; 8 | import org.eclipse.swt.widgets.Control; 9 | import org.eclipse.swt.widgets.Display; 10 | import org.eclipse.swt.widgets.Label; 11 | import org.eclipse.swt.widgets.Shell; 12 | import custom.swt.widgets.PopupDialog; 13 | 14 | 15 | // origin: https://github.com/cosbi-research/SWTCustomComponents/blob/master/src/custom/swt/widgets/InfoPopup.java 16 | public class InfoPopup extends PopupDialog { 17 | 18 | private static Display display; 19 | private static Shell shell; 20 | 21 | private Composite popupContent; 22 | private Composite parent; 23 | private String content; 24 | 25 | public InfoPopup(Composite parent, String textToBeDisplayed) { 26 | super(parent.getShell(), SWT.ON_TOP, true, false, false, false, false, null, 27 | null); 28 | content = textToBeDisplayed; 29 | } 30 | 31 | @Override 32 | protected Control createDialogArea(Composite parent) { 33 | this.parent = parent; 34 | // parent.setBackground(white); 35 | popupContent = new Composite(parent, SWT.NONE); 36 | // popupContent.setBackground(white); 37 | disposeContent(); 38 | updateContent(); 39 | return popupContent; 40 | } 41 | 42 | private void disposeContent() { 43 | for (Control child : popupContent.getChildren()) 44 | child.dispose(); 45 | } 46 | 47 | private void updateContent() { 48 | 49 | GridLayout gridLayout = new GridLayout(1, false); 50 | popupContent.setLayout(gridLayout); 51 | 52 | Label label = new Label(popupContent, SWT.NONE); 53 | label.setText(content); 54 | } 55 | 56 | @Override 57 | protected Color getBackground() { 58 | return parent.getBackground(); 59 | } 60 | 61 | @Override 62 | protected void adjustBounds() { 63 | getShell().setBounds(x, y, getShell().getSize().x, getShell().getSize().y); 64 | } 65 | 66 | private int x; 67 | private int y; 68 | 69 | public void setPosition(Point point) { 70 | this.x = point.x; 71 | this.y = point.y; 72 | } 73 | 74 | @Override 75 | public boolean close() { 76 | boolean ret = super.close(); 77 | return ret; 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/Log4jTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | // NOTE: the org.apache.log4j.Category 7 | // has been deprecated and needs to be replaced by the org.apache.log4jLogger 8 | // NOTE: the latter does not appear to allow different ConversionPattern for STDERR and FILE 9 | 10 | import org.apache.log4j.Logger; 11 | 12 | import org.apache.log4j.PropertyConfigurator; 13 | 14 | import java.util.Formatter; 15 | import java.util.Locale; 16 | import java.util.Properties; 17 | import java.io.FileInputStream; 18 | 19 | import java.io.IOException; 20 | 21 | import org.junit.After; 22 | import org.junit.AfterClass; 23 | import org.junit.Before; 24 | import org.junit.BeforeClass; 25 | import org.junit.Ignore; 26 | import org.junit.Test; 27 | 28 | import com.github.sergueik.swet.Utils; 29 | 30 | // based on: https://alvinalexander.com/blog/post/java/sample-how-format-log4j-logging-logfile-output 31 | public class Log4jTest { 32 | private static StringBuilder loggingSb = new StringBuilder(); 33 | private static Formatter formatter = new Formatter(loggingSb, Locale.US); 34 | 35 | @SuppressWarnings("deprecation") 36 | static final Logger logger = (Logger) Logger.getInstance(Log4jTest.class); 37 | private static Utils utils = Utils.getInstance(); 38 | 39 | // @Before 40 | 41 | @Test 42 | public void sampleLog4jtest() { 43 | Sample sample = new Sample(); 44 | logger.debug("sampleLog4jtest (debug) done."); 45 | logger.info("sampleLog4jtest (info) done."); 46 | } 47 | 48 | private static class Sample { 49 | 50 | private static StringBuilder loggingSb = new StringBuilder(); 51 | private static Formatter formatter = new Formatter(loggingSb, Locale.US); 52 | 53 | @SuppressWarnings("deprecation") 54 | static final Logger logger = (Logger) Logger.getInstance(Sample.class); 55 | private static Utils utils = Utils.getInstance(); 56 | 57 | public Sample() { 58 | utils.setDebug(true); 59 | // utils.initializeLogger(); 60 | utils.initializeLogger( 61 | String.format("%s/%s/%s", System.getProperty("user.dir"), 62 | "src/test/resources", "log4j_test.xml")); 63 | logger.info("Sample constructor (info) done."); 64 | logger.debug("Sample constructor (debug) done."); 65 | } 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/ConfigData.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | /** 4 | * Copyright 2018 Serguei Kouzmine 5 | */ 6 | 7 | import static java.lang.String.format; 8 | 9 | import java.util.Date; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 15 | */ 16 | 17 | final class ConfigData { 18 | 19 | private String browser; 20 | private String baseURL; 21 | private String templateName; 22 | private String templateDirectory; 23 | private String templatePath; 24 | private String id; 25 | 26 | private List tests; 27 | 28 | public String getBrowser() { 29 | return browser; 30 | } 31 | 32 | public void setBrowser(String data) { 33 | this.browser = data; 34 | } 35 | 36 | public String getBaseURL() { 37 | return baseURL; 38 | } 39 | 40 | public void setBaseURL(String data) { 41 | this.baseURL = data; 42 | } 43 | 44 | public String getTemplateName() { 45 | return templateName; 46 | } 47 | 48 | public void setTemplateName(String data) { 49 | this.templateName = data; 50 | } 51 | 52 | public String getTemplatePath() { 53 | return templatePath; 54 | } 55 | 56 | public void setTemplatePath(String data) { 57 | this.templatePath = data; 58 | } 59 | 60 | public void setTemplateDirectory(String data) { 61 | this.templateDirectory = data; 62 | } 63 | 64 | public String getTemplateDirectory() { 65 | return templateDirectory; 66 | } 67 | 68 | public String getId() { 69 | return id; 70 | } 71 | 72 | public void setId(String data) { 73 | this.id = data; 74 | } 75 | 76 | public void setTests(List data) { 77 | this.tests = data; 78 | } 79 | 80 | public List getTests() { 81 | return tests; 82 | } 83 | 84 | // https://stackoverflow.com/questions/11038553/serialize-java-object-with-gson 85 | // https://dzone.com/articles/automate-the-planet-10 86 | @Override 87 | public String toString() { 88 | return new StringBuilder().append(format("\"id\": \"%s\"\n", id)) 89 | .append(format("\"browser\": \"%s\"\n", browser)) 90 | .append(format("\"Template Name\": \"%s\"\n", templateName)) 91 | .append(format("\"Template Directory\": \"%s\"\n", templateDirectory)) 92 | .append(format("\"Template Path\": \"%s\"\n", templatePath)) 93 | .append(format("\"tests\": %s\n", tests.toString())).toString(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/ListJavaFonts.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | import java.awt.Font; 4 | import java.awt.FontMetrics; 5 | import java.awt.Graphics; 6 | import java.awt.GraphicsEnvironment; 7 | import java.awt.image.BufferedImage; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | /** 13 | * Utilities for Selenium WebDriver Elementor Tool (SWET) 14 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 15 | */ 16 | 17 | public class ListJavaFonts { 18 | 19 | public static void main(String[] args) { 20 | 21 | List monospaceFontFamilyNames = new ArrayList<>(); 22 | GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment 23 | .getLocalGraphicsEnvironment(); 24 | String[] fontFamilyNames = graphicsEnvironment 25 | .getAvailableFontFamilyNames(); 26 | 27 | BufferedImage bufferedImage = new BufferedImage(1, 1, 28 | BufferedImage.TYPE_INT_ARGB); 29 | Graphics graphics = bufferedImage.createGraphics(); 30 | 31 | for (String fontFamilyName : fontFamilyNames) { 32 | boolean isMonospaced = true; 33 | // 34 | int fontStyle = Font.PLAIN; 35 | int fontSize = 12; 36 | Font font = new Font(fontFamilyName, fontStyle, fontSize); 37 | @SuppressWarnings("serial") 38 | List codePoints = new ArrayList() { 39 | { 40 | add(108); /* l */ 41 | add(109); /* m */ 42 | add(119); /* w */ 43 | add(49); /* 1 */ 44 | add(52); /* 4 */ 45 | } 46 | }; 47 | FontMetrics fontMetrics = graphics.getFontMetrics(font); 48 | 49 | int firstCharacterWidth = 0; 50 | boolean hasFirstCharacterWidth = false; 51 | for (int codePoint : codePoints) { 52 | if (Character.isValidCodePoint(codePoint) 53 | && (Character.isLetter(codePoint) 54 | || Character.isDigit(codePoint))) { 55 | char character = (char) codePoint; 56 | int characterWidth = fontMetrics.charWidth(character); 57 | if (hasFirstCharacterWidth) { 58 | if (characterWidth != firstCharacterWidth) { 59 | isMonospaced = false; 60 | break; 61 | } 62 | } else { 63 | firstCharacterWidth = characterWidth; 64 | hasFirstCharacterWidth = true; 65 | } 66 | } 67 | } 68 | 69 | if (isMonospaced) { 70 | monospaceFontFamilyNames.add(fontFamilyName); 71 | } 72 | } 73 | 74 | graphics.dispose(); 75 | for (String fontFamily : monospaceFontFamilyNames) { 76 | System.out.println(fontFamily); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/main/resources/sampleTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "browser": "Firefox", 3 | "URL": "https://www.amazon.com/", 4 | "testsuite": { 5 | "name": "BuyTheItem", 6 | "testcase": [ 7 | { 8 | "name": "OutofStock", 9 | "step": [ 10 | { 11 | "name": "selectAttributes", 12 | "action": "Click", 13 | "locateElement": { 14 | "by": "Xpath", 15 | "value": ".//a[@title=\"Echo Dot (2nd Generation) - Black\"]" 16 | }, 17 | "thirdPara": "Step comment." 18 | }, 19 | { 20 | "name": "addAssertion", 21 | "action": "CheckValue", 22 | "locateElement": { 23 | "by": "id", 24 | "value": "availability" 25 | }, 26 | "thirdPara": "In Stock." 27 | } 28 | ] 29 | }, 30 | { 31 | "name": "AddtoCart", 32 | "step": [ 33 | { 34 | "name": "itemName", 35 | "action": "WriteText", 36 | "locateElement": { 37 | "by": "id", 38 | "value": "twotabsearchtextbox" 39 | }, 40 | "thirdPara": "echo dot" 41 | }, 42 | { 43 | "name": "searchItem", 44 | "action": "Click", 45 | "locateElement": { 46 | "by": "className", 47 | "value": "nav-input" 48 | } 49 | }, 50 | { 51 | "name": "selectAttributes", 52 | "action": "Click", 53 | "locateElement": { 54 | "by": "Xpath", 55 | "value": ".//a[@title=\"Echo Dot (2nd Generation) - White\"]" 56 | } 57 | }, 58 | { 59 | "name": "selectQty", 60 | "action": "SelectOption", 61 | "locateElement": { 62 | "by": "Xpath", 63 | "value": ".//select[@id=\"quantity\"]" 64 | }, 65 | "thirdPara": "3" 66 | }, 67 | { 68 | "name": "buy", 69 | "action": "Click", 70 | "locateElement": { 71 | "by": "Xpath", 72 | "value": ".//*[@title=\"Add to Shopping Cart\"]" 73 | } 74 | }, 75 | { 76 | "name": "addAssertion", 77 | "action": "CheckContainsValue", 78 | "locateElement": { 79 | "by": "id", 80 | "value": "availability" 81 | }, 82 | "thirdPara": "In Stock." 83 | } 84 | ] 85 | } 86 | ] 87 | } 88 | } -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/JavaHotkeyManager.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | import java.awt.event.KeyEvent; 4 | import com.sun.jna.Native; 5 | import com.sun.jna.NativeLibrary; 6 | import com.sun.jna.Pointer; 7 | import com.sun.jna.win32.W32APIOptions; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | import com.sun.jna.Pointer; 13 | import com.sun.jna.Structure; 14 | 15 | // based on: https://toster.ru/q/636535 16 | public class JavaHotkeyManager extends Thread { 17 | public static void register() { 18 | User32.RegisterHotKey(null, 1, 0x000, KeyEvent.VK_F); 19 | new JavaHotkeyManager().start(); 20 | } 21 | 22 | public JavaHotkeyManager() { 23 | 24 | } 25 | 26 | public static void main(String[] args) { 27 | register(); 28 | // run(); 29 | } 30 | 31 | @Override 32 | public void run() { 33 | JavaHotkeyManager.MSG msg = new JavaHotkeyManager.MSG(); 34 | System.err.println("Running " + this.toString()); 35 | while (true) { 36 | // register the key on the same thread as listening 37 | User32.RegisterHotKey(null, 1, 0x000, KeyEvent.VK_F); 38 | while (User32.PeekMessage(msg, null, 0, 0, User32.PM_REMOVE)) { 39 | if (msg.message == User32.WM_HOTKEY) { 40 | System.out.println("Hotkey pressed with id: " + msg.wParam); 41 | } 42 | } 43 | 44 | try { 45 | Thread.sleep(300); 46 | } catch (InterruptedException e) { 47 | // TODO Auto-generated catch block 48 | e.printStackTrace(); 49 | } 50 | } 51 | } 52 | 53 | private static class User32 { 54 | static { 55 | Native.register( 56 | NativeLibrary.getInstance("user32", W32APIOptions.DEFAULT_OPTIONS)); 57 | } 58 | 59 | public static final int MOD_ALT = 0x0001; 60 | public static final int MOD_CONTROL = 0x0002; 61 | public static final int MOD_SHIFT = 0x0004; 62 | public static final int MOD_WIN = 0x0008; 63 | public static final int WM_HOTKEY = 0x0312; 64 | public static final int PM_REMOVE = 0x0001; 65 | 66 | public static native boolean RegisterHotKey(Pointer hWnd, int id, 67 | int fsModifiers, int vk); 68 | 69 | public static native boolean UnregisterHotKey(Pointer hWnd, int id); 70 | 71 | public static native boolean PeekMessage(JavaHotkeyManager.MSG lpMsg, 72 | Pointer hWnd, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg); 73 | 74 | } 75 | 76 | public static class MSG extends Structure { 77 | public Pointer hWnd; 78 | public int lParam; 79 | public int message; 80 | public int time; 81 | public int wParam; 82 | public int x; 83 | public int y; 84 | 85 | @Override 86 | protected List getFieldOrder() { 87 | return Arrays.asList(new String[] { "hWnd", "lParam", "message", "time", 88 | "wParam", "x", "y" }); 89 | } 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/SwetImmutableListCopyOfExcerptionTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import org.junit.After; 9 | import org.junit.AfterClass; 10 | import org.junit.Before; 11 | import org.junit.BeforeClass; 12 | import org.junit.Test; 13 | import org.openqa.selenium.Alert; 14 | import org.openqa.selenium.WebDriver; 15 | import org.openqa.selenium.interactions.Actions; 16 | import org.openqa.selenium.support.ui.WebDriverWait; 17 | 18 | // reproduced launch button action 19 | @SuppressWarnings("deprecation") 20 | public class SwetImmutableListCopyOfExcerptionTest { 21 | 22 | private static WebDriver driver; 23 | private static WebDriverWait wait; 24 | private static Actions actions; 25 | private static Alert alert; // unused 26 | 27 | private static String browser = "chrome"; 28 | private static final String baseURL = "about:blank"; 29 | private static String osName = OSUtils.getOsName(); 30 | private Utils utils = Utils.getInstance(); 31 | 32 | private static final int flexibleWait = 30; 33 | private static final int implicitWait = 1; 34 | private static final long pollingInterval = 500; 35 | 36 | @BeforeClass 37 | public static void beforeClassMethod() { 38 | // for exception test the browser selection is hard-coded 39 | System.err.println("os: " + osName); 40 | if (osName.equals("windows")) { 41 | browser = "Chrome"; 42 | } else if (osName.startsWith("mac")) { 43 | browser = "safari"; 44 | } else { 45 | browser = "firefox"; 46 | } 47 | System.err.println("browser: " + browser); 48 | driver = BrowserDriver.initialize(browser); 49 | } 50 | 51 | @Before 52 | public void loadBaseURL() { 53 | utils.setDriver(driver); 54 | driver.manage().timeouts().pageLoadTimeout(50, TimeUnit.SECONDS) 55 | .implicitlyWait(implicitWait, TimeUnit.SECONDS) 56 | .setScriptTimeout(30, TimeUnit.SECONDS); 57 | utils.setFlexibleWait(flexibleWait); 58 | wait = new WebDriverWait(driver, flexibleWait); 59 | wait.pollingEvery(pollingInterval, TimeUnit.MILLISECONDS); 60 | actions = new Actions(driver); 61 | utils.setActions(actions); 62 | driver.get(baseURL); 63 | } 64 | 65 | // @Ignore 66 | @Test 67 | public void testWebPageElementSearch() { 68 | driver.get("https://www.codeproject.com/"); 69 | } 70 | 71 | @After 72 | public void resetBrowser() { 73 | driver.get("about:blank"); 74 | } 75 | 76 | @AfterClass 77 | public static void afterSuiteMethod() { 78 | if (driver != null) { 79 | try { 80 | BrowserDriver.close(); 81 | } catch (Exception e) { 82 | // System.err.println("Ignored exception (after suite): " + 83 | // e.toString()); 84 | } 85 | } 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/Configuration.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2018 Serguei Kouzmine 4 | */ 5 | 6 | import static java.lang.String.format; 7 | 8 | import java.util.Date; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * Test configuration serializer class for Selenium WebDriver Elementor Tool (SWET) 14 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 15 | */ 16 | 17 | final class Configuration { 18 | public Date created; 19 | public Date updated; 20 | public String version; 21 | public String seleniumVersion; 22 | public BrowserConfiguration browserConfiguration; 23 | public List browsers; 24 | public Map> elements; 25 | public Map plugins; 26 | 27 | public Date getCreated() { 28 | return created; 29 | } 30 | 31 | public void setCreated(Date data) { 32 | this.created = data; 33 | } 34 | 35 | public Date getUpdated() { 36 | return updated; 37 | } 38 | 39 | public void setUpdated(Date data) { 40 | this.updated = data; 41 | } 42 | 43 | public String getVersion() { 44 | return version; 45 | } 46 | 47 | public void setVersion(String data) { 48 | this.version = data; 49 | } 50 | 51 | public String getSeleniumVersion() { 52 | return seleniumVersion; 53 | } 54 | 55 | public void setSeleniumVersion(String data) { 56 | this.seleniumVersion = data; 57 | } 58 | 59 | public BrowserConfiguration getBrowserConfiguration() { 60 | return browserConfiguration; 61 | } 62 | 63 | public void setBrowserConfiguration(BrowserConfiguration data) { 64 | this.browserConfiguration = data; 65 | } 66 | 67 | public List getBrowsers() { 68 | return browsers; 69 | } 70 | 71 | public void setBrowsers(List data) { 72 | this.browsers = data; 73 | } 74 | 75 | public Map getPlugins() { 76 | return plugins; 77 | } 78 | 79 | public void setPlugins(Map data) { 80 | this.plugins = data; 81 | } 82 | 83 | public Map> getElements() { 84 | return elements; 85 | } 86 | 87 | public void setElements(Map> data) { 88 | this.elements = data; 89 | } 90 | 91 | @Override 92 | public String toString() { 93 | return new StringBuilder().append(format("Version: %s\n", version)) 94 | .append(format("Created: %s\n", created)) 95 | .append(format("Selenium version: %s\n", seleniumVersion)) 96 | .append(format("Supported browsers: %s\n", browsers)) 97 | .append(format("Using: %s\n", browserConfiguration)) 98 | .append(format("Plugins: %s\n", plugins)) 99 | .append(format("Elements: %s\n", elements)).toString(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/TestConfigurationParser.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import java.io.File; 7 | import java.io.FileNotFoundException; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | import java.util.Scanner; 13 | import java.util.regex.Pattern; 14 | import java.util.stream.Collectors; 15 | 16 | /** 17 | * Configuration table helper for Selenium WebDriver Elementor Tool (SWET) 18 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 19 | */ 20 | 21 | public class TestConfigurationParser { 22 | 23 | private static boolean skipHeaders = true; 24 | private static String defaultConfig = "test.configuration"; 25 | private static Scanner scanner; 26 | 27 | public static void main(String[] args) { 28 | String configuPath = (args.length == 0) 29 | ? String.format("%s/src/main/resources/%s", 30 | System.getProperty("user.dir"), defaultConfig) 31 | : String.format("%s/%s", System.getProperty("user.dir"), args[0]); 32 | TestConfigurationParser.getConfiguration(configuPath); 33 | 34 | } 35 | 36 | @SuppressWarnings("resource") 37 | public static Scanner loadTestData(final String filename) { 38 | Scanner scanner = null; 39 | System.err 40 | .println(String.format("Reading configuration file: '%s'", filename)); 41 | try { 42 | scanner = new Scanner(new File(filename)).useDelimiter("(?:\\r?\\n)+"); 43 | } catch (FileNotFoundException e) { 44 | System.err.println( 45 | String.format("Configuration file was not found: '%s'", filename)); 46 | e.printStackTrace(); 47 | } 48 | return scanner; 49 | } 50 | 51 | public static List getConfiguration(final String filename) { 52 | List result = new LinkedList<>(); 53 | scanner = loadTestData(filename); 54 | List separators = new ArrayList( 55 | Arrays.asList(new String[] { "|", "\t", ";", "," })); 56 | String separator = String 57 | .format("(?:%s)", 58 | String.join("|", 59 | separators.stream().map(o -> Pattern.compile("(\\||/)") 60 | .matcher(o).replaceAll("\\\\$1")) 61 | .collect(Collectors.toList()))); 62 | int lineNum = 0; 63 | // System.err.println("separator:" + separator); 64 | while (scanner.hasNext()) { 65 | String line = scanner.next(); 66 | // System.err.println("line: " + line); 67 | // skip comments 68 | if (line.matches("^#.*$")) { 69 | continue; 70 | } 71 | lineNum++; 72 | // skip headers 73 | if (skipHeaders) { 74 | if (lineNum == 1) { 75 | continue; 76 | } 77 | } 78 | 79 | String[] columns = line.split(separator); 80 | /* 81 | for (String column : columns) { 82 | System.err.println("data column: " + column); 83 | } 84 | */ 85 | result.add(columns); 86 | } 87 | scanner.close(); 88 | return result; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} %p %m%n 6 | %-5p - %m%n 7 | %-5p %d{yyyy-MM-dd HH:mm:ss} **** %F [%c{1}] - [%M] - %m%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/PropertiesTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.is; 7 | import static org.hamcrest.CoreMatchers.nullValue; 8 | import static org.hamcrest.Matchers.containsInAnyOrder; 9 | // NOTE: need to provide all entries 10 | import static org.hamcrest.Matchers.hasItems; 11 | import static org.hamcrest.CoreMatchers.notNullValue; 12 | import static org.hamcrest.CoreMatchers.containsString; 13 | import static org.hamcrest.Matchers.greaterThan; 14 | import static org.hamcrest.core.AnyOf.anyOf; 15 | 16 | import static org.junit.Assert.assertThat; 17 | 18 | import java.io.InputStream; 19 | import java.util.HashMap; 20 | import java.util.HashSet; 21 | import java.util.Map; 22 | import java.util.regex.Matcher; 23 | import java.util.regex.Pattern; 24 | 25 | import org.apache.commons.io.IOUtils; 26 | import org.junit.Ignore; 27 | import org.junit.Test; 28 | 29 | public class PropertiesTest { 30 | 31 | private static final Utils utils = Utils.getInstance(); 32 | private final static String propertiesFileName = "application.properties"; 33 | private static String result = null; 34 | private static Map properties = new HashMap<>(); 35 | private static Object[] definedProperties = new Object[] { "chromeDriverPath", 36 | "firefoxBrowserPath" }; 37 | 38 | @SuppressWarnings("static-access") 39 | @Test 40 | public void readPropertyTest() { 41 | result = utils.readProperty("chromeDriverPath"); 42 | // result will be empty: 43 | // `Utils.readProperty` will scan properties file in application 44 | // resource path build relative to target/test-classes 45 | assertThat(result, is(nullValue())); 46 | } 47 | 48 | @Test 49 | public void getResourcePathTest() { 50 | String resourcePath = utils.getResourcePath(propertiesFileName); 51 | properties = PropertiesParser.getProperties(resourcePath); 52 | assertThat(properties, notNullValue()); 53 | assertThat(properties.keySet().size(), greaterThan(1)); 54 | 55 | assertThat(new HashSet(properties.keySet()), 56 | hasItems(definedProperties)); 57 | /* 58 | Expected: (a collection containing "missing property") 59 | but: a collection containing "missing property" 60 | was "password", 61 | was "edgeDriverPath", 62 | was "ieDriverPath", 63 | was "firefoxBrowserPath", 64 | was "chromeDriverPath", was "geckoDriverPath", 65 | was "username" 66 | */ 67 | } 68 | 69 | @Test 70 | public void getResourceStreamTest() { 71 | utils.setDebug(true); 72 | result = utils.getScriptContent(propertiesFileName); 73 | assertThat(result, containsString("chromeDriverPath")); 74 | } 75 | 76 | // @Ignore 77 | // https://www.baeldung.com/junit-assert-exception 78 | @Test(expected = NullPointerException.class) 79 | public void failingResourceStreamTest() { 80 | utils.setDebug(true); 81 | result = utils.getScriptContent( 82 | String.format("src/main/resources/%s", propertiesFileName)); 83 | assertThat(result, is(nullValue())); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/EscapeUtilTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import static org.hamcrest.CoreMatchers.equalTo; 7 | import static org.hamcrest.CoreMatchers.is; 8 | import static org.hamcrest.CoreMatchers.notNullValue; 9 | import static org.hamcrest.Matchers.hasEntry; 10 | import static org.hamcrest.Matchers.hasItems; 11 | import static org.junit.Assert.assertFalse; 12 | import static org.junit.Assert.assertThat; 13 | import static org.junit.Assert.assertTrue; 14 | 15 | import java.lang.reflect.InvocationTargetException; 16 | import java.lang.reflect.Method; 17 | import java.util.ArrayList; 18 | import java.util.Arrays; 19 | import java.util.Collections; 20 | import java.util.Date; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.Optional; 25 | import java.util.concurrent.TimeUnit; 26 | import java.util.stream.Collectors; 27 | 28 | import org.hamcrest.Matchers; 29 | import org.junit.After; 30 | import org.junit.AfterClass; 31 | import org.junit.Before; 32 | import org.junit.BeforeClass; 33 | import org.junit.Ignore; 34 | import org.junit.Test; 35 | import org.openqa.selenium.Alert; 36 | import org.openqa.selenium.By; 37 | import org.openqa.selenium.WebDriver; 38 | import org.openqa.selenium.WebElement; 39 | import org.openqa.selenium.interactions.Actions; 40 | import org.openqa.selenium.support.ui.ExpectedConditions; 41 | import org.openqa.selenium.support.ui.WebDriverWait; 42 | import org.openqa.selenium.NoSuchElementException; 43 | 44 | import com.github.sergueik.swet.Utils; 45 | 46 | @SuppressWarnings("deprecation") 47 | public class EscapeUtilTest { 48 | 49 | private static String osName = OSUtils.getOsName(); 50 | private Utils utils = Utils.getInstance(); 51 | 52 | @BeforeClass 53 | public static void beforeClassMethod() { 54 | } 55 | 56 | @Before 57 | public void loadBaseURL() { 58 | utils.setDebug(true); 59 | } 60 | 61 | // @Ignore 62 | @Test 63 | public void testBasicXMLEscape() { 64 | String data = ""; 65 | String escapedData = utils.escape(data); 66 | assertFalse(escapedData.isEmpty()); 67 | assertFalse(escapedData.matches("&(?:<|>|\"|');")); 68 | // NOTE: negative lookahead 69 | assertFalse(escapedData.matches("&(?!lt|gt|amp|quot|apos|#x);")); 70 | System.err.println("Validated : " + escapedData); 71 | } 72 | 73 | @Test 74 | public void testCodePointEscape() { 75 | // Create 2 char primitives 76 | char ch1 = '\ud800'; 77 | char ch2 = '\udc00'; 78 | String data = "" + Character.toString(ch1) + Character.toString(ch2) 79 | + ""; 80 | 81 | // assign code point value of surrogate pair ch1, ch2 to cp 82 | int codePoint = Character.toCodePoint(ch1, ch2); 83 | // Print code point value of surrogate pair ch1, ch2 84 | System.err.println( 85 | String.format("Supplementary code point value is 0x%08X", codePoint)); 86 | String escapedData = utils.escape(data); 87 | // NOTE: pad the same way, usual format is the "0x%08X" 88 | assertTrue(escapedData.matches( 89 | String.format("^.*(?:%s).*$", String.format("&#x%05X", codePoint)))); 90 | System.err.println("Validated : " + escapedData); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/BatchPipeRun.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.OutputStream; 8 | import java.io.PrintWriter; 9 | import java.time.LocalDate; 10 | import java.time.format.DateTimeFormatter; 11 | 12 | /** 13 | * Selected test scenarios for Selenium WebDriver 14 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 15 | */ 16 | 17 | // based on: 18 | // https://qna.habr.com/q/704745 19 | 20 | public class BatchPipeRun { 21 | 22 | public static void main(String[] args) 23 | throws IOException, InterruptedException { 24 | LocalDate futureDate = LocalDate.now().plusMonths(12); 25 | String formattedDate = futureDate 26 | .format(DateTimeFormatter.ofPattern("yyyyMMdd")); 27 | String serialNumber = "foo"; 28 | String keyName = "bar"; 29 | String command = "c:\\Users\\Serguei\\echoargs.cmd " + serialNumber + " " 30 | + keyName + " " + formattedDate + " 2>&1"; 31 | System.err.println("Exit code:" + runWithPipes(command)); 32 | } 33 | 34 | public static String runWithPipes(String command) 35 | throws IOException, InterruptedException { 36 | String[] shell = { "cmd.exe", }; 37 | Process process = Runtime.getRuntime().exec(shell); 38 | // this code allows seeing the child process on the console 39 | new Thread(new SyncPipe(process.getErrorStream(), System.err)).start(); 40 | new Thread(new SyncPipe(process.getInputStream(), System.out)).start(); 41 | 42 | PrintWriter stdinPrintWriter = new PrintWriter(process.getOutputStream()); 43 | stdinPrintWriter.println(command); 44 | stdinPrintWriter.close(); 45 | 46 | BufferedReader stdoutBufferedReader = new BufferedReader( 47 | new InputStreamReader(process.getInputStream())); 48 | 49 | BufferedReader stderrBufferedReader = new BufferedReader( 50 | new InputStreamReader(process.getErrorStream())); 51 | String line = null; 52 | 53 | StringBuffer processOutput = new StringBuffer(); 54 | while ((line = stdoutBufferedReader.readLine()) != null) { 55 | processOutput.append(line); 56 | // add a platform-independent newline 57 | processOutput.append(System.getProperty("line.separator")); 58 | } 59 | StringBuffer processError = new StringBuffer(); 60 | while ((line = stderrBufferedReader.readLine()) != null) { 61 | processError.append(line); 62 | processError.append(String.format("%n")); 63 | } 64 | System.err.println("OUTPUT:" + processOutput.toString()); 65 | System.err.println("ERROR :" + processError.toString()); 66 | String exitCode = Integer.toString(process.waitFor()); 67 | return exitCode; 68 | } 69 | 70 | private static class SyncPipe implements Runnable { 71 | private final OutputStream outputStream; 72 | private final InputStream intputStream; 73 | 74 | public SyncPipe(InputStream intputStream, OutputStream outputStream) { 75 | this.intputStream = intputStream; 76 | this.outputStream = outputStream; 77 | 78 | } 79 | 80 | public void run() { 81 | try { 82 | final byte[] buffer = new byte[1024]; 83 | for (int length = 0; (length = this.intputStream.read(buffer)) != -1;) { 84 | this.outputStream.write(buffer, 0, length); 85 | } 86 | } catch (IOException e) { 87 | e.printStackTrace(); 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # set -x 3 | 4 | which xmllint > /dev/null 5 | 6 | if [ $? -ne 0 ] ; then 7 | echo 'Missing xmllint' 8 | # use bash scripting to extract project attributes 9 | # see run2.sh for the implemtnation. 10 | # NOTE: very slow 11 | exit 1 12 | fi 13 | 14 | echo 'Loading parameters from the project "pom.xml"' 15 | 16 | if [ -z "${APP_VERSION}" ] 17 | then 18 | APP_VERSION=$(xmllint -xpath "/*[local-name() = 'project' ]/*[local-name() = 'version' ]/text()" pom.xml) 19 | else 20 | echo "Using provided APP_VERSION=${APP_VERSION}" 21 | fi 22 | if [ -z "${PACKAGE}" ] 23 | then 24 | PACKAGE=$(xmllint -xpath "/*[local-name() = 'project' ]/*[local-name() = 'groupId' ]/text()" pom.xml) 25 | fi 26 | if [ -z "${APP_NAME}" ] 27 | then 28 | APP_NAME=$(xmllint -xpath "/*[local-name() = 'project' ]/*[local-name() = 'artifactId' ]/text()" pom.xml) 29 | fi 30 | if [ -z "${DEFAULT_MAIN_CLASS}" ] 31 | then 32 | DEFAULT_MAIN_CLASS=$(xmllint -xpath "/*[local-name() = 'project' ]/*[local-name() = 'properties' ]/*[local-name() = 'mainClass']/text()" pom.xml) 33 | fi 34 | MAIN_CLASS=${1:-$DEFAULT_MAIN_CLASS} 35 | 36 | if [ -z "${SCM_CONNECTION}" ] 37 | then 38 | SCM_CONNECTION=$(xmllint -xpath "/*[local-name() = 'project' ]/*[local-name()='scm']/*[local-name() = 'connection']/text()" pom.xml | sed 's|scm:git://||') 39 | fi 40 | 41 | DOWNLOAD_EXTERNAL_JAR=false 42 | 43 | if [[ $DOWNLOAD_EXTERNAL_JAR ]] 44 | then 45 | ALIAS='opal' 46 | JARFILE_VERSION='1.0.4' 47 | JARFILE="$ALIAS-$JARFILE_VERSION.jar" 48 | URL="https://github.com/lcaron/${ALIAS}/blob/releases/V$JARFILE_VERSION/${ALIAS}-$JARFILE_VERSION.jar?raw=true" 49 | if [[ ! -f "src/main/resources/$JARFILE" ]] 50 | then 51 | pushd 'src/main/resources/' 52 | wget -O $JARFILE -nv $URL 53 | popd 54 | # https://ftp.mozilla.org/pub/firefox/releases/40.0.3/mac/en-US/ 55 | fi 56 | fi 57 | 58 | if $(uname -s | grep -qi 'Darwin') 59 | then 60 | 61 | # OSX-specific 62 | # https://www.java.com/en/download/help/version_manual.xml 63 | JAVA_VERSION=$('/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java' -version 2>& 1| sed -n 's|^.*"\(.*\)\".*$|\1|p') 64 | if [ -z $JAVA_VERSION} ]; then 65 | JAVA_VERSION='1.8.0_121' 66 | fi 67 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk$JAVA_VERSION.jdk/Contents/Home 68 | 69 | # NOTE: No uniform way to query OSX for the installed maven version 70 | # If Maven is installed to 'Applications' need to adjust the command line to: "mdfind -onlyin '/Applications' -name mvn" 71 | M2=$(mdfind -onlyin "${HOME}/Downloads" -name mvn | sed -n 's|^\(.*\)/mvn$|\1|p'|head -1) 72 | 73 | if [ -z $M2 ] ; then 74 | MAVEN_VERSION='3.6.1' 75 | export M2_HOME="$HOME/Downloads/apache-maven-$MAVEN_VERSION" 76 | export M2="$M2_HOME/bin" 77 | else 78 | export M2 79 | export M2_HOME=$(echo $M2| sed 's|/bin||') 80 | fi 81 | export MAVEN_OPTS='-Xms256m -Xmx512m' 82 | export PATH=$M2_HOME/bin:$PATH 83 | # http://stackoverflow.com/questions/3976342/running-swt-based-cross-platform-jar-properly-on-a-mac 84 | LAUNCH_OPTS='-XstartOnFirstThread' 85 | fi 86 | if [[ $SKIP_BUILD != 'true' ]] ; then 87 | mvn -Dmaven.test.skip=true package install 88 | fi 89 | echo "java $LAUNCH_OPTS -cp target/$APP_NAME-$APP_VERSION.jar:target/lib/* $PACKAGE.$MAIN_CLASS" $* 90 | java $LAUNCH_OPTS -cp target/$APP_NAME-$APP_VERSION.jar:target/lib/* $PACKAGE.$MAIN_CLASS $* 91 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/WriteScriptFileTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import java.io.File; 7 | import java.io.FileNotFoundException; 8 | import java.io.FileReader; 9 | 10 | import org.junit.AfterClass; 11 | import org.junit.BeforeClass; 12 | import org.junit.Test; 13 | 14 | import com.google.gson.Gson; 15 | 16 | import com.github.sergueik.swet.WriteScriptFile; 17 | import com.github.sergueik.swet.Utils; 18 | import com.github.sergueik.swet.OSUtils; 19 | 20 | public class WriteScriptFileTest { 21 | 22 | private static String scriptsPath; 23 | private static Gson gson; 24 | private static String resourcePath; 25 | private static Utils utils = Utils.getInstance(); 26 | 27 | @BeforeClass 28 | public static void Setup() { 29 | resourcePath = utils.getResourcePath("sampleTest.json"); 30 | gson = new Gson(); 31 | scriptsPath = System.getProperty("user.dir") + File.separator + "scripts"; 32 | File scriptsDirectory = new File(scriptsPath); 33 | if (!scriptsDirectory.exists()) { 34 | if (scriptsDirectory.mkdir()) { 35 | } else { 36 | System.out.println("Failed to create directory: " + scriptsPath); 37 | } 38 | } 39 | } 40 | 41 | // cleanup generated test sources 42 | // TODO: error detection 43 | @AfterClass 44 | public static void Cleanup() { 45 | /* 46 | try { 47 | FileUtils.deleteDirectory(new File(scriptsPath)); 48 | } catch (IOException e) { 49 | } 50 | */ 51 | } 52 | 53 | @Test 54 | public void writeTestScript() throws FileNotFoundException { 55 | // Warning: places generated sources into the working girectory 56 | WriteScriptFile writeScriptFile = new WriteScriptFile(resourcePath); 57 | writeScriptFile.generateTestScripts(scriptsPath); 58 | } 59 | 60 | @Test 61 | public void dumplJSon() throws FileNotFoundException { 62 | WriteScriptFile.AI_Parser parser = new WriteScriptFile.AI_Parser( 63 | resourcePath); 64 | parser.printTestSuiteDetails(); 65 | } 66 | 67 | @Test 68 | public void dumpRawJSon() throws FileNotFoundException { 69 | 70 | WriteScriptFile.TestParamsDTO params = gson.fromJson( 71 | new FileReader(resourcePath), WriteScriptFile.TestParamsDTO.class); 72 | 73 | System.out.println(params.getBrowser()); 74 | System.out.println(params.getURL()); 75 | System.out.println(params.getTestsuite().getName()); 76 | System.out.println( 77 | "Number of testcases: " + params.getTestsuite().getTestcase().length); 78 | System.out.println(params.getTestsuite().getTestcase()[0].getName()); 79 | System.out.println("Number of test steps of testcase 1: " 80 | + params.getTestsuite().getTestcase()[0].getStep().length); 81 | System.out.println(String.format("Step 1 name: \"%s\"", 82 | params.getTestsuite().getTestcase()[0].getStep()[0].getName())); 83 | System.out.println(String.format("Step 1 action: \"%s\"", 84 | params.getTestsuite().getTestcase()[0].getStep()[0].getAction())); 85 | System.out 86 | .println(String.format("Step 1 locateElement selector type : \"%s\"", 87 | params.getTestsuite().getTestcase()[0].getStep()[0] 88 | .getLocateElement().getBy())); 89 | System.out 90 | .println(String.format("Step 1 locateElement selector value: \"%s\"", 91 | params.getTestsuite().getTestcase()[0].getStep()[0] 92 | .getLocateElement().getValue())); 93 | System.out.println(String.format("Step 1 extra param: \"%s\"", 94 | params.getTestsuite().getTestcase()[0].getStep()[0].getThirdPara())); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/custom/swt/widgets/ImageLabel.java: -------------------------------------------------------------------------------- 1 | package custom.swt.widgets; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.graphics.Image; 5 | import org.eclipse.swt.graphics.Point; 6 | import org.eclipse.swt.graphics.Rectangle; 7 | import org.eclipse.swt.widgets.Composite; 8 | import org.eclipse.swt.widgets.Label; 9 | 10 | public class ImageLabel extends Container { 11 | 12 | static final int hgap = 16; 13 | 14 | // no need since the label's.getImage() retrieves the image 15 | // private Image image; 16 | public final Label image; 17 | public final Label text; 18 | private int alignment = SWT.TOP; 19 | 20 | // ==[ Constructor 21 | // ]================================================================================= 22 | 23 | public ImageLabel(Composite parent, int style) { 24 | super(parent, style); 25 | 26 | // Children 27 | image = new Label(this, SWT.NONE); 28 | text = new Label(this, SWT.WRAP); 29 | 30 | } 31 | 32 | // ==[ Layout 33 | // ]====================================================================================== 34 | 35 | @Override 36 | protected Point onComputeSize(Composite composite, int wHint, int hHint, 37 | boolean flushCache) { 38 | // System.out.println("imageLabel.computeSize(" + wHint + "," + hHint + 39 | // ")"); 40 | Point imgPrefSize = image.computeSize(SWT.DEFAULT, SWT.DEFAULT); 41 | // System.out.println("\tImage Width: " + imgPrefSize.x); 42 | 43 | if (wHint != SWT.DEFAULT) 44 | wHint = Math.max(0, wHint - imgPrefSize.x - hgap); 45 | 46 | // System.out.println("\tReduced wHint: " + wHint); 47 | 48 | Point textPrefSize = text.computeSize(wHint, hHint); 49 | 50 | // System.out.println("\tImage Height: " + imgPrefSize.y); 51 | // System.out.println("\tText Height: " + textPrefSize.y); 52 | 53 | int height = Math.max(imgPrefSize.y, textPrefSize.y); 54 | int width = imgPrefSize.x + hgap + textPrefSize.x; 55 | 56 | // System.out.println("\t-> Result: " + width + "," + height); 57 | 58 | return new Point(width, height); 59 | } 60 | 61 | @Override 62 | protected void onLayout(Composite composite, boolean flushCache) { 63 | 64 | Rectangle bounds = composite.getBounds(); 65 | 66 | Point imgPrefSize = image.computeSize(SWT.DEFAULT, bounds.height); 67 | Point textPrefSize = text.computeSize(bounds.width - imgPrefSize.x, 68 | SWT.DEFAULT); 69 | 70 | int y = 0; 71 | if (alignment == SWT.CENTER) 72 | y = (bounds.height - textPrefSize.y) / 2; 73 | else if (alignment == SWT.BOTTOM) 74 | y = bounds.height - textPrefSize.y; 75 | 76 | image.setBounds(0, 0, imgPrefSize.x, imgPrefSize.y); 77 | text.setBounds(imgPrefSize.x + hgap, y, textPrefSize.x, textPrefSize.y); 78 | 79 | } 80 | 81 | // ==[ Getter & Setter 82 | // ]============================================================================= 83 | 84 | // public Label getImageLabel() { 85 | // return image; 86 | // } 87 | // 88 | // public Label getTextLabel() { 89 | // return text; 90 | // } 91 | 92 | public void setImage(Image newImage) { 93 | checkWidget(); 94 | // image = newImage; 95 | image.setImage(newImage); 96 | } 97 | 98 | public void setText(String content) { 99 | checkWidget(); 100 | text.setText(content); 101 | } 102 | 103 | public void setVerticalAlignment(int alignment) { 104 | checkWidget(); 105 | if (alignment != SWT.TOP && alignment != SWT.CENTER 106 | && alignment != SWT.BOTTOM) 107 | SWT.error(SWT.ERROR_INVALID_ARGUMENT); 108 | this.alignment = alignment; 109 | // TODO: locate and clone implementing class 110 | // requestLayout(); 111 | } 112 | 113 | } -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/BrowserDiscoveryTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2018 Serguei Kouzmine 4 | */ 5 | 6 | import static org.junit.Assert.assertFalse; 7 | import static org.junit.Assert.assertTrue; 8 | 9 | import java.io.IOException; 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import org.junit.Test; 17 | 18 | import com.github.sergueik.swet.OSUtils; 19 | import com.google.common.collect.Lists; 20 | 21 | public class BrowserDiscoveryTest { 22 | 23 | private static String osName = OSUtils.getOsName(); 24 | private static Map browserNames = new HashMap<>(); 25 | static { 26 | switch (osName) { 27 | case "windows": 28 | browserNames.put("chrome.exe", "Google Chrome"); 29 | browserNames.put("edge.exe", "Edge"); 30 | browserNames.put("iexplore.exe", "Internet Explorer"); 31 | browserNames.put("firefox.exe", "Mozilla Firefox"); 32 | browserNames.put("safari", "Safari"); 33 | break; 34 | case "linux": 35 | browserNames.put("google-chrome", "Google Chrome"); 36 | browserNames.put("firefox", "Mozilla Firefox"); 37 | // browserNames.put("chrome", "Google Chrome (wrong proces name)"); 38 | break; 39 | case "mac os x": 40 | browserNames.put("Google Chrome", "Google Chrome"); 41 | browserNames.put("Mozilla Firefox", "Mozilla Firefox"); 42 | browserNames.put("Safari", "Safari"); 43 | break; 44 | } 45 | } 46 | 47 | @Test 48 | public void testInstalledBrowserInformaation() { 49 | if (osName.equals("windows")) { 50 | List browsers = OSUtils.getInstalledBrowsers(); 51 | assertTrue(browsers.size() > 0); 52 | // System.err.println("Installed browsers: " + browsers); 53 | 54 | for (String browserName : browserNames.keySet()) { 55 | if (browsers.contains(browserName)) { 56 | assertTrue(OSUtils.isInstalled(browserName)); 57 | assertTrue(OSUtils.getMajorVersion(browserName) > 0); 58 | System.err.println(String.format("%s version: %s", browserNames.get(browserName), 59 | OSUtils.getVersion(browserName))); 60 | } else { 61 | assertFalse(OSUtils.isInstalled(browserName)); 62 | assertTrue(OSUtils.getMajorVersion(browserName) == 0); 63 | } 64 | } 65 | } 66 | if (osName.equals("mac os x")) { 67 | List browsers = new ArrayList(browserNames.keySet()); 68 | for (String browserName : browsers) { 69 | if ( !OSUtils.findAppInPath(browserName) ) { 70 | System.err.println( 71 | String.format("Broser not installed: %s", browserName)); 72 | } else { 73 | System.err.println("Found browser: " + browserNames.get(browserName)); 74 | 75 | } 76 | } 77 | } 78 | if (osName.equals("linux")) { 79 | List browsers = new ArrayList(browserNames.keySet()); 80 | for (String browserName : browsers) { 81 | String command = "/usr/bin/which " + browserName; 82 | Runtime runtime = Runtime.getRuntime(); 83 | Process process; 84 | try { 85 | process = runtime.exec(command); 86 | int exitCode = process.waitFor(); 87 | if (exitCode != 0) { 88 | System.err.println( 89 | String.format("Process exit code: %d for browser process %s", exitCode, browserName)); 90 | } else { 91 | System.err.println("Found browser: " + browserNames.get(browserName)); 92 | 93 | } 94 | } catch (IOException | InterruptedException e) { 95 | System.err.println("Exception (ignnord): " + e.getMessage()); 96 | } 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/custom/swt/widgets/MultilineButton.java: -------------------------------------------------------------------------------- 1 | package custom.swt.widgets; 2 | 3 | import org.eclipse.jface.resource.FontDescriptor; 4 | import org.eclipse.jface.resource.ResourceManager; 5 | import org.eclipse.swt.SWT; 6 | import org.eclipse.swt.events.SelectionEvent; 7 | import org.eclipse.swt.events.SelectionListener; 8 | import org.eclipse.swt.graphics.GC; 9 | import org.eclipse.swt.graphics.Point; 10 | import org.eclipse.swt.layout.FillLayout; 11 | import org.eclipse.swt.layout.GridData; 12 | import org.eclipse.swt.widgets.Button; 13 | import org.eclipse.swt.widgets.Composite; 14 | import org.eclipse.swt.widgets.Display; 15 | import org.eclipse.swt.widgets.Shell; 16 | import org.eclipse.swt.graphics.Color; 17 | import org.eclipse.swt.graphics.Font; 18 | import org.eclipse.swt.graphics.FontData; 19 | import org.eclipse.swt.graphics.TextLayout; 20 | import org.eclipse.swt.graphics.TextStyle; 21 | 22 | // origin: https://raw.githubusercontent.com/dfuchss/swt-utils/master/src/main/java/org/fuchss/swt/widgets/MultilineButton.java 23 | public class MultilineButton extends Button { 24 | 25 | public MultilineButton(Composite parent, int style) { 26 | super(parent, style | SWT.WRAP | SWT.PUSH | SWT.LEFT); 27 | // wrong layout class 28 | // this.setLayoutData( 29 | // new GridData(SWT.WRAP | SWT.PUSH | SWT.LEFT, SWT.LEFT, true, false)); 30 | } 31 | 32 | // Disable the check that prevents subclassing of SWT components 33 | @Override 34 | protected final void checkSubclass() { 35 | } 36 | 37 | @Override 38 | public Point computeSize(int wHint, int hHint, boolean changed) { 39 | Point size = super.computeSize(wHint, hHint, changed); 40 | GC gc = new GC(this); 41 | 42 | String text = this.getText(); 43 | Point mlSize = gc.textExtent(text, SWT.DRAW_DELIMITER | SWT.LEFT); 44 | Point simpleSize = gc.textExtent(text.replace('\n', ' ')); 45 | 46 | gc.dispose(); 47 | 48 | size.x -= simpleSize.x - mlSize.x; 49 | size.y += mlSize.y - simpleSize.y; 50 | 51 | return size; 52 | } 53 | 54 | // origin: 55 | // https://www.programcreek.com/java-api-examples/org.eclipse.swt.graphics.Font 56 | private Font createFont(final ResourceManager resourceManager) { 57 | final Font defaultFont = resourceManager.getDevice().getSystemFont(); 58 | 59 | if (defaultFont == null) { 60 | return null; 61 | } 62 | 63 | final FontData fd[] = FontDescriptor.copy(defaultFont.getFontData()); 64 | if (fd == null) { 65 | return null; 66 | } 67 | 68 | for (final FontData f : fd) { 69 | if (this.fontSize > 0) { 70 | f.setHeight(this.fontSize); 71 | } 72 | } 73 | return resourceManager.createFont(FontDescriptor.createFrom(fd)); 74 | } 75 | 76 | private final static int fontSize = 9; 77 | 78 | // testing the widget 79 | 80 | private static Shell shell; 81 | static Display display = new Display(); 82 | 83 | private final static int formWidth = 250; 84 | private final static int formHeight = 120; 85 | 86 | public static void main(String[] args) { 87 | shell = new Shell(display); 88 | shell.setLayout(new FillLayout()); 89 | 90 | final MultilineButton button = new MultilineButton(shell, SWT.PUSH); // NONE? 91 | // TODO: display.getSystemFont() 92 | Font font = new Font(display, "Helvetica", 9, SWT.NORMAL); 93 | // https://www.programcreek.com/java-api-examples/?class=org.eclipse.swt.SWT&method=LEFT 94 | button.setFont(font); 95 | button.addSelectionListener(new SelectionListener() { 96 | // required 97 | public void widgetDefaultSelected(SelectionEvent e) { 98 | } 99 | 100 | // required 101 | public void widgetSelected(SelectionEvent e) { 102 | // TODO: close Shell 103 | shell.dispose(); 104 | } 105 | }); 106 | button.setText("start\ncontinue\nmore action\nfinishing\nfinished"); 107 | shell.pack(); 108 | shell.setSize(formWidth, formHeight); 109 | 110 | shell.open(); 111 | while (!shell.isDisposed()) { // Event loop. 112 | if (!display.readAndDispatch()) 113 | display.sleep(); 114 | } 115 | display.dispose(); 116 | } 117 | } -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/TestConfigurationParserTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import java.lang.reflect.Array; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Set; 12 | 13 | import static org.junit.Assert.*; 14 | // import static org.hamcrest.CoreMatchers.*; 15 | // NOTE: a need to switch to hamcrest-all.jar and Matchers 16 | // just for resolving method 'containsInAnyOrder' 17 | import static org.hamcrest.Matchers.*; 18 | 19 | import static org.junit.Assert.assertThat; 20 | import static org.hamcrest.core.AnyOf.anyOf; 21 | import static org.hamcrest.CoreMatchers.is; 22 | import static org.hamcrest.CoreMatchers.containsString; 23 | 24 | import org.junit.After; 25 | import org.junit.AfterClass; 26 | import org.junit.Before; 27 | import org.junit.BeforeClass; 28 | import org.junit.Ignore; 29 | import org.junit.Test; 30 | 31 | import com.github.sergueik.swet.TestConfigurationParser; 32 | 33 | public class TestConfigurationParserTest { 34 | /** 35 | * Testing of the Selenium WebDriver Elementor Tool (SWET) Configuration table helper 36 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 37 | */ 38 | 39 | private static boolean skipHeaders = true; 40 | private static String defaultConfig = "test.configuration"; 41 | private static String configuPath = String.format("%s/src/main/resources/%s", 42 | System.getProperty("user.dir"), defaultConfig); 43 | private static List result = new ArrayList<>(); 44 | private static Object[] expected = new Object[] { "A1", "A2", "A3", "B1", 45 | "B2", "B3", "C1", "C2", "C3", "D1", "D2", "D3" /* , "E1" */ }; 46 | 47 | @BeforeClass 48 | public static void beforeSuiteMethod() throws Exception { 49 | result = flatten(TestConfigurationParser.getConfiguration(configuPath)); 50 | } 51 | 52 | // @Ignore 53 | @Test 54 | public void junitBuiltIArrayTest() { 55 | assertArrayEquals(expected, result.toArray()); 56 | } 57 | 58 | // @Ignore 59 | @Test 60 | public void orderInsensitiveTest() { 61 | // NOTE: would fail 62 | Set dataSet = new HashSet(Arrays.asList(expected)); 63 | assertTrue(new HashSet(result).containsAll(dataSet)); 64 | } 65 | 66 | // @Ignore 67 | @Test 68 | public void orderSensitiveTest() { 69 | // order-sensitive 70 | assertThat(result.toArray(), is(expected)); 71 | } 72 | 73 | @Test 74 | public void iterateAnyOfTest() { 75 | // origin: https://github.com/junit-team/junit4/blob/master/src/test/java/org/junit/experimental/categories/CategoryTest.java 76 | // see also: https://www.programcreek.com/java-api-examples/index.php?api=org.hamcrest.core.AnyOf 77 | for (Object resultItem : result) { 78 | // this expectation tailored to small sets 79 | // http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/core/AnyOf.html 80 | // will be failing with 81 | // Expected: (is "A1" or is "A2" or is "A3" or is "B1" or is "B2" or is 82 | // "B3") 83 | // but: was "C1" 84 | assertThat(resultItem, anyOf(is(expected[0]), is(expected[1]), 85 | is(expected[2]), is(expected[3]), is(expected[4]), is(expected[5]))); 86 | } 87 | } 88 | 89 | // https://www.javaworld.com/article/2074689/core-java/hamcrest-containing-matchers.html 90 | // @Ignore 91 | @Test 92 | public void hasItemsTest() { 93 | assertThat(new HashSet(result), hasItems(expected)); 94 | } 95 | 96 | // @Ignore 97 | // https://www.javaworld.com/article/2074689/core-java/hamcrest-containing-matchers.html 98 | @Test 99 | public void containsInAnyOrderTest() { 100 | assertThat(new HashSet(result), containsInAnyOrder(expected)); 101 | } 102 | 103 | // https://stackoverflow.com/questions/40186270/java-flatten-an-array-using-recursion 104 | private static List flatten(Object input) { 105 | List result = new ArrayList(); 106 | if (input.getClass().isArray()) { 107 | for (int pos = 0; pos < Array.getLength(input); pos++) { 108 | result.addAll(flatten(Array.get(input, pos))); 109 | } 110 | } else if (input instanceof List) { 111 | for (Object element : (List) input) { 112 | result.addAll(flatten(element)); 113 | } 114 | } else { 115 | result.add(input); 116 | } 117 | return result; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/AWTTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | import java.awt.AWTException; 4 | import java.awt.Robot; 5 | import java.awt.event.KeyEvent; 6 | import java.io.*; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | 12 | import org.junit.After; 13 | import org.junit.BeforeClass; 14 | import org.junit.Ignore; 15 | import org.junit.Test; 16 | 17 | public class AWTTest { 18 | 19 | private final static String command = "notepad.exe"; 20 | // Create an instance of Robot class 21 | private final static Runtime runtime = Runtime.getRuntime(); 22 | private static Robot robot = null; 23 | private static final int delay2 = 30; 24 | private static final int delay = 100; 25 | private static final int launchDelay = 5000; 26 | // low-level event is generated by a component object ( 27 | private static int[] rawKeys = { KeyEvent.VK_H, KeyEvent.VK_E, KeyEvent.VK_L, 28 | KeyEvent.VK_L, KeyEvent.VK_O, KeyEvent.VK_SPACE, }; 29 | 30 | @BeforeClass 31 | public static void load() throws IOException { 32 | runtime.exec(command); 33 | sleep(launchDelay); 34 | try { 35 | robot = new Robot(); 36 | } catch (AWTException e) { 37 | // TODO Auto-generated catch block 38 | e.printStackTrace(); 39 | } 40 | } 41 | 42 | @After 43 | public void writeNewLine() { 44 | robot.keyPress(KeyEvent.VK_ENTER); 45 | } 46 | 47 | @Ignore 48 | @Test 49 | public void basicTest() throws AWTException, InterruptedException { 50 | 51 | for (int cnt = 0; cnt != rawKeys.length; cnt++) { 52 | robot.keyPress(rawKeys[cnt]); 53 | Thread.sleep(delay); 54 | } 55 | writeString("Hello AWT!"); 56 | } 57 | 58 | // @Ignore 59 | @Test 60 | public void writeStringTest() { 61 | writeString("Hello AWT!"); 62 | robot.keyPress(KeyEvent.VK_ENTER); 63 | writeString("Hello again AWT!"); 64 | robot.keyPress(KeyEvent.VK_ENTER); 65 | writeString(",-./0123456789;=ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 66 | // prints 67 | // -.0123456789=ФИСВУАПРШОЛДЬТЩЗЙКЫЕГМЦЧНЯфисвуапршолдьтщзйкыегмцчня\0123456789-. 68 | robot.keyPress(KeyEvent.VK_ENTER); 69 | writeString("abcdefghijklmnopqrstuvwxyz[\\]0123456789*+-./"); 70 | // prints 71 | // -.0123456789=ФИСВУАПРШОЛДЬТЩЗЙКЫЕГМЦЧНЯфисвуапршолдьтщзйкыегмцчня\0123456789-. 72 | robot.keyPress(KeyEvent.VK_ENTER); 73 | writeString( 74 | ",-./0123456789;=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[\\]0123456789*+-./"); 75 | // prints 76 | // -.0123456789=ФИСВУАПРШОЛДЬТЩЗЙКЫЕГМЦЧНЯфисвуапршолдьтщзйкыегмцчня\0123456789-. 77 | } 78 | 79 | @Ignore 80 | @Test 81 | public void printAllCharactersTest() { 82 | 83 | // print range of character codes brute force 84 | for (int code = 17; code < 128; code++) { 85 | try { 86 | robot.keyPress(code); 87 | robot.delay(delay); 88 | robot.keyRelease(code); 89 | } catch (IllegalArgumentException e) { 90 | System.err.println( 91 | "Failed to press " + code + " " + KeyEvent.getKeyText(code)); 92 | // Failed to press 91 Open Bracket 93 | // Failed to press 93 Close Bracket 94 | // Failed to press 44 Comma 95 | // Failed to press 47 Slash 96 | } 97 | } 98 | } 99 | 100 | public static void sleep(Integer milliSeconds) { 101 | try { 102 | Thread.sleep((long) milliSeconds); 103 | } catch (InterruptedException e) { 104 | e.printStackTrace(); 105 | } 106 | } 107 | 108 | private void writeString(String s) { 109 | for (int code = 0; code < s.length(); code++) { 110 | char character = s.charAt(code); 111 | if (Character.isUpperCase(character)) { 112 | robot.keyPress(KeyEvent.VK_SHIFT); 113 | } 114 | try { 115 | System.err.println("Pressing " + character); 116 | robot.keyPress(character); 117 | sleep(delay2); 118 | System.err.println("Releasing " + character); 119 | robot.keyRelease(character); 120 | // https://stackoverflow.com/questions/29665534/type-a-string-using-java-awt-robots 121 | // robot.keyPress(KeyEvent.getExtendedKeyCodeForChar((int) character)); 122 | // 123 | } catch (IllegalArgumentException e) { 124 | System.err.println( 125 | "Failed to press " + code + " " + KeyEvent.getKeyText(code)); 126 | // 127 | } 128 | if (Character.isUpperCase(character)) { 129 | robot.keyRelease(KeyEvent.VK_SHIFT); 130 | } 131 | } 132 | robot.delay(delay); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/OSUtilsAndWinRegistryTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import static org.junit.Assert.assertArrayEquals; 7 | import static org.junit.Assert.assertTrue; 8 | import static org.junit.Assert.assertThat; 9 | 10 | import static org.hamcrest.CoreMatchers.containsString; 11 | import static org.hamcrest.Matchers.greaterThan; 12 | import static org.hamcrest.Matchers.equalTo; 13 | 14 | import java.lang.reflect.InvocationTargetException; 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.HashMap; 18 | import java.util.HashSet; 19 | import java.util.List; 20 | import java.util.Map; 21 | import java.util.Optional; 22 | import java.util.Set; 23 | 24 | import org.junit.Before; 25 | import org.junit.BeforeClass; 26 | import org.junit.Ignore; 27 | import org.junit.Test; 28 | 29 | import org.json.JSONArray; 30 | import org.json.JSONException; 31 | import org.json.JSONObject; 32 | 33 | import java.util.UUID; 34 | 35 | import static org.hamcrest.CoreMatchers.notNullValue; 36 | import static org.hamcrest.core.AnyOf.anyOf; 37 | 38 | import com.google.gson.Gson; 39 | import com.google.gson.GsonBuilder; 40 | 41 | import com.github.sergueik.swet.Utils; 42 | import com.github.sergueik.swet.OSUtils; 43 | 44 | @SuppressWarnings("deprecation") 45 | public class OSUtilsAndWinRegistryTest { 46 | 47 | private static Utils utils = Utils.getInstance(); 48 | private static String result = null; 49 | private static final boolean debug = true; 50 | 51 | @BeforeClass 52 | public static void beforeSuiteMethod() throws Exception { 53 | 54 | } 55 | 56 | @Before 57 | public void before() { 58 | } 59 | 60 | @Test 61 | public void registryReadBrowsersTest() { 62 | List browsers = OSUtils.getInstalledBrowsers(); 63 | assertThat(browsers, notNullValue()); 64 | assertThat(browsers.size(), greaterThan(2)); 65 | if (debug) { 66 | System.err.println("Installed browsers: " + browsers.toString()); 67 | } 68 | } 69 | 70 | @Test 71 | public void registryReadZoomTest() { 72 | int zoom = OSUtils.getZoom(); 73 | assertThat(zoom, notNullValue()); 74 | assertThat(zoom, anyOf(equalTo(100000), equalTo(80000), equalTo(-1))); 75 | // NOTE: possibly after a cold reboot: 76 | // Expected: <100000> 77 | // but: was <-1> 78 | // TODO: 79 | // "ResetZoomOnStartup2" 80 | // assertThat(zoom, anyOf(equalTo(1), equalTo(-1))); 81 | 82 | if (debug) { 83 | System.err.println("Zoom: " + zoom); 84 | } 85 | } 86 | 87 | // based on: 88 | // https://answers.microsoft.com/en-us/ie/forum/all/ie-11-how-do-i-get-a-default-zoom-to-stick/19510f5a-c339-45d1-b74e-edc885ef5517 89 | @Test 90 | public void registryReadAdvancedOptionsZoomTest() { 91 | int zoom = OSUtils.getAdvancedOptionsZoom(); 92 | assertThat(zoom, notNullValue()); 93 | assertThat(zoom, equalTo(1)); 94 | if (debug) { 95 | System.err.println("Accesibility Zoom: " + zoom); 96 | } 97 | } 98 | 99 | @Ignore 100 | @Test 101 | public void registryWinRegistryReadAdvancedOptionsTest1() { 102 | String value = null; 103 | try { 104 | value = OSUtils.WinRegistry.readString( 105 | OSUtils.WinRegistry.HKEY_LOCAL_MACHINE, 106 | "SOFTWARE\\Microsoft\\Internet Explorer\\AdvancedOptions\\ACCESSIBILITY\\ZOOMLEVEL", 107 | "CheckedValue"); 108 | } catch (IllegalArgumentException | IllegalAccessException 109 | | InvocationTargetException e) { 110 | System.err.println("Exceptiion (ignored): " + e.toString()); 111 | } 112 | // assertThat(value, notNullValue()); 113 | // java.lang.NumberFormatException: null 114 | assertThat(Integer.parseInt(value), equalTo(1)); 115 | if (debug) { 116 | System.err.println("Accesibility Zoom CheckedValue: " + value); 117 | } 118 | 119 | } 120 | 121 | @Test 122 | public void registryWinRegistryReadAdvancedOptionsTest2() { 123 | String value = null; 124 | try { 125 | value = OSUtils.WinRegistry.readString( 126 | OSUtils.WinRegistry.HKEY_LOCAL_MACHINE, 127 | "SOFTWARE\\Microsoft\\Internet Explorer\\AdvancedOptions\\ACCESSIBILITY\\ZOOMLEVEL", 128 | "ValueName"); 129 | } catch (IllegalArgumentException | IllegalAccessException 130 | | InvocationTargetException e) { 131 | System.err.println("Exceptiion (ignored): " + e.toString()); 132 | } 133 | assertThat(value, notNullValue()); 134 | // assertThat(Integer.parseInt(value), equalTo(1)); 135 | if (debug) { 136 | System.err.println("Accesibility Zoom ValueName: " + value); 137 | } 138 | 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/SystemTrayEx.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import javax.swing.ImageIcon; 7 | 8 | import org.eclipse.swt.SWT; 9 | import org.eclipse.swt.events.SelectionAdapter; 10 | import org.eclipse.swt.events.SelectionEvent; 11 | import org.eclipse.swt.graphics.Image; 12 | import org.eclipse.swt.layout.RowLayout; 13 | import org.eclipse.swt.widgets.Display; 14 | import org.eclipse.swt.widgets.Event; 15 | import org.eclipse.swt.widgets.Listener; 16 | import org.eclipse.swt.widgets.Menu; 17 | import org.eclipse.swt.widgets.MenuItem; 18 | import org.eclipse.swt.widgets.Shell; 19 | import org.eclipse.swt.widgets.ToolTip; 20 | import org.eclipse.swt.widgets.Tray; 21 | import org.eclipse.swt.widgets.TrayItem; 22 | 23 | // origin: https://github.com/Vladimir-Novick/System-Tray 24 | //////////////////////////////////////////////////////////////////////////// 25 | // Copyright 2006, 2017 : Vladimir Novick https://www.linkedin.com/in/vladimirnovick/ 26 | // 27 | // https://github.com/Vladimir-Novick/System-Tray 28 | // 29 | // NO WARRANTIES ARE EXTENDED. USE AT YOUR OWN RISK. 30 | // 31 | // To contact the author with suggestions or comments, use :vlad.novick@gmail.com 32 | // 33 | //////////////////////////////////////////////////////////////////////////// 34 | 35 | public class SystemTrayEx { 36 | 37 | public SystemTrayEx() { 38 | super(); 39 | } 40 | 41 | private static TrayItem trayItem = null; 42 | 43 | private static Image imageStarted = null; 44 | private static Image imageStopped = null; 45 | 46 | /** Returns an ImageIcon, or null if the path was invalid. */ 47 | protected ImageIcon createImage(String path, String description) { 48 | java.net.URL imgURL = SystemTrayEx.class.getResource(path); 49 | if (imgURL != null) { 50 | return new ImageIcon(imgURL, description); 51 | } else { 52 | System.err.println("Couldn't find file: " + path); 53 | return null; 54 | } 55 | } 56 | 57 | /** 58 | * @param args 59 | */ 60 | public static void main(String[] args) { 61 | 62 | // ------------- 63 | Display display = new Display(); 64 | final Shell shell = new Shell(display); 65 | shell.setLayout(new RowLayout()); 66 | 67 | // ------------- 68 | 69 | final ToolTip tip = new ToolTip(shell, SWT.BALLOON | SWT.ICON_INFORMATION); 70 | tip.setMessage("SGcombo System Agent Goes Here!"); 71 | 72 | Tray tray = display.getSystemTray(); 73 | 74 | if (tray != null) { 75 | trayItem = new TrayItem(tray, SWT.NONE); 76 | trayItem.setImage(imageStarted); 77 | final Menu menu = new Menu(shell, SWT.POP_UP); 78 | 79 | MenuItem menuItem = new MenuItem(menu, SWT.PUSH); 80 | menuItem.setText("Stop Agent"); 81 | 82 | Image imagemenu = new Image(display, "./src/main/resources/images/stop.gif"); 83 | menuItem.setImage(imagemenu); 84 | 85 | menuItem.addSelectionListener(new SelectionAdapter() { 86 | public void widgetSelected(SelectionEvent event) { 87 | stopAgent(); 88 | } 89 | }); 90 | 91 | menuItem = new MenuItem(menu, SWT.PUSH); 92 | menuItem.setText("Start Agent"); 93 | imagemenu = new Image(display, "./src/main/resources/images/start.gif"); 94 | menuItem.setImage(imagemenu); 95 | 96 | menuItem.addSelectionListener(new SelectionAdapter() { 97 | public void widgetSelected(SelectionEvent event) { 98 | startAgent(); 99 | trayItem.setImage(imageStarted); 100 | } 101 | }); 102 | 103 | menuItem = new MenuItem(menu, SWT.PUSH); 104 | menuItem.setText("Show Status"); 105 | 106 | menuItem = new MenuItem(menu, SWT.PUSH); 107 | menuItem.setText("Shutdown"); 108 | 109 | menuItem.addSelectionListener(new SelectionAdapter() { 110 | 111 | public void widgetSelected(SelectionEvent event) { 112 | 113 | shell.close(); // calls dispose() - see note below 114 | 115 | } 116 | 117 | }); 118 | 119 | trayItem.addListener(SWT.MouseEnter, new Listener() { 120 | public void handleEvent(Event e) { 121 | tip.setVisible(true); 122 | } 123 | }); 124 | 125 | trayItem.addListener(SWT.MenuDetect, new Listener() { 126 | public void handleEvent(Event event) { 127 | menu.setVisible(true); 128 | } 129 | }); 130 | } 131 | 132 | shell.pack(); 133 | shell.open(); 134 | 135 | shell.setVisible(false); 136 | 137 | while (!shell.isDisposed()) { 138 | if (!display.readAndDispatch()) 139 | display.sleep(); 140 | } 141 | trayItem.dispose(); 142 | display.dispose(); 143 | 144 | } 145 | 146 | protected static void startAgent() { 147 | trayItem.setImage(imageStarted); 148 | } 149 | 150 | protected static void stopAgent() { 151 | trayItem.setImage(imageStopped); 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/JavaScanner.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | import java.util.Hashtable; 4 | 5 | /** 6 | * Token scanner for Selenium WebDriver Elementor Tool(SWET) 7 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.cm) 8 | */ 9 | 10 | public class JavaScanner { 11 | 12 | public static final int EOF = -1; 13 | public static final int EOL = 10; 14 | public static final int WORD = 0; 15 | public static final int WHITE = 1; 16 | public static final int KEY = 2; 17 | public static final int COMMENT = 3; 18 | public static final int STRING = 5; 19 | public static final int OTHER = 6; 20 | public static final int NUMBER = 7; 21 | public static final int MAXIMUM_TOKEN = 8; 22 | 23 | @SuppressWarnings("rawtypes") 24 | protected Hashtable fgKeys = null; 25 | protected StringBuffer fBuffer = new StringBuffer(); 26 | protected String fDoc; 27 | protected int fPos; 28 | protected int fEnd; 29 | protected int fStartToken; 30 | protected boolean fEofSeen = false; 31 | 32 | private String[] fgKeywords = { "abstract", "boolean", "break", "byte", 33 | "case", "catch", "char", "class", "continue", "default", "do", "double", 34 | "else", "extends", "false", "final", "finally", "float", "for", "if", 35 | "implements", "import", "instanceof", "int", "interface", "long", 36 | "native", "new", "null", "package", "private", "protected", "public", 37 | "return", "short", "static", "super", "switch", "synchronized", "this", 38 | "throw", "throws", "transient", "true", "try", "void", "volatile", 39 | "while" }; 40 | 41 | public JavaScanner() { 42 | initialize(); 43 | } 44 | 45 | /** 46 | * Returns the ending location of the current token in the document. 47 | */ 48 | public final int getLength() { 49 | return fPos - fStartToken; 50 | } 51 | 52 | /** 53 | * Initialize the lookup table. 54 | */ 55 | @SuppressWarnings({ "rawtypes", "unchecked" }) 56 | void initialize() { 57 | fgKeys = new Hashtable(); 58 | Integer k = new Integer(KEY); 59 | for (int i = 0; i < fgKeywords.length; i++) 60 | fgKeys.put(fgKeywords[i], k); 61 | } 62 | 63 | /** 64 | * Returns the starting location of the current token in the document. 65 | */ 66 | public final int getStartOffset() { 67 | return fStartToken; 68 | } 69 | 70 | /** 71 | * Returns the next lexical token in the document. 72 | */ 73 | public int nextToken() { 74 | int c; 75 | fStartToken = fPos; 76 | while (true) { 77 | switch (c = read()) { 78 | case EOF: 79 | return EOF; 80 | case '/': // comment 81 | c = read(); 82 | if (c == '/') { 83 | while (true) { 84 | c = read(); 85 | if ((c == EOF) || (c == EOL)) { 86 | unread(c); 87 | return COMMENT; 88 | } 89 | } 90 | } else { 91 | unread(c); 92 | } 93 | return OTHER; 94 | case '\'': // char const 95 | character: for (;;) { 96 | c = read(); 97 | switch (c) { 98 | case '\'': 99 | return STRING; 100 | case EOF: 101 | unread(c); 102 | return STRING; 103 | case '\\': 104 | c = read(); 105 | break; 106 | } 107 | } 108 | 109 | case '"': // string 110 | string: for (;;) { 111 | c = read(); 112 | switch (c) { 113 | case '"': 114 | return STRING; 115 | case EOF: 116 | unread(c); 117 | return STRING; 118 | case '\\': 119 | c = read(); 120 | break; 121 | } 122 | } 123 | 124 | case '0': 125 | case '1': 126 | case '2': 127 | case '3': 128 | case '4': 129 | case '5': 130 | case '6': 131 | case '7': 132 | case '8': 133 | case '9': 134 | do { 135 | c = read(); 136 | } while (Character.isDigit((char) c)); 137 | unread(c); 138 | return NUMBER; 139 | default: 140 | if (Character.isWhitespace((char) c)) { 141 | do { 142 | c = read(); 143 | } while (Character.isWhitespace((char) c)); 144 | unread(c); 145 | return WHITE; 146 | } 147 | if (Character.isJavaIdentifierStart((char) c)) { 148 | fBuffer.setLength(0); 149 | do { 150 | fBuffer.append((char) c); 151 | c = read(); 152 | } while (Character.isJavaIdentifierPart((char) c)); 153 | unread(c); 154 | Integer i = (Integer) fgKeys.get(fBuffer.toString()); 155 | if (i != null) 156 | return i.intValue(); 157 | return WORD; 158 | } 159 | return OTHER; 160 | } 161 | } 162 | } 163 | 164 | /** 165 | * Returns next character. 166 | */ 167 | protected int read() { 168 | if (fPos <= fEnd) { 169 | return fDoc.charAt(fPos++); 170 | } 171 | return EOF; 172 | } 173 | 174 | public void setRange(String text) { 175 | fDoc = text; 176 | fPos = 0; 177 | fEnd = fDoc.length() - 1; 178 | } 179 | 180 | protected void unread(int c) { 181 | if (c != EOF) 182 | fPos--; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/UtilExtensions.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import java.lang.reflect.Field; 7 | import java.lang.reflect.InvocationTargetException; 8 | 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Map.Entry; 14 | import java.util.Set; 15 | 16 | import org.json.JSONArray; 17 | import org.json.JSONException; 18 | import org.json.JSONObject; 19 | 20 | // generic JSONobject (de-)serializer 21 | // origin: https://www.codeproject.com/Tips/709552/Google-App-Engine-JAVA 22 | 23 | public class UtilExtensions { 24 | public static JSONObject getJsonObject(String payload) throws JSONException { 25 | JSONObject jsonObject = new JSONObject(payload); 26 | return jsonObject; 27 | } 28 | 29 | public static JSONArray getJsonArray(String payload) throws JSONException { 30 | JSONArray jsonArray = new JSONArray(payload); 31 | return jsonArray; 32 | } 33 | 34 | public static JSONObject modelToJSON(Model model, Mapper mapper) 35 | throws NoSuchFieldException, IllegalAccessException, JSONException, 36 | NoSuchMethodException, InvocationTargetException { 37 | JSONObject jsonObject = new JSONObject(); 38 | if (mapper.size() > 0) { 39 | for (@SuppressWarnings("rawtypes") 40 | Entry entry : mapper.getEntrySet()) { 41 | String value = entry.getValue().toString(); 42 | String key = entry.getKey().toString(); 43 | jsonObject.put(value, model.getProperty(key)); 44 | } 45 | return jsonObject; 46 | } else { 47 | for (String property : model.getProperties()) { 48 | jsonObject.put(property, model.getProperty(property)); 49 | } 50 | return jsonObject; 51 | } 52 | } 53 | 54 | public static JSONArray modelsToJSON( 55 | @SuppressWarnings("rawtypes") List models, Mapper mapper) 56 | throws IllegalAccessException, NoSuchFieldException, JSONException, 57 | NoSuchMethodException, InvocationTargetException { 58 | JSONArray jsonArray = new JSONArray(); 59 | for (Object model : models) { 60 | jsonArray.put(modelToJSON((Model) model, mapper)); 61 | } 62 | return jsonArray; 63 | } 64 | 65 | public static Model jsonObjectToModel(JSONObject jsonObject, 66 | @SuppressWarnings("rawtypes") Class model, Mapper mapper) 67 | throws IllegalAccessException, InstantiationException, JSONException, 68 | NoSuchFieldException { 69 | Model m = null; 70 | if (mapper.size() > 0) { 71 | m = (Model) model.newInstance(); 72 | for (@SuppressWarnings("rawtypes") 73 | Entry entry : mapper.getEntrySet()) { 74 | String value = entry.getValue().toString(); 75 | String key = entry.getKey().toString(); 76 | String jValue = jsonObject.get(value).toString(); 77 | m.setProperty(key, jValue); 78 | } 79 | return m; 80 | } else { 81 | m = (Model) model.newInstance(); 82 | for (String property : m.getProperties()) { 83 | String jValue = jsonObject.get(property).toString(); 84 | m.setProperty(property, jValue); 85 | } 86 | return m; 87 | } 88 | } 89 | 90 | public static List jsonArrayToModel(JSONArray jsonArray, 91 | @SuppressWarnings("rawtypes") Class model, Mapper mapper) 92 | throws JSONException, IllegalAccessException, NoSuchFieldException, 93 | InstantiationException { 94 | List list = new ArrayList<>(); 95 | int length = jsonArray.length(); 96 | for (int index = 0; index < length; index++) { 97 | list.add( 98 | jsonObjectToModel(jsonArray.getJSONObject(index), model, mapper)); 99 | } 100 | return list; 101 | } 102 | 103 | private static abstract class Mapper { 104 | 105 | protected Map mapper = new HashMap<>(); 106 | 107 | abstract public void init(); 108 | 109 | public Mapper() { 110 | init(); 111 | } 112 | 113 | public Set> getEntrySet() { 114 | return this.mapper.entrySet(); 115 | } 116 | 117 | public int size() { 118 | return this.mapper.size(); 119 | } 120 | 121 | public String get(String key) { 122 | return this.mapper.get(key); 123 | } 124 | 125 | } 126 | 127 | private static abstract class Model { 128 | 129 | abstract public String keyToString(); 130 | 131 | public List getProperties() { 132 | List list = new ArrayList<>(); 133 | for (Field field : this.getClass().getDeclaredFields()) { 134 | list.add(field.getName()); 135 | } 136 | return list; 137 | } 138 | 139 | public Object getProperty(String property) 140 | throws NoSuchFieldException, IllegalAccessException, 141 | NoSuchMethodException, InvocationTargetException { 142 | Field f = this.getClass().getDeclaredField(property); 143 | f.setAccessible(true); 144 | /* 145 | if (f.getType() == Key.class) { 146 | Method method = this.getClass().getDeclaredMethod("keyToString"); 147 | return method.invoke(this); 148 | } 149 | */ 150 | return f.get(this); 151 | } 152 | 153 | public void setProperty(String property, Object value) 154 | throws IllegalAccessException, NoSuchFieldException { 155 | Field f = this.getClass().getDeclaredField(property); 156 | f.setAccessible(true); 157 | f.set(this, value); 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /MouseEventDemo.java: -------------------------------------------------------------------------------- 1 | // origin: https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/uiswing/examples/events/MouseEventDemoProject/src/events/MouseEventDemo.java 2 | 3 | /* 4 | * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. 5 | */ 6 | // default package 7 | // package events; 8 | 9 | /* 10 | * MouseEventDemo.java 11 | */ 12 | 13 | import java.awt.Color; 14 | import java.awt.Dimension; 15 | import java.awt.event.MouseListener; 16 | import java.awt.event.MouseEvent; 17 | import java.awt.Graphics; 18 | import java.awt.GridLayout; 19 | 20 | import javax.swing.*; 21 | import javax.swing.*; 22 | 23 | public class MouseEventDemo extends JPanel 24 | implements MouseListener { 25 | BlankArea blankArea; 26 | JTextArea textArea; 27 | static final String NEWLINE = System.getProperty("line.separator"); 28 | 29 | public static void main(String[] args) { 30 | /* Use an appropriate Look and Feel */ 31 | try { 32 | //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 33 | //UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); 34 | UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); 35 | } catch (UnsupportedLookAndFeelException ex) { 36 | ex.printStackTrace(); 37 | } catch (IllegalAccessException ex) { 38 | ex.printStackTrace(); 39 | } catch (InstantiationException ex) { 40 | ex.printStackTrace(); 41 | } catch (ClassNotFoundException ex) { 42 | ex.printStackTrace(); 43 | } 44 | /* Turn off metal's use of bold fonts */ 45 | UIManager.put("swing.boldMetal", Boolean.FALSE); 46 | //Schedule a job for the event dispatch thread: 47 | //creating and showing this application's GUI. 48 | javax.swing.SwingUtilities.invokeLater(new Runnable() { 49 | public void run() { 50 | createAndShowGUI(); 51 | } 52 | }); 53 | } 54 | 55 | /** 56 | * Create the GUI and show it. For thread safety, 57 | * this method should be invoked from the 58 | * event dispatch thread. 59 | */ 60 | private static void createAndShowGUI() { 61 | //Create and set up the window. 62 | JFrame frame = new JFrame("MouseEventDemo"); 63 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 64 | 65 | //Create and set up the content pane. 66 | JComponent newContentPane = new MouseEventDemo(); 67 | newContentPane.setOpaque(true); //content panes must be opaque 68 | frame.setContentPane(newContentPane); 69 | 70 | //Display the window. 71 | frame.pack(); 72 | frame.setVisible(true); 73 | } 74 | 75 | public MouseEventDemo() { 76 | super(new GridLayout(0,1)); 77 | blankArea = new BlankArea(Color.YELLOW); 78 | add(blankArea); 79 | textArea = new JTextArea(); 80 | textArea.setEditable(false); 81 | JScrollPane scrollPane = new JScrollPane(textArea); 82 | scrollPane.setVerticalScrollBarPolicy( 83 | JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 84 | scrollPane.setPreferredSize(new Dimension(200, 75)); 85 | add(scrollPane); 86 | 87 | //Register for mouse events on blankArea and the panel. 88 | blankArea.addMouseListener(this); 89 | addMouseListener(this); 90 | setPreferredSize(new Dimension(450, 450)); 91 | setBorder(BorderFactory.createEmptyBorder(20,20,20,20)); 92 | } 93 | 94 | void eventOutput(String eventDescription, MouseEvent e) { 95 | textArea.append(eventDescription + " detected on " 96 | + e.getComponent().getClass().getName() 97 | + "." + NEWLINE); 98 | textArea.setCaretPosition(textArea.getDocument().getLength()); 99 | } 100 | 101 | public void mousePressed(MouseEvent e) { 102 | eventOutput("Mouse pressed (# of clicks: " 103 | + e.getClickCount() + ")", e); 104 | } 105 | 106 | public void mouseReleased(MouseEvent e) { 107 | eventOutput("Mouse released (# of clicks: " 108 | + e.getClickCount() + ")", e); 109 | } 110 | 111 | public void mouseEntered(MouseEvent e) { 112 | eventOutput("Mouse entered", e); 113 | } 114 | 115 | public void mouseExited(MouseEvent e) { 116 | eventOutput("Mouse exited", e); 117 | } 118 | 119 | public void mouseClicked(MouseEvent e) { 120 | eventOutput("Mouse clicked (# of clicks: " 121 | + e.getClickCount() + ")", e); 122 | } 123 | 124 | public class BlankArea extends JLabel { 125 | Dimension minSize = new Dimension(100, 50); 126 | 127 | public BlankArea(Color color) { 128 | setBackground(color); 129 | setOpaque(true); 130 | setBorder(BorderFactory.createLineBorder(Color.black)); 131 | } 132 | 133 | public Dimension getMinimumSize() { 134 | return minSize; 135 | } 136 | 137 | public Dimension getPreferredSize() { 138 | return minSize; 139 | } 140 | } 141 | } 142 | 143 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/MouseEventDemo.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | // default package 3 | // package events; 4 | 5 | /* 6 | * MouseEventDemo.java 7 | * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. 8 | */ 9 | // origin: https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/uiswing/examples/events/MouseEventDemoProject/src/events/MouseEventDemo.java 10 | 11 | 12 | import java.awt.Color; 13 | import java.awt.Dimension; 14 | import java.awt.event.MouseListener; 15 | import java.awt.event.MouseEvent; 16 | import java.awt.Graphics; 17 | import java.awt.GridLayout; 18 | 19 | import javax.swing.*; 20 | import javax.swing.*; 21 | 22 | public class MouseEventDemo extends JPanel 23 | implements MouseListener { 24 | BlankArea blankArea; 25 | JTextArea textArea; 26 | static final String NEWLINE = System.getProperty("line.separator"); 27 | 28 | public static void main(String[] args) { 29 | /* Use an appropriate Look and Feel */ 30 | try { 31 | //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 32 | //UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); 33 | UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); 34 | } catch (UnsupportedLookAndFeelException ex) { 35 | ex.printStackTrace(); 36 | } catch (IllegalAccessException ex) { 37 | ex.printStackTrace(); 38 | } catch (InstantiationException ex) { 39 | ex.printStackTrace(); 40 | } catch (ClassNotFoundException ex) { 41 | ex.printStackTrace(); 42 | } 43 | /* Turn off metal's use of bold fonts */ 44 | UIManager.put("swing.boldMetal", Boolean.FALSE); 45 | //Schedule a job for the event dispatch thread: 46 | //creating and showing this application's GUI. 47 | javax.swing.SwingUtilities.invokeLater(new Runnable() { 48 | public void run() { 49 | createAndShowGUI(); 50 | } 51 | }); 52 | } 53 | 54 | /** 55 | * Create the GUI and show it. For thread safety, 56 | * this method should be invoked from the 57 | * event dispatch thread. 58 | */ 59 | private static void createAndShowGUI() { 60 | //Create and set up the window. 61 | JFrame frame = new JFrame("MouseEventDemo"); 62 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 63 | 64 | //Create and set up the content pane. 65 | JComponent newContentPane = new MouseEventDemo(); 66 | newContentPane.setOpaque(true); //content panes must be opaque 67 | frame.setContentPane(newContentPane); 68 | 69 | //Display the window. 70 | frame.pack(); 71 | frame.setVisible(true); 72 | } 73 | 74 | public MouseEventDemo() { 75 | super(new GridLayout(0,1)); 76 | blankArea = new BlankArea(Color.YELLOW); 77 | add(blankArea); 78 | textArea = new JTextArea(); 79 | textArea.setEditable(false); 80 | JScrollPane scrollPane = new JScrollPane(textArea); 81 | scrollPane.setVerticalScrollBarPolicy( 82 | JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 83 | scrollPane.setPreferredSize(new Dimension(200, 75)); 84 | add(scrollPane); 85 | 86 | //Register for mouse events on blankArea and the panel. 87 | blankArea.addMouseListener(this); 88 | addMouseListener(this); 89 | setPreferredSize(new Dimension(450, 450)); 90 | setBorder(BorderFactory.createEmptyBorder(20,20,20,20)); 91 | } 92 | 93 | void eventOutput(String eventDescription, MouseEvent e) { 94 | textArea.append(eventDescription + " detected on " 95 | + e.getComponent().getClass().getName() 96 | + "." + NEWLINE); 97 | textArea.setCaretPosition(textArea.getDocument().getLength()); 98 | } 99 | 100 | public void mousePressed(MouseEvent e) { 101 | eventOutput("Mouse pressed (# of clicks: " 102 | + e.getClickCount() + ")", e); 103 | } 104 | 105 | public void mouseReleased(MouseEvent e) { 106 | eventOutput("Mouse released (# of clicks: " 107 | + e.getClickCount() + ")", e); 108 | } 109 | 110 | public void mouseEntered(MouseEvent e) { 111 | eventOutput("Mouse entered", e); 112 | } 113 | 114 | public void mouseExited(MouseEvent e) { 115 | eventOutput("Mouse exited", e); 116 | } 117 | 118 | public void mouseClicked(MouseEvent e) { 119 | eventOutput("Mouse clicked (# of clicks: " 120 | + e.getClickCount() + ")", e); 121 | } 122 | 123 | public class BlankArea extends JLabel { 124 | Dimension minSize = new Dimension(100, 50); 125 | 126 | public BlankArea(Color color) { 127 | setBackground(color); 128 | setOpaque(true); 129 | setBorder(BorderFactory.createLineBorder(Color.black)); 130 | } 131 | 132 | public Dimension getMinimumSize() { 133 | return minSize; 134 | } 135 | 136 | public Dimension getPreferredSize() { 137 | return minSize; 138 | } 139 | } 140 | } 141 | 142 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/ExceptionDialogEx.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019,2024 Serguei Kouzmine 4 | */ 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import org.eclipse.core.runtime.IStatus; 10 | import org.eclipse.core.runtime.MultiStatus; 11 | import org.eclipse.core.runtime.Status; 12 | 13 | import org.eclipse.jface.dialogs.ErrorDialog; 14 | 15 | import org.eclipse.swt.widgets.Display; 16 | import org.eclipse.swt.widgets.Shell; 17 | // https://docs.oracle.com/javase/8/docs/api/org/omg/SendingContext/RunTime.html 18 | // The import org.omg.SendingContext.RunTime is never used 19 | // import org.omg.SendingContext.RunTime; 20 | 21 | import com.github.sergueik.swet.Utils; 22 | 23 | import org.eclipse.swt.SWTException; 24 | 25 | /** 26 | * Exception dialog for Selenium WebDriver Elementor Tool (SWET) 27 | * 28 | * @author Serguei Kouzmine (kouzmine_serguei@yahoo.com) 29 | */ 30 | 31 | public class ExceptionDialogEx { 32 | 33 | 34 | private Shell shell = null; 35 | private static boolean debug = false; 36 | private static final Utils utils = Utils.getInstance(); 37 | private static final String manifestVersion = utils.readManifestVersion(); 38 | private static final ExceptionDialogEx instance = new ExceptionDialogEx(); 39 | 40 | public static void setDebug(boolean debug) { 41 | ExceptionDialogEx.debug = debug; 42 | } 43 | 44 | public static ExceptionDialogEx getInstance() { 45 | return instance; 46 | } 47 | 48 | private static void testFunction1() throws Exception { 49 | testFunction2(); 50 | } 51 | 52 | private static void testFunction2() throws Exception { 53 | testFunction3(); 54 | } 55 | 56 | // throwing exception from a function to illustrate the calling stack 57 | private static void testFunction3() throws Exception { 58 | throw new Exception("This is a dummy exception thrown by testFunction3"); 59 | } 60 | 61 | public void render(Throwable e) { 62 | 63 | MultiStatus status; 64 | // Collect the exception stack trace 65 | Exception eCause = (Exception) e.getCause(); 66 | if (eCause != null) { 67 | if (debug) { 68 | System.err.println("Cause: " + eCause.toString()); 69 | } 70 | status = createMultiStatus(e.getLocalizedMessage(), eCause); 71 | } else { 72 | status = createMultiStatus(e.getLocalizedMessage(), e); 73 | } 74 | // the following walks the stack, useful to discover the caller during the 75 | // regular execution - not so useful with thrower of the exception 76 | // https://stackoverflow.com/questions/4065518/java-how-to-get-the-caller-function-name/46590924 77 | // https://toster.ru/q/684867 78 | StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2]; 79 | String originatingMethod = String.format("%s.%s()", stackTraceElement.getClassName(), 80 | stackTraceElement.getMethodName()); 81 | // [0] => getStackTrace 82 | // [1] => render 83 | // [2] => main 84 | 85 | ErrorDialog.openError(shell, "Exception", 86 | "Exception thrown from " + instance.getClass().getName() + " " + manifestVersion 87 | /* "Exception thrown" */, status); 88 | 89 | } 90 | 91 | private ExceptionDialogEx() { 92 | Display display = null; 93 | try { 94 | display = Display.getCurrent(); 95 | } catch (SWTException e) { 96 | System.err.println(e.toString()); 97 | throw new RuntimeException(e); 98 | } 99 | try { 100 | shell = Display.getCurrent().getActiveShell(); 101 | } catch (NullPointerException e) { 102 | shell = new Shell(display); 103 | } 104 | } 105 | 106 | private static MultiStatus createMultiStatus(String description, Throwable t) { 107 | 108 | List childStatuses = new ArrayList<>(); 109 | 110 | for (StackTraceElement stackTrace : t.getStackTrace()) { 111 | if (debug) { 112 | System.err.println(String.format("Adding stack trace: %s", stackTrace.toString())); 113 | } 114 | 115 | Status status = new Status(IStatus.ERROR, 116 | ExceptionDialogEx.getInstance().getClass().getPackage().toString(), stackTrace.toString()); 117 | childStatuses.add(status); 118 | } 119 | for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) { 120 | if (debug) { 121 | System.err.println(String.format("Adding stack trace element: %s", stackTraceElement.toString())); 122 | } 123 | Status status = new Status(IStatus.ERROR, 124 | ExceptionDialogEx.getInstance().getClass().getPackage().toString(), stackTraceElement.toString()); 125 | childStatuses.add(status); 126 | } 127 | 128 | String summary = (description != null) ? description : t.toString(); 129 | MultiStatus status = new MultiStatus(ExceptionDialogEx.getInstance().getClass().getPackage().toString(), 130 | IStatus.ERROR, childStatuses.toArray(new Status[] {}), 131 | (summary.length() > 120) ? summary.substring(0, 120) : summary, t); 132 | return status; 133 | } 134 | 135 | public static void main(String[] arg) { 136 | debug = true; 137 | try { 138 | testFunction1(); 139 | } catch (Exception e) { 140 | // when using in SWT application, 141 | // need to defer initialization to after the application is started 142 | // to avoid org.eclipse.swt.SWTException: Invalid thread access 143 | // ExceptionDialogEx x = ExceptionDialogEx.getInstance(); 144 | 145 | ExceptionDialogEx.getInstance().render(e); 146 | } 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/custom/swt/widgets/MultiSelectCombo.java: -------------------------------------------------------------------------------- 1 | package custom.swt.widgets; 2 | 3 | import java.awt.AWTException; 4 | import java.awt.Robot; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | 8 | import org.eclipse.swt.SWT; 9 | import org.eclipse.swt.events.SelectionAdapter; 10 | import org.eclipse.swt.events.SelectionEvent; 11 | import org.eclipse.swt.graphics.Color; 12 | import org.eclipse.swt.graphics.Font; 13 | import org.eclipse.swt.graphics.Image; 14 | import org.eclipse.swt.graphics.Point; 15 | import org.eclipse.swt.layout.GridData; 16 | import org.eclipse.swt.layout.GridLayout; 17 | import org.eclipse.swt.widgets.Button; 18 | import org.eclipse.swt.widgets.Canvas; 19 | import org.eclipse.swt.widgets.Composite; 20 | import org.eclipse.swt.widgets.Control; 21 | import org.eclipse.swt.widgets.Event; 22 | import org.eclipse.swt.widgets.Listener; 23 | import org.eclipse.swt.widgets.Menu; 24 | import org.eclipse.swt.widgets.MenuItem; 25 | import org.eclipse.swt.widgets.Text; 26 | 27 | // origin: https://github.com/brotenet/swt-ext/blob/master/src/org/eclipse/swt/controls/collective/MultiSelectCombo.java 28 | public class MultiSelectCombo extends Canvas { 29 | private static final long serialVersionUID = 1L; 30 | private Text txtValues; 31 | private String[] items = new String[] {}; 32 | private String separator = ","; 33 | private Image image = new Image(null, MultiSelectCombo.class 34 | .getResourceAsStream("/org/eclipse/swt/controls/collective/down.png")); 35 | private Button btnMenu; 36 | 37 | @SuppressWarnings("serial") 38 | public MultiSelectCombo(Composite parent, int style) { 39 | super(parent, style); 40 | GridLayout gridLayout = new GridLayout(2, false); 41 | gridLayout.marginHeight = 0; 42 | gridLayout.marginWidth = 0; 43 | setLayout(gridLayout); 44 | 45 | txtValues = new Text(this, SWT.BORDER); 46 | txtValues.setEditable(false); 47 | txtValues 48 | .setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 1)); 49 | 50 | btnMenu = new Button(this, SWT.NONE); 51 | btnMenu.addSelectionListener(new SelectionAdapter() { 52 | @Override 53 | public void widgetSelected(SelectionEvent event) { 54 | Point control_point = ((Control) event.widget).toDisplay(1, 55 | 1 + ((Control) event.widget).getBounds().height); 56 | Robot robot = null; 57 | try { 58 | robot = new Robot(); 59 | } catch (AWTException exception) { 60 | exception.printStackTrace(); 61 | } 62 | robot.mouseMove(control_point.x, control_point.y); 63 | 64 | Menu menu = new Menu(btnMenu); 65 | for (String item_text : getItems()) { 66 | MenuItem item = new MenuItem(menu, SWT.NONE); 67 | item.setText(item_text); 68 | item.addListener(SWT.Selection, new Listener() { 69 | 70 | @Override 71 | public void handleEvent(Event event) { 72 | if ((txtValues.getText().trim().length() > 0) 73 | & !txtValues.getText().trim().endsWith(getSeparator())) { 74 | txtValues.setText(txtValues.getText().trim() + getSeparator()); 75 | } 76 | if (!txtValues.getText().contains( 77 | ((MenuItem) event.widget).getText() + getSeparator())) { 78 | txtValues.setText(txtValues.getText() 79 | + ((MenuItem) event.widget).getText() + getSeparator()); 80 | } else { 81 | txtValues.setText(txtValues.getText().replace( 82 | ((MenuItem) event.widget).getText() + getSeparator(), "")); 83 | } 84 | if (txtValues.getText().endsWith(getSeparator())) { 85 | txtValues.setText(txtValues.getText().substring(0, 86 | txtValues.getText().length() - 1)); 87 | } 88 | } 89 | }); 90 | } 91 | menu.setVisible(true); 92 | 93 | } 94 | }); 95 | btnMenu.setImage(image); 96 | } 97 | 98 | public String[] getItems() { 99 | return items; 100 | } 101 | 102 | public void setItems(String[] items) { 103 | ArrayList elements = new ArrayList(Arrays.asList(items)); 104 | for (int i = 0; i < elements.size(); i++) { 105 | if (elements.get(i).trim().length() < 1) { 106 | elements.remove(i); 107 | } 108 | } 109 | this.items = elements.toArray(new String[elements.size()]); 110 | } 111 | 112 | public String getText() { 113 | return txtValues.getText(); 114 | } 115 | 116 | public String getSeparator() { 117 | return separator; 118 | } 119 | 120 | public void setSeparator(String separator) { 121 | this.separator = separator; 122 | } 123 | 124 | @Override 125 | public void setForeground(Color color) { 126 | txtValues.setForeground(color); 127 | } 128 | 129 | @Override 130 | public Color getForeground() { 131 | return txtValues.getForeground(); 132 | } 133 | 134 | public Image getImage() { 135 | return image; 136 | } 137 | 138 | public void setImage(Image image) { 139 | this.image = image; 140 | btnMenu.setImage(getImage()); 141 | } 142 | 143 | public void setFont(Font font) { 144 | txtValues.setFont(font); 145 | } 146 | 147 | public Font getFont() { 148 | return txtValues.getFont(); 149 | } 150 | 151 | public void setValues(String[] values) { 152 | txtValues.setText(""); 153 | for (String value : values) { 154 | txtValues.setText(txtValues.getText() + value.trim() + getSeparator()); 155 | } 156 | if (txtValues.getText().endsWith(getSeparator())) { 157 | txtValues.setText( 158 | txtValues.getText().substring(0, txtValues.getText().length() - 1)); 159 | } 160 | } 161 | 162 | public String[] getValues() { 163 | return getText().split(getSeparator()); 164 | } 165 | } -------------------------------------------------------------------------------- /src/test/java/com/github/sergueik/swet/ExcelWriterTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | /** 4 | * Copyright 2019 Serguei Kouzmine 5 | */ 6 | 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | 12 | import java.nio.file.FileSystems; 13 | import java.nio.file.Files; 14 | import java.nio.file.LinkOption; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | import org.apache.poi.EncryptedDocumentException; 20 | import org.apache.poi.openxml4j.exceptions.InvalidFormatException; 21 | import org.apache.poi.ss.usermodel.Cell; 22 | import org.apache.poi.ss.usermodel.Row; 23 | import org.apache.poi.ss.usermodel.Sheet; 24 | import org.apache.poi.ss.usermodel.Workbook; 25 | import org.apache.poi.ss.util.CellRangeAddress; 26 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; 27 | 28 | import static org.hamcrest.MatcherAssert.assertThat; 29 | import static org.hamcrest.Matchers.greaterThan; 30 | import static org.hamcrest.CoreMatchers.equalTo; 31 | import static org.hamcrest.CoreMatchers.is; 32 | 33 | import org.junit.AfterClass; 34 | import org.junit.BeforeClass; 35 | import org.junit.Test; 36 | 37 | /** 38 | * Test for Selenium WebDriver Elementor Tool (SWET) Excel file writer 39 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 40 | */ 41 | 42 | // see also the forum where few initially failing implementations were shown 43 | // http://software-testing.ru/forum/index.php?/topic/38373-apache-poi-dobavlenie-novoj-stranitcy-v-suschestvuiuschij-fa/ 44 | // see also: 45 | // https://smearg.wordpress.com/2013/01/23/powershell-и-excel-часть-1-заполнение-таблицы/ 46 | // https://powershell.org/forums/topic/dynamically-create-worksheets-in-excel/ 47 | // http://ntcoder.com/bab/2018/01/18/powershell-tidbits-creating-excel-workbook-and-filling-out-data-into-worksheets/ 48 | public class ExcelWriterTest { 49 | private static List dummyKeys = new ArrayList<>(); 50 | private static List dummyValues = new ArrayList<>(); 51 | private static String fileName = "dummy.xlsx"; 52 | private static Workbook wb = null; 53 | 54 | @AfterClass 55 | public static void cleanup() throws IOException { 56 | File file = new File(fileName); 57 | 58 | if (!file.delete()) { 59 | throw new IOException("Delete " + file.getAbsolutePath() + "failed "); 60 | } 61 | } 62 | 63 | @Test 64 | public void supportedKeywordsContainsKeywordTableTest() 65 | throws IOException, EncryptedDocumentException, InvalidFormatException { 66 | dummyKeys.add("key 1"); 67 | dummyKeys.add("key 2"); 68 | dummyKeys.add("key 3"); 69 | dummyKeys.add("key 4"); 70 | dummyValues.add("10"); 71 | dummyValues.add("20"); 72 | dummyValues.add("30"); 73 | dummyValues.add("40"); 74 | addSheet("Sheet 1", dummyKeys, dummyValues, fileName); 75 | dummyKeys.clear(); 76 | dummyValues.clear(); 77 | dummyKeys.add("key 1"); 78 | dummyKeys.add("key 2"); 79 | dummyValues.add("50"); 80 | dummyValues.add("60"); 81 | addSheet("Sheet 2", dummyKeys, dummyValues, fileName); 82 | 83 | wb = new XSSFWorkbook(new FileInputStream(fileName)); 84 | assertThat(wb.getNumberOfSheets(), greaterThan(1)); 85 | wb.close(); 86 | addSheet("Sheet 1", dummyKeys, dummyValues, fileName); 87 | // assertTrue(supportedKeywords.containsAll(keywordTable.keySet())); 88 | // assertFalse(keywordTable.keySet().containsAll(supportedKeywords)); 89 | wb = new XSSFWorkbook(new FileInputStream(fileName)); 90 | assertThat(wb.getNumberOfSheets(), equalTo(2)); 91 | wb.close(); 92 | } 93 | 94 | public static void addSheet(String sheetName, List keys, 95 | List values, String fileName) 96 | throws IOException, EncryptedDocumentException, InvalidFormatException { 97 | 98 | if (Files.exists(FileSystems.getDefault() 99 | .getPath(System.getProperty("user.dir"), fileName), 100 | new LinkOption[] { LinkOption.NOFOLLOW_LINKS })) { 101 | 102 | System.out.println("File exists: " + fileName); 103 | wb = new XSSFWorkbook(new FileInputStream(fileName)); 104 | } else { 105 | wb = new XSSFWorkbook(); 106 | } 107 | /* 108 | $idx = 1 109 | $o = new-object -ComObject 'excel.application' 110 | $o.visible = $true 111 | $excel = $o.workbooks.add() 112 | $excel.worksheets.item(1).delete() 113 | 114 | @('A1','B2','C3') | foreach-object { 115 | $group = $_ 116 | $sheet = $excel.worksheets.item($idx) 117 | $sheet.name = $group 118 | $idx++ 119 | $excel.worksheets.add($idx) 120 | } 121 | 122 | 123 | */ 124 | Sheet sheet = wb.getSheet(sheetName) != null ? wb.getSheet(sheetName) 125 | : wb.createSheet(sheetName); 126 | 127 | Row r0 = sheet.createRow(0); 128 | Cell c0 = r0.createCell(0); 129 | c0.setCellValue("Key"); 130 | Cell c1 = r0.createCell(1); 131 | c1.setCellValue("Value"); 132 | 133 | Row a; 134 | 135 | List valuesInt = new ArrayList<>(); 136 | for (String s : values) 137 | valuesInt.add(Integer.valueOf(s)); 138 | 139 | for (int i = 0; i < keys.size(); i++) { 140 | a = sheet.createRow(i + 1); 141 | String name = keys.get(i); 142 | a.createCell(0).setCellValue(name); 143 | } 144 | 145 | for (int j = 0; j < valuesInt.size(); j++) { 146 | a = sheet.getRow(j + 1); 147 | Integer price = valuesInt.get(j); 148 | a.createCell(1).setCellValue(price); 149 | } 150 | 151 | sheet.setAutoFilter(CellRangeAddress.valueOf("A1:B" + (valuesInt.size()))); 152 | 153 | FileOutputStream outputStream = new FileOutputStream(fileName); 154 | 155 | wb.write(outputStream); 156 | wb.close(); 157 | outputStream.close(); 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/ButtonSizeEx.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.graphics.Point; 5 | import org.eclipse.swt.graphics.Rectangle; 6 | import org.eclipse.swt.internal.win32.OS; 7 | import org.eclipse.swt.layout.GridData; 8 | import org.eclipse.swt.layout.GridLayout; 9 | import org.eclipse.swt.widgets.Button; 10 | import org.eclipse.swt.widgets.Control; 11 | import org.eclipse.swt.widgets.Display; 12 | import org.eclipse.swt.widgets.Shell; 13 | import org.eclipse.swt.widgets.Text; 14 | 15 | import com.sun.jna.Pointer; 16 | import com.sun.jna.platform.win32.User32; 17 | // this import is windows-only 18 | import com.sun.jna.platform.win32.WinDef.HWND; 19 | 20 | // origin: 21 | // https://www.eclipsezone.com/servlet/JiveServlet/download/18120-65152-91995796-4076/ButtonSizeSnippet.java 22 | public class ButtonSizeEx { 23 | public static void main(String[] args) { 24 | final Display display = new Display(); 25 | final Shell shell = new Shell(display); 26 | shell.setLayout(new GridLayout()); 27 | 28 | GridLayout layout = new GridLayout(2, true); 29 | shell.setLayout(layout); 30 | 31 | Text txt = new Text(shell, SWT.BORDER | SWT.SINGLE); 32 | txt.setText("Text here"); 33 | txt.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); 34 | 35 | Button b = new Button(shell, SWT.PUSH); 36 | b.setText("B1"); 37 | b.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); 38 | 39 | txt = new Text(shell, SWT.BORDER | SWT.MULTI); 40 | txt.setText("something else here"); 41 | GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); 42 | data.horizontalSpan = 2; 43 | txt.setLayoutData(data); 44 | 45 | b = new Button(shell, SWT.PUSH); 46 | b.setText("B2 Wide Wide Wide Wide Button"); 47 | b.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); 48 | 49 | // this does not change the heght of the button 50 | b = new Button(shell, SWT.PUSH); 51 | // https://stackoverflow.com/questions/4547209/multi-line-button-text-in-swt-windowbuilder 52 | // b = new Button(shell, SWT.WRAP | SWT.PUSH); 53 | 54 | // alternatively 55 | final int style = OS.GetWindowLong(b.handle, OS.GWL_STYLE); 56 | OS.SetWindowLong(b.handle, OS.GWL_STYLE, style | OS.BS_MULTILINE); 57 | 58 | // https://markmail.org/thread/qlfoejwbue24rtne 59 | 60 | // unrelated 61 | // https://www.codota.com/code/java/methods/com.sun.jna.platform.win32.User32/GetWindowText 62 | int windowTextLength = 512; 63 | char[] windowText = new char[windowTextLength]; 64 | User32 user32 = User32.INSTANCE; 65 | // the following code is windows-only 66 | HWND hwnd = new HWND(); 67 | hwnd.setPointer(new Pointer(b.handle)); 68 | user32.GetWindowText(hwnd, windowText, windowTextLength); 69 | System.err.println("GetWindow text: " + windowText.toString()); 70 | 71 | b.setText("B3\nTall Button"); 72 | b.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); 73 | GridData buttonGridData = (GridData) b.getLayoutData(); 74 | Point bSize = b.computeSize(SWT.DEFAULT, SWT.DEFAULT); 75 | buttonGridData.widthHint = bSize.x; 76 | buttonGridData.heightHint = (int) (bSize.y * 2.5); 77 | System.err.println( 78 | String.format("Manually adjusting size to: width: %d height: %d", 79 | buttonGridData.widthHint, buttonGridData.heightHint)); 80 | b.setLayoutData(buttonGridData); 81 | // does not work. 82 | b.setSize(new Point(buttonGridData.widthHint, buttonGridData.heightHint)); 83 | shell.pack(); 84 | 85 | // NOTE: there appears to be no SetWindowText in user32 86 | // user32.SetWindowText(hwnd, titleText, windowTextMaxLength); 87 | // however 88 | // http://www.javased.com/?source_dir=file.monitor/com.sun.jna.examples.win32/src/com/sun/jna/examples/win32/User32.java 89 | 90 | // Get the Maximum height and width for all buttons 91 | Point y = new Point(0, 0); 92 | Control[] ca = shell.getChildren(); 93 | for (int i = 0; i < ca.length; i++) { 94 | if (ca[i] instanceof Button) { 95 | Button _b = (Button) ca[i]; 96 | _b.setData("name", ellipsisText(_b.getText(), 10)); 97 | Point tmp = ((Button) ca[i]).computeSize(SWT.DEFAULT, SWT.DEFAULT); 98 | bSize.x = Math.max(bSize.x, tmp.x); 99 | bSize.y = Math.max(bSize.y, tmp.y); 100 | System.err.println(String.format("Measuring %s: width: %d height: %d", 101 | _b.getData("name"), tmp.x, tmp.y)); 102 | } 103 | } 104 | System.err.println(String.format( 105 | "Computed the maximum height and width for all buttons: %d, %d", 106 | bSize.x, bSize.y)); 107 | // Set the height and width for all buttons to the Maximum size 108 | // NOTE: hacking height 109 | bSize.y = (int) (1.7 * bSize.y); 110 | for (int i = 0; i < ca.length; i++) { 111 | if (ca[i] instanceof Button) { 112 | Button _b = (Button) ca[i]; 113 | System.err.println("Resizing " + _b.getData("name")); 114 | GridData gData = (GridData) _b.getLayoutData(); 115 | gData.widthHint = bSize.x; 116 | gData.heightHint = bSize.y; 117 | } 118 | } 119 | 120 | shell.pack(); 121 | Rectangle screen = display.getMonitors()[0].getBounds(); 122 | // center on the screen 123 | shell.setBounds(screen.width / 2 - 320, screen.height / 2 - 200, 640, 400); 124 | shell.open(); 125 | while (!shell.isDisposed()) { 126 | if (!display.readAndDispatch()) 127 | display.sleep(); 128 | } 129 | display.dispose(); 130 | } 131 | 132 | private static String ellipsisText(String text, int size) { 133 | 134 | String _text = text.replaceAll("\n", " "); 135 | return String.format("%s%s", 136 | (_text.length() > size) ? _text.substring(0, size) : _text, 137 | (OSUtils.getOsName().equals("windows")) ? "..." : "\u2026"); 138 | } 139 | 140 | private static String ellipsisText(String text) { 141 | return ellipsisText(text, 10); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/YamlHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019 Serguei Kouzmine 4 | */ 5 | 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.OutputStreamWriter; 10 | import java.io.Writer; 11 | import java.nio.file.Files; 12 | import java.nio.file.Paths; 13 | 14 | import java.text.DateFormat; 15 | import java.text.SimpleDateFormat; 16 | import java.util.Arrays; 17 | import java.util.Calendar; 18 | import java.util.Date; 19 | import java.util.GregorianCalendar; 20 | import java.util.HashMap; 21 | import java.util.HashSet; 22 | import java.util.Locale; 23 | import java.util.Map; 24 | import java.util.Set; 25 | 26 | import org.yaml.snakeyaml.DumperOptions; 27 | import org.yaml.snakeyaml.Yaml; 28 | 29 | // for generating the Keywords handled by KeywordLibrary 30 | 31 | // TODO: deploy to maven central 32 | // NOTE: need to package locally 33 | import com.github.sergueik.jprotractor.KeywordLibrary; 34 | 35 | /** 36 | * Common utilities for YAML configuration file for Selenium WebDriver Elementor Tool (SWET) 37 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 38 | */ 39 | 40 | public class YamlHelper { 41 | 42 | private static DumperOptions options = new DumperOptions(); 43 | private static Yaml yaml = null; 44 | private static Calendar calendar; 45 | private static String yamlFile = null; 46 | private static boolean debug = true; 47 | 48 | private static Map keywordTable = new HashMap<>(); 49 | 50 | @SuppressWarnings("unchecked") 51 | public static Map> loadData(String fileName) { 52 | if (yaml == null) { 53 | options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); 54 | options.setExplicitStart(true); 55 | yaml = new Yaml(options); 56 | } 57 | 58 | Map> data = new HashMap>(); 59 | try (InputStream in = Files.newInputStream(Paths.get(fileName))) { 60 | // NOTE: unchecked conversion 61 | // required: Map> 62 | // found: capture#1 of ? extends java.util.Map 63 | data = yaml.loadAs(in, data.getClass()); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | } 67 | return data; 68 | } 69 | 70 | // NOTE: redundant, can one do generics here 71 | @SuppressWarnings("unchecked") 72 | public static Map loadHelp(String fileName) { 73 | if (yaml == null) { 74 | options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); 75 | options.setExplicitStart(true); 76 | yaml = new Yaml(options); 77 | } 78 | Map data = new HashMap<>(); 79 | try (InputStream in = Files.newInputStream(Paths.get(fileName))) { 80 | // NOTE: unchecked conversion 81 | // required: Map> 82 | // found: capture#1 of ? extends java.util.Map 83 | data = yaml.loadAs(in, data.getClass()); 84 | } catch (IOException e) { 85 | e.printStackTrace(); 86 | } 87 | return data; 88 | } 89 | 90 | public static Configuration loadConfiguration(String fileName) { 91 | if (yaml == null) { 92 | options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); 93 | options.setExplicitStart(true); 94 | yaml = new Yaml(options); 95 | } 96 | Configuration config = null; 97 | try (InputStream in = Files.newInputStream(Paths.get(fileName))) { 98 | config = yaml.loadAs(in, com.github.sergueik.swet.Configuration.class); 99 | // TODO: better method naming 100 | YamlHelper.saveConfiguration(config); 101 | 102 | } catch (IOException e) { 103 | e.printStackTrace(); 104 | } 105 | return config; 106 | } 107 | 108 | public static void printConfiguration(Object config) { 109 | saveConfiguration(config); 110 | } 111 | 112 | public static void saveConfiguration(Object config) { 113 | saveConfiguration(config, null); 114 | } 115 | 116 | @SuppressWarnings("deprecation") 117 | public static void saveConfiguration(Object config, String fileName) { 118 | if (yaml == null) { 119 | options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); 120 | options.setExplicitStart(true); 121 | yaml = new Yaml(options); 122 | } 123 | /* 124 | String pattern = "yyyy-MM-dd"; 125 | SimpleDateFormat format = new SimpleDateFormat(pattern); 126 | Date date = new Date(); 127 | try { 128 | config.updated = format.parse(String.format("%4d-%2d-%2d", date.getYear(), 129 | date.getMonth(), date.getDay())); 130 | } catch (java.text.ParseException e) { 131 | config.updated = date; 132 | } 133 | */ 134 | calendar = new GregorianCalendar(); 135 | SimpleDateFormat dateFormat = new SimpleDateFormat( 136 | ((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, 137 | Locale.US)).toPattern().replaceAll("\\byy\\b", "yyyy") 138 | .replaceAll("\\bM\\b", "MM").replaceAll("\\bd\\b", "dd")); 139 | 140 | // System.err.println("Testing date format: " + dateFormat.toPattern()); 141 | 142 | if (config instanceof com.github.sergueik.swet.Configuration) { 143 | try { 144 | System.err.println("Adding save date: " 145 | + dateFormat.parse(dateFormat.format(calendar.getTime()))); 146 | ((Configuration) config).setUpdated( 147 | dateFormat.parse(dateFormat.format(calendar.getTime()))); 148 | } catch (java.text.ParseException e) { 149 | System.err.println("Ignoring date parse exception: " + e.toString()); 150 | ((com.github.sergueik.swet.Configuration) config) 151 | .setUpdated(new Date()); 152 | } 153 | } 154 | if (fileName != null) { 155 | try { 156 | Writer out = new OutputStreamWriter(new FileOutputStream(fileName), 157 | "UTF8"); 158 | System.err.println("Dumping the config to: " + fileName); 159 | 160 | yaml.dump(config, out); 161 | out.close(); 162 | } catch (IOException e) { 163 | e.printStackTrace(); 164 | } 165 | } else { 166 | System.err.println("Dumping the config: \n" + yaml.dump(config)); 167 | } 168 | } 169 | 170 | } -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/RenderTemplate.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2019,2021 Serguei Kouzmine 4 | */ 5 | 6 | import java.util.ArrayList; 7 | import java.util.Formatter; 8 | import java.util.HashMap; 9 | import java.util.Iterator; 10 | import java.util.List; 11 | import java.util.Locale; 12 | import java.util.Map; 13 | 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import org.jtwig.JtwigModel; 18 | import org.jtwig.JtwigTemplate; 19 | 20 | /** 21 | * Generate source code from TestData hash of ElementData recorded page interaction and a 22 | * caller-provided twig template for Selenium WebDriver Elementor Tool (SWET) 23 | * @author: Serguei Kouzmine (kouzmine_serguei@yahoo.com) 24 | */ 25 | 26 | public class RenderTemplate { 27 | 28 | private static String defaultTemplateFileName = "templates/core_selenium_java.twig"; 29 | private static String defaultTemplateName = "Core Selenium Java"; 30 | private String templateName = defaultTemplateName; 31 | 32 | private String templateAbsolutePath = ""; 33 | private JtwigTemplate template = null; 34 | private static boolean debug = false; 35 | 36 | public static String getDefaultTemplateFileName() { 37 | return defaultTemplateFileName; 38 | } 39 | 40 | public void setTemplateName(String data) { 41 | utils.initializeLogger(); 42 | logger.info("Initialized logger."); 43 | if (data != null) { 44 | this.templateName = data; 45 | } 46 | } 47 | 48 | public String getTemplateName() { 49 | return templateName; 50 | } 51 | 52 | public void setTemplateAbsolutePath(String data) { 53 | this.templateAbsolutePath = data; 54 | } 55 | 56 | public static void setDebug(boolean data) { 57 | RenderTemplate.debug = data; 58 | } 59 | 60 | public String getTemplateAbsolutePath() { 61 | return templateAbsolutePath; 62 | } 63 | 64 | private static Map createSampleElementData() { 65 | Map elementData = new HashMap<>(); 66 | elementData.put("ElementId", "id"); 67 | elementData.put("ElementCodeName", 68 | "name of the element, supplied during recoring"); 69 | elementData.put("ElementText", "text of the element, when available"); 70 | elementData.put("ElementXPath", "/html//img[1]"); 71 | elementData.put("ElementVariable", "elementVariable"); 72 | elementData.put("ElementCssSelector", "div#gbw > a.highlight"); 73 | elementData.put("ElementSelectedBy", "ElementCssSelector"); 74 | if (debug) { 75 | System.err.println("Sample Element data: " + elementData.toString()); 76 | } 77 | return elementData; 78 | } 79 | 80 | private static Map> createSampleTestData() { 81 | final Map> testData = new HashMap<>(); 82 | Map elementData = createSampleElementData(); 83 | testData.put("1", elementData); 84 | if (debug) { 85 | // NOTE: http://mmahmoodict.wikidot.com/apache-commons-lang3-builder-example 86 | // for strongly-typed Element class 87 | System.err.println("Sample Test data: " + testData.toString()); 88 | } 89 | return testData; 90 | } 91 | 92 | private static final Logger logger = LoggerFactory.getLogger(RenderTemplate.class); 93 | 94 | private static StringBuilder loggingSb = new StringBuilder(); 95 | private static Formatter formatter = new Formatter(loggingSb, Locale.US); 96 | 97 | private static Utils utils = Utils.getInstance(); 98 | 99 | public String renderTest() { 100 | Map> testData = new HashMap<>(); 101 | testData = createSampleTestData(); 102 | return renderTest(testData); 103 | } 104 | 105 | public String renderTest(Map> testData) { 106 | Iterator testDataKeys = testData.keySet().iterator(); 107 | String stepId; 108 | List scripts = new ArrayList<>(); 109 | while (testDataKeys.hasNext()) { 110 | stepId = testDataKeys.next(); 111 | System.err.println("Rendering step " + stepId); 112 | Map elementData = testData.get(stepId); 113 | scripts.add(renderElement(elementData)); 114 | } 115 | StringBuilder result = new StringBuilder(); 116 | for (String line : scripts) { 117 | result.append(line); 118 | result.append("\n"); 119 | } 120 | return result.toString(); 121 | } 122 | 123 | private String renderElement(Map data) { 124 | // Cache template contents 125 | if (template == null) { 126 | if (this.templateAbsolutePath != "") { 127 | System.err.println( 128 | "Load tempate by absolute path: " + this.templateAbsolutePath); 129 | template = JtwigTemplate.fileTemplate(this.templateAbsolutePath); 130 | } else { 131 | System.err 132 | .println("Load tempate by resource path: " + this.templateName); 133 | template = JtwigTemplate.classpathTemplate(this.templateName); 134 | } 135 | } 136 | JtwigModel model = JtwigModel.newModel(); 137 | if (debug) { 138 | System.err.println("The template: " + template.toString()); 139 | } 140 | 141 | for (String key : data.keySet()) { 142 | if (debug) { 143 | System.err 144 | .println(String.format("\"%s\" = \"%s\"", key, data.get(key))); 145 | } 146 | model.with(key, data.get(key).replace("\"", "\\\"")); 147 | } 148 | String output = template.render(model); 149 | if (debug) { 150 | System.err.println("renderElement : " + output); 151 | } 152 | return output; 153 | } 154 | 155 | @SuppressWarnings("unused") 156 | public static void main(String[] args) { 157 | RenderTemplate template = new RenderTemplate(); 158 | RenderTemplate.setDebug(true); 159 | // TODO: tests for by name template discoveries 160 | if (args.length > 0) { 161 | template.setTemplateAbsolutePath( 162 | String.format("%s/%s", System.getProperty("user.dir"), args[0])); 163 | } else { 164 | template.setTemplateAbsolutePath(String.format("%s/src/main/resources/%s", 165 | System.getProperty("user.dir"), 166 | RenderTemplate.getDefaultTemplateFileName())); 167 | } 168 | String payload = template.renderTest(); 169 | System.err.println("Rendered sample: " + payload); 170 | } 171 | 172 | } 173 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/User32WakeupTest.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2020 Serguei Kouzmine 4 | */ 5 | 6 | import com.sun.jna.Native; 7 | import com.sun.jna.platform.win32.BaseTSD; 8 | import com.sun.jna.platform.win32.User32; 9 | import com.sun.jna.platform.win32.Kernel32; 10 | import com.sun.jna.platform.win32.WinNT.HANDLE; 11 | import com.sun.jna.ptr.IntByReference; 12 | import com.sun.jna.ptr.PointerByReference; 13 | 14 | import com.sun.jna.platform.win32.Win32Exception; 15 | import com.sun.jna.platform.win32.WinDef; 16 | import com.sun.jna.platform.win32.WinDef.LONG; 17 | import com.sun.jna.platform.win32.WinUser; 18 | 19 | // origin: https://stackoverflow.com/questions/28538234/sending-a-keyboard-input-with-java-jna-and-sendinput 20 | // see also: https://www.codeproject.com/Articles/5264831/How-to-Send-mouseInputs-using-Csharp 21 | 22 | public class User32WakeupTest { 23 | 24 | private static final int WM_MOUSEMOVE = 512; 25 | private static final int WM_LBUTTONDOWN = 513; 26 | // https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttonup 27 | private static final int WM_LBUTTONUP = 0x0202; // 514 28 | private static final int WM_RBUTTONDOWN = 516; 29 | 30 | // https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keyup 31 | private static final int WM_KEYDOWN = 0x0100; // 514 32 | private static final int WM_KEYUP = 0x0101; 33 | // String to locate target window by title starting with (downcase) 34 | // like ubiquitous "Untitled - Notepad" 35 | private static String title = "untitled"; 36 | private static String message = "wakeup neo"; 37 | private static WinUser.INPUT input; 38 | private static WinDef.RECT rect; 39 | private static WinDef.POINT point; 40 | private static int delay = 100; 41 | 42 | public static void main(String[] args) { 43 | // inspect all windows 44 | User32.INSTANCE.EnumWindows((hWnd, data) -> { 45 | char[] name = new char[512]; 46 | 47 | User32.INSTANCE.GetWindowText(hWnd, name, name.length); 48 | String windowTitle = Native.toString(name).toLowerCase(); 49 | if (windowTitle.startsWith(title)) { 50 | System.err.println("Found target window: " + windowTitle); 51 | // Bring the window to the front 52 | User32.INSTANCE.SetForegroundWindow(hWnd); 53 | 54 | // instantiate keyboard input reference 55 | input = new WinUser.INPUT(); 56 | input.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD); 57 | input.input.setType("ki"); 58 | // https://groups.google.com/d/msg/jna-users/NDBGwC1VZbU/cjYCQ1CjBwAJ 59 | input.input.ki.wScan = new WinDef.WORD(0); 60 | input.input.ki.time = new WinDef.DWORD(0); 61 | input.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0); 62 | 63 | char[] chars = message.toUpperCase().toCharArray(); 64 | for (int index = 0; index < chars.length; index++) { 65 | char letter = chars[index]; 66 | 67 | System.err.println(String.format("type: %c", letter)); 68 | input.input.ki.wVk = new WinDef.WORD(letter); 69 | // 0x41 for 'a'etc. 70 | input.input.ki.dwFlags = new WinDef.DWORD(0); 71 | // keydown 72 | 73 | User32.INSTANCE.SendInput(new WinDef.DWORD(1), 74 | (WinUser.INPUT[]) input.toArray(1), input.size()); 75 | 76 | // Release 77 | input.input.ki.wVk = new WinDef.WORD(letter); 78 | // keyup 79 | input.input.ki.dwFlags = new WinDef.DWORD(2); 80 | 81 | User32.INSTANCE.SendInput(new WinDef.DWORD(1), 82 | (WinUser.INPUT[]) input.toArray(1), input.size()); 83 | try { 84 | Thread.sleep(delay); 85 | } catch (InterruptedException e) { 86 | } 87 | } 88 | // Prepare mouse button press event reference 89 | input = new WinUser.INPUT(); 90 | 91 | input.type = new WinDef.DWORD(WinUser.INPUT.INPUT_MOUSE); 92 | input.input.setType("mi"); 93 | 94 | // click on the center of the target window 95 | // https://www.codota.com/code/java/methods/com.sun.jna.platform.win32.User32/GetWindowRect 96 | rect = new WinDef.RECT(); 97 | // https://www.codota.com/code/java/methods/com.sun.jna.platform.win32.Kernel32/GetLastError 98 | if (!User32.INSTANCE.GetWindowRect(hWnd, rect)) { 99 | throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); 100 | } 101 | 102 | point = new WinDef.POINT(); 103 | point.x = (rect.left + rect.right) / 2; 104 | point.y = (rect.top + rect.bottom) / 2; 105 | System.err.println( 106 | String.format("Drawing line from (%d, %d)", point.x, point.y)); 107 | input.input.mi.dx = new WinDef.LONG(point.x); 108 | input.input.mi.dy = new WinDef.LONG(point.y); 109 | // https://www.programcreek.com/java-api-examples/?api=com.sun.jna.platform.win32.WinDef 110 | // https://www.programcreek.com/java-api-examples/?code=martin-lizner/trezor-ssh-agent/trezor-ssh-agent-master/src/main/java/com/trezoragent/mouselistener/JNIMouseHook.java 111 | 112 | User32.INSTANCE.SetCursorPos(point.x, point.y); 113 | input.input.mi.dwFlags = new WinDef.DWORD( 114 | WM_LBUTTONDOWN | WM_MOUSEMOVE); 115 | 116 | input.input.mi.time = new WinDef.DWORD(0); 117 | input.input.mi.dx = new WinDef.LONG(0); 118 | input.input.mi.dy = new WinDef.LONG(0); 119 | input.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0); 120 | User32.INSTANCE.SendInput(new WinDef.DWORD(1), 121 | (WinUser.INPUT[]) input.toArray(1), input.size()); 122 | 123 | input.input.mi.dx = new WinDef.LONG(40); 124 | input.input.mi.dy = new WinDef.LONG(60); 125 | input.input.mi.dwFlags = new WinDef.DWORD( 126 | WM_LBUTTONDOWN | WM_MOUSEMOVE); 127 | User32.INSTANCE.SendInput(new WinDef.DWORD(1), 128 | (WinUser.INPUT[]) input.toArray(1), input.size()); 129 | input.input.mi.dx = new WinDef.LONG(0); 130 | input.input.mi.dy = new WinDef.LONG(0); 131 | input.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0); 132 | input.input.mi.dwFlags = new WinDef.DWORD(WM_LBUTTONUP); 133 | User32.INSTANCE.SendInput(new WinDef.DWORD(1), 134 | (WinUser.INPUT[]) input.toArray(1), input.size()); 135 | 136 | User32.INSTANCE.GetCursorPos(point); 137 | System.err.println(String.format("Releasing mouse button at (%d, %d)", 138 | point.x, point.y)); 139 | 140 | return false; // exit enum windows loop 141 | } 142 | 143 | return true; // Keep searching 144 | }, null); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/com/github/sergueik/swet/TemplateCache.java: -------------------------------------------------------------------------------- 1 | package com.github.sergueik.swet; 2 | /** 3 | * Copyright 2014 - 2018 Serguei Kouzmine 4 | */ 5 | 6 | import java.io.File; 7 | import java.io.FileReader; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.net.URL; 11 | import java.security.CodeSource; 12 | import java.util.Collections; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import java.util.regex.Matcher; 16 | import java.util.regex.Pattern; 17 | import java.util.zip.ZipEntry; 18 | import java.util.zip.ZipInputStream; 19 | 20 | import org.apache.commons.io.IOUtils; 21 | 22 | public class TemplateCache { 23 | private Utils utils = Utils.getInstance(); 24 | private static Map cache = Collections 25 | .synchronizedMap(new HashMap()); 26 | 27 | private static TemplateCache instance = new TemplateCache(); 28 | 29 | private TemplateCache() { 30 | } 31 | 32 | public static TemplateCache getInstance() { 33 | return instance; 34 | } 35 | 36 | public static Map getCache() { 37 | return cache; 38 | } 39 | 40 | public void addItem(String tag, String path) { 41 | cache.put(tag, path); 42 | } 43 | 44 | public String getItem(String tag) { 45 | return cache.get(tag); 46 | } 47 | 48 | private String extractTag(String payload) { 49 | 50 | String templateTag = null; 51 | 52 | // find specially formatted twig comment in the template 53 | Matcher matcherTwigComment = Pattern 54 | .compile("\\{#(?:\\r?\\n)?(.*)(?:\\r?\\n)?#\\}", Pattern.MULTILINE) 55 | .matcher(payload); 56 | if (matcherTwigComment.find()) { 57 | String comment = matcherTwigComment.group(1); 58 | // extract template tag from the comment 59 | Matcher matcherTemplate = Pattern 60 | .compile("template: (.+)$", Pattern.MULTILINE).matcher(comment); 61 | if (matcherTemplate.find()) { 62 | templateTag = matcherTemplate.group(1); 63 | System.err 64 | .println(String.format("Discovered tag: \"%s\": ", templateTag)); 65 | } 66 | } 67 | return templateTag; 68 | } 69 | 70 | public void fillTemplateDirectoryCache(final File dir, String note, 71 | Map templates) { 72 | FileReader fileReader = null; 73 | String contents = null; 74 | if (dir.listFiles().length == 0) { 75 | return; 76 | } 77 | for (final File fileEntry : dir.listFiles()) { 78 | contents = null; 79 | if (fileEntry.getName().endsWith(".twig")) { 80 | if (fileEntry.isFile()) { 81 | try { 82 | fileReader = new FileReader(fileEntry); 83 | char[] template = new char[(int) fileEntry.length()]; 84 | fileReader.read(template); 85 | contents = new String(template); 86 | } catch (Exception e) { 87 | e.printStackTrace(); 88 | } finally { 89 | if (fileReader != null) { 90 | try { 91 | fileReader.close(); 92 | } catch (IOException e) { 93 | } 94 | } 95 | } 96 | } 97 | if (contents != null) { 98 | 99 | String templateName = extractTag(contents); 100 | if (templateName != null) { 101 | String templateLabel = String.format("%s (%s)", templateName, 102 | (note == null) ? "unknown" : note); 103 | String templateAbsolutePath = fileEntry.getAbsolutePath(); 104 | System.out.println(String.format("Make option for \"%s\": \"%s\"", 105 | templateAbsolutePath, templateLabel)); 106 | if (templates.containsKey(templateLabel)) { 107 | templates.replace(templateLabel, templateAbsolutePath); 108 | } else { 109 | templates.put(templateLabel, templateAbsolutePath); 110 | } 111 | System.out.println(String.format("Data for option \"%s\": \"%s\"", 112 | templateLabel, templates.get(templateLabel))); 113 | } else { 114 | System.out 115 | .println(String.format("no tag: %s", fileEntry.getName())); 116 | } 117 | } 118 | } 119 | } 120 | } 121 | 122 | public void fillEmbeddedTemplateCache() { 123 | // https://stackoverflow.com/questions/1429172/how-do-i-list-the-files-inside-a-jar-file 124 | CodeSource src = this.getClass().getProtectionDomain().getCodeSource(); 125 | String note = "embedded"; 126 | String templateTag = null; 127 | try { 128 | URL jar = src.getLocation(); 129 | ZipInputStream zip = new ZipInputStream(jar.openStream()); 130 | ZipEntry ze = null; 131 | 132 | while ((ze = zip.getNextEntry()) != null) { 133 | String templateResourcePath = ze.getName(); 134 | if (templateResourcePath.startsWith("templates") 135 | && templateResourcePath.endsWith(".twig")) { 136 | InputStream inputStream = utils 137 | .getResourceStream(templateResourcePath); 138 | String templateContents = IOUtils.toString(inputStream, "UTF8"); 139 | 140 | if (templateContents != null) { 141 | 142 | templateTag = extractTag(templateContents); 143 | if (templateTag != null) { 144 | String templateLabel = String.format("%s (embedded)", 145 | templateTag); 146 | System.err 147 | .println(String.format("Discovered template \"%s\": \"%s\": ", 148 | templateLabel, templateResourcePath)); 149 | synchronized (cache) { 150 | if (cache.containsKey(templateLabel)) { 151 | cache.replace(templateLabel, templateResourcePath); 152 | } else { 153 | cache.put(templateLabel, templateResourcePath); 154 | } 155 | } 156 | 157 | } 158 | } 159 | IOUtils.closeQuietly(inputStream); 160 | } 161 | } 162 | } catch (Exception e) { 163 | e.printStackTrace(); 164 | } 165 | } 166 | 167 | public String approxLookup(String templateTag) { 168 | Pattern pattern = Pattern.compile(Pattern.quote(templateTag), 169 | Pattern.CASE_INSENSITIVE); 170 | String matchedKey = null; 171 | for (String key : cache.keySet()) { 172 | Matcher matcher = pattern.matcher(key); 173 | if (matcher.find()) { 174 | matchedKey = key; 175 | } 176 | } 177 | return matchedKey; 178 | } 179 | 180 | public void clearCache() { 181 | cache.clear(); 182 | } 183 | 184 | public Object removeEntry(String tag) { 185 | return cache.remove(tag); 186 | } 187 | 188 | public String toString() { 189 | StringBuffer result = new StringBuffer(); 190 | for (String key : cache.keySet()) { 191 | result.append(key + ": " + cache.get(key)); 192 | result.append("\n"); 193 | } 194 | return result.toString(); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /run.cmd: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | SETLOCAL 3 | 4 | set SKIP_TEST=tue 5 | if "%TOOLS_DIR%"=="" set TOOLS_DIR=c:\java 6 | if "%JAVA_VERSION%"=="" set JAVA_VERSION=1.8.0_101 7 | if "%JAVA_HOME%"=="" set JAVA_HOME=%TOOLS_DIR%\jdk%JAVA_VERSION% 8 | set JAVA_OPTS=-Xms256m -Xmx512m 9 | if "%MAVEN_VERSION%"=="" set MAVEN_VERSION=3.6.1 10 | if "%M2_HOME%"=="" set M2_HOME=%TOOLS_DIR%\apache-maven-%MAVEN_VERSION% 11 | if "%M2%"=="" set M2=%M2_HOME%\bin 12 | set MAVEN_OPTS=-Xms256m -Xmx512m 13 | 14 | REM Clear the environment entry that is created by git bash when starting cmd and ruins Maven 3.5.0 ANSI colors. 15 | REM see also: https://issues.apache.org/jira/browse/MNG-6282 16 | REM See also: https://stackoverflow.com/questions/43425304/how-to-customize-colors-in-maven-3-5-console-output 17 | set TERM= 18 | 19 | PATH=%JAVA_HOME%\bin;%M2%;%PATH% 20 | 21 | set DEBUG=true 22 | set TARGET=target 23 | set VERBOSE=true 24 | 25 | set APP_NAME=swet 26 | set APP_VERSION=0.0.10-SNAPSHOT 27 | REM if "%APP_PACKAGE%"=="" set APP_PACKAGE=com.github.sergueik.swet 28 | set DEFAULT_MAIN_CLASS=SimpleToolBarEx 29 | set SCM_CONNECTION= 30 | 31 | call :CALL_JAVASCRIPT /project/artifactId 32 | set APP_NAME=%VALUE% 33 | 34 | if NOT "%APP_PACKAGE%"=="" goto :app_package_set_explicitly 35 | call :CALL_JAVASCRIPT /project/groupId 36 | set APP_PACKAGE=%VALUE% 37 | :app_package_set_explicitly 38 | 39 | call :CALL_JAVASCRIPT /project/version 40 | set APP_VERSION=%VALUE% 41 | 42 | call :CALL_JAVASCRIPT /project/properties/mainClass 43 | set DEFAULT_MAIN_CLASS=%VALUE% 44 | 45 | call :CALL_JAVASCRIPT /project/scm/connection 46 | set SCM_CONNECTION=%VALUE:scm:git:=% 47 | 48 | set APP_JAR=%APP_NAME%.jar 49 | 50 | if /i "%SKIP_PACKAGE_VERSION%"=="true" goto :SKIP_PACKAGE_VERSION 51 | set APP_JAR=%APP_NAME%-%APP_VERSION%.jar 52 | :SKIP_PACKAGE_VERSION 53 | 54 | REM Testing skipping the default jar 55 | REM origin: https://stackoverflow.com/questions/12809559/remove-jar-created-by-default-in-maven 56 | REM see also: https://www.cyberforum.ru/javafx/thread3059580.html 57 | REM TODO: scan the "pom.xml" for the presence of the "finalName" property (custom configuration) 58 | set APP_JAR=SWTsample.jar 59 | 60 | if /i NOT "%VERBOSE%"=="true" goto :CONTINUE 61 | 62 | call :SHOW_VARIABLE APP_VERSION 63 | call :SHOW_VARIABLE APP_NAME 64 | call :SHOW_VARIABLE APP_PACKAGE 65 | call :SHOW_VARIABLE APP_JAR 66 | call :SHOW_VARIABLE DEFAULT_MAIN_CLASS 67 | call :SHOW_VARIABLE SCM_CONNECTION 68 | 69 | :CONTINUE 70 | 71 | CALL :SHOW_LAST_ARGUMENT %* 72 | 73 | set CLEAN=%1 74 | 75 | if /i "%CLEAN%" EQU "clean" shift 76 | if /i "%DEBUG%" EQU "true" ( 77 | if /i "%CLEAN%" EQU "clean" echo >&2 CLEAN=%CLEAN% 78 | if "%ARGS_COUNT%" GEQ "1" echo >&2 ARG1=%1 79 | if "%ARGS_COUNT%" GEQ "2" echo >&2 ARG2=%2 80 | if "%ARGS_COUNT%" GEQ "3" echo >&2 ARG3=%3 81 | if "%ARGS_COUNT%" GEQ "4" echo >&2 ARG4=%4 82 | if "%ARGS_COUNT%" GEQ "5" echo >&2 ARG5=%5 83 | if "%ARGS_COUNT%" GEQ "6" echo >&2 ARG6=%6 84 | if "%ARGS_COUNT%" GEQ "7" echo >&2 ARG7=%7 85 | if "%ARGS_COUNT%" GEQ "8" echo >&2 ARG8=%8 86 | if "%ARGS_COUNT%" GEQ "9" echo >&2 ARG9=%9 87 | ) 88 | 89 | set MAIN_CLASS=%~1 90 | if NOT "%MAIN_CLASS%" == "" shift 91 | if "%MAIN_CLASS%"=="" set MAIN_CLASS=%DEFAULT_MAIN_CLASS% 92 | 93 | set APP_HOME=%CD:\=/% 94 | REM omit the extension - on different Windows 95 | REM will be mvn.bat or mvn.cmd 96 | 97 | if "%SKIP_TEST%"=="" ( 98 | REM Test 99 | call mvn test 2 > NUL 100 | ) else ( 101 | if /i NOT "%SKIP_BUILD%" == "true" ( 102 | REM Compile 103 | 104 | if /i "%CLEAN%" EQU "clean" ( 105 | ECHO "DO CLEAN" 106 | call mvn -Dmaven.test.skip=true clean package install 107 | ) else ( 108 | ECHO "DO INCREMENTAL" 109 | 110 | call mvn -Dmaven.test.skip=true package install 111 | ) 112 | ) 113 | ) 114 | REM Run 115 | REM NOTE: shift does not modify the %* 116 | REM The log4j configuration argument seems to be ignored 117 | REM -Dlog4j.configuration=file:///%APP_HOME%/src/main/resources/log4j.properties ^ 118 | set COMMAND=^ 119 | java ^ 120 | -cp %TARGET%\%APP_JAR%;%TARGET%\lib\* ^ 121 | %APP_PACKAGE%.%MAIN_CLASS% ^ 122 | %1 %2 %3 %4 %5 %6 %7 %8 %9 123 | echo %COMMAND%>&2 124 | %COMMAND% 125 | ENDLOCAL 126 | exit /b 127 | 128 | :CALL_JAVASCRIPT 129 | 130 | REM This script extracts project g.a.v a custom property from pom.xml using mshta.exe and DOM selectSingleNode method 131 | set "SCRIPT=javascript:{" 132 | set "SCRIPT=%SCRIPT% var fso = new ActiveXObject('Scripting.FileSystemObject');" 133 | set "SCRIPT=%SCRIPT% var out = fso.GetStandardStream(1);" 134 | set "SCRIPT=%SCRIPT% var fh = fso.OpenTextFile('pom.xml', 1, true);" 135 | set "SCRIPT=%SCRIPT% var xd = new ActiveXObject('Msxml2.DOMDocument');" 136 | set "SCRIPT=%SCRIPT% xd.async = false;" 137 | set "SCRIPT=%SCRIPT% data = fh.ReadAll();" 138 | set "SCRIPT=%SCRIPT% xd.loadXML(data);" 139 | set "SCRIPT=%SCRIPT% root = xd.documentElement;" 140 | set "SCRIPT=%SCRIPT% var xpath = '%~1';" 141 | set "SCRIPT=%SCRIPT% var xmlnode = root.selectSingleNode( xpath);" 142 | set "SCRIPT=%SCRIPT% if (xmlnode != null) {" 143 | set "SCRIPT=%SCRIPT% out.Write(xpath + '=' + xmlnode.text);" 144 | set "SCRIPT=%SCRIPT% } else {" 145 | set "SCRIPT=%SCRIPT% out.Write('ERR');" 146 | set "SCRIPT=%SCRIPT% }" 147 | set "SCRIPT=%SCRIPT% close();}" 148 | 149 | for /F "tokens=2 delims==" %%_ in ('mshta.exe "%SCRIPT%" 1 ^| more') do set VALUE=%%_ 150 | ENDLOCAL 151 | exit /b 152 | 153 | 154 | :SHOW_VARIABLE 155 | SETLOCAL ENABLEDELAYEDEXPANSION 156 | set VAR=%1 157 | if /i "%DEBUG%"=="true" echo>&2 VAR=!VAR! 158 | set RESULT=!VAR! 159 | call :SHOW_VARIABLE_VALUE !%VAR%! 160 | set RESULT=!RESULT!="!DATA!" 161 | echo>&2 !RESULT! 162 | ENDLOCAL 163 | goto :EOF 164 | 165 | :SHOW_VARIABLE_VALUE 166 | set VAL=%1 167 | if /i "%DEBUG%"=="true" echo>&2 %1 168 | set DATA=%VAL% 169 | if /i "%DEBUG%"=="true" echo>&2 VALUE=%VAL% 170 | goto :EOF 171 | 172 | 173 | :SHOW_LAST_ARGUMENT 174 | REM https://stackoverflow.com/questions/1291941/batch-files-number-of-command-line-arguments 175 | set /A ARGS_COUNT=0 176 | for %%_ in (%*) DO SET /A ARGS_COUNT+=1 177 | if /i "%DEBUG%"=="true" echo>&2 The number of arguments is %ARGS_COUNT% 178 | REM the following does not work 179 | SETLOCAL ENABLEDELAYEDEXPANSION 180 | for /F "tokens=*" %%_ in ('echo %%!ARGS_COUNT!') DO set P=%%_ 181 | if /i "%DEBUG%"=="true" echo P=%P% 182 | call :SHOW_VARIABLE_VALUE !P! 183 | set CLEAN=%VALUE% 184 | REM the value disappears after ENDLOCAL 185 | ENDLOCAL 186 | goto :EOF 187 | -------------------------------------------------------------------------------- /src/main/java/custom/swt/widgets/SWTUtil.java: -------------------------------------------------------------------------------- 1 | package custom.swt.widgets; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.SWTException; 5 | import org.eclipse.swt.events.ShellEvent; 6 | import org.eclipse.swt.events.ShellListener; 7 | import org.eclipse.swt.graphics.Point; 8 | import org.eclipse.swt.graphics.Rectangle; 9 | import org.eclipse.swt.widgets.Composite; 10 | import org.eclipse.swt.widgets.Control; 11 | import org.eclipse.swt.widgets.Display; 12 | import org.eclipse.swt.widgets.Monitor; 13 | import org.eclipse.swt.widgets.Shell; 14 | 15 | public class SWTUtil { 16 | 17 | // ==[ Event Loop 18 | // ]================================================================================== 19 | 20 | // Main Event Loop for an application that terminates once the associated 21 | // Display is disposed 22 | public static void eventLoop() { 23 | Display dsp = getDisplay(); 24 | while (!dsp.isDisposed()) { 25 | if (!dsp.readAndDispatch()) 26 | dsp.sleep(); 27 | } 28 | } 29 | 30 | // Event Loop that terminates once the given shell is disposed (and optionally 31 | // also disposes the display) 32 | public static void eventLoop(Shell shell, boolean dispose) { 33 | Display dsp = getDisplay(); 34 | while (!shell.isDisposed()) 35 | if (!dsp.readAndDispatch()) 36 | dsp.sleep(); 37 | if (dispose) 38 | dsp.dispose(); 39 | } 40 | 41 | // Event Loop that terminates the application if the given shell is disposed 42 | public static void eventLoop(Shell shell) { 43 | eventLoop(shell, true); 44 | } 45 | 46 | // Temporary Event Loop for Dialogs... doesn't dispose the entire application 47 | // once shell closes 48 | public static void dialogLoop(Shell shell) { 49 | eventLoop(shell, false); 50 | } 51 | 52 | ///// Private helper 53 | 54 | // Get current display ( throw an exception if the current thread is not the 55 | // UI thread ) 56 | private static Display getDisplay() { 57 | Display dsp = Display.getCurrent(); 58 | if (dsp == null) 59 | new SWTException(SWT.ERROR_THREAD_INVALID_ACCESS); 60 | return dsp; 61 | } 62 | 63 | // ==[ Center Shell 64 | // ]================================================================================ 65 | 66 | // Set shell dimensions and center the shell on the current monitor 67 | public static void center(Shell shell, int width, int height) { 68 | shell.setSize(width, height); 69 | center(shell); 70 | } 71 | 72 | // Set shell dimensions and center the shell over its parent 73 | public static void center(Shell parent, Shell child, int width, int height) { 74 | child.setSize(width, height); 75 | center(parent, child); 76 | } 77 | 78 | // Center the shell on the current monitor 79 | public static void center(Shell shell) { 80 | center(shell, 0.5, 0.5); 81 | } 82 | 83 | public static void center(Shell shell, double xfrac, double yfrac) { 84 | Display dsp = shell.getDisplay(); 85 | Rectangle monitorBounds = getCurrentMonitorBounds(dsp); 86 | center(monitorBounds, shell, xfrac, yfrac); 87 | } 88 | 89 | // Center the shell over its parent 90 | public static void center(Composite parent, Shell child) { 91 | center(parent, child, 0.5, 0.5); 92 | } 93 | 94 | public static void center(Composite parent, Shell child, double xfrac, 95 | double yfrac) { 96 | Display dsp = child.getDisplay(); 97 | Rectangle region = parent.isVisible() ? parent.getBounds() 98 | : getCurrentMonitorBounds(dsp); 99 | center(region, child, xfrac, yfrac); 100 | } 101 | 102 | ///// Private Helper 103 | 104 | // Center the shell over the given region 105 | private static void center(Rectangle region, Shell shell, double xfrac, 106 | double yfrac) { 107 | Rectangle s_bounds = shell.getBounds(); 108 | 109 | // System.out.println("Center: " + s_bounds); 110 | // System.out.println("Over: " + region); 111 | 112 | // int x = region.x + (region.width - s_bounds.width) / 2; 113 | // int y = region.y + (region.height - s_bounds.height) / 2; 114 | 115 | int x = region.x 116 | + (int) Math.round((region.width - s_bounds.width) * xfrac); 117 | int y = region.y 118 | + (int) Math.round((region.height - s_bounds.height) * yfrac); 119 | 120 | shell.setLocation(x, y); 121 | } 122 | 123 | // Retrieve the current monitor (via the mouse cursor location) 124 | private static Rectangle getCurrentMonitorBounds(Display dsp) { 125 | Monitor monitor = dsp.getPrimaryMonitor(); 126 | 127 | // Choose current Monitor 128 | Point cursor = dsp.getCursorLocation(); 129 | Monitor[] monitors = dsp.getMonitors(); 130 | for (Monitor mon : monitors) { 131 | Rectangle mbounds = mon.getBounds(); 132 | if (mbounds.contains(cursor)) { 133 | monitor = mon; 134 | break; 135 | } 136 | } 137 | 138 | return monitor.getBounds(); 139 | } 140 | 141 | // ==[ Pack Widget in only one dimension 142 | // ]=========================================================== 143 | 144 | public static void packWidth(Control control) { 145 | Point prefSize = control.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); 146 | Point currSize = control.getSize(); 147 | control.setSize(prefSize.x, currSize.y); 148 | } 149 | 150 | public static void packHeight(Control control) { 151 | Point prefSize = control.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); 152 | Point currSize = control.getSize(); 153 | control.setSize(currSize.x, prefSize.y); 154 | } 155 | 156 | public static void pack(Control control, int minWidth, int minHeight) { 157 | Point prefSize = control.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); 158 | if (prefSize.x < minWidth) 159 | prefSize.x = minWidth; 160 | if (prefSize.y < minHeight) 161 | prefSize.y = minHeight; 162 | control.setSize(prefSize.x, prefSize.y); 163 | } 164 | 165 | // ==[ Automatically Dispose App on Shell Exit 166 | // ]===================================================== 167 | 168 | // Dispose the associated Display when the given shell is closed (adds a 169 | // ShellListener) 170 | public static void exitOnClose(Shell shell) { 171 | shell.addShellListener(new ShellListener() { 172 | @Override 173 | public void shellActivated(ShellEvent event) { 174 | } 175 | 176 | @Override 177 | public void shellClosed(ShellEvent event) { 178 | Display dsp = shell.getDisplay(); 179 | if (dsp != null) 180 | dsp.dispose(); 181 | } 182 | 183 | @Override 184 | public void shellDeactivated(ShellEvent arg0) { 185 | } 186 | 187 | @Override 188 | public void shellDeiconified(ShellEvent arg0) { 189 | } 190 | 191 | @Override 192 | public void shellIconified(ShellEvent arg0) { 193 | } 194 | 195 | }); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /run2.cmd: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | SETLOCAL 3 | 4 | set SKIP_TEST=tue 5 | if "%TOOLS_DIR%"=="" set TOOLS_DIR=c:\java 6 | if "%JAVA_VERSION%"=="" set JAVA_VERSION=1.8.0_101 7 | if "%JAVA_HOME%"=="" set JAVA_HOME=%TOOLS_DIR%\jdk%JAVA_VERSION% 8 | set JAVA_OPTS=-Xms256m -Xmx512m 9 | if "%MAVEN_VERSION%"=="" set MAVEN_VERSION=3.6.1 10 | if "%M2_HOME%"=="" set M2_HOME=%TOOLS_DIR%\apache-maven-%MAVEN_VERSION% 11 | if "%M2%"=="" set M2=%M2_HOME%\bin 12 | set MAVEN_OPTS=-Xms256m -Xmx512m 13 | 14 | REM Clear the environment entry that is created by git bash when starting cmd and ruins Maven 3.5.0 ANSI colors. 15 | REM see also: https://issues.apache.org/jira/browse/MNG-6282 16 | REM See also: https://stackoverflow.com/questions/43425304/how-to-customize-colors-in-maven-3-5-console-output 17 | set TERM= 18 | 19 | PATH=%JAVA_HOME%\bin;%M2%;%PATH% 20 | 21 | set DEBUG=true 22 | set TARGET=target 23 | set VERBOSE=true 24 | 25 | set APP_NAME=swet 26 | set APP_VERSION=0.0.10-SNAPSHOT 27 | REM if "%APP_PACKAGE%"=="" set APP_PACKAGE=com.github.sergueik.swet 28 | set DEFAULT_MAIN_CLASS=SimpleToolBarEx 29 | set SCM_CONNECTION= 30 | 31 | call :CALL_JAVASCRIPT /project/artifactId VALUE1 32 | set APP_NAME=%VALUE1% 33 | 34 | if NOT "%APP_PACKAGE%"=="" goto :app_package_set_explicitly 35 | call :CALL_JAVASCRIPT /project/groupId VALUE2 36 | set APP_PACKAGE=%VALUE2% 37 | :app_package_set_explicitly 38 | 39 | call :CALL_JAVASCRIPT /project/version VALUE3 40 | set APP_VERSION=%VALUE3% 41 | 42 | call :CALL_JAVASCRIPT /project/properties/mainClass VALUE4 43 | set DEFAULT_MAIN_CLASS=%VALUE4% 44 | 45 | call :CALL_JAVASCRIPT /project/scm/connection VALUE5 46 | set SCM_CONNECTION=%VALUE5:scm:git:=% 47 | 48 | 49 | call :CALL_JAVASCRIPT /project/build/plugins/plugin/configuration/finalName VALUE6 50 | set FINALNAME=%VALUE6:"=% 51 | REM TODO: detect variable interpolation and give up 52 | 53 | set APP_JAR=%APP_NAME%.jar 54 | 55 | if /i "%SKIP_PACKAGE_VERSION%"=="true" goto :SKIP_PACKAGE_VERSION 56 | set APP_JAR=%APP_NAME%-%APP_VERSION%.jar 57 | :SKIP_PACKAGE_VERSION 58 | 59 | REM Testing skipping the default jar 60 | REM origin: https://stackoverflow.com/questions/12809559/remove-jar-created-by-default-in-maven 61 | REM see also: https://www.cyberforum.ru/javafx/thread3059580.html 62 | REM TODO: scan the "pom.xml" for the presence of the "finalName" property (custom configuration) 63 | if NOT "%FINALNAME%" == "" set APP_JAR=%FINALNAME%.jar 64 | 65 | if /i NOT "%VERBOSE%"=="true" goto :CONTINUE 66 | 67 | call :SHOW_VARIABLE APP_VERSION 68 | call :SHOW_VARIABLE APP_NAME 69 | call :SHOW_VARIABLE APP_PACKAGE 70 | call :SHOW_VARIABLE APP_JAR 71 | call :SHOW_VARIABLE DEFAULT_MAIN_CLASS 72 | call :SHOW_VARIABLE SCM_CONNECTION 73 | call :SHOW_VARIABLE FINALNAME 74 | 75 | :CONTINUE 76 | 77 | CALL :SHOW_LAST_ARGUMENT %* 78 | 79 | set CLEAN=%1 80 | 81 | if /i "%CLEAN%" EQU "clean" shift 82 | if /i "%DEBUG%" EQU "true" ( 83 | if /i "%CLEAN%" EQU "clean" echo >&2 CLEAN=%CLEAN% 84 | if "%ARGS_COUNT%" GEQ "1" echo >&2 ARG1=%1 85 | if "%ARGS_COUNT%" GEQ "2" echo >&2 ARG2=%2 86 | if "%ARGS_COUNT%" GEQ "3" echo >&2 ARG3=%3 87 | if "%ARGS_COUNT%" GEQ "4" echo >&2 ARG4=%4 88 | if "%ARGS_COUNT%" GEQ "5" echo >&2 ARG5=%5 89 | if "%ARGS_COUNT%" GEQ "6" echo >&2 ARG6=%6 90 | if "%ARGS_COUNT%" GEQ "7" echo >&2 ARG7=%7 91 | if "%ARGS_COUNT%" GEQ "8" echo >&2 ARG8=%8 92 | if "%ARGS_COUNT%" GEQ "9" echo >&2 ARG9=%9 93 | ) 94 | 95 | set MAIN_CLASS=%~1 96 | if NOT "%MAIN_CLASS%" == "" shift 97 | if "%MAIN_CLASS%"=="" set MAIN_CLASS=%DEFAULT_MAIN_CLASS% 98 | 99 | set APP_HOME=%CD:\=/% 100 | REM omit the extension - on different Windows 101 | REM will be mvn.bat or mvn.cmd 102 | 103 | if "%SKIP_TEST%"=="" ( 104 | REM Test 105 | call mvn test 2 > NUL 106 | ) else ( 107 | if /i NOT "%SKIP_BUILD%" == "true" ( 108 | REM Compile 109 | 110 | if /i "%CLEAN%" EQU "clean" ( 111 | ECHO "DO CLEAN" 112 | call mvn -Dmaven.test.skip=true clean package install 113 | ) else ( 114 | ECHO "DO INCREMENTAL" 115 | 116 | call mvn -Dmaven.test.skip=true package install 117 | ) 118 | ) 119 | ) 120 | REM Run 121 | REM NOTE: shift does not modify the %* 122 | REM The log4j configuration argument seems to be ignored 123 | REM -Dlog4j.configuration=file:///%APP_HOME%/src/main/resources/log4j.properties ^ 124 | set COMMAND=^ 125 | java ^ 126 | -cp %TARGET%\%APP_JAR%;%TARGET%\lib\* ^ 127 | %APP_PACKAGE%.%MAIN_CLASS% ^ 128 | %1 %2 %3 %4 %5 %6 %7 %8 %9 129 | echo %COMMAND%>&2 130 | %COMMAND% 131 | ENDLOCAL 132 | exit /b 133 | 134 | :CALL_JAVASCRIPT 135 | 136 | REM This script extracts project g.a.v a custom property from pom.xml using mshta.exe and DOM selectSingleNode method 137 | set "SCRIPT=javascript:{" 138 | set "SCRIPT=%SCRIPT% var fso = new ActiveXObject('Scripting.FileSystemObject');" 139 | set "SCRIPT=%SCRIPT% var out = fso.GetStandardStream(1);" 140 | set "SCRIPT=%SCRIPT% var fh = fso.OpenTextFile('pom.xml', 1, true);" 141 | set "SCRIPT=%SCRIPT% var xd = new ActiveXObject('Msxml2.DOMDocument');" 142 | set "SCRIPT=%SCRIPT% xd.async = false;" 143 | set "SCRIPT=%SCRIPT% data = fh.ReadAll();" 144 | set "SCRIPT=%SCRIPT% xd.loadXML(data);" 145 | set "SCRIPT=%SCRIPT% root = xd.documentElement;" 146 | set "SCRIPT=%SCRIPT% var xpath = '%~1';" 147 | set "SCRIPT=%SCRIPT% var xmlnode = root.selectSingleNode( xpath);" 148 | set "SCRIPT=%SCRIPT% if (xmlnode != null) {" 149 | set "SCRIPT=%SCRIPT% out.Write(xpath + '=' + xmlnode.text);" 150 | set "SCRIPT=%SCRIPT% } else {" 151 | set "SCRIPT=%SCRIPT% out.Write('ERR');" 152 | set "SCRIPT=%SCRIPT% }" 153 | set "SCRIPT=%SCRIPT% close();}" 154 | 155 | for /F "tokens=2 delims==" %%_ in ('mshta.exe "%SCRIPT%" 1 ^| more') do set "%2=%%_" 156 | ENDLOCAL 157 | exit /b 158 | 159 | 160 | :SHOW_VARIABLE 161 | SETLOCAL ENABLEDELAYEDEXPANSION 162 | set VAR=%1 163 | if /i "%DEBUG%"=="true" echo>&2 VAR=!VAR! 164 | set RESULT=!VAR! 165 | call :SHOW_VARIABLE_VALUE !%VAR%! 166 | set RESULT=!RESULT!="!DATA!" 167 | echo>&2 !RESULT! 168 | ENDLOCAL 169 | goto :EOF 170 | 171 | :SHOW_VARIABLE_VALUE 172 | set VAL=%1 173 | if /i "%DEBUG%"=="true" echo>&2 %1 174 | set DATA=%VAL% 175 | if /i "%DEBUG%"=="true" echo>&2 VALUE=%VAL% 176 | goto :EOF 177 | 178 | 179 | :SHOW_LAST_ARGUMENT 180 | REM https://stackoverflow.com/questions/1291941/batch-files-number-of-command-line-arguments 181 | set /A ARGS_COUNT=0 182 | for %%_ in (%*) DO SET /A ARGS_COUNT+=1 183 | if /i "%DEBUG%"=="true" echo>&2 The number of arguments is %ARGS_COUNT% 184 | REM the following does not work 185 | SETLOCAL ENABLEDELAYEDEXPANSION 186 | for /F "tokens=*" %%_ in ('echo %%!ARGS_COUNT!') DO set P=%%_ 187 | if /i "%DEBUG%"=="true" echo P=%P% 188 | call :SHOW_VARIABLE_VALUE !P! 189 | set CLEAN=%VALUE% 190 | REM the value disappears after ENDLOCAL 191 | ENDLOCAL 192 | goto :EOF 193 | --------------------------------------------------------------------------------