Example usage for javafx.beans.property ReadOnlyObjectWrapper ReadOnlyObjectWrapper

List of usage examples for javafx.beans.property ReadOnlyObjectWrapper ReadOnlyObjectWrapper

Introduction

In this page you can find the example usage for javafx.beans.property ReadOnlyObjectWrapper ReadOnlyObjectWrapper.

Prototype

public ReadOnlyObjectWrapper(T initialValue) 

Source Link

Document

The constructor of ReadOnlyObjectWrapper

Usage

From source file:com.bdb.weather.display.summary.RainSummary.java

@SuppressWarnings("LeakingThisInConstructor")
public RainSummary(SummaryInterval interval, SummarySupporter supporter) {
    this.setPrefSize(500, 300);
    this.interval = interval;
    this.supporter = supporter;
    dataTable = new TableView();
    Node component = createChartElements();

    TableColumn<SummaryRecord, String> col = new TableColumn<>("Date");
    col.setCellValueFactory(/* ww w . j av a2 s .  c  o  m*/
            (rec) -> new ReadOnlyStringWrapper(DisplayConstants.formatDate(rec.getValue().getDate())));
    dataTable.getColumns().add(col);

    TableColumn<SummaryRecord, Depth> rainfallColumn = new TableColumn<>("Rainfall");
    rainfallColumn.setCellValueFactory((rec) -> new ReadOnlyObjectWrapper(rec.getValue().getTotalRainfall()));
    dataTable.getColumns().add(rainfallColumn);

    TableColumn<SummaryRecord, Depth> etColumn = new TableColumn<>("ET");
    etColumn.setCellValueFactory((rec) -> new ReadOnlyObjectWrapper(rec.getValue().getTotalET()));
    dataTable.getColumns().add(etColumn);

    this.setTabContents(component, dataTable);
}

From source file:com.bekwam.examples.javafx.memorytests.BigTableController.java

@FXML
public void initialize() {

    btnSave.disableProperty().bind(dirtyFlag.not());

    // id is read-only
    /*      tcId.setCellValueFactory(new PropertyValueFactory<MyObject,Number>("id") {
            //from   w w w.j a  v  a  2s  .  c  o  m
             @Override
             public ObservableValue<Number> call(CellDataFeatures<MyObject, Number> param) {
    return new ReadOnlyObjectWrapper<Number>(param.getValue().getId());
             }
                     
          });      
    */
    tcId.setCellValueFactory(new PropertyValueFactory<MyObject, Number>("id"));

    tcData.setCellValueFactory(new PropertyValueFactory<MyObject, String>("data") {
        @Override
        public ObservableValue<String> call(CellDataFeatures<MyObject, String> param) {
            System.out.println("pvCounter=" + pvCounter++);
            return new ReadOnlyObjectWrapper<String>(param.getValue().getData());
        }

    });
    tcData.setCellFactory(TextFieldTableCell.forTableColumn());
    tcData.setOnEditCommit(dataEditCommitHandler);

}

From source file:com.bdb.weather.display.windrose.WindRosePane.java

/**
 * Constructor.//  ww w .  j a  v  a2 s . c om
 */
public WindRosePane() {
    this.setPrefSize(300, 300);
    ChartFactory.getChartTheme().apply(chart);
    chartViewer.setMinHeight(10);
    chartViewer.setMinWidth(10);
    chartViewer.setPrefSize(300, 300);

    dataTable = new TableView();

    FlowPane summaryPanel = new FlowPane();

    summaryPanel.getChildren().add(new LabeledFieldPane<>("Date:", timeField));
    timeField.setEditable(false);
    summaryPanel.getChildren().add(new LabeledFieldPane<>("% Winds are calm:", calmField));
    calmField.setEditable(false);

    summaryPanel.getChildren().add(new Label("Speeds are in " + Speed.getDefaultUnit()));

    BorderPane p = new BorderPane();

    p.setCenter(dataTable);
    p.setTop(summaryPanel);
    this.setTabContents(chartViewer, p);

    TableColumn<WindSlice, String> headingColumn = new TableColumn<>("Heading");
    headingColumn.setCellValueFactory((rec) -> new ReadOnlyStringWrapper(
            Heading.headingForSlice(rec.getValue().getHeadingIndex(), 16).getCompassLabel()));
    dataTable.getColumns().add(headingColumn);

    TableColumn<WindSlice, String> percentOfWindColumn = new TableColumn<>("% of Wind");
    percentOfWindColumn.setCellValueFactory(
            (rec) -> new ReadOnlyStringWrapper(String.format("%.1f", rec.getValue().getPercentageOfWind())));
    dataTable.getColumns().add(percentOfWindColumn);

    TableColumn<WindSlice, Speed> avgSpeedColumn = new TableColumn<>("Avg Speed");
    avgSpeedColumn.setCellValueFactory((rec) -> new ReadOnlyObjectWrapper<>(rec.getValue().getAvgSpeed()));
    dataTable.getColumns().add(avgSpeedColumn);

    TableColumn<WindSlice, Speed> maxSpeedColumn = new TableColumn<>("Max Speed");
    maxSpeedColumn.setCellValueFactory((rec) -> new ReadOnlyObjectWrapper<>(rec.getValue().getMaxSpeed()));
    dataTable.getColumns().add(maxSpeedColumn);

}

From source file:com.bdb.weather.display.summary.WindSummary.java

/**
 * Create the table./*  w ww . j  av  a2s  .  c  om*/
 * 
 * @return The JavaFX Node
 */
private Node createTable() {
    dataTable = new TableView();

    TableColumn<SummaryRecord, String> col = new TableColumn<>("Date");
    col.setCellValueFactory(
            (rec) -> new ReadOnlyStringWrapper(DisplayConstants.formatDate(rec.getValue().getDate())));
    dataTable.getColumns().add(col);

    TableColumn<SummaryRecord, Speed> avgWindColumn = new TableColumn<>("Avg Wind");
    avgWindColumn.setCellValueFactory((rec) -> new ReadOnlyObjectWrapper(rec.getValue().getAvgWindSpeed()));
    dataTable.getColumns().add(avgWindColumn);

    TableColumn<SummaryRecord, Depth> maxWindColumn = new TableColumn<>("Max Wind");
    maxWindColumn.setCellValueFactory((rec) -> new ReadOnlyObjectWrapper(rec.getValue().getMaxWindSpeed()));
    dataTable.getColumns().add(maxWindColumn);

    TableColumn<SummaryRecord, Depth> maxGustColumn = new TableColumn<>("Max Wind");
    maxGustColumn.setCellValueFactory((rec) -> new ReadOnlyObjectWrapper(rec.getValue().getMaxWindGust()));
    dataTable.getColumns().add(maxGustColumn);

    return dataTable;
}

From source file:be.virtualsushi.jfx.dorse.control.table.MyRelatedPropertyValueFactory.java

private ObservableValue<T> getCellDataReflectively(T rowData) {
    OrderLineProperty line = (OrderLineProperty) rowData;
    if (getRelatedProperty() == null || getRelatedProperty().isEmpty() || line == null)
        return null;

    try {/*from   ww w  .j ava2 s .co  m*/
        // we attempt to cache the property reference here, as otherwise
        // performance suffers when working in large data models. For
        // a bit of reference, refer to RT-13937.
        if (columnClass == null || previousProperty == null || !previousProperty.equals(getRelatedProperty())) {

            // create a new PropertyReference
            this.previousProperty = getRelatedProperty();
            this.propertyRef = new PropertyReference<T>(Article.class, getRelatedProperty());
        }
        Long id = line.getId();
        Article a = findArticleById(line.getId());
        return propertyRef.getProperty(findArticleById(line.getId()));
    } catch (IllegalStateException e) {
        try {
            // attempt to just get the value
            T value = propertyRef.get(line);
            return new ReadOnlyObjectWrapper<T>(value);
        } catch (IllegalStateException e2) {
            // fall through to logged exception below
        }

        // log the warning and move on
        final PlatformLogger logger = Logging.getControlsLogger();
        if (logger.isLoggable(PlatformLogger.WARNING)) {
            logger.finest("Can not retrieve property '" + getRelatedProperty() + "' in PropertyBindingFactory: "
                    + this + " with provided class type: " + rowData.getClass(), e);
        }
    }

    return null;
}

From source file:com.ggvaidya.scinames.dataset.BinomialChangesSceneController.java

private void setupTableWithBinomialChanges() {
    changesTableView.setEditable(false);
    changesTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    changesTableView.setItems(potentialChanges);

    changesTableView.getColumns().clear();

    TableColumn<PotentialChange, ChangeType> colChangeType = new TableColumn<>("Type");
    colChangeType.setCellFactory(ComboBoxTableCell.forTableColumn(new ChangeTypeStringConverter(),
            ChangeType.ADDITION, ChangeType.DELETION, ChangeType.RENAME, ChangeType.LUMP, ChangeType.SPLIT,
            ChangeType.COMPLEX, ChangeType.ERROR));
    colChangeType.setCellValueFactory(new PropertyValueFactory<>("type"));
    colChangeType.setPrefWidth(100.0);//from w ww  .  ja  v  a  2  s .  com
    colChangeType.setEditable(true);
    changesTableView.getColumns().add(colChangeType);

    TableColumn<PotentialChange, ObservableSet<Name>> colChangeFrom = new TableColumn<>("From");
    colChangeFrom.setCellFactory(TextFieldTableCell.forTableColumn(new NameSetStringConverter()));
    colChangeFrom.setCellValueFactory(new PropertyValueFactory<>("from"));
    colChangeFrom.setPrefWidth(200.0);
    colChangeFrom.setEditable(true);
    changesTableView.getColumns().add(colChangeFrom);

    TableColumn<PotentialChange, ObservableSet<Name>> colChangeTo = new TableColumn<>("To");
    colChangeTo.setCellFactory(TextFieldTableCell.forTableColumn(new NameSetStringConverter()));
    colChangeTo.setCellValueFactory(new PropertyValueFactory<>("to"));
    colChangeTo.setPrefWidth(200.0);
    colChangeTo.setEditable(true);
    changesTableView.getColumns().add(colChangeTo);

    TableColumn<PotentialChange, String> colDataset = new TableColumn<>("Dataset");
    colDataset.setCellValueFactory(cvf -> {
        return new ReadOnlyStringWrapper(cvf.getValue().getDataset().toString());
    });
    colDataset.setPrefWidth(150.0);
    changesTableView.getColumns().add(colDataset);

    TableColumn<PotentialChange, SimplifiedDate> dateCol = new TableColumn<>("Date");
    dateCol.setCellFactory(
            TextFieldTableCell.forTableColumn(new SimplifiedDate.SimplifiedDateStringConverter()));
    dateCol.setCellValueFactory(cvf -> new ReadOnlyObjectWrapper<>(cvf.getValue().getDataset().getDate()));
    dateCol.setPrefWidth(150);
    dateCol.setSortable(true);
    dateCol.setSortType(SortType.ASCENDING);
    changesTableView.getColumns().add(dateCol);
    changesTableView.getSortOrder().add(dateCol);

    TableColumn<PotentialChange, String> colChangeSummary = new TableColumn<>("Changes summary");
    colChangeSummary.setCellValueFactory(cvf -> {
        Set<Change> changes = changesByPotentialChange.get(cvf.getValue());
        return new ReadOnlyStringWrapper(changes.size() + ": "
                + changes.stream().map(ch -> ch.toString()).collect(Collectors.joining("; ")));
    });
    colChangeSummary.setPrefWidth(200.0);
    changesTableView.getColumns().add(colChangeSummary);

    /*
    TableColumn<PotentialChange, String> colExplicit = new TableColumn<>("Explicit or implicit?");
    colExplicit.setCellValueFactory(
       (TableColumn.CellDataFeatures<Change, String> features) -> 
    new ReadOnlyStringWrapper(
       features.getValue().getDataset().isChangeImplicit(features.getValue()) ? "Implicit" : "Explicit"
    )
    );
    tv.getColumns().add(colExplicit);
            
    ChangeFilter cf = binomialChangesView.getProjectView().getProject().getChangeFilter();
    TableColumn<Change, String> colFiltered = new TableColumn<>("Eliminated by filter?");
    colFiltered.setCellValueFactory(
       (TableColumn.CellDataFeatures<Change, String> features) -> 
    new ReadOnlyStringWrapper(
       cf.test(features.getValue()) ? "Allowed" : "Eliminated"
    )
    );
    tv.getColumns().add(colFiltered);
    */

    TableColumn<PotentialChange, String> colNote = new TableColumn<>("Note");
    colNote.setCellFactory(TextFieldTableCell.forTableColumn());
    colNote.setCellValueFactory(new PropertyValueFactory<>("note"));
    colNote.setPrefWidth(100.0);
    changesTableView.getColumns().add(colNote);

    TableColumn<PotentialChange, String> colReason = new TableColumn<>("Reason");
    colReason.setCellValueFactory(cvf -> new ReadOnlyStringWrapper(calculateReason(cvf.getValue())));
    colReason.setPrefWidth(100.0);
    changesTableView.getColumns().add(colReason);

    TableColumn<PotentialChange, String> colReasonDate = new TableColumn<>("ReasonDate");
    colReasonDate.setCellValueFactory(cvf -> {
        String result;
        Set<SimplifiedDate> dates = calculateReasonDate(cvf.getValue());

        if (dates.size() > 1) {
            result = "(" + dates.size() + ") " + dates.stream().distinct().sorted()
                    .map(sd -> sd.asYYYYmmDD("-")).collect(Collectors.joining("|"));

        } else if (dates.size() == 1) {
            result = dates.iterator().next().asYYYYmmDD("-");

        } else {
            result = "NA";
        }

        return new ReadOnlyStringWrapper(result);
    });
    colReasonDate.setPrefWidth(100.0);
    changesTableView.getColumns().add(colReasonDate);

    TableColumn<PotentialChange, String> colCitations = new TableColumn<>("Citations");
    colCitations.setCellValueFactory(
            (TableColumn.CellDataFeatures<PotentialChange, String> features) -> new ReadOnlyStringWrapper(
                    features.getValue().getCitationStream().map(citation -> citation.getCitation()).sorted()
                            .collect(Collectors.joining("; "))));
    changesTableView.getColumns().add(colCitations);

    TableColumn<PotentialChange, String> colGenera = new TableColumn<>("Genera");
    colGenera.setCellValueFactory(
            (TableColumn.CellDataFeatures<PotentialChange, String> features) -> new ReadOnlyStringWrapper(
                    String.join(", ", features.getValue().getAllNames().stream().map(n -> n.getGenus())
                            .distinct().sorted().collect(Collectors.toList()))));
    changesTableView.getColumns().add(colGenera);

    TableColumn<PotentialChange, String> colSpecificEpithet = new TableColumn<>("Specific epithets");
    colSpecificEpithet.setCellValueFactory(
            (TableColumn.CellDataFeatures<PotentialChange, String> features) -> new ReadOnlyStringWrapper(String
                    .join(", ", features.getValue().getAllNames().stream().map(n -> n.getSpecificEpithet())
                            .filter(s -> s != null).distinct().sorted().collect(Collectors.toList()))));
    changesTableView.getColumns().add(colSpecificEpithet);

    // The infraspecific string.
    TableColumn<PotentialChange, String> colInfraspecificEpithet = new TableColumn<>("Infraspecific epithets");
    colInfraspecificEpithet.setCellValueFactory(
            (TableColumn.CellDataFeatures<PotentialChange, String> features) -> new ReadOnlyStringWrapper(
                    String.join(", ",
                            features.getValue().getAllNames().stream()
                                    .map(n -> n.getInfraspecificEpithetsAsString()).filter(s -> s != null)
                                    .distinct().sorted().collect(Collectors.toList()))));
    changesTableView.getColumns().add(colInfraspecificEpithet);

    // The very last epithet of all
    TableColumn<PotentialChange, String> colTerminalEpithet = new TableColumn<>("Terminal epithet");
    colTerminalEpithet.setCellValueFactory(
            (TableColumn.CellDataFeatures<PotentialChange, String> features) -> new ReadOnlyStringWrapper(
                    String.join(", ", features.getValue().getAllNames().stream().map(n -> {
                        List<Name.InfraspecificEpithet> infraspecificEpithets = n.getInfraspecificEpithets();
                        if (!infraspecificEpithets.isEmpty()) {
                            return infraspecificEpithets.get(infraspecificEpithets.size() - 1).getValue();
                        } else {
                            return n.getSpecificEpithet();
                        }
                    }).filter(s -> s != null).distinct().sorted().collect(Collectors.toList()))));
    changesTableView.getColumns().add(colTerminalEpithet);

    TableColumn<PotentialChange, String> dateForRCol = new TableColumn<>("DateYMD");
    dateForRCol.setCellValueFactory(
            cvf -> new ReadOnlyObjectWrapper<>(cvf.getValue().getDataset().getDate().asYYYYmmDD("-")));
    changesTableView.getColumns().add(dateForRCol);

    // Properties
    TableColumn<PotentialChange, String> colProperties = new TableColumn<>("Properties");
    colProperties.setCellValueFactory(
            (TableColumn.CellDataFeatures<PotentialChange, String> features) -> new ReadOnlyStringWrapper(
                    features.getValue().getProperties().entrySet().stream()
                            .map(entry -> entry.getKey() + ": " + entry.getValue()).sorted()
                            .collect(Collectors.joining("; "))));
    changesTableView.getColumns().add(colProperties);

    fillTableWithBinomialChanges();

    // When someone selects a cell in the Table, try to select the appropriate data in the
    // additional data view.
    changesTableView.getSelectionModel().getSelectedItems()
            .addListener((ListChangeListener<PotentialChange>) lcl -> {
                AdditionalData aData = additionalDataCombobox.getSelectionModel().getSelectedItem();

                if (aData != null) {
                    aData.onSelectChange(changesTableView.getSelectionModel().getSelectedItems());
                }
            });

    // Create a right-click menu for table rows.
    changesTableView.setRowFactory(table -> {
        TableRow<PotentialChange> row = new TableRow<>();

        row.setOnContextMenuRequested(event -> {
            if (row.isEmpty())
                return;

            // We don't currently use the clicked change, since currently all options
            // change *all* the selected changes, but this may change in the future.
            PotentialChange change = row.getItem();

            ContextMenu changeMenu = new ContextMenu();

            Menu lookupChange = new Menu("Look up change");
            lookupChange.getItems().addAll(changesByPotentialChange.getOrDefault(change, new HashSet<>())
                    .stream()
                    .map(ch -> createMenuItem(ch.toString() + " in " + ch.getDataset().toString(), action -> {
                        binomialChangesView.getProjectView().openDetailedView(ch);
                    })).collect(Collectors.toList()));
            changeMenu.getItems().add(lookupChange);

            changeMenu.getItems().add(new SeparatorMenuItem());

            Menu searchForName = new Menu("Search for name");
            searchForName.getItems().addAll(
                    change.getAllNames().stream().sorted().map(n -> createMenuItem(n.getFullName(), action -> {
                        binomialChangesView.getProjectView().openDetailedView(n);
                    })).collect(Collectors.toList()));
            changeMenu.getItems().add(searchForName);

            changeMenu.getItems().add(new SeparatorMenuItem());

            // Create a submenu for tags and urls.
            String note = change.noteProperty().get();

            Menu removeTags = new Menu("Tags");
            removeTags.getItems().addAll(change.getTags().stream().sorted()
                    .map(tag -> new MenuItem(tag.getName())).collect(Collectors.toList()));

            Menu lookupURLs = new Menu("Lookup URL");
            change.getURIs().stream().sorted().map(uri -> {
                return createMenuItem(uri.toString(), evt -> {
                    try {
                        Desktop.getDesktop().browse(uri);
                    } catch (IOException ex) {
                        LOGGER.warning("Could not open URL '" + uri + "': " + ex);
                    }
                });
            }).forEach(mi -> lookupURLs.getItems().add(mi));
            changeMenu.getItems().add(lookupURLs);

            changeMenu.show(binomialChangesView.getScene().getWindow(), event.getScreenX(), event.getScreenY());

        });

        return row;
    });

    LOGGER.info("setupTableWithChanges() completed");
}

From source file:io.bitsquare.gui.main.funds.withdrawal.WithdrawalView.java

private void setAddressColumnCellFactory() {
    addressColumn/*from w  w w. j  a  v a  2 s.c  om*/
            .setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
    addressColumn.setCellFactory(
            new Callback<TableColumn<WithdrawalListItem, WithdrawalListItem>, TableCell<WithdrawalListItem, WithdrawalListItem>>() {

                @Override
                public TableCell<WithdrawalListItem, WithdrawalListItem> call(
                        TableColumn<WithdrawalListItem, WithdrawalListItem> column) {
                    return new TableCell<WithdrawalListItem, WithdrawalListItem>() {
                        private HyperlinkWithIcon hyperlinkWithIcon;

                        @Override
                        public void updateItem(final WithdrawalListItem item, boolean empty) {
                            super.updateItem(item, empty);

                            if (item != null && !empty) {
                                String address = item.getAddressString();
                                hyperlinkWithIcon = new HyperlinkWithIcon(address, AwesomeIcon.EXTERNAL_LINK);
                                hyperlinkWithIcon.setOnAction(event -> openBlockExplorer(item));
                                hyperlinkWithIcon.setTooltip(new Tooltip(
                                        "Open external blockchain explorer for " + "address: " + address));
                                setGraphic(hyperlinkWithIcon);
                            } else {
                                setGraphic(null);
                                if (hyperlinkWithIcon != null)
                                    hyperlinkWithIcon.setOnAction(null);
                            }
                        }
                    };
                }
            });
}

From source file:io.bitsquare.gui.main.funds.withdrawal.WithdrawalView.java

private void setBalanceColumnCellFactory() {
    balanceColumn/*from  w w  w. ja v  a 2  s  . c  om*/
            .setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
    balanceColumn.setCellFactory(
            new Callback<TableColumn<WithdrawalListItem, WithdrawalListItem>, TableCell<WithdrawalListItem, WithdrawalListItem>>() {

                @Override
                public TableCell<WithdrawalListItem, WithdrawalListItem> call(
                        TableColumn<WithdrawalListItem, WithdrawalListItem> column) {
                    return new TableCell<WithdrawalListItem, WithdrawalListItem>() {
                        @Override
                        public void updateItem(final WithdrawalListItem item, boolean empty) {
                            super.updateItem(item, empty);
                            setGraphic((item != null && !empty) ? item.getBalanceLabel() : null);
                        }
                    };
                }
            });
}

From source file:io.bitsquare.gui.main.funds.withdrawal.WithdrawalView.java

private void setSelectColumnCellFactory() {
    selectColumn//from w w w .ja va 2 s .  co m
            .setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
    selectColumn.setCellFactory(
            new Callback<TableColumn<WithdrawalListItem, WithdrawalListItem>, TableCell<WithdrawalListItem, WithdrawalListItem>>() {

                @Override
                public TableCell<WithdrawalListItem, WithdrawalListItem> call(
                        TableColumn<WithdrawalListItem, WithdrawalListItem> column) {
                    return new TableCell<WithdrawalListItem, WithdrawalListItem>() {

                        CheckBox checkBox;

                        @Override
                        public void updateItem(final WithdrawalListItem item, boolean empty) {
                            super.updateItem(item, empty);
                            if (item != null && !empty) {
                                if (checkBox == null) {
                                    checkBox = new CheckBox();
                                    checkBox.setOnAction(e -> selectForWithdrawal(item, checkBox.isSelected()));
                                    setGraphic(checkBox);
                                }
                            } else {
                                setGraphic(null);
                                if (checkBox != null) {
                                    checkBox.setOnAction(null);
                                    checkBox = null;
                                }
                            }
                        }
                    };
                }
            });
}

From source file:org.beryx.viewreka.fxapp.BundleChooser.java

@SuppressWarnings("deprecation")
@Override//  ww w . j ava  2 s. c o  m
public void initialize(URL location, ResourceBundle resources) {
    check("ttvBundles", ttvBundles);
    check("ttColName", ttColName);
    check("ttColVersion", ttColVersion);
    check("ttColId", ttColId);
    check("ttColDescription", ttColDescription);

    ttvBundles.getColumns().forEach(col -> col.impl_setReorderable(false));

    CatalogManager catalogManager = new CatalogManager(guiSettingsManager.getSettings());
    Map<String, Map<Pair<String, Version>, BundleInfo>> categoryMap = new TreeMap<>();
    catalogManager.getCatalogUrls().forEach(url -> {
        CatalogRepo repo = new CatalogRepo(url, catalogManager.getCatalogCache());
        List<BundleInfo> infoEntries = Collections.emptyList();
        try {
            infoEntries = repo.getEntries();
        } catch (Exception e) {
            Dialogs.error("Cannot read from repository " + repo.getCatalogUrl(), e.getMessage(), e);
        }
        infoEntries.forEach(entry -> entry.getCategories().forEach(category -> {
            Map<Pair<String, Version>, BundleInfo> idMap = categoryMap.get(category);
            if (idMap == null) {
                idMap = new TreeMap<>();
                categoryMap.put(category, idMap);
            }
            String bundleId = entry.getId();
            Version version = entry.getVersion();
            Pair<String, Version> infoPair = new ImmutablePair<>(bundleId, version);
            BundleInfo oldEntry = idMap.get(infoPair);
            if (oldEntry == null) {
                idMap.put(infoPair, entry);
            } else if (entry.getUrl().equals(oldEntry.getUrl())) {
                log.warn("Different URLs for " + entry.getName() + " " + version + ": " + entry.getUrl()
                        + " and " + oldEntry.getUrl());
            }
        }));
    });

    ttvBundles.setRowFactory(item -> new BundleInfoTreeTableRow());
    ttColName.setCellFactory(p -> new BundleInfoNameTreeTableCell<>());

    ttColName.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getValue()));
    ttColVersion.setCellValueFactory(
            param -> new ReadOnlyStringWrapper(param.getValue().getValue().getVersion().toString()));
    ttColId.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue().getId()));
    ttColDescription.setCellValueFactory(
            param -> new ReadOnlyStringWrapper(param.getValue().getValue().getDescription()));

    TreeItem<BundleInfo> root = new TreeItem<>(new NullBundleInfo("Bundles"));
    root.setExpanded(true);
    ttvBundles.setRoot(root);
    ttvBundles.setShowRoot(false);
    categoryMap.entrySet().forEach(categoryEntry -> {
        String category = categoryEntry.getKey();
        TreeItem<BundleInfo> categoryItem = new TreeItem<>(new NullBundleInfo(category));
        categoryItem.setExpanded(true);
        root.getChildren().add(categoryItem);

        List<BundleInfo> bInfo = new ArrayList<>(categoryEntry.getValue().values());
        bInfo.sort((b1, b2) -> {
            int res = b1.getName().compareTo(b2.getName());
            if (res == 0) {
                res = b1.getVersion().compareTo(b2.getVersion());
            }
            return res;
        });
        bInfo.forEach(bundleInfo -> {
            boolean existing = existingBundles.stream()
                    .anyMatch(pair -> bundleInfo.getId().equals(pair.getKey())
                            && bundleInfo.getVersion().equals(pair.getValue()));
            BundleInfoTreeItem bundleItem = new BundleInfoTreeItem(bundleInfo, existing);

            bundleItem.setIndependent(true);
            Pair<String, Version> infoPair = new ImmutablePair<>(bundleInfo.getId(), bundleInfo.getVersion());
            bundleItem.setSelected(initialInfoEntries.stream().anyMatch(
                    entry -> new ImmutablePair<>(entry.getId(), entry.getVersion()).equals(infoPair)));
            bundleItem.selectedProperty()
                    .addListener((obs, oldVal, newVal) -> updateSelection(bundleInfo, newVal));
            categoryItem.getChildren().add(bundleItem);
        });
    });
}