Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add plugin to create tag set for the highlighting of cell divisions #54

Merged
merged 1 commit into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ public List< ViewMenuBuilder.MenuItem > getMenuItems()
{
return Arrays.asList(
menu( "Plugins",
item( COPY_TAG ),
item( MIRROR_SPOTS ),
menu( "Tags",
item( COPY_TAG ) ),
menu( "Auxiliary Displays",
item( COMPACT_LINEAGE_VIEW ) ),
menu( "Trees Management",
Expand All @@ -266,10 +266,11 @@ public List< ViewMenuBuilder.MenuItem > getMenuItems()
menu( "Exports",
item( EXPORTS_LINEAGE_LENGTHS ),
item( EXPORTS_SPOTS_COUNTS ),
item( EXPORT_PHYLOXML ) ) ),
item( EXPORT_PHYLOXML ) ),
item( MIRROR_SPOTS ) ),
menu( "File",
item( TWEAK_DATASET_PATH ),
item( MERGE_PROJECTS )) );
item( MERGE_PROJECTS ) ) );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*-
* #%L
* mastodon-tomancak
* %%
* Copyright (C) 2018 - 2024 Tobias Pietzsch
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.mastodon.mamut.tomancak.divisiontagset;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.apache.commons.lang3.tuple.Pair;
import org.mastodon.mamut.ProjectModel;
import org.mastodon.mamut.model.Model;
import org.mastodon.mamut.model.Spot;
import org.mastodon.mamut.model.branch.BranchSpot;
import org.mastodon.mamut.model.branch.ModelBranchGraph;
import org.mastodon.model.tag.TagSetStructure;
import org.mastodon.util.ColorUtils;
import org.mastodon.util.TagSetUtils;
import org.scijava.Cancelable;
import org.scijava.command.Command;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.util.ColorRGB;

/**
* {@link Command A SciJava command} that is called by the {@link CellDivisionsTagSetPlugin}.
* <p>
* The command creates a tag set that highlights cell divisions. The user interface allows to
* specify the number of spots to highlight before and after a division, and the highlight and
* background colors.
*/
@Plugin( type = Command.class, label = "Add a Tag Set to Highlight Cell Divisions", visible = false )
public class CellDivisionsTagSetCommand implements Command, Cancelable
{
@Parameter
private ProjectModel projectModel;

@Parameter( label = "Tag set name" )
private String tagSetName = "cell divisions";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the users view, it is possible to have different tag set names for different settings. However, users may easily forget to do this.

If they do, they end up with this situation:

grafik

You could consider adding the timepoints setting to the tagset name automatically so that it is easier for the user afterwards to differentiate between different tagset.

E.g.: "highlight cell division (+/- 3 timepoints)"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I understand your point. But I would like to wait for user feedback. Having a predictable tag set name is also an advantage. There would also be the question if to include the colors in the tag set name and how, etc. Maybe overwriting existing tag sets is the best thing to do?


@Parameter( label = "Default color" )
private ColorRGB defaultColor = new ColorRGB( "dark gray" );

@Parameter( label = "Highlight color" )
private ColorRGB highlightColor = new ColorRGB( "pink" );

@Parameter( label = "Timepoints to highlight before and after cell division" )
private int n = 3;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this maybe could have got a little longer name... down in the code I realized I had to search what 'n' is... but the code is short, so easy :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I simply have no idea how to name the variable properly.


private List< TagSetStructure.Tag > tagsBefore;

private List< TagSetStructure.Tag > tagsAfter;

private TagSetStructure.Tag backgroundTag;

private Model model;

@Override
public void run()
{
projectModel.getBranchGraphSync().sync();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I run the the plugin on this dataset: https://github.com/mastodon-sc/mastodon-example-data/tree/master/tgmm-mini with these settings:
grafik
I get this exception:


Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index 8 out of bounds for length 0
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
	at java.base/java.util.Objects.checkIndex(Objects.java:372)
	at java.base/java.util.ArrayList.get(ArrayList.java:458)
	at org.mastodon.views.table.FeatureTagTablePanel$MyTableModel.getValueAt(FeatureTagTablePanel.java:635)
	at java.desktop/javax.swing.JTable.getValueAt(JTable.java:2706)
	at java.desktop/javax.swing.JTable.prepareRenderer(JTable.java:5721)
	at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2185)
	at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2087)
	at java.desktop/javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1883)
	at com.formdev.flatlaf.ui.FlatTableUI.paint(FlatTableUI.java:405)
	at java.desktop/javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
	at java.desktop/javax.swing.JComponent.paintComponent(JComponent.java:797)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074)
	at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5255)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1643)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1618)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1556)
	at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323)
	at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203)
	at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823)
	at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772)
	at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1890)
	at java.desktop/java.awt.event.InvocationEvent.dispatch$$$capture(InvocationEvent.java:313)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
[ERROR] Malfunctioning plugin: org.scijava.ui.swing.widget.SwingObjectWidget
java.lang.NullPointerException
	at org.scijava.widget.WidgetModel.getChoices(WidgetModel.java:140)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:101)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:54)
	at org.scijava.plugin.TypedService.find(TypedService.java:70)
	at org.scijava.plugin.WrapperService.create(WrapperService.java:64)
	at org.scijava.widget.AbstractInputHarvester.addInput(AbstractInputHarvester.java:110)
	at org.scijava.widget.AbstractInputHarvester.buildPanel(AbstractInputHarvester.java:84)
	at org.scijava.widget.InputHarvester.harvest(InputHarvester.java:67)
	at org.scijava.ui.AbstractInputHarvesterPlugin.process(AbstractInputHarvesterPlugin.java:74)
	at org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:103)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:154)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
	at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
[ERROR] Malfunctioning plugin: org.scijava.ui.swing.widget.SwingObjectWidget
java.lang.NullPointerException
	at org.scijava.widget.WidgetModel.getChoices(WidgetModel.java:140)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:101)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:54)
	at org.scijava.plugin.TypedService.find(TypedService.java:70)
	at org.scijava.plugin.WrapperService.create(WrapperService.java:64)
	at org.scijava.widget.AbstractInputHarvester.addInput(AbstractInputHarvester.java:110)
	at org.scijava.widget.AbstractInputHarvester.buildPanel(AbstractInputHarvester.java:84)
	at org.scijava.widget.InputHarvester.harvest(InputHarvester.java:67)
	at org.scijava.ui.AbstractInputHarvesterPlugin.process(AbstractInputHarvesterPlugin.java:74)
	at org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:103)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:154)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
	at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

I am not sure, if this related to this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's related to this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exception does not appear if I execute the code inside a full Fiji installation. I guess this exception is specific to some version of some scijava artifact.

model = projectModel.getModel();
createTagSet();
applyTags();
}

private void createTagSet()
{
int defaultColor = this.defaultColor.getARGB();
maarzt marked this conversation as resolved.
Show resolved Hide resolved
int highlightColor = this.highlightColor.getARGB();
List< Pair< String, Integer > > tagColors = new ArrayList<>( Collections.nCopies( 2 * n + 1, null ) );
tagColors.set( 0, Pair.of( "default", defaultColor ) );
for ( int i = 0; i < n; i++ )
{
int color = ColorUtils.mixColors( highlightColor, defaultColor, ( float ) i / n );
String label = "T-" + ( i + 1 );
tagColors.set( n - i, Pair.of( label, color ) );
}
for ( int i = 0; i < n; i++ )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is maybe unnecessarily the same - symmetrical, but it makes no sense to optimize it either

unless you maybe want to offer a transition from mother-default, over division, to daughters-new-default colors
(I could imagine color encoding a generation number.. but that's for some different story)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the colors are very similar. But having different tags for before and after the cell division allows the user to manually assign a different color before the cell division. If they would want to.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a good and very valid point... (to have explicit Tags for the colors before and after the division so that the user can later change them...)

{
int color = ColorUtils.mixColors( highlightColor, defaultColor, ( float ) i / n );
String label = "T" + ( i + 1 );
tagColors.set( n + i + 1, Pair.of( label, color ) );
}
TagSetStructure.TagSet tagset = TagSetUtils.addNewTagSetToModel( model, tagSetName, tagColors );
List< TagSetStructure.Tag > allTags = tagset.getTags();
backgroundTag = allTags.get( 0 );
tagsBefore = IntStream.range( 0, n ).mapToObj( i -> allTags.get( n - i ) ).collect( Collectors.toList() );
tagsAfter = IntStream.range( 0, n ).mapToObj( i -> allTags.get( n + i + 1 ) ).collect( Collectors.toList() );
}

private void applyTags()
{
ModelBranchGraph branchGraph = model.getBranchGraph();
for ( BranchSpot branch : branchGraph.vertices() )
{
int start = branch.getFirstTimePoint();
int end = branch.getTimepoint();
boolean dividesBefore = !branch.incomingEdges().isEmpty();
boolean dividesAfter = !branch.outgoingEdges().isEmpty();
Iterator< Spot > iterator = branchGraph.vertexBranchIterator( branch );
while ( iterator.hasNext() )
{
Spot spot = iterator.next();
int time = spot.getTimepoint();
int startOffset = time - start;
int endOffset = end - time;
TagSetStructure.Tag tag = getTag( dividesBefore, dividesAfter, startOffset, endOffset );
model.getTagSetModel().getVertexTags().set( spot, tag );
}
branchGraph.releaseIterator( iterator );
}
}

private TagSetStructure.Tag getTag( boolean dividesBefore,
boolean dividesAfter, int startOffset, int endOffset )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be on the same line as the line above.

{
if ( dividesAfter && ( endOffset < tagsBefore.size() ) )
return tagsBefore.get( endOffset );
if ( dividesBefore && ( startOffset < tagsAfter.size() ) )
return tagsAfter.get( startOffset );
return backgroundTag;
}

@Override
public boolean isCanceled()
{
return false;
}

@Override
public void cancel( String reason )
{

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could consider adding a comment, why this method is intentionally empty.

Cf.: https://rules.sonarsource.com/java/RSPEC-1186/

}

@Override
public String getCancelReason()
{
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*-
* #%L
* mastodon-tomancak
* %%
* Copyright (C) 2018 - 2024 Tobias Pietzsch
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.mastodon.mamut.tomancak.divisiontagset;

import static org.mastodon.app.ui.ViewMenuBuilder.item;
import static org.mastodon.app.ui.ViewMenuBuilder.menu;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.mastodon.app.ui.ViewMenuBuilder;
import org.mastodon.mamut.KeyConfigScopes;
import org.mastodon.mamut.ProjectModel;
import org.mastodon.mamut.plugin.MamutPlugin;
import org.mastodon.ui.keymap.KeyConfigContexts;
import org.scijava.command.CommandService;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.ui.behaviour.io.gui.CommandDescriptionProvider;
import org.scijava.ui.behaviour.io.gui.CommandDescriptions;
import org.scijava.ui.behaviour.util.AbstractNamedAction;
import org.scijava.ui.behaviour.util.Actions;
import org.scijava.ui.behaviour.util.RunnableAction;

/**
* A Mastodon plugin that adds a tag set for highlighting cell divisions.
* <p>
* This class executes the {@link CellDivisionsTagSetCommand} when the
* menu item is clicked.
*/
@Plugin( type = MamutPlugin.class )
public class CellDivisionsTagSetPlugin implements MamutPlugin
{
@Parameter
private CommandService commandService;

private static final String ID = "[tomancak] create cell divisions tag set";

private static final String[] KEYS = { "not mapped" };

private static final Map< String, String > menuTexts = Collections.singletonMap( ID, "Add Tag Set to Highlight Cell Divisions ..." );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend to omit the "..." at the end. This would be more consistent with other function that can be called from the menu, which also do not have the "..."


private ProjectModel projectModel = null;

@Plugin( type = CommandDescriptionProvider.class )
public static class Descriptions extends CommandDescriptionProvider
{
public Descriptions()
{
super( KeyConfigScopes.MAMUT, KeyConfigContexts.TRACKSCHEME, KeyConfigContexts.BIGDATAVIEWER );
}

@Override
public void getCommandDescriptions( CommandDescriptions descriptions )
{
descriptions.add( ID, KEYS, "Adds a tag set to highlight cell divisions." );
}
}

private final AbstractNamedAction action;

public CellDivisionsTagSetPlugin()
{
action = new RunnableAction( ID, () -> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is nice, I like the defensive style of it, makes the SW more robust..
(always learning from ya ;-) )

if ( projectModel != null )
run();
} );
updateEnabledActions();
}

@Override
public void setAppPluginModel( ProjectModel projectModel )
{
this.projectModel = projectModel;
updateEnabledActions();
}

private void updateEnabledActions()
{
action.setEnabled( projectModel != null );
}

@Override
public List< ViewMenuBuilder.MenuItem > getMenuItems()
{
return Collections.singletonList( menu( "Plugins", menu( "Tags", item( ID ) ) ) );
}

@Override
public Map< String, String > getMenuTexts()
{
return menuTexts;
}

@Override
public void installGlobalActions( Actions actions )
{
actions.namedAction( action, KEYS );
}

private void run()
{
commandService.run( CellDivisionsTagSetCommand.class, true, "projectModel", projectModel );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this is called, on my machine, I get this exception:

[ERROR] Malfunctioning plugin: org.scijava.ui.swing.widget.SwingObjectWidget
java.lang.NullPointerException
	at org.scijava.widget.WidgetModel.getChoices(WidgetModel.java:140)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:101)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:54)
	at org.scijava.plugin.TypedService.find(TypedService.java:70)
	at org.scijava.plugin.WrapperService.create(WrapperService.java:64)
	at org.scijava.widget.AbstractInputHarvester.addInput(AbstractInputHarvester.java:110)
	at org.scijava.widget.AbstractInputHarvester.buildPanel(AbstractInputHarvester.java:84)
	at org.scijava.widget.InputHarvester.harvest(InputHarvester.java:67)
	at org.scijava.ui.AbstractInputHarvesterPlugin.process(AbstractInputHarvesterPlugin.java:74)
	at org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:103)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:154)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
	at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

However, the expected dialog still opens:
grafik

}
}
Loading