diff --git a/docs/ReleaseNotes.html b/docs/ReleaseNotes.html index 4856bc5..40902ef 100644 --- a/docs/ReleaseNotes.html +++ b/docs/ReleaseNotes.html @@ -30,6 +30,11 @@ has been added to the DispatchEvents constructors that lets a user provide the location of the OLB or EXE that contains the information required to retrieve the events. +
+ * -Djava.library.path=d:/jacob/release -Dcom.jacob.autogc=false + * -Dcom.jacob.debug=false + *+ */ +public class VisioDemo extends JFrame implements ActionListener, WindowListener { + + /** + * Totally dummy value to make Eclipse quit complaining + */ + private static final long serialVersionUID = 1L; + + JButton chooseButton; + JButton openButton; + JPanel buttons; + + ImageIcon theImage; + JLabel theLabel; // the icon on the page is actually this button's icon + + File selectedFile; + /** everyone should get this through getVisio() */ + private VisioAppFacade visioProxy = null; + + // put this up here so it remembers where we were on the last choose + JFileChooser chooser = null; + + + public class VisioFileFilter extends FileFilter { + public boolean accept(File f) { + if (f.isDirectory()){ + return true; + } else { + return (f.getName().toUpperCase().endsWith(".VSD")); + } + } + + public String getDescription() { + return "Visio Drawings"; + } + } + + public VisioDemo() { + super("Visio in Swing POC"); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + buttons = new JPanel(); + getContentPane().setLayout(new BorderLayout()); + chooseButton = new JButton("Choose file to display"); + openButton = new JButton("Open file chosen file in Visio"); + chooseButton.addActionListener(this); + openButton.addActionListener(this); + buttons.add(chooseButton); + buttons.add(openButton); + getContentPane().add(buttons, BorderLayout.SOUTH); + theLabel = new JLabel(""); + getContentPane().add(theLabel, BorderLayout.CENTER); + addWindowListener(this); + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + setSize(640,480); + this.setVisible(true); + } + + public static void main(String args[]) throws Exception { + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + ComThread.InitSTA(); + VisioDemo poc = new VisioDemo(); + ComThread.Release(); + if (poc == null){ + System.out.println("poc== null? That should never happen!"); + } + } + }); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == chooseButton) { + pickFile(); + } else if (e.getSource() == openButton) { + try { + openFile(); + } catch (Exception ex) { + ex.printStackTrace(); + throw new RuntimeException(ex); + } + } else { + System.out.println("Awesome!"); + } + } + + private void pickFile() { + try { + chooser = new JFileChooser(); + // comment this out if you want it to always go to myDocuments + chooser.setCurrentDirectory(new File(System.getProperty("user.dir"))); + chooser.setFileFilter(new VisioFileFilter()); + int returnVal = chooser.showOpenDialog(this); + if(returnVal == JFileChooser.APPROVE_OPTION) { + selectedFile = chooser.getSelectedFile(); + showSelectedFilePreview(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * use this private method instead of initializing on boot up so that instance + * and all listeners are created in this thread (event thread) rather than root thread + * @return + */ + private VisioAppFacade getVisio(){ + if (visioProxy == null){ + try { + visioProxy = VisioAppFacade.getInstance(); + } catch (VisioException ve){ + System.out.println("ailed to openFile()"); + ve.printStackTrace(); + } + } + return visioProxy; + } + private void showSelectedFilePreview() throws VisioException { + if (selectedFile != null) { + byte[] image = getVisio().createPreview(selectedFile); + theImage = new ImageIcon(image); + theLabel.setIcon(theImage); + } + } + + private void openFile() throws VisioException { + try { + getVisio().editDiagram(selectedFile); + showSelectedFilePreview(); + } catch (VisioException ve){ + System.out.println("ailed to openFile()"); + ve.printStackTrace(); + } + + } + + public void windowActivated(WindowEvent e) { + } + + public void windowClosed(WindowEvent e) { + System.out.println("WINDOW CLOSED"); + if (visioProxy != null){ + visioProxy.quit(); + } + } + public void windowClosing(WindowEvent e){ + } + + public void windowDeactivated(WindowEvent e){ + } + + public void windowDeiconified(WindowEvent e){ + } + + public void windowIconified(WindowEvent e){ + System.out.println("Fooboo"); + } + public void windowOpened(WindowEvent e){ + } +} diff --git a/samples/com/jacob/samples/visio/VisioEventAdapter.java b/samples/com/jacob/samples/visio/VisioEventAdapter.java new file mode 100644 index 0000000..77b91a6 --- /dev/null +++ b/samples/com/jacob/samples/visio/VisioEventAdapter.java @@ -0,0 +1,59 @@ +package com.jacob.samples.visio; +import com.jacob.com.*; + +/** + * Created as part of sourceforge 1386454 to demonstrate returning values in event handlers + * @author miles@rowansoftware.net + * + * You can subclass this class and only implement the methods you're interested in + */ +public class VisioEventAdapter implements VisioEventListener { + + VisioApp app = null; + + public VisioEventAdapter(VisioApp pApp){ + app = pApp; + System.out.println("Event listener constructed"); + } + + public void BeforeQuit(Variant[] args){ } + + public void DocumentChanged(Variant[] args){ + System.out.println("documentChanged()"); + } + + public void DocumentCloseCanceled(Variant[] args){ } + + public void DocumentCreated(Variant[] args){ } + + public void DocumentOpened(Variant[] args){ + System.out.println("DocumentOpened()"); + } + + public void DocumentSaved(Variant[] args){ } + + public void DocumentSavedAs(Variant[] args){ } + + public Variant QueryCancelDocumentClose(Variant[] args){ + System.out.println("QueryCancelDocumentClose()"); + return new Variant(false); + } + + /** + * we don't actually let it quit. We block it so + * that we don't have to relaunch when we look at a new document + */ + public Variant QueryCancelQuit(Variant[] args) { + // these may throw VisioException + System.out.println("Saving document, hiding and telling visio not to quit"); + try { + app.save(); + app.setVisible(false); + } catch (VisioException ve){ + System.out.println("ailed to openFile()"); + ve.printStackTrace(); + } + return new Variant(true); + } +} + diff --git a/samples/com/jacob/samples/visio/VisioEventListener.java b/samples/com/jacob/samples/visio/VisioEventListener.java new file mode 100644 index 0000000..3303045 --- /dev/null +++ b/samples/com/jacob/samples/visio/VisioEventListener.java @@ -0,0 +1,33 @@ +package com.jacob.samples.visio; +import com.jacob.com.*; + + + +/** + * Created as part of sourceforge 1386454 to demonstrate returning values in event handlers + * @author miles@rowansoftware.net + * + * There are many more Visio events available. See the Microsoft + * Office SDK documentation. To receive an event, add a method to this interface + * whose name matches the event name and has only one parameter, Variant[]. + * The JACOB library will use reflection to call that method when an event is received. + */ +public interface VisioEventListener { + + public void BeforeQuit(Variant[] args); + + public void DocumentChanged(Variant[] args); + + public void DocumentCloseCanceled(Variant[] args); + + public void DocumentCreated(Variant[] args); + + public void DocumentOpened(Variant[] args); + + public void DocumentSaved(Variant[] args); + + public void DocumentSavedAs(Variant[] args); + + public Variant QueryCancelQuit(Variant[] args); +} + diff --git a/samples/com/jacob/samples/visio/VisioException.java b/samples/com/jacob/samples/visio/VisioException.java new file mode 100644 index 0000000..1a055cb --- /dev/null +++ b/samples/com/jacob/samples/visio/VisioException.java @@ -0,0 +1,22 @@ +package com.jacob.samples.visio; + +/** + * Created as part of sourceforge 1386454 to demonstrate returning values in event handlers + * @author miles@rowansoftware.net + * + * This extends runtime exception so that we can be sloppy and not put catch blocks everywhere + */ +public class VisioException extends Exception { + /** + * Totally dummy value to make Eclipse quit complaining + */ + private static final long serialVersionUID = 1L; + + public VisioException(String msg) { + super(msg); + } + + public VisioException(Throwable cause) { + super(cause); + } +} diff --git a/src/com/jacob/com/InvocationProxy.java b/src/com/jacob/com/InvocationProxy.java index 0ffc4a8..d797a73 100644 --- a/src/com/jacob/com/InvocationProxy.java +++ b/src/com/jacob/com/InvocationProxy.java @@ -28,12 +28,17 @@ import java.lang.reflect.Method; * * DispatchProxy wraps this class around any event handlers * before making the JNI call that sets up the link with EventProxy. - * This means that EventProxy just calls invoke(String,Variant[]) + * This means that EventProxy.cpp just calls invoke(String,Variant[]) * against the instance of this class. Then this class does * reflection against the event listener to call the actual event methods. * All Event methods have the signature * *
void eventMethodName(Variant[])
+ * or
+ * Variant eventMethodName(Variant[])
+ * The void returning signature is the standard legacy signature.
+ * The Variant returning signature was added in 1.10 to support event handlers
+ * returning values.
*
*/
public class InvocationProxy {
@@ -69,7 +74,7 @@ public class InvocationProxy {
}
// JNI code apparently bypasses this check and could operate against
// protected classes. This seems like a security issue...
- // mayb eit was because JNI code isn't in a package?
+ // maybe it was because JNI code isn't in a package?
if (!java.lang.reflect.Modifier.isPublic(
pTargetObject.getClass().getModifiers())){
throw new IllegalArgumentException(
@@ -78,17 +83,24 @@ public class InvocationProxy {
}
/**
- * the method actually invoked by EventProxy.cpp
+ * The method actually invoked by EventProxy.cpp.
+ * The method name is calculated by the underlying JNI code from the MS windows
+ * Callback function name. The method is assumed to take an array of Variant
+ * objects. The method may return a Variant or be a void. Those are the only
+ * two options that will not blow up.
+ *
* @param methodName name of method in mTargetObject we will invoke
* @param targetParameter Variant[] that is the single parameter to the method
*/
- public void invoke(String methodName, Variant targetParameter[]){
+ public Variant invoke(String methodName, Variant targetParameter[]){
+ Variant mVariantToBeReturned = null;
if (mTargetObject == null){
if (JacobObject.isDebugEnabled()){
JacobObject.debug(
- "InvocationProxy: received notification with no target set");
+ "InvocationProxy: received notification ("+methodName+") with no target set");
}
- return;
+ // structured programming guidlines say this return should not be up here
+ return null;
}
Class targetClass = mTargetObject.getClass();
if (methodName == null){
@@ -103,24 +115,39 @@ public class InvocationProxy {
JacobObject.debug("InvocationProxy: trying to invoke "+methodName
+" on "+mTargetObject);
}
- Method targetMethod = targetClass.getMethod(methodName,
+ Method targetMethod;
+ targetMethod = targetClass.getMethod(methodName,
new Class[] {Variant[].class});
if (targetMethod != null){
// protected classes can't be invoked against even if they
// let you grab the method. you could do targetMethod.setAccessible(true);
// but that should be stopped by the security manager
- targetMethod.invoke(mTargetObject,new Object[] {targetParameter});
+ Object mReturnedByInvocation = null;
+ mReturnedByInvocation =
+ targetMethod.invoke(mTargetObject,new Object[] {targetParameter});
+ if (mReturnedByInvocation == null){
+ // so we do something in this block
+ mVariantToBeReturned = null;
+ } else if (!(mReturnedByInvocation instanceof Variant)){
+ throw new IllegalArgumentException(
+ "InvocationProxy: invokation of target method returned "
+ +"non-null non-variant object: "+mReturnedByInvocation);
+ } else {
+ mVariantToBeReturned = (Variant) mReturnedByInvocation;
+ }
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
// this happens whenever the listener doesn't implement all the methods
if (JacobObject.isDebugEnabled()){
- JacobObject.debug("InvocationProxy: listener doesn't implement "
+ JacobObject.debug("InvocationProxy: listener ("+mTargetObject+") doesn't implement "
+ methodName);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
+ // we can throw these inside the catch block so need to re-throw it
+ throw e;
} catch (IllegalAccessException e) {
if (JacobObject.isDebugEnabled()){
JacobObject.debug("InvocationProxy: probably tried to access public method on non public class"
@@ -130,6 +157,7 @@ public class InvocationProxy {
} catch (InvocationTargetException e) {
e.printStackTrace();
}
+ return mVariantToBeReturned;
}
/**
diff --git a/unittest/com/jacob/com/ExcelEventTest.java b/unittest/com/jacob/com/ExcelEventTest.java
index 6bfac2d..85b0907 100644
--- a/unittest/com/jacob/com/ExcelEventTest.java
+++ b/unittest/com/jacob/com/ExcelEventTest.java
@@ -74,10 +74,11 @@ public class ExcelEventTest extends InvocationProxy {
}
/**
- * override the invoke method to loga ll the events
+ * override the invoke method to log all the events
*/
- public void invoke(String methodName, Variant targetParameter[]) {
+ public Variant invoke(String methodName, Variant targetParameter[]) {
System.out.println("Received event from Windows program" + methodName);
+ return null;
}
}
diff --git a/unittest/com/jacob/com/WordEventTest.java b/unittest/com/jacob/com/WordEventTest.java
index 9f49a2c..4d07ed7 100644
--- a/unittest/com/jacob/com/WordEventTest.java
+++ b/unittest/com/jacob/com/WordEventTest.java
@@ -68,8 +68,9 @@ public class WordEventTest extends InvocationProxy {
/**
* override the invoke method to loga ll the events
*/
- public void invoke(String methodName, Variant targetParameter[]) {
+ public Variant invoke(String methodName, Variant targetParameter[]) {
System.out.println("Received event from Windows program" + methodName);
+ return null;
}
}