I'm trying to use OpenGL directly from Java using JNA on Mac OSX (I have done it successfully with Windows and Linux). I've browsed thru JOGL source but they use CALayers which I don't understand yet. I would like to just simply use NSOpenGLView if possible and place it over top the AWT Canvas. I find the NSWindow using JNA and add the NSOpenGLView I created and it seems to work except when I call [nsOpenGLContext setView] or [nsOpenGLView lockFocus] I get an 'invalid drawable' error. I learned from Rococoa how to use ObjectiveC from Java.
Here is some sample code:
private static boolean createMac(GL gl, Component c) {
NSAutoreleasePool pool = new NSAutoreleasePool();
pool.alloc();
pool.init();
gl.nsopenglview = new NSOpenGLView();
gl.nsopenglview.alloc();
Pointer ptr = Native.getWindowPointer(findWindow(c));
NSObject nsComponent = new NSObject();
nsComponent.obj = ptr;
Pointer cClass = nsComponent._class();
NSView view = new NSView();
view.alloc();
boolean isView = view.isKindOfClass(cClass);
// JFLog.log("test=" + isView);
if (isView) {
view.dealloc();
view.obj = ptr; //do NOT dealloc this (usually NSWindowViewAWT)
gl.nswindow = view.window();
} else {
view.dealloc();
gl.nswindow = new NSWindow();
gl.nswindow.obj = ptr;
}
NSOpenGLPixelFormat fmt = new NSOpenGLPixelFormat();
fmt.alloc();
fmt.initWithAttributes(new int[] {
NSOpenGLPFAWindow,
// NSOpenGLPFAAccelerated, //is not available on my test system
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorSize,24,
NSOpenGLPFADepthSize,16,
0 //zero terminate list
}
);
if (fmt.obj == null) {
JFLog.log("NSOpenGLPixelFormat initWithAttributes failed");
return false;
}
if (gl.nsopenglview != null) {
gl.nsopenglview.initWithFrame(new NSRect(c.getBounds()), fmt);
}
NSView content = gl.nswindow.contentView();
JFLog.log("content view=" + content.obj);
content.addSubview(gl.nsopenglview);
JFLog.log("layered=" + content.wantsLayer());
//use created context
gl.nsopenglcontext = gl.nsopenglview.openGLContext();
//create some resize/move listeners
final GL _gl = gl;
final Component _c = c;
c.addComponentListener(new ComponentListener() {
public void componentResized(ComponentEvent e) {
_gl.nsopenglview.setFrame(new NSRect(_c.getBounds()));
}
public void componentMoved(ComponentEvent e) {
_gl.nsopenglview.setFrame(new NSRect(_c.getBounds()));
}
public void componentShown(ComponentEvent e) {}
public void componentHidden(ComponentEvent e) {}
});
if (api == null) {
api = new GLFuncs();
gl.glLibrary = NativeLibrary.getInstance("OpenGL");
try {
Field fields[] = api.getClass().getFields();
for(int a=0;a<fields.length;a++) {
String name = fields[a].getName();
try {
fields[a].set(api, gl.glLibrary.getFunction(name));
} catch (Throwable t) {
JFLog.log("OpenGL:Warning:Function not found:" + name);
}
}
} catch (Exception e) {
JFLog.log(e);
}
}
pool.release();
return true;
}
I can't use the drawRect function in NSOpenGLView so I just lockFocus, use gl commands and unlockFocus when done. But the NSOpenGLContext doesn't have a view assigned and trying to assign the one I created generates the 'invalid drawable'.
Any ideas?
If you want a full working demo goto http://javaforce.sf.net and download v7.15.0, run ant in /jf and then in /projects/jtest3d and then execute run.sh (click the GLCanvas test).
I got it working! The problem was in Rococoa (or possibly a bug in JNA). Their NSRect structure does not pass to [NSOpenGLView initWithFrame] or [NSWindow initWithContentRect] properly. If I pass the 4 fields directly (x,y,width,height) to the function instead of the Structure itself then it works. Also I used [NSObject performSelectorOnMainThread] to make sure I do all GUI stuff on the main thread.
So it is possible to use OpenGL using pure JNA from Java. No native code needed.
This should be available in my javaforce.sf.net in v7.16 which I'll release in a while.
Thanks.
Related
I have in my RCP application a View that extends the CommonNavigator class. The projects in the workspace of my application should have different icons depending on their location on the disk: the projects that exist locally in the workspace should have a different icon from the projects that were imported.
I realised this by defining in the plugin.xml two project natures: MyProjectNature and MyProjectNatureImported with different icons and changing between the natures accordingly with the following method:
private void updateProjectNature(final IWorkspace lf_workspace)
{
String l_workspacePath = lf_workspace.getRoot().getLocation().toString();
IProject[] l_projectsInWorkspace = lf_workspace.getRoot().getProjects();
for (IProject l_project : l_projectsInWorkspace)
{
try
{
File l_projectFile = new File(l_workspacePath + l_project.getFullPath().toString());
final IProjectDescription l_projectDescription = l_project.getDescription();
final String[] l_currentNatures = l_projectDescription.getNatureIds();
final String[] l_newNatures = new String[l_currentNatures.length];
int l_index = 0;
if (l_projectFile.exists())
{
for (String l_nature : l_currentNatures)
{
if (l_nature.equals(MyProjectNatureImported.NATURE_ID))
{
l_newNatures[l_index] = MyProjectNature.NATURE_ID;
}
else
{
l_newNatures[l_index] = l_nature;
}
l_index++;
}
}
else
{
for (String l_nature : l_currentNatures)
{
if (l_nature.equals(MyProjectNature.NATURE_ID))
{
l_newNatures[l_index] = MyProjectNatureImported.NATURE_ID;
}
else
{
l_newNatures[l_index] = l_nature;
}
l_index++;
}
}
l_projectDescription.setNatureIds(l_newNatures);
l_project.setDescription(l_projectDescription, null);
}
catch (CoreException e)
{
LOGGER.warning("Error when setting the project nature of the project " + l_project.getName() + ": " + e.getMessage());
}
}
}
When I call this method from the ResourceChangeListener that I added to the workspace, I get an error for each project that it is locked and cannot be editted:
final IWorkspace lf_workspace = ResourcesPlugin.getWorkspace();
lf_workspace.addResourceChangeListener(new IResourceChangeListener()
{
#Override
public void resourceChanged(IResourceChangeEvent event)
{
updateProjectNature(lf_workspace);
}
});
But when I create a Job that runs each few seconds, then it works:
Job l_testJob = new Job("Update navigator")
{
#Override
protected IStatus run(IProgressMonitor monitor)
{
updateProjectNature(lf_workspace);
schedule(1000);
return Status.OK_STATUS;
}
#Override
public boolean shouldSchedule()
{
// Check if the job should be scheduled / executed or not
return !PlatformUI.getWorkbench().isClosing();
}
};
l_testJob.schedule(1000);
I would like to call the method only when changes are made to the workspace and not each second (to save the resources), but I don't understand why I get the error and cannot change the nature from the listener while from the job there is no problem.
Any ideas?
The workspace is locked while the resource change event is sent so that listeners can't make any more changes.
You should be able to submit a single Job from your listener with a scheduling rule to delay the job until the workspace is available. You should use a WorkspaceJob to make sure the update is atomic.
class UpdateNatureJob extends WorkspaceJob
{
UpdateNatureJob()
{
// Scheduling rule
setRule(ResourcesPlugin.getWorkspace().getRoot());
}
#Override
public IStatus runInWorkspace(final IProgressMonitor monitor)
{
... your nature update
return Status.OK_STATUS;
}
}
You are misusing project natures. While your actual problem can be worked around with an extra job, it is an indicator that project nature are likely the wrong means to achieve different images.
The designated way to emphasize those differences like local and imported projects are decorators. Decorators allow you to decorate or exchange image and text of an element (almost) irrespective where it is shown.
so, here is my today problem:
First of all, please note that I do NOT have the Matlab parallel toolbox available.
I am running java code witch interact with Matlab. Sometime Matlab directly call some java functions, sometimes it is the opposite. In this case, we use a notification system which comes from here:
http://undocumentedmatlab.com/blog/matlab-callbacks-for-java-events
We then address the notification in proper callbacks.
Here is a simple use case:
My user select a configuration file using the java interface, loaded into Matlab.
Using an interface listener, we notify Matlab that the configuration file has been selected, it then run a certain number of functions that will analyzes the file
Once the analysis is done, it is pushed into the java runtime, which will populate interface tables with the result. This step involve that matlab will call a java function.
Finally, java request the interface to be switched to an arbitrary decided tab.
This is the order of which things would happen in an ideal world, however, here is the code of the listener actionPerformed method:
#Override
public void actionPerformed(ActionEvent arg0) {
Model wModel = controller.getModel();
Window wWindow = controller.getWindow();
MatlabStructure wStructure = new MatlabStructure();
if(null != wModel) {
wModel.readMatlabData(wStructure);
wModel.notifyMatlab(wStructure, MatlabAction.UpdateCircuit);
}
if(null != wWindow) {
wWindow.getTabContainer().setSelectedComponent(wWindow.getInfosPannel());
}
}
What happen here, is that, when the notifyMatlab method is called, the code does not wait for it to be completed before it continues. So what happen is that the method complete and switch to an empty interface page (setSelectedComponent), and then the component is filled with values.
What I would like to, is for java to wait that my notifyMatlab returns a "I have completed !!" signal, and then pursue. Which involves asynchrounous code since Matlab will code java methods during its execution too ...
So far here is what I tried:
In the MatlabEventObject class, I added an isAcknowledge member, so now the class (which I originaly found in the above link), look like this (I removed all unchanged code from the original class):
public class MatlabEventObject extends java.util.EventObject {
private static final long serialVersionUID = 1L;
private boolean isAcknowledged = false;
public void onNotificationReceived() {
if (source instanceof MatlabEvent) {
System.out.println("Catched a MatlabEvent Pokemon !");
MatlabEvent wSource = (MatlabEvent) source;
wSource.onNotificationReceived();
}
}
public boolean isAcknowledged() {
return isAcknowledged;
}
public void acknowledge() {
isAcknowledged = true;
}
}
In the MatlabEvent class, I have added a future task which goal is to wait for acknowledgement, the methods now look like this:
public class MatlabEvent {
private Vector<IMatlabListener> data = new Vector<IMatlabListener>();
private Vector<MatlabEventObject> matlabEvents = new Vector<MatlabEventObject>();
public void notifyMatlab(final Object obj, final MatlabAction action) {
final Vector<IMatlabListener> dataCopy;
matlabEvents.clear();
synchronized (this) {
dataCopy = new Vector<IMatlabListener>(data);
}
for (int i = 0; i < dataCopy.size(); i++) {
matlabEvents.add(new MatlabEventObject(this, obj, action));
((IMatlabListener) dataCopy.elementAt(i)).testEvent(matlabEvents.get(i));
}
}
public void onNotificationReceived() {
ExecutorService service = Executors.newSingleThreadExecutor();
long timeout = 15;
System.out.println("Executing runnable.");
Runnable r = new Runnable() {
#Override
public void run() {
waitForAcknowledgement(matlabEvents);
}
};
try {
Future<?> task = service.submit(r);
task.get(timeout, TimeUnit.SECONDS);
System.out.println("Notification acknowledged.");
} catch (Exception e) {
e.printStackTrace();
}
}
private void waitForAcknowledgement(final Vector<MatlabEventObject> matlabEvents) {
boolean allEventsAcknowledged = false;
while(!allEventsAcknowledged) {
allEventsAcknowledged = true;
for(MatlabEventObject eventObject : matlabEvents) {
if(!eventObject.isAcknowledged()) {
allEventsAcknowledged = false;
}
break;
}
}
}
}
What happen is that I discover that Matlab actually WAIT for the java code to be completed. So my waitForAcknowledgement method always wait until it timeouts.
In addition, I must say that I have very little knowledge in parallel computing, but I think our java is single thread, so having java waiting for matlab code to complete while matlab is issuing calls to java functions may be an issue. But I can't be sure : ]
If you have any idea on how to solve this issue in a robust way, it will be much much appreciated.
I am customizing Jitsi to play a Wav file when a call is in progress.
I am facing trouble doing it, and would appreciate if you can help me out.
I can switch the data source before the call starts, by using a custom AudioFileMediaDevice and switching it on in CallPeerMediaHandler.
But I am having problems in replacing the datasource when the call is in progress.
=============================================================
I've tried the following but couldn't make it work.
1) I tried getting the device's output datasource and added a URLDatasource of the wav file using addInDataSource method. Didn't work.
DataSource dataSource = device.createOutputDataSource();
DataSource fileDataSource = Manager.createDataSource(new URL("file://resources/sounds/Sample.wav"));
((AudioMixingPushBufferDataSource)dataSource).addInDataSource(fileDataSource);
2) I tried adding a custom Capture device and switch it, but its not working too:
CaptureDeviceInfo2 fileDevice =
new CaptureDeviceInfo2("Recorded Audio 1",
fileDataSource.getLocator(), null, null, null, null);
((MediaServiceImpl) LibJitsi.getMediaService())
.getDeviceConfiguration().getAudioSystem().setDevice(AudioSystem.DataFlow.CAPTURE, fileDevice, false);
This is working for playback though, not as a capture device.
3) I even tried adding a new Audio system with the playback device as the file data source, but thats not working too.
=============================================================
I am new to libjitsi, so I'm having tough time trying to decode what is happening.
Any directions on how to resolve this would be great.
I made playback sound in call with this code:
public void startPlaying(CallPeer callPeer, DataSource soundDataSource) throws OperationFailedException {
assert callPeer instanceof CallPeerSipImpl;
CallPeerSipImpl cp = (CallPeerSipImpl) callPeer;
AudioMediaStreamImpl audioMediaStream = (AudioMediaStreamImpl) cp.getMediaHandler().getStream(MediaType.AUDIO);
AudioMediaDeviceSession deviceSession = audioMediaStream.getDeviceSession();
assert deviceSession != null;
assert deviceSession.getDevice() instanceof AudioMixerMediaDevice;
AudioMixerMediaDevice dev = (AudioMixerMediaDevice) deviceSession.getDevice();
dev.getAudioMixer().addInDataSource(soundDataSource);
}
Note that AudioMixerMediaDevice.getAudioMixer() has private access in libjitsi, so I made it public and recompiled.
I needed to play an audio file during a call, but only on the remote side of the call. So I played around a little bit with stokitos example and modified it for my needs. In case somebody ever needs it, here is what I did:
private void playAudioFromDataSource(final CallPeerSipImpl callPeer, final DataSource audioDataSource, final MediaDirection direction) {
final CallPeerMediaHandlerSipImpl mediaHandler = callPeer.getMediaHandler();
final AudioMediaStreamImpl audioMediaStream = (AudioMediaStreamImpl) mediaHandler.getStream(AUDIO);
final AudioMediaDeviceSession deviceSession = audioMediaStream.getDeviceSession();
if (null != deviceSession) {
if (RECVONLY == direction) {
// plays audio local only:
deviceSession.addPlaybackDataSource(audioDataSource);
} else {
final AudioMixerMediaDevice mediaDevice = (AudioMixerMediaDevice) deviceSession.getDevice();
final AudioMixer audioMixer = getAudioMixer(mediaDevice);
if (null != audioMixer) {
if (SENDONLY == direction) {
// plays audio remote only:
audioMixer.getLocalOutDataSource().addInDataSource(audioDataSource);
} else if (SENDRECV == direction) {
// plays audio on both sides of call (local and remote):
audioMixer.addInDataSource(audioDataSource);
}
}
}
}
}
private AudioMixer getAudioMixer(final AudioMixerMediaDevice device) {
try {
final Method privateGetAudioMixerMethod = device.getClass().getDeclaredMethod("getAudioMixer");
privateGetAudioMixerMethod.setAccessible(true);
final Object audioMixerObject = privateGetAudioMixerMethod.invoke(device, (Object[]) null);
return (AudioMixer) audioMixerObject;
} catch (final Exception e) {
log.error("Could not get AudioMixer", e);
}
return null;
}
NOTE: I sued reflection to get the private AudioMixer object. I admit it's not the cleanest approach, but it works. :)
I'm using the upload component of vaadin(7.1.9), now my trouble is that I'm not able to restrict what kind of files that can be sent with the upload component to the server, but I haven't found any API for that purpose. The only way is that of discarding file of wrong types after the upload.
public OutputStream receiveUpload(String filename, String mimeType) {
if(!checkIfAValidType(filename)){
upload.interruptUpload();
}
return out;
}
Is this a correct way?
No, its not the correct way. The fact is, Vaadin does provide many useful interfaces that you can use to monitor when the upload started, interrupted, finished or failed. Here is a list:
com.vaadin.ui.Upload.FailedListener;
com.vaadin.ui.Upload.FinishedListener;
com.vaadin.ui.Upload.ProgressListener;
com.vaadin.ui.Upload.Receiver;
com.vaadin.ui.Upload.StartedListener;
Here is a code snippet to give you an example:
#Override
public void uploadStarted(StartedEvent event) {
// TODO Auto-generated method stub
System.out.println("***Upload: uploadStarted()");
String contentType = event.getMIMEType();
boolean allowed = false;
for(int i=0;i<allowedMimeTypes.size();i++){
if(contentType.equalsIgnoreCase(allowedMimeTypes.get(i))){
allowed = true;
break;
}
}
if(allowed){
fileNameLabel.setValue(event.getFilename());
progressBar.setValue(0f);
progressBar.setVisible(true);
cancelButton.setVisible(true);
upload.setEnabled(false);
}else{
Notification.show("Error", "\nAllowed MIME: "+allowedMimeTypes, Type.ERROR_MESSAGE);
upload.interruptUpload();
}
}
Here, allowedMimeTypes is an array of mime-type strings.
ArrayList<String> allowedMimeTypes = new ArrayList<String>();
allowedMimeTypes.add("image/jpeg");
allowedMimeTypes.add("image/png");
I hope it helps you.
Can be done.
You can add this and it will work (all done by HTML 5 and most browsers now support accept attribute) - this is example for .csv files:
upload.setButtonCaption("Import");
JavaScript.getCurrent().execute("document.getElementsByClassName('gwt-FileUpload')[0].setAttribute('accept', '.csv')");
I think it's better to throw custom exception from Receiver's receiveUpload:
Upload upload = new Upload(null, new Upload.Receiver() {
#Override
public OutputStream receiveUpload(String filename, String mimeType) {
boolean typeSupported = /* do your check*/;
if (!typeSupported) {
throw new UnsupportedImageTypeException();
}
// continue returning correct stream
}
});
The exception is just a simple custom exception:
public class UnsupportedImageTypeException extends RuntimeException {
}
Then you just simply add a listener if the upload fails and check whether the reason is your exception:
upload.addFailedListener(new Upload.FailedListener() {
#Override
public void uploadFailed(Upload.FailedEvent event) {
if (event.getReason() instanceof UnsupportedImageTypeException) {
// do your stuff but probably don't log it as an error since it's not 'real' error
// better would be to show sth like a notification to inform your user
} else {
LOGGER.error("Upload failed, source={}, component={}", event.getSource(), event.getComponent());
}
}
});
public static boolean checkFileType(String mimeTypeToCheck) {
ArrayList allowedMimeTypes = new ArrayList();
allowedMimeTypes.add("image/jpeg");
allowedMimeTypes.add("application/pdf");
allowedMimeTypes.add("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
allowedMimeTypes.add("image/png");
allowedMimeTypes.add("application/vnd.openxmlformats-officedocument.presentationml.presentation");
allowedMimeTypes.add("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
for (int i = 0; i < allowedMimeTypes.size(); i++) {
String temp = allowedMimeTypes.get(i);
if (temp.equalsIgnoreCase(mimeTypeToCheck)) {
return true;
}
}
return false;
}
I am working with Vaadin 8 and I there is no change in Upload class.
FileUploader receiver = new FileUploader();
Upload upload = new Upload();
upload.setAcceptMimeTypes("application/json");
upload.setButtonCaption("Open");
upload.setReceiver(receiver);
upload.addSucceededListener(receiver);
FileUploader is the class that I created that handles the upload process. Let me know if you need to see the implementation.
I've met a problem and I've been struggling last 2 days. I have a compiled program that runs some simulations and visualizes the results in an SVG file. The file is replaced every 2 seconds with a new one, until the simulation is done.
Wanting to visualize the results, I made a java swing program which uses batik and JSVGCanvas to display the svg file and update it every 2 seconds.
The code I use is:
// In the main part of my code
svgCanvas = new JSVGCanvas();
oneLineInnerPanel.add("Center", svgCanvas);
(new Thread() {
#Override
public void run() {
try {
Thread.sleep(2000);
File f = new File("file_that_shows_simulation_still_running");
while (f.exists()) {
svgReloadButtonActionPerformed(null);
Thread.sleep(2000);
}
} catch (InterruptedException ex) {
Logger.getLogger(testUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();
// -----------------------------------------------
private void svgReloadButtonActionPerformed(java.awt.event.ActionEvent evt) {
try {
svgCanvas.loadSVGDocument(SVGFile.toURL().toString());
} catch (MalformedURLException ex) {
Logger.getLogger(testUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
It works fine with the exception that every 30-40 updates, it happens that the loadSVGDocument tries to read the document while it's being written by the simulator and thus I get a jdialog error:
XML document structures must start and end within the same entity.
org.apache.batik.dom.util.SAXIOException: XML document structures must start and end within the same entity.
at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:437)
at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:349)
at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createDocument(SAXSVGDocumentFactory.java:200)
at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createSVGDocument(SAXSVGDocumentFactory.java:124)
at org.apache.batik.bridge.DocumentLoader.loadDocument(DocumentLoader.java:106)
at org.apache.batik.swing.svg.SVGDocumentLoader.run(SVGDocumentLoader.java:84)
Caused by: org.xml.sax.SAXParseException; systemId: file:/tmp/tempDir9189341730639722289/svgOut.svg; lineNumber: 272; columnNumber: 2; XML document structures must start and end within the same entity.
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:431)
... 5 more
This doesn't affect the whole procedure, but it's ugly. I get 2-3 of these jdialogs throughout the simulation. I cannot lock the file I/O, because I don't have access to the simulator code. If I lock from java only, the simulator crashes saying it cannot access the file.
What I want is that if there is an error while loading the svg file to somehow catch it internally and not have a jdialog. I can accept missing an update every 30-40 times (60-80 secs).
Now, JSVGCanvas gives you the option to provide a useragent and overwrite the displayError() method to do as you like. I tried that but the dialogs still occur. The problem is that the dialogs are not produced by the svgUserAgent I provide but by an internal BridgeUserAgent:
public JSVGComponent(SVGUserAgent ua, boolean eventsEnabled,
boolean selectableText) {
super(eventsEnabled, selectableText);
svgUserAgent = ua;
userAgent = new BridgeUserAgentWrapper(createUserAgent());
addSVGDocumentLoaderListener((SVGListener)listener);
addGVTTreeBuilderListener((SVGListener)listener);
addSVGLoadEventDispatcherListener((SVGListener)listener);
if (updateOverlay != null)
getOverlays().add(updateOverlay);
}
public void loadSVGDocument(String url) {
String oldURI = null;
if (svgDocument != null) {
oldURI = svgDocument.getURL();
}
final ParsedURL newURI = new ParsedURL(oldURI, url);
stopThenRun(new Runnable() {
public void run() {
String url = newURI.toString();
fragmentIdentifier = newURI.getRef();
loader = new DocumentLoader(userAgent);
nextDocumentLoader = new SVGDocumentLoader(url, loader);
nextDocumentLoader.setPriority(Thread.MIN_PRIORITY);
Iterator it = svgDocumentLoaderListeners.iterator();
while (it.hasNext()) {
nextDocumentLoader.addSVGDocumentLoaderListener
((SVGDocumentLoaderListener)it.next());
}
startDocumentLoader();
}
});
}
Can anyone help me get out of this mess, please?
Thanks in advance!
Finally solved the issue. Extended JSVGCanvas, override the createUserAgent() method to provide a bridgeuseragent of my own. This useragent extends the JSVGCanvas user agent but overrides the displayError methods. Here's the code:
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.util.XMLConstants;
/**
*
* #author
*/
public class myJSVGCanvas extends JSVGCanvas{
#Override
protected UserAgent createUserAgent() {
return new myCanvasUserAgent();
}
protected class myCanvasUserAgent extends CanvasUserAgent
implements XMLConstants {
/**
* Displays an error message in the User Agent interface.
*/
#Override
public void displayError(String message) {
if (svgUserAgent != null) {
super.displayError(message);
} else {
System.out.println(message);
// JOptionPane pane =
// new JOptionPane(message, JOptionPane.ERROR_MESSAGE);
// JDialog dialog =
// pane.createDialog(myJSVGCanvas.this, "ERROR");
// dialog.setModal(false);
// dialog.setVisible(true); // Safe to be called from any thread
}
}
/**
* Displays an error resulting from the specified Exception.
*/
#Override
public void displayError(Exception ex) {
if (svgUserAgent != null) {
super.displayError(ex);
} else {
ex.printStackTrace();
// JErrorPane pane =
// new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
// JDialog dialog = pane.createDialog(myJSVGCanvas.this, "ERROR");
// dialog.setModal(false);
// dialog.setVisible(true); // Safe to be called from any thread
}
}
}
}
Hope it helps somebody. If anyone has a better idea for dealing with the problem, than just hiding it, I'd be glad to hear it!