{"id":20713860,"url":"https://github.com/diffplug/durian-swt","last_synced_at":"2025-08-06T16:34:09.145Z","repository":{"id":32760677,"uuid":"36352008","full_name":"diffplug/durian-swt","owner":"diffplug","description":"Reactive utilities and fluent builders for SWT","archived":false,"fork":false,"pushed_at":"2024-07-05T03:24:33.000Z","size":10976,"stargazers_count":31,"open_issues_count":6,"forks_count":4,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-12-12T17:12:10.655Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diffplug.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2015-05-27T07:54:16.000Z","updated_at":"2024-11-26T19:44:19.000Z","dependencies_parsed_at":"2023-02-12T05:00:33.998Z","dependency_job_id":"b02a2d3c-08c0-4cb8-9943-c883ca6821d1","html_url":"https://github.com/diffplug/durian-swt","commit_stats":null,"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diffplug%2Fdurian-swt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diffplug%2Fdurian-swt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diffplug%2Fdurian-swt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diffplug%2Fdurian-swt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diffplug","download_url":"https://codeload.github.com/diffplug/durian-swt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230561014,"owners_count":18245324,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T02:27:48.728Z","updated_at":"2025-08-06T16:34:09.121Z","avatar_url":"https://github.com/diffplug.png","language":"Java","readme":"# \u003cimg align=\"left\" src=\"durian-swt.png\"\u003e DurianSwt: Reactive utilities and fluent builders for SWT\n\n\u003c!---freshmark shields\noutput = [\n    link(shield('Maven central', 'mavencentral', 'com.diffplug.durian:durian-swt', 'blue'), 'https://search.maven.org/artifact/com.diffplug.durian/durian-swt'),\n    link(shield('Apache 2.0', 'license', 'apache-2.0', 'blue'), 'https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)'),\n    '',\n    link(shield('Changelog', 'changelog', versionLast, 'brightgreen'), 'CHANGES.md'),\n    link(shield('Javadoc', 'javadoc', 'yes', 'brightgreen'), 'https://javadoc.io/static/com.diffplug.durian/durian-swt/{{versionLast}}/overview-summary.html'),\n    link(shield('Live chat', 'gitter', 'chat', 'brightgreen'), 'https://gitter.im/diffplug/durian'),\n    link(image('Travis CI', 'https://travis-ci.org/diffplug/durian-swt.svg?branch=master'), 'https://travis-ci.org/diffplug/durian-swt'),\n    ].join('\\n');\n--\u003e\n[![Maven central](https://img.shields.io/badge/mavencentral-com.diffplug.durian%3Adurian--swt-blue.svg)](https://search.maven.org/artifact/com.diffplug.durian/durian-swt)\n[![Apache 2.0](https://img.shields.io/badge/license-apache--2.0-blue.svg)](https://tldrlegal.com/license/apache-license-2.0-(apache-2.0))\n\n[![Changelog](https://img.shields.io/badge/changelog-5.0.1-brightgreen.svg)](CHANGES.md)\n[![Javadoc](https://img.shields.io/badge/javadoc-yes-brightgreen.svg)](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/overview-summary.html)\n[![Live chat](https://img.shields.io/badge/gitter-chat-brightgreen.svg)](https://gitter.im/diffplug/durian)\n[![Travis CI](https://travis-ci.org/diffplug/durian-swt.svg?branch=master)](https://travis-ci.org/diffplug/durian-swt)\n\u003c!---freshmark /shields --\u003e\n\n\u003c!---freshmark javadoc\noutput = prefixDelimiterReplace(input, 'https://javadoc.io/static/com.diffplug.durian/durian-swt/', '/', versionLast);\n--\u003e\n### Infrastructure\n\n* [`ControlWrapper`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/ControlWrapper.html) - create custom widgets which properly encapsulate their base control.\n* [`Coat`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/Coat.html) - a functional interface for populating an empty Composite.\n* [`CoatMux`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/CoatMux.html) - a mechanism for layering and swapping Coats.\n* [`SwtExec`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/SwtExec.html) - an `ExecutorService` which executes on the SWT thread.\n* [`SwtExec.Guarded`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/SwtExec.Guarded.html) - an `ExecutorService` which is tied to the lifetime of an SWT widget. Say goodbye to `SWTException: Widget is disposed` forever! It can also subscribe to any kind of observable (Guava's ListenableFuture or RxJava's Observable), see [DurianRx](https://github.com/diffplug/durian-rx) for more info.\n\n```java\nSwtExec.async().guardOn(textBox).subscribe(serverResponse, txt -\u003e {\n  textBox.setText(txt);\n});\n```\n\n### Fluent builders\n\n* [`Layouts`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/Layouts.html) - all the layouts you'll need in SWT\n\n```java\nvoid textOkCanel(Composite cmp) {\n  Layouts.setGrid(cmp).numColumns(3);\n\n  // instructions fill the full width\n  Text text = new Text(cmp, SWT.WRAP);\n  Layouts.setGridData(text).horizontalSpan(3).grabAll();\n\n  // right-justified ok / cancel buttons\n  Layouts.newGridPlaceholder(cmp).grabHorizontal();\n  Button btnOk = new Button(cmp, SWT.PUSH);\n  Layouts.setGridData(btn).widthHint(SwtMisc.defaultButtonWidth());\n  Button btnCancel = new Button(cmp, SWT.PUSH);\n  Layouts.setGridData(btn).widthHint(SwtMisc.defaultButtonWidth());\n}\n```\n\n* [`Shells`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/Shells.html) - dialogs without boilerplate\n\n```java\nShells.builder(SWT.DIALOG_TRIM, this::textOkCanel)\n  .setTitle(\"Confirm operation\")\n  .setSize(SwtMisc.defaultDialogWidth(), 0) // set the width, pack height to fit contents\n  .openOnDisplayBlocking();\n```\n\n* [`Actions`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/jface/Actions.html) - builder and one-liner:\n`Actions.create(\"Redo\", this::redo);`\n\n* [`LabelProviders`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/jface/LabelProviders.html) - builder and one-liner:\n`LabelProviders.createWithText(Person::getName)`\n\n* [`ColumnFormat`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/ColumnFormat.html) and [`ColumnViewerFormat`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/jface/ColumnViewerFormat.html) - tables and trees without boilerplate\n\n```java\nColumnViewerFormat\u003cPerson\u003e format = ColumnViewerFormat.builder();\nformat.setStyle(SWT.SINGLE | SWT.FULL_SELECTION);\nformat.addColumn().setText(\"First\").setLabelProviderText(Person::getFirstName);\nformat.addColumn().setText(\"Last\").setLabelProviderText(Person::getLastName);\nformat.addColumn().setText(\"Age\").setLabelProviderText(p -\u003e Integer.toString(p.getAge())).setLayoutPixel(3 * SwtMisc.systemFontWidth());\nTableViewer table = format.buildTable(parent);\nTreeViewer tree = format.buildTree(parent);\n```\n\n### Resource management\n\n* [`OnePerWidget`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/OnePerWidget.html) - a cache tied to the lifetime of an SWT Widget.\n* [`ColorPool`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/ColorPool.html) - a pool of colors tied to the lifetime of a widget. `ColorPool.forWidget(widget).getColor(rgbValue)`\n* [`ImageDescriptors`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/jface/ImageDescriptors.html) - use ImageDescriptors with proper resource sharing. `ImageDescriptors.set(btn, imageDescriptor)`\n\n### Interactive testing\n\nIdeally, all UI code would have fully automated UI testing, but\nsuch tests are time-consuming to write, so they often just don't\nget written at all. [`InteractiveTest`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/InteractiveTest.html)\nbridges the gap by making it easy to write user-in-the-loop guided tests. Furthermore,\nthese tests can even be run in a [headless enviroment on a CI server](https://github.com/diffplug/durian-swt/blob/master/build.gradle#L66-L93), where the test UI\nwill be opened, then automatically closed after a timeout.  This ensures that the tests\nare all in working order and ready for a human tester to do final validation.\n\n![InteractiveTest](interactive-test.png)\n\nFrom [`ViewerMiscTest.java`](https://github.com/diffplug/durian-swt/blob/master/test/com/diffplug/common/swt/jface/ViewerMiscTest.java):\n\n```java\nString message = StringPrinter.buildStringFromLines(\n  \"- The table and the tree should keep their selection in sync.\",\n  \"- The table and the tree should not allow multi-selection.\",\n  \"- The categories in the tree should not be selectable.\");\nInteractiveTest.testCoat(message, cmp -\u003e {\n  TableAndTree tableAndTree = new TableAndTree(cmp, SWT.SINGLE);\n\n  // get the selection of the tree\n  RxBox\u003cOptional\u003cTreeNode\u003cString\u003e\u003e\u003e treeSelection = ViewerMisc.\u003cTreeNode\u003cString\u003e\u003e singleSelection(tableAndTree.tree)\n      // only names can be selected - not categories\n      .enforce(opt -\u003e opt.map(val -\u003e isName(val) ? val : null));\n\n  // sync the tree and the table\n  RxOptional\u003cTreeNode\u003cString\u003e\u003e tableSelection = ViewerMisc.singleSelection(tableAndTree.table);\n  Rx.subscribe(treeSelection, tableSelection::set);\n  Rx.subscribe(tableSelection, treeSelection::set);\n});\n```\n\n### Miscellaneous stuff\n\n* [`SwtMisc`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/SwtMisc.html) - useful static methods.\n  + `blockForError`, `blockForSuccess`, `blockForQuestion`, etc. - opens a dialog and blocks for the user's response, can be called from any thread.\n  + `loopUntil`, `loopUntilDisposed`, `loopUntilGet` - spins the SWT display loop until some condition is satisfied.\n  + `systemFontHeight/Width`, `scaleByFont`, `scaleByFontHeight` - resolution-independent sizes.\n  + `treeDefControl`, `treeDefComposite` - a [`TreeDef`](http://diffplug.github.io/durian/javadoc/snapshot/com/diffplug/common/base/TreeDef.html) for traversing UI elements.\n  + `setEnabledDeep` - sets the enabled status of every child, grandchild, etc. of the given composite.\n* [`SwtRx`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/SwtRx.html) - methods for converting SWT events and models to RxJava Observables.\n* [`SwtDebug`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/SwtDebug.html) - utilities for debugging SWT events.\n* [`OS`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/os/OS.html), [`Arch`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/os/Arch.html), and [`SwtPlatform`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/os/SwtPlatform.html) - detect things about the running system, and manipulate the SWT jars for build tools.\n  + These do not require SWT or JFace, so you can add DurianSwt to your gradle or maven dependencies without needing to also figure out the SWT messiness.\n  + You can also just copy-paste these straight into your own code - they have no external dependencies.\n```java\nString installerExtension = OS.getNative().winMacLinux(\"exe\",\"dmg\",\"sh\");\nString helperBinary = \"driver_\" + Arch.getNative().x86x64(\"\", \"_64\") + \".dll\";\nString swtJarName = \"org.eclipse.swt.\" + SwtPlatform.getRunning();\n```\n* [`ViewerMisc`](https://javadoc.io/static/com.diffplug.durian/durian-swt/5.0.1/com/diffplug/common/swt/jface/ViewerMisc.html) - useful static methods for JFace viewers.\n  + `singleSelection`, `multiSelection` - returns an RxBox for listening to and setting the selection of a viewer.\n  + `setTreeContentProvider`, `setLazyTreeContentProvider` - uses a TreeDef to provide the content of a TreeViewer.\n\n\u003c!---freshmark /javadoc --\u003e\n\n## Requirements\n\nDurian requires:\n* Java 8\n* [Durian](https://github.com/diffplug/durian) and [DurianRx](https://github.com/diffplug/durian-rx)\n* [Guava](https://github.com/google/guava) and [RxJava](https://github.com/reactivex/rxjava)\n* SWT and JFace from Eclipse 4.4+\n  + SWT and JFace are not included in the Maven POM, but everything else is.\n\n## Acknowledgements\n\n* Thanks to [David Karnok](https://akarnokd.blogspot.com/) for [contributing an SwtScheduler that honors the Scheduler/Worker contracts](https://github.com/diffplug/durian-swt/pull/1).\n* Thanks to Moritz Post for his [fluent layout idea](http://eclipsesource.com/blogs/2013/07/25/efficiently-dealing-with-swt-gridlayout-and-griddata/).\n* Formatted by [spotless](https://github.com/diffplug/spotless), [as such](https://github.com/diffplug/durian-rx/blob/v1.0/build.gradle?ts=4#L70-L90).\n* Bugs found by [findbugs](http://findbugs.sourceforge.net/), [as such](https://github.com/diffplug/durian-rx/blob/v1.0/build.gradle?ts=4#L92-L116).\n* OSGi metadata generated by JRuyi's [osgibnd-gradle-plugin] (https://github.com/jruyi/osgibnd-gradle-plugin), which leverages Peter Kriens' [bnd](http://www.aqute.biz/Bnd/Bnd).\n* Scripts in the `.ci` folder are inspired by [Ben Limmer's work](http://benlimmer.com/2013/12/26/automatically-publish-javadoc-to-gh-pages-with-travis-ci/).\n* Built by [gradle](http://gradle.org/).\n* Tested by [junit](http://junit.org/).\n* Maintained by [DiffPlug](http://www.diffplug.com/).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiffplug%2Fdurian-swt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiffplug%2Fdurian-swt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiffplug%2Fdurian-swt/lists"}