- 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- ExecutorServicewhich executes on the SWT thread.
- SwtExec.Guarded- an- ExecutorServicewhich is tied to the lifetime of an SWT widget. Say goodbye to- SWTException: Widget is disposedforever! 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);
});- 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();- 
Actions- builder and one-liner:Actions.create("Redo", this::redo);
- 
LabelProviders- builder and one-liner:LabelProviders.createWithText(Person::getName)
- 
ColumnFormatandColumnViewerFormat- tables and trees without boilerplate
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);- 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)
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.
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);
});- 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- TreeDeffor 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.
 
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.
 
- Thanks to David Karnok for contributing an SwtScheduler that honors the Scheduler/Worker contracts.
- Thanks to Moritz Post for his fluent layout idea.
- Formatted by spotless, as such.
- Bugs found by findbugs, as such.
- OSGi metadata generated by JRuyi's [osgibnd-gradle-plugin] (https://github.com/jruyi/osgibnd-gradle-plugin), which leverages Peter Kriens' bnd.
- Scripts in the .cifolder are inspired by Ben Limmer's work.
- Built by gradle.
- Tested by junit.
- Maintained by DiffPlug.

