Skip to content

diffplug/durian-swt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DurianSwt: Reactive utilities and fluent builders for SWT

Maven central Apache 2.0

Changelog Javadoc Live chat Travis CI

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

About

Reactive utilities and fluent builders for SWT

Resources

License

Stars

Watchers

Forks

Packages

No packages published