Java源码示例:org.reactfx.EventStreams
示例1
public EventLoggerImpl(DesignerRoot designerRoot) {
this.designerRoot = designerRoot; // we have to be careful with initialization order here
EventStream<LogEntry> onlyParseException = deleteOnSignal(latestEvent, PARSE_EXCEPTION, PARSE_OK);
EventStream<LogEntry> onlyXPathException = deleteOnSignal(latestEvent, XPATH_EVALUATION_EXCEPTION, XPATH_OK);
EventStream<LogEntry> otherExceptions =
filterOnCategory(latestEvent, true, PARSE_EXCEPTION, XPATH_EVALUATION_EXCEPTION, SELECTION_EVENT_TRACING)
.filter(it -> isDeveloperMode() || !it.getCategory().isInternal());
// none of this is done if developer mode isn't enabled because then those events aren't even pushed in the first place
EventStream<LogEntry> reducedTraces = ReactfxUtil.reduceEntangledIfPossible(
latestEvent.filter(LogEntry::isTrace),
(a, b) -> Objects.equals(a.messageProperty().getValue(), b.messageProperty().getValue()),
LogEntry::appendMessage,
EVENT_TRACING_REDUCTION_DELAY
);
EventStreams.merge(reducedTraces, onlyParseException, otherExceptions, onlyXPathException)
.distinct()
.subscribe(fullLog::add);
}
示例2
/**
* This is a weird hack to preload the FXML and CSS, so that the
* first opening of the popover doesn't look completely broken
* (twitching and obviously being restyled).
*
* <p>We show the popover briefly with opacity 0, just the time for its
* content graph to load. When hidden the opacity is reset to 1.
*/
public void doFirstLoad(Stage stage) {
myPopover.ifPresent(pop -> {
pop.setOpacity(0);
pop.setAnimated(false);
pop.show(stage, 40000, 40000);
EventStreams.eventsOf(pop, WindowEvent.WINDOW_HIDDEN)
.subscribeForOne(e -> pop.setOpacity(1));
Platform.runLater(() -> {
pop.hide();
pop.setAnimated(true);
});
});
}
示例3
@Override
protected void beforeParentInit() {
additionalInfoListView.setPlaceholder(new Label("No additional info"));
Val<Node> currentSelection = initNodeSelectionHandling(getDesignerRoot(), EventStreams.never(), false);
// pin to see updates
currentSelection.pin();
hideCommonAttributesProperty()
.values()
.distinct()
.subscribe(show -> setFocusNode(currentSelection.getValue(), new DataHolder()));
attrValueColumn.setCellValueFactory(param -> Val.constant(DesignerUtil.attrToXpathString(param.getValue())));
attrNameColumn.setCellValueFactory(param -> Val.constant("@" + param.getValue().getName()));
attrNameColumn.setCellFactory(col -> new AttributeNameTableCell());
Label valueColGraphic = new Label("Value");
valueColGraphic.setTooltip(new Tooltip("This is the XPath 2.0 representation"));
attrValueColumn.setGraphic(valueColGraphic);
}
示例4
private void setupListeners() {
ObjectProperty<Point2D> mouseDown = new SimpleObjectProperty<>();
EventStreams.eventsOf(imageView, MouseEvent.MOUSE_PRESSED).subscribe(e -> {
Point2D mousePress = imageViewToImage(new Point2D(e.getX(), e.getY()));
mouseDown.set(mousePress);
});
EventStreams.eventsOf(imageView, MouseEvent.MOUSE_DRAGGED).subscribe(e -> {
Point2D dragPoint = imageViewToImage(new Point2D(e.getX(), e.getY()));
shift(dragPoint.subtract(mouseDown.get()));
mouseDown.set(imageViewToImage(new Point2D(e.getX(), e.getY())));
});
EventStream<ScrollEvent> scrollEvents = EventStreams.eventsOf(imageView, ScrollEvent.SCROLL);
EventStream<ScrollEvent> scrollEventsUp = scrollEvents.filter(scrollEvent -> scrollEvent.getDeltaY() < 0);
EventStream<ScrollEvent> scrollEventsDown = scrollEvents.filter(scrollEvent -> scrollEvent.getDeltaY() > 0);
scrollEventsUp.subscribe(scrollEvent -> scale = Math.min(scale + 0.25, 3));
scrollEventsDown.subscribe(scrollEvent -> scale = Math.max(scale - 0.25, 0.25));
EventStreams.merge(scrollEventsUp, scrollEventsDown).subscribe(scrollEvent -> scaleImageViewport(scale));
EventStreams.eventsOf(imageView, MouseEvent.MOUSE_CLICKED)
.filter(mouseEvent -> mouseEvent.getClickCount() == 2)
.subscribe(mouseEvent -> fitToView());
}
示例5
private void setupNvidiaListener() {
log.log(Level.FINER, "Setting nvidia ram listener.");
EventStreams.nonNullValuesOf(nvidiaService.progressProperty())
.filter(vramUsage -> vramUsage.doubleValue() > 0)
.subscribe(vramUsage -> vramBar.setProgress(vramUsage.doubleValue()));
log.log(Level.FINER, "Setting nvidia timer.");
nvidiaTimer = FxTimer.createPeriodic(Duration.ofMillis(1000), () -> {
log.log(Level.FINEST, "Timer: checking service");
if (nvidiaService == null || nvidiaService.isRunning())
return;
log.log(Level.FINEST, "Timer: starting service");
nvidiaService.restart();
nvidiaTimer.restart();
});
nvidiaTimer.restart();
}
示例6
public NeuralImageCell(ObservableBooleanValue editable) {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/neuralImageCell.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
setEditable(false);
if (editable != null) {
EventStreams.changesOf(editable).subscribe(editableChange -> {
setEditable(editableChange.getNewValue());
});
}
}
示例7
public void setNeuralImage(NeuralImage newNeuralImage) {
// Remove previous bindings if applicable
image.imageProperty().unbind();
if (neuralImage != null)
selected.selectedProperty().unbindBidirectional(neuralImage.selectedProperty());
if (weightChanges != null)
weightChanges.unsubscribe();
neuralImage = newNeuralImage;
if (neuralImage != null) {
image.imageProperty().bind(neuralImage.imageProperty());
selected.selectedProperty().bindBidirectional(neuralImage.selectedProperty());
// Event Streams for Weight to convert between double and string
weight.setText(String.valueOf(neuralImage.getWeight()));
weightChanges = EventStreams.changesOf(weight.focusedProperty()).subscribe(focusChange -> {
if (!focusChange.getNewValue()) { // focusing away from input
double newWeight = NeuralDouble.DOUBLE_CONVERTER.fromString(weight.getText()).doubleValue();
neuralImage.setWeight(newWeight);
if (newWeight == 0)
weight.setText("1.0");
}
});
}
}
示例8
public FullImageView(File imageFile, Consumer<ActionEvent> styleEvent, Consumer<ActionEvent> contentEvent, Consumer<ActionEvent> initEvent, ResourceBundle resources) {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/imagePreviewTab.fxml"));
fxmlLoader.setResources(resources);
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
image.fitWidthProperty().bind(widthProperty());
image.fitHeightProperty().bind(heightProperty());
imageView = new MovingImageView(image);
imageView.setImage(imageFile);
EventStreams.eventsOf(style, ActionEvent.ACTION)
.subscribe(styleEvent);
EventStreams.eventsOf(content, ActionEvent.ACTION)
.subscribe(contentEvent);
EventStreams.eventsOf(init, ActionEvent.ACTION)
.subscribe(initEvent);
}
示例9
private C cellForItem(T item) {
C cell = cellPool.getCell(item);
// apply CSS when the cell is first added to the scene
Node node = cell.getNode();
EventStreams.nonNullValuesOf(node.sceneProperty())
.subscribeForOne(scene -> {
node.applyCss();
});
// Make cell initially invisible.
// It will be made visible when it is positioned.
node.setVisible(false);
if (cell.isReusable()) {
// if cell is reused i think adding event handler
// would cause resource leakage.
node.setOnScroll(this::pushScrollEvent);
node.setOnScrollStarted(this::pushScrollEvent);
node.setOnScrollFinished(this::pushScrollEvent);
} else {
node.addEventHandler(ScrollEvent.ANY, this::pushScrollEvent);
}
return cell;
}
示例10
@Test
public void test() {
IntegerProperty src = new SimpleIntegerProperty(0);
IntegerBinding twice = src.multiply(2);
Var<Number> twiceVar = Var.fromVal(twice, n -> src.set(n.intValue() / 2));
List<Number> values = new ArrayList<>();
EventStreams.valuesOf(twiceVar).subscribe(values::add);
src.set(1);
twiceVar.setValue(4);
twiceVar.setValue(5); // no effect
twiceVar.setValue(7); // will become 6
assertEquals(Arrays.asList(0, 2, 4, 6), values);
}
示例11
@Test
public void testEqualNumberOfFramesForFixedDuration() throws InterruptedException, ExecutionException, TimeoutException {
Var<Double> src1 = Var.newSimpleVar(0.0);
Var<Double> src2 = Var.newSimpleVar(0.0);
Val<Double> anim1 = src1.animate(Duration.ofMillis(500), Interpolator.LINEAR_DOUBLE);
Val<Double> anim2 = src2.animate(Duration.ofMillis(500), Interpolator.LINEAR_DOUBLE);
List<Double> vals1 = new ArrayList<>();
List<Double> vals2 = new ArrayList<>();
Platform.runLater(() -> {
EventStreams.valuesOf(anim1).subscribe(vals1::add);
EventStreams.valuesOf(anim2).subscribe(vals2::add);
src1.setValue(10.0);
src2.setValue(20.0);
});
waitUntil(anim1, x -> x == 10.0, 1000);
waitUntil(anim2, x -> x == 20.0, 100);
assertEquals(vals1.size(), vals2.size());
}
示例12
@Test
public void testProportionalNumberOfFramesForFixedSpeed() throws InterruptedException, ExecutionException, TimeoutException {
Var<Integer> src1 = Var.newSimpleVar(0);
Var<Integer> src2 = Var.newSimpleVar(0);
Val<Integer> anim1 = src1.animate((a, b) -> Duration.ofMillis(b - a), Interpolator.LINEAR_INTEGER);
Val<Integer> anim2 = src2.animate((a, b) -> Duration.ofMillis(b - a), Interpolator.LINEAR_INTEGER);
List<Integer> vals1 = new ArrayList<>();
List<Integer> vals2 = new ArrayList<>();
Platform.runLater(() -> {
EventStreams.valuesOf(anim1).subscribe(vals1::add);
EventStreams.valuesOf(anim2).subscribe(vals2::add);
src1.setValue(100);
src2.setValue(300);
});
waitUntil(anim2, x -> x == 300, 1000);
assertEquals(100, anim1.getValue().intValue());
// test that the number of frames for 0 -> 300 is at least
// twice the number of frames for 0 -> 100 (i.e. a conservative test)
assertThat(vals2.size(), greaterThan(2 * vals1.size()));
}
示例13
@Test
public void midAnimationChangeTest() throws InterruptedException, ExecutionException, TimeoutException {
Var<Double> src = Var.newSimpleVar(100.0);
Val<Double> anim = src.animate(Duration.ofMillis(200), Interpolator.EASE_BOTH_DOUBLE);
List<Double> vals = new ArrayList<>();
Platform.runLater(() -> {
EventStreams.valuesOf(anim).subscribe(vals::add);
// when animated value reaches 200.0, set src to -1.0
anim.addListener((obs, old, newVal) -> {
if(newVal >= 200.0) {
src.setValue(-1.0);
}
});
src.setValue(300.0);
});
waitUntil(anim, x -> x == -1.0, 1000);
assertTrue("Value 300.0 never reached", vals.stream().noneMatch(x -> x == 300.0));
}
示例14
@Test
public void test() {
ObservableList<Integer> list = FXCollections.observableArrayList();
Val<Integer> size = LiveList.sizeOf(list);
List<Integer> sizes = new ArrayList<>();
Subscription sub = EventStreams.valuesOf(size).subscribe(sizes::add);
list.add(1);
list.addAll(2, 3, 4);
assertEquals(Arrays.asList(0, 1, 4), sizes);
sub.unsubscribe();
sizes.clear();
list.addAll(5, 6);
assertEquals(Arrays.asList(), sizes);
EventStreams.valuesOf(size).subscribe(sizes::add);
list.addAll(7, 8);
assertEquals(Arrays.asList(6, 8), sizes);
}
示例15
@Override
public void start(Stage primaryStage) {
TextArea textArea = new TextArea();
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
EventStreams.valuesOf(textArea.textProperty())
.successionEnds(Duration.ofMillis(500))
.subscribe(html -> engine.loadContent(html));
SplitPane root = new SplitPane();
root.getItems().addAll(textArea, webView);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
示例16
@Override
protected void beforeParentInit() {
exportResultArea.setSyntaxHighlighter(AvailableSyntaxHighlighters.XML);
ControlUtil.copyToClipboardButton(copyResultButton, exportResultArea::getText);
ControlUtil.saveToFileButton(saveToFileButton, myPopupStage, exportResultArea::getText, this, () -> null);
TreeRendererRegistry rendererRegistry = getService(DesignerRoot.TREE_RENDERER_REGISTRY);
rendererChoicebox.setConverter(DesignerUtil.stringConverter(LiveTreeRenderer::getName, rendererRegistry::fromId));
rendererChoicebox.setItems(rendererRegistry.getRenderers());
rendererChoicebox.getSelectionModel().select(0);
EventStreams.valuesOf(rendererChoicebox.getSelectionModel().selectedItemProperty()).subscribe(propertiesPopover::rebind);
ReactfxUtil.subscribeDisposable(
rendererChoicebox.getSelectionModel().selectedItemProperty(),
renderer -> renderer.getLiveProperties().nonDefaultProperty().values().subscribe(it -> updater.run())
);
EventStreams.valuesOf(rendererChoicebox.getSelectionModel().selectedItemProperty())
.map(LiveTreeRenderer::getLiveProperties)
.subscribe(props -> propertiesMapButton.setDisable(props.asList().isEmpty()));
propertiesMapButton.setOnAction(e -> propertiesPopover.showOrFocus(p -> p.show(propertiesMapButton)));
exportResultArea.setParagraphGraphicFactory(LineNumberFactory.get(exportResultArea));
}
示例17
private static void registerPseudoClassListeners(SmartPopover popOver) {
EventStreams.valuesOf(popOver.detachedProperty())
.subscribe(v -> popOver.pseudoClassStateChanged(PseudoClass.getPseudoClass("detached"), v));
EventStreams.valuesOf(popOver.focusedProperty())
// JavaFX lacks a focus model that works across several popups and stuff.
// The only solution we have to avoid having duplicate carets or so, is
// to *not* let a popover that openly has textfields or other controls
// that steal focus *be detachable*
.subscribe(v -> popOver.pseudoClassStateChanged(PseudoClass.getPseudoClass("focused"), v));
}
示例18
private Subscription subscribeKeyNav(int numResults, Var<Integer> curIdx, Node eventSource) {
// Make TAB or F3 cycle forward,
// SHIFT+TAB or SHIFT+F3 cycle backwards
return EventStreams.eventsOf(eventSource, KeyEvent.KEY_RELEASED)
.filter(it -> it.getCode() == KeyCode.F3 || it.getCode() == KeyCode.TAB)
.subscribe(ke -> {
int offset = ke.isShiftDown() ? -1 : +1;
curIdx.setValue((curIdx.getValue() + offset) % numResults);
ke.consume();
});
}
示例19
private void setupContentLayersTable() {
log.log(Level.FINER, "Setting content layer table list.");
contentLayersTable.setItems(contentLayers);
contentLayersTable.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
log.log(Level.FINER, "Setting content layer table selection listener.");
EventStreams.changesOf(contentLayers).subscribe(change -> {
log.log(Level.FINE, "contentLayers changed");
List<NeuralBoolean> selectedContentLayers = contentLayers.stream()
.filter(NeuralBoolean::getValue)
.collect(Collectors.toList());
String[] newContentLayers = new String[selectedContentLayers.size()];
for (int i = 0; i < selectedContentLayers.size(); i++)
newContentLayers[i] = selectedContentLayers.get(i).getName();
neuralStyle.setContentLayers(newContentLayers);
toggleStyleButtons();
});
log.log(Level.FINER, "Setting style layer table shortcut listener");
EventStreams.eventsOf(contentLayersTable, KeyEvent.KEY_RELEASED).filter(spaceBar::match).subscribe(keyEvent -> {
ObservableList<NeuralBoolean> selectedStyleLayers =
contentLayersTable.getSelectionModel().getSelectedItems();
for (NeuralBoolean neuralLayer : selectedStyleLayers)
neuralLayer.setValue(!neuralLayer.getValue());
});
log.log(Level.FINER, "Setting content layer table column factories.");
contentLayersTableSelected.setCellValueFactory(new PropertyValueFactory<>("value"));
contentLayersTableSelected.setCellFactory(CheckBoxTableCell.forTableColumn(contentLayersTableSelected));
contentLayersTableName.setCellValueFactory(new PropertyValueFactory<>("name"));
contentLayersTableName.setCellFactory(TextFieldTableCell.forTableColumn());
}
示例20
/**
* Private constructor
*/
private LineNumAndBreakpointFactory(StyledTextArea<?> area, IntFunction<String>
format, String stylesheet) {
this.nParagraphs = EventStreams.sizeOf(area.getParagraphs());
this.area = area;
this.format = new SimpleObjectProperty<>(format);
this.stylesheet = stylesheet;
this.breakPoints = FXCollections.observableArrayList();
this.currentBreakPointLineNumber = new SimpleIntegerProperty(-1);
// add a listener to the codeArea's set of breakpoints
// so that breakpoints can be added dynamically as the code is being stepped
// through when in debug mode
// ((LineNumAndBreakpointFactory) area.getParagraphGraphicFactory())
// .getBreakPoints().
// addListener((SetChangeListener<Paragraph>) change -> {
// if (newTab.getFile() != null) {
// boolean set = change.wasAdded();
// String fileName = newTab.getFile().getAbsolutePath();
// Paragraph paragraph = set ? change.getElementAdded() : change
// .getElementRemoved();
// int line = getIndexOf(codeArea, paragraph);
// if (line >= 0) {
// SourceLine sourceLine = new SourceLine(line, fileName);
// mediator.setBreakPointInRAM(sourceLine, set);
// }
// }
// });
}
示例21
/**
* Creates a LiveDirs instance to be used from a designated thread.
* @param projector converts the ({@link T}) {@link TreeItem#getValue()} into a {@link Path} object
* @param injector converts a given {@link Path} object into {@link T}. The reverse of {@code projector}
* @param externalInitiator object to represent an initiator of an external
* file-system change.
* @param clientThreadExecutor executor to execute actions on the caller
* thread. Used to publish updates and errors on the caller thread.
* @throws IOException
*/
public LiveDirs(I externalInitiator, Function<T, Path> projector, Function<Path, T> injector, Executor clientThreadExecutor) throws IOException {
this.externalInitiator = externalInitiator;
this.clientThreadExecutor = clientThreadExecutor;
this.dirWatcher = new DirWatcher(clientThreadExecutor);
this.model = new LiveDirsModel<>(externalInitiator, projector, injector);
this.io = new LiveDirsIO<>(dirWatcher, model, clientThreadExecutor);
this.dirWatcher.signalledKeys().subscribe(this::processKey);
this.errors = EventStreams.merge(dirWatcher.errors(), model.errors(), localErrors);
}
示例22
private static EventStream<Boolean> booleanPulse(javafx.util.Duration javafxDuration, EventStream<?> restartImpulse) {
Duration duration = Duration.ofMillis(Math.round(javafxDuration.toMillis()));
EventStream<?> ticks = EventStreams.restartableTicks(duration, restartImpulse);
return StateMachine.init(false)
.on(restartImpulse.withDefaultEvent(null)).transition((state, impulse) -> true)
.on(ticks).transition((state, tick) -> !state)
.toStateStream();
}
示例23
public Val<Map<String, String>> nonDefaultProperty() {
return withInvalidations(
observableMapVal(mapping),
map -> EventStreams.merge(map.values().stream().map(Val::values).collect(Collectors.toCollection(() -> observableSet(new HashSet<>()))))
).map(this::computeNonDefault);
}
示例24
public Subscription init(ASTManager astManager) {
MessageChannel<VersionedXPathQuery> service = root.getService(DesignerRoot.LATEST_XPATH);
EventStream<?> merged = EventStreams.merge(
astManager.compilationUnitProperty().values(),
additionalTicks(),
service.messageStream(true, this),
astManager.ruleProperties().values().withDefaultEvent(Collections.emptyMap())
);
subscription = merged.subscribe(
tick -> {
Node compil = astManager.compilationUnitProperty().getOrElse(null);
VersionedXPathQuery query = service.latestMessage().getOrElse(null);
Map<String, String> props = astManager.ruleProperties().getOrElse(Collections.emptyMap());
if (compil == null) {
handleNoCompilationUnit();
return;
}
if (query == null || StringUtils.isBlank(query.getExpression())) {
handleNoXPath();
return;
}
try {
List<Node> results = XPathEvaluator.evaluateQuery(compil,
astManager.languageVersionProperty().getValue(),
query.getVersion(),
query.getExpression(),
props,
query.getDefinedProperties());
handleXPathSuccess(results);
} catch (XPathEvaluationException e) {
handleXPathError(e);
}
});
return this::unsubscribe;
}
示例25
@Override
protected void beforeParentInit() {
scopeHierarchyTreeView.setCellFactory(view -> new ScopeHierarchyTreeCell());
// suppress as early as possible in the pipeline
myScopeItemSelectionEvents = EventStreams.valuesOf(scopeHierarchyTreeView.getSelectionModel().selectedItemProperty()).suppressible();
EventStream<NodeSelectionEvent> selectionEvents = myScopeItemSelectionEvents.filter(Objects::nonNull)
.map(TreeItem::getValue)
.filterMap(o -> o instanceof NameDeclaration, o -> (NameDeclaration) o)
.map(NameDeclaration::getNode)
.map(NodeSelectionEvent::of);
initNodeSelectionHandling(getDesignerRoot(), selectionEvents, true);
}
示例26
public AstTreeView(@NamedArg("designerRoot") DesignerRoot root) {
designerRoot = root;
baseSelectionEvents = new EventSource<>();
suppressibleSelectionEvents = baseSelectionEvents.suppressible();
getStyleClass().addAll("ast-tree-view");
initNodeSelectionHandling(root, suppressibleSelectionEvents, false);
// this needs to be done even if the selection originates from this node
EventStreams.changesOf(getSelectionModel().selectedItemProperty())
.subscribe(item -> highlightFocusNodeParents((ASTTreeItem) item.getOldValue(), (ASTTreeItem) item.getNewValue()));
// push a node selection event whenever...
// * The selection changes
EventStreams.valuesOf(getSelectionModel().selectedItemProperty())
.filterMap(Objects::nonNull, TreeItem::getValue)
.map(NodeSelectionEvent::of)
.subscribe(baseSelectionEvents::push);
// * the currently selected cell is explicitly clicked
setCellFactory(tv -> new ASTTreeCell(getDesignerRoot(), n -> {
ASTTreeItem selectedTreeItem = (ASTTreeItem) getSelectionModel().getSelectedItem();
// only push an event if the node was already selected
if (selectedTreeItem != null && selectedTreeItem.getValue() != null
&& selectedTreeItem.getValue().equals(n)) {
baseSelectionEvents.push(NodeSelectionEvent.of(n));
}
}));
EventStreams.valuesOf(additionalStyleClasses)
.repeatOn(EventStreams.valuesOf(rootProperty()))
.subscribe(fun -> {
TreeItem<Node> rootNode = getRoot();
if (rootNode != null && fun != null) {
((ASTTreeItem) rootNode).foreach(it -> ((ASTTreeItem) it).setStyleClasses(fun.apply(it.getValue())));
}
});
}
示例27
/**
* Textfield for the search query.
*/
private void popSearchField() {
TextField textField = new TextField();
textField.setPrefWidth(150);
textField.setPromptText("Search tree");
ControlUtil.makeTextFieldShowPromptEvenIfFocused(textField);
Label label = new Label();
label.getStyleClass().addAll("hint-label");
label.setTooltip(new Tooltip("Go to next result with F3"));
StackPane pane = new StackPane();
pane.getStyleClass().addAll("search-popup");
pane.getStylesheets().addAll(DesignerUtil.getCss("designer").toString());
StackPane.setAlignment(textField, Pos.TOP_RIGHT);
StackPane.setAlignment(label, Pos.BOTTOM_RIGHT);
pane.getChildren().addAll(textField, label);
Val<String> query = Val.wrap(textField.textProperty())
.filter(StringUtils::isNotBlank).map(String::trim)
.filter(it -> it.length() >= MIN_QUERY_LENGTH);
Var<Integer> numResults = Var.newSimpleVar(0);
Subscription subscription = bindSearchQuery(query.conditionOnShowing(pane), numResults, textField);
label.textProperty().bind(
numResults.map(n -> n == 0 ? "no match" : n == 1 ? "1 match" : n + " matches")
);
label.visibleProperty().bind(query.map(Objects::nonNull));
Popup popup = new Popup();
popup.getContent().addAll(pane);
popup.setAutoHide(true);
popup.setHideOnEscape(true);
Bounds bounds = localToScreen(getBoundsInLocal());
popup.show(this, bounds.getMaxX() - textField.getPrefWidth() - 1, bounds.getMinY());
popup.setOnHidden(e -> {
openSearchField = null;
subscription.unsubscribe();
}); // release resources
// Hide popup when ENTER or ESCAPE is pressed
EventStreams.eventsOf(popup, KeyEvent.KEY_RELEASED)
.filter(it -> it.getCode() == KeyCode.ENTER || it.getCode() == KeyCode.ESCAPE)
.subscribeForOne(e -> {
popup.hide();
e.consume();
});
textField.requestFocus();
openSearchField = textField;
}
示例28
public void initialiseAutoCompletion() {
// allows tab/enter completion
EventStreams.eventsOf(autoCompletePopup, KeyEvent.ANY)
.filter(e -> !e.isConsumed())
.filter(e ->
// For some reason this has to be asymmetric
// Delivered events vary between JREs, as well as their properties
// This is the common denominator I found for JREs 8..10
// Only KEY_RELEASED events are delivered for ENTER
e.getEventType().equals(KeyEvent.KEY_RELEASED) && e.getCode() == KeyCode.ENTER
// All KEY_TYPED, KEY_PRESSED, and KEY_RELEASED are delivered for TAB,
// but we have to handle it before it inserts a \t so we catch KEY_PRESSED
|| e.getEventType().equals(KeyEvent.KEY_PRESSED) && e.getCode() == KeyCode.TAB
)
.conditionOn(autoCompletePopup.showingProperty())
.subscribe(e -> {
int focusIdx = getFocusIdx();
if (focusIdx == -1) {
focusIdx = 0;
}
if (focusIdx < autoCompletePopup.getItems().size()) {
autoCompletePopup.getItems().get(focusIdx).getOnAction().handle(new ActionEvent());
}
e.consume();
});
EventStream<Integer> changesEventStream = myCodeArea.plainTextChanges()
// filter out copy paste
.filter(it -> it.getNetLength() == 1)
.map(characterChanges -> {
if (characterChanges.getRemoved().length() > 0) {
return characterChanges.getRemovalEnd() - 1;
}
return characterChanges.getInsertionEnd();
});
EventStream<Integer> keyCombo = EventStreams.eventsOf(myCodeArea, KeyEvent.KEY_PRESSED)
.filter(key -> key.isControlDown() && key.getCode().equals(KeyCode.SPACE))
.map(searchPoint -> myCodeArea.getCaretPosition());
EventStreams.merge(keyCombo, changesEventStream)
.map(this::getInsertionPointAndQuery)
.hook(t -> {
if (t == null) {
autoCompletePopup.hide();
}
})
.filter(Objects::nonNull)
.subscribe(s -> showAutocompletePopup(s._1, s._2));
}
示例29
public EventStream<T> toStream(){
//this instead of EventStream.nonNullValues bc we want to omit initial (artificial) value
return EventStreams.changesOf(this).filterMap(c -> Optional.ofNullable(c.getNewValue()));
}
示例30
private void setupCodeArea() {
codeArea = new CodeArea();
// codeArea.setWrapText(true);
setupParagraphGraphics();
EventStream<Object> highLightTrigger = EventStreams.merge(codeArea.multiPlainChanges(),
EventStreams.changesOf(highlighters.getSelectionModel().selectedItemProperty()),
EventStreams.eventsOf(format, MouseEvent.MOUSE_CLICKED));
//behavior of TAB: 2 spaces, allow outdention via SHIFT-TAB, if cursor is at beginning
Nodes.addInputMap(codeArea, InputMap.consume(
EventPattern.keyPressed(KeyCode.TAB),
e -> codeArea.replaceSelection(" ")
));
Nodes.addInputMap(codeArea, InputMap.consume(
EventPattern.keyPressed(KeyCode.TAB, SHIFT_DOWN),
e -> {
var paragraph = codeArea.getParagraph(codeArea.getCurrentParagraph());
var indentation = StringUtils.countStartSpaces(paragraph.getText());
//is the cursor in the white spaces
if (codeArea.getCaretColumn() <= indentation){
var charsToRemove = Math.min(indentation, 2);
codeArea.replaceText(new IndexRange(codeArea.getAbsolutePosition(codeArea.getCurrentParagraph(), 0),
codeArea.getAbsolutePosition(codeArea.getCurrentParagraph(), (int) charsToRemove)),
"");
}
}
));
// sync highlighting:
// Subscription cleanupWhenNoLongerNeedIt = highLightTrigger
// .successionEnds(Duration.ofMillis(500))
// .subscribe(ignore -> {
// System.out.println("Triggered highlight via end-of-succession");
// highlightCode();
// });
// async highlighting:
Subscription cleanupWhenNoLongerNeedIt = highLightTrigger.successionEnds(Duration.ofMillis(500))
.supplyTask(this::highlightCodeAsync).awaitLatest(codeArea.multiPlainChanges()).filterMap(t -> {
if (t.isSuccess()) {
return Optional.of(t.get());
} else {
t.getFailure().printStackTrace();
return Optional.empty();
}
}).subscribe(this::applyHighlighting);
KeyCombination.Modifier controlKey = KeyCombination.CONTROL_DOWN;
if (SystemUtils.IS_OS_MAC){
controlKey = KeyCombination.META_DOWN;
}
val keyCombination = PlatformUtil.getControlKeyCombination(KeyCode.F);
codeArea.setOnKeyPressed(e -> {
if (keyCombination.match(e)) {
focusSearch();
}
});
}