Commit 63321f81 authored by Joachim Pouderoux's avatar Joachim Pouderoux

Introduce the new AWT and SWT java components.

These 2 classes are intended to replace the old vtkCanvas/vtkPanel
AWT classes at a long term.
The (optional, default is OFF, because it adds a dependency to
Eclipse SWT jar file) SWT component is a pure SWT components
to avoid the AWT-SWT bridge which may generate some difficult to
avoid crashes.
FindSWT provides a CMake procedure to search for the SWT jar file
which stands in the Eclipse plugins directory.

Remove the @Override annotations to avoid issues with OpenJDK.

Change-Id: I96a80b8fdd4c56e591026a17df59e13a6a17ad72
parent 0830ae93
#
# Try to find SWT jar library path.
# Once done this will define
#
# ECLIPSE_PLUGINS_DIR = directory where Eclipse plugins reside
# ECLIPSE_SWT_LIBRARIES = full path to the SWT jar libraries
#
FIND_PATH(ECLIPSE_PLUGINS_DIR plugins
HINTS
$ENV{ECLIPSE_HOME}
DOC "Eclipse plugins directory"
)
if(NOT EXISTS ${ECLIPSE_SWT_LIBRARIES})
file(GLOB SWT_FILES "${ECLIPSE_PLUGINS_DIR}/org.eclipse.swt.*" )
set(ECLIPSE_SWT_LIBRARIES "" CACHE FILEPATH "SWT library" FORCE)
foreach(f ${SWT_FILES})
if(NOT ${f} MATCHES "^.*source.*")
set(ECLIPSE_SWT_LIBRARIES ${f} CACHE FILEPATH "SWT library" FORCE)
endif()
endforeach()
endif()
......@@ -3,6 +3,13 @@ find_package(JNI REQUIRED)
include_directories(${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
# Add the option for build the SWT component to VTK.
option(VTK_JAVA_SWT_COMPONENT "Should SWT component for Java be built (it requires Eclipse)?" OFF)
if(VTK_JAVA_SWT_COMPONENT)
find_package(SWT REQUIRED)
endif()
set(WrappingJava_SRCS
vtkJavaUtil.cxx
)
......@@ -147,15 +154,35 @@ endif()
if(vtkRenderingCore_ENABLED AND vtkIOImage_ENABLED)
set(VTK_JAVA_DEPENDENCIES ${VTK_JAVA_DEPENDENCIES}
vtkPanel
rendering/vtkAbstractComponent
rendering/vtkComponent
rendering/vtkEventInterceptor
rendering/vtkInteractorForwarder
rendering/awt/vtkAwtComponent
rendering/awt/vtkInternalAwtComponent
)
if(VTK_JAVA_SWT_COMPONENT)
set(VTK_JAVA_DEPENDENCIES ${VTK_JAVA_DEPENDENCIES}
rendering/swt/vtkSwtComponent
rendering/swt/vtkInternalSwtComponent
rendering/swt/vtkSwtInteractorForwarderDecorator
)
endif()
set(VTK_JAVA_SAMPLE_DEPENDENCIES ${VTK_JAVA_SAMPLE_DEPENDENCIES}
InternalFrames
Demo
SimpleVTK
VTKCanvas
ReleaseVtkPanel
rendering/AwtConeRendering
rendering/annotation/LabeledCubeAxesActor
)
if(VTK_JAVA_SWT_COMPONENT)
set(VTK_JAVA_SAMPLE_DEPENDENCIES ${VTK_JAVA_SAMPLE_DEPENDENCIES}
rendering/SwtConeRendering
)
endif()
endif()
if(vtkFiltersModeling_ENABLED AND vtkIOImage_ENABLED)
......@@ -189,13 +216,23 @@ foreach(jfile ${VTK_JAVA_DEPENDENCIES})
endif()
endforeach()
if(WIN32)
set(SEPARATOR "\;")
else()
set(SEPARATOR ":")
endif()
if(VTK_JAVA_SWT_COMPONENT)
set(SWT_FILES "${VTK_BINARY_DIR}/java/vtk/rendering/swt/*.java")
endif()
# Compile the Java classes
add_custom_command(
OUTPUT ${VTK_BINARY_DIR}/java/javac_stamp.txt
DEPENDS ${VTK_JAVA_SOURCE_FILES}
COMMAND ${JAVA_COMPILE} ${JAVAC_OPTIONS}
-source 1.5 -classpath ${VTK_JAVA_HOME}/.. -sourcepath ${VTK_SOURCE_DIR}/Wrapping/Java/ -d ${VTK_BINARY_DIR}/java
${VTK_BINARY_DIR}/java/vtk/*.java
-source 1.5 -classpath ${VTK_JAVA_HOME}/..${SEPARATOR}${ECLIPSE_SWT_LIBRARIES} -sourcepath ${VTK_SOURCE_DIR}/Wrapping/Java/ -d ${VTK_BINARY_DIR}/java
${VTK_BINARY_DIR}/java/vtk/*.java ${VTK_BINARY_DIR}/java/vtk/rendering/*.java ${VTK_BINARY_DIR}/java/vtk/rendering/awt/*.java ${SWT_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${VTK_BINARY_DIR}/java/javac_stamp.txt
COMMENT "Compiling Java Classes"
)
......@@ -211,12 +248,6 @@ add_custom_command(
)
if(BUILD_TESTING)
if(WIN32)
set(SEPARATOR "\;")
else()
set(SEPARATOR ":")
endif()
foreach(jfile
Regression
ConcurrencyGC
......
package vtk.rendering.awt;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import vtk.vtkObject;
import vtk.vtkRenderWindow;
import vtk.rendering.vtkAbstractComponent;
/**
* Provide AWT based vtk rendering component
*
* @authors Sebastien Jourdain - sebastien.jourdain@kitware.com
* Joachim Pouderoux - joachim.pouderoux@kitware.com
*/
public class vtkAwtComponent extends vtkAbstractComponent<Canvas> {
protected vtkInternalAwtComponent uiComponent;
protected boolean isWindowCreated;
public vtkAwtComponent() {
this(new vtkRenderWindow());
}
public vtkAwtComponent(vtkRenderWindow renderWindowToUse) {
super(renderWindowToUse);
this.isWindowCreated = false;
this.uiComponent = new vtkInternalAwtComponent(this);
this.uiComponent.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent arg0) {
Dimension size = vtkAwtComponent.this.uiComponent.getSize();
vtkAwtComponent.this.setSize(size.width, size.height);
}
});
}
public void Render() {
// Make sure we can render
if (inRenderCall || renderer == null || renderWindow == null) {
return;
}
// Try to render
try {
lock.lockInterruptibly();
inRenderCall = true;
// Initialize the window only once
if (!isWindowCreated) {
uiComponent.RenderCreate(renderWindow);
setSize(uiComponent.getWidth(), uiComponent.getHeight());
isWindowCreated = true;
}
// Trigger the real render
renderWindow.Render();
} catch (InterruptedException e) {
// Nothing that we can do except skipping execution
} finally {
lock.unlock();
inRenderCall = false;
}
}
public Canvas getComponent() {
return this.uiComponent;
}
public void Delete() {
this.lock.lock();
// We prevent any further rendering
inRenderCall = true;
if (this.uiComponent.getParent() != null) {
this.uiComponent.getParent().remove(this.uiComponent);
}
super.Delete();
// On linux we prefer to have a memory leak instead of a crash
if (!this.renderWindow.GetClassName().equals("vtkXOpenGLRenderWindow")) {
this.renderWindow = null;
} else {
System.out.println("The renderwindow has been kept arount to prevent a crash");
}
this.lock.unlock();
vtkObject.JAVA_OBJECT_MANAGER.gc(false);
}
/**
* @return true if the graphical component has been properly set and
* operation can be performed on it.
*/
public boolean isWindowSet() {
return this.isWindowCreated;
}
/**
* Just allow class in same package to affect inRenderCall boolean
*
* @param value
*/
protected void updateInRenderCall(boolean value) {
this.inRenderCall = value;
}
}
package vtk.rendering.awt;
import java.awt.Canvas;
import java.awt.Graphics;
import vtk.vtkRenderWindow;
public class vtkInternalAwtComponent extends Canvas {
protected native int RenderCreate(vtkRenderWindow renderWindow);
private static final long serialVersionUID = -7756069664577797620L;
private vtkAwtComponent parent;
public vtkInternalAwtComponent(vtkAwtComponent parent) {
this.parent = parent;
this.addMouseListener(this.parent.getInteractorForwarder());
this.addMouseMotionListener(this.parent.getInteractorForwarder());
this.addKeyListener(this.parent.getInteractorForwarder());
}
public void addNotify() {
super.addNotify();
parent.isWindowCreated = false;
parent.getRenderWindow().SetForceMakeCurrent();
parent.updateInRenderCall(false);
}
public void removeNotify() {
parent.updateInRenderCall(true);
super.removeNotify();
}
public void paint(Graphics g) {
parent.Render();
}
public void update(Graphics g) {
parent.Render();
}
}
package vtk.rendering.swt;
import org.eclipse.swt.SWT;
import org.eclipse.swt.opengl.GLCanvas;
import org.eclipse.swt.opengl.GLData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import vtk.vtkObject;
public class vtkInternalSwtComponent extends GLCanvas implements Listener {
private vtkSwtComponent parent;
public static GLData GetGLData() {
GLData gl = new GLData();
gl.doubleBuffer = true;
gl.depthSize = 1; // must be set to something on Linux
return gl;
}
public vtkInternalSwtComponent(vtkSwtComponent parent, Composite parentComposite) {
super(parentComposite, SWT.NO_BACKGROUND, GetGLData());
this.parent = parent;
vtkSwtInteractorForwarderDecorator forwarder =
(vtkSwtInteractorForwarderDecorator)this.parent.getInteractorForwarder();
this.addMouseListener(forwarder);
this.addKeyListener(forwarder);
this.addMouseMoveListener(forwarder);
this.addMouseTrackListener(forwarder);
this.addMouseWheelListener(forwarder);
this.addListener(SWT.Paint, this);
this.addListener(SWT.Close, this);
this.addListener(SWT.Dispose, this);
this.addListener(SWT.Resize, this);
this.IntializeRenderWindow();
}
protected void IntializeRenderWindow() {
setCurrent(); // need to be done so SetWindowIdFromCurrentContext can get the current context!
parent.getRenderWindow().InitializeFromCurrentContext();
}
public void update() {
super.update();
parent.Render();
}
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Paint:
parent.Render();
break;
case SWT.Dispose:
parent.Delete();
vtkObject.JAVA_OBJECT_MANAGER.gc(false);
break;
case SWT.Close:
//System.out.println("closing");
break;
case SWT.Resize:
parent.setSize(getClientArea().width, getClientArea().height);
break;
}
}
}
package vtk.rendering.swt;
import org.eclipse.swt.opengl.GLCanvas;
import org.eclipse.swt.widgets.Composite;
import vtk.vtkRenderWindow;
import vtk.rendering.vtkAbstractComponent;
/**
* Provide SWT based vtk rendering component
*
* @author Joachim Pouderoux - joachim.pouderoux@kitware.com
*/
public class vtkSwtComponent extends vtkAbstractComponent<GLCanvas> {
protected vtkInternalSwtComponent uiComponent;
protected boolean isWindowCreated;
public vtkSwtComponent(Composite parentComposite) {
this(new vtkRenderWindow(), parentComposite);
}
public vtkSwtComponent(vtkRenderWindow renderWindowToUse, Composite parentComposite) {
super(renderWindowToUse);
this.eventForwarder = new vtkSwtInteractorForwarderDecorator(this, this.eventForwarder);
this.isWindowCreated = true;
this.uiComponent = new vtkInternalSwtComponent(this, parentComposite);
}
/**
* Set the size of the VTK component
* @param x width
* @param y height
*/
public void setSize(int x, int y) {
x = x < 1 ? 1 : x;
y = y < 1 ? 1 : y;
super.setSize(x, y);
this.uiComponent.setSize(x, y);
this.uiComponent.redraw();
this.uiComponent.update();
}
/**
* Render the VTK component. Should not be called externally.
* Call update() to refresh the window content.
*/
public void Render() {
// Make sure we can render
if (inRenderCall || renderer == null || renderWindow == null) {
return;
}
// Try to render
try {
lock.lockInterruptibly();
inRenderCall = true;
// Trigger the real render
renderWindow.Render();
} catch (InterruptedException e) {
// Nothing that we can do except skipping execution
} finally {
lock.unlock();
inRenderCall = false;
}
}
/**
* Redraw the VTK component
*/
public void update() {
this.uiComponent.redraw();
this.uiComponent.update();
}
/**
* @return the encapsulated SWT component (a GLCanvas instance)
* @see vtk.rendering.vtkAbstractComponent#getComponent()
*/
public GLCanvas getComponent() {
return this.uiComponent;
}
public void Delete() {
this.lock.lock();
// We prevent any further rendering
this.inRenderCall = true;
this.renderWindow = null;
super.Delete();
this.lock.unlock();
}
/**
* @return true if the graphical component has been properly set and
* operation can be performed on it.
*/
public boolean isWindowSet() {
return this.isWindowCreated;
}
/**
* Just allow class in same package to affect inRenderCall boolean
*
* @param value
*/
protected void updateInRenderCall(boolean value) {
this.inRenderCall = value;
}
}
package vtk.rendering.swt;
import java.awt.Label;
import vtk.rendering.vtkComponent;
import vtk.rendering.vtkInteractorForwarder;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.MouseWheelListener;
/**
* Decorator class used to implement all Mouse/Key SWT listener and convert them
* into the vtkInteractorForwarder proper AWT event.
*
* @author Joachim Pouderoux - joachim.pouderoux@kitware.com
*/
public class vtkSwtInteractorForwarderDecorator extends vtkInteractorForwarder
implements MouseListener, MouseMoveListener, MouseTrackListener, MouseWheelListener, KeyListener {
vtkInteractorForwarder forwarder;
Label dummyComponent;
public vtkSwtInteractorForwarderDecorator(vtkComponent<?> component, vtkInteractorForwarder forwarder) {
super(component);
dummyComponent = new Label();
this.forwarder = forwarder;
}
public static int convertModifiers(int mods) {
int modifiers = 0;
if ((mods & SWT.SHIFT) != 0) modifiers |= java.awt.Event.SHIFT_MASK;
if ((mods & SWT.CTRL) != 0) modifiers |= java.awt.Event.CTRL_MASK;
if ((mods & SWT.ALT) != 0) modifiers |= java.awt.Event.ALT_MASK;
return modifiers;
}
public java.awt.event.KeyEvent convertKeyEvent(org.eclipse.swt.events.KeyEvent e) {
return new java.awt.event.KeyEvent(dummyComponent, 0, (long)e.time, convertModifiers(e.stateMask), e.keyCode, e.character);
}
public java.awt.event.MouseEvent convertMouseEvent(org.eclipse.swt.events.MouseEvent e) {
int button = 0;
if ((e.button == 1) || (e.stateMask & SWT.BUTTON1) != 0) button = java.awt.event.MouseEvent.BUTTON1;
else if ((e.button == 2) || (e.stateMask & SWT.BUTTON2) != 0) button = java.awt.event.MouseEvent.BUTTON2;
else if ((e.button == 3) || (e.stateMask & SWT.BUTTON3) != 0) button = java.awt.event.MouseEvent.BUTTON3;
return new java.awt.event.MouseEvent(dummyComponent, 0, (long)e.time, convertModifiers(e.stateMask), e.x, e.y, e.count, false, button);
}
public void keyPressed(KeyEvent e) {
super.keyPressed(convertKeyEvent(e));
}
public void keyReleased(KeyEvent e) {
super.keyReleased(convertKeyEvent(e));
}
public void mouseEnter(MouseEvent e) {
super.mouseEntered(convertMouseEvent(e));
}
public void mouseExit(MouseEvent e) {
super.mouseExited(convertMouseEvent(e));
}
public void mouseMove(MouseEvent e) {
if (((e.stateMask & SWT.BUTTON1) == 0)
&& ((e.stateMask & SWT.BUTTON2) == 0)
&& ((e.stateMask & SWT.BUTTON3) == 0)) {
super.mouseMoved(convertMouseEvent(e));
} else {
super.mouseDragged(convertMouseEvent(e));
}
}
public void mouseDown(MouseEvent e) {
super.mousePressed(convertMouseEvent(e));
}
public void mouseUp(MouseEvent e) {
super.mouseReleased(convertMouseEvent(e));
}
public void mouseScrolled(MouseEvent e) {
}
public void mouseHover(MouseEvent e) {
}
public void mouseDoubleClick(MouseEvent e) {
}
}
package vtk.rendering;
import java.util.concurrent.locks.ReentrantLock;
import vtk.vtkCamera;
import vtk.vtkGenericRenderWindowInteractor;
import vtk.vtkInteractorStyle;
import vtk.vtkInteractorStyleTrackballCamera;
import vtk.vtkRenderWindow;
import vtk.vtkRenderer;
/**
* Abstract class that bring most of the VTK logic to any rendering component
* regardless its origin. (awt, swt, sing, ...)
*
* @param <T>
* The concrete type of the graphical component that will contains
* the vtkRenderWindow.
*
* @authors Sebastien Jourdain - sebastien.jourdain@kitware.com
* Joachim Pouderoux - joachim.pouderoux@kitware.com
*/
public abstract class vtkAbstractComponent<T> implements vtkComponent<T> {
protected vtkRenderWindow renderWindow;
protected vtkRenderer renderer;
protected vtkCamera camera;
protected vtkGenericRenderWindowInteractor windowInteractor;
protected vtkInteractorForwarder eventForwarder;
protected ReentrantLock lock;
protected boolean inRenderCall;
public vtkAbstractComponent() {
this(new vtkRenderWindow());
}
public vtkAbstractComponent(vtkRenderWindow renderWindowToUse) {
this.inRenderCall = false;
this.renderWindow = renderWindowToUse;
this.renderer = new vtkRenderer();
this.windowInteractor = new vtkGenericRenderWindowInteractor();
this.lock = new ReentrantLock();
// Init interactor
this.windowInteractor.SetRenderWindow(this.renderWindow);
this.windowInteractor.TimerEventResetsTimerOff();
this.windowInteractor.SetSize(200, 200);
this.windowInteractor.ConfigureEvent();
// Update style
vtkInteractorStyleTrackballCamera style = new vtkInteractorStyleTrackballCamera();
this.windowInteractor.SetInteractorStyle(style);
// Setup event forwarder
this.eventForwarder = new vtkInteractorForwarder(this);
this.windowInteractor.AddObserver("CreateTimerEvent", this.eventForwarder, "StartTimer");
this.windowInteractor.AddObserver("DestroyTimerEvent", this.eventForwarder, "DestroyTimer");
// Link renderWindow with renderer
this.renderWindow.AddRenderer(this.renderer);
// Keep camera around to prevent its creation/deletion in Java world
this.camera = this.renderer.GetActiveCamera();
}
public ReentrantLock getVTKLock() {
return this.lock;
}
public void resetCamera() {
if (renderer == null) {
return; // Nothing to do we are deleted...
}
try {
lock.lockInterruptibly();
renderer.ResetCamera();
} catch (InterruptedException e) {
// Nothing that we can do
} finally {
this.lock.unlock();
}
}
public void resetCameraClippingRange() {
if (renderWindow == null) {
return; // Nothing to do we are deleted...
}
try {
this.lock.lockInterruptibly();
renderer.ResetCameraClippingRange();
} catch (InterruptedException e) {
// Nothing that we can do
} finally {
this.lock.unlock();
}
}
public vtkCamera getActiveCamera() {
return this.camera;
}
public vtkRenderer getRenderer() {
return this.renderer;
}
public vtkRenderWindow getRenderWindow() {
return this.renderWindow;
}
public vtkGenericRenderWindowInteractor getRenderWindowInteractor() {
return this.windowInteractor;
}
public void setInteractorStyle(vtkInteractorStyle style) {
if (this.windowInteractor != null) {
this.lock.lock();
this.windowInteractor.SetInteractorStyle(style);
this.lock.unlock();
}
}
public void setSize(int w, int h) {
if (renderWindow == null || windowInteractor == null) {
return; // Nothing to do we are deleted...
}
try {
lock.lockInterruptibly();
renderWindow.SetSize(w, h);
windowInteractor.SetSize(w, h);
} catch (InterruptedException e) {
// Nothing that we can do
} finally {
this.lock.unlock();
}
}
public void Delete() {
this.lock.lock();
this.renderer = null;
this.camera = null;
this.windowInteractor = null;
// removing the renderWindow is let to the superclass
// because in the very special case of an AWT component
// under Linux, destroying renderWindow crashes.
this.lock.unlock();
}
public vtkInteractorForwarder getInteractorForwarder() {
return this.eventForwarder;
}
public abstract T getComponent();
}
package vtk.rendering;
import java.util.concurrent.locks.ReentrantLock;
import vtk.vtkCamera