Reactive utilities and fluent builders for SWT
Clone or download
Permalink
Failed to load latest commit information.
.ci Fixed durian-swt javadoc publishing. Jun 10, 2016
META-INF Bump gradle 4.7 to 4.9 Jul 21, 2018
durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/widgets Delete all the MANIFEST.MF and keep it out of git. Aug 1, 2018
durian-swt.gtk.linux.x86/src/main/java/com/diffplug/common/swt/widgets Delete all the MANIFEST.MF and keep it out of git. Aug 1, 2018
durian-swt.gtk.linux.x86_64/src/main/java/com/diffplug/common/swt/widgets Delete all the MANIFEST.MF and keep it out of git. Aug 1, 2018
durian-swt.os/src Delete all the MANIFEST.MF and keep it out of git. Aug 1, 2018
durian-swt.win32.win32.x86/src/main/java/com/diffplug/common/swt/widgets Delete all the MANIFEST.MF and keep it out of git. Aug 1, 2018
durian-swt.win32.win32.x86_64/src/main/java/com/diffplug/common/swt/widgets Delete all the MANIFEST.MF and keep it out of git. Aug 1, 2018
durian-swt Reduced noise in `InteractiveTest` failures. Nov 9, 2018
gradle Bump copyright to 2018. Aug 1, 2018
.gitattributes Added .gitattributes Jul 23, 2018
.gitignore Delete all the MANIFEST.MF and keep it out of git. Aug 1, 2018
.travis.yml Improved travis caching. Aug 19, 2016
CHANGES.md Reduced noise in `InteractiveTest` failures. Nov 9, 2018
CONTRIBUTING.md Improved the README format. May 28, 2015
LICENSE Scaffolding for durian.swt. Apr 26, 2015
README.md Bump to 3.1.0-SNAPSHOT Aug 1, 2018
build.gradle Fix gradle deprecation warnings. Aug 1, 2018
durian-swt.png move to other computer May 16, 2015
durian.svg Scaffolding for durian.swt. Apr 26, 2015
durian.svg.license Scaffolding for durian.swt. Apr 26, 2015
gradle.properties Bump to 3.1.0-SNAPSHOT Aug 1, 2018
gradlew Gradle 3.5 -> 4.0.1 Jul 14, 2017
gradlew.bat Bump to gradle 3.5 Apr 11, 2017
interactive-test.png Big update to Durian SWT's docs. Jun 25, 2015
settings.gradle Set root project to have a different name than any subproject to fix … Sep 11, 2018

README.md

DurianSwt: Reactive utilities and fluent builders for SWT

Maven artifact Latest version Javadoc License Apache

Changelog Travis CI Live chat

Infrastructure

  • ControlWrapper - create custom widgets which properly encapsulate their base control.
  • Coat - a functional interface for populating an empty Composite.
  • CoatMux - a mechanism for layering and swapping Coats.
  • SwtExec - an ExecutorService which executes on the SWT thread.
  • SwtExec.Guarded - 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 for more info.
SwtExec.async().guardOn(textBox).subscribe(serverResponse, txt -> {
	textBox.setText(txt);
});

Fluent builders

  • Layouts - all the layouts you'll need in SWT
void textOkCanel(Composite cmp) {
	Layouts.setGrid(cmp).numColumns(3);

	// instructions fill the full width
	Text text = new Text(cmp, SWT.WRAP);
	Layouts.setGridData(text).horizontalSpan(3).grabAll();

	// right-justified ok / cancel buttons
	Layouts.newGridPlaceholder(cmp).grabHorizontal();
	Button btnOk = new Button(cmp, SWT.PUSH);
	Layouts.setGridData(btn).widthHint(SwtMisc.defaultButtonWidth());
	Button btnCancel = new Button(cmp, SWT.PUSH);
	Layouts.setGridData(btn).widthHint(SwtMisc.defaultButtonWidth());
}
  • Shells - dialogs without boilerplate
Shells.builder(SWT.DIALOG_TRIM, this::textOkCanel)
	.setTitle("Confirm operation")
	.setSize(SwtMisc.defaultDialogWidth(), 0) // set the width, pack height to fit contents
	.openOnDisplayBlocking();
ColumnViewerFormat<Person> format = ColumnViewerFormat.builder();
format.setStyle(SWT.SINGLE | SWT.FULL_SELECTION);
format.addColumn().setText("First").setLabelProviderText(Person::getFirstName);
format.addColumn().setText("Last").setLabelProviderText(Person::getLastName);
format.addColumn().setText("Age").setLabelProviderText(p -> Integer.toString(p.getAge())).setLayoutPixel(3 * SwtMisc.systemFontWidth());
TableViewer table = format.buildTable(parent);
TreeViewer tree = format.buildTree(parent);

Resource management

  • OnePerWidget - a cache tied to the lifetime of an SWT Widget.
  • ColorPool - a pool of colors tied to the lifetime of a widget. ColorPool.forWidget(widget).getColor(rgbValue)
  • ImageDescriptors - use ImageDescriptors with proper resource sharing. ImageDescriptors.set(btn, imageDescriptor)

Interactive testing

Ideally, all UI code would have fully automated UI testing, but such tests are time-consuming to write, so they often just don't get written at all. InteractiveTest bridges the gap by making it easy to write user-in-the-loop guided tests. Furthermore, these tests can even be run in a headless enviroment on a CI server, where the test UI will be opened, then automatically closed after a timeout. This ensures that the tests are all in working order and ready for a human tester to do final validation.

InteractiveTest

From ViewerMiscTest.java:

String message = StringPrinter.buildStringFromLines(
	"- The table and the tree should keep their selection in sync.",
	"- The table and the tree should not allow multi-selection.",
	"- The categories in the tree should not be selectable.");
InteractiveTest.testCoat(message, cmp -> {
	TableAndTree tableAndTree = new TableAndTree(cmp, SWT.SINGLE);

	// get the selection of the tree
	RxBox<Optional<TreeNode<String>>> treeSelection = ViewerMisc.<TreeNode<String>> singleSelection(tableAndTree.tree)
			// only names can be selected - not categories
			.enforce(opt -> opt.map(val -> isName(val) ? val : null));

	// sync the tree and the table
	RxOptional<TreeNode<String>> tableSelection = ViewerMisc.singleSelection(tableAndTree.table);
	Rx.subscribe(treeSelection, tableSelection::set);
	Rx.subscribe(tableSelection, treeSelection::set);
});

Miscellaneous stuff

  • SwtMisc - useful static methods.
    • blockForError, blockForSuccess, blockForQuestion, etc. - opens a dialog and blocks for the user's response, can be called from any thread.
    • loopUntil, loopUntilDisposed, loopUntilGet - spins the SWT display loop until some condition is satisfied.
    • systemFontHeight/Width, scaleByFont, scaleByFontHeight - resolution-independent sizes.
    • treeDefControl, treeDefComposite - a TreeDef for traversing UI elements.
    • setEnabledDeep - sets the enabled status of every child, grandchild, etc. of the given composite.
  • SwtRx - methods for converting SWT events and models to RxJava Observables.
  • SwtDebug - utilities for debugging SWT events.
  • OS, Arch, and SwtPlatform - detect things about the running system, and manipulate the SWT jars for build tools.
    • 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.
    • You can also just copy-paste these straight into your own code - they have no external dependencies.
String installerExtension = OS.getNative().winMacLinux("exe","dmg","sh");
String helperBinary = "driver_" + Arch.getNative().x86x64("", "_64") + ".dll";
String swtJarName = "org.eclipse.swt." + SwtPlatform.getRunning();
  • ViewerMisc - useful static methods for JFace viewers.
    • singleSelection, multiSelection - returns an RxBox for listening to and setting the selection of a viewer.
    • setTreeContentProvider, setLazyTreeContentProvider - uses a TreeDef to provide the content of a TreeViewer.

Requirements

Durian requires:

  • Java 8
  • Durian and DurianRx
  • Guava and RxJava
  • SWT and JFace from Eclipse 4.4+
    • SWT and JFace are not included in the Maven POM, but everything else is.

Acknowledgements