From 4dc52f9c5798fa0c01ffecc1421633d258a77df1 Mon Sep 17 00:00:00 2001 From: Thomas <thomas.musset@pasteur.fr> Date: Mon, 1 Jul 2024 17:45:31 +0200 Subject: [PATCH] updated pom to v2.0.0-a.1, fix classes accordingly to new architecture, added icon, updated .gitignore --- .gitignore | 46 ++++-- pom.xml | 10 +- .../Microscopy/MicroManager/MicroManager.java | 153 ++++++++---------- .../MicroManager/core/AcquisitionHandler.java | 31 ++-- .../MicroManager/core/AcquisitionResult.java | 13 +- .../event/AcquisitionListener.java | 4 +- .../MicroManager/event/CoreListener.java | 2 +- .../MicroManager/event/LiveListener.java | 4 +- .../MicroManager/gui/AboutPanel.java | 4 +- .../gui/AcquisitionInfoPanel.java | 10 +- .../MicroManager/gui/ActionsPanel.java | 46 +++--- .../MicroManager/gui/CameraSettingsPanel.java | 56 +++---- .../MicroManager/gui/ChannelTable.java | 14 +- .../MicroManager/gui/ConfigurationPanel.java | 35 ++-- .../MicroManager/gui/LiveSettingsPanel.java | 6 +- .../MicroManager/gui/LoadFrame.java | 35 ++-- .../MicroManager/gui/LoadingFrame.java | 8 +- .../MicroManager/gui/MMMainFrame.java | 82 ++++------ .../MicroManager/gui/MainPanel.java | 2 +- .../MicroManager/gui/OptionsPanel.java | 4 +- .../MicroManager/gui/PluginsToolbar.java | 40 ++--- .../MicroManager/patch/ClassPatcher.java | 45 +++--- .../MicroManager/patch/MMPatcher.java | 4 +- .../MicroManager/patch/MMStudioMethods.java | 7 +- .../MicroManager/tools/FrameUtils.java | 56 +------ .../MicroManager/tools/MMUtils.java | 110 ++++++------- .../MicroManager/tools/StageMover.java | 28 ++-- .../MicromanagerPlugin.java | 10 +- .../MicroManagerForIcy/MicroscopePlugin.java | 4 +- src/main/resources/mmj.png | Bin 0 -> 15076 bytes 30 files changed, 403 insertions(+), 466 deletions(-) create mode 100644 src/main/resources/mmj.png diff --git a/.gitignore b/.gitignore index 4d4593d..57f16fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,41 @@ -.idea/ -.settings/ -workspace/ -build/ +/build* +/workspace +setting.xml +release/ target/ -bin/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +icy.log + +### IntelliJ IDEA ### +.idea/ +*.iws *.iml -*.eml -*.jar -.project +*.ipr + +### Eclipse ### +.apt_generated .classpath -export.jardesc +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### **/.DS_Store +Icon? \ No newline at end of file diff --git a/pom.xml b/pom.xml index e8a2787..3c35a3a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,11 +7,11 @@ <parent> <artifactId>pom-icy</artifactId> <groupId>org.bioimageanalysis.icy</groupId> - <version>2.2.0</version> + <version>3.0.0-a.1</version> </parent> <artifactId>micromanager</artifactId> - <version>2.0.0</version> + <version>2.0.0-a.1</version> <name>MicroManager for Icy</name> <description> @@ -20,10 +20,6 @@ Compatible with Micro-Manager 1.4.19 or above but we recommend to use the current last (1.4.23 / nightly build) </description> - <properties> - <artifact-to-extract>MMCoreJ,MMJ_</artifact-to-extract> - </properties> - <dependencies> <dependency> <groupId>org.micromanager</groupId> @@ -40,7 +36,7 @@ <repositories> <repository> <id>icy</id> - <url>https://icy-nexus.pasteur.fr/repository/Icy/</url> + <url>https://nexus-icy.pasteur.cloud/repository/icy/</url> </repository> </repositories> </project> \ No newline at end of file diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/MicroManager.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/MicroManager.java index 91a6305..f695b7a 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/MicroManager.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/MicroManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,21 +18,24 @@ package plugins.tprovoost.Microscopy.MicroManager; -import icy.common.Version; -import icy.file.FileUtil; -import icy.gui.dialog.MessageDialog; -import icy.gui.frame.progress.FailedAnnounceFrame; -import icy.image.IcyBufferedImage; -import icy.main.Icy; -import icy.sequence.Sequence; -import icy.system.IcyExceptionHandler; -import icy.system.thread.ThreadUtil; -import icy.util.ClassUtil; -import icy.util.StringUtil; import mmcorej.CMMCore; import mmcorej.MMCoreJ; import mmcorej.StrVector; import mmcorej.TaggedImage; +import org.bioimageanalysis.icy.Icy; +import org.bioimageanalysis.icy.common.Version; +import org.bioimageanalysis.icy.common.reflect.ClassUtil; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.gui.dialog.MessageDialog; +import org.bioimageanalysis.icy.gui.frame.progress.FailedAnnounceFrame; +import org.bioimageanalysis.icy.io.FileUtil; +import org.bioimageanalysis.icy.model.image.IcyBufferedImage; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.json.JSONObject; import org.micromanager.MMStudio; import org.micromanager.MMVersion; @@ -85,6 +88,7 @@ public class MicroManager { /** * @return the MicroManager main frame instance. */ + @Contract(pure = true) public static MMMainFrame getInstance() { // initialize micro manager if needed --> NO ! we need to init ourself // if (instance == null) @@ -96,14 +100,16 @@ public class MicroManager { /** * @return the MicroManager version */ - public static Version getMMVersion() { + @Contract(value = " -> new", pure = true) + public static @NotNull Version getMMVersion() { // is this method really safe ?? - return new Version(MMVersion.VERSION_STRING); + return Version.fromString(MMVersion.VERSION_STRING); } /** * @return the core listener list. */ + @Contract(pure = true) public static List<CoreListener> getCoreListeners() { final List<CoreListener> result; @@ -136,6 +142,7 @@ public class MicroManager { /** * @return the acquisition listener list. */ + @Contract(pure = true) public static List<AcquisitionListener> getAcquisitionListeners() { final List<AcquisitionListener> result; @@ -170,6 +177,7 @@ public class MicroManager { /** * @return the live listener list. */ + @Contract(pure = true) public static List<LiveListener> getLiveListeners() { final List<LiveListener> result; @@ -210,49 +218,13 @@ public class MicroManager { } } - /** - * @param listener the <i>acquisition</i> listener to register - * @deprecated Use {@link #addAcquisitionListener(AcquisitionListener)} instead. - */ - @Deprecated - public static void registerListener(final AcquisitionListener listener) { - addAcquisitionListener(listener); - } - - /** - * @param listener the <i>acquisition</i> listener to remove - * @deprecated Use {@link #removeAcquisitionListener(AcquisitionListener)} instead. - */ - @Deprecated - public static void removeListener(final AcquisitionListener listener) { - removeAcquisitionListener(listener); - } - - /** - * @param listener the <i>live</i> listener to register - * @deprecated Use {@link #addLiveListener(LiveListener)} instead. - */ - @Deprecated - public static void registerListener(final LiveListener listener) { - addLiveListener(listener); - } - - /** - * @param listener the <i>live</i> listener to remove - * @deprecated Use {@link #removeLiveListener(LiveListener)} instead. - */ - @Deprecated - public static void removeListener(final LiveListener listener) { - removeLiveListener(listener); - } - /** * Use this to access micro-manager main object to access low level function that * are not been implemented in Icy's micro-Manager. * * @return The micro-manager main studio object. */ - public static MMStudio getMMStudio() { + public static @Nullable MMStudio getMMStudio() { final MMMainFrame inst = getInstance(); if (inst == null) return null; @@ -271,7 +243,7 @@ public class MicroManager { * * @return The micro-manager core object */ - public static CMMCore getCore() { + public static @Nullable CMMCore getCore() { final MMStudio mmstudio = getMMStudio(); if (mmstudio == null) return null; @@ -389,7 +361,7 @@ public class MicroManager { /** * @return The acquisition engine wrapper from MicroManager. */ - public static AcquisitionWrapperEngine getAcquisitionEngine() { + public static @Nullable AcquisitionWrapperEngine getAcquisitionEngine() { final MMStudio mmstudio = getMMStudio(); if (mmstudio == null) return null; @@ -400,7 +372,7 @@ public class MicroManager { /** * @return The internal new acquisition engine from MicroManager. */ - public static IAcquisitionEngine2010 getAcquisitionEngine2010() { + public static @Nullable IAcquisitionEngine2010 getAcquisitionEngine2010() { final MMStudio mmstudio = getMMStudio(); if (mmstudio == null) return null; @@ -412,7 +384,7 @@ public class MicroManager { * @return The engine settings for the most recently started acquisition sequence, or return * null if you never started an acquisition. */ - public static SequenceSettings getAcquisitionSettings() { + public static @Nullable SequenceSettings getAcquisitionSettings() { final AcquisitionWrapperEngine acqEngine = getAcquisitionEngine(); if (acqEngine == null) return null; @@ -424,7 +396,7 @@ public class MicroManager { * @return The summaryMetadata for the most recently started acquisition sequence, or return * null if you never started an acquisition. */ - public static JSONObject getAcquisitionMetaData() { + public static @Nullable JSONObject getAcquisitionMetaData() { final AcquisitionWrapperEngine acqEngine = getAcquisitionEngine(); if (acqEngine == null) return null; @@ -499,7 +471,7 @@ public class MicroManager { * {@link #addAcquisitionListener(AcquisitionListener)}<br> * @throws Exception if an error occurred while retrieved last tagged images */ - public static List<TaggedImage> getLastTaggedImage() throws Exception { + public static @NotNull List<TaggedImage> getLastTaggedImage() throws Exception { final CMMCore core = MicroManager.getCore(); if (core == null || !core.isSequenceRunning()) @@ -567,7 +539,7 @@ public class MicroManager { * @return next captured image as List of {@link TaggedImage} or an empty list if the continuous acquisition is not running * @throws Exception if an error occurred */ - public static List<TaggedImage> getNextTaggedImage() throws Exception { + public static @NotNull List<TaggedImage> getNextTaggedImage() throws Exception { final CMMCore core = MicroManager.getCore(); if (core == null || !core.isSequenceRunning()) @@ -575,16 +547,19 @@ public class MicroManager { final boolean[] done = new boolean[]{false}; final LiveListener listener = new LiveListener() { + @Contract(pure = true) @Override public void liveStopped() { done[0] = true; } + @Contract(pure = true) @Override public void liveStarted() { // nothing here } + @Contract(pure = true) @Override public void liveImgReceived(final List<TaggedImage> images) { done[0] = true; @@ -642,7 +617,7 @@ public class MicroManager { * @return the captured image as List of {@link TaggedImage} * @throws Exception if an error occurred */ - public static List<TaggedImage> snapTaggedImage() throws Exception { + public static @NotNull List<TaggedImage> snapTaggedImage() throws Exception { final CMMCore core = MicroManager.getCore(); if (core == null) return new ArrayList<>(); @@ -846,7 +821,7 @@ public class MicroManager { * @return the list of sequence corresponding to the last sequence acquisition or * <code>null</code> if no acquisition was done. * @see #startAcquisition(int, double) */ - public static List<Sequence> getAcquisitionResult() { + public static @Nullable List<Sequence> getAcquisitionResult() { if ((acquisitionManager == null) || acquisitionManager.getSequences().isEmpty()) return null; @@ -923,7 +898,7 @@ public class MicroManager { * @return the current camera binning mode (String format) * @throws Exception if an error occurred */ - private static String getBinningAsString(final CMMCore core, final String camera) throws Exception { + private static String getBinningAsString(final @NotNull CMMCore core, final String camera) throws Exception { return core.getProperty(camera, MMCoreJ.getG_Keyword_Binning()); } @@ -1175,7 +1150,7 @@ public class MicroManager { /** * @return all available config group */ - public static List<String> getConfigGroups() { + public static @NotNull List<String> getConfigGroups() { final CMMCore core = getCore(); if (core == null) return new ArrayList<>(); @@ -1193,7 +1168,7 @@ public class MicroManager { * @param group group name * @return all available config preset for the specified group */ - public static List<String> getConfigs(final String group) { + public static @NotNull List<String> getConfigs(final String group) { final CMMCore core = getCore(); if (core == null) return new ArrayList<>(); @@ -1278,6 +1253,7 @@ public class MicroManager { /** * @return internal preset name set on last call to {@link #setConfigForGroup(String, String, boolean)} method (workaround for MM empty preset name bug) */ + @Contract(pure = true) public static String getInternalSetPreset() { if (inConfigSet) return lastPresetSet; @@ -1336,7 +1312,7 @@ public class MicroManager { * @see #getChannelGroup() * @see #getConfigs(String) */ - public static List<String> getChannelConfigs() { + public static @NotNull List<String> getChannelConfigs() { return getConfigs(MicroManager.getChannelGroup()); } @@ -1408,6 +1384,7 @@ public class MicroManager { * @return <code>true</code> if Micro-Manager is initialized / loaded.<br> * @see MicromanagerPlugin#init() */ + @Contract(pure = true) public static boolean isInitialized() { return instance != null; } @@ -1450,17 +1427,19 @@ public class MicroManager { } catch (final Throwable t) { // an fatal error occurred, force error on version checking then... - version = new Version("1"); + version = new Version(1); } // cannot get version or wrong version ? - if ((version == null) || version.isLower(new Version("1.4.19"))) + if ((version == null) || version.isLower(new Version(1, 4, 19))) // || version.isGreater(new Version("1.4.22"))) { MessageDialog.showDialog("Error while loading Micro-Manager", - "Your version of Micro-Manager seems to not be compatible !\n" + "This plugin is only compatible with version 1.4.19 or above.\n" - + "Also check that you are using the same architecture for Icy and Micro-Manager (32/64 bits)\n" - + "You need to restart Icy to redefine the Micro-Manager folder.", + """ + Your version of Micro-Manager seems to not be compatible ! + This plugin is only compatible with version 1.4.19 or above. + Also check that you are using the same architecture for Icy and Micro-Manager (32/64 bits) + You need to restart Icy to redefine the Micro-Manager folder.""", MessageDialog.ERROR_MESSAGE); // so user can change the defined MM folder MMUtils.resetLibrayPath(); @@ -1480,9 +1459,7 @@ public class MicroManager { instance = new MMMainFrame(); } catch (final Throwable e) { - IcyExceptionHandler.showErrorMessage(e, true, true); - MessageDialog.showDialog("Error while loading Micro-Manager", e.getMessage() + "\nYou may try to restart Icy to fix the issue.", - MessageDialog.ERROR_MESSAGE); + IcyLogger.error(MicroManager.class, e, "Error while loading Micro-Manager.", "You may try to restart Icy to fix the issue."); return; } @@ -1529,8 +1506,7 @@ public class MicroManager { cleanOldMM(); } catch (final Throwable e) { - IcyExceptionHandler.showErrorMessage(e, true, true); - new FailedAnnounceFrame("An error occurred while initializing Micro-Manager (see console output for more details)."); + IcyLogger.error(MicroManager.class, e, "Error while initializing Micro-Manager."); // shutdown everything shutdown(); @@ -1543,8 +1519,10 @@ public class MicroManager { // cannot load class --> version mismatch probably MessageDialog .showDialog("Cannot load Micro-Manager", - "Your version of Micro-Manager seems to not be compatible !\n" + "This plugin is only compatible with version 1.4.19 or above.\n" - + "Also check that you are using the same architecture for Icy and Micro-Manager (32/64 bits).", + """ + Your version of Micro-Manager seems to not be compatible ! + This plugin is only compatible with version 1.4.19 or above. + Also check that you are using the same architecture for Icy and Micro-Manager (32/64 bits).""", MessageDialog.ERROR_MESSAGE); } } @@ -1609,17 +1587,17 @@ public class MicroManager { stopLiveMode(); } catch (final Throwable t) { - IcyExceptionHandler.showErrorMessage(t, true); + IcyLogger.error(MicroManager.class, t); } } - if (liveListeners != null) - liveListeners.clear(); - if (acqListeners != null) - acqListeners.clear(); + //if (liveListeners != null) + liveListeners.clear(); + //if (acqListeners != null) + acqListeners.clear(); StageMover.clearListener(); - if (metadatas != null) - metadatas.clear(); + //if (metadatas != null) + metadatas.clear(); // stop live listener if (liveManager != null) { @@ -1674,8 +1652,7 @@ public class MicroManager { final JSONObject tags = image.tags; - final boolean firstImage = (MDUtils.getPositionIndex(tags) == 0) && (MDUtils.getFrameIndex(tags) == 0) && (MDUtils.getChannelIndex(tags) == 0) - && (MDUtils.getSliceIndex(tags) == 0); + final boolean firstImage = (MDUtils.getPositionIndex(tags) == 0) && (MDUtils.getFrameIndex(tags) == 0) && (MDUtils.getChannelIndex(tags) == 0) && (MDUtils.getSliceIndex(tags) == 0); final boolean newAcquisition = (acquisitionManager == null) || acquisitionManager.isDone(); // first acquisition image or new acquisition --> create the new acquisition @@ -1717,7 +1694,7 @@ public class MicroManager { l.acqImgReveived(image); } catch (final Exception e) { - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(MicroManager.class, e); } } } @@ -1753,7 +1730,7 @@ public class MicroManager { catch (final Exception e) { // can happen with advanced acquisition set with a lower time // interval than current exposure time - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(MicroManager.class, e); } } } @@ -1769,7 +1746,7 @@ public class MicroManager { } catch (final Exception e) { // should not happen - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(MicroManager.class, e); } } diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/core/AcquisitionHandler.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/core/AcquisitionHandler.java index fe236a8..f5c973d 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/core/AcquisitionHandler.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/core/AcquisitionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,15 +18,16 @@ package plugins.tprovoost.Microscopy.MicroManager.core; -import icy.gui.frame.IcyFrame; -import icy.gui.frame.IcyFrameAdapter; -import icy.gui.frame.IcyFrameEvent; -import icy.gui.util.GuiUtil; -import icy.sequence.Sequence; -import icy.system.IcyExceptionHandler; -import icy.system.thread.ThreadUtil; -import icy.util.ReflectionUtil; import mmcorej.TaggedImage; +import org.bioimageanalysis.icy.common.reflect.ReflectionUtil; +import org.bioimageanalysis.icy.gui.GuiUtil; +import org.bioimageanalysis.icy.gui.frame.IcyFrame; +import org.bioimageanalysis.icy.gui.frame.IcyFrameAdapter; +import org.bioimageanalysis.icy.gui.frame.IcyFrameEvent; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; +import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; import org.micromanager.MMStudio; @@ -65,7 +66,7 @@ public class AcquisitionHandler implements AcquisitionListener { MicroManager.addAcquisitionListener(this); } - private void initDialog(final MMMainFrame mainFrame) { + private void initDialog(final @NotNull MMMainFrame mainFrame) { final MMStudio mmstudio = mainFrame.getMMStudio(); try { @@ -73,7 +74,7 @@ public class AcquisitionHandler implements AcquisitionListener { advAcqDialog = (AcqControlDlg) ReflectionUtil.getFieldObject(mmstudio, "acqControlWin_"); } catch (final Exception ex) { - System.err.println("Warning: cannot retrieve AcqControlDlg from Micro-Manager."); + IcyLogger.warn(this.getClass(), ex, "Cannot retrieve AcqControlDlg from Micro-Manager."); } // not existing yet ? --> create it now @@ -85,7 +86,7 @@ public class AcquisitionHandler implements AcquisitionListener { ReflectionUtil.getField(mmstudio.getClass(), "acqControlWin_").set(mmstudio, advAcqDialog); } catch (final Exception ex) { - System.err.println("Warning: cannot set AcqControlDlg from Micro-Manager."); + IcyLogger.warn(this.getClass(), ex, "Cannot set AcqControlDlg from Micro-Manager."); } } @@ -199,7 +200,7 @@ public class AcquisitionHandler implements AcquisitionListener { MicroManager.stopLiveMode(); } catch (final Exception e) { - IcyExceptionHandler.showErrorMessage(e, false); + IcyLogger.error(this.getClass(), e); } } @@ -229,7 +230,7 @@ public class AcquisitionHandler implements AcquisitionListener { }); } catch (final JSONException e) { - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(this.getClass(), e); } } @@ -246,7 +247,7 @@ public class AcquisitionHandler implements AcquisitionListener { MicroManager.startLiveMode(); } catch (final Exception e) { - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(this.getClass(), e); } liveModeWasRunning = false; diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/core/AcquisitionResult.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/core/AcquisitionResult.java index 23cfb5a..5c75c65 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/core/AcquisitionResult.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/core/AcquisitionResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,11 +18,12 @@ package plugins.tprovoost.Microscopy.MicroManager.core; -import icy.gui.viewer.Viewer; -import icy.main.Icy; -import icy.sequence.Sequence; -import icy.util.StringUtil; import mmcorej.TaggedImage; +import org.bioimageanalysis.icy.Icy; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.gui.viewer.Viewer; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; import org.micromanager.api.SequenceSettings; @@ -61,7 +62,7 @@ public class AcquisitionResult { return new ArrayList<>(sequences.values()); } - public void imageReceived(final TaggedImage taggedImage) throws JSONException, MMScriptException { + public void imageReceived(final @NotNull TaggedImage taggedImage) throws JSONException, MMScriptException { final JSONObject tags = taggedImage.tags; final Integer position = MDUtils.getPositionIndex(tags); diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/AcquisitionListener.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/AcquisitionListener.java index f1c04f5..083ea0f 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/AcquisitionListener.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/AcquisitionListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,8 +18,8 @@ package plugins.tprovoost.Microscopy.MicroManager.event; -import icy.sequence.Sequence; import mmcorej.TaggedImage; +import org.bioimageanalysis.icy.model.sequence.Sequence; import org.json.JSONObject; import org.micromanager.api.SequenceSettings; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/CoreListener.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/CoreListener.java index f466c01..53936b0 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/CoreListener.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/CoreListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/LiveListener.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/LiveListener.java index 8d2b2d8..585c6ad 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/LiveListener.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/event/LiveListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,8 +18,8 @@ package plugins.tprovoost.Microscopy.MicroManager.event; -import icy.sequence.Sequence; import mmcorej.TaggedImage; +import org.bioimageanalysis.icy.model.sequence.Sequence; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; import plugins.tprovoost.Microscopy.MicroManager.tools.MMUtils; diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/AboutPanel.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/AboutPanel.java index 1067b46..12f9fc6 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/AboutPanel.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/AboutPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.network.NetworkUtil; +import org.bioimageanalysis.icy.network.NetworkUtil; import org.micromanager.MMVersion; import javax.swing.*; diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/AcquisitionInfoPanel.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/AcquisitionInfoPanel.java index c46f9ff..b36d1e7 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/AcquisitionInfoPanel.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/AcquisitionInfoPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,9 +18,10 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.math.MathUtil; -import icy.system.thread.ThreadUtil; import mmcorej.CMMCore; +import org.bioimageanalysis.icy.common.math.MathUtil; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; import plugins.tprovoost.Microscopy.MicroManager.tools.StageMover; @@ -251,8 +252,7 @@ public class AcquisitionInfoPanel extends JPanel implements Runnable { setPixelSize(core.getPixelSizeUm()); } catch (final Throwable t) { - System.err.println("Warning: can't read camera informations from Micro-Manager"); - System.err.println("Cause: " + t); + IcyLogger.warn(this.getClass(), t, "Cannot read camera information from Micro-Manager."); } } } diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ActionsPanel.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ActionsPanel.java index f28a4e1..f41c073 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ActionsPanel.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ActionsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,20 +18,20 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.gui.component.button.IcyButton; -import icy.gui.component.button.IcyToggleButton; -import icy.gui.dialog.MessageDialog; -import icy.main.Icy; -import icy.math.FPSMeter; -import icy.resource.ResourceUtil; -import icy.resource.icon.IcyIcon; -import icy.sequence.Sequence; -import icy.sequence.SequenceEvent; -import icy.sequence.SequenceListener; -import icy.system.IcyExceptionHandler; -import icy.util.StringUtil; import mmcorej.CMMCore; import mmcorej.TaggedImage; +import org.bioimageanalysis.icy.Icy; +import org.bioimageanalysis.icy.common.math.FPSMeter; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.gui.component.button.IcyButton; +import org.bioimageanalysis.icy.gui.component.button.IcyToggleButton; +import org.bioimageanalysis.icy.gui.component.icon.SVGIcon; +import org.bioimageanalysis.icy.gui.dialog.MessageDialog; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.bioimageanalysis.icy.model.sequence.SequenceEvent; +import org.bioimageanalysis.icy.model.sequence.SequenceListener; +import org.bioimageanalysis.icy.system.IcyExceptionHandler; +import org.bioimageanalysis.icy.system.logging.IcyLogger; import org.json.JSONObject; import org.micromanager.MMStudio; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; @@ -116,7 +116,7 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen gridBagLayout.rowWeights = new double[]{1.0, 1.0, 1.0, 1.0, 1.0, Double.MIN_VALUE}; setLayout(gridBagLayout); - snapBtn = new IcyButton("Snap", new IcyIcon(ResourceUtil.ICON_PHOTO)); + snapBtn = new IcyButton("Snap", SVGIcon.PHOTO_CAMERA); snapBtn.setToolTipText("Snap an image"); snapBtn.setIconTextGap(12); final GridBagConstraints gbc_snapBtn = new GridBagConstraints(); @@ -126,7 +126,7 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen gbc_snapBtn.gridy = 0; add(snapBtn, gbc_snapBtn); - liveBtn = new IcyToggleButton("Live", new IcyIcon("camera")); + liveBtn = new IcyToggleButton("Live", SVGIcon.VIDEOCAM); liveBtn.setToolTipText("Enable / Disable the live display"); liveBtn.setIconTextGap(12); final GridBagConstraints gbc_liveBtn = new GridBagConstraints(); @@ -136,7 +136,7 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen gbc_liveBtn.gridy = 1; add(liveBtn, gbc_liveBtn); - albumBtn = new IcyButton("Album", new IcyIcon("movie")); + albumBtn = new IcyButton("Album", SVGIcon.CAMERA_ROLL); albumBtn.setToolTipText("Snap an image and store it in the album"); albumBtn.setIconTextGap(12); final GridBagConstraints gbc_albumBtn = new GridBagConstraints(); @@ -146,7 +146,7 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen gbc_albumBtn.gridy = 2; add(albumBtn, gbc_albumBtn); - advAcqBtn = new IcyButton("Multi-D Acq.", new IcyIcon(ResourceUtil.ICON_LAYER_V1)); + advAcqBtn = new IcyButton("Multi-D Acq.", SVGIcon.LAYERS); advAcqBtn.setToolTipText("Multi dimension acquisition"); advAcqBtn.setIconTextGap(8); final GridBagConstraints gbc_advAcqBtn = new GridBagConstraints(); @@ -156,7 +156,7 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen gbc_advAcqBtn.gridy = 3; add(advAcqBtn, gbc_advAcqBtn); - refreshBtn = new IcyButton("Refresh", new IcyIcon(ResourceUtil.ICON_RELOAD)); + refreshBtn = new IcyButton("Refresh", SVGIcon.REPLAY); refreshBtn.setToolTipText("Force GUI refresh"); refreshBtn.setIconTextGap(12); final GridBagConstraints gbc_refreshBtn = new GridBagConstraints(); @@ -403,7 +403,7 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen liveSequence.beginUpdate(); try { // format not anymore compatible --> need to clear sequence first - if (!MMUtils.isCompatible(liveSequence, images.get(0).tags)) + if (!MMUtils.isCompatible(liveSequence, images.getFirst().tags)) liveSequence.removeAllImages(); final LiveSettingsPanel livePanel = mainFrame.livePanel; @@ -474,8 +474,7 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen } } catch (final Exception e) { - System.err.println("MicroManager: cannot update live image."); - IcyExceptionHandler.showErrorMessage(e, false, true); + IcyLogger.error(this.getClass(), e, "Cannot update live image."); } finally { liveSequence.endUpdate(); @@ -499,7 +498,6 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen @Override public void sequenceChanged(final SequenceEvent sequenceEvent) { // ignore this event - } @Override @@ -511,7 +509,7 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen if (sequence == albumSequence) { // album not saved ? //if (StringUtil.isEmpty(sequence.getFilename())) { - // ask user if he want to save it + // ask user if he wants to save it //} // clear it @@ -561,7 +559,7 @@ public class ActionsPanel extends JPanel implements LiveListener, SequenceListen } } catch (final Exception e) { - System.err.println("MicroManager: cannot process stack acquisition."); + //IcyLogger.error(this.getClass(), e, "Stack acquisition failed."); IcyExceptionHandler.handleException(e, true); } } diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/CameraSettingsPanel.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/CameraSettingsPanel.java index 48a128a..48183ad 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/CameraSettingsPanel.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/CameraSettingsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,18 +18,17 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.gui.component.NumberTextField; -import icy.gui.component.button.IcyButton; -import icy.gui.component.button.IcyToggleButton; -import icy.gui.dialog.MessageDialog; -import icy.resource.icon.IcyIcon; -import icy.system.IcyExceptionHandler; -import icy.system.thread.ThreadUtil; -import icy.util.StringUtil; import mmcorej.CMMCore; import mmcorej.DeviceType; import mmcorej.MMCoreJ; import mmcorej.StrVector; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.gui.component.button.IcyButton; +import org.bioimageanalysis.icy.gui.component.button.IcyToggleButton; +import org.bioimageanalysis.icy.gui.component.field.NumberTextField; +import org.bioimageanalysis.icy.gui.component.icon.SVGIcon; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; import org.micromanager.MMStudio; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; @@ -116,8 +115,7 @@ public class CameraSettingsPanel extends JPanel implements Runnable { refreshOpenShutterButton(open); } catch (final Throwable t) { - MessageDialog.showDialog("Cannot change shutter state: " + t, MessageDialog.ERROR_MESSAGE); - System.err.println("Cannot change shutter state: " + t); + IcyLogger.error(this.getClass(), t, "Cannot change shutter state."); } }); lblAutoShutter.addMouseListener(new MouseAdapter() { @@ -145,8 +143,7 @@ public class CameraSettingsPanel extends JPanel implements Runnable { shutterOpenBtn.setEnabled(!autoshutter); } catch (final Throwable t) { - MessageDialog.showDialog("Cannot set auto shutter: " + t, MessageDialog.ERROR_MESSAGE); - System.err.println("Cannot set auto shutter: " + t); + IcyLogger.error(this.getClass(), t, "Cannot set auto shutter."); } }); autofocusBtn.addActionListener(e -> { @@ -154,14 +151,14 @@ public class CameraSettingsPanel extends JPanel implements Runnable { if (studio != null) studio.autofocusNow(); else - System.err.println("MMStudio is null, cannot autofocus"); + IcyLogger.error(this.getClass(), "Cannot autofocus now (MMStudio is null)."); }); autofocusSettingBtn.addActionListener(e -> { final MMStudio studio = MicroManager.getMMStudio(); if (studio != null) studio.showAutofocusDialog(); else - System.err.println("MMStudio is null, cannot open autofocus setting panel"); + IcyLogger.error(this.getClass(), "Cannot show autofocus dialog (MMStudio is null)."); }); } @@ -226,7 +223,7 @@ public class CameraSettingsPanel extends JPanel implements Runnable { gbc_shuttersCombo.gridy = 2; add(shuttersCombo, gbc_shuttersCombo); - shutterOpenBtn = new IcyToggleButton("Open", new IcyIcon("shutter")); + shutterOpenBtn = new IcyToggleButton("Open", SVGIcon.CAMERA); shutterOpenBtn.setIconTextGap(10); shutterOpenBtn.setToolTipText("Open / close the shutter"); @@ -265,7 +262,7 @@ public class CameraSettingsPanel extends JPanel implements Runnable { gbc_lblAutofocus.gridy = 4; add(lblAutofocus, gbc_lblAutofocus); - autofocusBtn = new IcyButton(new IcyIcon("autofocus")); + autofocusBtn = new IcyButton(SVGIcon.CENTER_FOCUS_STRONG); autofocusBtn.setToolTipText("Perform autofocus now"); final GridBagConstraints gbc_autofocusBtn = new GridBagConstraints(); gbc_autofocusBtn.fill = GridBagConstraints.BOTH; @@ -274,7 +271,7 @@ public class CameraSettingsPanel extends JPanel implements Runnable { gbc_autofocusBtn.gridy = 4; add(autofocusBtn, gbc_autofocusBtn); - autofocusSettingBtn = new IcyButton(new IcyIcon("af_setting")); + autofocusSettingBtn = new IcyButton(SVGIcon.SETTINGS_PHOTO_CAMERA); autofocusSettingBtn.setToolTipText("Autofocus settings"); final GridBagConstraints gbc_autoFocusSettingBtn = new GridBagConstraints(); gbc_autoFocusSettingBtn.fill = GridBagConstraints.BOTH; @@ -299,13 +296,15 @@ public class CameraSettingsPanel extends JPanel implements Runnable { mainFrame.unlock(); } + /*@Deprecated(forRemoval = true) public void logError(final Exception e) { getMMStudio().logError(e); - } + }*/ + /*@Deprecated(forRemoval = true) public void logError(final Exception e, final String msg) { getMMStudio().logError(e, msg); - } + }*/ public String getCameraName() { return cameraName; @@ -343,8 +342,8 @@ public class CameraSettingsPanel extends JPanel implements Runnable { MicroManager.setExposure(exposure); } catch (final Exception e) { - logError(e, "Couldn't set exposure time."); - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(this.getClass(), e, "Cannot set exposure time."); + //logError(e, "Couldn't set exposure time."); } } @@ -360,8 +359,8 @@ public class CameraSettingsPanel extends JPanel implements Runnable { MicroManager.setBinning(binning); } catch (final Exception e) { - logError(e, "Couldn't set camera binning."); - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(this.getClass(), e, "Cannot set camera binning."); + //logError(e, "Couldn't set camera binning."); } } @@ -420,7 +419,8 @@ public class CameraSettingsPanel extends JPanel implements Runnable { } } catch (final Exception e) { - logError(e); + IcyLogger.error(this.getClass(), e); + //logError(e); } } @@ -463,7 +463,8 @@ public class CameraSettingsPanel extends JPanel implements Runnable { } } catch (final Exception e) { - logError(e); + IcyLogger.error(this.getClass(), e); + //logError(e); } } @@ -512,7 +513,8 @@ public class CameraSettingsPanel extends JPanel implements Runnable { autoShutterCheckbox.setSelected(autoShutter); } catch (final Exception e) { - logError(e); + IcyLogger.error(this.getClass(), e); + //logError(e); } } diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ChannelTable.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ChannelTable.java index bb67d21..62c1426 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ChannelTable.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ChannelTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,10 +18,10 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.system.IcyExceptionHandler; import mmcorej.CMMCore; import mmcorej.Configuration; import mmcorej.PropertySetting; +import org.bioimageanalysis.icy.system.logging.IcyLogger; import org.micromanager.acquisition.AcquisitionWrapperEngine; import org.micromanager.dialogs.ChannelCellEditor; import org.micromanager.dialogs.ChannelCellRenderer; @@ -42,7 +42,7 @@ import java.util.List; /** * Custom table representing channel definition for Micro-Manager advanced acquisition * - * @author Stephane + * @author Stephane Dallongeville */ public class ChannelTable extends JTable { final protected ChannelTableModel model; @@ -118,8 +118,7 @@ public class ChannelTable extends JTable { return true; } catch (final Throwable t) { - System.err.println("Cannot set channel group in Micro-Manager."); - IcyExceptionHandler.showErrorMessage(t, true); + IcyLogger.error(ChannelTable.class, t, "Cannot set channel group in Micro-Manager."); } } @@ -135,7 +134,7 @@ public class ChannelTable extends JTable { if (!cfgs.isEmpty()) { try { - final Configuration presetData = core.getConfigData(group, cfgs.get(0)); + final Configuration presetData = core.getConfigData(group, cfgs.getFirst()); if (presetData.size() >= 1L) { final PropertySetting setting = presetData.getSetting(0L); @@ -147,8 +146,7 @@ public class ChannelTable extends JTable { } } catch (final Exception e) { - System.err.println("Error with Micro-Manager:"); - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(ChannelTable.class, e, "Error with Micro-Manager"); return false; } } diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ConfigurationPanel.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ConfigurationPanel.java index d8b61bf..dcc7a0c 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ConfigurationPanel.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/ConfigurationPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,15 +18,14 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.gui.component.button.IcyButton; -import icy.gui.dialog.ConfirmDialog; -import icy.gui.dialog.MessageDialog; -import icy.resource.ResourceUtil; -import icy.resource.icon.IcyIcon; -import icy.system.IcyExceptionHandler; -import icy.system.thread.ThreadUtil; -import icy.util.StringUtil; import mmcorej.CMMCore; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.gui.component.button.IcyButton; +import org.bioimageanalysis.icy.gui.component.icon.SVGIcon; +import org.bioimageanalysis.icy.gui.dialog.ConfirmDialog; +import org.bioimageanalysis.icy.gui.dialog.MessageDialog; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; import org.micromanager.ConfigGroupPad; import org.micromanager.MMStudio; import org.micromanager.dialogs.GroupEditor; @@ -81,7 +80,7 @@ public class ConfigurationPanel extends JPanel { ThreadUtil.invokeLater(() -> refreshGroupNow(groupNameRefresh, configName)); } catch (final Exception e) { - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(this.getClass(), e); } }; } @@ -104,7 +103,7 @@ public class ConfigurationPanel extends JPanel { gbl_configButtonPanel.rowWeights = new double[]{0.0, Double.MIN_VALUE}; configButtonPanel.setLayout(gbl_configButtonPanel); - final IcyButton addGroupBtn = new IcyButton(new IcyIcon("sq_plus")); + final IcyButton addGroupBtn = new IcyButton(SVGIcon.ADD); addGroupBtn.addActionListener(e -> { final GroupEditor ge = new GroupEditor("", "", getMMStudio(), getCore(), true); if (ge.getWidth() < 580) @@ -132,10 +131,10 @@ public class ConfigurationPanel extends JPanel { gbc_addGroupBtn.gridx = 1; gbc_addGroupBtn.gridy = 0; configButtonPanel.add(addGroupBtn, gbc_addGroupBtn); - final IcyButton editGroupBtn = new IcyButton(new IcyIcon("doc_edit")); + final IcyButton editGroupBtn = new IcyButton(SVGIcon.EDIT); editGroupBtn.addActionListener(e -> { final String groupName = MMUtils.getSelectedGroupName(groupPad); - final String groupName2 = groupPad.getSelectedGroup(); + //final String groupName2 = groupPad.getSelectedGroup(); if (StringUtil.isEmpty(groupName)) MessageDialog.showDialog("To edit a group, please select it first then press the edit group button."); @@ -151,7 +150,7 @@ public class ConfigurationPanel extends JPanel { }); } }); - final IcyButton removeGroupBtn = new IcyButton(new IcyIcon("sq_minus")); + final IcyButton removeGroupBtn = new IcyButton(SVGIcon.REMOVE); removeGroupBtn.addActionListener(e -> { final String groupName = MMUtils.getSelectedGroupName(groupPad); @@ -192,7 +191,7 @@ public class ConfigurationPanel extends JPanel { gbc_presetLabel.gridy = 0; configButtonPanel.add(presetLabel, gbc_presetLabel); - final IcyButton addPresetBtn = new IcyButton(new IcyIcon("sq_plus")); + final IcyButton addPresetBtn = new IcyButton(SVGIcon.ADD); addPresetBtn.addActionListener(e -> { final String groupName = MMUtils.getSelectedGroupName(groupPad); @@ -215,7 +214,7 @@ public class ConfigurationPanel extends JPanel { gbc_addPresetBtn.gridx = 7; gbc_addPresetBtn.gridy = 0; configButtonPanel.add(addPresetBtn, gbc_addPresetBtn); - final IcyButton editPresetBtn = new IcyButton(new IcyIcon("doc_edit")); + final IcyButton editPresetBtn = new IcyButton(SVGIcon.EDIT); editPresetBtn.addActionListener(e -> { final String groupName = MMUtils.getSelectedGroupName(groupPad); final String presetName = MMUtils.getSelectedPresetName(groupPad); @@ -232,7 +231,7 @@ public class ConfigurationPanel extends JPanel { }); } }); - final IcyButton removePresetBtn = new IcyButton(new IcyIcon("sq_minus")); + final IcyButton removePresetBtn = new IcyButton(SVGIcon.REMOVE); removePresetBtn.addActionListener(e -> { final String groupName = MMUtils.getSelectedGroupName(groupPad); final String presetName = MMUtils.getSelectedPresetName(groupPad); @@ -282,7 +281,7 @@ public class ConfigurationPanel extends JPanel { gbc_editPresetBtn.gridy = 0; configButtonPanel.add(editPresetBtn, gbc_editPresetBtn); - final IcyButton saveBtn = new IcyButton(new IcyIcon(ResourceUtil.ICON_SAVE)); + final IcyButton saveBtn = new IcyButton(SVGIcon.SAVE); saveBtn.setToolTipText("Save current presets to configuration file..."); saveBtn.addActionListener(e -> mainFrame.saveConfig()); final GridBagConstraints gbc_saveBtn = new GridBagConstraints(); diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LiveSettingsPanel.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LiveSettingsPanel.java index 1ece6a7..4372153 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LiveSettingsPanel.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LiveSettingsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,8 +18,8 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.gui.component.NumberTextField; -import icy.util.StringUtil; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.gui.component.field.NumberTextField; import javax.swing.*; import javax.swing.border.TitledBorder; diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LoadFrame.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LoadFrame.java index b6d9e3a..ca334be 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LoadFrame.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LoadFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,16 +18,15 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.action.IcyAbstractAction; -import icy.file.FileUtil; -import icy.gui.component.button.IcyButton; -import icy.gui.dialog.OpenDialog; -import icy.main.Icy; -import icy.preferences.PluginsPreferences; -import icy.preferences.XMLPreferences; -import icy.resource.ResourceUtil; -import icy.resource.icon.IcyIcon; -import icy.system.IcyExceptionHandler; +import org.bioimageanalysis.icy.Icy; +import org.bioimageanalysis.icy.gui.action.IcyAbstractAction; +import org.bioimageanalysis.icy.gui.component.button.IcyButton; +import org.bioimageanalysis.icy.gui.component.icon.SVGIcon; +import org.bioimageanalysis.icy.gui.dialog.OpenDialog; +import org.bioimageanalysis.icy.io.FileUtil; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.bioimageanalysis.icy.system.preferences.PluginsPreferences; +import org.bioimageanalysis.icy.system.preferences.XMLPreferences; import plugins.tprovoost.Microscopy.MicroManager.tools.MMUtils; import plugins.tprovoost.Microscopy.MicroManagerForIcy.MicromanagerPlugin; @@ -132,7 +131,7 @@ public class LoadFrame extends JDialog { openButton.setEnabled(true); } catch (final IOException e1) { - IcyExceptionHandler.showErrorMessage(e1, true); + IcyLogger.error(this.getClass(), e1); } } else @@ -232,15 +231,11 @@ public class LoadFrame extends JDialog { lbl_devices.setFont(lbl_files.getFont().deriveFont(Font.BOLD, 12)); lbl_config_presets.setFont(lbl_files.getFont().deriveFont(Font.BOLD, 12)); - openButton = new IcyButton(openAction); - openButton.setIcon(new IcyIcon(ResourceUtil.ICON_OPEN)); + openButton = new IcyButton(openAction, SVGIcon.FOLDER_OPEN); openButton.setEnabled(false); - final IcyButton cancelButton = new IcyButton(cancelAction); - cancelButton.setIcon(new IcyIcon(ResourceUtil.ICON_DELETE)); - final IcyButton addButton = new IcyButton(addAction); - addButton.setIcon(new IcyIcon(ResourceUtil.ICON_PLUS)); - final IcyButton removeButton = new IcyButton(removeAction); - removeButton.setIcon(new IcyIcon(ResourceUtil.ICON_MINUS)); + final IcyButton cancelButton = new IcyButton(cancelAction, SVGIcon.DELETE); + final IcyButton addButton = new IcyButton(addAction, SVGIcon.ADD); + final IcyButton removeButton = new IcyButton(removeAction, SVGIcon.REMOVE); final JPanel buttonPanel = new JPanel(); getContentPane().add(buttonPanel, BorderLayout.SOUTH); diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LoadingFrame.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LoadingFrame.java index 800aa72..7603247 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LoadingFrame.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/LoadingFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,8 +18,8 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.gui.frame.IcyFrame; -import icy.system.thread.ThreadUtil; +import org.bioimageanalysis.icy.gui.frame.IcyFrame; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; import javax.swing.*; import java.awt.*; @@ -27,7 +27,7 @@ import java.awt.*; /** * Simple static Loading Frame for Micro-Manager initialization. * - * @author Stephane + * @author Stephane Dallongeville */ public class LoadingFrame extends IcyFrame { JProgressBar progressBar; diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/MMMainFrame.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/MMMainFrame.java index 4e8f9d0..9bea7ce 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/MMMainFrame.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/MMMainFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,30 +18,28 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.common.MenuCallback; -import icy.file.FileUtil; -import icy.gui.dialog.ActionDialog; -import icy.gui.dialog.ConfirmDialog; -import icy.gui.dialog.MessageDialog; -import icy.gui.dialog.SaveDialog; -import icy.gui.frame.IcyFrame; -import icy.gui.frame.IcyFrameAdapter; -import icy.gui.frame.IcyFrameEvent; -import icy.gui.frame.progress.FailedAnnounceFrame; -import icy.gui.frame.progress.ToolTipFrame; -import icy.gui.util.ComponentUtil; -import icy.main.Icy; -import icy.preferences.PluginPreferences; -import icy.preferences.XMLPreferences; -import icy.resource.ResourceUtil; -import icy.resource.icon.IcyIcon; -import icy.system.IcyExceptionHandler; -import icy.system.thread.ThreadUtil; -import icy.util.ReflectionUtil; -import icy.util.StringUtil; import mmcorej.CMMCore; import mmcorej.MMCoreJ; import mmcorej.MMEventCallback; +import org.bioimageanalysis.icy.Icy; +import org.bioimageanalysis.icy.common.reflect.ReflectionUtil; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.gui.component.ComponentUtil; +import org.bioimageanalysis.icy.gui.component.icon.SVGIcon; +import org.bioimageanalysis.icy.gui.component.menu.IcyMenuItem; +import org.bioimageanalysis.icy.gui.dialog.ActionDialog; +import org.bioimageanalysis.icy.gui.dialog.ConfirmDialog; +import org.bioimageanalysis.icy.gui.dialog.MessageDialog; +import org.bioimageanalysis.icy.gui.dialog.SaveDialog; +import org.bioimageanalysis.icy.gui.frame.IcyFrame; +import org.bioimageanalysis.icy.gui.frame.IcyFrameAdapter; +import org.bioimageanalysis.icy.gui.frame.IcyFrameEvent; +import org.bioimageanalysis.icy.gui.frame.progress.ToolTipFrame; +import org.bioimageanalysis.icy.io.FileUtil; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.bioimageanalysis.icy.system.preferences.PluginPreferences; +import org.bioimageanalysis.icy.system.preferences.XMLPreferences; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; import org.micromanager.MMOptions; import org.micromanager.MMStudio; import org.micromanager.MainFrame; @@ -50,7 +48,6 @@ import org.micromanager.conf2.ConfiguratorDlg2; import org.micromanager.conf2.MMConfigFileException; import org.micromanager.conf2.MicroscopeModel; import org.micromanager.dialogs.CalibrationListDlg; -import org.micromanager.utils.ReportingUtils; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; import plugins.tprovoost.Microscopy.MicroManager.core.AcquisitionHandler; import plugins.tprovoost.Microscopy.MicroManager.event.CoreListener; @@ -170,7 +167,7 @@ public class MMMainFrame extends IcyFrame { options.closeOnExit_ = false; } catch (final Exception ex) { - System.err.println("Warning: cannot patch options informations from Micro-Manager."); + IcyLogger.warn(MMMainFrame.this.getClass(), ex, "Cannot patch options information from Micro-Manager"); } try { @@ -181,7 +178,7 @@ public class MMMainFrame extends IcyFrame { contrastPrefs = (Preferences) ReflectionUtil.getFieldObject(mmstudio, "contrastPrefs_"); } catch (final Exception ex) { - System.err.println("Warning: cannot retrieve Preferences from Micro-Manager."); + IcyLogger.warn(MMMainFrame.this.getClass(), ex, "Cannot retrieve Preferences from Micro-Manager"); } final MainFrame frame = MMStudio.getFrame(); @@ -363,8 +360,7 @@ public class MMMainFrame extends IcyFrame { final JMenuBar menuBar = new JMenuBar(); menuBar.add(toReturn); setJMenuBar(menuBar); - final JMenuItem hconfig = new JMenuItem("Configuration Wizard"); - hconfig.setIcon(new IcyIcon("star.png")); + final IcyMenuItem hconfig = new IcyMenuItem("Configuration Wizard", SVGIcon.STAR); hconfig.addActionListener(e -> { // we have some plugins running ? if (pluginsPanel.getRunningPluginsCount() > 0) { @@ -394,8 +390,7 @@ public class MMMainFrame extends IcyFrame { refreshGUI(); }); - final JMenuItem menuPxSizeConfigItem = new JMenuItem("Pixel Size Config"); - menuPxSizeConfigItem.setIcon(new IcyIcon(ResourceUtil.ICON_PROPERTIES)); + final IcyMenuItem menuPxSizeConfigItem = new IcyMenuItem("Pixel Size Config", SVGIcon.SETTINGS); menuPxSizeConfigItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)); menuPxSizeConfigItem.addActionListener(e -> { final CalibrationListDlg dlg = new CalibrationListDlg(mmstudio.getCore()); @@ -407,9 +402,8 @@ public class MMMainFrame extends IcyFrame { pixelSizeConfig.setResizable(true); }); - final JMenuItem loadConfigItem = new JMenuItem("Load Configuration"); + final IcyMenuItem loadConfigItem = new IcyMenuItem("Load Configuration", SVGIcon.FOLDER_OPEN); loadConfigItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)); - loadConfigItem.setIcon(new IcyIcon(ResourceUtil.ICON_OPEN)); loadConfigItem.addActionListener(e -> { final LoadFrame f = new LoadFrame(); @@ -431,13 +425,11 @@ public class MMMainFrame extends IcyFrame { } }); - final JMenuItem saveConfigItem = new JMenuItem("Save Configuration"); + final IcyMenuItem saveConfigItem = new IcyMenuItem("Save Configuration", SVGIcon.SAVE); saveConfigItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)); - saveConfigItem.setIcon(new IcyIcon(ResourceUtil.ICON_SAVE)); saveConfigItem.addActionListener(e -> saveConfig()); - final JMenuItem aboutItem = new JMenuItem("About"); - aboutItem.setIcon(new IcyIcon(ResourceUtil.ICON_INFO)); + final IcyMenuItem aboutItem = new IcyMenuItem("About", SVGIcon.INFO); aboutItem.addActionListener(e -> { final JDialog dialog = new JDialog(Icy.getMainInterface().getMainFrame(), "About"); @@ -449,9 +441,8 @@ public class MMMainFrame extends IcyFrame { dialog.setVisible(true); }); - final JMenuItem propertyBrowserItem = new JMenuItem("Property Browser"); + final IcyMenuItem propertyBrowserItem = new IcyMenuItem("Property Browser", SVGIcon.DATABASE); propertyBrowserItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_COMMA, InputEvent.CTRL_DOWN_MASK)); - propertyBrowserItem.setIcon(new IcyIcon(ResourceUtil.ICON_DATABASE)); propertyBrowserItem.addActionListener(e -> { final PropertyEditor editor = new PropertyEditor(); editor.setGui(mmstudio); @@ -463,13 +454,11 @@ public class MMMainFrame extends IcyFrame { propertyBrowser.setResizable(true); }); - final JMenuItem resetMMPath = new JMenuItem("Reset Micro-Manager path"); - resetMMPath.setIcon(new IcyIcon("folder")); + final IcyMenuItem resetMMPath = new IcyMenuItem("Reset Micro-Manager path", SVGIcon.FOLDER); resetMMPath.addActionListener(e -> { // so user can change the defined MM folder MMUtils.resetLibrayPath(); - MessageDialog.showDialog("Information", "You need to restart Icy now to change the defined Micro-Manager folder.", - MessageDialog.INFORMATION_MESSAGE); + MessageDialog.showDialog("Information", "You need to restart Icy now to change the defined Micro-Manager folder.", MessageDialog.INFORMATION_MESSAGE); }); // JMenuItem loadPresetConfigItem = new JMenuItem("Load Core properties from XML"); @@ -494,8 +483,7 @@ public class MMMainFrame extends IcyFrame { // } // }); // - final JMenuItem mmSettingItem = new JMenuItem("Micro-Manager options"); - mmSettingItem.setIcon(new IcyIcon(ResourceUtil.ICON_COG, true)); + final IcyMenuItem mmSettingItem = new IcyMenuItem("Micro-Manager options", SVGIcon.SETTINGS); mmSettingItem.setToolTipText("Set a variety of Micro-Manager configuration options"); mmSettingItem.addActionListener(e -> { if (options == null) @@ -522,8 +510,7 @@ public class MMMainFrame extends IcyFrame { // } // }); - final JMenuItem mmScriptPanel = new JMenuItem("Script panel"); - mmScriptPanel.setIcon(new IcyIcon(ResourceUtil.getAlphaIconAsImage("text_curstor"), true)); + final IcyMenuItem mmScriptPanel = new IcyMenuItem("Script panel", SVGIcon.EDIT); mmScriptPanel.setToolTipText("Open Micro-Manager script panel"); mmScriptPanel.addActionListener(e -> mmstudio.showScriptPanel()); @@ -621,9 +608,8 @@ public class MMMainFrame extends IcyFrame { model.saveToFile(path); } catch (final MMConfigFileException e) { - ReportingUtils.logError(e); - IcyExceptionHandler.showErrorMessage(e, false); - new FailedAnnounceFrame("Unable to save configuration file"); + IcyLogger.error(this.getClass(), e, "Error while saving Micro-Manager configuration."); + //ReportingUtils.logError(e); } } diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/MainPanel.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/MainPanel.java index a353018..1b33279 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/MainPanel.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/MainPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/OptionsPanel.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/OptionsPanel.java index cf25b00..7f09f49 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/OptionsPanel.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/OptionsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,8 +18,8 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.gui.dialog.ConfirmDialog; import mmcorej.CMMCore; +import org.bioimageanalysis.icy.gui.dialog.ConfirmDialog; import org.micromanager.MMOptions; import org.micromanager.logging.LogFileManager; import org.micromanager.utils.NumberUtils; diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/PluginsToolbar.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/PluginsToolbar.java index 079fed1..7c6beac 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/PluginsToolbar.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/gui/PluginsToolbar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,10 +18,12 @@ package plugins.tprovoost.Microscopy.MicroManager.gui; -import icy.plugin.PluginDescriptor; -import icy.plugin.PluginLauncher; -import icy.plugin.PluginLoader; -import plugins.tprovoost.Microscopy.MicroManager.tools.FrameUtils; +import org.bioimageanalysis.icy.extension.plugin.PluginDescriptor; +import org.bioimageanalysis.icy.extension.plugin.PluginLauncher; +import org.bioimageanalysis.icy.extension.plugin.PluginLoader; +import org.bioimageanalysis.icy.gui.component.button.IcyButton; +import org.bioimageanalysis.icy.gui.component.icon.SVGIcon; +import org.jetbrains.annotations.NotNull; import plugins.tprovoost.Microscopy.MicroManagerForIcy.MicroscopePlugin; import javax.swing.*; @@ -53,14 +55,23 @@ public class PluginsToolbar extends JPanel { initialize(PluginLoader.getPlugins(MicroscopePlugin.class)); } - private void initialize(final List<PluginDescriptor> plugins) { + private void initialize(final @NotNull List<PluginDescriptor> plugins) { pluginToolbar = new JToolBar(SwingConstants.HORIZONTAL); pluginToolbar.setRollover(true); pluginToolbar.setFloatable(false); pluginToolbar.setToolTipText("Micro Manager plugins for Icy"); for (final PluginDescriptor plugin : plugins) { - pluginToolbar.add(FrameUtils.createPluginButton(plugin, e -> { + final JButton pluginButton; + final SVGIcon pluginSVGIcon = plugin.getSVGIcon(); + if (pluginSVGIcon != null) + pluginButton = new IcyButton(pluginSVGIcon); + else + pluginButton = new JButton(plugin.getIcon()); + + pluginButton.setToolTipText(plugin.getName()); + + pluginButton.addActionListener(e -> { // create the microscope plugin final MicroscopePlugin microscopePlugin = (MicroscopePlugin) PluginLauncher.start(plugin); @@ -69,19 +80,10 @@ public class PluginsToolbar extends JPanel { addPlugin(microscopePlugin); microscopePlugin.start(); } - })); + }); + pluginToolbar.add(pluginButton); } - // if (plugins.size() == 0) - // { - // MessageDialog.showDialog("Information", - // "You don't have any Micro manager plugins installed, use the search bar to install some", - // MessageDialog.INFORMATION_MESSAGE); - // - // // search for micro manager plugin - // // Icy.getMainInterface().getSearchEngine().search("micro-manager"); - // } - setLayout(new BorderLayout()); setBorder(new TitledBorder("Plugins")); add(pluginToolbar, BorderLayout.CENTER); @@ -139,7 +141,7 @@ public class PluginsToolbar extends JPanel { } /** - * Shutdown all running plugins (should automatically call removePlugin(..)) + * Shutdown all running plugins (should automatically call removePlugin(...)) */ public void shutdownPlugins() { for (final MicroscopePlugin plugin : getRunningPlugins()) diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/ClassPatcher.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/ClassPatcher.java index c6d55b5..9ccf1fa 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/ClassPatcher.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/ClassPatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,23 +18,16 @@ package plugins.tprovoost.Microscopy.MicroManager.patch; -import java.security.ProtectionDomain; -import java.util.ArrayList; - -import icy.system.IcyExceptionHandler; -import icy.system.SystemUtil; -import icy.util.StringUtil; -import javassist.CannotCompileException; -import javassist.ClassClassPath; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtField; -import javassist.CtMethod; -import javassist.CtNewMethod; -import javassist.LoaderClassPath; -import javassist.NotFoundException; +import javassist.*; import javassist.bytecode.AccessFlag; import javassist.bytecode.FieldInfo; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.system.SystemUtil; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.jetbrains.annotations.NotNull; + +import java.security.ProtectionDomain; +import java.util.ArrayList; /** * The code hacker provides a mechanism for altering the behavior of classes @@ -239,8 +232,7 @@ public class ClassPatcher { return pool.toClass(classRef); } catch (final CannotCompileException e) { - IcyExceptionHandler.showErrorMessage(e, false); - System.err.println("Cannot load class: " + fullClass); + IcyLogger.error(this.getClass(), e, "Cannot load class: " + fullClass); return null; } } @@ -265,8 +257,7 @@ public class ClassPatcher { return pool.toClass(classRef, neighbor, classLoader, protectionDomain); } catch (final CannotCompileException e) { - IcyExceptionHandler.showErrorMessage(e, false); - System.err.println("Cannot load class: " + fullClass); + IcyLogger.error(this.getClass(), e, "Cannot load class: " + fullClass); return null; } } @@ -323,7 +314,7 @@ public class ClassPatcher { * Generates a new line of code calling the <code>imagej.legacy.patches</code> class and method * corresponding to the given method signature. */ - private String newCode(final String fullClass, final String methodSig) { + private @NotNull String newCode(final @NotNull String fullClass, final String methodSig) { final int dotIndex = fullClass.lastIndexOf("."); final String className = fullClass.substring(dotIndex + 1); @@ -360,13 +351,13 @@ public class ClassPatcher { /** * Extracts the method name from the given method signature. */ - private String getMethodName(final String methodSig) { + private @NotNull String getMethodName(final @NotNull String methodSig) { final int parenIndex = methodSig.indexOf("("); final int spaceIndex = methodSig.lastIndexOf(" ", parenIndex); return methodSig.substring(spaceIndex + 1, parenIndex); } - private String[] getMethodArgs(final String methodSig, final boolean wantResult) { + private String @NotNull [] getMethodArgs(final @NotNull String methodSig, final boolean wantResult) { final ArrayList<String> result = new ArrayList<>(); final int parenIndex = methodSig.indexOf("("); @@ -381,14 +372,14 @@ public class ClassPatcher { return result.toArray(new String[0]); } - private String[] getMethodArgTypes(final String methodSig, final boolean wantResult) { + private String @NotNull [] getMethodArgTypes(final String methodSig, final boolean wantResult) { final String[] args = getMethodArgs(methodSig, wantResult); for (int i = 0; i < args.length; i++) args[i] = args[i].split(" ")[0]; return args; } - private String[] getMethodArgNames(final String methodSig, final boolean wantResult) { + private String @NotNull [] getMethodArgNames(final String methodSig, final boolean wantResult) { final String[] args = getMethodArgs(methodSig, wantResult); for (int i = 0; i < args.length; i++) args[i] = args[i].split(" ")[1]; @@ -398,7 +389,7 @@ public class ClassPatcher { /** * Returns true if the given method signature is static. */ - private boolean isStatic(final String methodSig) { + private boolean isStatic(final @NotNull String methodSig) { final int parenIndex = methodSig.indexOf("("); final String methodPrefix = methodSig.substring(0, parenIndex); for (final String token : methodPrefix.split(" ")) { @@ -411,7 +402,7 @@ public class ClassPatcher { /** * Returns true if the given method signature returns void. */ - private boolean isVoid(final String methodSig) { + private boolean isVoid(final @NotNull String methodSig) { final int parenIndex = methodSig.indexOf("("); final String methodPrefix = methodSig.substring(0, parenIndex); return methodPrefix.startsWith("void ") || methodPrefix.indexOf(" void ") > 0; diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/MMPatcher.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/MMPatcher.java index 38cf863..73d993b 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/MMPatcher.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/MMPatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ package plugins.tprovoost.Microscopy.MicroManager.patch; -import icy.plugin.PluginLoader; +import org.bioimageanalysis.icy.extension.plugin.PluginLoader; import org.micromanager.MMVersion; /** diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/MMStudioMethods.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/MMStudioMethods.java index 2771b26..203b847 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/MMStudioMethods.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/patch/MMStudioMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -21,9 +21,8 @@ package plugins.tprovoost.Microscopy.MicroManager.patch; +import org.bioimageanalysis.icy.system.logging.IcyLogger; import org.micromanager.MMStudio; - -import icy.system.IcyExceptionHandler; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; /** @@ -56,7 +55,7 @@ public class MMStudioMethods { MicroManager.stopLiveMode(); } catch (final Throwable t) { - IcyExceptionHandler.showErrorMessage(t, true); + IcyLogger.error(MMStudioMethods.class, t); } } } \ No newline at end of file diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/FrameUtils.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/FrameUtils.java index d0e519a..f014470 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/FrameUtils.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/FrameUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,15 +18,13 @@ package plugins.tprovoost.Microscopy.MicroManager.tools; -import icy.gui.component.button.IcyButton; -import icy.gui.frame.IcyFrame; -import icy.gui.util.GuiUtil; -import icy.plugin.PluginDescriptor; -import icy.resource.icon.IcyIcon; +import org.bioimageanalysis.icy.gui.GuiUtil; +import org.bioimageanalysis.icy.gui.frame.IcyFrame; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionListener; /** * Utilities class used for wrapping Micro-Manager Frames and Dialogs in a IcyFrame. @@ -42,7 +40,7 @@ public class FrameUtils { * @param window the window to add to the main pane * @return the window converted as an {@link IcyFrame} */ - public static IcyFrame addMMWindowToDesktopPane(final Window window) { + public static @NotNull IcyFrame addMMWindowToDesktopPane(final Window window) { final IcyFrame frame = GuiUtil.createIcyFrameFromWindow(window); frame.addToDesktopPane(); frame.setVisible(true); @@ -56,11 +54,9 @@ public class FrameUtils { * @param label button label * @return the button searched or <code>null</code> if was not found */ - public static JButton findButtonComponents(final Container container, final String label) { + public static @Nullable JButton findButtonComponents(final @NotNull Container container, final String label) { for (final Component c : container.getComponents()) { - if (c instanceof JButton) { - final JButton button = (JButton) c; - + if (c instanceof final JButton button) { if (button.getText().equalsIgnoreCase(label)) return button; } @@ -68,40 +64,4 @@ public class FrameUtils { return null; } - - /** - * Create an {@link IcyButton} from given information - * - * @param buttonText button text - * @param iconPath the icon path. Can be null if no icon wanted - * @param action the action to execute when button is clicked - * @return an IcyButton with buttonText and an icon on it if iconPath not null.<br> - * The button returned have an actionListener wich execute the runnable. - */ - public static IcyButton createUIButton(final String buttonText, final String iconPath, final Runnable action) { - final IcyButton theButton; - if (iconPath != null && !iconPath.isEmpty()) - theButton = new IcyButton(buttonText, new IcyIcon(iconPath, IcyIcon.DEFAULT_SIZE)); - else - theButton = new IcyButton(buttonText); - theButton.addActionListener(e -> action.run()); - return theButton; - } - - /** - * Create a button to launch the specified plugin - * - * @param plugin plugin descriptor - * @param action the action to execute when we click on the button - * @return an IcyButton with text and icon describing the specified plugin. - */ - public static IcyButton createPluginButton(final PluginDescriptor plugin, final ActionListener action) { - final IcyButton result = new IcyButton(new IcyIcon(plugin.getIconAsImage(), 32, false)); - - result.setToolTipText(plugin.getName()); - if (action != null) - result.addActionListener(action); - - return result; - } } diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/MMUtils.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/MMUtils.java index ca4af07..34ba4f2 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/MMUtils.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/MMUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,37 +18,38 @@ package plugins.tprovoost.Microscopy.MicroManager.tools; -import icy.file.FileUtil; -import icy.gui.dialog.MessageDialog; -import icy.gui.frame.progress.FailedAnnounceFrame; -import icy.gui.frame.progress.ProgressFrame; -import icy.image.IcyBufferedImage; -import icy.image.colormap.IcyColorMap; -import icy.main.Icy; -import icy.network.NetworkUtil; -import icy.plugin.PluginLoader; -import icy.plugin.PluginLoader.PluginClassLoader; -import icy.preferences.PluginsPreferences; -import icy.preferences.XMLPreferences; -import icy.sequence.MetaDataUtil; -import icy.sequence.Sequence; -import icy.system.IcyExceptionHandler; -import icy.system.SystemUtil; -import icy.system.thread.ThreadUtil; -import icy.type.DataType; -import icy.type.collection.CollectionUtil; -import icy.type.collection.array.Array2DUtil; -import icy.type.collection.array.ArrayUtil; -import icy.type.point.Point3D; -import icy.util.DateUtil; -import icy.util.OMEUtil; -import icy.util.ReflectionUtil; -import icy.util.StringUtil; import mmcorej.TaggedImage; import ome.xml.meta.OMEXMLMetadata; import ome.xml.model.Pixels; import ome.xml.model.primitives.NonNegativeInteger; import ome.xml.model.primitives.Timestamp; +import org.bioimageanalysis.icy.Icy; +import org.bioimageanalysis.icy.common.collection.CollectionUtil; +import org.bioimageanalysis.icy.common.collection.array.Array2DUtil; +import org.bioimageanalysis.icy.common.collection.array.ArrayUtil; +import org.bioimageanalysis.icy.common.datetime.DateUtil; +import org.bioimageanalysis.icy.common.geom.point.Point3D; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.common.type.DataType; +import org.bioimageanalysis.icy.extension.plugin.PluginLoader; +import org.bioimageanalysis.icy.gui.dialog.MessageDialog; +import org.bioimageanalysis.icy.gui.frame.progress.FailedAnnounceFrame; +import org.bioimageanalysis.icy.gui.frame.progress.ProgressFrame; +import org.bioimageanalysis.icy.io.FileUtil; +import org.bioimageanalysis.icy.model.OMEUtil; +import org.bioimageanalysis.icy.model.colormap.IcyColorMap; +import org.bioimageanalysis.icy.model.image.IcyBufferedImage; +import org.bioimageanalysis.icy.model.sequence.MetaDataUtil; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.bioimageanalysis.icy.network.NetworkUtil; +import org.bioimageanalysis.icy.system.SystemUtil; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.bioimageanalysis.icy.system.preferences.PluginsPreferences; +import org.bioimageanalysis.icy.system.preferences.XMLPreferences; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.joda.time.DateTime; import org.json.JSONArray; import org.json.JSONException; @@ -195,7 +196,8 @@ public class MMUtils { * @param images the list of {@link TaggedImage} to test * @return <code>true</code> if the specified list of TaggedImage contains a <code>null</code> or poison image. */ - public static boolean hasNullOrPoison(final List<TaggedImage> images) { + @Contract(pure = true) + public static boolean hasNullOrPoison(final @NotNull List<TaggedImage> images) { for (final TaggedImage image : images) if ((image == null) || TaggedImageQueue.isPoison(image)) return true; @@ -218,7 +220,7 @@ public class MMUtils { * @return the resulting {@link IcyBufferedImage} image * @throws JSONException if an error occurred while reading the metadata */ - public static IcyBufferedImage convertToIcyImage(final List<TaggedImage> images) throws JSONException { + public static @Nullable IcyBufferedImage convertToIcyImage(final @NotNull List<TaggedImage> images) throws JSONException { final List<TaggedImage> goodImages = new ArrayList<>(images.size()); int w, h, bpp; @@ -246,7 +248,7 @@ public class MMUtils { if ((!goodImages.isEmpty()) && (w > 0) && (h > 0) && (bpp > 0)) { // create the data array - final Object[] data = Array2DUtil.createArray(ArrayUtil.getDataType(goodImages.get(0).pix), + final Object[] data = Array2DUtil.createArray(ArrayUtil.getDataType(goodImages.getFirst().pix), goodImages.size()); for (int i = 0; i < goodImages.size(); i++) @@ -278,7 +280,7 @@ public class MMUtils { * @throws JSONException if an error occurred while reading the metadata * @throws MMScriptException if an error occurred on MM script parsing */ - public static void setMetadata(final Sequence sequence, final JSONObject tags) throws JSONException, MMScriptException { + public static void setMetadata(final @NotNull Sequence sequence, final JSONObject tags) throws JSONException, MMScriptException { final OMEXMLMetadata metadata = sequence.getOMEXMLMetadata(); final int numComp = Math.max(1, MDUtils.getNumberOfComponents(tags)); @@ -420,8 +422,7 @@ public class MMUtils { * @param sizeC wanted global size C (number of channel), set to <code>-1</code> to keep current value * @throws JSONException if an error occurred while reading the metadata */ - public static void setImageMetadata(final TaggedImage taggedImage, final int t, final int z, final int c, final int sizeT, final int sizeZ, final int sizeC) - throws JSONException { + public static void setImageMetadata(final TaggedImage taggedImage, final int t, final int z, final int c, final int sizeT, final int sizeZ, final int sizeC) throws JSONException { if (taggedImage == null) return; @@ -489,8 +490,8 @@ public class MMUtils { * @throws MMScriptException if an error occurred on MM script parsing * @see #setImageMetadata(TaggedImage, int, int, int, int, int, int) */ - public static boolean setImage(final Sequence sequence, final TaggedImage taggedImage, final long startDate) - throws JSONException, MMScriptException { + @Contract("_, null, _ -> false") + public static boolean setImage(final Sequence sequence, final TaggedImage taggedImage, final long startDate) throws JSONException, MMScriptException { // incorrect image --> do nothing if ((taggedImage == null) || TaggedImageQueue.isPoison(taggedImage)) return false; @@ -576,7 +577,7 @@ public class MMUtils { exposure = MicroManager.getExposure() / 1000d; } catch (final Throwable e) { - IcyExceptionHandler.showErrorMessage(e, false); + IcyLogger.error(MMUtils.class, e); } metadata.setPlanePositionX(OMEUtil.getLength(pos.getX()), 0, planeIndex); @@ -599,6 +600,7 @@ public class MMUtils { * @throws JSONException if an error occurred while reading the metadata * @throws MMScriptException if an error occurred on MM script parsing */ + @Contract("_, null -> false") public static boolean setImage(final Sequence sequence, final TaggedImage taggedImage) throws JSONException, MMScriptException { return setImage(sequence, taggedImage, 0L); } @@ -611,7 +613,7 @@ public class MMUtils { * @throws JSONException if an error occurred while reading the metadata * @throws MMScriptException if an error occurred on MM script parsing */ - public static boolean isCompatible(final Sequence sequence, final JSONObject metadata) throws JSONException, MMScriptException { + public static boolean isCompatible(final @NotNull Sequence sequence, final JSONObject metadata) throws JSONException, MMScriptException { if (sequence.isEmpty()) return true; @@ -619,7 +621,7 @@ public class MMUtils { && (sequence.getSizeY() == MDUtils.getHeight(metadata)) && (sequence.getSizeC() == (MDUtils.getNumChannels(metadata) * Math.max(1, MDUtils.getNumberOfComponents(metadata)))) - && (sequence.getDataType_().getSize() == ((MDUtils.getBitDepth(metadata) + 7) / 8)); + && (sequence.getDataType().getSize() == ((MDUtils.getBitDepth(metadata) + 7) / 8)); } /** @@ -629,35 +631,27 @@ public class MMUtils { * @throws JSONException if an error occurred while reading the metadata * @throws MMScriptException if an error occurred on MM script parsing */ - public static IcyBufferedImage createEmptyImage(final JSONObject metadata) throws JSONException, MMScriptException { + @Contract("_ -> new") + public static @NotNull IcyBufferedImage createEmptyImage(final JSONObject metadata) throws JSONException, MMScriptException { final int width = MDUtils.getWidth(metadata); final int height = MDUtils.getHeight(metadata); final int numChannels = MDUtils.getNumChannels(metadata) * Math.max(1, MDUtils.getNumberOfComponents(metadata)); final int bpp = MDUtils.getBitDepth(metadata); final int bytespp = (bpp + 7) / 8; - switch (bytespp) { - default: - case 1: - return new IcyBufferedImage(width, height, numChannels, DataType.UBYTE); - case 2: - return new IcyBufferedImage(width, height, numChannels, DataType.USHORT); - case 3: - case 4: - return new IcyBufferedImage(width, height, numChannels, DataType.UINT); - case 5: - case 6: - case 7: - case 8: - return new IcyBufferedImage(width, height, numChannels, DataType.DOUBLE); - } + return switch (bytespp) { + default -> new IcyBufferedImage(width, height, numChannels, DataType.UBYTE); + case 2 -> new IcyBufferedImage(width, height, numChannels, DataType.USHORT); + case 3, 4 -> new IcyBufferedImage(width, height, numChannels, DataType.UINT); + case 5, 6, 7, 8 -> new IcyBufferedImage(width, height, numChannels, DataType.DOUBLE); + }; } /** * @param group the {@link ConfigGroupPad} name * @return the selected group name from specified ConfigGroupPad */ - public static String getSelectedGroupName(final ConfigGroupPad group) { + public static String getSelectedGroupName(final @NotNull ConfigGroupPad group) { /*try { return (String) ReflectionUtil.invokeMethod(group, "getGroup", true, new Object[]{}); } @@ -677,7 +671,7 @@ public class MMUtils { * @param group the {@link ConfigGroupPad} name * @return the selected preset name from specified ConfigGroupPad */ - public static String getSelectedPresetName(final ConfigGroupPad group) { + public static String getSelectedPresetName(final @NotNull ConfigGroupPad group) { /*try { return (String) ReflectionUtil.invokeMethod(group, "getPreset", true, new Object[]{}); } @@ -734,7 +728,7 @@ public class MMUtils { return false; final ClassLoader cl = PluginLoader.getLoader(); - if (cl instanceof PluginClassLoader) { + if (cl instanceof PluginLoader.PluginClassLoader) { for (final File f : files) { final String path = f.getAbsolutePath(); final String ext = FileUtil.getFileExtension(path, false).toLowerCase(); @@ -757,7 +751,7 @@ public class MMUtils { continue; // we can add it - ((PluginClassLoader) cl).add(path); + ((PluginLoader.PluginClassLoader) cl).add(path); } } } diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/StageMover.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/StageMover.java index b6c45ee..17dacf0 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/StageMover.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManager/tools/StageMover.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,13 +18,15 @@ package plugins.tprovoost.Microscopy.MicroManager.tools; -import icy.preferences.XMLPreferences; -import icy.roi.ROI2D; -import icy.sequence.Sequence; -import icy.system.thread.ThreadUtil; -import icy.type.point.Point3D; -import icy.util.StringUtil; import mmcorej.CMMCore; +import org.bioimageanalysis.icy.common.geom.point.Point3D; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.model.roi.ROI2D; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.bioimageanalysis.icy.system.preferences.XMLPreferences; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; import java.awt.geom.Point2D; @@ -143,6 +145,7 @@ public class StageMover { /** * @return state of X inverted axis. */ + @Contract(pure = true) public static boolean isInvertX() { return invertX; } @@ -150,6 +153,7 @@ public class StageMover { /** * @return state of Y inverted axis. */ + @Contract(pure = true) public static boolean isInvertY() { return invertY; } @@ -157,6 +161,7 @@ public class StageMover { /** * @return state of Y inverted axis. */ + @Contract(pure = true) public static boolean isInvertZ() { return invertZ; } @@ -174,6 +179,7 @@ public class StageMover { /** * @return state of X and Y axis inversion. */ + @Contract(pure = true) public static boolean isSwitchXY() { return switchXY; } @@ -181,7 +187,7 @@ public class StageMover { /** * Fire Z stage position change event * - * @param s stage devicce name + * @param s stage device name * @param z Z position */ public static void onStagePositionChanged(final String s, final double z) { @@ -322,7 +328,7 @@ public class StageMover { * @return the X, Y and Z coordinates of the current stage/focus device(s). * @throws Exception if an error occurs */ - public static Point3D.Double getXYZ() throws Exception { + public static Point3D.@NotNull Double getXYZ() throws Exception { final Point2D.Double pt2d = getXY(); return new Point3D.Double(pt2d.x, pt2d.y, getZ()); } @@ -333,7 +339,7 @@ public class StageMover { * @return the X, Y and Z coordinates of the current stage/focus device(s) in double[3] format * @throws Exception if an error occurs */ - public static double[] getXYZAsDoubleArray() throws Exception { + public static double @NotNull [] getXYZAsDoubleArray() throws Exception { final Point3D.Double pt = getXYZ(); return new double[]{pt.x, pt.y, pt.z}; } @@ -642,7 +648,7 @@ public class StageMover { * @param y y value of the point we want to go to. * @throws Exception if an error occurs */ - public static void moveToPoint(final Sequence s, final double x, final double y) throws Exception { + public static void moveToPoint(final @NotNull Sequence s, final double x, final double y) throws Exception { final double pxsize; final double vectx = x - s.getBounds2D().getCenterX(); // Y coordinates are inverted in the sequence diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManagerForIcy/MicromanagerPlugin.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManagerForIcy/MicromanagerPlugin.java index 737b860..0d954c9 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManagerForIcy/MicromanagerPlugin.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManagerForIcy/MicromanagerPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,11 +18,15 @@ package plugins.tprovoost.Microscopy.MicroManagerForIcy; -import icy.plugin.abstract_.PluginActionable; -import icy.plugin.interface_.PluginThreaded; +import org.bioimageanalysis.icy.extension.plugin.abstract_.PluginActionable; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName; +import org.bioimageanalysis.icy.extension.plugin.interface_.PluginThreaded; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; import plugins.tprovoost.Microscopy.MicroManager.tools.MMUtils; +@IcyPluginName("Micro-Manager") +@IcyPluginIcon(path = "/mmj.png") public final class MicromanagerPlugin extends PluginActionable implements PluginThreaded { /** * Initialize Micro-Manager sub system. diff --git a/src/main/java/plugins/tprovoost/Microscopy/MicroManagerForIcy/MicroscopePlugin.java b/src/main/java/plugins/tprovoost/Microscopy/MicroManagerForIcy/MicroscopePlugin.java index 2f7603e..291e932 100644 --- a/src/main/java/plugins/tprovoost/Microscopy/MicroManagerForIcy/MicroscopePlugin.java +++ b/src/main/java/plugins/tprovoost/Microscopy/MicroManagerForIcy/MicroscopePlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ package plugins.tprovoost.Microscopy.MicroManagerForIcy; -import icy.plugin.abstract_.Plugin; +import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin; import plugins.tprovoost.Microscopy.MicroManager.MicroManager; /** diff --git a/src/main/resources/mmj.png b/src/main/resources/mmj.png new file mode 100644 index 0000000000000000000000000000000000000000..9a64c58c2537a9f82c3e99f8f8ec2bc82c754549 GIT binary patch literal 15076 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%0AJx@DqfSTYh-4u2LG2_0jg@ItywRw9XlN+o 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 RAH2N^QFx&$TP|(t|33p96F>j} literal 0 HcmV?d00001 -- GitLab