Search in sources :

Example 1 with Version

use of qupath.lib.common.Version in project qupath by qupath.

the class QuPathGUI method refreshExtensions.

/**
 * Check the extensions directory, loading any new extensions found there.
 * @param showNotification if true, display a notification if a new extension has been loaded
 */
public void refreshExtensions(final boolean showNotification) {
    boolean initializing = initializingMenus.get();
    initializingMenus.set(true);
    // Refresh the extensions
    extensionClassLoader.refresh();
    extensionLoader.reload();
    // Sort the extensions by name, to ensure predictable loading order
    // (also, menus are in a better order if ImageJ extension installed before OpenCV extension)
    List<QuPathExtension> extensions = new ArrayList<>();
    Iterator<QuPathExtension> iterator = extensionLoader.iterator();
    while (iterator.hasNext()) {
        try {
            extensions.add(iterator.next());
        } catch (Throwable e) {
            if (getStage() != null && getStage().isShowing()) {
                Dialogs.showErrorMessage("Extension error", "Error loading extension - check 'View -> Show log' for details.");
            }
            logger.error(e.getLocalizedMessage(), e);
        }
    }
    Collections.sort(extensions, Comparator.comparing(QuPathExtension::getName));
    Version qupathVersion = getVersion();
    for (QuPathExtension extension : extensions) {
        if (!loadedExtensions.containsKey(extension.getClass())) {
            Version version = extension.getVersion();
            try {
                long startTime = System.currentTimeMillis();
                extension.installExtension(this);
                long endTime = System.currentTimeMillis();
                logger.info("Loaded extension {} ({} ms)", extension.getName(), endTime - startTime);
                if (version != null)
                    logger.debug("{} was written for QuPath {}", extension.getName(), version);
                else
                    logger.debug("{} does not report a compatible QuPath version", extension.getName());
                loadedExtensions.put(extension.getClass(), extension);
                if (showNotification)
                    Dialogs.showInfoNotification("Extension loaded", extension.getName());
            } catch (Exception | LinkageError e) {
                String message = "Unable to load " + extension.getName();
                if (showNotification)
                    Dialogs.showErrorNotification("Extension error", message);
                logger.error("Error loading extension " + extension + ": " + e.getLocalizedMessage(), e);
                if (!Objects.equals(qupathVersion, version)) {
                    if (version == null)
                        logger.warn("QuPath version for which the '{}' was written is unknown!", extension.getName());
                    else if (version.equals(qupathVersion))
                        logger.warn("'{}' reports that it is compatible with the current QuPath version {}", extension.getName(), qupathVersion);
                    else
                        logger.warn("'{}' was written for QuPath {} but current version is {}", extension.getName(), version, qupathVersion);
                }
                try {
                    logger.error("It is recommended that you delete {} and restart QuPath", URLDecoder.decode(extension.getClass().getProtectionDomain().getCodeSource().getLocation().toExternalForm(), StandardCharsets.UTF_8));
                } catch (Exception e2) {
                    logger.debug("Error finding code source " + e2.getLocalizedMessage(), e2);
                }
                defaultActions.SHOW_LOG.handle(null);
            }
        }
    }
    // Set the ImageServer to also look on the same search path
    List<ImageServerBuilder<?>> serverBuildersBefore = ImageServerProvider.getInstalledImageServerBuilders();
    ImageServerProvider.setServiceLoader(ServiceLoader.load(ImageServerBuilder.class, extensionClassLoader));
    if (showNotification) {
        // A bit convoluted... but try to show new servers that have been loaded by comparing with the past
        List<String> serverBuilders = serverBuildersBefore.stream().map(s -> s.getName()).collect(Collectors.toList());
        List<String> serverBuildersUpdated = ImageServerProvider.getInstalledImageServerBuilders().stream().map(s -> s.getName()).collect(Collectors.toList());
        serverBuildersUpdated.removeAll(serverBuilders);
        for (String builderName : serverBuildersUpdated) {
            Dialogs.showInfoNotification("Image server loaded", builderName);
        }
    }
    initializingMenus.set(initializing);
}
Also used : Change(javafx.collections.ListChangeListener.Change) PathObjectHierarchyView(qupath.lib.gui.panes.PathObjectHierarchyView) SelectedMeasurementTableView(qupath.lib.gui.panes.SelectedMeasurementTableView) Version(qupath.lib.common.Version) ProjectBrowser(qupath.lib.gui.panes.ProjectBrowser) ListChangeListener(javafx.collections.ListChangeListener) Map(java.util.Map) Path(java.nio.file.Path) ReleaseVersion(qupath.lib.gui.extensions.UpdateChecker.ReleaseVersion) Rectangle2D(javafx.geometry.Rectangle2D) PathObjects(qupath.lib.objects.PathObjects) Rectangle(javafx.scene.shape.Rectangle) BooleanProperty(javafx.beans.property.BooleanProperty) Project(qupath.lib.projects.Project) ObservableList(javafx.collections.ObservableList) Divider(javafx.scene.control.SplitPane.Divider) QuPathExtension(qupath.lib.gui.extensions.QuPathExtension) ByteArrayOutputStream(java.io.ByteArrayOutputStream) FXCollections(javafx.collections.FXCollections) PathIcons(qupath.lib.gui.tools.IconFactory.PathIcons) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Bindings(javafx.beans.binding.Bindings) LinkedHashMap(java.util.LinkedHashMap) TreeTableView(javafx.scene.control.TreeTableView) PreferencePane(qupath.lib.gui.panes.PreferencePane) Commands(qupath.lib.gui.commands.Commands) QuPathStyleManager(qupath.lib.gui.prefs.QuPathStyleManager) IOException(java.io.IOException) OverlayOptions(qupath.lib.gui.viewer.OverlayOptions) Preferences(java.util.prefs.Preferences) ROI(qupath.lib.roi.interfaces.ROI) PathTools(qupath.lib.gui.viewer.tools.PathTools) ParameterPanelFX(qupath.lib.gui.dialogs.ParameterPanelFX) DragDropImportListener(qupath.lib.gui.viewer.DragDropImportListener) ImageView(javafx.scene.image.ImageView) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) Image(javafx.scene.image.Image) PathIO(qupath.lib.io.PathIO) EventHandler(javafx.event.EventHandler) ImageServer(qupath.lib.images.servers.ImageServer) BooleanBinding(javafx.beans.binding.BooleanBinding) TextInputControl(javafx.scene.control.TextInputControl) URLDecoder(java.net.URLDecoder) UncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler) Date(java.util.Date) URISyntaxException(java.net.URISyntaxException) ObjectInputStream(java.io.ObjectInputStream) KeyCombination(javafx.scene.input.KeyCombination) DefaultImageRegionStore(qupath.lib.gui.images.stores.DefaultImageRegionStore) ByteArrayInputStream(java.io.ByteArrayInputStream) Locale(java.util.Locale) GitHubProject(qupath.lib.gui.extensions.GitHubProject) ImageIO(javax.imageio.ImageIO) RotateEvent(javafx.scene.input.RotateEvent) WindowEvent(javafx.stage.WindowEvent) PathInteractivePlugin(qupath.lib.plugins.PathInteractivePlugin) Orientation(javafx.geometry.Orientation) MenuItem(javafx.scene.control.MenuItem) Ellipse(javafx.scene.shape.Ellipse) ImageServerProvider(qupath.lib.images.servers.ImageServerProvider) Collection(java.util.Collection) Font(javafx.scene.text.Font) ServiceLoader(java.util.ServiceLoader) Collectors(java.util.stream.Collectors) BorderStroke(javafx.scene.layout.BorderStroke) PathObject(qupath.lib.objects.PathObject) Objects(java.util.Objects) ImageTypeSetting(qupath.lib.gui.prefs.PathPrefs.ImageTypeSetting) ProjectIO(qupath.lib.projects.ProjectIO) GuiTools(qupath.lib.gui.tools.GuiTools) ExecutorCompletionService(java.util.concurrent.ExecutorCompletionService) Scene(javafx.scene.Scene) ListView(javafx.scene.control.ListView) ReadOnlyObjectProperty(javafx.beans.property.ReadOnlyObjectProperty) SimpleStringProperty(javafx.beans.property.SimpleStringProperty) Action(org.controlsfx.control.action.Action) PathClassFactory(qupath.lib.objects.classes.PathClassFactory) ScriptEditor(qupath.lib.gui.scripting.ScriptEditor) TableColumn(javafx.scene.control.TableColumn) HashSet(java.util.HashSet) Insets(javafx.geometry.Insets) DetectionDisplayMode(qupath.lib.gui.viewer.OverlayOptions.DetectionDisplayMode) ExecutorService(java.util.concurrent.ExecutorService) KeyCode(javafx.scene.input.KeyCode) ActionAccelerator(qupath.lib.gui.ActionTools.ActionAccelerator) Logger(org.slf4j.Logger) Dialog(javafx.scene.control.Dialog) Label(javafx.scene.control.Label) MenuBar(javafx.scene.control.MenuBar) ActionIcon(qupath.lib.gui.ActionTools.ActionIcon) ServerBuilder(qupath.lib.images.servers.ImageServerBuilder.ServerBuilder) ScrollEvent(javafx.scene.input.ScrollEvent) Consumer(java.util.function.Consumer) SimpleBooleanProperty(javafx.beans.property.SimpleBooleanProperty) Stage(javafx.stage.Stage) ViewerPlusDisplayOptions(qupath.lib.gui.viewer.ViewerPlusDisplayOptions) Comparator(java.util.Comparator) PathTool(qupath.lib.gui.viewer.tools.PathTool) Arrays(java.util.Arrays) ServerTools(qupath.lib.images.servers.ServerTools) ActionUtils(org.controlsfx.control.action.ActionUtils) ActionDescription(qupath.lib.gui.ActionTools.ActionDescription) ReadOnlyBooleanProperty(javafx.beans.property.ReadOnlyBooleanProperty) StackPane(javafx.scene.layout.StackPane) AnnotationPane(qupath.lib.gui.panes.AnnotationPane) JFXPanel(javafx.embed.swing.JFXPanel) Category(java.util.Locale.Category) ParameterList(qupath.lib.plugins.parameters.ParameterList) TabPane(javafx.scene.control.TabPane) ScriptException(javax.script.ScriptException) CountingPanelCommand(qupath.lib.gui.commands.CountingPanelCommand) SplitPane(javafx.scene.control.SplitPane) Border(javafx.scene.layout.Border) Event(javafx.event.Event) Set(java.util.Set) KeyEvent(javafx.scene.input.KeyEvent) Screen(javafx.stage.Screen) AffineTransform(java.awt.geom.AffineTransform) QuPathViewerListener(qupath.lib.gui.viewer.QuPathViewerListener) StandardCharsets(java.nio.charset.StandardCharsets) Executors(java.util.concurrent.Executors) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) Platform(javafx.application.Platform) Region(javafx.scene.layout.Region) CommandFinderTools(qupath.lib.gui.tools.CommandFinderTools) InputDisplayCommand(qupath.lib.gui.commands.InputDisplayCommand) ImageRegionStoreFactory(qupath.lib.gui.images.stores.ImageRegionStoreFactory) ThreadTools(qupath.lib.common.ThreadTools) DefaultScriptEditor(qupath.lib.gui.scripting.DefaultScriptEditor) GitHubRepo(qupath.lib.gui.extensions.GitHubProject.GitHubRepo) BorderPane(javafx.scene.layout.BorderPane) ButtonData(javafx.scene.control.ButtonBar.ButtonData) SimpleDateFormat(java.text.SimpleDateFormat) PathPlugin(qupath.lib.plugins.PathPlugin) Projects(qupath.lib.projects.Projects) StandardCopyOption(java.nio.file.StandardCopyOption) ArrayList(java.util.ArrayList) TabClosingPolicy(javafx.scene.control.TabPane.TabClosingPolicy) QuPathViewerPlus(qupath.lib.gui.viewer.QuPathViewerPlus) ObjectOutputStream(java.io.ObjectOutputStream) LinkedHashSet(java.util.LinkedHashSet) Color(javafx.scene.paint.Color) CirclePopupMenu(jfxtras.scene.menu.CirclePopupMenu) TitledPane(javafx.scene.control.TitledPane) Files(java.nio.file.Files) ToolBar(javafx.scene.control.ToolBar) GeneralTools(qupath.lib.common.GeneralTools) Node(javafx.scene.Node) CheckBox(javafx.scene.control.CheckBox) ProjectCommands(qupath.lib.gui.commands.ProjectCommands) File(java.io.File) PathObjectTools(qupath.lib.objects.PathObjectTools) Menu(javafx.scene.control.Menu) Cursor(javafx.scene.Cursor) KeyCodeCombination(javafx.scene.input.KeyCodeCombination) Paths(java.nio.file.Paths) SimpleObjectProperty(javafx.beans.property.SimpleObjectProperty) Tab(javafx.scene.control.Tab) PathPrefs(qupath.lib.gui.prefs.PathPrefs) StringBinding(javafx.beans.binding.StringBinding) Pos(javafx.geometry.Pos) Area(java.awt.geom.Area) CheckMenuItem(javafx.scene.control.CheckMenuItem) LoggerFactory(org.slf4j.LoggerFactory) UpdateChecker(qupath.lib.gui.extensions.UpdateChecker) Parent(javafx.scene.Parent) ContextMenu(javafx.scene.control.ContextMenu) URI(java.net.URI) ImageServers(qupath.lib.images.servers.ImageServers) TableView(javafx.scene.control.TableView) ImageType(qupath.lib.images.ImageData.ImageType) Shape(java.awt.Shape) BufferedImage(java.awt.image.BufferedImage) GroovyLanguage(qupath.lib.gui.scripting.languages.GroovyLanguage) ImageServerBuilder(qupath.lib.images.servers.ImageServerBuilder) FileNotFoundException(java.io.FileNotFoundException) TreeView(javafx.scene.control.TreeView) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) QuPathViewer(qupath.lib.gui.viewer.QuPathViewer) List(java.util.List) Duration(javafx.util.Duration) ColorToolsFX(qupath.lib.gui.tools.ColorToolsFX) Optional(java.util.Optional) LogManager(qupath.lib.gui.logging.LogManager) RadioMenuItem(javafx.scene.control.RadioMenuItem) WorkflowCommandLogView(qupath.lib.gui.panes.WorkflowCommandLogView) TextArea(javafx.scene.control.TextArea) ButtonType(javafx.scene.control.ButtonType) MouseEvent(javafx.scene.input.MouseEvent) HashMap(java.util.HashMap) BrightnessContrastCommand(qupath.lib.gui.commands.BrightnessContrastCommand) UriImageSupport(qupath.lib.images.servers.ImageServerBuilder.UriImageSupport) Dialogs(qupath.lib.gui.dialogs.Dialogs) SwingUtilities(javax.swing.SwingUtilities) HostServices(javafx.application.HostServices) ZoomEvent(javafx.scene.input.ZoomEvent) TMACommands(qupath.lib.gui.commands.TMACommands) Tooltip(javafx.scene.control.Tooltip) ImageDetailsPane(qupath.lib.gui.panes.ImageDetailsPane) ImageData(qupath.lib.images.ImageData) Desktop(java.awt.Desktop) RoiTools(qupath.lib.roi.RoiTools) ObjectProperty(javafx.beans.property.ObjectProperty) Iterator(java.util.Iterator) ProjectImageEntry(qupath.lib.projects.ProjectImageEntry) TableRow(javafx.scene.control.TableRow) PathClass(qupath.lib.objects.classes.PathClass) TMACoreObject(qupath.lib.objects.TMACoreObject) DropShadow(javafx.scene.effect.DropShadow) MenuTools(qupath.lib.gui.tools.MenuTools) BorderStrokeStyle(javafx.scene.layout.BorderStrokeStyle) ActionEvent(javafx.event.ActionEvent) ToggleGroup(javafx.scene.control.ToggleGroup) LogViewerCommand(qupath.lib.gui.commands.LogViewerCommand) SwingFXUtils(javafx.embed.swing.SwingFXUtils) Collections(java.util.Collections) InputStream(java.io.InputStream) DialogButton(qupath.lib.gui.dialogs.Dialogs.DialogButton) ImageServerBuilder(qupath.lib.images.servers.ImageServerBuilder) QuPathExtension(qupath.lib.gui.extensions.QuPathExtension) ArrayList(java.util.ArrayList) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) ScriptException(javax.script.ScriptException) FileNotFoundException(java.io.FileNotFoundException) Version(qupath.lib.common.Version) ReleaseVersion(qupath.lib.gui.extensions.UpdateChecker.ReleaseVersion)

Example 2 with Version

use of qupath.lib.common.Version in project qupath by qupath.

the class QuPathGUI method doUpdateCheck.

/**
 * Do an update check.
 * @param isAutoCheck if true, avoid prompting the user unless an update is available. If false, the update has been explicitly
 *                    requested and so the user should be notified of the outcome, regardless of whether an update is found.
 */
private synchronized void doUpdateCheck(boolean isAutoCheck) {
    String title = "Update check";
    // Get a map of all the projects we can potentially check
    Map<GitHubRepo, Version> projects = new LinkedHashMap<>();
    Map<GitHubRepo, ReleaseVersion> projectUpdates = new LinkedHashMap<>();
    // Start with the main app
    var qupathVersion = getVersion();
    if (qupathVersion != null && qupathVersion != Version.UNKNOWN) {
        projects.put(GitHubRepo.create("QuPath", "qupath", "qupath"), qupathVersion);
    }
    // Work through extensions
    for (var ext : getLoadedExtensions()) {
        var v = ext.getVersion();
        if (v != null && v != Version.UNKNOWN && ext instanceof GitHubProject) {
            var project = (GitHubProject) ext;
            projects.put(project.getRepository(), v);
        }
    }
    // Report if there is nothing to update
    if (projects.isEmpty()) {
        if (isAutoCheck) {
            logger.warn("Cannot check for updates for this installation");
        } else {
            Dialogs.showMessageDialog(title, "Sorry, no update check is available for this installation");
        }
        return;
    }
    // Check for any updates
    for (var entry : projects.entrySet()) {
        try {
            var project = entry.getKey();
            logger.info("Update check for {}", project.getUrlString());
            var release = UpdateChecker.checkForUpdate(entry.getKey());
            if (release != null && release.getVersion() != Version.UNKNOWN && entry.getValue().compareTo(release.getVersion()) < 0)
                projectUpdates.put(project, release);
        } catch (Exception e) {
            logger.error("Update check failed for {}", entry.getKey());
            logger.debug(e.getLocalizedMessage(), e);
        }
    }
    PathPrefs.getUserPreferences().putLong("lastUpdateCheck", System.currentTimeMillis());
    // If we couldn't determine the version, tell the user only if this isn't the automatic check
    if (projectUpdates.isEmpty()) {
        if (!isAutoCheck)
            Dialogs.showMessageDialog(title, "No updates found!");
        return;
    }
    // Create a table showing the updates available
    var table = new TableView<GitHubRepo>();
    table.getItems().setAll(projectUpdates.keySet());
    var colRepo = new TableColumn<GitHubRepo, String>("Name");
    colRepo.setCellValueFactory(r -> new SimpleStringProperty(r.getValue().getName()));
    var colCurrent = new TableColumn<GitHubRepo, String>("Current version");
    colCurrent.setCellValueFactory(r -> new SimpleStringProperty(projects.get(r.getValue()).toString()));
    var colNew = new TableColumn<GitHubRepo, String>("New version");
    colNew.setCellValueFactory(r -> new SimpleStringProperty(projectUpdates.get(r.getValue()).getVersion().toString()));
    table.setRowFactory(r -> {
        var row = new TableRow<GitHubRepo>();
        row.itemProperty().addListener((v, o, n) -> {
            if (n == null) {
                row.setTooltip(null);
                row.setOnMouseClicked(null);
            } else {
                var release = projectUpdates.get(n);
                var uri = release.getUri();
                if (uri == null) {
                    row.setTooltip(new Tooltip("No URL available, sorry!"));
                    row.setOnMouseClicked(null);
                } else {
                    row.setTooltip(new Tooltip(uri.toString()));
                    row.setOnMouseClicked(e -> {
                        if (e.getClickCount() > 1) {
                            launchBrowserWindow(uri.toString());
                        }
                    });
                }
            }
        });
        return row;
    });
    table.getColumns().setAll(Arrays.asList(colRepo, colCurrent, colNew));
    table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
    table.setPrefHeight(200);
    table.setPrefWidth(500);
    var checkbox = new CheckBox("Automatically check for updates on startup");
    checkbox.setSelected(PathPrefs.doAutoUpdateCheckProperty().get());
    checkbox.setMaxWidth(Double.MAX_VALUE);
    var pane = new BorderPane(table);
    checkbox.setPadding(new Insets(5, 0, 0, 0));
    pane.setBottom(checkbox);
    var result = new Dialogs.Builder().buttons(ButtonType.OK).title(title).headerText("Updates are available!\nDouble-click an entry to open the webpage, if available.").content(pane).resizable().showAndWait().orElse(ButtonType.CANCEL) == ButtonType.OK;
    if (result) {
        PathPrefs.doAutoUpdateCheckProperty().set(checkbox.isSelected());
    }
}
Also used : BorderPane(javafx.scene.layout.BorderPane) Insets(javafx.geometry.Insets) Tooltip(javafx.scene.control.Tooltip) ServerBuilder(qupath.lib.images.servers.ImageServerBuilder.ServerBuilder) ImageServerBuilder(qupath.lib.images.servers.ImageServerBuilder) GitHubProject(qupath.lib.gui.extensions.GitHubProject) SimpleStringProperty(javafx.beans.property.SimpleStringProperty) TableColumn(javafx.scene.control.TableColumn) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) ScriptException(javax.script.ScriptException) FileNotFoundException(java.io.FileNotFoundException) LinkedHashMap(java.util.LinkedHashMap) ReleaseVersion(qupath.lib.gui.extensions.UpdateChecker.ReleaseVersion) Version(qupath.lib.common.Version) ReleaseVersion(qupath.lib.gui.extensions.UpdateChecker.ReleaseVersion) CheckBox(javafx.scene.control.CheckBox) TableRow(javafx.scene.control.TableRow) GitHubRepo(qupath.lib.gui.extensions.GitHubProject.GitHubRepo) SelectedMeasurementTableView(qupath.lib.gui.panes.SelectedMeasurementTableView) TreeTableView(javafx.scene.control.TreeTableView) TableView(javafx.scene.control.TableView)

Aggregations

FileNotFoundException (java.io.FileNotFoundException)2 IOException (java.io.IOException)2 URISyntaxException (java.net.URISyntaxException)2 LinkedHashMap (java.util.LinkedHashMap)2 SimpleStringProperty (javafx.beans.property.SimpleStringProperty)2 Insets (javafx.geometry.Insets)2 CheckBox (javafx.scene.control.CheckBox)2 TableColumn (javafx.scene.control.TableColumn)2 TableRow (javafx.scene.control.TableRow)2 TableView (javafx.scene.control.TableView)2 Tooltip (javafx.scene.control.Tooltip)2 TreeTableView (javafx.scene.control.TreeTableView)2 BorderPane (javafx.scene.layout.BorderPane)2 ScriptException (javax.script.ScriptException)2 Version (qupath.lib.common.Version)2 GitHubProject (qupath.lib.gui.extensions.GitHubProject)2 GitHubRepo (qupath.lib.gui.extensions.GitHubProject.GitHubRepo)2 ReleaseVersion (qupath.lib.gui.extensions.UpdateChecker.ReleaseVersion)2 SelectedMeasurementTableView (qupath.lib.gui.panes.SelectedMeasurementTableView)2 ImageServerBuilder (qupath.lib.images.servers.ImageServerBuilder)2