Example usage for javafx.scene.control TreeItem TreeItem

List of usage examples for javafx.scene.control TreeItem TreeItem

Introduction

In this page you can find the example usage for javafx.scene.control TreeItem TreeItem.

Prototype

public TreeItem(final T value) 

Source Link

Document

Creates a TreeItem with the value property set to the provided object.

Usage

From source file:com.cdd.bao.editor.endpoint.BrowseEndpoint.java

private void rebuildTree() {
    currentlyRebuilding = true;/*from   w w  w  .  ja  v  a 2 s. co m*/

    treeRoot.getChildren().clear();

    for (int n = 0; n < schemaList.length; n++) {
        TreeItem<Branch> item = new TreeItem<>(new Branch(this, schemaList[n]));
        item.setExpanded(true);
        treeRoot.getChildren().add(item);

        for (int i = 0; i < schemaList[n].numAssays(); i++) {
            Schema.Assay assay = schemaList[n].getAssay(i);
            item.getChildren().add(new TreeItem<Branch>(new Branch(this, schemaList[n], assay)));
        }
    }

    currentlyRebuilding = false;
}

From source file:edu.mit.lib.handbag.Controller.java

public void initialize() {

    Image wfIm = new Image(getClass().getResourceAsStream("/SiteMap.png"));
    workflowLabel.setGraphic(new ImageView(wfIm));
    workflowLabel.setContentDisplay(ContentDisplay.BOTTOM);

    workflowChoiceBox.addEventHandler(ActionEvent.ACTION, event -> {
        if (workflowChoiceBox.getItems().size() != 0) {
            return;
        }/*from w w w.  ja v  a2 s .c o  m*/
        ObservableList<Workflow> wflowList = FXCollections.observableArrayList(loadWorkflows());
        workflowChoiceBox.setItems(wflowList);
        workflowChoiceBox.getSelectionModel().selectedIndexProperty().addListener((ov, value, new_value) -> {
            int newVal = (int) new_value;
            if (newVal != -1) {
                Workflow newSel = workflowChoiceBox.getItems().get(newVal);
                if (newSel != null) {
                    workflowLabel.setText(newSel.getName());
                    generateBagName(newSel.getBagNameGenerator());
                    bagLabel.setText(bagName);
                    sendButton.setText(newSel.getDestinationName());
                    setMetadataList(newSel);
                }
            }
        });
    });

    Image bagIm = new Image(getClass().getResourceAsStream("/Bag.png"));
    bagLabel.setGraphic(new ImageView(bagIm));
    bagLabel.setContentDisplay(ContentDisplay.BOTTOM);

    Image sendIm = new Image(getClass().getResourceAsStream("/Cabinet.png"));
    sendButton.setGraphic(new ImageView(sendIm));
    sendButton.setContentDisplay(ContentDisplay.BOTTOM);
    sendButton.setDisable(true);
    sendButton.setOnAction(e -> transmitBag());

    Image trashIm = new Image(getClass().getResourceAsStream("/Bin.png"));
    trashButton.setGraphic(new ImageView(trashIm));
    trashButton.setContentDisplay(ContentDisplay.BOTTOM);
    trashButton.setDisable(true);
    trashButton.setOnAction(e -> reset(false));

    TreeItem<PathRef> rootItem = new TreeItem<>(new PathRef("", Paths.get("data")));
    rootItem.setExpanded(true);
    payloadTreeView.setRoot(rootItem);
    payloadTreeView.setOnDragOver(event -> {
        if (event.getGestureSource() != payloadTreeView && event.getDragboard().getFiles().size() > 0) {
            event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
        }
        event.consume();
    });
    payloadTreeView.setOnDragDropped(event -> {
        Dragboard db = event.getDragboard();
        boolean success = false;
        if (db.getFiles().size() > 0) {
            for (File dragFile : db.getFiles()) {
                if (dragFile.isDirectory()) {
                    // explode directory and add expanded relative paths to tree
                    relPathSB = new StringBuilder();
                    try {
                        Files.walkFileTree(dragFile.toPath(), new SimpleFileVisitor<Path>() {
                            @Override
                            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                                    throws IOException {
                                relPathSB.append(dir.getFileName()).append("/");
                                return FileVisitResult.CONTINUE;
                            }

                            @Override
                            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                                    throws IOException {
                                payloadTreeView.getRoot().getChildren()
                                        .add(new TreeItem<>(new PathRef(relPathSB.toString(), file)));
                                bagSize += Files.size(file);
                                return FileVisitResult.CONTINUE;
                            }
                        });
                    } catch (IOException ioe) {
                    }
                } else {
                    payloadTreeView.getRoot().getChildren()
                            .add(new TreeItem<>(new PathRef("", dragFile.toPath())));
                    bagSize += dragFile.length();
                }
            }
            bagSizeLabel.setText(scaledSize(bagSize, 0));
            success = true;
            updateButtons();
        }
        event.setDropCompleted(success);
        event.consume();
    });

    metadataPropertySheet.setModeSwitcherVisible(false);
    metadataPropertySheet.setDisable(false);
    metadataPropertySheet.addEventHandler(KeyEvent.ANY, event -> {
        checkComplete(metadataPropertySheet.getItems());
        event.consume();
    });
}

From source file:com.cdd.bao.editor.EditSchema.java

public EditSchema(Stage stage) {
    this.stage = stage;

    if (MainApplication.icon != null)
        stage.getIcons().add(MainApplication.icon);

    menuBar = new MenuBar();
    menuBar.setUseSystemMenuBar(true);//w w w.ja v a 2  s  .  com
    menuBar.getMenus().add(menuFile = new Menu("_File"));
    menuBar.getMenus().add(menuEdit = new Menu("_Edit"));
    menuBar.getMenus().add(menuValue = new Menu("_Value"));
    menuBar.getMenus().add(menuView = new Menu("Vie_w"));
    createMenuItems();

    treeRoot = new TreeItem<>(new Branch(this));
    treeView = new TreeView<>(treeRoot);
    treeView.setEditable(true);
    treeView.setCellFactory(p -> new HierarchyTreeCell());
    treeView.getSelectionModel().selectedItemProperty().addListener((observable, oldVal, newVal) -> {
        if (oldVal != null)
            pullDetail(oldVal);
        if (newVal != null)
            pushDetail(newVal);
    });
    treeView.focusedProperty()
            .addListener((val, oldValue, newValue) -> Platform.runLater(() -> maybeUpdateTree()));

    detail = new DetailPane(this);

    StackPane sp1 = new StackPane(), sp2 = new StackPane();
    sp1.getChildren().add(treeView);
    sp2.getChildren().add(detail);

    splitter = new SplitPane();
    splitter.setOrientation(Orientation.HORIZONTAL);
    splitter.getItems().addAll(sp1, sp2);
    splitter.setDividerPositions(0.4, 1.0);

    progBar = new ProgressBar();
    progBar.setMaxWidth(Double.MAX_VALUE);

    root = new BorderPane();
    root.setTop(menuBar);
    root.setCenter(splitter);
    root.setBottom(progBar);

    BorderPane.setMargin(progBar, new Insets(2, 2, 2, 2));

    Scene scene = new Scene(root, 1000, 800, Color.WHITE);

    stage.setScene(scene);

    treeView.setShowRoot(false);
    treeRoot.getChildren().add(treeTemplate = new TreeItem<>(new Branch(this, "Template")));
    treeRoot.getChildren().add(treeAssays = new TreeItem<>(new Branch(this, "Assays")));
    treeTemplate.setExpanded(true);
    treeAssays.setExpanded(true);

    rebuildTree();

    Platform.runLater(() -> treeView.getFocusModel().focus(treeView.getSelectionModel().getSelectedIndex())); // for some reason it defaults to not the first item

    stage.setOnCloseRequest(event -> {
        if (!confirmClose())
            event.consume();
    });

    updateTitle();

    // loading begins in a background thread, and is updated with a status bar
    Vocabulary.Listener listener = new Vocabulary.Listener() {
        public void vocabLoadingProgress(Vocabulary vocab, float progress) {
            Platform.runLater(() -> {
                progBar.setProgress(progress);
                if (vocab.isLoaded())
                    root.getChildren().remove(progBar);
            });
        }

        public void vocabLoadingException(Exception ex) {
            ex.printStackTrace();
        }
    };
    Vocabulary.globalInstance(listener);
}

From source file:musicmetadatak1009705.FolderTreeView.java

private TreeItem<File> createNode(final File f) {
    return new TreeItem<File>(f) {
        private boolean isLeaf;
        private boolean isFirstTimeChildren = true;
        private boolean isFirstTimeLeaf = true;

        @Override/*w w w  . j  av a2  s  .  c o  m*/
        public ObservableList<TreeItem<File>> getChildren() {
            if (isFirstTimeChildren) {
                isFirstTimeChildren = false;
                super.getChildren().setAll(buildChildren(this));
            }
            return super.getChildren();
        }

        @Override
        public boolean isLeaf() {
            if (isFirstTimeLeaf) {
                isFirstTimeLeaf = false;
                File f = (File) getValue();
                isLeaf = f.isFile();
            }
            return isLeaf;
        }

        private ObservableList<TreeItem<File>> buildChildren(TreeItem<File> TreeItem) {
            File f = TreeItem.getValue();
            if (f == null) {
                return FXCollections.emptyObservableList();
            }
            if (f.isFile()) {
                return FXCollections.emptyObservableList();
            }
            File[] files = f.listFiles();
            if (files != null) {
                ObservableList<TreeItem<File>> children = FXCollections.observableArrayList();
                for (File childFile : files) {
                    //System.out.println("Adding " + childFile.getAbsolutePath());
                    if (childFile.isDirectory()) {
                        children.add(createNode(childFile));
                    }
                }
                return children;
            }
            return FXCollections.emptyObservableList();
        }
    };
}

From source file:eu.fthevenet.binjr.sources.jrds.adapters.JrdsDataAdapter.java

@Override
public TreeItem<TimeSeriesBinding<Double>> getBindingTree() throws DataAdapterException {
    Gson gson = new Gson();
    try {/*from  w  w  w . j ava2 s .  c o m*/
        JsonJrdsTree t = gson.fromJson(getJsonTree(treeViewTab.getCommand(), treeViewTab.getArgument(), filter),
                JsonJrdsTree.class);
        Map<String, JsonJrdsItem> m = Arrays.stream(t.items).collect(Collectors.toMap(o -> o.id, (o -> o)));
        TreeItem<TimeSeriesBinding<Double>> tree = new TreeItem<>(
                bindingFactory.of("", getSourceName(), "/", this));
        for (JsonJrdsItem branch : Arrays.stream(t.items).filter(
                jsonJrdsItem -> JRDS_TREE.equals(jsonJrdsItem.type) || JRDS_FILTER.equals(jsonJrdsItem.type))
                .collect(Collectors.toList())) {
            attachNode(tree, branch.id, m);
        }
        return tree;
    } catch (JsonParseException e) {
        throw new DataAdapterException(
                "An error occurred while parsing the json response to getBindingTree request", e);
    } catch (URISyntaxException e) {
        throw new SourceCommunicationException("Error building URI for request", e);
    }
}

From source file:sonicScream.utilities.ScriptParser.java

private static void parseLine(String line) throws NullPointerException {
    //System.out.println(line); //Enable this to write out scripts as they're parsed. Warning: Causes massive slowdown
    if (StringUtils.isBlank(line)) {
        return;/* w w  w .j  ava2 s  .co  m*/
    }
    //Need this if we want braces commented out too
    if (line.trim().startsWith("//")) {
        try {
            TreeItem<String> newNode = new TreeItem<>(StringUtils.normalizeSpace(line));
            _currentNode = newNode;
            if (_currentNode != null) {
                _currentParent.getChildren().add(newNode);
            }
        } catch (NullPointerException ex) {
            ex.printStackTrace();
        }
    } else if (line.contains("{")) {
        _currentParent = _currentNode;
    } else if (line.contains("}")) {
        _currentParent = _currentParent.getParent();
        if (_currentParent == null) {
            _currentParent = _rootItem;
        }
    } else {
        try {
            TreeItem<String> newNode = new TreeItem<>(StringUtils.normalizeSpace(line));
            _currentNode = newNode;
            if (_currentNode != null) {
                _currentParent.getChildren().add(newNode);
            }
        } catch (NullPointerException ex) {
            ex.printStackTrace();
        }
    }
}

From source file:net.rptools.tokentool.client.TokenTool.java

/**
 * //  w  w  w .j  a va2 s  .  c o m
 * @author Jamz
 * @throws IOException
 * @since 2.0
 * 
 *        This method loads and processes all the overlays found in user.home/overlays and it can take a minute to load as it creates thumbnail versions for the comboBox so we call this during the
 *        init and display progress in the preLoader (splash screen).
 * 
 */
private TreeItem<Path> cacheOverlays(File dir, TreeItem<Path> parent, int THUMB_SIZE) throws IOException {
    TreeItem<Path> root = new TreeItem<>(dir.toPath());
    root.setExpanded(false);

    log.debug("caching " + dir.getAbsolutePath());

    File[] files = dir.listFiles();
    for (File file : files) {
        if (file.isDirectory()) {
            cacheOverlays(file, root, THUMB_SIZE);
        } else {
            Path filePath = file.toPath();
            TreeItem<Path> imageNode = new TreeItem<>(filePath,
                    ImageUtil.getOverlayThumb(new ImageView(), filePath));
            root.getChildren().add(imageNode);

            notifyPreloader(new Preloader.ProgressNotification((double) loadCount++ / overlayCount));
        }
    }

    if (parent != null) {
        // When we show the overlay image, the TreeItem value is "" so we need to
        // sort those to the bottom for a cleaner look and keep sub dir's at the top.
        // If a node has no children then it's an overlay, otherwise it's a directory...
        root.getChildren().sort(new Comparator<TreeItem<Path>>() {
            @Override
            public int compare(TreeItem<Path> o1, TreeItem<Path> o2) {
                if (o1.getChildren().size() == 0 && o2.getChildren().size() == 0)
                    return 0;
                else if (o1.getChildren().size() == 0)
                    return Integer.MAX_VALUE;
                else if (o2.getChildren().size() == 0)
                    return Integer.MIN_VALUE;
                else
                    return o1.getValue().compareTo(o2.getValue());
            }
        });

        parent.getChildren().add(root);
    }

    return root;
}

From source file:sonicScream.models.Script.java

/**
 * Returns the Script's tree with everything removed but each entry's title
 * and its wave file list, and flattens the hierarchy.
 * Initializes the rootNode if it has not yet been initialized.
 * @param forceUpdate If true, will force the method to regenerate the simple tree from the current rootNode tree.
 * @return A simplified version of the Script's tree.
 *///from   w ww . j  a va  2 s.  c om
public TreeItem<String> getSimpleTree(boolean forceUpdate) {
    if (_simpleRootNode != null && !forceUpdate) {
        return _simpleRootNode;
    }
    if (_rootNode == null) {
        _rootNode = getRootNode();
    }
    TreeItem<String> local = new TreeItem<String>("root");
    for (TreeItem<String> child : getRootNode().getChildren()) {
        List<TreeItem<String>> localWaveStrings = FXCollections.observableArrayList();
        List<TreeItem<String>> waveStrings = getWaveStrings(child).orElse(null);
        if (waveStrings == null)
            continue;
        for (TreeItem<String> wave : waveStrings) {
            TreeItem<String> sound = new TreeItem<String>();
            //Remove whitespace, quotes, and value# text.
            String waveValue = wave.getValue().trim();
            int thirdQuoteIndex = StringUtils.ordinalIndexOf(waveValue, "\"", 3);
            waveValue = (waveValue.substring(thirdQuoteIndex + 1, waveValue.length() - 1));
            sound.setValue(waveValue);
            localWaveStrings.add(sound);
        }
        TreeItem<String> localChild = new TreeItem<>(child.getValue());
        localChild.getChildren().setAll(localWaveStrings);
        local.getChildren().add(localChild);
    }
    _simpleRootNode = local;
    return _simpleRootNode;
}

From source file:ubicrypt.ui.ctrl.HomeController.java

@PostConstruct
public void init() {
    gProgress = new GeneralProgress(inProgress, inProgressMessage);
    treeView.setCellFactory(treeView1 -> new TreeCellFactory(treeView1, fileUntracker, appEvents, gProgress));
    addProvider.setOnMouseClicked(event -> ctx.browse("selectProvider"));
    addFile.setOnMouseClicked(event -> {
        if (!localConfig.getProviders().stream().findAny().isPresent()) {
            ctx.browse("selectProvider");
            return;
        }//from  w  w  w  .  j av a  2 s .  c  om
        fileAdder.accept(emptyPath);
    });
    settings.setOnMouseClicked(event -> ctx.browse("settings"));
    filesRoot = new TreeItem<>(new RootFilesItem(event -> fileAdder.accept(emptyPath)));
    TreeItem<ITreeItem> root = new TreeItem<>();
    treeView.setRoot(root);

    root.getChildren().add(filesRoot);
    treeView.setShowRoot(false);
    localConfig.getLocalFiles().stream().filter(Utils.ignoredFiles)
            .forEach(localFile -> addFiles(localFile.getPath().iterator(), basePath, filesRoot, localFile));

    //providers
    providersRoot = new TreeItem<>(new RootProvidersItem());
    root.getChildren().add(providersRoot);
    localConfig.getProviders().stream().forEach(providerAdder);

    //provider status events
    providerEvent.subscribe(pevent -> {
        switch (pevent.getEvent()) {
        case added:
            log.info("new provider added:{}", pevent.getHook().getProvider());
            final Optional<TreeItem<ITreeItem>> optItem = providersRoot.getChildren().stream()
                    .filter(item -> ((ProviderItem) item.getValue()).getProvider()
                            .equals(pevent.getHook().getProvider()))
                    .findFirst();
            if (!optItem.isPresent()) {
                providerAdder.accept(pevent.getHook().getProvider());
            }
            pevent.getHook().getStatusEvents().subscribe(event -> {
                Function<String, String> classLabel;
                log.info("provider status {}:{}", event, pevent.getHook().getProvider());
                switch (event) {
                case error:
                    classLabel = code -> format("tree-provider-%s-error", code);
                    break;
                default:
                    //TODO:labels for other statuses
                    classLabel = code -> format("tree-provider-%s", code);
                }
                optItem.ifPresent(item -> {
                    final ProviderItem providerItem = (ProviderItem) item.getValue();
                    final Node graphics = providerItem.getGraphics();
                    graphics.getStyleClass().clear();
                    providerDescriptors.stream()
                            .filter(pd -> pd.getType().equals(providerItem.getProvider().getClass()))
                            .map(ProviderDescriptor::getCode).findFirst()
                            .ifPresent(code -> graphics.getStyleClass().add(classLabel.apply(code)));
                });
            });
            break;
        case removed:
            //TODO: remove provider
            break;
        default:
            log.warn("unmanaged event:{}", pevent.getEvent());
        }
    });

    //remote file events
    fileEvents.filter(fileEvent -> fileEvent.getLocation() == FileEvent.Location.remote)
            .subscribe(fileEvent -> {
                log.debug("file remote event:{}", fileEvent);
                //update file icon
                final UbiFile<UbiFile> file = fileEvent.getFile();
                Observable.create(fileInSync.call(file)).subscribe(res -> {
                    searchFile(filesRoot, file).ifPresent(treeView -> {
                        final Node graphics = treeView.getValue().getGraphics();
                        graphics.getStyleClass().clear();
                        graphics.getStyleClass().add(format("tree-file-saved-%s", res));
                    });
                });
            });
    //local file events
    fileEvents.filter(fileEvent -> fileEvent.getLocation() == FileEvent.Location.local
            && fileEvent.getType() == FileEvent.Type.created).subscribe(fileEvent -> {
                log.debug("file local event:{}", fileEvent);
                localConfig.getLocalFiles().stream().filter(fileEvent.getFile()::equals).findFirst().ifPresent(
                        fe -> addFiles(fileEvent.getFile().getPath().iterator(), basePath, filesRoot, fe));
                searchFile(filesRoot, fileEvent.getFile()).ifPresent(treeView -> {
                    final Node graphics = treeView.getValue().getGraphics();
                    graphics.getStyleClass().clear();
                    graphics.getStyleClass().add(format("tree-file-saved-%s", true));
                });
            });

    //file progress monitor
    progressEvents.subscribe(progress -> {
        Platform.runLater(() -> {
            if (progress.isCompleted()) {
                log.debug("progress completed");
                if (!filesInProgress.remove(progress)) {
                    log.warn("progress not tracked. progress file:{}, element:{}",
                            progress.getProvenience().getFile());
                }
                Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(2), ae -> {
                    progressFile.setText("");
                    progressProvider.setText("");
                    progressBar.setProgress(0D);
                }));
                timeline.play();
            } else {
                filesInProgress.add(progress);
            }
            if (filesInProgress.isEmpty()) {
                //                    footer.setVisible(false);
                return;
            }
            footer.setVisible(true);
            filesInProgress.stream().findFirst().ifPresent(pr -> {
                progressFile.setText(StringUtils
                        .abbreviate(pr.getProvenience().getFile().getPath().getFileName().toString(), 30));
                progressProvider.setText(StringUtils.abbreviate(pr.getTarget().toString(), 30));
                progressBar.setProgress((double) progress.getChunk() / pr.getProvenience().getFile().getSize());
            });
        });
    });

    //sync-done events
    appEvents.subscribe(ClassMatcher.newMatcher().on(SyncBeginEvent.class, event -> {
        log.info("sync begin received");
        Platform.runLater(() -> {
            gProgress.startProgress("Synchronizing providers");
            addFile.setDisable(true);
            addProvider.setDisable(true);
        });
    }).on(SynchDoneEvent.class, event -> {
        log.debug("sync done");
        refreshItems(filesRoot);
        Platform.runLater(() -> {
            gProgress.stopProgress();
            addFile.setDisable(false);
            addProvider.setDisable(false);
        });
    }));
}

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

@SuppressWarnings("deprecation")
@Override/*w w  w  .java2s .co  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);
        });
    });
}