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);
}
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());
}
}
Aggregations