Access ImageJ 1.x classes directly from the legacy service

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Code Hacker: require a class loader in which to define the classes

This opens the door to have multiple LegacyServices, each with their
own class loader, in which the ImageJ 1.x classes and the classes
using them are defined.

This is necessary because ij.IJ is basically a singleton but still has
to be connected to the appropriate ImageJ context and LegacyService. By
having a separate class loader for each LegacyService, ij.IJ can be
a singleton *in that class loader*, and things will still work out.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Failed try: load the DefaultLegacyService into its own class loader

This would have been so cool: by having an own class loader for each
DefaultLegacyService instance, we would have let ImageJ 1.x continue to
pretend that it is a singleton, but it would not really have been (since
its class definition would have been local to the legacy service).

Alas, it is not to be. If we were to do that, nobody could instantiate an
ImagePlus *except* in classes loaded by those class loaders, which would
have been unintuitive and fragile. So a simple

	ImagePlus image = IJ.openImage(path);
	ImageDisplay display =
		legacyService.getImageMap().lookupDisplay(image);

would have thrown a non-intuitive ClassCastException, stating that
"ij.ImagePlus could not be cast to ij.ImagePlus" because the respective
classes' class definitions would be incompatible by virtue of being
defined in different class loaders.

So we have to undo this change, recording for history that we tried.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Revert "Failed try: load the DefaultLegacyService into its own class loader"

As described in the commit message of the reverted commit
49e497c0f8fe08b3f90a40e0a992ac783b131323.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Allow only one instance of the DefaultLegacyService

In a later commit, we might want to solve this issue a bit cleaner;
while we cannot hope to execute legacy commands and macros in multiple
legacy services within the same class loader, we may still synchronize
preferences to a certain degree.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
CodeHacker: avoid using the LogService

At the time CodeHacker is running, we cannot hope for a LogService
being initialized already.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
CodeHacker: pass LegacyService instance to patched functions

We really need the instance of the legacy service in those functions...

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Require the LegacyService to divulge its LogService

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Avoid the use of the deprecated Log class in the legacy layer

Since all the patched functions get a LegacyService, and since that
service can now be asked for its LogService, we do not need to use
that deprecated class any longer.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
LegacyService: yes, we refer to non-public methods in the javadocs

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Do not identify the legacy thread group by its name

That comparison would be fragile. Instead, subclass the
ThreadGroup. Now, even if the ImageJ 1.x plugin called by the legacy
layer decides to change the thread group's name, we are still able
to identify it for what it is.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Reduce visibility of some constants

There is no reason to access these constants, other than trying to
identify legacy threads or legacy thread groups. But that is done
better by comparing classes than Strings.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Let LegacyThreadGroup divulge its LegacyService

It is pretty darn convenient to be able to get the LegacyService
corresponding to a legacy thread group.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
LegacyImageMap: offer the list of handled images

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
LegacyImageMap: we need a reference to the current legacy service

To support the upcoming legacy ImageJ 1.x mode, we will need to
determine in the legacy image map whether to hold off displaying
images based on said mode, so we need to have a reference to the
service which knows whether that mode is active.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Add the method ApplicationFrame#setVisible(boolean)

LegacyService's toggleLegacyMode() will use this method.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
SwingImageWindow: avoid pack() when hiding the window

This is needed for the upcoming Help>Legacy Mode, which would otherwise
experience an 'IllegalStateException: Cannot sync viewport from thread'.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Introduce a legacy mode to the LegacyService

To fall back to original ImageJ1 (e.g. should some plugin or macro not
work in ImageJ2 as it did in ImageJ1), we'd like to be able to drive a
patched ImageJ1 in such a way that it behaves exactly like unpatched
ImageJ1 (except still synchronizing all the data with ImageJ2).

This change introduces a flag in the LegacyService, and changes the
Javassist patches so that the legacy mode is heeded.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
CodeHacker: remove unused replaceMethod() method

For the legacy mode, we should avoid replacing methods in every case,
so we will not need this method anymore, ever.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Add Help>Start Legacy ImageJ 1.x Mode

Since it is very hard (or might be impossible) to achieve full 100%
backwards-compatibility with ImageJ1, we want to have one last way out
for users whose plugin/macro might not work in ImageJ2, namely to show
the old ImageJ1 GUI and lose all the ImageJ2 goodness.

This is what Help>Start Legacy ImageJ 1.x Mode does.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>