@Override public void bindBidirectional(Property<ObservableSet<E>> other) { try { super.bindBidirectional(other); } catch (IllegalArgumentException e) { if ("Cannot bind property to itself".equals(e.getMessage()) && this != other) { // XXX: The super implementation relies on equals() not on // object identity to infer whether a binding is valid. It thus // throw an IllegalArgumentException if two equal properties are // passed in, even if they are not identical. We have to // ensure they are thus unequal to establish the binding; as // our value will be initially overwritten anyway, we may adjust // the local value; to reduce noise, we only adjust the local // value if necessary if (other.getValue() == null) { if (getValue() == null) { // set to value != null setValue(FXCollections.observableSet(new HashSet<E>())); } } else { if (getValue().equals(other)) { // set to null value setValue(null); } } // try again super.bindBidirectional(other); } else { throw (e); } } }
@Override public void unbindBidirectional(Property<ObservableSet<E>> other) { try { super.unbindBidirectional(other); } catch (IllegalArgumentException e) { if ("Cannot bind property to itself".equals(e.getMessage()) && this != other) { // XXX: The super implementation relies on equals() not on // object identity to infer whether a binding is valid. It thus // throw an IllegalArgumentException if two equal properties are // passed in, even if they are not identical. We have to // ensure they are thus unequal to remove the binding; we // have to restore the current value afterwards. ObservableSet<E> oldValue = getValue(); if (other.getValue() == null) { // set to value != null setValue(FXCollections.observableSet(new HashSet<E>())); } else { // set to null value setValue(null); } // try again super.unbindBidirectional(other); setValue(oldValue); } else { throw (e); } } }
protected Market(GoodType goodType) { this.goodType = goodType; // if the market is a labor market, buyers hire and sellers get hired. Otherwise buyers receive // and sellers earn if (goodType.isLabor()) policy = new SimpleHiringTradePolicy(); else policy = SimpleGoodTradePolicy.getInstance(); buyers = FXCollections.observableSet(new HashSet<>()); sellers = FXCollections.observableSet(new HashSet<>()); marketData = new MarketData(); // build the gui inspector if (MacroII.hasGUI()) { marketInspector = buildInspector(); } }
/** * AbstractDisableable. * * <p>Binds {@code disabled} to {@code disablers.emptyProperty().not()}. * * <p>If a subclass wants to bind {@code disabled} to additional reasons, it must unbind {@code * disabled} first. * * @author Werner Randelshofer * @version $Id$ */ public class AbstractDisableable implements Disableable { protected final ReadOnlyBooleanWrapper disabled = new ReadOnlyBooleanWrapper(); protected final SetProperty<Object> disablers = new SimpleSetProperty<Object>(FXCollections.observableSet()); public AbstractDisableable() { disabled.bind(disablers.emptyProperty().not()); } @Override public ReadOnlyBooleanProperty disabledProperty() { return disabled.getReadOnlyProperty(); } @Override public SetProperty<Object> disablersProperty() { return disablers; } }
/** * Event handler of OK button. * * @param event ActionEvent of this event. */ @FXML private void onOkClick(ActionEvent event) { int startIdx = startCombo.getSelectionModel().getSelectedIndex(); int endIdx = endCombo.getSelectionModel().getSelectedIndex(); currentTarget.set( FXCollections.observableArrayList(startCombo.getItems().subList(startIdx, endIdx + 1))); currentClassNameSet.set(FXCollections.observableSet()); summaryData.set(new SummaryData(currentTarget.get())); Task<Void> topNTask = histogramController.getDrawTopNDataTask(currentTarget.get(), true, null); super.bindTask(topNTask); Thread topNThread = new Thread(topNTask); topNThread.start(); Task<Void> summarizeTask = summaryController.getCalculateGCSummaryTask(this::drawRebootSuspectLine); super.bindTask(summarizeTask); Thread summarizeThread = new Thread(summarizeTask); summarizeThread.start(); }
@Test public void mirroredSet() throws Exception { ObservableSet<String> source = FXCollections.observableSet(); source.add("alpha"); source.add("beta"); ObservableSet<String> dest = ObservableMirrors.mirrorSet(source, gate); assertEquals(0, gate.getTaskQueueSize()); assertEquals(2, dest.size()); source.add("delta"); assertEquals(1, gate.getTaskQueueSize()); assertEquals(2, dest.size()); gate.waitAndRun(); assertEquals(0, gate.getTaskQueueSize()); assertEquals(3, dest.size()); source.removeAll(ImmutableList.of("alpha", "beta")); assertEquals(2, gate.getTaskQueueSize()); gate.waitAndRun(); gate.waitAndRun(); assertEquals(1, dest.size()); assertTrue(dest.contains("delta")); }
@IDProperty("id") @DefaultProperty("children") public class Widget { private StringProperty id = new SimpleStringProperty(); private StringProperty name = new SimpleStringProperty(); private IntegerProperty number = new SimpleIntegerProperty(); private ObservableList<Widget> children = FXCollections.observableArrayList(); private ObservableSet<String> set = FXCollections.observableSet(); private ObservableMap<String, Object> properties = FXCollections.observableHashMap(); private BooleanProperty enabledProperty = new SimpleBooleanProperty(true); private ArrayList<String> styles = new ArrayList<String>(); private ArrayList<String> values = new ArrayList<String>(); private float[] ratios = new float[] {}; private String[] names = new String[] {}; public static final String ALIGNMENT_KEY = "alignment"; public static final int TEN = 10; private EventHandler<ActionEvent> actionHandler; public Widget() { this(null); } public Widget(String name) { setName(name); } public String getId() { return id.get(); } public void setId(String value) { id.set(value); } public StringProperty idProperty() { return id; } public String getName() { return name.get(); } public void setName(String value) { name.set(value); } public StringProperty nameProperty() { return name; } public int getNumber() { return number.get(); } public void setNumber(int value) { number.set(value); } public IntegerProperty numberProperty() { return number; } public ObservableList<Widget> getChildren() { return children; } public ObservableMap<String, Object> getProperties() { return properties; } public boolean isEnabled() { return enabledProperty.get(); } public void setEnabled(boolean value) { enabledProperty.set(value); } public BooleanProperty enabledProperty() { return enabledProperty; } public List<String> getStyles() { return styles; } public List<String> getValues() { return values; } public void setValues(List<String> values) { if (values == null) { throw new IllegalArgumentException(); } this.values = new ArrayList<String>(); this.values.addAll(values); } public float[] getRatios() { return Arrays.copyOf(ratios, ratios.length); } public void setRatios(float[] ratios) { this.ratios = Arrays.copyOf(ratios, ratios.length); } public String[] getNames() { return Arrays.copyOf(names, names.length); } public void setNames(String[] names) { this.names = Arrays.copyOf(names, names.length); } public ObservableSet<String> getSet() { return set; } public static Alignment getAlignment(Widget widget) { return (Alignment) widget.getProperties().get(ALIGNMENT_KEY); } public static void setAlignment(Widget widget, Alignment alignment) { widget.getProperties().put(ALIGNMENT_KEY, alignment); } public final void setOnAction(EventHandler<ActionEvent> value) { actionHandler = value; } public final EventHandler<ActionEvent> getOnAction() { return actionHandler; } public final void fire() { actionHandler.handle(new ActionEvent()); } }
public class FileTreePane extends BorderPane { private static final Logger logger = LoggerFactory.getLogger(FileTreePane.class); // TODO make use of the useCase => store and retrieve the last selection per use-case! private final StringProperty useCaseProperty = new SimpleStringProperty(this, "useCase", "default") { @Override public void set(final String useCase) { assertNotNull("useCase", useCase); } }; @FXML private TreeTableView<FileTreeItem<?>> treeTableView; @FXML private CheckBox showHiddenFilesCheckBox; @FXML private Button refreshButton; @FXML private Button createDirButton; @FXML private Button renameButton; @FXML private Button deleteButton; @FXML private TreeTableColumn<FileTreeItem<?>, String> nameTreeTableColumn; @FXML private TreeTableColumn<FileTreeItem<?>, String> sizeTreeTableColumn; @FXML private TreeTableColumn<FileTreeItem<?>, String> lastModifiedTreeTableColumn; private final BooleanProperty showHiddenFilesProperty = new SimpleBooleanProperty(this, "showHiddenFiles", false); private FileTreeItem<?> rootFileTreeItem; private final ObservableSet<File> selectedFiles = FXCollections.observableSet(new HashSet<File>()); private final ObjectProperty<FileFilter> fileFilterProperty = new SimpleObjectProperty<FileFilter>(this, "fileFilter") { @Override public void set(FileFilter newValue) { // WORKAROUND: the selection is modified when setting the fileFilter from the outside // (refreshing the children seems to cause it) :-( if (updatingSelectedFiles) { super.set(newValue); return; } updatingSelectedFiles = true; try { super.set(newValue); treeTableView.getSelectionModel().clearSelection(); } finally { updatingSelectedFiles = false; } for (File f : selectedFiles) selectFileTreeItemForSelectedFile(f); } }; private final SetChangeListener<File> selectedFilesChangeListener = new SetChangeListener<File>() { @Override public void onChanged(final SetChangeListener.Change<? extends File> c) { assertFxApplicationThread(); if (c.getElementRemoved() != null) unselectTreeItemForUnselectedFile(c.getElementRemoved()); if (c.getElementAdded() != null) selectFileTreeItemForSelectedFile(c.getElementAdded()); updateDisable(); } }; private boolean updatingSelectedFiles; private final CopyOnWriteArrayList<WeakReference<RefreshListener>> refreshListeners = new CopyOnWriteArrayList<>(); private final ReferenceQueue<RefreshListener> refreshListenersReferenceQueue = new ReferenceQueue<>(); public FileTreePane() { loadDynamicComponentFxml(FileTreePane.class, this); rootFileTreeItem = new RootFileTreeItem(this); // The root here is *not* the real root of the file system and should be hidden, because // (1) we might want to have 'virtual' visible roots like "Home", "Desktop", "Drives" and // (2) even if we displayed only the real file system without any shortcuts like "Desktop", // we'd still have multiple roots on a crappy pseudo-OS like Windows still having these shitty // drive letters. treeTableView.setShowRoot(false); treeTableView.setRoot(rootFileTreeItem); treeTableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); treeTableView .getSelectionModel() .selectedItemProperty() .addListener( (ChangeListener<TreeItem<FileTreeItem<?>>>) (observable, o, n) -> updateSelectedFiles()); treeTableView .getSelectionModel() .getSelectedItems() .addListener((InvalidationListener) observable -> updateSelectedFiles()); selectedFiles.addListener(selectedFilesChangeListener); showHiddenFilesCheckBox.selectedProperty().bindBidirectional(showHiddenFilesProperty); // TODO remove the following line - preferably replace by proper, use-case-dependent management! selectedFiles.add(IOUtil.getUserHome()); updateDisable(); } private void updateDisable() { final int seletectItemsSize = treeTableView.getSelectionModel().getSelectedItems().size(); createDirButton.setDisable( seletectItemsSize != 1); // the selection is the parent - and thus required! renameButton.setDisable(seletectItemsSize != 1); deleteButton.setDisable(seletectItemsSize < 1); } public boolean isRefreshButtonVisible() { return refreshButton.isVisible(); } public void setRefreshButtonVisible(boolean visible) { refreshButton.setVisible(visible); } private void updateSelectedFiles() { assertFxApplicationThread(); if (updatingSelectedFiles) return; updatingSelectedFiles = true; try { final ObservableList<TreeItem<FileTreeItem<?>>> selectedItems = treeTableView.getSelectionModel().getSelectedItems(); final Set<File> newSelectedFiles = new HashSet<File>(selectedItems.size()); for (final TreeItem<FileTreeItem<?>> selectedItem : selectedItems) { final FileTreeItem<?> fileTreeItem = selectedItem == null ? null : selectedItem.getValue(); // strange but true: it can be null if (fileTreeItem instanceof FileFileTreeItem) newSelectedFiles.add(((FileFileTreeItem) fileTreeItem).getFile()); } selectedFiles.retainAll(newSelectedFiles); selectedFiles.addAll(newSelectedFiles); } finally { updatingSelectedFiles = false; } } private void selectFileTreeItemForSelectedFile(final File file) { if (updatingSelectedFiles) return; updatingSelectedFiles = true; try { final FileTreeItem<?> fileTreeItem = rootFileTreeItem.findFirst(file); if (fileTreeItem == null) { IllegalStateException x = new IllegalStateException("File does not have corresponding FileTreeItem: " + file); logger.warn("selectFileTreeItemForSelectedFile: " + x, x); } else { TreeItem<?> ti = fileTreeItem.getParent(); while (ti != null) { ti.setExpanded(true); ti = ti.getParent(); } // TODO maybe, instead of scrolling here (after each single item is selected), immediately, // we should wait (=> Timer) and scroll to the *first* selection, later?! treeTableView.getSelectionModel().select(fileTreeItem); int row = treeTableView.getRow(fileTreeItem); if (row >= 0) treeTableView.scrollTo(row); } } finally { updatingSelectedFiles = false; } } private void unselectTreeItemForUnselectedFile(final File file) { if (updatingSelectedFiles) return; updatingSelectedFiles = true; try { final FileTreeItem<?> fileTreeItem = rootFileTreeItem.findFirst(file); if (fileTreeItem != null) { final Set<TreeItem<FileTreeItem<?>>> selectedItems = new LinkedHashSet<TreeItem<FileTreeItem<?>>>( treeTableView.getSelectionModel().getSelectedItems()); if (selectedItems.remove(fileTreeItem)) { treeTableView.getSelectionModel().clearSelection(); for (TreeItem<FileTreeItem<?>> treeItem : selectedItems) treeTableView.getSelectionModel().select(treeItem); } } } finally { updatingSelectedFiles = false; } } public ObservableSet<File> getSelectedFiles() { return selectedFiles; } public void refresh() { fireRefreshEvent(); } private void fireRefreshEvent() { final RefreshEvent event = new RefreshEvent(this); expungeRefreshListeners(); for (final Reference<RefreshListener> reference : refreshListeners) { final RefreshListener listener = reference.get(); if (listener != null) listener.onRefresh(event); } } protected void addRefreshListener(RefreshListener listener) { expungeRefreshListeners(); refreshListeners.add( new IdentityWeakReference<RefreshListener>( assertNotNull("listener", listener), refreshListenersReferenceQueue)); } protected void removeRefreshListener(RefreshListener listener) { expungeRefreshListeners(); refreshListeners.remove( new IdentityWeakReference<RefreshListener>(assertNotNull("listener", listener))); } private void expungeRefreshListeners() { Reference<? extends RefreshListener> ref; while ((ref = refreshListenersReferenceQueue.poll()) != null) refreshListeners.remove(ref); } public SelectionMode getSelectionMode() { return treeTableView.getSelectionModel().getSelectionMode(); } public void setSelectionMode(SelectionMode selectionMode) { assertNotNull("selectionMode", selectionMode); treeTableView.getSelectionModel().setSelectionMode(selectionMode); } protected TreeTableView<FileTreeItem<?>> getTreeTableView() { return treeTableView; } public FileTreeItem<?> getRootFileTreeItem() { return rootFileTreeItem; } public void setRootFileTreeItem(FileTreeItem<?> rootFileTreeItem) { this.rootFileTreeItem = rootFileTreeItem; treeTableView.setRoot(rootFileTreeItem); } public BooleanProperty showHiddenFilesProperty() { return showHiddenFilesProperty; } public ObjectProperty<FileFilter> fileFilterProperty() { return fileFilterProperty; } /** * Gets the use-case. * * @return the use-case. Never <code>null</code>. * @see #useCaseProperty() */ public String getUseCase() { return useCaseProperty.get(); } /** * Sets the use-case. * * @param useCase the use-case. Must not be <code>null</code>. * @see #useCaseProperty() */ public void setUseCase(String useCase) { useCaseProperty.set(useCase); } /** * The use-case-property. This identifier is used to remember the last selection. * * @return the use-case-property. Never <code>null</code>. */ public StringProperty useCaseProperty() { return useCaseProperty; } @Override public void requestFocus() { super.requestFocus(); treeTableView.requestFocus(); } @FXML private void refreshButtonClicked(final ActionEvent event) { fireRefreshEvent(); treeTableView.refresh(); } @FXML private void createDirButtonClicked(final ActionEvent event) { final File parent = assertNotNull("getSelectedDirectory()", getSelectedDirectory()); final String dirName = showCreateOrRenameDialog( "Create folder", "What should be the new folder's name?", parent, null, (name) -> !createFile(parent, name).exists()); if (dirName != null) { final File directory = createFile(parent, dirName); directory.mkdirs(); if (!directory.isDirectory()) showErrorDialog( "Failed to create directory!", "The directory could not be created! Maybe you're missing the required permissions?!"); else { refresh(); getSelectedFiles().clear(); getSelectedFiles().add(directory); } } } @FXML private void renameButtonClicked(final ActionEvent event) { final File selectedFile = getSelectedFile(); final File parent = selectedFile.getParentFile(); final String newName = showCreateOrRenameDialog( "Rename", "What should be the new name?", parent, selectedFile.getName(), (name) -> !selectedFile.getName().equals(name) && !createFile(parent, name).exists()); if (newName != null) { final File newFile = createFile(parent, newName); if (!selectedFile.renameTo(newFile)) showErrorDialog( "Failed to rename file!", "The file could not be renamed! Maybe you're missing the required permissions?!"); else { refresh(); getSelectedFiles().clear(); getSelectedFiles().add(newFile); } } } @FXML private void deleteButtonClicked(final ActionEvent event) { final Set<File> selectedFiles = getSelectedFiles(); if (selectedFiles.isEmpty()) return; Alert alert = new Alert(AlertType.CONFIRMATION); alert.setTitle("Delete"); alert.setHeaderText("Delete these files?"); final VBox contentContainer = new VBox(); contentContainer.setSpacing(8); final Text contentText = new Text("The following files and folders are about to be deleted (folders recursively!):"); contentText.setWrappingWidth(400); contentContainer.getChildren().add(contentText); final ListView<String> fileListView = new ListView<>(); for (final File file : selectedFiles) fileListView.getItems().add(file.getAbsolutePath()); fileListView.setPrefSize(400, 200); contentContainer.getChildren().add(fileListView); alert.getDialogPane().setContent(contentContainer); if (alert.showAndWait().get() == ButtonType.OK) { final List<File> notDeletedFiles = new ArrayList<>(); for (final File file : selectedFiles) { file.deleteRecursively(); if (file.exists()) notDeletedFiles.add(file); } refresh(); if (!notDeletedFiles.isEmpty()) showErrorDialog( "Deleting failed!", "The selected files (or directories) could be not deleted. They may have been deleted partially, though."); } } private String showCreateOrRenameDialog( final String title, final String headerText, final File parent, final String name, final NameVerifier nameVerifier) { final Alert alert = new Alert(AlertType.CONFIRMATION); alert.setTitle(title); alert.setHeaderText(headerText); final GridPane contentContainer = new GridPane(); contentContainer.setPadding(new Insets(8)); contentContainer.setHgap(8); contentContainer.setVgap(8); contentContainer.add(new Label("Parent:"), 0, 0); final TextField parentTextField = new TextField(); parentTextField.setEditable(false); parentTextField.setText(parent.getAbsolutePath()); contentContainer.add(parentTextField, 1, 0); contentContainer.add(new Label("Name:"), 0, 1); final TextField dirNameTextField = new TextField(); dirNameTextField.setText(name); GridPane.setHgrow(dirNameTextField, Priority.ALWAYS); contentContainer.add(dirNameTextField, 1, 1); final InvalidationListener updateDisableInvalidationListener = (observable) -> { final String dirName = dirNameTextField.getText(); final Node okButton = alert.getDialogPane().lookupButton(ButtonType.OK); if (isEmpty(dirName)) okButton.setDisable(true); else { final boolean nameAcceptable = nameVerifier.isNameAcceptable(dirName); okButton.setDisable(!nameAcceptable); } }; dirNameTextField.textProperty().addListener(updateDisableInvalidationListener); alert.getDialogPane().setContent(contentContainer); alert.setOnShowing( (event) -> { dirNameTextField.requestFocus(); dirNameTextField.selectAll(); updateDisableInvalidationListener.invalidated(null); }); if (alert.showAndWait().get() == ButtonType.OK) return dirNameTextField.getText(); else return null; } private void showErrorDialog(final String headerText, final String contentText) { final Alert alert = new Alert(AlertType.ERROR); // alert.setTitle("Error"); alert.setHeaderText(headerText); alert.setContentText(contentText); alert.showAndWait(); } @FunctionalInterface private static interface NameVerifier { boolean isNameAcceptable(String name); } private File getSelectedFile() { final Iterator<File> iterator = getSelectedFiles().iterator(); if (!iterator.hasNext()) return null; // nothing selected final File file = iterator.next(); if (iterator.hasNext()) return null; // more than one selected. else return file; } private File getSelectedDirectory() { File directory = getSelectedFile(); if (directory != null && !directory.isDirectory()) directory = directory.getParentFile(); return directory; } protected TreeTableColumn<FileTreeItem<?>, String> getNameTreeTableColumn() { return nameTreeTableColumn; } protected TreeTableColumn<FileTreeItem<?>, String> getSizeTreeTableColumn() { return sizeTreeTableColumn; } protected TreeTableColumn<FileTreeItem<?>, String> getLastModifiedTreeTableColumn() { return lastModifiedTreeTableColumn; } }