Mercurial > hg > octave-nkf
changeset 15625:acf0addfc610
include Octave Forge java package in core Octave
* scripts/java: New directory tree.
* scripts/Makefile.am: Include java/module.mk.
(JAR_FILES): New variable.
(nobase_fcnfile_DATA): Include $(JAR_FILES) in the list.
(all-local): Depend on $(JAR_FILES).
(java/PKG_ADD, java_GEN_FCN_FILES, java/$(octave_dirstamp)):
New rules.
* libinterp/link-deps (LIBOCTINTERP_LINK_DEP): Include $(JAVA_LIBS) in
the list.
* dldfcn/__java__.h, dldfcn/__java__.cc: New files.
* dldfcn/module-files (__java__.cc): New file description.
* doc/interpreter/java.txi: New file.
* doc/interpreter/octave.texi: Include java.texi.
* doc/interpreter/java-images: New directory.
* doc/interpreter/Makefile.am (JAVA_IMAGES): New variable.
(IMAGES): Include $(JAVA_IMAGSES) in the list.
(MUNGED_TEXI_SRC): Include java.texi in the list.
* configure.ac: Check for Java libraries and tools.
Include Java info in the summary message.
* build-aux/common.mk (JAVA_CPPFLAGS, JAVA_LIBS): New variables.
* NEWS: Update.
* contributors.in: Include Martin Hepperle in the list.
line wrap: on
line diff
--- a/NEWS +++ b/NEWS @@ -97,7 +97,29 @@ ** The default name of the Octave crash dump file is now called octave-workspace instead of octave-core. - + + ** The java package from Octave Forge is now part of Octave. The + following new functions are available for interacting with Java + directly from Octave: + + java java_invoke + java2mat java_new + javaArray java_set + javaMethod java_unsigned_conversion + javaObject javaaddpath + java_convert_matrix javaclasspath + java_debug javafields + java_exit javamem + java_get javamethods + java_init javarmpath + + In addition, the following functions that use the Java interface + are now available (provided that Octave is compiled with support for + Java enabled): + + helpdlg listdlg questdlg + inputdlg msgbox warndlg + ** Other new functions added in 3.8.0: betaincinv erfcinv lines rgbplot
--- a/build-aux/common.mk +++ b/build-aux/common.mk @@ -224,6 +224,9 @@ HDF5_LDFLAGS = @HDF5_LDFLAGS@ HDF5_LIBS = @HDF5_LIBS@ +JAVA_CPPFLAGS = @JAVA_CPPFLAGS@ +JAVA_LIBS = @JAVA_LIBS@ + LAPACK_LIBS = @LAPACK_LIBS@ LLVM_CPPFLAGS = @LLVM_CPPFLAGS@
--- a/configure.ac +++ b/configure.ac @@ -738,6 +738,105 @@ AC_SUBST(LLVM_LDFLAGS) AC_SUBST(LLVM_LIBS) +### Check for Java. + +warn_java= + +if test -z "$JAVA_HOME"; then + AC_CHECK_PROG(JAVA, java, java) + AC_CHECK_PROG(JAVAC, javac, javac) + AC_CHECK_PROG(JAR, jar, jar) +else + AC_PATH_PROG(JAVA, java, [], [$JAVA_HOME/bin$PATH_SEPARATOR$PATH]) + AC_PATH_PROG(JAVAC, javac, [], [$JAVA_HOME/bin$PATH_SEPARATOR$PATH]) + AC_PATH_PROG(JAR, jar, [], [$JAVA_HOME/bin$PATH_SEPARATOR$PATH]) +fi +HAVE_JAVA=no +if test -n "$JAVAC" -a -n "$JAR"; then + AC_MSG_CHECKING([for Java version]) + java_version=[`$JAVA -version 2>&1 | sed -n -e 's/^java version[^0-9"]*"\([^"]*\)"/\1/p'`] + AC_MSG_RESULT($java_version) + java_major=[`echo -n $java_version | sed -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\)\..*$/\1/'`] + java_minor=[`echo -n $java_version | sed -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\)\..*$/\2/'`] + if test $java_major -ge 1 -a $java_minor -ge 5; then + case "$canonical_host_type" in + *-msdosmsvc*) + HAVE_JAVA=yes + JAVA_LIBS=-ladvapi32 + ;; + *) + if test -z "$JAVA_HOME"; then + # This is the location of Java on an OS X box. In this + # directory we can find the various versions of a + # JavaVMs. Check for the newest version set the JAVA_HOME + # variable. + if test -d "/System/Library/Frameworks/JavaVM.framework"; then + # Sneak the -framework flag into mkoctfile via LFLAGS + LFLAGS="$LFLAGS -framework JavaVM" + JAVA_TEMP="/System/Library/Frameworks/JavaVM.framework" + JAVA_HOME="${JAVA_TEMP}/Home" + JAVA_ARCH="${JAVA_TEMP}/Libraries/libjvm_compat.dylib" + # According to: + # http://developer.apple.com/unix/crossplatform.html + # you need to explicitely set the include path + JAVA_CPPFLAGS="-I${JAVA_HOME}/include" + HAVE_JAVA=yes + # This is the Debian default path + elif test -d "/usr/lib/jvm/default-java"; then + JAVA_HOME=/usr/lib/jvm/default-java + # This is the path of java 6 on debian + elif test -d "/usr/lib/jvm/java-6-sun"; then + JAVA_HOME=//usr/lib/jvm/java-6-sun + else + JAVA_HOME=/usr/lib/jvm + fi + fi + JAVA_HOME=[`echo -n $JAVA_HOME | sed -e 's|/$||'`] + if test -z "$JAVA_ARCH"; then + if test -d "${JAVA_HOME}/jre/lib/i386"; then + JAVA_ARCH="i386"; + elif test -d "${JAVA_HOME}/jre/lib/amd64"; then + JAVA_ARCH="amd64" + elif test -d "${JAVA_HOME}/jre/lib/mac"; then + JAVA_ARCH="mac" + elif test -d "${JAVA_HOME}/jre/lib/maci"; then + JAVA_ARCH="maci" + elif test -d "${JAVA_HOME}/jre/lib/solaris"; then + JAVA_ARCH="solaris" + elif test -d "${JAVA_HOME}/jre/lib/solarisv9"; then + JAVA_ARCH="solarisv9" + fi + fi + if test -n "$JAVA_ARCH"; then + HAVE_JAVA=yes + case "$canonical_host_type" in + *-mingw* | *-cygwin*) + JAVA_LIBS=-ladvapi32 + JAVA_CPPFLAGS="-I${JAVA_HOME}/include -I${JAVA_HOME}/include/win32" + ;; + *) + JAVA_CPPFLAGS="-I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux" + ;; + esac + fi + ;; + esac + if test "$HAVE_JAVA" = "yes"; then + AC_DEFINE(HAVE_JAVA, 1, + [Define to 1 if Java is available and is at least version 1.5]) + fi + else + warn_java="Java 1.5 or later not found. Octave will not be able to call Java methods." + fi +fi + +AC_SUBST(JAVAC) +AC_SUBST(JAR) +AC_SUBST(JAVA_CPPFLAGS) +AC_SUBST(JAVA_LIBS) +AC_DEFINE_UNQUOTED([JAVA_HOME], ["$JAVA_HOME"], [Java home.]) +AC_DEFINE_UNQUOTED([JAVA_ARCH], ["$JAVA_ARCH"], [Java arch.]) + ### Check for HDF5 library. save_CPPFLAGS="$CPPFLAGS" @@ -2535,6 +2634,10 @@ HDF5 CPPFLAGS: $HDF5_CPPFLAGS HDF5 LDFLAGS: $HDF5_LDFLAGS HDF5 libraries: $HDF5_LIBS + Java arch: $JAVA_ARCH + Java home: $JAVA_HOME + Java CPPFLAGS: $JAVA_CPPFLAGS + Java libraries: $JAVA_LIBS LAPACK libraries: $LAPACK_LIBS LLVM CPPFLAGS: $LLVM_CPPFLAGS LLVM LDFLAGS: $LLVM_LDFLAGS
--- a/doc/interpreter/Makefile.am +++ b/doc/interpreter/Makefile.am @@ -83,11 +83,23 @@ $(srcdir)/images.mk: $(srcdir)/config-images.sh $(srcdir)/images.awk $(srcdir)/images $(srcdir)/config-images.sh $(top_srcdir) +JAVA_IMAGES = \ + java-images/image001.png \ + java-images/image002.png \ + java-images/image003.png \ + java-images/image004.png \ + java-images/image005.png \ + java-images/image006.png \ + java-images/image007.png \ + java-images/image008.png \ + java-images/image009.png + IMAGES = \ $(IMAGES_EPS) \ $(IMAGES_PDF) \ $(IMAGES_PNG) \ - $(IMAGES_TXT) + $(IMAGES_TXT) \ + $(JAVA_IMAGES) HTMLDIR_IMAGES = $(addprefix octave.html/, $(IMAGES_PNG)) @@ -123,6 +135,7 @@ interp.texi \ intro.texi \ io.texi \ + java.texi \ linalg.texi \ matrix.texi \ nonlin.texi \
--- a/doc/interpreter/contributors.in +++ b/doc/interpreter/contributors.in @@ -93,6 +93,7 @@ Daniel Heiserer Martin Helm Stefan Hepp +Martin Hepperle Jordi GutiƩrrez Hermoso Yozo Hida Ryan Hinton
new file mode 100755 index 0000000000000000000000000000000000000000..d5ffef6d4345c4a12336e6ca5a03eeed7e6ca750 GIT binary patch literal 14199 zc$~Gk^;cWn^9Gs_2zGEwTC|3=K!BEFg#a~*7ARIExD}_k1qrmYKwI2t@nVJI7Tn$4 z-QCIMec#XbuKN$%{E&09v)1gH*)z{P&;F#O@QRG&76}LhB9nRjTp0ucbKblM5<zah zJs;@B-aPP4CFLbSpg$oV7jJ*u{AM+Ltt<}$x!nhWeEdM5Gu+K{6$JW-0D;y~AdpBD z2*h9$l@&7x0zp7Za;h)-yPBUUej4iP`#?(k$}DPhup<ge$o<@XQ%48w<2l;0ND{q; zyErOq8>8W|?Hi~V>T7KuY>%#7nwuIP>}@1*Tp!-N?(1y-7}-);nje@wjPdp9YOC)W zs%!7>o9Jja!Ia}JcCeLyvy63?u5t9(v*EtZ@$RPSvHsYy3EcJB^4xev>0-y=)L>6r zYh(3lW4WwWcxwIPJD1=6gC%C}g<lhTJ388=rIF&#M4CHBF{vH0rm3A)R(FK0<~pk9 ztFYRR#e;oyUO&6%+uF~|iwN<+33Xe|brq>ihdMq5mH5PWo_g<J<0O${=7CMYrGrHk zEgd5jk?CV@QKiE@Exn!f{rx@j?VHlt>7@gCEBL^<l+y4*Z$~qBpr`rbGsex$nVLg) zv9D`<xU03VQ`0=f2~*`B*Q4^`@5aik*^d&Vpd8=e$kMvCqemhQ0|V%9O(hE*hg&PA zAx7to^}PewptQL=0&gPomYVyT-{xNNPhJlUjt_NrU0%&ZH%-m7Om?)?4AHPc-nI7h zbrIin5>t(z80qaC8tfYB8t85Be=1Vb+1S#YIS_`K=xK{B-K}mu85p1UNvKJU_}Vo# zF~4)w+BY`UP*c;?Y2b-%o-G#*I1@lBTZdu?vDm_#G+!HI`H*op@6XuI?yDo*abIii zc(<e&lK8eZQpp%MH;Fsm$E_ZoxVZ0+tjHM_)J|aQM>_Hb&Y$Uq+@>O4y&M_q&l&5+ zZe4HIk6axw-rZkqs%b0j&P{HpDQ#q?$WnX_dY;lU`Kx!dp<!qZY~4KEnH5?%J>Asi zl)j~8m)Ox=*wZ-D+=^{(>QIw^fzE9o9_g_Q$%l~gjLok&CRg|L47N-RZk${%%{LCr zj5&n%e$DP~9d4p!<?A2nJ~`MK9&8Thd~}(ep5C?4-#$3dT94#rA8qf_@JbkKY3y%l z>uGNs?JJ%gZ5-*VN-U2Y8m;|NFnGPy7npZ2+%tVO(~OIc?r!*Vj9WwLsmmvI_x868 z_O?`5bCrNV0>?7XB~@MG4HT9|C01T*r_CR4jI)&9*Nm9To!|2~KYJ~A{xR5c2NLy% zYp;xH+~sI4B?1r6S=}qVmiwxD*UKuU&66sl_Rbv}=k2hiZ<JZpJRm5w`qLS)Hk7T? zg8T~cZP$C#m~D3#tNNptthAJ7lSAH2{shS7No`Mck_Y7J_g!WW^Sp|Xlr@RCWU8S1 zFyp8M6K&i9uP;3ny3fY>=l(bIWNq)z4eE~^5?fx}FrN2#w0eaHBP<23M2waAIoBi2 zJESw$Ps$JO7$1!}WV~sYbxy;bvUR%7$MYdUd_1#Hj);s=nQs>^yWv^`$^(U&Cxq@> zFFcnjLl>psgYf=E<`nGm_e5$al+}xy#5aBh?l#XLmBJB5){KNhp_CYOz@F`cSXbLt zP(N6O@FyGW17Yg}D3k~zne6^YD#%UF4w_kM2MId^M9K+5pTl)KB>gS4U@%7V&0SR4 z4hbdl%Y1zmsk5_<K>?mjv@rjqQ9<Q5@3V;Ji|SCJLRjA9DVNBzgC{V*xwLl=Yj&UK z1ZmiX)VaJNr}Q$({9ua8T+Lhs^|9`%l@&6zcE=|QGc}TF{t$j<L>7d3?RWZmJ_Z;N zfct2G=H`2cY#*JN@yR`Q=khm*jwSPT@c<yf^GFyz`p~q@wv(C&Q#iLQ<+G6c&f9dF zL<7b`YM+qO+7KgUPWOAeDF=^;^(9%labV?%m8lSkYMN^T+kBU#EL0I=!Tui8Fvrm3 zEZ`w2L%idEOn<WNsP0mrqD=AK<oSCGA27TSN)L;{8gX9I6S?|`^uW>KK6rWG!6xLs z(AXC2E|DBRLK}~Y`w0MK6-mN~zIMakl_X6NQxg&Z_=;WEtrU&2tm2TOx=R=Wze!>I z5v4*L!S}#F17CW0LMv0i#5K2Xg|Ql;%zpc#!i1}ou17M;i~Qa*2=<6O-w&C~4VF>f z9cKy5*l*dwCt__jGX3@DNTWlTla47lm8viuZ=F3tluJ|<2HOU$k%tLA=GY9oV^#W) z$d3&Ip~US^w?i8NfE6IHdPiwytKX6KPXD)7WaA*hY_hkk?uw3F@m|8R3F=)nnQzjm zPuLm@O%DU>BK`w|gY)Je%j{j;7SFrj{M0Kwt<m4Wf~6^7|2mL$R0EjRzcA{RZ}NyB z>lYoy%4kV|!^G_tP`7{UDGXMxj>*S2l|Ksv1Ydm!`LH+kJ>D~v&8UMSj)2Q~nLT?_ zA0<>|Ii~1@X}OjMf$<+@Jche%A6n=cgDk!pWEv8c)$PhIa<w9q3YbLk|BP-^Qu<bb zf4;>dWt2nh29puNVWYRQQGEm?tgPe^0;+pHJR5j^F9m<r9mWnn;oixe7QN=j$;W*h zJ}u!2-{#rkAs8>ZyGbfkCdA-o1tFw^_yvH)qFE&gNblK#Bq794Tv$Q0uYr7@!-oh` zM%16DVR#)jG>A+X%=$N;AJ?}vyK%3ctzuGEH=2+_8}AtF^Nm#nACLj<wd-<Au4vv< z{^PPuJN+;Nmu4(>NZrVqKu!g~{#CUL)R!ls#d~r~+lK%Sfp8p4dV!=ClMOBiNZu%g zNrHRbDDjJ;8hv)Z!*E}(Q+}hD!kUPo7#ezZk_WVMC{(n&g~@rRV}ZzC6q1O08Zttd zM~Jcf_)yv*_xc5D)jC(g&>k}<gT?p=So)2Ws6+FOM|WDWpv4u%&ZJgb_c!E|+Z(Yc zBBR`qYT(|pByE%3Npg%+ASw%ZEfB*(Xb>h*2p<)AGIzeirN>LZ7jF~qB~HZZ6K&nj zms34pw>H8I%`2;~-`(}a%exFb!}^TZ_12+C8!dfy$zivAW>a#p$re|QfkYh8*T^eh z0$PNhHF&=S%PJI&1Q+|)Ni=(Z!dc*kwty`l6upa2s{pEZ#Ha|!!uw5s5~?nqTLRyZ zWdV}4!?&aJH<Cb*&vpJO6lObGm}13;Xd@7<S9wB%Z5&(RoCuMVb}e~2Tu>mVwn%)} zp4HF#!U=^Oa~-!L{0=SfDa3~k*8TwGkOzh6rOI!D(x$cfUkgj^)AnCj2EQ2TuGli1 z<^BRCVtp{I)KLr2-RU_wPYXEeiC^n#J?)yFzW(vqb1EU{(HJq-SI}Rd9MV7lMa39{ z?nz~nHF~)v(Hf3+u|^`E>5FjaMf-WAJ|cZ1GhI6h8-;m{!eAaS-x6&D2vp@ZC4_WS z7T^PJM}06Fg;jh@`7TLMq^O~Rpw-ZzrA5#pI*n(I5VGn721-iRMlR(GX$)cb>6xx* zEuaJL1?oEJn`tk2SNkocFZCO`E;T4+iX1lIpM0xy&`uf)#gG9G@7~!c>MI%d;@6Q- zX0=k1Iv!SZpf^Uq5K`6r5BZZ`tv|s2aG1gf#Bcpn1>+6ibRm2Vs+cT_?lZ(=ub9!q zU*809TR%hH;p>BP$7SAvJA^mzm~p|<%}vN<aN3PP2eZwLrP(eOF#$c!Wq&UXPE-Gw z=}88){8Z$^`Z8&ht!zfyxc6%td);YZ@<M$co@}xeI60q+_yYu7$<{xIFJBbIu$UO0 z5&$p^cS2y@eYN*=h!;Bjm8mVD9;f6lgbLjBNHK8u-tvPU`Iqe;qGC=iJ}PvN55NM< zhz&l(s@`C&#te~vZw^{J1FvWr1G3eG_#?*`J1IgoKA+SX51k`9@Qo#24;y9@LY+MC z3dy@#L5yp?kwmF0d74<(t98RAWhfn_L!t-X=skTA(bM~^IG&Ex2PSb`Znvr0)@{RU zwCglyFxp7TFs)~fy9~i=V8*Dcy#+GpHM1s#O>*N6oH>lv=EK9(12=PS!M)@s9#lB` zI<zP|h-0S6-c48Pl%69lO$+kyOeAtGfxO{Y#w_mzlJQV3lA6iKFiI)cWFN2;;sOK3 zzm-r~NBObaOmmQ5=_*Q)bUfD3c4n={Az1NQff+<<U;ubu{cxg`8Eo<vCBqE*ptG*s zSB^)L&BBNzdQ72_19|wQW1)1=8vMT5cpS@`4~>$;-Xr=#3JoAs?xAJo2&#da5GW01 zPD7!;UJ1Kvv_=x&hF`*eir=2O_^4l#S9H#GgH;9^gA*i={CtdEz2gU;qRe-JRxzT# zi+BA98xr(%gJEz$YTlP&?0#3K&<yi_#m>rCL!fVZ;*K6)0Yk0e%FaaBti)Hldh3ZF zKxHY(WW4Q<Io}QAW>holMz(Aa5>L_$`N9W}<hd^%F@9a0KM}`WRD{vr&LB1tfA~+` z48E$wqg#W5rat(pS4Jo#pGLG6$YC?>F47?sB>QIx++hg|hj;4;x7Z5r@+0!EPszwR z;+g~_0j!Tf8J%9UQo7YGlonYdR{Plxv}QaUrbN<1>%|$w5AMKI;!1RP-*)N|ZOR3F zO-&e1XAE2Sbx0q*_~_=I4f_ek3+fZ^kx!3Lk-!m3OO(z3(E1ypZ*u)C^xj(&C?@qj zx$qJbmOgT%A=SVN^IMl9Ul-RH)|l*M`E_}*_0HBlGS0wip{Gb?M4*Zad<6abm4Od* zn-M+#;m5qs)=c!r<oV0n4EVkf$f70+YJ>vKu`mMcfDp2n1yXh^e&}3@8E+2FNTDDX zMoaKp1`Y2$JR~L!2Z%bnl2t!;uQKx9dpD(yF9o%Y#Y@lTPaZ&a%W8yyh9Pg>rDveC zNMa2nvn;lATB%!_1KBlrw>f5KS1K)&miGD{P01(RRCP3SqktILB9^Fe4hT?IraW=o ze7)j9*WZk_MSVM#f$~}@78^h@ezS}ThkMa`+)tnw_zR~cpcD`GMIxU;(|h0g?Y2xZ zbukhpEgFTMo4BX+ju80$ZpH`P1VV2kS8HjA&~35cAVtu|CmMPNY%xp0A1rGRi0mKO z-@>ndi87^(j{U29fyB#Zrd3Km0y5BPlWHg=n9q+)sR{~HdIE?5rD*WSm=k`XWH}_b zsUUie9+5oUl24e<g<|E4#<RoA>;_4pvPE)1<QxxBQ|#oA&3PI!K2P4Oy^Y841oq(4 z_FUC)`Em%*P!AUX;ZxrI(JX_CrS`5tcq|pkFzLT>1p*#QEdB<k9Y4*@3KAy!V0F<& zr{g9NB^k#SvJ~_+>g8lODci~btdM$VSD<lCAa&O{n_Fwf-Hr-^KySs?i1UBwm}Gxv z<HlmC1B!T!U1smSi@kG2O^J46L{6{wwiF_XjL^4)E27YpvAzm1V79Ut><KY#!>lrl z2)U)oiZ4iw<>s<|-;V!1J@Ji11hnv2)VF`o>YZ&0`LLgvY#r%GL}fL#a;Bfp+FF%N zftqOQYg5Hfw4q{FYHNC|AEm5)cfLb3ndkA69}`d_<+uQrel~Ni_>_5wX;Y#Uf<nW3 zbt<c1=rf_9^$LH`i=I{ER;7nCmC4a_N~djMXPAkSvFW*;E0~IQXYc!K|ELt$D5RP| zPPGaEEPuQGhLxai(Z7eO`DiJ-0Z~ZSWokqWx4s4$2?wU7kP1jkM&c0;I%AA5Do7Uy zkt8@`Px(@%xdTx8MMEnGjCdgH@JTp!g0aVgG)fa~_@map@ukdJ@%Nb|4cf3b5MV1x z!YDWUlHCu^kqKi3FA<Y)KsAst3j74={7Ro=DS*s!z(ED3{n$8y<Pr{y(HGNxxNfZu zmIOtoE5ku}L3S;6#RDs<YWAK#NOo4*ou^52AQ#REmmWTp(1G1VOY5|Hl!=e1yFv1U zitu(eDCa|rA%j=DubW`#ua$=aubJqdNVK(p<U~TFh>X1E-Jd*_gD-w=0c7h-<a&&J zihEOX9VtOiX^~5`Wwv;w{oD%3XaL(um`^MzE&Mg?oY5COD{+_77e@J=&6I?(z6;ky zg0c0|p`rB^qND}@9v`-7vhCMBZy*&1B`z^t!yW84m~GzLpT{bWZ<piCUVQUaxd}tY zhwbiG{Vg6$yD5&eR^G^ra2W0Gqq7tq67nqLg@b}@Kxa_I_v}iCKuL?x@bCzYpzzOH z5)D18Ei5cJmk-v46J8_P9_uZkp}*<>%EkzIgt@U7i<t~9d<un&U+J_oH5XJu$CU}` zn}F-rwol69@uVn0{Wn7~DKU|pD+Bd}?Q!xteEZ3?At+J<CrL@KgmfY&^7SLa^Y&vC zOV&uK!}pa(QPT<m8?2sR<Dh}aLuXb6NS!87#Cn&q6umVh?H;wUrCojaxjQv;i5?&p zh3iHz;Nepm?zek;NdjYM*heS1AhU4g7d2OsD9k&s+6*w4i>;aA`z@MJ4z6r>QUjPG zaH5+qpR0=8+!k04PTl=|sep&|gjYY^C>&Cfm2+Dgo)fB78VnW{rIrh<PPyqE83J&! zAcxj(lEM2Xqju%t;P2nDTbw8wFfex>b`iqbtB&ulB-jeVk3af`yDOp1G$27lW>MgK zJF2*gwUzao$VC9YnFk>Zl8o6D%x6lr09yGK<DPJ9Up?w!Odg0wb8egBhJKLFC)QNq zQzARho=E_@X1I5_dL^EY_VxWk+4B0jPsX9J=?L?W1@CG^k9(K*7V?2_E%Ry*CA=Q( zl)dn>#G`3o8*y!~)Ld~zh}F!yU4)N+oxu7OPDi*LHg7fls-n3)e4221_(ei7WRAKl zW(!E=t;UC-JQrN<&%f~x3F)SxBf8AlKU;nV-4lKPyd-Fnvb=5=O2k%|N_v8Loa|xE zhDV|idWT>T<D51Hw7fCB5<8}WDX|Enb|s{*=0sS<8eLxRlTz--L!_B84!|qbaaAYK zT&SqC^^`Gw2?sj&O^+zx@kxzXYJ1YMY36kmpVE2F^vd+aQA+Kl#qEDOt)Wytjvn#I z0Q3L`#Rzi(*zktlGT5NK2`ZX@ir+|{sDPkiA*8*(2~hFztRiIt@{xCmxn#$rmy7s( zDrRa&JK?i;Ns{-dSXDO0sd-ogcU|bphR7Qk!ej~XK_g<l<AnI#x2M&f*#zOI%)eYo zrfgr4GEd_}FcyoqV?p&wtQQ*eYIRblO6Re|^`~*`sMX3b=L0>HOd+#fNb2;7RNqI` zh*ji(IAyqJd<)i#UC2{^<^2tl@o-1}S=A$lm<16$HX`gx$Lk_-Rvq@Ad|TdNTL)@H zwaW0JKwnEierxQRw;_O#C@TYuAKQ)PMfGTG;Kk856yMkXZQzsU+WQ@WDUp5JD+Lvd zce>@OK}P=?`6Z8$>Ny9PfPxD(K}Mwk0I$9|`uY;nA}vahuv=mPP!q=nV}70tvNP~0 zL3rf%;L*PaT5^yJvB)*L11>b#psR}2O@4(hm43f0Du`5WNxEW7$1UYN9{yOSQL}!$ z$hYhI@NGR?-t4`+yDPW@T0@PH!wa5IIQpK2d$bKqQ;$a&E{}U;%Jq73`g(GWzTN*= zEYH26NhYf9tv~Z#2lA&{j(DcZvndrm4U?L6hakMtJkDBVS#`B*sfcQ4${kwH8WfBJ zD3Zv_b{Gie^932$b~n^d1dtzU9)W>cE<Jo{V@Zx#G?JM$@{4;1)W{6Id(GREz@w%2 zw`7c^mW?^+qwouHd%Qh1LZYhWf@w*$<G4*3TS4!JunJ*!t>e#|<`%xUb0qNg{ALgK z4OSY}nM8-{(%q#`v=930iQK)R=`tX2V`|B&JypwisO(k0^mQUndF5xe`Q;Iv-wbkB zttg%a*X4xfL3W9rcA+dIbq|SMIILM%ZYl$wE^&4iQ=MHHf$ODe+e#ESwKk58jZQr5 zd2GH!YB^Q@@Lm(kXb+9COZ|NRo=TJaeIkFf)j@K?ffEmYy1F-O;z|iAKD@t(LLf7B z1d+LFtSB!*-Ux7waRIE+3EXXAU97~3dZ_4|8l(yUe*5vk6sjTqrGSV?qO)AWdDTL< zDvBwyKDoUBnz<oB$)B0YqdG?1C}|1vA-A20$&JmepdoT~aFOtvwL)b%5IzRjv8<r_ z`W08;QBAC0bE7i4H%9V{zQWbc>AuuWxmNN1YP9X#6?75G!=QII+mFfEEwOF;f(^g0 z_E1u#4myfR>5fOCcq2&#VeVLL@-C6;NPK2Z?q`;tYqej$UF|}Y{NnEcw?-wKVcX_e z=uR@9`1+H!g}Qj!S{d><?HhWV6+NeNui>|f9Ln;2cY3J}3SnvnhWaoz{Gv%#<E8;$ z64BuuX<WMFhl8QCVShm)J7C=}#QidL$b8`+zI<{@FZ?Pkodh<;i5rond!BDhg@pHn zq?rqbNGXwD5?)nMG<t`bjEb9f6GKlb;)7&mf5Bn80{(pQB1|9O7jx4p3s8kBHdqLd z+d5Bwk#z7A(fva5_-P{#IV<=_G(Mc?=iX7@X<fpS64Bhuqveana)if^he!}#cXT*I z4;DL>5%aX|&QgEqsrd?7zzp8Smj3Y79_bHqnr^ZH<j2=S8TJ%%jEt&o!>^v?FEp&O z5paqJVN#)VDPcEbI5_1X*H)OeHo|csjwZiBX@!Im3G8<yO5m)IE?u3caJY~8(b3ij zaNR>#-f!swI|J2IMiRZD>g*r+19zn)Nb>GdeJ5FO+*l9etGHC4Vy7aSUc>hnWl54J zrXi-8J%kXkLLcO=%+z{&UsvZ{;BdVn={rxYeIOg6luz-x2>xvB8anRy9{D1AIa3;4 z2!^UelCM%x)NH+PIbb@>FtK%|OS_fs1Qv;HqbrU({atH>H)$0OVL=gXI`_IhQ#m@m zi&8(LZdf5(&k*wJwC9BkC+bcp(7f*YW_Gy*0D9f<J&!qk#MDOB$Qcz&!Q{YQf*;Xw ztU5B(tQAg=uOC98y9Ve|0QeNj%e|%T{pu``ydfzm@1_ayH(OQt8U_C1J?tbzrQIKa zC^QM!cD^MP<acYT@{!d4%<#)E5U|;r=C3ji65H|^kCEK&KQq(!h@SIUQKkj5ZDi`) z?nyabMT2PNZlqXrPx6Q+`G<r*0*{O-4M0S!FTs+P1RrXt1#4QUjPpu`y(SeWPnNXp z@^$Vtz){4wu#|)p`o|<~1y0MR7-yHe9;<%r$rU>n0WJTy*NFY3w`4WM!iepC*3wIw zm?#J)Ekrl7!Pnva<~#jpXaxXVz=Tu+U^kE&FemC2VUjEtv&*6X(68X<IYmgNI-c_@ zQT{=Hf<>dG3WSWDFHbiU(zZMrJnEi!6#{1UAxh_@T-Dt51~*tfJCb3fW<+nGjfo-B z*m~oPPT2l~>f~}2LYU9Mpa(1DMoAH+W#v7?;i3>6T(Bxn?=ts2Kb9pgEOhMp?m(xO zN%i;HN9=dv0|m=EL2@d|n%X{~JJIQz-Du8`398axKE<hAlu-h!I&Q^!u-19P!a!l4 zC>0R+c|p90(V^Nj-e@31&8>sp%jvRh_FD1FL5J|!fKx(LWXWDn5H{bl72+a%!}}Xk zvjPD?LKUtJi}b8%!-~Js*`zBdwrk~yV*8{&8m0Vti53Z>dX&K|h~VeX5v=s|>bS~J zZ+CNRAt0G>p!2%=e1&j6mIQy|bhO(B;r(mWe?wf!1;cNvK`Wjo){QOr{BSpLW-FST z^l1KT`m1i&-B_P(Hj3H*S*}-%NpQpN>UADWiCR)bc$H))xs(5yjxu%Gt$$}2)p+Mz z$QcB#ipL{j^))9MB*f>gtRAeJ|I-kmzppP29j2=lWqH%c_+iDU<|AqCcFO;2c%EU} z2#1qsTbkX}7-*$y)(l<d<N2aZ-`2{^dA6@U_`tg2|7*F>_oR~<N&pqdkSgn*cxg}U z8V*tLib6*YgQA}ttj&&s33lyCZjL!pML5aO``P0+bd$Ym;=COrU)k!tf2qE`C%rM% zKuQhcDR&xZsfG~#=ZBn1lFfDYU-yo%#Dl#iin;YADuFH&H>)owmyKrIlfdT<_XW?( zoM%D*^W#nTU+2<^q{!m4cGIO9dRHrtyY*q+vpXzp*n$!-zlP=D0ZW$2{lOUL(WE~~ z=qxMTffwVl<Mq0s?SLz-gF#GP7H_Sd#l241*wyTh*tv85?XV~GJ^6fQI)=8o-)fT` zrb~J42^$0Q1Tx){Q2dp<A-FXRYA5&`-Hr+OMUx4l&Uax%BA7;I<gbYxKMP8!nw!@7 zxU}Do!Q^4``mcVH3nmyj$0s|nBk{dG5x?(MS(9(Z9_mdx5qpNau9~PmR2}WX3FF3z zAC#~F?2X<<Tr<76Zd<*Bsr!V)8A~&8>!0Pf<I|D<%Z>pry#KvGEdhisUw<@Oyhz0J zmY;<5qJ8q9$u~&lqceQ#thFkI)5hJTI{%dQ@_RfE<W-q2`3D9qrJmI9>Fh}&w$(1P zDEqZ$!%AjH)P<ST*nxRPuc5@@%S4gjCxI*KW7c-Tn$tAaG3Hm4f;B5z?YpMs1xf@9 z`I##8j6jQ!f*sF*R=WKubwf_ET0KL?w09zFBS@uI`zW<{hBtek@oj0b0&REU`R*c( zbPk;aWJSIE=}0u3i<XQbs7FM2XOLJRtMrXpyPeji+wcke4n>t}b))T8WdcD(<=nqv z=3L~2<c~URssDEH6hS0kUX|vas$>;8aW`mT!b)vsf>sr9EDMK6O(yy_I?x{ifX(o; z7US+U_uA1|Q_Hli{wFnMW%Ix1MFp)QNs36iM7scWmrjYc<>&`u`>qYWM}1{_fphAC zUAar|nFbXYXI%<kzblg3=yg`n4^2X=aK-TGC_fQ8UXjI7K!eL-|Nb@nz~lDKJ1>n7 zI~Z5UB<tG3d9aA}l{GKwkK}yJmlOMOg(~>6F!Q}~@lVY?Il8CU-3JLrX`6$(Hfil6 zfCQYU_&NWs&?UV%wqPf>UEI;x@22VhY5wP56axeh&t;xXTt=ex38amTDr`xmeQiY$ zq_>D_J%1T}cxw98&!5+?$9PKM0gwj>4TN_tK70#=RPd?{Ck-WJr{q)Ci5E|8HI>w_ zleFLqw~RZhFni<v{yAtMUZA1IE#A2fXcODxa}k}>Yk99`D1iCfN`s@v{g}vgQ0}&h z%Zd#9+wMUQ4G21tBB842u=ty*w`u5;rT*#jsK`lnnJxbNmyI<vKf*&0)`oGO<L9x4 zWeaVu+^pv8;r0Ez<58XCovau0QJHf16W*mXyyE$fZB<U2v4&i0f!o&qA{>58pPs;` z`}w>teSu0<`clC3@1WbWPH3p#vxcl7Ybp%QQu|Kq6Xr!k(D;i)eJy?bbp=C$EK+Av zJv;BSgO`)`Ek(^2bP@YMJ5_5o2ejy%A|>?Qytqqo{ChiRH1f`6d{+*!A6c8s&t8y~ zcSzYB>Wxmi-Yb<FI?bVY8n)-7!f&IjyF}wvT%|EUXdeo@=B%QPD%+JM&+~fmTrxm) z+W!@fmbq$+X34@(XrrN`#%AqTW@yy!@$P+zWkGlSqLs+F#^HWXg$o#S)stylzna^N zMv{pJD!DfgZAfn#R6K<IW;%Rvy~VHk38bPLTsRmPd)5mbjH~swR131@7s}4JSJkL< zvwG0LhKl`+!j^A*R8Vy)d(@zK9HQcpoEFYV@!$h0+S7vAkHGIwTf1Jcv-)Q45u(~M zex-RgItADH48!R?eIL;oF>HF;xBuFjAv3vevJTap%$oRAzs3J`cS{C)j*in8Nd*Nk zEKp1D1Ig?<6RcnNvpg!>QUCP8coQNNZN4QVoYVmD=4o>mn3h>yD1VvjAE&V(V5nN* zd&E)Jtgkf-W7A=6RI)u%u8T0|hy5`7KNPpJ!da0-a|Z;_=;kC|?uB`bTVN<|-C~KO zxGWRBYIg0os+HDE6VJA2YnzC9g!6PCQPo~%r2OXD*nrBL)@iHnZMR)}g(vNVeozU4 zTnt>Xqzcy(^7d#xSlPYI3czpB$4CW#z{s*R<@0G&sg6b5Gipw5ybPJUsLChEC&}9? zbm^-@Y^3qCOJgD+4fdbtc*|h@;?{{E6>s+J+0qMQjOms=AXb~MAoPxvhVkQvF&j+& z28*JZ3FTB~OI>oE#f4RUKCukY@?eqCHX5<g-EoHk%KdehSiwzEtaplxH{*uO*v7uu zaHKn{9UE~LkRFbB5lWFbO(qAmSr>vU5Un5(jHalt{Fp!AQ`QlPiDw?k6~oj~e6q|3 zOmAHdJ+3C4JTpcB3r2H-K=#X^O%%d&?J|6hFyoI~uCAU{o#<~G>~p@I;df9r<~<r9 z8{oF?7`l_K`lXhC^7`1+w*jB+t0pxa5IWSEh`2QLZb!s*{e)<2xRBNl{Z^Gjh{ZLc zB2jg_u`Bop#9};q;&pp_?<BmtSDW>=J?H1Sq#t(V4Gh6r(D#_nng=isSFd(qgld5- z?T0Cx6Z!wa>!S?o;ab#bX_eTX?^?>!uU9MEi38%T1&Sr1`cw6creMt9yqJ9n+^662 zCJ5s&!`XAHp5CAaMnRM$?Z@S*Nn)T9c1RAIU<~z=kHKPhXKU^jFzEhO*0PtZKZ)pi z1w%gMV_~APcZhB6c`)?8wV+-qg-b(Yt`0wWUI&lv0!G4h(t|gwq%fk35aMPqMY*`j z6a6KD=sauqO<@fH&f+`@^!>UlWg8EBZ<Q-1?LR=gHUodmw*|>_JyUYAm5Lx+O{JsH z??if#HV5GPCjUD*RO}n&;C3?|uvTIl>rW;JbyrK-#kGqb`1bbM8t}p0F(OSsFM>j| zsemc-kP>11YL5R^)oabOrB^BO!Mp*YogehJzoV98b~7zTJhwA0?n_KwwPLf&`R-mC z9{wWaJw<<|z9OWn5`0Uct-Dz$!uIX$`Id3NzfLG~t14qz$wTh`IfbFmgdGZEE(M#o zU_xreJEZq@t6V<iUHeBDG`=9FUyH}?#&xwULKKNr`EneE?z)zz{anxTUq@S-#zar+ zswjKL>6LG!akW%iQpEFIC<x`DpU9)zIsav|pW!^WgW|5C=@MUQ=xs(HSz1Ku*%+W^ zH8Q-UeCDJz85*`*EEfmG)rk2W!Esg@3c>S;SBpD@WYswUv_y}j1IA-q#o*08NM(6` zT7Yucs-vN^R_I`PGh+}G73^qq(Ymh?JSS?ph&GN=a3pm=Xq9Sc1o8CE9Ch#AO8W9K zc<60zL|qz_LHrC{=%_d^L8Mu!AR_52no0gjHs*d^zl2b2Eq8IR%E#&Zdv_L32hZGH zLo}<57piXz%vEbn)fWl!UYsaAv>zKNuJ}S<Dgq-%#7C9+aLe;CdT-vSL;sGf`?c_6 z7Li1#k>(_&CiGD>>@i%c%zj3I$jk#&Y^Kx0e`&+{!?di?mMAD{j{gD9Gx{v8e8lt; z<-k!Sq<<ZP#=Y9#8YoorRj*g?>bE^V+HJ^1Ld%ye@*e9CFDEHJs^Kl`j~(VVwBxjY zRrfykD1drg?P92k%n4DDbtSCtwgqWPqM`RL(H&5xEET#RZ(@zf6AzHM$VE3frx!25 z)x>{Kzw!+G@$63k&J7xPnExIq^7?G9TiIpzGfJ;O*uEUx!BwmYoOduha(`q`W*LhY z@vqX@HVo3A>av}0&iVWI_S44-@rP4&*x7e0eHZof(1uTi%RErb6i`K2PkoH=abm7{ z*A#QHsm!a>YiLS@;ztQt@$GmYP%PL?(*p*ZdPR8{PcgpVp~9P`A^g%@4W7{8cuo=< z#YyGfu}-`9`~Ktn-K72IEEkHfhnZe8uFW#<J`Xt7alb5v1e%(|-IJnQlG|M6%=h*@ zSJxG9<KFd;#~kwc)GY_wzslBWpZZLYK9}h3?Wx~8Q0CO|bJzcP;Bgv5i%D0di@}n3 zHw2jRp0-8td41ZpK0W=9oAUZ(LHpp}^QXt_5oZJ6e+IHY7WW~C{TbbA-;L3iknZPH z`nKwF+w?WJ{%a-E(?!m`7r*D*vfgW%vn%X6+to~+>xrG38)dCNTPp=_bpb7r#xIyh zW9hqDJ5$&kVi)>z+~wF|+`nK)&-J`SFLJ`w7k7ErOcjqGco;2ZQe~qwQX>vm&|@^g z#_F|u$-i-~^RNykN$53Y50jcY{Uh!DxF>%4J5yUW)Gn}}v^?v3s`0aQA5S&dx|;{T zh2L<py3%`?vWyFc6yDw!;r|>OLjIYdmuH<<OW+WIU2G_*>{ZR-oV)mb-}=JoX_P03 zB*E4g^uUiHP@qeJPkXvnub3=Kxb{R|f3~vG^dNOY`n(Bk4c$w98Uk3PLA$+!PZ=!v zT1j#WvxX{_sj809yJ^o({L@Aiz4?RQ+g?VWo<zHT6WhGyjk~UP+Onwo1bLeyML3;k zAk@z4kZU;2FNpDsr_ZjB3Q75mvzHPu4;kA(0n}>_azB5+s@^L-`;uuKyAvf~dpvVN zL)WZ?&E8$Gd2uhUzWA@+jzYAjOr_o1K}j;hKM$&&{Ubd)I4x0u%X8aPI#}Al__NL< znBgTIrcI|`zfz~eNm^k>$tX<d)<-U8*kwLE+ZNv77MgVMx9iW0TT-G9LkCR>Wp)|! z*-B&KQpdWQS6>YbH|r@TJ>?b(>8>X^8Sr{A<+kg9lNE$6cg#yM*3oy=Joh^LD6O`U z)-3)YnDg^|#sZxDa;LQ~yQ~RykQfkX#Vw7dt8n8XyoR`a`Nq4V;rTsS&-~|Fi5*)3 zj`IHXvp1{v2L@f?Zl)RHr>i}->-~N&=mi={i@6w;6Ftfu^@ygX{$(sMeA)$E(RC=p zX()t<x1hAt`1ttP#J%lu<;Umt5tcx5I)>kyg?f$6%U#XQm-Z8~Yfo!6;;yeQ7;rf6 zOfen@43`UIBsD!tdh<WGLihuN+~`as%HeZL=R1q*6f<ZS&3MS0bGd;BD?0ebe`_h= z9`HAjWlj(p^E(`i!bGXPY=r+Ot$k}{xtQFDJ{a<I2-PaCzB%^VObNepEm)T?E$Q?W zQY6-}%pes7IY6J;dfkCE+&^S%_&>ofr}C&2=18aRN0NF*%zR(23Fq{_jQ_d6o8RI! zp5J<oO>gL3^=WSus7DZo)C-bW{GUKySlxGuqi}?Inwyld<80keu3Lb-JRt9l_sMM= z26yac<7L#`Sjfpaz{C$c;r=uO>r@+PI&;L|wR8M;*eq)4m3bNVf_M0+Xet*-=pBuf z`X4$Q*%Cl$8@h1<A$*4t24>(0l?;sO{{dY5IcE&DN~i6Io@%DfeV!1Y62}jkfL6vV zu}JKqruUo=OxAh`+CshjB7fb?w2-;?3SfLnKEp&^zBpJcocY?=1oYKm3X*WpjP1k% z)^c!nIz+tg{ai8wik<(lQ0{#<H&bzk>3w0y2kKS<gg}R%-zqQ1f>q+KFL6~LL*ZLc zbUK#M40s6oADwe+Roahn*7rD@y8`w*JCg_T@j8=pyJ_h4{Nm-t@a|AEAb^$Q{|;*M zi&ROp1!A$&V^3#p4pWOLK<oP*EN?#%p~8maW4?SMrB=(;3iu=Gp84N}kpDn<&^L0w zTYj7!+L)qJ2ef>zDeCP^SM$^b&vTZVVbLUgaU#Ew917|G+(8L96-W&Q>A$_Kr}KUc z_w~+G(;y_tE@}qq={`Q>xumQhxn&?kM}DtfjSq3JlhCwo4*$PGn0`uAhi#xNMR>`6 zJ)Ia(EGcO%3JkDX)wcHjzP0`KY$($(>lrCV2g&v?ThLIDZ+mLOA1Q%w&5!o~A@fUN zygh<C`1&P=H?C9sMW3GBiH$}y^ln3z>}-jvOuffp*4O{5Ii8F`uiw}7`a-73QF*|J zboTt^fgjaJ-y{#nq(_3)lihavDSDe_J}Swkn1Y$&6-@t&ZFaKrHR0}=_|5JXyu+`d z{|Selt}nL#{%`hJo(lBu+RFi2FeqsULX_P1_yq{tapUhTc@_MBuXO(ZS-K+@qG0S} zX~kFWGu%RnZRrF5f8FWe!~^Nxlwz-0>>bd*DfpUxvoxJ}(@5tTStF{L$NvTMa>axQ zbXo(y*@HWS2=s3SJho9>^PeE-h~9Sj<Pb*`FuP<pMngx)JbCp(gH!WABe5A-g%9&= znDg|5v|5q3IUFnr8)$1Pi~rh7{M)UuQ7W+t_B3aD{yBSr`#pO7?wkrQK6qocD$r}+ zctiIpd_De4@mpkjcskoqCt~9w18Znr@cNZRXuPuRv&6Z>h7(`whglzZ0HTULtKG!> zy-_+=A2VHrXXlGK@!PybTR?a|Wpy|j{n_P&^b>>UTmflS)_(`yCng_|zrLzgr1h$@ zzju!D*UFzQnCXcMsm}ndUpKztP5#Olf(=-IQSD^3p7SKKi39%d#w^l>3@t4a;=r|m z_Osb)jXjHauNxFNs0jU9w|pOxk+by@{k0NV7N_?$Db~gCQ|4-%qKJg~l9!7+$v>W* z@U8184~(9uWZKSX8fJKMIXjgn@c(eXcgC0?Zv0>u?09#P^i$OQ$lvJeXG)nC?wr@J z$)nubRs>%yGV_gUFI9Ax-FcMyDjr;Aj*=*@e7bw|4+>ofo>O2h@|S4!(uHHPA9>sE z<P;!-y4=8Ow;jj3mZRlgylcIN@ZQxsmx*_(D3(%Oik+<G(q2E=_I4aro89Ec&=~;6 zUch~&iAd#%v)zA?p^sC3=&;toBl+-jr?38QygDG~T;RF*>eqd10^N$Zice_vlsnz! z!Dk(!u9gmZEv1(;c9|z*8-HHj(bpStbW7z_`X}bq@N^5k>)~QsMB>{@jxDw9wb+(W z&t7v)&2P7hshNuw55=BWrh2DMStc!8F4gZ+MV)`u8z$AspJM4Oz#F9yQdoFQ!1YfZ z951La0-t||!Wxfwc`Kae8WWvKojRDlDK1s|D0B!h4Mn?b_Qkv+!0CD$A>P~m+)tpp zNQ~06%?h2@?ttrVtO6Drj+*?3NUPxVl7qR0e-c+}zuqQG)(1Jb9<7P4eYD;dg0);d zJP#NVhhG1PKMh@|3y$~Awby0HwSNB6f^R`tVrwkBRwR_!u0QvmA{I%@x@Tv;2Umwr zr?>5Y;M;L<3eiVq%m|4lX}7W#Mjmh~_23(_t5tiyai)Jg-JB+Vo$RkWLsd=yQ02oa z1p9>K(akrF8DzaQh|X~3CoiRl_loiE-|9b^<!}_a{L@*D^^G{T@f0F4p+ls8+EIM7 zA+n4@%U0VvF-bRlz4CQ@_)l)Ex3VOfM_g#bwP5^CG6fRf_)u5=FY~<@IJ?hZV^_!1 zKYJ>sB^>K4$O!FfI0eRn$&YHIIN3YjOq2@v>Tcbj#n1P`#mAhrF<;8L{aT^7j}+_P zAEyjh(lC~dY~pOU{SRwidBgJ(hLj7GxJ0>g{AI7|PusP+MFq3|=fRR{!C^~+!}yHm zl*3hZ@I~Kk1;_D-%Hhecp=*A=homNg(A)`ooPs~yl-C6)>OB0(i}sz8*v;hk{~*eZ zk?C!N(_hVrxN~sBNj?jVy1vgGb5zI<$7{Nupeycqvax2cm#5Qln94m^Gpo$2&S3q+ z)hw8Ns{LQ@-PaT1!W{c?kPiZb!#l%a6HllTmgx;DOHbNjNDp#Gt_@6GPx|MP;fAyu zraao~I}fVH?3~XM2pugIZwB&Idsbo57sV((t}BwVv`wt-(gnNYxYWf_greHqh>2%g z4b#~xM|$aF-_i~WJ^A`HFU>LChr^*G*1i80LPdm%;+K5*?V$X}k+zrf&DZELss!<? zxgU|k-%MJ*FwERde=V?C6n33<#BMMwuDu?|BJ7PS%ZZRG{Rd=M)fCz`-OlD4RlMk) z2{WUU@N5!#*ZQM8@Yd(G>~Ybf_w1R)s-51<FOWtus2ndS>+zId_wBsO5byhU`{wZK z14V5;`mzq3D7$=emSto2?u#E|k|z=ZKD(Q$*#;@c=C?Cc2@<`DMaF4@o@H)c(*cB1 zGl{0cwa^>h*pTP3A7)9e-SlRw)yG!_Zv8bs!19j3bG-q4K>?#6@u1l6DidP7#9y*D zuN?sIJGC06<F_IBl!lWr6Q6ICu>w)`FS5S|v+7Bv9mt}qw%c%J!xs%R?>Y@!&J<{Z zvbMa?Ej#>Pwj8$A1VpUqG&6Kthd*GC1{=*GW9p>WRgX3#u4-v$mEl5THn`X=rL(YF zrCb*OtgY+VTalsqvPWtN(9LdYArnO-p`PDOxWrJXWN>$-omTC9Ylb{Y$6Yuq^4E-` ztgsO4o<YV%H)kB$sgCvC)Qs3ks&K<zuy`{F+*r0N`~KbShDzr67FlJYNf=D78>COH zpJs%Yl3n7Qe3wSDQS?g@4JQE>XvOvpEFaU~q=wgoR*u7#Xw=qcTn#CSDEMM<*<<GY zRgmD^5{jbYfaVZDU?dL^AUklx)C`5ASY|jKga`p5EGF%fvXPVq-F#$TC_K-TLizqb Df?*ZT
new file mode 100755 index 0000000000000000000000000000000000000000..8f1ae84942c80bf7d389e8e3bbc505222ab13df1 GIT binary patch literal 24794 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 YrmUnmE@YW2)AsMm1-<jR=PZK%0|Q?C{Qv*}
new file mode 100755 index 0000000000000000000000000000000000000000..4ea78c63c5b7a12557daa52c7ed06e0723ff4613 GIT binary patch literal 5332 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
new file mode 100755 index 0000000000000000000000000000000000000000..06de4cf8fff9b8a8e74679802bf396baebdb110d GIT binary patch literal 13008 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
new file mode 100755 index 0000000000000000000000000000000000000000..a443b7e054d71c9120a56ac2ff36253053c381c1 GIT binary patch literal 14327 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
new file mode 100755 index 0000000000000000000000000000000000000000..3cf5e8fea3758c0b5a7f101a1f93e6cb3e813c52 GIT binary patch literal 13754 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 b0YCtH##<Ti0e~0a;`93D+ZQ>KNU#3`DhE%d
new file mode 100755 index 0000000000000000000000000000000000000000..c9658c727e30a0278afdab266b7fb833b02baba0 GIT binary patch literal 14931 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 DDl5iw
new file mode 100755 index 0000000000000000000000000000000000000000..0132fb753e79d4dce0fb8fe8c14f1c8c506277c1 GIT binary patch literal 13497 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 I4>2D94_ZKbZ2$lO
new file mode 100755 index 0000000000000000000000000000000000000000..25ab16174c52fcc8f45f80f29428687214570a3e GIT binary patch literal 11198 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 UJ3qV?Bsp9T9y{>K5ts140Nz{d;Q#;t
new file mode 100644 --- /dev/null +++ b/doc/interpreter/java.txi @@ -0,0 +1,1705 @@ +@c Copyright (C) 2010-2012 Martin Hepperle +@c +@c This file is part of Octave. +@c +@c Octave is free software; you can redistribute it and/or modify it +@c under the terms of the GNU General Public License as published by the +@c Free Software Foundation; either version 3 of the License, or (at +@c your option) any later version. +@c +@c Octave is distributed in the hope that it will be useful, but WITHOUT +@c ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +@c FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +@c for more details. +@c +@c You should have received a copy of the GNU General Public License +@c along with Octave; see the file COPYING. If not, see +@c <http://www.gnu.org/licenses/>. + +@node Java Interface +@chapter Java Interface + +@cindex using Octave with Java +@cindex Java, using with Octave +@cindex calling Java from Octave +@cindex Java, calling from Octave +@cindex calling Octave from Java +@cindex Octave, calling from Java + +The @code{java} package is designed for calling Java from Octave. +If you want to call Octave from Java, you might want to use a library like +@code{javaOctave} (@url{http://kenai.com/projects/javaOctave}) or +@code{joPas} (@url{http://jopas.sourceforge.net}). + +@menu +* Available Functions:: +* FAQ - Frequently asked Questions:: +@end menu + +@node Available Functions +@section Available Functions + +@menu +* javaclasspath:: +* javaaddpath:: +* javarmpath:: +* javamem:: +* javaArray:: +* javaObject:: +* java_new:: +* javaMethod:: +* java_invoke:: +* java_get:: +* java_set:: +* javamethods:: +* javafields:: +* msgbox:: +* errordlg:: +* helpdlg:: +* inputdlg:: +* listdlg:: +* questdlg:: +* warndlg:: +@end menu + +@node javaclasspath +@subsection javaclasspath +@findex javaclasspath +@anchor{doc-javaclasspath} +@c - index - +@cindex classpath, displaying +@cindex classpath, dynamic +@cindex dynamic classpath +@cindex classpath, static +@cindex static classpath +@c - index - + +@deftypefn {Function file} {} javaclasspath +@deftypefnx {Function file} {@var{STATIC} =} javaclasspath +@deftypefnx {Function file} {[@var{STATIC}, @var{DYNAMIC}] =} javaclasspath +@deftypefnx {Function file} {@var{PATH} =} javaclasspath (@var{WHAT}) + +Return the class path of the Java virtual machine as a cell array of strings. + +If called without an input parameter: +@itemize +@item If no output variable is given, the result is simply printed +to the standard output. +@item If one output variable @var{STATIC} is given, the result is +the static classpath. +@item If two output variables @var{STATIC} and @var{DYNAMIC} are +given, the first variable will contain the static classpath, +the second will be filled with the dynamic claspath. +@end itemize + +If called with a single input parameter @var{WHAT}: +@itemize +If no output parameter is given: +@item The result is printed to the standard output similar to the call without input parameter.@* +If the output parameter @var{PATH} is used: +@item If @var{WHAT} is '-static' the static classpath is returned. +@item If @var{WHAT} is '-dynamic' the dynamic classpath is returned. +@item If @var{WHAT} is '-all' the static and the dynamic classpath +are returned in a single cell array. +@end itemize + +For the example two entries have been added to the static classpath using the file @code{classpath.txt}. + +Example: +@example +Octave > javaclasspath('-all') + STATIC JAVA PATH + + z:/someclasses.jar + z:/classdir/classfiles + + DYNAMIC JAVA PATH + - empty - + +Octave > javaaddpath('z:/dynamic'); +Octave > ps = javaclasspath('-all') +ps = +@{ + [1,1] = z:/someclasses.jar + [1,2] = z:/classdir/classfiles + [1,3] = z:/dynamic +@} +@end example + +@seealso{@ref{doc-javaaddpath,,javaaddpath}, + @ref{doc-javarmpath,,javarmpath}, + @ref{doc-FAQ,,How to make Java classes available to Octave?}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node javaaddpath +@subsection javaaddpath +@anchor{doc-javaaddpath} +@c - index - +@findex javaaddpath +@cindex classpath, adding new path +@cindex path, adding to classpath +@cindex classpath, dynamic +@cindex dynamic classpath, adding new path +@c - index - + +@deftypefn {Function File} {} javaaddpath (@var{PATH}) + +Add @var{PATH} to the dynamic class path of the Java virtual machine. @var{PATH} can be either a directory where .class files can be found, or a .jar file containing Java classes. In both cases the directory or file must exist. + +Example: + +This example adds a Java archive and a directory containing @var{.class} files to the @var{classpath} and displays the current @var{classpath} list. + +@example +Octave > javaaddpath('C:/java/myclasses.jar'); +Octave > javaaddpath('C:/java/classes'); +Octave > javaclasspath; +ans = +@{ + [1,1] = C:\java\myclasses.jar + [1,2] = C:\java\classes +@} +@end example +@seealso{@ref{doc-javaclasspath,,javaclasspath}, @ref{doc-javarmpath,,javarmpath}, + @ref{doc-FAQ,,How to make Java classes available to Octave?}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node javarmpath +@subsection javarmpath +@anchor{doc-javarmpath} +@c - index - +@cindex classpath, removing path +@cindex path, removing from classpath +@c - index - + +@deftypefn {Function File} {} javarmpath (@var{PATH}) +Remove @var{PATH} from the dynamic class path of the Java virtual machine. @var{PATH} can be either a directory where .class files can be found, or a .jar file containing Java classes. + +Example: This example removes one of the directories added in the example for the @code{javaaddpath} function. + +@example +Octave > javarmpath('C:/java/classes'); +Octave > javaclasspath +@{ + [1,1] = C:\java\myclasses.jar +@} +@end example + +@seealso{@ref{doc-javaaddpath,,javaaddpath}, @ref{doc-javaclasspath,,javaclasspath}, + @ref{doc-FAQ,,How to make Java classes available to Octave?}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node javamem +@subsection javamem +@anchor{doc-javamem} +@c - index - +@cindex memory, displaying Java memory status +@c - index - + +@deftypefn {Function File} {} javamem +@deftypefnx {Function File} {[@var{JMEM}] =} javamem + +Show current memory status of the java virtual machine (JVM) +& run garbage collector. + +When no return argument is given the info is echoed to the screen. +Otherwise, cell array @var{JMEM} contains @var{Maximum}, @var{Total}, and +@var{Free} memory (in bytes). + +All java-based routines are run in the JVM's shared memory pool, +a dedicated and separate part of memory claimed by the JVM from +your computer's total memory (which comprises physical RAM and +virtual memory / swap space on hard disk). + +The maximum available memory can be set using the file @code{java.opts} +(in the same subdirectory where @code{javaaddpath.m} lives, see +@samp{which javaaddpath}. Usually that is: @* +[/usr]/share/Octave/packages/java-1.2.8. + +@code{java.opts} is a plain text file. It can contain memory related +options, starting with @code{-X}. +In the following exmaple, the first line specifies the initial +memory size in megabytes, the second line specifies the requested +maximum size: +@example +-Xms64m +-Xmx512m +@end example +You can adapt these values if your system has limited available +physical memory. When no @code{java.opts} file is present, the default +assignments are depending on system hardware and Java version. +Typically these are an initial memory size of @math{RAM/64} and +a maximum memory size of @math{min(RAM/4, 1GB)}, where @var{RAM} +is the amount of installed memory. + +In the output of javamem @var{Total memory} is what the operating +system has currently assigned to the JVM and depends on actual +and active memory usage. +@var{Free memory} is self-explanatory. During operation of java-based +Octave functions the amounts of Total and Free memory will vary, +due to java's own cleaning up and your operating system's memory +management. + +Example: +@example +Octave > javamem +Java virtual machine (JVM) memory info: +Maximum available memory: 247 MB; + (...running garbage collector...) +OK, current status: +Total memory in virtual machine: 15 MB; +Free memory in virtual machine: 15 MB; +2 CPUs available. + +Octave > [MEM] = javamem() +MEM = +@{ + [1,1] = 259522560 + [2,1] = 16318464 + [3,1] = 16085576 +@} +@end example + +@seealso{@ref{doc-FAQ,,How can I handle memory limitations?}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node javaArray +@subsection javaArray +@anchor{doc-javaArray} +@c - index - +@cindex array, creating a Java array +@c - index - + +@deftypefn {Function File} {ARRAY =} javaArray (@var{CLASS}, [@var{M}, @var{N}, ...]) +@deftypefnx {Function File} {ARRAY =} javaArray (@var{CLASS}, @var{M}, @var{N}, ...) + +Create a Java array of size @code{[M, N, ...]} with elements of class @var{CLASS}. @var{CLASS} can be a Java object representing a class or a string containing the fully qualified class name. +The generated array is uninitialized, all elements are set to null if @var{CLASS} is a reference type, or to a default value (usually 0) if @var{CLASS} is a primitive type. + +Example: This example creates a (2 x 2) array of Java @var{String} objects and assigns a value to one of the elements. Finally it displays the type of @var{a}. +@example +Octave > a = javaArray('java.lang.String', 2, 2); +Octave > a(1,1) = 'Hello'; +Octave > a +a = +<Java object: java.lang.String[][]> +@end example +@end deftypefn + +@c ------------------------------------------------------------------------ +@node javaObject +@subsection javaObject +@anchor{doc-javaObject} +@c - index - +@cindex object, creating a Java object +@c - index - + +@deftypefn {Function File} {OBJECT =} javaObject (@var{CLASS}, [@var{ARG1}, ..., @var{ARGN}]) + +Create a Java object of class @var{CLASS}, by calling the class constructor with the given arguments @var{ARG1}, ..., @var{ARGN}. The @var{CLASS} name should be given in fully qualified string form (including any package prefix). In Matlab you should avoid to use the import statement and the short form of object creation. + +Example: This example demonstrates two ways to create a Java @code{StringBuffer} object. The first variant creates an uninitialized @var{StringBuffer} object, while the second variant calls a constructor with the given initial @code{String}. Then it displays the type of @code{o}, and finally the content of the @code{StringBuffer} object is displayed by using its @code{toString} method. + +@example +Octave > o = javaObject('java.lang.StringBuffer'); +Octave > o = javaObject('java.lang.StringBuffer', 'Initial'); +Octave > o +o = +<Java object: java.lang.StringBuffer> +Octave > o.toString +ans = Initial +@end example + +Equivalent to the @code{java_new} function. +For compatibility with Matlab it is recommended to use the @code{javaObject} function. + +@seealso{@ref{doc-java_new,,java_new}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node java_new +@subsection java_new +@anchor{doc-java_new} +@c - index - +@cindex object, creating a Java object +@c - index - + +@deftypefn {Function File} {OBJECT =} java_new (@var{CLASS}, [@var{ARG1}, ..., @var{ARGN}]) + +Create a Java object of class @var{CLASS}, by calling the class constructor with the given arguments @var{ARG1}, ..., @var{ARGN}. +Equivalent to the @code{javaObject} function. +For compatibility with Matlab it is recommended to use the @code{javaObject} function. + +Example: +@example +Octave > o = java_new('java.lang.StringBuffer', 'Initial'); +Octave > o +o = +<Java object: java.lang.StringBuffer> +Octave > o.toString +ans = Initial +@end example + +@seealso{@ref{doc-javaObject,,javaObject}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node javaMethod +@subsection javaMethod +@anchor{doc-javaMethod} +@c - index - +@cindex method, invoking a method of a Java object +@c - index - + +@deftypefn {Function File} {RET =} javaMethod (@var{NAME}, @var{OBJECT}[, @var{ARG1}, ..., @var{ARGN}]) + +Invoke the method @var{NAME} on the Java object @var{OBJECT} with the arguments @var{ARG1}, ... For static methods, @var{OBJECT} can be a string representing the fully qualified name of the corresponding class. The function returns the result of the method invocation. +When @var{OBJECT} is a regular Java object, the structure-like indexing can be used as a shortcut syntax. For instance, the two statements in the example are equivalent. + +Example: +@example +Octave > ret = javaMethod("method1", x, 1.0, "a string") +Octave > ret = x.method1(1.0, "a string") +@end example + +@seealso{@ref{doc-javamethods,,javamethods}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node java_invoke +@subsection java_invoke +@anchor{doc-java_invoke} +@c - index - +@cindex method, invoking a method of a Java object +@c - index - + +@deftypefn {Function File} {RET =} java_invoke (@var{OBJECT}, @var{NAME}[, @var{ARG1}, ..., @var{ARGN}]) + +Invoke the method @var{NAME} on the Java object @var{OBJECT} with the arguments @var{ARG1}, ... For static methods, @var{OBJECT} can be a string representing the fully qualified name of the corresponding class. The function returns the result of the method invocation. Equivalent to the @code{javaMethod} function. When @var{OBJECT} is a regular Java object, the structure-like indexing can be used as a shortcut syntax. For instance, the two statements in the example are equivalent. + +Example: +@example +Octave > ret = java_invoke(x, "method1", 1.0, "a string") +Octave > ret = x.method1(1.0, "a string") +@end example + +@seealso{@ref{doc-javamethods,,javamethods}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node java_get +@subsection java_get +@anchor{doc-java_get} +@c - index - +@cindex field, returning value of Java object field +@c - index - + +@deftypefn {Function File} {VAL =} java_get (@var{OBJECT}, @var{NAME}) + +Get the value of the field @var{NAME} of the Java object @var{OBJECT}. For static fields, @var{OBJECT} can be a string representing the fully qualified name of the corresponding class. + +When @var{OBJECT} is a regular Java object, the structure-like indexing can be used as a shortcut syntax. For instance, the two statements in the example are equivalent + +Example: +@example +Octave > java_get(x, "field1") +Octave > x.field1 +@end example + +@seealso{@ref{doc-javafields,,javafields}, + @ref{doc-java_set,,java_set}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node java_set +@subsection java_set +@anchor{doc-java_set} +@c - index - +@cindex field, setting value of Java object field +@c - index - + +@deftypefn {Function File} {OBJECT =} java_set (@var{OBJECT}, @var{NAME}, @var{VALUE}) + +Set the value of the field @var{NAME} of the Java object @var{OBJECT} to @var{VALUE}. For static fields, @var{OBJECT} can be a string representing the fully qualified named of the corresponding Java class. +When @var{OBJECT} is a regular Java object, the structure-like indexing can be used as a shortcut syntax. For instance, the two statements in the example are equivalent + +Example: +@example +Octave > java_set(x, "field1", val) +Octave > x.field1 = val +@end example + +@seealso{@ref{doc-javafields,,javafields}, + @ref{doc-java_get,,java_get}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node javamethods +@subsection javamethods +@anchor{doc-javamethods} +@c - index - +@cindex methods, displaying available methods of a Java object +@c - index - + +@deftypefn {Function File} {M =} javamethods (@var{CLASSNAME}) +@deftypefnx {Function File} {M =} javamethods (@var{OBJECT}) + +Given a string with a Java class name @var{CLASSNAME} or a regular Java object @var{OBJECT}, this function returns a cell array containing descriptions of all methods of the Java class @var{CLASSNAME} respectively the class of @var{OBJECT}. + +Examples: The first example shows how the methods of a class can be queried, while the second example works with the methods of a concrete instance of a class. Note that creation of a @code{java.lang.Double} object requires an initializer (in the example the value 1.2). +@example +Octave > m = javamethods('java.lang.Double'); +Octave > size(m) +ans = + 1 30 + +Octave > m@{7@} +ans = double longBitsToDouble(long) + +Octave > o = javaObject('java.lang.Double', 1.2); +Octave > m = javamethods(o); +Octave > size(m) +ans = + 1 30 + +Octave > m@{7@} +ans = double longBitsToDouble(long) +@end example + +@seealso{@ref{doc-javafields,,javafields}, + @ref{doc-java_invoke,,java_invoke}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node javafields +@subsection javafields +@anchor{doc-javafields} +@c - index - +@cindex fields, displaying available fields of a Java object +@c - index - + +@deftypefn {Function File} {F =} javafields (@var{CLASSNAME}) +@deftypefnx {Function File} {F =} javafields (@var{OBJECT}) + +Given a string with a Java class name @var{CLASSNAME} or a regular Java object @var{OBJECT}, this function returns a cell array containing the descriptions for all fields of the Java class @var{CLASSNAME} respectively the class of @var{OBJECT}. + +Examples: + +The first example shows how the fields of a class can be queried without creating an instance of the class. +@example +Octave > f = javafields('java.lang.Double'); +Octave > size(f) +ans = + 1 10 + +Octave > f@{7@} +ans = public static final int java.lang.Double.MAX_EXPONENT +@end example + +The second example works with the fields of an instance of a class. Note that creation of a @code{java.lang.Double} object requires an initializer (in the example a value of 1.2 is specified). +@example +Octave > o = javaObject('java.lang.Double', 1.2); +Octave > f = javafields(o); +Octave > size(f) +ans = + 1 10 + +Octave > f@{7@} +ans = public static final int java.lang.Double.MAX_EXPONENT +@end example + +@seealso{@ref{doc-java_set,,java_set}, + @ref{doc-java_get,,java_get}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node msgbox +@subsection msgbox +@anchor{doc-msgbox} +@c - index - +@cindex dialog, displaying a warning dialog +@c - index - + +@deftypefn {Function File} {F =} msgbox (@var{MESSAGE}) +@deftypefnx {Function File} {F =} msgbox (@var{MESSAGE}, @var{TITLE}) +@deftypefnx {Function File} {F =} msgbox (@var{MESSAGE}, @var{TITLE}, @var{ICON}) + +Displays a @var{MESSAGE} using a dialog box. The parameter @var{TITLE} can be used to optionally decorate the dialog caption. +The third optional parameter @var{ICON} can be either @code{'error'}, @code{'help'} or @code{'warn'} +and selectes the corresponding icon. +If it is omitted, no icon is shown. + +Examples: The first example shows a dialog box without a caption text, whereas the second example specifies a caption text of its own. +The third example also demonstrates how a character +according to the @TeX{} symbol set can be specified. It is important to include a space character +after the symbol code and how to embed a newline character (ASCII code 10) into the string. + +@example +Octave > msgbox('This is an important message'); +Octave > msgbox('Do not forget to feed the cat.', 'Remember'); +Octave > msgbox(['I \heartsuit Octave!',10, ... + ' Even if I hate it sometimes.'], ... + 'I Confess','warn'); +@end example + +@c @image{java-images/image003} + +@seealso{@ref{doc-errordlg,,errordlg}, + @ref{doc-helpdlg,,helpdlg}, + @ref{doc-warndlg,,warndlg}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node errordlg +@subsection errordlg +@anchor{doc-errordlg} +@c - index - +@cindex dialog, displaying an error dialog +@c - index - + +@deftypefn {Function File} {F =} errordlg (@var{MESSAGE}) +@deftypefnx {Function File} {F =} errordlg (@var{MESSAGE}, @var{TITLE}) + +Displays the @var{MESSAGE} using an error dialog box. The @var{TITLE} can be used optionally to decorate the dialog caption instead of the default title "Error Dialog". + +Examples: The first example shows a dialog box with default caption, whereas the second example specifies a its own caption +@example +Octave > errordlg('Oops, an expected error occured'); +@end example +@c @image{java-images/image001 +@example +Octave > errordlg('Another error occured', 'Oops'); +@end example + +@seealso{@ref{doc-helpdlg,,helpdlg}, + @ref{doc-inputdlg,,inputdlg}, + @ref{doc-listdlg,,listdlg}, + @ref{doc-questdlg,,questdlg}, + @ref{doc-warndlg,,warndlg}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node helpdlg +@subsection helpdlg +@anchor{doc-helpdlg} +@c - index - +@cindex dialog, displaying a help dialog +@c - index - + +@deftypefn {Function File} {F =} helpdlg (@var{MESSAGE}) +@deftypefnx {Function File} {F =} helpdlg (@var{MESSAGE}, @var{TITLE}) + +Displays the @var{MESSAGE} using a help dialog box. The help message can consist of multiple lines, separated by a newline character. The @var{TITLE} can be used optionally to decorate the dialog caption bar instead of the default title "Help Dialog". + +Examples: The first example shows a dialog box with default caption, whereas the next two examples specify their own caption. Note that if the backslash escape notation is used in a double quoted string, it is immediately replaced by Octave with a newline. +If it is contained in a single quoted string, it is not replaced by Octave, +but later by the dialog function. + +@example +Octave > helpdlg('This is a short notice'); +Octave > helpdlg(['line #1',10,'line #2'], 'Inventory'); +Octave > helpdlg("1 eel\n9 buckazoids\n2 peas", 'Inventory'); +@end example + +@c @image{java-images/image004} + +@seealso{@ref{doc-errordlg,,errordlg}, + @ref{doc-inputdlg,,inputdlg}, + @ref{doc-listdlg,,listdlg}, + @ref{doc-questdlg,,questdlg}, + @ref{doc-warndlg,,warndlg}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node inputdlg +@subsection inputdlg +@anchor{doc-inputdlg} +@c - index - +@cindex dialog, displaying an input dialog +@c - index - + +@deftypefn {Function File} {C =} inputdlg (@var{PROMPT}) +@deftypefnx {Function File} {C =} inputdlg (@var{PROMPT}, @var{TITLE}) +@deftypefnx {Function File} {C =} inputdlg (@var{PROMPT}, @var{TITLE}, @var{ROWSCOLS}) +@deftypefnx {Function File} {C =} inputdlg (@var{PROMPT}, @var{TITLE}, @var{ROWSCOLS}, @var{DEFAULTS}) + +Returns the user's inputs from a multi-textfield dialog box in form of a cell array of strings. If the user closed the dialog with the Cancel button, en empty cell array is returned. This can be checked with the @var{isempty} function. The first argument @var{PROMPT} is mandatory. It is a cell array with strings labeling each text field. The optional string @var{TITLE} can be used as the caption of the dialog. The size of the text fields can be defined by the argument @var{ROWSCOLS}, which can be either a scalar to define the number of columns used for each text field, a vector to define the number of rows for each text field individually, or a matrix to define the number of rows and columns for each text field individually. It is possible to place default values into the text fields by supplying a cell array of strings for the argument @var{DEFAULTS}. + +Examples: The first example shows a simple usage of the input dialog box without defaults. +@example +Octave > prompt = @{'Width','Height','Depth'@}; +Octave > dims = inputdlg(prompt, 'Enter Box Dimensions'); +Octave > volume = str2num(dims@{1@}) * ... + str2num(dims@{2@}) * str2num(dims@{3@}); +@end example + +@c @image{java-images/image005} + +The second example shows the application of a scalar for the number of rows and a cell array with default values. +@example +Octave > prompt = @{'Width', 'Height', 'Depth'@}; +Octave > defaults = @{'1.1', '2.2', '3.3'@}; +Octave > title = 'Enter Box Dimensions'; +Octave > dims = inputdlg(prompt, title, 1, defaults); +Octave > dims +dims = +@{ + [1,1] = 1.1 + [2,1] = 2.2 + [3,1] = 3.3 +@} +@end example + +@c @image{java-images/image006} + +The third example shows the application of row height and column width specification.. +@example +Octave > prompt = @{'Width', 'Height', 'Depth'@}; +Octave > defaults = @{'1.1', '2.2', '3.3'@}; +Octave > rc = [1,10; 2,20; 3,30]; +Octave > title = 'Enter Box Dimensions'; +Octave > dims = inputdlg(prompt, title, rc, defaults); +@end example + +@c @image{java-images/image007} + +@seealso{@ref{doc-errordlg,,errordlg}, + @ref{doc-helpdlg,,helpdlg}, + @ref{doc-listdlg,,listdlg}, + @ref{doc-questdlg,,questdlg}, + @ref{doc-warndlg,,warndlg}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node listdlg +@subsection listdlg +@anchor{doc-listdlg} +@c - index - +@cindex dialog, displaying a list dialog +@c - index - + +@deftypefn {Function File} {[SEL, OK] =} listdlg (@var{KEY}, @var{VALUE}[, @var{KEY}, @var{VALUE}, ...]) + +This function returns the inputs from a list dialog box. The result is returned as a vector of indices and a flag. The vector @var{SEL} contains the 1-based indices of all list items selected by the user. The flag @var{OK} is 1 if the user closed the dialog with the OK Button, otherwise it is 0 and @var{SEL} is empty.. The arguments of this function are specified in the form of @var{KEY}, @var{VALUE} pairs. At least the @code{'ListString'} argument pair must be specified. It is also possible to preselect items in the list in order to provide a default selection. + +The @var{KEY} and @var{VALUE} pairs can be selected from the following list: + +@table @code +@item ListString +a cell array of strings comprising the content of the list. +@item SelectionMode +can be either @code{'single'} or @code{'multiple'}. +@item ListSize +a vector with two elements @code{[width, height]} defining the size of the list field in pixels. +@item InitialValue +a vector containing 1-based indices of preselected elements. +@item Name +a string to be used as the dialog caption. +@item PromptString +a cell array of strings to be displayed above the list field. +@item OKString +a string used to label the OK button. +@item CancelString +a string used to label the Cancel button. +@end table + +Example: +@example +Octave > [s,ok] = listdlg('ListString', ... + @{'An item', 'another', 'yet another'@}, ... + 'Name', 'Selection Dialog', ... + 'SelectionMode', 'Multiple', ... + 'PromptString',['Select an item...',10,'...or multiple items']); + +Octave > imax = length(s); +Octave > for i=1:1:imax +Octave > disp(s(i)); +Octave > end +@end example + +@c @image{java-images/image002} + +@seealso{@ref{doc-errordlg,,errordlg}, + @ref{doc-helpdlg,,helpdlg}, + @ref{doc-inputdlg,,inputdlg}, + @ref{doc-questdlg,,questdlg}, + @ref{doc-warndlg,,warndlg}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node questdlg +@subsection questdlg +@anchor{doc-questdlg} +@c - index - +@cindex dialog, displaying a question dialog +@c - index - + +@deftypefn {Function File} {C =} questdlg (@var{MESSAGE}, @var{TITLE}) +@deftypefnx {Function File} {C =} questdlg (@var{MESSAGE}, @var{TITLE}, @var{DEFAULT}) +@deftypefnx {Function File} {C =} questdlg (@var{MESSAGE}, @var{TITLE}, @var{BTN1}, @var{BTN2}, @var{DEFAULT}) +@deftypefnx {Function File} {C =} questdlg (@var{MESSAGE}, @var{TITLE}, @var{BTN1}, @var{BTN2}, @var{BTN3}, @var{DEFAULT}) + +Displays the @var{MESSAGE} using a question dialog box with a caption @var{TITLE}. The dialog contains two or three buttons which all close the dialog. It returns the caption of the activated button. + +If only @var{MESSAGE} and @var{TITLE} are specified, three buttons with the default captions "Yes", +"No", "Cancel" are used. +The string @var{DEFAULT} identifies the default button, which is activated by pressing the ENTER key. It must match one of the strings given in @var{BTN1}, @var{BTN2} or @var{BTN3}. If only two button captions @var{BTN1} and @var{BTN2} are specified, the dialog will have only these two buttons. + + +Examples: The first example shows a dialog box with two buttons, whereas the next example demonstrates the use of three buttons. +@example +Octave > questdlg('Select your gender', 'Sex', ... + 'Male', 'Female', 'Female'); +@end example + +@c @image{java-images/image008} + +@example +Octave > questdlg('Select your gender', 'Sex', ... + 'Male', 'dont know', 'Female', 'Female'); +@end example + +@c @image{java-images/image009} + +@seealso{@ref{doc-errordlg,,errordlg}, + @ref{doc-helpdlg,,helpdlg}, + @ref{doc-inputdlg,,inputdlg}, + @ref{doc-listdlg,,listdlg}, + @ref{doc-warndlg,,warndlg}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node warndlg +@subsection warndlg +@anchor{doc-warndlg} +@c - index - +@cindex dialog, displaying a warning dialog +@c - index - + +@deftypefn {Function File} {F =} warndlg (@var{MESSAGE}) +@deftypefnx {Function File} {F =} warndlg (@var{MESSAGE}, @var{TITLE}) + +Displays a @var{MESSAGE} using a warning dialog box. The @var{TITLE} can be used optionally to decorate the dialog caption instead of the default title "Warning Dialog". + +Examples: The first example shows a dialog box with default caption, whereas the second example specifies a caption text of its own. The second example also demonstrates how a character +according to the @TeX{} symbol set can be specified. It is important to include a space character +after the symbol code. The \n character can be used to start a new line. +The third example shows an alternate way to embed the newline character (the newline character has the ASCII code 10) into the string. +Please refer to the Octave manual for the difference between single and double quoted +strings. + +@example +Octave > warndlg('An expected warning occured'); +Octave > warndlg('I \heartsuit Octave!\nEven if I hate her sometimes.', ... + 'Confession'); +Octave > warndlg(['I \heartsuit Octave!',10, ... + ' Even if I hate her sometimes.'], ... + 'I Confess'); +@end example + +@c @image{java-images/image003} + +@seealso{@ref{doc-errordlg,,errordlg}, + @ref{doc-helpdlg,,helpdlg}, + @ref{doc-inputdlg,,inputdlg}, + @ref{doc-listdlg,,listdlg}, + @ref{doc-questdlg,,questdlg}} +@end deftypefn + +@c ------------------------------------------------------------------------ +@node FAQ - Frequently asked Questions +@section FAQ - Frequently asked Questions + +@menu +* How to distinguish between Octave and Matlab?:: +* How to make Java classes available?:: +* How to create an instance of a Java class?:: +* How can I handle memory limitations?:: +* How to compile the java package in Octave?:: +* Which @TeX{} symbols are implemented in the dialog functions?:: +@end menu + +@c ------------------------------------------------------------------------ +@node How to distinguish between Octave and Matlab? +@subsection How to distinguish between Octave and Matlab? +@anchor{doc-FAQ} +@c - index - +@cindex Octave and Matlab, how to distinguish between +@c - index - + +Octave and Matlab are very similar, but handle Java slightly different. Therefore it may be necessary to detect the environment and use the appropriate functions. The following function can be used to detect the environment. Due to the persistent variable it can be called repeatedly without a heavy performance hit. + +Example: +@example +%% +%% Return: true if the environment is Octave. +%% +function ret = isOctave + persistent retval; % speeds up repeated calls + + if isempty(retval) + retval = (exist('Octave_VERSION','builtin') > 0); + end + + ret = retval; +end +@end example + +@c ------------------------------------------------------------------------ +@node How to make Java classes available? +@subsection How to make Java classes available to Octave? +@c - index - +@cindex classpath, setting +@cindex classpath, difference between static and dynamic +@cindex static classpath +@cindex dynamic classpath +@cindex @code{classpath.txt} +@cindex classes, making available to Octave +@c - index - + +Java finds classes by searching a @var{classpath}. This is a list of Java archive files and/or directories containing class files. +In Octave and Matlab the @var{classpath} is composed of two parts: +@itemize +@item the @var{static classpath} is initialized once at startup of the JVM, and +@item the @var{dynamic classpath} which can be modified at runtime. +@end itemize +Octave searches the @var{static classpath} first, then the @var{dynamic classpath}. +Classes appearing in the @var{static} as well as in the @var{dynamic classpath} will therefore be found in the @var{static classpath} and loaded from this location. +@* +Classes which shall be used regularly or must be available to all users should be +added to the @var{static classpath}. +The @var{static classpath} is populated once from the contents of a plain text file named @code{classpath.txt} when the Java Virtual Machine starts. This file contains one line for each individual classpath to be added to the @var{static classpath}. +These lines can identify single class files, directories containing class files or Java archives with complete class file hierarchies. +Comment lines starting with a @code{#} or a @code{%} character are ignored. + +The search rules for the file @code{classpath.txt} are: +@itemize +@item First, Octave searches for the file @code{classpath.txt} in your home directory, +If such a file is found, it is read and defines the initial @var{static classpath}. +Thus it is possible to build an initial static classpath on a 'per user' basis. + +@item Next, Octave looks for another file @code{classpath.txt} in the package installation directory. +This is where @code{javaclasspath.m} resides, usually something like @code{...\share\Octave\packages\java-1.2.8}. +You can find this directory by executing the command +@example +pkg list +@end example +If this file exists, its contents is also appended to the static classpath. +Note that the archives and class directories defined in this file will affect all users. +@end itemize + +Classes which are used only by a specific script should be placed in the @var{dynamic classpath}. This portion of the classpath can be modified at runtime using the @code{javaaddpath} and @code{javarmpath} functions. + +Example: +@example +Octave > base_path = 'C:/Octave/java_files'; + +Octave > % add two JARchives to the dynamic classpath +Octave > javaaddpath([base_path, '/someclasses.jar']); +Octave > javaaddpath([base_path, '/moreclasses.jar']); + +Octave > % check the dynamic classpath +Octave > p = javaclasspath; +Octave > disp(p@{1@}); +C:/Octave/java_files/someclasses.jar +Octave > disp(p@{2@}); +C:/Octave/java_files/moreclasses.jar + +Octave > % remove the first element from the classpath +Octave > javarmpath([base_path, '/someclasses.jar']); +Octave > p = javaclasspath; +Octave > disp(p@{1@}); +C:/Octave/java_files/moreclasses.jar + +Octave > % provoke an error +Octave > disp(p@{2@}); +error: A(I): Index exceeds matrix dimension. +@end example + +Another way to add files to the @var{dynamic classpath} exclusively for your user account is to use the file @code{.octaverc} which is stored in your home directory. +All Octave commands in this file are executed each time you start a new instance of Octave. +The following example adds the directory @code{octave} to Octave's search path and +the archive @code{myclasses.jar} in this directory to the Java search path. +@example +% content of .octaverc: +addpath('~/octave'); +javaaddpath('~/octave/myclasses.jar'); +@end example + +@c ------------------------------------------------------------------------ +@node How to create an instance of a Java class? +@subsection How to create an instance of a Java class? +@c - index - +@cindex object, how to create +@cindex instance, how to create +@c - index - + +If your code shall work under Octave as well as Matlab you should use the function @code{javaObject} to create Java objects. The function @code{java_new} is Octave specific and does not exist in the Matlab environment. + +Example 1, suitable for Octave but not for Matlab: +@example + Passenger = java_new('package.FirstClass', row, seat); +@end example + +Example 2, which works in Octave as well as in Matlab: +@example + Passenger = javaObject('package.FirstClass', row, seat); +@end example + +@c ------------------------------------------------------------------------ +@node How can I handle memory limitations? +@subsection How can I handle memory limitations? +@cindex memory, limitations + +In order to execute Java code Octave creates a Java Virtual Machine (JVM). Such a JVM allocates a fixed amount of initial memory and may expand this pool up to a fixed maximum memory limit. The default values depend on the Java version (see @ref{doc-javamem,,javamem}). +The memory pool is shared by all Java objects running in the JVM. +This strict memory limit is intended mainly to avoid that runaway applications inside web browsers or in enterprise servers can consume all memory and crash the system. +When the maximum memory limit is hit, Java code will throw exceptions so that applications will fail or behave unexpectedly. + +In Octave as well as in Matlab, you can specify options for the creation of the JVM inside a file named @code{java.opts}. +This is a text file where you can enter lines containing @code{-X} and @code{-D} options handed to the JVM during initialization. + +In Octave, the Java options file must be located in the directory where @code{javaclasspath.m} resides, i.e. the package installation directory, usually something like @var{...\share\Octave\packages\java-1.2.8}. You can find this directory by executing +@example +pkg list +@end example + +In Matlab, the options file goes into the @var{MATLABROOT/bin/ARCH} directory or in your personal Matlab startup directory (can be determined by a @samp{pwd} command). @var{MATLABROOT} is the Matlab root directory and @var{ARCH} is your system architecture, which you find by issuing the commands @samp{matlabroot} respectively @samp{computer('arch')}. + +The @code{-X} options allow you to increase the maximum amount of memory available to the JVM to 256 Megabytes by adding the following line to the @code{java.opts} file: +@example +-Xmx256m +@end example + +The maximum possible amount of memory depends on your system. On a Windows system with 2 Gigabytes main memory you should be able to set this maximum to about 1 Gigabyte. + +If your application requires a large amount of memory from the beginning, you can also specify the initial amount of memory allocated to the JVM. Adding the following line to the @code{java.opts} file starts the JVM with 64 Megabytes of initial memory: +@example +-Xms64m +@end example + +For more details on the available @code{-X} options of your Java Virtual Machine issue the command @samp{java -X} at the operating system command prompt and consult the Java documentation. + + +The @code{-D} options can be used to define system properties which can then be used by Java classes inside Octave. System properties can be retrieved by using the @code{getProperty()} methods of the @code{java.lang.System} class. The following example line defines the property @var{MyProperty} and assigns it the string @code{12.34}. +@example +-DMyProperty=12.34 +@end example +The value of this property can then be retrieved as a string by a Java object or in Octave: +@example +Octave > javaMethod('java.lang.System', 'getProperty', 'MyProperty'); +ans = 12.34 +@end example + +@seealso{@ref{doc-javamem,,javamem}} + +@c ------------------------------------------------------------------------ +@node How to compile the java package in Octave? +@subsection How to compile the java package in Octave? +@c - index - +@cindex package, how to compile? +@cindex compiling the java package, how? +@cindex java package, how to compile? +@cindex java package, how to install? +@cindex java package, how to uninstall? +@c - index - + +Most Octave installations come with the @var{java} package pre-installed. In case you want to replace this package with a more recent version, you must perform the following steps: + +@c --------- +@menu +* Uninstall the currently installed package @var{java}:: +* Make sure that the build environment is configured properly:: +* Compile and install the package in Octave:: +* Test the java package installation:: +@end menu + +@node Uninstall the currently installed package @var{java} +@subsubsection Uninstall the currently installed package @var{java} +Check whether the @var{java} package is already installed by issuing +the @code{pkg list} command: +@example +Octave > pkg list +Package Name | Version | Installation directory +--------------+---------+----------------------- + java *| 1.2.8 | /home/octavio/octave/java-1.2.8 +Octave > +@end example + +@noindent +If the @var{java} package appears in the list you must uninstall it first by issuing the command +@example +Octave > pkg uninstall java +Octave > pkg list +@end example + +Now the java package should not be listed anymore. If you have used the @var{java} package during the current session of Octave, you have to exit and restart Octave before you can uninstall the package. This is because the system keeps certain libraries in memory after they have been loaded once. + +@c --------- +@node Make sure that the build environment is configured properly +@subsubsection Make sure that the build environment is configured properly +The installation process requires that the environment variable @code{JAVA_HOME} points to the Java Development Kit (JDK) on your computer. + +@itemize @bullet +@item +Note that JDK is not equal to JRE (Java Runtime Environment). The JDK home directory contains subdirectories with include, library and executable files which are required to compile the @var{java} package. These files are not part of the JRE, so you definitely need the JDK. +@item +Do not use backslashes but ordinary slashes in the path. +@end itemize + +Set the environment variable @code{JAVA_HOME} according to your local JDK installation. Please adapt the path in the following examples according to the JDK installation on your system.@* +If you are using a Windows system that might be: +@example +Octave > setenv("JAVA_HOME","C:/Java/jdk1.6.0_21"); +@end example +Note, that on both system types, Windows as well as Linux, you must use the forward slash '/' as the separator, not the backslash '\'. + +If you are using a Linux system this would look probably more like: +@example +Octave > setenv("JAVA_HOME","/usr/local/jdk1.6.0_21"); +@end example + +@c --------- +@node Compile and install the package in Octave +@subsubsection Compile and install the package in Octave +If you have for example saved the package archive on your @var{z:} drive the command would be: +@example +Octave> pkg install -verbose z:/java-1.2.8.tar.gz +@end example +or if you have Linux and the package file is stored in your home directory: +@example +Octave > pkg install -verbose ~/java-1.2.8.tar.gz +@end example +The option @code{-verbose} will produce some lengthy output, which should not show any errors +(maybe a few warnings at best). + +You can then produce a list of all installed packages: +@example +Octave > pkg list +@end example + +This list of packages should now include the package @var{java}: +@example +Octave > pkg list +Package Name | Version | Installation directory +--------------+---------+----------------------- + java *| 1.2.8 | /home/octavio/octave/java-1.2.8 +Octave > +@end example + +@c --------- +@node Test the java package installation +@subsubsection Test the java package installation + +The following code creates a Java string object, which however is automatically converted to an Octave string: +@example +Octave > s = javaObject('java.lang.String', 'Hello OctaveString') +s = Hello OctaveString +@end example + +Note that the java package automatically transforms the Java String object to an Octave string. This means that you cannot apply Java String methods to the result. + +This "auto boxing" scheme seems to be implemented for the following Java classes: +@itemize @bullet +@item +java.lang.Integer +@item +java.lang.Double +@item +java.lang.Boolean +@item +java.lang.String +@end itemize + +If you instead create an object for which no "auto-boxing" is implemented, @code{javaObject} returns the genuine Java object: +@example +Octave > v = javaObject('java.util.Vector') +v = +<Java object: java.util.Vector> +Octave > v.add(12); +Octave > v.get(0) +ans = 12 +@end example + +If you have created such a Java object, you can apply all methods of the Java class to the returned object. Note also that for some objects you must specify an initializer: +@example +% not: +Octave > d = javaObject('java.lang.Double') +error: [java] java.lang.NoSuchMethodException: java.lang.Double +% but: +Octave > d = javaObject('java.lang.Double',12.34) +d = 12.340 +@end example + +@c ------------------------------------------------------------------------ +@node Which @TeX{} symbols are implemented in the dialog functions? +@subsection Which @TeX{} symbols are implemented in the dialog functions? +@c - index - +@cindex symbols, translation table +@cindex @TeX{} symbols, translation table +@cindex translation table for @TeX{} symbols +@c - index - + +The dialog functions contain a translation table for @TeX{} like symbol codes. Thus messages and labels can be tailored to show some common mathematical symbols or Greek characters. No further @TeX{} formatting codes are supported. The characters are translated to their Unicode equivalent. However, not all characters may be displayable on your system. This depends on the font used by the Java system on your computer. + +Each @TeX{} symbol code must be terminated by a space character to make it distinguishable from the surrounding text. Therefore the string @samp{\alpha =12.0} will produce the desired result, whereas @samp{\alpha=12.0} would produce the literal text @var{'\alpha=12.0'}. + +@seealso{@ref{doc-errordlg,,errordlg}, + @ref{doc-helpdlg,,helpdlg}, + @ref{doc-inputdlg,,inputdlg}, + @ref{doc-listdlg,,listdlg}, + @ref{doc-msgbox,,msgbox}, + @ref{doc-questdlg,,questdlg}, + @ref{doc-warndlg,,warndlg}} + +@need 5000 +@c --------------------------------- +@ifhtml +@float Table +The table below shows each @TeX{} character code and the corresponding Unicode character: +@multitable @columnfractions 0.18 0.1 0.05 0.18 0.1 0.05 0.18 0.1 +@item \alpha +@tab 'α' +@tab +@tab \beta +@tab 'β' +@tab +@tab \gamma +@tab 'γ' +@c ---------- +@item \delta +@tab 'Ī“' +@tab +@tab \epsilon +@tab 'ε' +@tab +@tab \zeta +@tab 'ζ' +@c ---------- +@item \eta +@tab 'Ī·' +@tab +@tab \theta +@tab 'Īø' +@tab +@tab \vartheta +@tab 'Ļ' +@c ---------- +@item \iota +@tab 'ι' +@tab +@tab \kappa +@tab 'Īŗ' +@tab +@tab \lambda +@tab 'Ī»' +@c ---------- +@item \mu +@tab 'μ' +@tab +@tab \nu +@tab 'ν' +@tab +@tab \xi +@tab 'ξ' +@c ---------- +@item \pi +@tab 'Ļ' +@tab +@tab \rho +@tab 'Ļ' +@tab +@tab \sigma +@tab 'Ļ' +@c ---------- +@item \varsigma +@tab 'Ļ' +@tab +@tab \tau +@tab 'Ļ' +@tab +@tab \phi +@tab 'Ļ' +@c ---------- +@item \chi +@tab 'Ļ' +@tab +@tab \psi +@tab 'Ļ' +@tab +@tab \omega +@tab 'Ļ' +@c ---------- +@item \upsilon +@tab 'Ļ ' +@tab +@tab \Gamma +@tab 'Ī' +@tab +@tab \Delta +@tab 'Ī' +@c ---------- +@item \Theta +@tab 'Ī' +@tab +@tab \Lambda +@tab 'Ī' +@tab +@tab \Pi +@tab 'Ī ' +@c ---------- +@item \Xi +@tab 'Ī' +@tab +@tab \Sigma +@tab 'Ī£' +@tab +@tab \Upsilon +@tab 'Ī„' +@c ---------- +@item \Phi +@tab 'Φ' +@tab +@tab \Psi +@tab 'ĪØ' +@tab +@tab \Omega +@tab 'Ī©' +@c ---------- +@item \Im +@tab 'ā' +@tab +@tab \Re +@tab 'ā' +@tab +@tab \leq +@tab 'ā¤' +@c ---------- +@item \geq +@tab 'ā„' +@tab +@tab \neq +@tab 'ā ' +@tab +@tab \pm +@tab '±' +@c ---------- +@item \infty +@tab 'ā' +@tab +@tab \partial +@tab 'ā' +@tab +@tab \approx +@tab 'ā' +@c ---------- +@item \circ +@tab 'ā' +@tab +@tab \bullet +@tab 'ā¢' +@tab +@tab \times +@tab 'Ć' +@c ---------- +@item \sim +@tab '~' +@tab +@tab \nabla +@tab 'ā' +@tab +@tab \ldots +@tab 'ā¦' +@c ---------- +@item \exists +@tab 'ā' +@tab +@tab \neg +@tab '¬' +@tab +@tab \aleph +@tab 'āµ' +@c ---------- +@item \forall +@tab 'ā' +@tab +@tab \cong +@tab 'ā ' +@tab +@tab \wp +@tab 'ā' +@c ---------- +@item \propto +@tab 'ā' +@tab +@tab \otimes +@tab 'ā' +@tab +@tab \oplus +@tab 'ā' +@c ---------- +@item \oslash +@tab 'ā' +@tab +@tab \cap +@tab 'ā©' +@tab +@tab \cup +@tab 'āŖ' +@c ---------- +@item \ni +@tab 'ā' +@tab +@tab \in +@tab 'ā' +@tab +@tab \div +@tab 'Ć·' +@c ---------- +@item \equiv +@tab 'ā”' +@tab +@tab \int +@tab 'ā«' +@tab +@tab \perp +@tab 'ā„' +@c ---------- +@item \wedge +@tab 'ā§' +@tab +@tab \vee +@tab 'āØ' +@tab +@tab \supseteq +@tab 'ā' +@c ---------- +@item \supset +@tab 'ā' +@tab +@tab \subseteq +@tab 'ā' +@tab +@tab \subset +@tab 'ā' +@c ---------- +@item \clubsuit +@tab 'ā£' +@tab +@tab \spadesuit +@tab 'ā ' +@tab +@tab \heartsuit +@tab 'ā„' +@c ---------- +@item \diamondsuit +@tab 'ā¦' +@tab +@tab \copyright +@tab 'Ā©' +@tab +@tab \leftarrow +@tab 'ā' +@c ---------- +@item \uparrow +@tab 'ā' +@tab +@tab \rightarrow +@tab 'ā' +@tab +@tab \downarrow +@tab 'ā' +@c ---------- +@item \leftrightarrow +@tab 'ā' +@tab +@tab \updownarrow +@tab 'ā' +@tab +@c ---------- +@end multitable +@caption{@TeX{} character codes and the resulting symbols.} +@end float +@end ifhtml +@c --------------------------------- +@iftex +@float Table +The table below shows each @TeX{} character code and the corresponding Unicode character: +@multitable @columnfractions 0.18 0.1 0.05 0.18 0.1 0.05 0.18 0.1 +@headitem @TeX{} code +@tab Symbol +@tab +@tab @TeX{} code +@tab Symbol +@tab +@tab @TeX{} code +@tab Symbol +@c ---------- +@item \alpha +@tab '@math{\alpha}' +@tab +@tab \beta +@tab '@math{\beta}' +@tab +@tab \gamma +@tab '@math{\gamma}' +@c ---------- +@item \delta +@tab '@math{\delta}' +@tab +@tab \epsilon +@tab '@math{\epsilon}' +@tab +@tab \zeta +@tab '@math{\zeta}' +@c ---------- +@item \eta +@tab '@math{\eta}' +@tab +@tab \theta +@tab '@math{\theta}' +@tab +@tab \vartheta +@tab '@math{\vartheta}' +@c ---------- +@item \iota +@tab '@math{\iota}' +@tab +@tab \kappa +@tab '@math{\kappa}' +@tab +@tab \lambda +@tab '@math{\lambda}' +@c ---------- +@item \mu +@tab '@math{\mu}' +@tab +@tab \nu +@tab '@math{\nu}' +@tab +@tab \xi +@tab '@math{\xi}' +@c ---------- +@item \pi +@tab '@math{\pi}' +@tab +@tab \rho +@tab '@math{\rho}' +@tab +@tab \sigma +@tab '@math{\sigma}' +@c ---------- +@item \varsigma +@tab '@math{\varsigma}' +@tab +@tab \tau +@tab '@math{\tau}' +@tab +@tab \phi +@tab '@math{\phi}' +@c ---------- +@item \chi +@tab '@math{\chi}' +@tab +@tab \psi +@tab '@math{\psi}' +@tab +@tab \omega +@tab '@math{\omega}' +@c ---------- +@item \upsilon +@tab '@math{\upsilon}' +@tab +@tab \Gamma +@tab '@math{\Gamma}' +@tab +@tab \Delta +@tab '@math{\Delta}' +@c ---------- +@item \Theta +@tab '@math{\Theta}' +@tab +@tab \Lambda +@tab '@math{\Lambda}' +@tab +@tab \Pi +@tab '@math{\Pi}' +@c ---------- +@item \Xi +@tab '@math{\Xi}' +@tab +@tab \Sigma +@tab '@math{\Sigma}' +@tab +@tab \Upsilon +@tab '@math{\Upsilon}' +@c ---------- +@item \Phi +@tab '@math{\Phi}' +@tab +@tab \Psi +@tab '@math{\Psi}' +@tab +@tab \Omega +@tab '@math{\Omega}' +@c ---------- +@item \Im +@tab '@math{\Im}' +@tab +@tab \Re +@tab '@math{\Re}' +@tab +@tab \leq +@tab '@math{\leq}' +@c ---------- +@item \geq +@tab '@math{\geq}' +@tab +@tab \neq +@tab '@math{\neq}' +@tab +@tab \pm +@tab '@math{\pm}' +@c ---------- +@item \infty +@tab '@math{\infty}' +@tab +@tab \partial +@tab '@math{\partial}' +@tab +@tab \approx +@tab '@math{\approx}' +@c ---------- +@item \circ +@tab '@math{\circ}' +@tab +@tab \bullet +@tab '@math{\bullet}' +@tab +@tab \times +@tab '@math{\times}' +@c ---------- +@item \sim +@tab '@math{\sim}' +@tab +@tab \nabla +@tab '@math{\nabla}' +@tab +@tab \ldots +@tab '@math{\ldots}' +@c ---------- +@item \exists +@tab '@math{\exists}' +@tab +@tab \neg +@tab '@math{\neg}' +@tab +@tab \aleph +@tab '@math{\aleph}' +@c ---------- +@item \forall +@tab '@math{\forall}' +@tab +@tab \cong +@tab '@math{\cong}' +@tab +@tab \wp +@tab '@math{\wp}' +@c ---------- +@item \propto +@tab '@math{\propto}' +@tab +@tab \otimes +@tab '@math{\otimes}' +@tab +@tab \oplus +@tab '@math{\oplus}' +@c ---------- +@item \oslash +@tab '@math{\oslash}' +@tab +@tab \cap +@tab '@math{\cap}' +@tab +@tab \cup +@tab '@math{\cup}' +@c ---------- +@item \ni +@tab '@math{\ni}' +@tab +@tab \in +@tab '@math{\in}' +@tab +@tab \div +@tab '@math{\div}' +@c ---------- +@item \equiv +@tab '@math{\equiv}' +@tab +@tab \int +@tab '@math{\int}' +@tab +@tab \perp +@tab '@math{\perp}' +@c ---------- +@item \wedge +@tab '@math{\wedge}' +@tab +@tab \vee +@tab '@math{\vee}' +@tab +@tab \supseteq +@tab '@math{\supseteq}' +@c ---------- +@item \supset +@tab '@math{\supset}' +@tab +@tab \subseteq +@tab '@math{\subseteq}' +@tab +@tab \subset +@tab '@math{\subset}' +@c ---------- +@item \clubsuit +@tab '@math{\clubsuit}' +@tab +@tab \spadesuit +@tab '@math{\spadesuit}' +@tab +@tab \heartsuit +@tab '@math{\heartsuit}' +@c ---------- +@item \diamondsuit +@tab '@math{\diamondsuit}' +@tab +@tab \copyright +@tab '@math{\copyright}' +@tab +@tab \leftarrow +@tab '@math{\leftarrow}' +@c ---------- +@item \uparrow +@tab '@math{\uparrow}' +@tab +@tab \rightarrow +@tab '@math{\rightarrow}' +@tab +@tab \downarrow +@tab '@math{\downarrow}' +@c ---------- +@item \leftrightarrow +@tab '@math{\leftrightarrow}' +@tab +@tab \updownarrow +@tab '@math{\updownarrow}' +@tab +@c ---------- +@end multitable +@caption{@TeX{} character codes and the resulting symbols.} +@end float +@end iftex +@c ---------------------------------
--- a/doc/interpreter/octave.texi +++ b/doc/interpreter/octave.texi @@ -177,6 +177,7 @@ * Object Oriented Programming:: * GUI Development:: * System Utilities:: +* Java Interface:: * Packages:: * Dynamically Linked Functions:: * Test and Demo Functions:: @@ -909,6 +910,7 @@ @include oop.texi @include gui.texi @include system.texi +@include java.texi @include package.texi @c maybe add again later, if anyone every writes any really interesting
new file mode 100644 --- /dev/null +++ b/libinterp/dldfcn/__java__.cc @@ -0,0 +1,2039 @@ +/* Copyright (C) 2007 Michael Goffioul +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "__java__.h" + +#include "parse.h" +#include "Cell.h" +#include "file-stat.h" +#include "file-ops.h" +#include "cmd-edit.h" +#ifdef __WIN32__ +#include <windows.h> +#endif +#include "load-path.h" +#include "oct-env.h" +#include "oct-shlib.h" +#include "oct-env.h" + +#include <algorithm> +#include <map> +#include <iostream> +#include <fstream> + +#include <clocale> + +typedef jint (JNICALL *JNI_CreateJavaVM_t) (JavaVM **pvm, JNIEnv **penv, void *args); +typedef jint (JNICALL *JNI_GetCreatedJavaVMs_t) (JavaVM **pvm, jsize bufLen, jsize *nVMs); + +extern "C" JNIEXPORT jboolean JNICALL Java_org_octave_Octave_call + (JNIEnv *, jclass, jstring, jobjectArray, jobjectArray); +extern "C" JNIEXPORT void JNICALL Java_org_octave_OctaveReference_doFinalize + (JNIEnv *, jclass, jint); +extern "C" JNIEXPORT void JNICALL Java_org_octave_Octave_doInvoke + (JNIEnv *, jclass, jint, jobjectArray); +extern "C" JNIEXPORT void JNICALL Java_org_octave_Octave_doEvalString + (JNIEnv *, jclass, jstring); +extern "C" JNIEXPORT jboolean JNICALL Java_org_octave_Octave_needThreadedInvokation + (JNIEnv *, jclass); + +static octave_value _java_new ( const octave_value_list& args ); +static octave_value _java_invoke ( const octave_value_list& args ); + +static JavaVM *jvm = 0; +static bool jvm_attached = false; + +// Need to keep hold of the shared library handle until exit. +static octave_shlib jvm_lib; + +static std::map<int,octave_value> listener_map; +static std::map<int,octave_value> octave_ref_map; +static int octave_java_refcount = 0; +static long octave_thread_ID = -1; + +bool Vjava_convert_matrix = false; +bool Vjava_unsigned_conversion = true; +bool Vjava_debug = false; + +class JVMArgs +{ +public: + JVMArgs () + { + vm_args.version = JNI_VERSION_1_2; + vm_args.nOptions = 0; + vm_args.options = 0; + vm_args.ignoreUnrecognized = false; + } + + ~JVMArgs () + { + clean (); + } + + JavaVMInitArgs* to_args () + { + update (); + return &vm_args; + } + + void add (const std::string& opt) + { + java_opts.push_back (opt); + } + + void read_java_opts (const std::string& filename) + { + std::ifstream js (filename.c_str ()); + + if (! js.bad () && ! js.fail ()) + { + std::string line; + + while (! js.eof () && ! js.fail ()) + { + std::getline (js, line); + if (line.length () > 2 && + (line.find ("-D") == 0 || line.find ("-X") == 0)) + java_opts.push_back (line); + else if (line.length () > 0 && Vjava_debug) + std::cerr << "invalid JVM option, skipping: " << line << std::endl; + } + } + } + +private: + void clean () + { + if (vm_args.options != 0) + { + for (int i=0; i<vm_args.nOptions; i++) + free (vm_args.options[i].optionString); + free (vm_args.options); + + vm_args.options = 0; + vm_args.nOptions = 0; + } + } + + void update () + { + clean (); + if (java_opts.size () > 0) + { + int index = 0; + + vm_args.nOptions = java_opts.size (); + vm_args.options = (JavaVMOption*) malloc (sizeof (JavaVMOption) * vm_args.nOptions); + for (std::list<std::string>::const_iterator it = java_opts.begin (); it != java_opts.end (); ++it) + { + if (Vjava_debug) + std::cout << *it << std::endl; + vm_args.options[index++].optionString = strdup ((*it).c_str ()); + } + java_opts.clear (); + } + } + +private: + JavaVMInitArgs vm_args; + std::list<std::string> java_opts; +}; + +static dim_vector compute_array_dimensions (JNIEnv* jni_env, jobject obj); + +#ifdef __WIN32__ +static std::string read_registry_string (const std::string& key, const std::string& value) +{ + HKEY hkey; + DWORD len; + std::string retval = ""; + + if (! RegOpenKeyEx (HKEY_LOCAL_MACHINE, key.c_str (), 0, KEY_READ, &hkey)) + { + if (! RegQueryValueEx (hkey, value.c_str (), 0, 0, 0, &len)) + { + retval.resize (len); + if (RegQueryValueEx (hkey, value.c_str (), 0, 0, (LPBYTE)&retval[0], &len)) + retval = ""; + else if (retval[len-1] == '\0') + retval.resize (--len); + } + RegCloseKey (hkey); + } + return retval; +} + +static std::string get_module_filename (HMODULE hMod) +{ + int n = 1024; + std::string retval(n, '\0'); + bool found = false; + + while (n < 65536) + { + int status = GetModuleFileName(hMod, &retval[0], n); + + if (status < n) + { + retval.resize(n); + found = true; + break; + } + else + { + n *= 2; + retval.resize(n); + } + } + return (found ? retval : ""); +} + +static void set_dll_directory (const std::string& dir = "") +{ + typedef BOOL (WINAPI *dllfcn_t) (LPCTSTR path); + + static dllfcn_t dllfcn = NULL; + static bool first = true; + + if (! dllfcn && first) + { + HINSTANCE hKernel32 = GetModuleHandle ("kernel32"); + dllfcn = reinterpret_cast<dllfcn_t> (GetProcAddress (hKernel32, "SetDllDirectoryA")); + first = false; + } + + if (dllfcn) + dllfcn (dir.empty () ? NULL : dir.c_str ()); +} +#endif + +static std::string get_module_path(const std::string& name, bool strip_name = true) +{ + std::string retval; + + retval = octave_env::make_absolute (load_path::find_file (name), +#ifdef HAVE_OCTAVE_32 + octave_env::getcwd ()); +#else + octave_env::get_current_directory ()); +#endif + + if (! retval.empty () && strip_name) + { + size_t pos = retval.rfind (file_ops::dir_sep_str () + name); + + if (pos != std::string::npos) + retval.resize (pos); + else + throw std::string("No module path in ")+retval; + } + else + throw std::string("Could not find file ")+name; + + return retval; +} + +static std::string initial_java_dir (bool arch_dependent = false) +{ + static std::string path1; + static std::string path2; + + if (arch_dependent) + { + if (path1.empty ()) + path1 = get_module_path ("__java__.oct", true); + return path1; + } + else + { + if (path2.empty ()) + path2 = get_module_path ("javaclasspath.m", true); + return path2; + } +} + +/* + * Read the content of a file filename (usually "classpath.txt") + * + * Returns a string with all lines concatenated and separated + * by the path separator character. + * The return string also starts with a path separator so that + * it can be appended easily to a base classpath. + * + * The file "classpath.txt" must contain single lines, each + * with a classpath. + * Comment lines starting with a '#' or a '%' in column 1 are allowed. + * + * On Windiows the usual path separator is a ';', on Unix a ':'. + * + * Created: 28 Aug 2010 Martin Hepperle + */ +static std::string read_classpath_txt (const std::string& filepath) +{ + std::string classpath; + + std::ifstream fs (filepath.c_str ()); + + if (! fs.bad () && ! fs.fail ()) + { + std::string line; + + while (! fs.eof () && ! fs.fail ()) + { + std::getline (fs, line); + if (line.length () > 1 ) + { + if ( (line.at(0) == '#') || + (line.at(0) == '%') ) + { + // this is a comment line: skip + } + else + { + // prepend separator character + classpath.append(dir_path::path_sep_str()); + // append content of line without trailing blanks + int iLast = line.find_last_not_of(' '); + classpath.append(file_ops::tilde_expand(line.substr(0,iLast+1))); + } + } + } + } + return ( classpath ); +} + + +static std::string initial_class_path () +{ + std::string retval = initial_java_dir (); + + // find octave.jar file + if (! retval.empty ()) + { + std::string jar_file = retval + file_ops::dir_sep_str () + "octave.jar"; + file_stat jar_exists (jar_file); + + if (jar_exists) + { + // initialize static classpath to octave.jar + retval = jar_file; + + /* + * The base classpath has been set. + * Try to find the optional file "classpath.txt" in two places. + * The users classes will take precedence over the settings + * defined in the package directory + */ + std::string str_filename = "classpath.txt"; + std::string cp_file; + file_stat cp_exists; + /* + * Try to read the file "classpath.txt" in the user's home directory + */ + cp_file = file_ops::tilde_expand ( "~" + file_ops::dir_sep_str () + str_filename ); + cp_exists = file_stat(cp_file); + if (cp_exists) + { + /* + * The file "classpath.txt" has been found: add its contents to the static classpath + */ + std::string theClassPath = read_classpath_txt (cp_file); + retval.append(theClassPath); + } + /* + * Try to read a file "classpath.txt" in the package directory + */ + cp_file = initial_java_dir () + file_ops::dir_sep_str () + str_filename; + cp_exists = file_stat(cp_file); + if (cp_exists) + { + /* + * The file "classpath.txt" has been found: add its contents to the static classpath + */ + std::string theClassPath = read_classpath_txt (cp_file); + retval.append(theClassPath); + } + } + else + { + throw std::string("octave jar does not exist: ") + jar_file; + } + } + else + { + throw std::string("initial java dir is empty"); + } + + return retval; +} + +static void initialize_jvm () +{ + JNIEnv *current_env; + + if (jvm) return; + + const char *static_locale = setlocale(LC_ALL, NULL); + const std::string locale(static_locale); + +#if defined (__WIN32__) + + HMODULE hMod = GetModuleHandle("jvm.dll"); + std::string jvm_lib_path; + std::string old_cwd; + + if (hMod == NULL) + { + // In windows, find the location of the JRE from the registry + // and load the symbol from the dll. + std::string key, value; + + key = "software\\javasoft\\java runtime environment"; + + value = octave_env::getenv ("JAVA_VERSION"); + if (value.empty ()) + { + value = "Currentversion"; + std::string regval = read_registry_string (key,value); + if (regval.empty ()) + throw std::string ("unable to find Java Runtime Environment: ")+key+"::"+value; + value = regval; + } + + key = key + "\\" + value; + value = "RuntimeLib"; + jvm_lib_path = read_registry_string (key,value); + if (jvm_lib_path.empty()) + throw std::string ("unable to find Java Runtime Environment: ")+key+"::"+value; + + std::string jvm_bin_path; + + value = "JavaHome"; + jvm_bin_path = read_registry_string (key, value); + if (! jvm_bin_path.empty ()) + { + jvm_bin_path = (jvm_bin_path + std::string ("\\bin")); +#ifdef HAVE_OCTAVE_32 + old_cwd = octave_env::getcwd (); +#else + old_cwd = octave_env::get_current_directory (); +#endif + set_dll_directory (jvm_bin_path); + octave_env::chdir (jvm_bin_path); + } + } + else + { + // JVM seems to be already loaded, better to use that DLL instead + // of looking in the registry, to avoid opening a different JVM. + jvm_lib_path = get_module_filename(hMod); + if (jvm_lib_path.empty()) + throw std::string ("unable to find Java Runtime Environment"); + } + +#else + + std::string jvm_lib_path = JAVA_HOME+std::string("/jre/lib/")+JAVA_ARCH+"/server/libjvm.so"; + +#endif + + jsize nVMs = 0; + +# if !defined (__APPLE__) && !defined (__MACH__) + + octave_shlib lib (jvm_lib_path); + if (!lib) + throw std::string("unable to load Java Runtime Environment from ")+jvm_lib_path; + +#if defined (__WIN32__) + set_dll_directory (); + if (! old_cwd.empty ()) + octave_env::chdir (old_cwd); +#endif + + JNI_CreateJavaVM_t create_vm = (JNI_CreateJavaVM_t)lib.search("JNI_CreateJavaVM"); + JNI_GetCreatedJavaVMs_t get_vm = (JNI_GetCreatedJavaVMs_t)lib.search("JNI_GetCreatedJavaVMs"); + if (!create_vm) + throw std::string("unable to find JNI_CreateJavaVM in ")+jvm_lib_path; + if (!get_vm) + throw std::string("unable to find JNI_GetCreatedJavaVMs in ")+jvm_lib_path; + + if (get_vm(&jvm, 1, &nVMs) == 0 && nVMs > 0) + +#else + + // FIXME: There exists a problem on the Mac platform that + // octave_shlib lib (jvm_lib_path) + // doesn't work with 'not-bundled' *.oct files. + + if (JNI_GetCreatedJavaVMs(&jvm, 1, &nVMs) == 0 && nVMs > 0) + +#endif + + { + // At least one JVM exists, try to attach to it + + switch (jvm->GetEnv((void**)¤t_env, JNI_VERSION_1_2)) + { + case JNI_EDETACHED: + // Attach the current thread + JavaVMAttachArgs vm_args; + vm_args.version = JNI_VERSION_1_2; + vm_args.name = (char*)"octave"; + vm_args.group = NULL; + if (jvm->AttachCurrentThread((void**)¤t_env, &vm_args) < 0) + throw std::string("JVM internal error, unable to attach octave to existing JVM"); + break; + case JNI_EVERSION: + throw std::string("JVM internal error, the required JNI version is not supported"); + break; + case JNI_OK: + // Don't do anything, the current thread is already attached to JVM + break; + } + + jvm_attached = true; + //printf("JVM attached\n"); + } + else + { + // No JVM exists, create one + + JVMArgs vm_args; + + vm_args.add ("-Djava.class.path=" + initial_class_path ()); + vm_args.add ("-Doctave.java.path=" + initial_java_dir (true)); + vm_args.add ("-Xrs"); + vm_args.add ("-Djava.system.class.loader=org.octave.OctClassLoader"); + vm_args.read_java_opts (initial_java_dir (false) + file_ops::dir_sep_str () + "java.opts"); + +# if !defined (__APPLE__) && !defined (__MACH__) + + if (create_vm (&jvm, ¤t_env, vm_args.to_args ()) != JNI_OK) + throw std::string("unable to start Java VM in ")+jvm_lib_path; + //printf("JVM created\n"); + } + + jvm_lib = lib; + +#else + + if (JNI_CreateJavaVM (&jvm, reinterpret_cast<void **>(¤t_env), + vm_args.to_args ()) != JNI_OK) + throw std::string("unable to start Java VM in ")+jvm_lib_path; + + } + +#endif + + setlocale(LC_ALL, locale.c_str()); +} + +static void terminate_jvm(void) +{ + if (jvm) + { + if (jvm_attached) + jvm->DetachCurrentThread (); + else + jvm->DestroyJavaVM (); + jvm = 0; + jvm_attached = false; + + if (jvm_lib) + jvm_lib.close (); + } +} + +std::string jstring_to_string (JNIEnv* jni_env, jstring s) +{ + std::string retval; + if (jni_env) + { + const char *cstr = jni_env->GetStringUTFChars (s, 0); + retval = cstr; + jni_env->ReleaseStringUTFChars (s, cstr); + } + return retval; +} + +std::string jstring_to_string (JNIEnv* jni_env, jobject obj) +{ + std::string retval; + if (jni_env && obj) + { + jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String")); + if (cls) + { + if (jni_env->IsInstanceOf (obj, cls)) + retval = jstring_to_string (jni_env, reinterpret_cast<jstring> (obj)); + } + } + return retval; +} + +static octave_value check_exception (JNIEnv* jni_env) +{ + octave_value retval; + jthrowable_ref ex (jni_env, jni_env->ExceptionOccurred ()); + + if (ex) + { + if (Vjava_debug) + jni_env->ExceptionDescribe (); + jni_env->ExceptionClear (); + + jclass_ref jcls (jni_env, jni_env->GetObjectClass (ex)); + jmethodID mID = jni_env->GetMethodID (jcls, "toString", "()Ljava/lang/String;"); + jstring_ref js (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (ex, mID))); + std::string msg = jstring_to_string (jni_env, js); + + error ("[java] %s", msg.c_str ()); + } + else + retval = Matrix (); + return retval; +} + +static jclass find_octave_class (JNIEnv *jni_env, char *name) +{ + static std::string class_loader; + static jclass uiClass = 0; + + jclass jcls = jni_env->FindClass (name); + + if (jcls == 0) + { + jni_env->ExceptionClear (); + + if (! uiClass) + { + if (class_loader.empty ()) + { + jclass_ref syscls (jni_env, jni_env->FindClass ("java/lang/System")); + jmethodID mID = jni_env->GetStaticMethodID (syscls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"); + jstring_ref js (jni_env, jni_env->NewStringUTF ("octave.class.loader")); + js = reinterpret_cast<jstring> (jni_env->CallStaticObjectMethod (syscls, mID, jstring (js))); + class_loader = jstring_to_string (jni_env, jstring (js)); + std::replace (class_loader.begin(), class_loader.end (), '.', '/'); + } + + jclass_ref uicls (jni_env, jni_env->FindClass (class_loader.c_str ())); + + if (! uicls) + { + jni_env->ExceptionClear (); + + /* Try the netbeans way */ + std::replace (class_loader.begin(), class_loader.end (), '/', '.'); + jclass_ref jcls2 (jni_env, jni_env->FindClass ("org/openide/util/Lookup")); + jmethodID mID = jni_env->GetStaticMethodID (jcls2, "getDefault", "()Lorg/openide/util/Lookup;"); + jobject_ref lObj (jni_env, jni_env->CallStaticObjectMethod (jcls2, mID)); + mID = jni_env->GetMethodID (jcls2, "lookup", "(Ljava/lang/Class;)Ljava/lang/Object;"); + jclass_ref cLoaderCls (jni_env, jni_env->FindClass ("java/lang/ClassLoader")); + jobject_ref cLoader (jni_env, jni_env->CallObjectMethod (lObj, mID, jclass (cLoaderCls))); + mID = jni_env->GetMethodID (cLoaderCls, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + jstring_ref js (jni_env, jni_env->NewStringUTF (class_loader.c_str ())); + uicls = reinterpret_cast<jclass> (jni_env->CallObjectMethod (cLoader, mID, jstring (js))); + } + + if (uicls) + uiClass = reinterpret_cast<jclass> (jni_env->NewGlobalRef (jclass (uicls))); + } + + if (uiClass) + { + jmethodID mID = jni_env->GetStaticMethodID (uiClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + jstring_ref js (jni_env, jni_env->NewStringUTF (name)); + jcls = reinterpret_cast<jclass> (jni_env->CallStaticObjectMethod (uiClass, mID, jstring (js))); + } + } + return jcls; +} + +static dim_vector compute_array_dimensions (JNIEnv* jni_env, jobject obj) +{ + jobjectArray_ref jobj (jni_env, reinterpret_cast<jobjectArray> (obj)); + jclass_ref jcls (jni_env, jni_env->GetObjectClass (obj)); + jclass_ref ccls (jni_env, jni_env->GetObjectClass (jcls)); + jmethodID isArray_ID = jni_env->GetMethodID (ccls, "isArray", "()Z"), + getComponentType_ID = jni_env->GetMethodID (ccls, "getComponentType", "()Ljava/lang/Class;"); + dim_vector dv (1, 1); + int idx = 0; + + jobj.detach (); + while (jcls && jni_env->CallBooleanMethod (jcls, isArray_ID)) + { + int len = (jobj ? jni_env->GetArrayLength (jobj) : 0); + if (idx >= dv.length ()) + dv.resize (idx+1); + dv (idx) = len; + jcls = reinterpret_cast<jclass> (jni_env->CallObjectMethod (jcls, getComponentType_ID)); + jobj = (len > 0 ? reinterpret_cast<jobjectArray> (jni_env->GetObjectArrayElement (jobj, 0)) : 0); + idx++; + } + return dv; +} + +static jobject make_java_index (JNIEnv* jni_env, const octave_value_list& idx) +{ + jclass_ref ocls (jni_env, jni_env->FindClass ("[I")); + jobjectArray retval = jni_env->NewObjectArray (idx.length (), ocls, 0); + for (int i=0; i<idx.length (); i++) + { + idx_vector v = idx(i).index_vector (); + if (! error_state) + { + jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ())); + jint *buf = jni_env->GetIntArrayElements (i_array, 0); + for (int k=0; k<v.length (); k++) + buf[k] = v(k); + jni_env->ReleaseIntArrayElements (i_array, buf, 0); + jni_env->SetObjectArrayElement (retval, i, i_array); + check_exception (jni_env); + if (error_state) + break; + } + else + break; + } + return retval; +} + +static octave_value get_array_elements (JNIEnv* jni_env, jobject jobj, const octave_value_list& idx) +{ + octave_value retval; + jobject_ref resObj (jni_env); + jobject_ref java_idx (jni_env, make_java_index (jni_env, idx)); + + if (! error_state) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, (char*)"org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "arraySubsref", "(Ljava/lang/Object;[[I)Ljava/lang/Object;"); + resObj = jni_env->CallStaticObjectMethod (helperClass, mID, jobj, jobject (java_idx)); + } + + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + + return retval; +} + +static octave_value set_array_elements (JNIEnv* jni_env, jobject jobj, const octave_value_list& idx, const octave_value& rhs) +{ + octave_value retval; + jclass_ref rhsCls (jni_env); + jobject_ref resObj (jni_env), rhsObj (jni_env); + jobject_ref java_idx (jni_env, make_java_index (jni_env, idx)); + + if (! error_state && unbox (jni_env, rhs, rhsObj, rhsCls)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, (char*)"org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "arraySubsasgn", + "(Ljava/lang/Object;[[ILjava/lang/Object;)Ljava/lang/Object;"); + resObj = jni_env->CallStaticObjectMethod (helperClass, mID, + jobj, jobject (java_idx), jobject (rhsObj)); + } + + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + + return retval; +} + +static string_vector get_invoke_list (JNIEnv* jni_env, jobject jobj) +{ + std::list<std::string> name_list; + if (jni_env) + { + jclass_ref cls (jni_env, jni_env->GetObjectClass (jobj)); + jclass_ref ccls (jni_env, jni_env->GetObjectClass (cls)); + jmethodID getMethods_ID = jni_env->GetMethodID (ccls, "getMethods", "()[Ljava/lang/reflect/Method;"), + getFields_ID = jni_env->GetMethodID (ccls, "getFields", "()[Ljava/lang/reflect/Field;"); + jobjectArray_ref mList (jni_env, reinterpret_cast<jobjectArray> (jni_env->CallObjectMethod (cls, getMethods_ID))), + fList (jni_env, reinterpret_cast<jobjectArray> (jni_env->CallObjectMethod (cls, getFields_ID))); + int mLen = jni_env->GetArrayLength (mList), fLen = jni_env->GetArrayLength (fList); + jclass_ref mCls (jni_env, jni_env->FindClass ("java/lang/reflect/Method")), + fCls (jni_env, jni_env->FindClass ("java/lang/reflect/Field")); + jmethodID m_getName_ID = jni_env->GetMethodID (mCls, "getName", "()Ljava/lang/String;"), + f_getName_ID = jni_env->GetMethodID (fCls, "getName", "()Ljava/lang/String;"); + for (int i=0; i<mLen; i++) + { + jobject_ref meth (jni_env, jni_env->GetObjectArrayElement (mList, i)); + jstring_ref methName (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (meth, m_getName_ID))); + name_list.push_back (jstring_to_string (jni_env, methName)); + } + for (int i=0; i<fLen; i++) + { + jobject_ref field (jni_env, jni_env->GetObjectArrayElement (fList, i)); + jstring_ref fieldName (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (field, f_getName_ID))); + name_list.push_back (jstring_to_string (jni_env, fieldName)); + } + } + + string_vector v (name_list); + return v.sort (true); +} + +static octave_value convert_to_string (JNIEnv *jni_env, jobject java_object, bool force, char type) +{ + octave_value retval; + + if (jni_env && java_object) + { + jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/String")); + if (jni_env->IsInstanceOf (java_object, cls)) + retval = octave_value (jstring_to_string (jni_env, java_object), type); + else if (force) + { + cls = jni_env->FindClass ("[Ljava/lang/String;"); + if (jni_env->IsInstanceOf (java_object, cls)) + { + jobjectArray array = reinterpret_cast<jobjectArray> (java_object); + int len = jni_env->GetArrayLength (array); + Cell c (len, 1); + for (int i=0; i<len; i++) + { + jstring_ref js (jni_env, reinterpret_cast<jstring> (jni_env->GetObjectArrayElement (array, i))); + if (js) + c(i) = octave_value (jstring_to_string (jni_env, js), type); + else + { + c(i) = check_exception (jni_env); + if (error_state) + break; + } + } + retval = octave_value (c); + } + else + { + cls = jni_env->FindClass ("java/lang/Object"); + jmethodID mID = jni_env->GetMethodID (cls, "toString", "()Ljava/lang/String;"); + jstring_ref js (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (java_object, mID))); + if (js) + retval = octave_value (jstring_to_string (jni_env, js), type); + else + retval = check_exception (jni_env); + } + } + else + error ("unable to convert Java object to string"); + } + + return retval; +} + +#define TO_JAVA(obj) dynamic_cast<octave_java*>((obj).internal_rep()) + +octave_value box (JNIEnv* jni_env, jobject jobj, jclass jcls) +{ + octave_value retval; + jclass_ref cls (jni_env); + + if (! jobj) + retval = Matrix (); + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("java/lang/Integer"); + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID m = jni_env->GetMethodID (cls, "intValue", "()I"); + retval = jni_env->CallIntMethod (jobj, m); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("java/lang/Double"); + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID m = jni_env->GetMethodID (cls, "doubleValue", "()D"); + retval = jni_env->CallDoubleMethod (jobj, m); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("java/lang/Boolean"); + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID m = jni_env->GetMethodID (cls, "booleanValue", "()Z"); + // MH retval = jni_env->CallBooleanMethod (jobj, m); + retval = (jni_env->CallBooleanMethod (jobj, m) ? true : false); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("java/lang/String"); + if (jni_env->IsInstanceOf (jobj, cls)) + { + retval = jstring_to_string (jni_env, jobj); + } + } + + if (retval.is_undefined () && Vjava_convert_matrix) + { + cls = find_octave_class (jni_env, (char*)"org/octave/Matrix"); + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID mID = jni_env->GetMethodID (cls, "getDims", "()[I"); + jintArray_ref iv (jni_env, reinterpret_cast<jintArray> (jni_env->CallObjectMethod (jobj, mID))); + jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv), 0); + dim_vector dims; + dims.resize (jni_env->GetArrayLength (jintArray (iv))); + for (int i=0; i<dims.length (); i++) + dims(i) = iv_data[i]; + jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0); + mID = jni_env->GetMethodID (cls, "getClassName", "()Ljava/lang/String;"); + jstring_ref js (jni_env, reinterpret_cast<jstring> (jni_env->CallObjectMethod (jobj, mID))); + std::string s = jstring_to_string (jni_env, js); + if (s == "double") + { + NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toDouble", "()[D"); + jdoubleArray_ref dv (jni_env, reinterpret_cast<jdoubleArray> (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetDoubleArrayRegion (dv, 0, m.length (), m.fortran_vec ()); + retval = m; + } + else if (s == "byte") + { + if (Vjava_unsigned_conversion) + { + uint8NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toByte", "()[B"); + jbyteArray_ref dv (jni_env, reinterpret_cast<jbyteArray> (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetByteArrayRegion (dv, 0, m.length (), (jbyte*)m.fortran_vec ()); + retval = m; + } + else + { + int8NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toByte", "()[B"); + jbyteArray_ref dv (jni_env, reinterpret_cast<jbyteArray> (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetByteArrayRegion (dv, 0, m.length (), (jbyte*)m.fortran_vec ()); + retval = m; + } + } + else if (s == "integer") + { + if (Vjava_unsigned_conversion) + { + uint32NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toInt", "()[I"); + jintArray_ref dv (jni_env, reinterpret_cast<jintArray> (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetIntArrayRegion (dv, 0, m.length (), (jint*)m.fortran_vec ()); + retval = m; + } + else + { + int32NDArray m (dims); + mID = jni_env->GetMethodID (cls, "toInt", "()[I"); + jintArray_ref dv (jni_env, reinterpret_cast<jintArray> (jni_env->CallObjectMethod (jobj, mID))); + jni_env->GetIntArrayRegion (dv, 0, m.length (), (jint*)m.fortran_vec ()); + retval = m; + } + } + } + } + + if (retval.is_undefined ()) + { + cls = find_octave_class (jni_env, (char*)"org/octave/OctaveReference"); + if (jni_env->IsInstanceOf (jobj, cls)) + { + jmethodID mID = jni_env->GetMethodID (cls, "getID", "()I"); + int ID = jni_env->CallIntMethod (jobj, mID); + std::map<int,octave_value>::iterator it = octave_ref_map.find (ID); + + if (it != octave_ref_map.end ()) + retval = it->second; + } + } + + if (retval.is_undefined ()) + retval = octave_value (new octave_java (jobj, jcls)); + + return retval; +} + +octave_value box_more (JNIEnv* jni_env, jobject jobj, jclass jcls) +{ + octave_value retval = box (jni_env, jobj, jcls); + + if (retval.class_name () == "octave_java") + { + retval = octave_value (); + + jclass_ref cls (jni_env); + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("[D"); + if (jni_env->IsInstanceOf (jobj, cls)) + { + jdoubleArray jarr = reinterpret_cast<jdoubleArray> (jobj); + int len = jni_env->GetArrayLength (jarr); + if (len > 0) + { + Matrix m (1, len); + jni_env->GetDoubleArrayRegion (jarr, 0, len, m.fortran_vec ()); + retval = m; + } + else + retval = Matrix (); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("[[D"); + if (jni_env->IsInstanceOf (jobj, cls)) + { + jobjectArray jarr = reinterpret_cast<jobjectArray> (jobj); + int rows = jni_env->GetArrayLength (jarr), cols = 0; + if (rows > 0) + { + Matrix m; + for (int r = 0; r < rows; r++) + { + jdoubleArray_ref row (jni_env, reinterpret_cast<jdoubleArray> (jni_env->GetObjectArrayElement (jarr, r))); + if (m.length () == 0) + { + cols = jni_env->GetArrayLength (row); + m.resize (cols, rows); + } + jni_env->GetDoubleArrayRegion (row, 0, cols, m.fortran_vec () + r * cols); + } + retval = m.transpose (); + } + else + retval = Matrix(); + } + } + + if (retval.is_undefined ()) + { + cls = jni_env->FindClass ("[Ljava/lang/String;"); + if (jni_env->IsInstanceOf (jobj, cls)) + { + jobjectArray jarr = reinterpret_cast<jobjectArray> (jobj); + int len = jni_env->GetArrayLength (jarr); + Cell m(len, 1); + for (int i=0; i<len; i++) + { + jstring_ref js (jni_env, reinterpret_cast<jstring> (jni_env->GetObjectArrayElement (jarr, i))); + m(i) = jstring_to_string (jni_env, js); + } + retval = m; + } + } + } + + if (retval.is_undefined ()) + retval = octave_value (new octave_java (jobj, jcls)); + + return retval; +} + +int unbox (JNIEnv* jni_env, const octave_value& val, jobject_ref& jobj, jclass_ref& jcls) +{ + int found = 1; + + if (val.class_name () == "octave_java") + { + octave_java *ovj = TO_JAVA (val); + jobj = ovj->to_java (); + jobj.detach (); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_string ()) + { + std::string s = val.string_value (); + jobj = jni_env->NewStringUTF (s.c_str ()); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_bool_scalar ()) + { + bool bval = val.bool_value (); + jclass_ref bcls (jni_env, jni_env->FindClass ("java/lang/Boolean")); + jfieldID fid = jni_env->GetStaticFieldID (bcls, "TYPE", "Ljava/lang/Class;"); + jmethodID mid = jni_env->GetMethodID (bcls, "<init>", "(Z)V"); + jcls = reinterpret_cast<jclass> (jni_env->GetStaticObjectField (bcls, fid)); + jobj = jni_env->NewObject (bcls, mid, bval); + } + else if (val.is_real_scalar ()) + { + double dval = val.double_value (); + jclass_ref dcls (jni_env, jni_env->FindClass ("java/lang/Double")); + jfieldID fid = jni_env->GetStaticFieldID (dcls, "TYPE", "Ljava/lang/Class;"); + jmethodID mid = jni_env->GetMethodID (dcls, "<init>", "(D)V"); + jcls = reinterpret_cast<jclass> (jni_env->GetStaticObjectField (dcls, fid)); + jobj = jni_env->NewObject (dcls, mid, dval); + } + else if (val.is_empty ()) + { + jobj = 0; + //jcls = jni_env->FindClass ("java/lang/Object"); + jcls = 0; + } + else if (!Vjava_convert_matrix && ((val.is_real_matrix () && (val.rows() == 1 || val.columns() == 1)) || val.is_range ())) + { + Matrix m = val.matrix_value (); + jdoubleArray dv = jni_env->NewDoubleArray (m.length ()); + //for (int i=0; i<m.length (); i++) + jni_env->SetDoubleArrayRegion (dv, 0, m.length (), m.fortran_vec ()); + jobj = dv; + jcls = jni_env->GetObjectClass (jobj); + } + else if (Vjava_convert_matrix && (val.is_matrix_type () || val.is_range()) && val.is_real_type ()) + { + jclass_ref mcls (jni_env, find_octave_class (jni_env, (char*)"org/octave/Matrix")); + dim_vector dims = val.dims (); + jintArray_ref iv (jni_env, jni_env->NewIntArray (dims.length ())); + jint *iv_data = jni_env->GetIntArrayElements (jintArray (iv), 0); + for (int i=0; i<dims.length (); i++) + iv_data[i] = dims(i); + jni_env->ReleaseIntArrayElements (jintArray (iv), iv_data, 0); + if (val.is_double_type ()) + { + NDArray m = val.array_value (); + jdoubleArray_ref dv (jni_env, jni_env->NewDoubleArray (m.length ())); + jni_env->SetDoubleArrayRegion (jdoubleArray (dv), 0, m.length (), m.fortran_vec ()); + jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([D[I)V"); + jobj = jni_env->NewObject (jclass (mcls), mID, jdoubleArray (dv), jintArray (iv)); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_int8_type ()) + { + int8NDArray m = val.int8_array_value (); + jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.length ())); + jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.length (), (jbyte*)m.fortran_vec ()); + jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([B[I)V"); + jobj = jni_env->NewObject (jclass (mcls), mID, jbyteArray (bv), jintArray (iv)); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_uint8_type ()) + { + uint8NDArray m = val.uint8_array_value (); + jbyteArray_ref bv (jni_env, jni_env->NewByteArray (m.length ())); + jni_env->SetByteArrayRegion (jbyteArray (bv), 0, m.length (), (jbyte*)m.fortran_vec ()); + jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([B[I)V"); + jobj = jni_env->NewObject (jclass (mcls), mID, jbyteArray (bv), jintArray (iv)); + jcls = jni_env->GetObjectClass (jobj); + } + else if (val.is_int32_type ()) + { + int32NDArray m = val.int32_array_value (); + jintArray_ref v (jni_env, jni_env->NewIntArray (m.length ())); + jni_env->SetIntArrayRegion (jintArray (v), 0, m.length (), (jint*)m.fortran_vec ()); + jmethodID mID = jni_env->GetMethodID (mcls, "<init>", "([I[I)V"); + jobj = jni_env->NewObject (jclass (mcls), mID, jintArray (v), jintArray (iv)); + jcls = jni_env->GetObjectClass (jobj); + } + else + { + found = 0; + error ("cannot convert matrix of type `%s'", val.class_name ().c_str ()); + } + } + else if (val.is_cellstr ()) + { + Cell cellStr = val.cell_value (); + jclass_ref scls (jni_env, jni_env->FindClass ("java/lang/String")); + jobjectArray array = jni_env->NewObjectArray (cellStr.length (), scls, 0); + for (int i=0; i<cellStr.length (); i++) + { + jstring_ref jstr (jni_env, jni_env->NewStringUTF (cellStr(i).string_value().c_str())); + jni_env->SetObjectArrayElement (array, i, jstr); + } + jobj = array; + jcls = jni_env->GetObjectClass (jobj); + } + else + { + jclass rcls = find_octave_class (jni_env, (char*)"org/octave/OctaveReference"); + jmethodID mID = jni_env->GetMethodID (rcls, "<init>", "(I)V"); + int ID = octave_java_refcount++; + + jobj = jni_env->NewObject (rcls, mID, ID); + jcls = rcls; + octave_ref_map[ID] = val; + } + + return found; +} + +int unbox (JNIEnv* jni_env, const octave_value_list& args, jobjectArray_ref& jobjs, jobjectArray_ref& jclss) +{ + int found = 1; + jclass_ref ocls (jni_env, jni_env->FindClass ("java/lang/Object")); + jclass_ref ccls (jni_env, jni_env->FindClass ("java/lang/Class")); + + if (! jobjs) + jobjs = jni_env->NewObjectArray (args.length (), ocls, 0); + if (! jclss) + jclss = jni_env->NewObjectArray (args.length (), ccls, 0); + for (int i=0; i<args.length (); i++) + { + jobject_ref jobj (jni_env); + jclass_ref jcls (jni_env); + + if (! unbox (jni_env, args(i), jobj, jcls)) + { + found = 0; + break; + } + jni_env->SetObjectArrayElement (jobjs, i, jobj); + jni_env->SetObjectArrayElement (jclss, i, jcls); + } + + return found; +} + + +static long get_current_thread_ID(JNIEnv *jni_env) +{ + if (jni_env) + { + jclass_ref cls (jni_env, jni_env->FindClass ("java/lang/Thread")); + jmethodID mID = jni_env->GetStaticMethodID (cls, "currentThread", "()Ljava/lang/Thread;"); + jobject_ref jthread (jni_env, jni_env->CallStaticObjectMethod (cls, mID)); + if (jthread) + { + jclass_ref jth_cls (jni_env, jni_env->GetObjectClass (jthread)); + mID = jni_env->GetMethodID (jth_cls, "getId", "()J"); + long result = jni_env->CallLongMethod (jthread, mID); + //printf("current java thread ID = %ld\n", result); + return result; + } + } + return -1; +} + +static int java_event_hook (void) +{ + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (current_env) + { + jclass_ref cls (current_env, find_octave_class (current_env, (char*)"org/octave/Octave")); + jmethodID mID = current_env->GetStaticMethodID (cls, "checkPendingAction", "()V"); + current_env->CallStaticVoidMethod (cls, mID); + } + return 0; +} + +static void initialize_java (void) +{ + if (! jvm) + { + try + { + initialize_jvm (); + + JNIEnv *current_env = octave_java::thread_jni_env (); + + octave_java::register_type (); + command_editor::add_event_hook (java_event_hook); + octave_thread_ID = get_current_thread_ID (current_env); + //printf("octave thread ID=%ld\n", octave_thread_ID); + } + catch (std::string msg) + { + error (msg.c_str ()); + } + } +} + +DEFUN_DLD (java_init, args, , "") +{ + + octave_value retval; + + retval = 0; + initialize_java (); + if (! error_state) + retval = 1; + + return retval; +} + +DEFUN_DLD (java_exit, args, , "") +{ + octave_value retval; + + terminate_jvm (); + + return retval; +} + +DEFUN_DLD (java_new, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{obj} =} java_new (@var{name}, @var{arg1}, ...)\n\ +Create a Java object of class @var{name}, by calling the class constructor with the\n\ +arguments @var{arg1}, ...\n\ +\n\ +@example\n\ + x = java_new (\"java.lang.StringBuffer\", \"Initial string\")\n\ +@end example\n\ +\n\ +@seealso{java_invoke, java_get, java_set}\n\ +@end deftypefn") +{ + return _java_new ( args ); +} + + +DEFUN_DLD (javaObject, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{obj} =} javaObject (@var{name}, @var{arg1}, ...)\n\ +Create a Java object of class @var{name}, by calling the class constructor with the\n\ +arguments @var{arg1}, ...\n\ +The first example creates an unitialized object, \ +while the second example supplies an initializer argument.\n\ +\n\ +@example\n\ + x = javaObject (\"java.lang.StringBuffer\")\n\ + x = javaObject (\"java.lang.StringBuffer\", \"Initial string\")\n\ +@end example\n\ +\n\ +@seealso{java_invoke, java_new, java_get, java_set}\n\ +@end deftypefn") +{ + return _java_new ( args ); +} + +// internally called from java_new and javaObject for backward compatibility +static octave_value _java_new ( const octave_value_list& args ) +{ + octave_value retval; + + initialize_java (); + if (! error_state) + { + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (args.length () > 0) + { + std::string name = args(0).string_value (); + if (! error_state) + { + octave_value_list tmp; + for (int i=1; i<args.length (); i++) + tmp(i-1) = args(i); + retval = octave_java::do_java_create (current_env, name, tmp); + } + else + error ("java_new: first argument must be a string"); + } + else + print_usage (); + } + + return retval; +} + +DEFUN_DLD (java_invoke, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{ret} =} java_invoke (@var{obj}, @var{name}, @var{arg1}, ...)\n\ +Invoke the method @var{name} on the Java object @var{obj} with the arguments\n\ +@var{arg1}, ... For static methods, @var{obj} can be a string representing the\n\ +fully qualified name of the corresponding class. The function returns the result\n\ +of the method invocation.\n\ +\n\ +When @var{obj} is a regular Java object, the structure-like indexing can be used\n\ +as a shortcut syntax. For instance, the two following statements are equivalent\n\ +\n\ +@example\n\ + ret = java_invoke (x, \"method1\", 1.0, \"a string\")\n\ + ret = x.method1 (1.0, \"a string\")\n\ +@end example\n\ +\n\ +@seealso{java_get, java_set, java_new}\n\ +@end deftypefn") +{ + return _java_invoke ( args ); +} + +DEFUN_DLD (javaMethod, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{ret} =} javaMethod (@var{name}, @var{obj}, @var{arg1}, ...)\n\ +Invoke the method @var{name} on the Java object @var{obj} with the arguments\n\ +@var{arg1}, ... For static methods, @var{obj} can be a string representing the\n\ +fully qualified name of the corresponding class. The function returns the result\n\ +of the method invocation.\n\ +\n\ +When @var{obj} is a regular Java object, the structure-like indexing can be used\n\ +as a shortcut syntax. For instance, the two following statements are equivalent\n\ +\n\ +@example\n\ + ret = javaMethod (\"method1\", x, 1.0, \"a string\")\n\ + ret = x.method1 (1.0, \"a string\")\n\ +@end example\n\ +\n\ +@seealso{java_get, java_set, java_new}\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length() > 1) + { + // swap first two arguments + octave_value_list tmp; + tmp(0) = args(1); + tmp(1) = args(0); + // copy remaining arguments + for (int i=2; i<args.length (); i++) + tmp(i) = args(i); + retval = _java_invoke ( tmp ); + } + else + { + print_usage (); + } + return retval; +} + +// internally called from java_invoke and javaMethod for backward compatibility +static octave_value _java_invoke ( const octave_value_list& args ) +{ + octave_value retval; + + initialize_java (); + if (! error_state) + { + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (args.length() > 1) + { + std::string name = args(1).string_value (); + if (! error_state) + { + octave_value_list tmp; + for (int i=2; i<args.length (); i++) + tmp(i-2) = args(i); + + if (args(0).class_name () == "octave_java") + { + octave_java *jobj = TO_JAVA (args(0)); + retval = jobj->do_java_invoke (current_env, name, tmp); + } + else if (args(0).is_string ()) + { + std::string cls = args(0).string_value (); + retval = octave_java::do_java_invoke (current_env, cls, name, tmp); + } + else + error ("java_invoke: first argument must be a Java object or a string"); + } + else + error ("java_invoke: second argument must be a string"); + } + else + print_usage (); + } + + return retval; +} + +DEFUN_DLD (java_get, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{val} =} java_get (@var{obj}, @var{name})\n\ +Get the value of the field @var{name} of the Java object @var{obj}. For\n\ +static fields, @var{obj} can be a string representing the fully qualified\n\ +name of the corresponding class.\n\ +\n\ +When @var{obj} is a regular Java object, the structure-like indexing can be used\n\ +as a shortcut syntax. For instance, the two following statements are equivalent\n\ +\n\ +@example\n\ + java_get (x, \"field1\")\n\ + x.field1\n\ +@end example\n\ +\n\ +@seealso{java_set, java_invoke, java_new}\n\ +@end deftypefn") +{ + octave_value retval; + + initialize_java (); + if (! error_state) + { + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (args.length () == 2) + { + std::string name = args(1).string_value (); + if (! error_state) + { + if (args(0).class_name () == "octave_java") + { + octave_java *jobj = TO_JAVA (args(0)); + retval = jobj->do_java_get (current_env, name); + } + else if (args(0).is_string ()) + { + std::string cls = args(0).string_value (); + retval = octave_java::do_java_get (current_env, cls, name); + } + else + error ("java_get: first argument must be a Java object or a string"); + } + else + error ("java_get: second argument must be a string"); + } + else + print_usage (); + } + + return retval; +} + +DEFUN_DLD (java_set, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{obj} =} java_set (@var{obj}, @var{name}, @var{val})\n\ +Set the value of the field @var{name} of the Java object @var{obj} to @var{val}.\n\ +For static fields, @var{obj} can be a string representing the fully qualified named\n\ +of the corresponding Java class.\n\ +\n\ +When @var{obj} is a regular Java object, the structure-like indexing can be used as\n\ +a shortcut syntax. For instance, the two following statements are equivalent\n\ +\n\ +@example\n\ + java_set (x, \"field1\", val)\n\ + x.field1 = val\n\ +@end example\n\ +\n\ +@seealso{java_get, java_invoke, java_new}\n\ +@end deftypefn") +{ + octave_value retval; + + initialize_java (); + if (! error_state) + { + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (args.length () == 3) + { + std::string name = args(1).string_value (); + if (! error_state) + { + if (args(0).class_name () == "octave_java") + { + octave_java *jobj = TO_JAVA (args(0)); + retval = jobj->do_java_set (current_env, name, args(2)); + } + else if (args(0).is_string ()) + { + std::string cls = args(0).string_value (); + retval = octave_java::do_java_set (current_env, cls, name, args(2)); + } + else + error ("java_set: first argument must be a Java object or a string"); + } + else + error ("java_set: second argument must be a string"); + } + else + print_usage (); + } + + return retval; +} + +DEFUN_DLD (java2mat, args, , "") +{ + octave_value_list retval; + + initialize_java (); + if (! error_state) + { + JNIEnv *current_env = octave_java::thread_jni_env (); + + if (args.length () == 1) + { + if (args(0).class_name () == "octave_java") + { + octave_java *jobj = TO_JAVA (args(0)); + retval(0) = box_more (current_env, jobj->to_java (), 0); + } + else + retval(0) = args(0); + } + else + print_usage (); + } + + return retval; +} + +DEFUN_DLD (__java__, args, , "") +{ + return octave_value (); +} + +DEFUN_DLD (java_convert_matrix, args, nargout, "") +{ + return SET_INTERNAL_VARIABLE (java_convert_matrix); +} + +DEFUN_DLD (java_unsigned_conversion, args, nargout, "") +{ + return SET_INTERNAL_VARIABLE (java_unsigned_conversion); +} + +DEFUN_DLD (java_debug, args, nargout, "") +{ + return SET_INTERNAL_VARIABLE (java_debug); +} + +JNIEXPORT jboolean JNICALL Java_org_octave_Octave_call + (JNIEnv *env, jclass, jstring funcName, jobjectArray argin, jobjectArray argout) +{ + std::string fname = jstring_to_string (env, funcName); + int nargout = env->GetArrayLength (argout); + int nargin = env->GetArrayLength (argin); + octave_value_list varargin, varargout; + + for (int i=0; i<nargin; i++) + varargin(i) = box (env, env->GetObjectArrayElement (argin, i), 0); + varargout = feval (fname, varargin, nargout); + + if (! error_state) + { + jobjectArray_ref out_objs (env, argout), out_clss (env); + + out_objs.detach (); + if (unbox (env, varargout, out_objs, out_clss)) + return true; + } + + return false; +} + +JNIEXPORT void JNICALL Java_org_octave_OctaveReference_doFinalize + (JNIEnv *env, jclass, jint ID) +{ + octave_ref_map.erase (ID); +} + +JNIEXPORT void JNICALL Java_org_octave_Octave_doInvoke + (JNIEnv *env, jclass, jint ID, jobjectArray args) +{ + std::map<int,octave_value>::iterator it = octave_ref_map.find (ID); + + if (it != octave_ref_map.end ()) + { + octave_value val = it->second; + int len = env->GetArrayLength (args); + octave_value_list oct_args; + + for (int i=0; i<len; i++) + { + jobject_ref jobj (env, env->GetObjectArrayElement (args, i)); + oct_args(i) = box (env, jobj, 0); + if (error_state) + break; + } + + if (! error_state) + { + BEGIN_INTERRUPT_WITH_EXCEPTIONS; + + if (val.is_function_handle ()) + { + octave_function *fcn = val.function_value (); + feval (fcn, oct_args); + } + else if (val.is_cell () && val.length () > 0 && + (val.rows () == 1 || val.columns() == 1) && + val.cell_value()(0).is_function_handle ()) + { + Cell c = val.cell_value (); + octave_function *fcn = c(0).function_value (); + + for (int i=1; i<c.length (); i++) + oct_args(len+i-1) = c(i); + + if (! error_state) + feval (fcn, oct_args); + } + else + error ("trying to invoke non-invocable object"); + + END_INTERRUPT_WITH_EXCEPTIONS; + } + } +} + +JNIEXPORT void JNICALL Java_org_octave_Octave_doEvalString + (JNIEnv *env, jclass, jstring cmd) +{ + std::string s = jstring_to_string (env, cmd); + int pstatus; + + eval_string (s, false, pstatus, 0); +} + +JNIEXPORT jboolean JNICALL Java_org_octave_Octave_needThreadedInvokation + (JNIEnv *env, jclass) +{ + return (get_current_thread_ID (env) != octave_thread_ID); +} + +// octave_java class definition + +DEFINE_OCTAVE_ALLOCATOR (octave_java); + +DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_java, + "octave_java", + "octave_java"); + +dim_vector octave_java::dims(void) const +{ + JNIEnv *current_env = thread_jni_env (); + + if (current_env && java_object) + return compute_array_dimensions (current_env, java_object); + else + return dim_vector (1, 1); +} + +JNIEnv* octave_java::thread_jni_env (void) +{ + JNIEnv *env = NULL; + + if (jvm) + jvm->GetEnv ((void**)&env, JNI_VERSION_1_2); + + return env; +} + +octave_value_list octave_java::subsref(const std::string& type, const std::list<octave_value_list>& idx, int nargout) +{ + octave_value_list retval; + int skip = 1; + + JNIEnv *current_env = thread_jni_env (); + + switch (type[0]) + { + case '.': + if (type.length () > 1 && type[1] == '(') + { + octave_value_list ovl; + count++; + ovl(0) = octave_value (this); + ovl(1) = (idx.front ())(0); + std::list<octave_value_list>::const_iterator it = idx.begin (); + ovl.append (*++it); + retval = feval (std::string ("java_invoke"), ovl, 1); + skip++; + } + else + { + octave_value_list ovl; + count++; + ovl(0) = octave_value (this); + ovl(1) = (idx.front ())(0); + retval = feval (std::string ("java_get"), ovl, 1); + } + break; + case '(': + if (current_env) + retval = get_array_elements (current_env, to_java (), idx.front ()); + break; + default: + error ("subsref: Java object cannot be indexed with %c", type[0]); + break; + } + + if (idx.size () > 1 && type.length () > 1) + retval = retval(0).next_subsref (nargout, type, idx, skip); + + return retval; +} + +octave_value octave_java::subsasgn (const std::string& type, const std::list<octave_value_list>&idx, const octave_value &rhs) +{ + octave_value retval; + + JNIEnv *current_env = thread_jni_env (); + + switch (type[0]) + { + case '.': + if (type.length () == 1) + { + // field assignment + octave_value_list ovl; + count++; + ovl(0) = octave_value (this); + ovl(1) = (idx.front ())(0); + ovl(2) = rhs; + feval ("java_set", ovl, 0); + if (! error_state) + { + count++; + retval = octave_value (this); + } + } + else if (type.length () > 2 && type[1] == '(') + { + std::list<octave_value_list> new_idx; + std::list<octave_value_list>::const_iterator it = idx.begin (); + new_idx.push_back (*it++); + new_idx.push_back (*it++); + octave_value_list u = subsref (type.substr (0, 2), new_idx, 1); + if (! error_state) + { + std::list<octave_value_list> next_idx (idx); + next_idx.erase (next_idx.begin ()); + next_idx.erase (next_idx.begin ()); + u(0).subsasgn (type.substr (2), next_idx, rhs); + if (! error_state) + { + count++; + retval = octave_value (this); + } + } + } + else if (type[1] == '.') + { + octave_value_list u = subsref (type.substr (0, 1), idx, 1); + if (! error_state) + { + std::list<octave_value_list> next_idx (idx); + next_idx.erase (next_idx.begin ()); + u(0).subsasgn (type.substr (1), next_idx, rhs); + if (! error_state) + { + count++; + retval = octave_value (this); + } + } + } + else + error ("invalid indexing/assignment on Java object"); + break; + case '(': + if (current_env) + { + set_array_elements (current_env, to_java (), idx.front (), rhs); + if (! error_state) + { + count++; + retval = octave_value (this); + } + } + break; + default: + error ("Java object cannot be indexed with %c", type[0]); + break; + } + + return retval; +} + +string_vector octave_java::map_keys (void) const +{ + JNIEnv *current_env = thread_jni_env (); + + if (current_env) + return get_invoke_list (current_env, to_java ()); + else + return string_vector (); +} + +octave_value octave_java::convert_to_str_internal (bool, bool force, char type) const +{ + JNIEnv *current_env = thread_jni_env (); + + if (current_env) + return convert_to_string (current_env, to_java (), force, type); + else + return octave_value (""); +} + +octave_value octave_java::do_java_invoke (JNIEnv* jni_env, const std::string& name, + const octave_value_list& args) +{ + octave_value retval; + + if (jni_env) + { + jobjectArray_ref arg_objs (jni_env), arg_types (jni_env); + if (unbox (jni_env, args, arg_objs, arg_types)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, (char*)"org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeMethod", + "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;"); + jstring_ref methName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jobjectArray_ref resObj (jni_env, reinterpret_cast<jobjectArray> (jni_env->CallStaticObjectMethod (helperClass, mID, + to_java (), jstring (methName), jobjectArray (arg_objs), jobjectArray (arg_types)))); + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + } + } + return retval; +} + +octave_value octave_java:: do_java_invoke (JNIEnv* jni_env, const std::string& class_name, + const std::string& name, const octave_value_list& args) +{ + octave_value retval; + + if (jni_env) + { + jobjectArray_ref arg_objs (jni_env), arg_types (jni_env); + if (unbox (jni_env, args, arg_objs, arg_types)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, (char*)"org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeStaticMethod", + "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;"); + jstring_ref methName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jstring_ref clsName (jni_env, jni_env->NewStringUTF (class_name.c_str ())); + jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, + jstring (clsName), jstring (methName), jobjectArray (arg_objs), jobjectArray (arg_types))); + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + } + } + return retval; +} + +octave_value octave_java::do_java_create (JNIEnv* jni_env, const std::string& name, const octave_value_list& args) +{ + octave_value retval; + + if (jni_env) + { + jobjectArray_ref arg_objs (jni_env), arg_types (jni_env); + if (unbox (jni_env, args, arg_objs, arg_types)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, (char*)"org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "invokeConstructor", + "(Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;"); + jstring_ref clsName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, + jstring (clsName), jobjectArray (arg_objs), jobjectArray (arg_types))); + if (resObj) + retval = box (jni_env, resObj); + else + check_exception (jni_env); + } + } + return retval; +} + +octave_value octave_java::do_java_get (JNIEnv* jni_env, const std::string& name) +{ + octave_value retval; + + if (jni_env) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, (char*)"org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "getField", + "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;"); + jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, + to_java (), jstring (fName))); + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + } + return retval; +} + +octave_value octave_java::do_java_get (JNIEnv* jni_env, const std::string& class_name, const std::string& name) +{ + octave_value retval; + + if (jni_env) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, (char*)"org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "getStaticField", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); + jstring_ref cName (jni_env, jni_env->NewStringUTF (class_name.c_str ())); + jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jobject_ref resObj (jni_env, jni_env->CallStaticObjectMethod (helperClass, mID, + jstring (cName), jstring (fName))); + if (resObj) + retval = box (jni_env, resObj); + else + retval = check_exception (jni_env); + } + return retval; +} + +octave_value octave_java::do_java_set (JNIEnv* jni_env, const std::string& name, const octave_value& val) +{ + octave_value retval; + + if (jni_env) + { + jobject_ref jobj (jni_env); + jclass_ref jcls (jni_env); + + if (unbox (jni_env, val, jobj, jcls)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, (char*)"org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "setField", + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V"); + jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jni_env->CallStaticObjectMethod (helperClass, mID, to_java (), jstring (fName), jobject (jobj)); + check_exception (jni_env); + } + } + return retval; +} + +octave_value octave_java::do_java_set (JNIEnv* jni_env, const std::string& class_name, const std::string& name, const octave_value& val) +{ + octave_value retval; + + if (jni_env) + { + jobject_ref jobj (jni_env); + jclass_ref jcls (jni_env); + + if (unbox (jni_env, val, jobj, jcls)) + { + jclass_ref helperClass (jni_env, find_octave_class (jni_env, (char*)"org/octave/ClassHelper")); + jmethodID mID = jni_env->GetStaticMethodID (helperClass, "setStaticField", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V"); + jstring_ref cName (jni_env, jni_env->NewStringUTF (class_name.c_str ())); + jstring_ref fName (jni_env, jni_env->NewStringUTF (name.c_str ())); + jni_env->CallStaticObjectMethod (helperClass, mID, jstring (cName), jstring (fName), jobject (jobj)); + check_exception (jni_env); + } + } + return retval; +}
new file mode 100755 --- /dev/null +++ b/libinterp/dldfcn/__java__.h @@ -0,0 +1,272 @@ +/* Copyright (C) 2007 Michael Goffioul +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __JAVA__H__ +#define __JAVA__H__ + +#include "oct.h" +#include "config.h" +#ifndef OCTAVE_EXPORT +#include "oct-dlldefs.h" +#endif // OCTAVE_EXPORT +#include <jni.h> + +#ifdef JAVAPKG_BUILD +# define JAVAPKG_API OCTAVE_EXPORT +#else +# define JAVAPKG_API OCTAVE_IMPORT +#endif + +template <class T> +class java_local_ref +{ +public: + java_local_ref (JNIEnv *_env) + : jobj (0), detached (false), env (_env) + { } + + java_local_ref (JNIEnv *_env, T obj) + : jobj (obj), detached (false), env (_env) + { } + + ~java_local_ref (void) + { + release (); + } + + T& operator= (T obj) + { + release (); + jobj = obj; + detached = false; + return jobj; + } + operator bool () const { return (jobj != 0); } + operator T () { return jobj; } + + void detach () { detached = true; } + +private: + void release (void) + { + if (env && jobj && ! detached) + env->DeleteLocalRef (jobj); + jobj = 0; + } + + java_local_ref (void) + : jobj (0), detached (false), env (0) + { } + + +protected: + T jobj; + bool detached; + JNIEnv *env; +}; + +typedef java_local_ref<jobject> jobject_ref; +typedef java_local_ref<jclass> jclass_ref; +typedef java_local_ref<jstring> jstring_ref; +typedef java_local_ref<jobjectArray> jobjectArray_ref; +typedef java_local_ref<jintArray> jintArray_ref; +typedef java_local_ref<jbyteArray> jbyteArray_ref; +typedef java_local_ref<jdoubleArray> jdoubleArray_ref; +typedef java_local_ref<jthrowable> jthrowable_ref; + +extern JAVAPKG_API std::string jstring_to_string (JNIEnv* jni_env, jstring s); +extern JAVAPKG_API std::string jstring_to_string (JNIEnv* jni_env, jobject obj); +extern JAVAPKG_API octave_value box (JNIEnv* jni_env, jobject jobj, jclass jcls = 0); +extern JAVAPKG_API octave_value box_more (JNIEnv* jni_env, jobject jobj, jclass jcls = 0); +extern JAVAPKG_API int unbox (JNIEnv* jni_env, const octave_value& val, jobject_ref& jobj, jclass_ref& jcls); +extern JAVAPKG_API int unbox (JNIEnv* jni_env, const octave_value_list& args, jobjectArray_ref& jobjs, jobjectArray_ref& jclss); + +extern JAVAPKG_API bool Vjava_convert_matrix; +extern JAVAPKG_API bool Vjava_unsigned_conversion; +extern JAVAPKG_API bool Vjava_debug; + +class JAVAPKG_API octave_java : public octave_base_value +{ +public: + octave_java (void) + : java_object (0), java_class (0) + { } + + octave_java (const octave_java& jobj) + : java_object (0), java_class (0) + { + init (jobj.java_object, jobj.java_class); + } + + octave_java (jobject obj, jclass cls = 0) + : java_object (0) + { + init (obj, cls); + } + + ~octave_java (void) + { + release (); + } + + jobject to_java () const { return java_object; } + jclass to_class () const { return java_class; } + std::string java_class_name () const { return java_type; } + + octave_base_value* clone(void) const { return new octave_java(*this); } + octave_base_value* empty_clone(void) const { return new octave_java(); } + + bool is_defined(void) const { return true; } + + bool is_map (void) const { return true; } + + string_vector map_keys(void) const; + + dim_vector dims(void) const; + + void print(std::ostream& os, bool pr_as_read_syntax = false) const + { + os << "<Java object: " << java_type << ">"; + newline(os); + } + + void print_raw(std::ostream& os, bool pr_as_read_syntax = false) const + { + print(os, pr_as_read_syntax); + } + + octave_value_list subsref (const std::string& type, const std::list<octave_value_list>& idx, int nargout); + + octave_value subsref (const std::string& type, + const std::list<octave_value_list>& idx) + { + octave_value_list retval = subsref (type, idx, 1); + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + octave_value subsasgn (const std::string& type, const std::list<octave_value_list>& idx, const octave_value& rhs); + + octave_value convert_to_str_internal (bool pad, bool force, char type) const; + + bool is_string (void) const + { + JNIEnv *current_env = thread_jni_env (); + + if (current_env && java_object) + { + jclass_ref cls (current_env, current_env->FindClass ("java/lang/String")); + return current_env->IsInstanceOf (java_object, cls); + } + return false; + } + + static JNIEnv* thread_jni_env (void); + + octave_value do_java_invoke (JNIEnv* jni_env, const std::string& name, + const octave_value_list& args); + + octave_value do_java_invoke (const std::string& name, const octave_value_list& args) + { return do_java_invoke(thread_jni_env (), name, args); } + + static octave_value do_java_invoke (JNIEnv* jni_env, const std::string& class_name, + const std::string& name, const octave_value_list& args); + + static octave_value do_java_invoke (const std::string& class_name, + const std::string& name, const octave_value_list& args) + { return do_java_invoke(thread_jni_env (), class_name, name, args); } + + static octave_value do_java_create (JNIEnv* jni_env, const std::string& name, + const octave_value_list& args); + + static octave_value do_java_create (const std::string& name, const octave_value_list& args) + { return do_java_create (thread_jni_env (), name, args); } + + octave_value do_java_get (JNIEnv* jni_env, const std::string& name); + + octave_value do_java_get (const std::string& name) + { return do_java_get (thread_jni_env (), name); } + + static octave_value do_java_get (JNIEnv* jni_env, const std::string& class_name, + const std::string& name); + + static octave_value do_java_get (const std::string& class_name, const std::string& name) + { return do_java_get (thread_jni_env (), class_name, name); } + + octave_value do_java_set (JNIEnv* jni_env, const std::string& name, const octave_value& val); + + octave_value do_java_set (const std::string& name, const octave_value& val) + { return do_java_set (thread_jni_env (), name, val); } + + static octave_value do_java_set (JNIEnv* jni_env, const std::string& class_name, + const std::string& name, const octave_value& val); + + static octave_value do_java_set (const std::string& class_name, const std::string& name, + const octave_value& val) + { return do_java_set (thread_jni_env (), class_name, name, val); } + +private: + void init (jobject jobj, jclass jcls) + { + JNIEnv *current_env = thread_jni_env (); + + if (current_env) + { + if (jobj) + java_object = current_env->NewGlobalRef (jobj); + if (jcls) + java_class = reinterpret_cast<jclass> (current_env->NewGlobalRef (jcls)); + else if (java_object) + { + jclass_ref ocls (current_env, current_env->GetObjectClass (java_object)); + java_class = reinterpret_cast<jclass> (current_env->NewGlobalRef (jclass (ocls))); + } + + if (java_class) + { + jclass_ref clsCls (current_env, current_env->GetObjectClass (java_class)); + jmethodID mID = current_env->GetMethodID (clsCls, "getCanonicalName", "()Ljava/lang/String;"); + jobject_ref resObj (current_env, current_env->CallObjectMethod (java_class, mID)); + java_type = jstring_to_string (current_env, resObj); + } + } + } + + void release () + { + JNIEnv *current_env = thread_jni_env (); + + if (current_env) + { + if (java_object) + current_env->DeleteGlobalRef (java_object); + if (java_class) + current_env->DeleteGlobalRef (java_class); + java_object = 0; + java_class = 0; + } + } + +private: + DECLARE_OCTAVE_ALLOCATOR + + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA + + jobject java_object; + jclass java_class; + std::string java_type; +}; + +#endif /* __JAVA__H__ */
--- a/libinterp/dldfcn/module-files +++ b/libinterp/dldfcn/module-files @@ -5,6 +5,7 @@ __glpk__.cc|$(GLPK_CPPFLAGS)|$(GLPK_LDFLAGS)|$(GLPK_LIBS) __init_fltk__.cc|$(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS)|$(GRAPHICS_LDFLAGS) $(FT2_LDFLAGS)|$(GRAPHICS_LIBS) $(FT2_LIBS) __init_gnuplot__.cc +__java__.cc|$(JAVA_CPPFLAGS)||$(JAVA_LIBS) __magick_read__.cc|$(MAGICK_CPPFLAGS)|$(MAGICK_LDFLAGS)|$(MAGICK_LIBS) __voronoi__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) amd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS)
--- a/libinterp/link-deps.mk +++ b/libinterp/link-deps.mk @@ -17,6 +17,7 @@ $(X11_LIBS) \ $(CARBON_LIBS) \ $(LLVM_LIBS) \ + $(JAVA_LIBS) \ $(LAPACK_LIBS) LIBOCTINTERP_LINK_OPTS = \
--- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -36,6 +36,8 @@ IMAGES = +JAR_FILES = + ## Read subdirs to set all variables above include @ftp/module.mk include audio/module.mk @@ -46,6 +48,7 @@ include help/module.mk include image/module.mk include io/module.mk +include java/module.mk include linear-algebra/module.mk include miscellaneous/module.mk include optimization/module.mk @@ -68,16 +71,16 @@ include testfun/module.mk include time/module.mk -nobase_fcnfile_DATA = $(FCN_FILES) $(GEN_FCN_FILES) +nobase_fcnfile_DATA = $(FCN_FILES) $(GEN_FCN_FILES) $(JAR_FILES) image_DATA = $(IMAGES) FCN_FILES_IN = $(GEN_FCN_FILES:.m=.in) if AMCOND_BUILD_DOCS -all-local: $(GEN_FCN_FILES) $(PKG_ADD_FILES) .DOCSTRINGS +all-local: $(GEN_FCN_FILES) $(PKG_ADD_FILES) $(JAR_FILES) .DOCSTRINGS else -all-local: $(GEN_FCN_FILES) $(PKG_ADD_FILES) +all-local: $(GEN_FCN_FILES) $(PKG_ADD_FILES) $(JAR_FILES) endif octave_dirstamp = $(am__leading_dot)dirstamp @@ -118,6 +121,10 @@ $(srcdir)/mk-pkg-add $(srcdir) $(io_FCN_FILES) -- $(io_GEN_FCN_FILES) > $@-t mv $@-t $@ +java/PKG_ADD: $(java_FCN_FILES) $(java_GEN_FCN_FILES) java/$(octave_dirstamp) mk-pkg-add + $(srcdir)/mk-pkg-add $(srcdir) $(java_FCN_FILES) -- $(java_GEN_FCN_FILES) > $@-t + mv $@-t $@ + linear-algebra/PKG_ADD: $(linear_algebra_FCN_FILES) $(linear_algebra_GEN_FCN_FILES) linear-algebra/$(octave_dirstamp) mk-pkg-add $(srcdir)/mk-pkg-add $(srcdir) $(linear_algebra_FCN_FILES) -- $(linear_algebra_GEN_FCN_FILES) > $@-t mv $@-t $@ @@ -211,6 +218,7 @@ $(help_GEN_FCN_FILES): help/$(octave_dirstamp) $(image_GEN_FCN_FILES): image/$(octave_dirstamp) $(io_GEN_FCN_FILES): io/$(octave_dirstamp) +$(java_GEN_FCN_FILES): java/$(octave_dirstamp) $(linear_algebra_GEN_FCN_FILES): linear-algebra/$(octave_dirstamp) $(miscellaneous_GEN_FCN_FILES): miscellaneous/$(octave_dirstamp) $(optimization_GEN_FCN_FILES): optimization/$(octave_dirstamp) @@ -260,6 +268,9 @@ io/$(octave_dirstamp): $(MKDIR_P) io : > io/$(octave_dirstamp) +java/$(octave_dirstamp): + $(MKDIR_P) java + : > java/$(octave_dirstamp) linear-algebra/$(octave_dirstamp): $(MKDIR_P) linear-algebra : > linear-algebra/$(octave_dirstamp)
new file mode 100644 --- /dev/null +++ b/scripts/java/dlgtest.m @@ -0,0 +1,255 @@ +% +% Install the java package. +% Test the dlg... functions of the java package. +% +% Author: Martin Hepperle +% Version August 2010 +% +function dlgtest ( reinstall ) + + % Windows example paths + if ispc() + % NOTE: do NOT use backslashes as separator, only forward slashes! + pkgpath = 'z:/java-1.2.8.tar.gz'; + java_home = getenv ("JAVA_HOME"); + elseif isunix() + % Linux example paths + pkgpath = '~/java-1.2.8.tar.gz'; + java_home = getenv ("JAVA_HOME"); + else + pkgpath = 'unknown'; + java_home = 'unknown'; + end + + if nargin<1 + disp('usage: dlgtest ( reinstall )'); + disp( 'where: reinstall = 0 : do not reinstall java package'); + disp([' reinstall = 1 : reinstall java package from ', pkgpath, ... + ', using Java JDK from ', java_home]); + return + end + + if ! exist (java_home, "dir") + disp(['Java JDK home directory ', java_home,' does not exist.']); + disp('Please adapt java_home in dlgtest.m.'); + return; + end + + if reinstall == 1 + if ! exist (pkgpath, "file") + disp(['Package file ', pkgpath, ' does not exist.']); + disp('Please adapt pkgpath in dlgtest.m.'); + return; + end + end + + page_screen_output(0); + + if reinstall == 1 + disp('- uninstalling package java'); + pkg uninstall java + + disp(['- installing package java from ',pkgpath]); + disp([' using JDK from ',java_home]); + setenv('JAVA_HOME',java_home) + %% pkg does not understand variables as arguments? + eval(['pkg install ', pkgpath]) + disp('Done.'); + end + + page_screen_output(1); + + answer = 1; + while (answer > 0 ) + + disp(''); + disp('0 ... STOP'); + disp('1 ... listdlg tests'); + disp('2 ... errordlg tests'); + disp('3 ... warndlg tests'); + disp('4 ... helpdlg tests'); + disp('5 ... inputdlg tests'); + disp('6 ... TeX code tests'); + + answer = str2num(input ('Run which test? [0] > ','s')); + + disp(''); + + switch answer + case 1 + test_listdlg(); + case 2 + test_errordlg(); + case 3 + test_warndlg(); + case 4 + test_helpdlg(); + case 5 + test_inputdlg(); + case 6 + test_TeXCodes(); + end + end + + % d = javaObject('javax.swing.JDialog'); + % cp = d.getContentPane; + % b = javaObject('javax.swing.JButton','OK'); + % cp.add(b); + % d.pack; + % d.setVisible(true); + + + page_screen_output(1); + +end + +function test_listdlg + + %----------------------------------------------- + disp('- test listdlg with selectionmode single. No caption, no prompt.'); + itemlist = {'An item \\alpha', 'another', 'yet another'}; + s = listdlg ( 'ListString',itemlist, 'SelectionMode','Single' ); + imax = length(s); + for i=1:1:imax + disp(['Selected: ',num2str(i),': ', itemlist{s(i)}]); + end + + %----------------------------------------------- + disp('- test listdlg with selectionmode and preselection. Has caption and two lines prompt.'); + s = listdlg ( 'ListString',itemlist, ... + 'SelectionMode','Multiple', ... + 'Name','Selection Dialog', ... + 'InitialValue',[1,2,3,4], + 'PromptString',{'Select an item...', '...or multiple items'} ); + imax = length(s); + for i=1:1:imax + disp(['Selected: ',num2str(i),': ', itemlist{s(i)}]); + end + +end + +function test_errordlg + %----------------------------------------------- + disp('- test errordlg with prompt only.'); + errordlg('Oops, an expected error occured'); + %----------------------------------------------- + disp('- test errordlg with prompt and caption.'); + errordlg('Oops another error','This is a very long and informative caption'); +end + +function test_warndlg + %----------------------------------------------- + disp('- test warndlg with prompt only.'); + warndlg('Oh, a warning occured'); + %----------------------------------------------- + disp('- test warndlg with prompt and caption.'); + warndlg('Oh, No...','This is the last Warning'); +end + +function test_helpdlg + %----------------------------------------------- + disp('- test helpdlg with a help message only.'); + helpdlg("Below, you should see 3 lines:\nline #1\nline #2, and\nline #3."); + %----------------------------------------------- + disp('- test helpdlg with help message and caption.'); + helpdlg('You should see a single line.','A help dialog'); +end + +function test_inputdlg + %----------------------------------------------- + disp('- test inputdlg with prompt and caption only.'); + prompt = {'Width','Height','Depth'}; + dims = inputdlg ( prompt, 'Enter Box Dimensions' ); + if isempty(dims) + helpdlg('Canceled by user', 'Information'); + else + volume = str2num(dims{1}) * str2num(dims{2}) * str2num(dims{3}); + surface = 2 * (str2num(dims{1}) * str2num(dims{2}) + ... + str2num(dims{2}) * str2num(dims{3}) + ... + str2num(dims{1}) * str2num(dims{3})); + helpdlg(sprintf('Results:\nVolume = %.3f\nSurface = %.3f', volume, surface), 'Box Dimensions'); + end + + %----------------------------------------------- + disp('- test inputdlg with prescribed scalar (2 lines per text field) and defaults.'); + prompt = {'Width','Height','Depth'}; + default = {'1.1','2.2','3.3'}; + rc = 2; + dims = inputdlg ( prompt, 'Enter Box Dimensions',rc,default ); + if isempty(dims) + helpdlg('Canceled by user', 'Information'); + else + volume = str2num(dims{1}) * str2num(dims{2}) * str2num(dims{3}); + surface = 2 * (str2num(dims{1}) * str2num(dims{2}) + ... + str2num(dims{2}) * str2num(dims{3}) + ... + str2num(dims{1}) * str2num(dims{3})); + helpdlg(sprintf('Results:\nVolume = %.3f\nSurface = %.3f', volume, surface), 'Box Dimensions'); + end + %----------------------------------------------- + disp('- test inputdlg with prescribed vector [1,2,3] for # of lines per text field and defaults.'); + prompt = {'Width','Height','Depth'}; + default = {'1.10', '2.10', '3.10'}; + rc = [1,2,3]; % NOTE: must be an array + dims = inputdlg ( prompt, 'Enter Box Dimensions',rc,default ); + if isempty(dims) + helpdlg('Canceled by user', 'Information'); + else + volume = str2num(dims{1}) * str2num(dims{2}) * str2num(dims{3}); + surface = 2 * (str2num(dims{1}) * str2num(dims{2}) + ... + str2num(dims{2}) * str2num(dims{3}) + ... + str2num(dims{1}) * str2num(dims{3})); + helpdlg(sprintf('Results:\nVolume = %.3f\nSurface = %.3f', volume, surface), 'Box Dimensions'); + end + %----------------------------------------------- + disp('- test inputdlg with prescribed row by column sizes and defaults.'); + prompt = {'Width','Height','Depth'}; + default = {'1.10', '2.20', '3.30'}; + rc = [1,10; 2,20; 3,30]; % NOTE: must be an array + dims = inputdlg ( prompt, 'Enter Box Dimensions',rc,default ); + if isempty(dims) + helpdlg('Canceled by user', 'Information'); + else + volume = str2num(dims{1}) * str2num(dims{2}) * str2num(dims{3}); + surface = 2 * (str2num(dims{1}) * str2num(dims{2}) + ... + str2num(dims{2}) * str2num(dims{3}) + ... + str2num(dims{1}) * str2num(dims{3})); + helpdlg(sprintf('Results:\nVolume = %.3f\nSurface = %.3f', volume, surface), 'Box Dimensions'); + end +end + +%% show a table of TeX symbol codes and the resulting Unicode character +function test_TeXCodes + %----------------------------------------------- + disp('- test TeX code to Unicode translation.'); + + msgbox ( ['\\alpha = ''\alpha '' \\beta = ''\beta '' \\gamma = ''\gamma ''', 10, ... + '\\delta = ''\delta '' \\epsilon = ''\epsilon '' \\zeta = ''\zeta ''', 10, ... + '\\eta = ''\eta '' \\theta = ''\theta '' \\vartheta = ''\vartheta ''', 10, ... + '\\iota = ''\iota '' \\kappa = ''\kappa '' \\lambda = ''\lambda ''', 10, ... + '\\mu = ''\mu '' \\nu = ''\nu '' \\xi = ''\xi ''', 10, ... + '\\pi = ''\pi '' \\rho = ''\rho '' \\sigma = ''\sigma ''', 10, ... + '\\varsigma = ''\varsigma '' \\tau = ''\tau '' \\phi = ''\phi ''', 10, ... + '\\chi = ''\chi '' \\psi = ''\psi '' \\omega = ''\omega ''', 10, ... + '\\upsilon = ''\upsilon '' \\Gamma = ''\Gamma '' \\Delta = ''\Delta ''', 10, ... + '\\Theta = ''\Theta '' \\Lambda = ''\Lambda '' \\Pi = ''\Pi ''', 10, ... + '\\Xi = ''\Xi '' \\Sigma = ''\Sigma '' \\Upsilon = ''\Upsilon ''', 10, ... + '\\Phi = ''\Phi '' \\Psi = ''\Psi '' \\Omega = ''\Omega ''', 10, ... + '\\Im = ''\Im '' \\Re = ''\Re '' \\leq = ''\leq ''', 10, ... + '\\geq = ''\geq '' \\neq = ''\neq '' \\pm = ''\pm ''', 10, ... + '\\infty = ''\infty '' \\partial = ''\partial '' \\approx = ''\approx ''', 10, ... + '\\circ = ''\circ '' \\bullet = ''\bullet '' \\times = ''\times ''', 10, ... + '\\sim = ''\sim '' \\nabla = ''\nabla '' \\ldots = ''\ldots ''', 10, ... + '\\exists = ''\exists '' \\neg = ''\neg '' \\aleph = ''\aleph ''', 10, ... + '\\forall = ''\forall '' \\cong = ''\cong '' \\wp = ''\wp ''', 10, ... + '\\propto = ''\propto '' \\otimes = ''\otimes '' \\oplus = ''\oplus ''', 10, ... + '\\oslash = ''\oslash '' \\cap = ''\cap '' \\cup = ''\cup ''', 10, ... + '\\ni = ''\ni '' \\in = ''\in '' \\div = ''\div ''', 10, ... + '\\equiv = ''\equiv '' \\int = ''\int '' \\perp = ''\perp ''', 10, ... + '\\wedge = ''\wedge '' \\vee = ''\vee '' \\supseteq = ''\supseteq ''', 10, ... + '\\supset = ''\supset '' \\subseteq = ''\subseteq '' \\subset = ''\subset ''', 10, ... + '\\clubsuit = ''\clubsuit '' \\spadesuit = ''\spadesuit '' \\heartsuit = ''\heartsuit ''', 10, ... + '\\diamondsuit = ''\diamondsuit '' \\copyright = ''\copyright '' \\leftarrow = ''\leftarrow ''', 10, ... + '\\uparrow = ''\uparrow '' \\rightarrow = ''\rightarrow '' \\downarrow = ''\downarrow ''', 10, ... + '\\leftrightarrow = ''\leftrightarrow '' \\updownarrow = ''\updownarrow '''], ... + 'TeX symbol code table Test'); +end
new file mode 100644 --- /dev/null +++ b/scripts/java/errordlg.m @@ -0,0 +1,37 @@ +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{P} =} errordlg (@var{MESSAGE} [,@var{TITLE}]) +## +## Displays the @var{MESSAGE} using an error dialog box. +## The @var{TITLE} can be used optionally to decorate the dialog caption. +## The return value is always 1. +## +## @end deftypefn +## @seealso{helpdlg, inputdlg, listdlg, questdlg, warndlg} + +function ret = errordlg(message,varargin) + + switch length (varargin) + case 0 + title = "Error Dialog"; + otherwise + title = varargin{1}; + endswitch + + ret = java_invoke ("org.octave.JDialogBox", "errordlg", message, title); + +endfunction
new file mode 100644 --- /dev/null +++ b/scripts/java/helpdlg.m @@ -0,0 +1,38 @@ +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{P} =} helpdlg (@var{MESSAGE} [,@var{TITLE}]) +## +## Displays a @var{MESSAGE} in a help dialog box. +## The help message can have multiple lines, separated by a newline character '\n'. +## The @var{TITLE} can be used optionally to decorate the dialog caption. +## The return value is always 1. +## +## @end deftypefn +## @seealso{errordlg, inputdlg, listdlg, questdlg, warndlg} + +function ret = helpdlg(message,varargin) + + switch length (varargin) + case 0 + title = "Help Dialog"; + otherwise + title = varargin{1}; + endswitch + + ret = java_invoke ("org.octave.JDialogBox", "helpdlg", message, title); + +endfunction
new file mode 100644 --- /dev/null +++ b/scripts/java/inputdlg.m @@ -0,0 +1,106 @@ +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{P} =} inputdlg (@var{PROMPT} [,@var{TITLE} [,@var{ROWSCOLS}, @var{DEFAULTS}]]) +## +## Returns the user's inputs from a multi-textfield dialog box in form of a cell array of strings. +## If the dialog is closed by the Cancel button, an empty cell array is returned. +## +## @table @samp +## @item PROMPT +## The first argument @var{PROMPT} is mandatory. +## It is a cell array with strings labeling each textfield. +## @item TITLE +## The optional string @var{TITLE} can be used as the caption of the dialog. +## @item ROWSCOLS +## The size of the text fields can be defined by the argument @var{ROWSCOLS}, +## which can have three forms: +## - a scalar value which defines the number of rows used for each text field. +## - a vector which defines the individual number of rows used for each text field. +## - a matrix which defines the individual number of rows and columns used for each text field. +## @item DEFAULTS +## It is possible to place default values into the text fields by supplying +## the a cell array of strings or number for the argument @var{DEFAULTS}. +## @end table +## +## @end deftypefn +## @seealso{errordlg, helpdlg, listdlg, questdlg, warndlg} + +function varargout = inputdlg(prompt,varargin) + + switch length (varargin) + case 0 + title = "Input Dialog"; + lineNo = 1; + defaults = cellstr(cell(size(prompt))); + case 1 + title = varargin{1}; + lineNo = 1; + defaults = cellstr(cell(size(prompt))); + case 2 + title = varargin{1}; + lineNo = varargin{2}; + defaults = cellstr(cell(size(prompt))); + otherwise + title = varargin{1}; + lineNo = varargin{2}; + defaults = varargin{3}; + end + + + % specification of text field sizes as in Matlab + % Matlab requires a matrix for lineNo, not a cell array... + % rc = [1,10; 2,20; 3,30]; + % c1 c2 + % r1 1 10 first text field is 1x10 + % r2 2 20 second text field is 2x20 + % r3 3 30 third text field is 3x30 + if isscalar(lineNo) + % only scalar value in lineTo, copy from lineNo and add defaults + rowscols = zeros(size(prompt)(2),2); + % cols + rowscols(:,2) = 25; + rowscols(:,1) = lineNo; + elseif isvector(lineNo) + % only one column in lineTo, copy from vector lineNo and add defaults + rowscols = zeros(size(prompt)(2),2); + % rows from colum vector lineNo, columns are set to default + rowscols(:,2) = 25; + rowscols(:,1) = lineNo(:); + elseif ismatrix(lineNo) + if (size(lineNo)(1) == size(prompt)(2)) && (size(lineNo)(2) == 2) + % (rows x columns) match, copy array lineNo + rowscols = lineNo; + end + else + % dunno + disp('inputdlg: unknown form of lineNo argument.'); + lineNo + end + + % convert numeric values in defaults cell array to strings + defs = cellfun(@num2str,defaults,'UniformOutput',false); + rc = arrayfun(@num2str,rowscols,'UniformOutput',false); + + user_inputs = java_invoke ("org.octave.JDialogBox", "inputdlg", prompt, title, rc, defs); + + if isempty(user_inputs) + varargout{1} = {}; % empty + else + varargout{1} = cellstr (user_inputs); + end + +end
new file mode 100755 --- /dev/null +++ b/scripts/java/java.m @@ -0,0 +1,19 @@ +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## Please enter @code{doc java} to view the documentation for +## the package @code{java}. +##
new file mode 100644 --- /dev/null +++ b/scripts/java/javaArray.m @@ -0,0 +1,48 @@ +## Copyright (C) 2007 Michael Goffioul +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{a} =} javaArray (@var{class},@var{[M,N,...]}) +## @deftypefnx {Function file} {@var{a} =} javaArray (@var{class},@var{M},@var{N},...) +## +## Creates a Java array of size [@var{M},@var{N},...] with elements of +## class @var{class}. @var{class} can be a Java object representing a class +## or a string containing the fully qualified class name. +## +## The generated array is uninitialized, all elements are set to null +## if @var{class} is a reference type, or to a default value (usually 0) +## if @var{class} is a primitive type. +## +## @example +## a = javaArray ("java.lang.String", 2, 2); +## a(1,1) = "Hello"; +## @end example +## +## @end deftypefn + +function [ ret ] = javaArray (class_name, varargin) + + switch length (varargin) + case 0 + error ("missing array size"); + case 1 + dims = varargin{1}; + otherwise + dims = [varargin{:}]; + endswitch + + ret = java_invoke ("org.octave.ClassHelper", "createArray", class_name, dims); + +endfunction
new file mode 100644 --- /dev/null +++ b/scripts/java/javaaddpath.m @@ -0,0 +1,44 @@ +## Copyright (C) 2007 Michael Goffioul +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {} javaaddpath (@var{path}) +## +## Adds @var{path} to the dynamic class path of the Java virtual +## machine. @var{path} can be either a directory where .class files +## can be found, or a .jar file containing Java classes. +## +## @end deftypefn +## @seealso{javaclasspath} + +function javaaddpath (class_path) + + if (nargin != 1) + print_usage (); + else + % MH 30-08-2010: added tilde_expand to allow for specification of user's home + new_path = canonicalize_file_name (tilde_expand (class_path)); + if (exist (new_path, "dir")) + if (! strcmp (new_path (end), filesep)) + new_path = [new_path, filesep]; + endif + elseif (! exist (new_path, "file")) + error ("invalid Java classpath: %s", class_path); + endif + success = java_invoke ("org.octave.ClassHelper", "addClassPath", new_path); + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/scripts/java/javaclasspath.m @@ -0,0 +1,106 @@ +## Copyright (C) 2007 Michael Goffioul, 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {} javaclasspath +## @deftypefnx {Function file} {@var{STATIC} =} javaclasspath +## @deftypefnx {Function file} {[@var{STATIC}, @var{DYNAMIC}] =} javaclasspath +## @deftypefnx {Function file} {@var{PATH} =} javaclasspath (@var{WHAT}) +## +## Returns the class path of the Java virtual machine in +## the form of a cell array of strings. +## +## If called without input parameter:@* +## @itemize +## @item If no output variable is given, the result is simply printed +## on the standard output. +## @item If one output variable @var{STATIC} is given, the result is +## the static classpath. +## @item If two output variables @var{STATIC} and @var{DYNAMIC} are +## given, the first variable will contain the static classpath, +## the second will be filled with the dynamic claspath. +## @end itemize +## +## If called with a single input parameter @var{WHAT}:@* +## @itemize +## @item If @var{WHAT} is '-static' the static classpath is returned. +## @item If @var{WHAT} is '-dynamic' the dynamic classpath is returned. +## @item If @var{WHAT} is '-all' the static and the dynamic classpath +## are returned in a single cell array +## @end itemize +## @end deftypefn +## @seealso{javaaddpath,javarmpath} + +function varargout = javaclasspath (which) + + % dynamic classpath + dynamic_path = java_invoke ("org.octave.ClassHelper", "getClassPath"); + dynamic_path_list = strsplit (dynamic_path, pathsep ()); + + % static classpath + static_path = java_invoke ('java.lang.System', 'getProperty', 'java.class.path'); + static_path_list = strsplit (static_path, pathsep ()); + if (length (static_path_list) > 1) + % remove first element (which is .../octave.jar) + static_path_list = static_path_list(2:length (static_path_list)); + else + static_path_list = {}; + end + + switch nargin + case 0 + switch nargout + case 0 + disp_path_list ( 'STATIC', static_path_list ) + disp(''); + disp_path_list ( 'DYNAMIC', dynamic_path_list ) + case 1 + varargout{1} = cellstr (dynamic_path_list); + case 2 + varargout{1} = cellstr (dynamic_path_list); + varargout{2} = cellstr (static_path_list); + endswitch + + case 1 + switch nargout + case 0 + if (strcmp (which, '-static') == 1) + disp_path_list ( 'STATIC', static_path_list ) + elseif (strcmp (which, '-dynamic') == 1) + disp_path_list ( 'DYNAMIC', dynamic_path_list ) + end + case 1 + if (strcmp (which, '-static') == 1) + varargout{1} = cellstr (static_path_list); + elseif (strcmp (which, '-dynamic') == 1) + varargout{1} = cellstr (dynamic_path_list); + elseif (strcmp (which, '-all') == 1) + varargout{1} = cellstr ([static_path_list, dynamic_path_list]); + end + endswitch + endswitch + +end +# +# Display cell array of paths +# +function disp_path_list ( which, path_list ) + printf (' %s JAVA PATH\n\n', which); + if (length (path_list) > 0) + printf (' %s\n', path_list{:}); + else + printf (' - empty -\n'); + endif +end
new file mode 100755 --- /dev/null +++ b/scripts/java/javafields.m @@ -0,0 +1,44 @@ +## Copyright (C) 2007 Michael Goffioul +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{P} =} javafields (@var{class}) +## +## Returns the fields of a Java object in the form of a cell +## array of strings. If no output variable is +## given, the result is simply printed on the standard output. +## +## @end deftypefn +## @seealso{javamethods} + +function varargout = javafields(classname) + + if (nargin != 1) + print_usage (); + else + c_methods = java_invoke ("org.octave.ClassHelper", "getFields",classname); + method_list = strsplit (c_methods, ';'); + + switch nargout + case 0 + if (! isempty (method_list)) + disp(method_list); + endif + case 1 + varargout{1} = cellstr (method_list); + endswitch + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/scripts/java/javamem.m @@ -0,0 +1,84 @@ +## Copyright (C) 2010 Philip Nienhuis, <prnienhuis@users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} javamem +## @deftypefnx {Function File} [@var{jmem}] = javamem +## Show current memory status of the Java virtual machine (JVM) +## & run garbage collector. +## +## When no return argument is given the info is echoed to the screen. +## Otherwise, output cell array @var{jmem} contains Maximum, Total, +## and Free memory (in bytes). +## +## All Java-based routines are run in the JVM's shared memory pool, +## a dedicated and separate part of memory claimed by the JVM from +## your computer's total memory (which comprises physical RAM and +## virtual memory / swap space on hard disk). +## +## The maximum available memory can be set using the file java.opts +## (in the same subdirectory where javaaddpath.m lives, see +## "which javaaddpath". Usually that is: @* +## [/usr]/share/octave/packages/java-<version>. +## +## java.opts is a plain text file, one option per line. The +## default initial memory size and default maximum memory size (which +## are both system dependent) can be overridden like so: @* +## -Xms64m @* +## -Xmx512m @* +## (in megabytes in this example.) +## You can adapt these values to your own requirements if your system +## has limited available physical memory or when you get Java memory +## errors. +## +## "Total memory" is what the operating system has currently assigned +## to the JVM and depends on actual and active memory usage. +## "Free memory" is self-explanatory. During operation of Java-based +## octave functions the amounts of Total and Free memory will vary, +## due to Java's own cleaning up and your operating system's memory +## management. +## +## @end deftypefn + +## Author: Philip Nienhuis +## Created: 2010-03-25 +## Updates: +## 2010-03-26 Changed name to javamem & indentation to double spaces +## 2010-08-25 Corrected text on java memory assignments +## 2010-09-05 Further overhauled help text + +function [ j_mem ] = javamem () + + rt = java_invoke ('java.lang.Runtime', 'getRuntime'); + rt.gc; + jmem = cell (3, 1); + jmem{1} = rt.maxMemory ().doubleValue (); + jmem{2} = rt.totalMemory ().doubleValue (); + jmem{3} = rt.freeMemory ().doubleValue (); + + if (nargout < 1) + printf ("\nJava virtual machine (JVM) memory info:\n"); + printf ("Maximum available memory: %5d MiB;\n", jmem{1} / 1024 / 1024); + printf (" (...running garbage collector...)\n"); + printf ("OK, current status:\n"); + printf ("Total memory in virtual machine: %5d MiB;\n", jmem{2} / 1024 / 1024); + printf ("Free memory in virtual machine: %5d MiB;\n", jmem{3} / 1024 / 1024); + printf ("%d CPUs available.\n", rt.availableProcessors ()); + else + j_mem = jmem; + endif + +endfunction
new file mode 100755 --- /dev/null +++ b/scripts/java/javamethods.m @@ -0,0 +1,44 @@ +## Copyright (C) 2007 Michael Goffioul +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{P} =} javamethods (@var{class}) +## +## Returns the methods of a Java object in the form of a cell +## array of strings. If no output variable is +## given, the result is simply printed on the standard output. +## +## @end deftypefn +## @seealso{methods} + +function varargout = javamethods (classname) + + if (nargin != 1) + print_usage (); + else + c_methods = java_invoke ("org.octave.ClassHelper", "getMethods", classname); + method_list = strsplit (c_methods, ';'); + + switch nargout + case 0 + if (! isempty (method_list)) + disp(method_list); + endif + case 1 + varargout{1} = cellstr (method_list); + endswitch + endif + +endfunction
new file mode 100755 --- /dev/null +++ b/scripts/java/javarmpath.m @@ -0,0 +1,45 @@ +## Copyright (C) 2007 Michael Goffioul +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {} javarmpath (@var{path}) +## +## Removes @var{path} from the dynamic class path of the Java virtual +## machine. @var{path} can be either a directory where .class files +## can be found, or a .jar file containing Java classes. +## +## @end deftypefn +## @seealso{javaaddpath,javaclasspath} + +function javarmpath (class_path) + + if (nargin != 1) + print_usage (); + else + % MH 30-08-2010: added tilde_expand to allow for specification of user's home + old_path = canonicalize_file_name (tilde_expand(class_path)); + if (exist (old_path, "dir")) + if (! strcmp (old_path (end), filesep)) + old_path = [old_path, filesep]; + end + end + success = java_invoke ('org.octave.ClassHelper', 'removeClassPath', old_path); + if (! success) + disp (['Warning: ', old_path, ' not found in Java classpath.', 10]); + end + end + +end
new file mode 100644 --- /dev/null +++ b/scripts/java/listdlg.m @@ -0,0 +1,126 @@ +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{[SEL,OK]} =} listdlg (@var{KEY} ,@var{VALUE} [, @var{KEY} ,@var{VALUE}, ...]]) +## +## Returns the user's inputs from a list dialog box in form of a vector of +## selection indices SEL and a flag OK indicating how the user closed the dialog box. +## The returned flag OK is 1 if the user closed the box with the OK button, +## otherwise it is 0 and SEL is empty. +## The indices in SEL are 1 based, i.e. the first list item carries the index 1. +## +## The arguments are specified in form of @var{KEY}, @var{VALUE} pairs. +## At least the 'ListString' argument pair must be specified. +## +## @var{KEY}s and @var{VALUE}s pairs can be selected from the following list: +## +## @table @samp +## @item ListString +## a cell array of strings comprising the content of the list. +## @item SelectionMode +## can be either @samp{Single} or @samp{Multiple}. +## @item ListSize +## a vector with two elements [width, height] defining the size of the list field in pixels. +## @item InitialValue +## a vector containing 1-based indices of preselected elements. +## @item Name +## a string to be used as the dialog caption. +## @item PromptString +## a cell array of strings to be displayed above the list field. +## @item OKString +## a string used to label the OK button. +## @item CancelString +## a string used to label the Cancel button. +## @end table +## +## Example: +## +## @example +## [sel, ok] = listdlg ( 'ListString',@{'An item', 'another', 'yet another'@}, 'SelectionMode','Multiple' ); +## if ok == 1 +## imax = length(sel); +## for i=1:1:imax +## disp(sel(i)); +## end +## end +## @end example +## +## @end deftypefn +## @seealso{errordlg, helpdlg, inputdlg, questdlg, warndlg} + +function varargout = listdlg(varargin) + + if nargin < 2 + print_usage (); + return; + end + + listcell = {''}; + selmode = 'single'; + listsize = [300,160]; % vector! + initialvalue = [1]; % vector! + name = ''; + prompt = {''}; + okstring = 'OK'; + cancelstring = 'Cancel'; + + % handle key, value pairs + for i=1:2:nargin-1 + if strcmp(varargin{i},'ListString') + listcell = varargin{i+1}; + elseif strcmp(varargin{i},'SelectionMode') + selmode = varargin{i+1}; + elseif strcmp(varargin{i},'ListSize') + listsize = varargin{i+1}; + elseif strcmp(varargin{i},'InitialValue') + initialvalue = varargin{i+1}; + elseif strcmp(varargin{i},'Name') + name = varargin{i+1}; + elseif strcmp(varargin{i},'PromptString') + prompt = varargin{i+1}; + elseif strcmp(varargin{i},'OKString') + okstring = varargin{i+1}; + elseif strcmp(varargin{i},'CancelString') + cancelstring = varargin{i+1}; + end + end + + % make sure prompt strings are a cell array + if ! iscell(prompt) + prompt = {prompt}; + end + + % make sure listcell strings are a cell array + if ! iscell(listcell) + listcell = {listcell}; + end + + + % transform matrices to cell arrays of strings + listsize = arrayfun(@num2str,listsize,'UniformOutput',false); + initialvalue = arrayfun(@num2str,initialvalue,'UniformOutput',false); + + ret = java_invoke ('org.octave.JDialogBox', 'listdlg', listcell, ... + selmode, listsize, initialvalue, name, prompt, ... + okstring, cancelstring ); + if length(ret) > 0 + varargout = {ret, 1}; + else + varargout = {{}, 0}; + end + + +end
new file mode 100644 --- /dev/null +++ b/scripts/java/module.mk @@ -0,0 +1,78 @@ +FCN_FILE_DIRS += java + +EXTRA_DIST += java/octave.jar + +java_FCN_FILES = \ + java/dlgtest.m \ + java/errordlg.m \ + java/helpdlg.m \ + java/inputdlg.m \ + java/java.m \ + java/javaArray.m \ + java/javaaddpath.m \ + java/javaclasspath.m \ + java/javafields.m \ + java/javamem.m \ + java/javamethods.m \ + java/javarmpath.m \ + java/listdlg.m \ + java/msgbox.m \ + java/questdlg.m \ + java/warndlg.m + +FCN_FILES += $(java_FCN_FILES) + +PKG_ADD_FILES += java/PKG_ADD + +DIRSTAMP_FILES += java/$(octave_dirstamp) + +JAR_FILES += java/octave.jar + +org_octave_dir = org/octave + +JAVA_SRC = \ + $(org_octave_dir)/ClassHelper.java \ + $(org_octave_dir)/OctClassLoader.java \ + $(org_octave_dir)/Octave.java \ + $(org_octave_dir)/OctaveReference.java \ + $(org_octave_dir)/Matrix.java \ + $(org_octave_dir)/JDialogBox.java \ + $(org_octave_dir)/DlgListener.java \ + $(org_octave_dir)/TeXtranslator.java \ + $(org_octave_dir)/TeXcode.java + +JAVA_CLASSES = $(JAVA_SRC:.java=.class) + +JAVA_IMAGES = \ + $(org_octave_dir)/images/question.png \ + $(org_octave_dir)/images/error.png \ + $(org_octave_dir)/images/warning.png \ + $(org_octave_dir)/images/information.png \ + $(org_octave_dir)/images/octave.png + +java_JAVA_SRC = $(addprefix java/, $(JAVA_SRC)) + +java_JAVA_CLASSES = $(addprefix java/, $(JAVA_CLASSES)) + +java_JAVA_IMAGES = $(addprefix java/, $(JAVA_IMAGES)) + +java_JAVA_IMAGES_src = $(addprefix $(srcdir)/java/, $(JAVA_IMAGES)) + +java_JAVA_CLASSES_src = $(addprefix $(srcdir)/java/, $(java_JAVA_CLASSES)) + +%.class : %.java + $(MKDIR_P) java/$(org_octave_dir) + ( cd $(srcdir)/java; $(JAVAC) -source 1.3 -target 1.3 -d $(abs_builddir)/java $(org_octave_dir)/$(<F) ) + +java/images.stamp: $(java_JAVA_IMAGES_src) + if [ "x$(srcdir)" != "x." ]; then \ + $(MKDIR_P) java/$(org_octave_dir)/images; \ + cp $(java_JAVA_IMAGES_src) java/$(org_octave_dir)/images; \ + fi + touch $@ + +java/octave.jar: java/images.stamp $(java_JAVA_CLASSES) + ( cd java; $(JAR) cf octave.jar.t $(JAVA_CLASSES) $(JAVA_IMAGES) ) + mv $@.t $@ + +EXTRA_DIST += $(java_JAVA_SRC) $(java_JAVA_IMAGES)
new file mode 100644 --- /dev/null +++ b/scripts/java/msgbox.m @@ -0,0 +1,54 @@ +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{P} =} msgbox (@var{MESSAGE} [,@var{TITLE} [,@var{ICON}]]) +## +## Displays the @var{MESSAGE} using a message dialog. +## The @var{TITLE} is an optional string, which can be used to decorate the dialog caption. +## The @var{ICON} can be used optionally to select a dialog icon. +## It can be one of @code{'error'}, @code{'help'} or @code{'warn'}. +## The return value is always 1. +## +## @end deftypefn +## @seealso{helpdlg, questdlg, warndlg} + +function ret = msgbox(message,varargin) + + switch length (varargin) + case 0 + title = ""; + dlg = 'emptydlg'; + case 1 + title = varargin{1}; + dlg = 'emptydlg'; + otherwise + % two or more arguments + title = varargin{1}; + icon = varargin{2}; + if strcmp(icon,'error') == 1 + dlg = 'errordlg'; + elseif strcmp(icon,'help') == 1 + dlg = 'helpdlg'; + elseif strcmp(icon,'warn') == 1 + dlg = 'warndlg'; + else + dlg = 'emptydlg'; + end + endswitch + + ret = java_invoke ('org.octave.JDialogBox', dlg, message, title ); + +endfunction
new file mode 100644 --- /dev/null +++ b/scripts/java/org/octave/ClassHelper.java @@ -0,0 +1,955 @@ +/* Copyright (C) 2007 Michael Goffioul + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with this program; If not, see <http://www.gnu.org/licenses/>. + */ + +package org.octave; + +import java.lang.reflect.*; + +public class ClassHelper +{ + private static OctClassLoader loader; + + static + { + ClassLoader l = ClassHelper.class.getClassLoader (); + loader = ( l instanceof OctClassLoader ? ( OctClassLoader ) l : + new OctClassLoader ( l ) ); + } + + + /** + * Add the given path to the classpath. + * @param name String - path to addd to the classpath + * @return boolean - true if the given path exists and was added to the classpath. + * @throws Exception + */ + public static boolean addClassPath ( String name ) + throws Exception + { + boolean found = false; + java.io.File f = new java.io.File ( name ); + if ( f.exists () ) + { + loader.addClassPath ( name ); + found = true; + } + return ( found ); + } + + + // new -MH- + /** + * + * @param name String - path to remove from classpath. + * @return boolean - true if the given path existed in the classpath before it was removed. + * @throws Exception + */ + public static boolean removeClassPath ( String name ) + throws Exception + { + boolean found = false; + java.io.File f = new java.io.File ( name ); + java.net.URL urlToRemove = f.toURI ().toURL (); + // save urls in current class path + java.net.URL[] urls = loader.getURLs (); + + // create a completely new class loader because java.net.URLClassLoader has no removeClassPath() method + ClassLoader l = ClassHelper.class.getClassLoader (); + loader = ( l instanceof OctClassLoader ? ( OctClassLoader ) l : + new OctClassLoader ( l ) ); + + // add the previous urls back, except for the one + for ( int i = 0; i < urls.length; i++ ) + { + java.net.URL url = urls[i]; + if ( !url.equals ( urlToRemove ) ) + { + loader.addURL ( url ); + } + else + { + // path to remove + found = true; + } + } + + return ( found ); + } + + + public static String getClassPath () + { + StringBuffer buf = new StringBuffer (); + String pathSep = System.getProperty ( "path.separator" ); + java.net.URL[] urls = loader.getURLs (); + + for ( int i = 0; i < urls.length; i++ ) + { + try + { + java.io.File f = new java.io.File ( urls[i].toURI () ); + if ( buf.length () > 0 ) + { + buf.append ( pathSep ); + } + buf.append ( f.toString () ); + } + catch ( java.net.URISyntaxException ex ) + {} + } + return buf.toString (); + } + + + // new -MH- + // return list of methods for given class name + public static String getMethods ( String classname ) + throws ClassNotFoundException + { + return ( getMethods ( Class.forName ( classname ) ) ); + } + + + // new -MH- + // return list of methods for given class instance + public static String getMethods ( Object obj ) + throws ClassNotFoundException + { + return ( getMethods ( obj.getClass () ) ); + } + + + // new -MH- + // return list of methods for given class + public static String getMethods ( Class klass ) + { + StringBuffer sb = new StringBuffer (); + + Method theMethod[] = klass.getMethods (); + for ( int i = 0; i < theMethod.length; i++ ) + { + if ( i > 0 ) + { + sb.append ( ";" ); + } + sb.append ( theMethod[i].getReturnType ().getCanonicalName () ); + sb.append ( " " ); + sb.append ( theMethod[i].getName () ); + sb.append ( "(" ); + + Class theParameter[] = theMethod[i].getParameterTypes (); + for ( int j = 0; j < theParameter.length; j++ ) + { + if ( j > 0 ) + { + sb.append ( ", " ); + } + sb.append ( theParameter[j].getCanonicalName () ); + } + sb.append ( ")" ); + + Class theExceptions[] = theMethod[i].getExceptionTypes (); + if ( theExceptions.length > 0 ) + { + sb.append ( " throws " ); + for ( int j = 0; j < theExceptions.length; j++ ) + { + if ( j > 0 ) + { + sb.append ( ", " ); + } + sb.append ( theExceptions[j].getCanonicalName () ); + } + } + } + + return ( sb.toString () ); + } + + + // new -MH- + // return list of fields for given class + public static String getFields ( Class klass ) + { + StringBuffer sb = new StringBuffer (); + + Field theField[] = klass.getFields (); + for ( int i = 0; i < theField.length; i++ ) + { + if ( i > 0 ) + { + sb.append ( ";" ); + } + sb.append ( theField[i].toString () ); + } + + return ( sb.toString () ); + } + + + // new -MH- + // return list of fields for given class name + public static String getFields ( String classname ) + throws ClassNotFoundException + { + return ( getFields ( Class.forName ( classname ) ) ); + } + + + // new -MH- + // return list of fields for given class instance + public static String getFields ( Object obj ) + throws ClassNotFoundException + { + return ( getFields ( obj.getClass () ) ); + } + + + public static Method findMethod ( Class cls, String name, Class[] argTypes ) + { + try + { + return cls.getMethod ( name, argTypes ); + } + catch ( Exception e ) + { + Method[] mList = cls.getMethods (); + Method m; + for ( int i = 0; i < mList.length; i++ ) + { + m = mList[i]; + if ( m.getName ().equals ( name ) && + m.getParameterTypes ().length == argTypes.length && + isCallableFrom ( m, argTypes ) ) + { + return m; + } + } + return null; + } + } + + + public static Constructor findConstructor ( Class cls, Class[] argTypes ) + { + try + { + return cls.getConstructor ( argTypes ); + } + catch ( Exception e ) + { + Constructor[] cList = cls.getConstructors (); + //System.out.println("# constructors: " + cList.length); + Constructor c; + for ( int i = 0; i < cList.length; i++ ) + { + //System.out.println("Considering constructor: " + cList[i]); + c = cList[i]; + if ( c.getParameterTypes ().length == argTypes.length && + isCallableFrom ( c, argTypes ) ) + { + return c; + } + } + return null; + } + } + + + private static Object invokeMethod ( Method m, Object target, Object[] args ) + throws Exception + { + try + { + return m.invoke ( target, args ); + } + catch ( IllegalAccessException ex ) + { + String mName = m.getName (); + Class[] pTypes = m.getParameterTypes (); + Class currClass = target.getClass (); + + while ( currClass != null ) + { + try + { + Method meth = currClass.getMethod ( mName, pTypes ); + if ( !meth.equals ( m ) ) + { + return meth.invoke ( target, args ); + } + } + catch ( NoSuchMethodException ex2 ) + {} + catch ( IllegalAccessException ex2 ) + {} + + Class[] ifaceList = currClass.getInterfaces (); + for ( int i = 0; i < ifaceList.length; i++ ) + { + try + { + Method meth = ifaceList[i].getMethod ( mName, pTypes ); + return meth.invoke ( target, args ); + } + catch ( NoSuchMethodException ex2 ) + {} + catch ( IllegalAccessException ex2 ) + {} + } + + currClass = currClass.getSuperclass (); + } + + throw ex; + } + } + + + public static Object invokeMethod ( Object target, String name, + Object[] args, Class[] argTypes ) + throws Throwable + { + Method m = findMethod ( target.getClass (), name, argTypes ); + if ( m != null ) + { + try + { + Object result = invokeMethod ( m, target, + castArguments ( args, argTypes, + m.getParameterTypes () ) ); + return result; + } + catch ( InvocationTargetException ex ) + { + throw ex.getCause (); + } + } + else + { + throw new NoSuchMethodException ( name ); + } + } + + + public static Object invokeStaticMethod ( String cls, String name, + Object[] args, Class[] argTypes ) + throws Throwable + { + Method m = findMethod ( Class.forName ( cls, true, loader ), name, + argTypes ); + if ( m != null ) + { + try + { + Object result = m.invoke ( null, + castArguments ( args, argTypes, + m.getParameterTypes () ) ); + return result; + } + catch ( InvocationTargetException ex ) + { + throw ex.getCause (); + } + } + else + { + throw new NoSuchMethodException ( name ); + } + } + + + public static Object invokeConstructor ( String cls, Object[] args, + Class[] argTypes ) + throws Throwable + { + Constructor c = findConstructor ( Class.forName ( cls, true, loader ), + argTypes ); + if ( c != null ) + { + try + { + Object result = c.newInstance ( castArguments ( args, argTypes, + c.getParameterTypes () ) ); + return result; + } + catch ( InvocationTargetException ex ) + { + throw ex.getCause (); + } + } + else + { + throw new NoSuchMethodException ( cls ); + } + } + + + public static Object getField ( Object target, String name ) + throws Throwable + { + try + { + Field f = target.getClass ().getField ( name ); + return f.get ( target ); + } + catch ( NoSuchFieldException ex ) + { + try + { + return invokeMethod ( target, name, new Object[0], new Class[0] ); + } + catch ( NoSuchMethodException ex2 ) + { + throw ex; + } + } + } + + + public static Object getStaticField ( String cls, String name ) + throws Throwable + { + try + { + Field f = Class.forName ( cls, true, loader ).getField ( name ); + return f.get ( null ); + } + catch ( NoSuchFieldException ex ) + { + try + { + return invokeStaticMethod ( cls, name, new Object[0], new Class[0] ); + } + catch ( NoSuchMethodException ex2 ) + { + throw ex; + } + } + } + + + public static void setField ( Object target, String name, Object value ) + throws Exception + { + Field f = target.getClass ().getField ( name ); + f.set ( target, castArgument ( value, value.getClass (), f.getType () ) ); + } + + + public static void setStaticField ( String cls, String name, Object value ) + throws Exception + { + Field f = Class.forName ( cls, true, loader ).getField ( name ); + f.set ( null, castArgument ( value, value.getClass (), f.getType () ) ); + } + + + private static boolean isCallableFrom ( Method m, Class[] argTypes ) + { + Class[] expTypes = m.getParameterTypes (); + for ( int i = 0; i < argTypes.length; i++ ) + { + if ( !isCallableFrom ( expTypes[i], argTypes[i] ) ) + { + return false; + } + } + return true; + } + + + private static boolean isCallableFrom ( Constructor c, Class[] argTypes ) + { + Class[] expTypes = c.getParameterTypes (); + for ( int i = 0; i < argTypes.length; i++ ) + { + if ( !isCallableFrom ( expTypes[i], argTypes[i] ) ) + { + return false; + } + } + return true; + } + + + private static boolean isCallableFrom ( Class expCls, Class argCls ) + { + //System.out.println("isCallableFrom: "+expCls.getCanonicalName() + " <=? " + argCls.getCanonicalName()); + if ( argCls == null ) + { + return!expCls.isPrimitive (); + } + else if ( expCls.isAssignableFrom ( argCls ) ) + { + return true; + } + else if ( ( isNumberClass ( expCls ) || isBooleanClass ( expCls ) ) && + isNumberClass ( argCls ) ) + { + return true; + } + else if ( isCharClass ( expCls ) && argCls.equals ( Character.class ) ) + { + /* + modified into a more strict check to avoid char to string matching + to avoid matching method signatureslike + java_method(char) with octave_call('a String') + Date: 28-08-2010 + Author: Martin Hepperle + */ + return true; + } + else if ( isStringClass ( expCls ) && argCls.equals ( String.class ) ) + { + /* + added for strict String to String matching + java_method(String) with octave_call('a String') + but not + java_method(char) with octave_call('a String') + Date: 28-08-2010 + Author: Martin Hepperle + */ + return true; + } + else if ( expCls.isArray () && argCls.isArray () && + isCallableFrom ( expCls.getComponentType (), + argCls.getComponentType () ) ) + { + return true; + } + else if ( expCls.equals ( Object.class ) && argCls.isPrimitive () ) + { + return true; + } + else + { + return false; + } + } + + + private static boolean isNumberClass ( Class cls ) + { + return ( + cls.equals ( Integer.TYPE ) || + cls.equals ( Integer.class ) || + cls.equals ( Short.TYPE ) || + cls.equals ( Short.class ) || + cls.equals ( Long.TYPE ) || + cls.equals ( Long.class ) || + cls.equals ( Float.TYPE ) || + cls.equals ( Float.class ) || + cls.equals ( Double.TYPE ) || + cls.equals ( Double.class ) + ); + } + + + private static boolean isBooleanClass ( Class cls ) + { + return ( + cls.equals ( Boolean.class ) || + cls.equals ( Boolean.TYPE ) + ); + } + + + private static boolean isCharClass ( Class cls ) + { + return ( + cls.equals ( Character.class ) || + cls.equals ( Character.TYPE ) + ); + } + + + /** + * Check whether the supplied class is a String class. + * + * Added for more strict char/string mathicng of method signatures + * Date: 28-08-2010 + * Author: Martin Hepperle + * @param cls Class - the class to check + * @return boolean - true if clas is of class java.lang.String + */ + private static boolean isStringClass ( Class cls ) + { + return ( + cls.equals ( String.class ) + ); + } + + + private static Object[] castArguments ( Object[] args, Class[] argTypes, + Class[] expTypes ) + { + for ( int i = 0; i < args.length; i++ ) + { + args[i] = castArgument ( args[i], argTypes[i], expTypes[i] ); + } + return args; + } + + + private static Object castArgument ( Object obj, Class type, Class expType ) + { + // System.out.println("expType:"+expType.getCanonicalName() + " <= type:" + type.getCanonicalName()); + if ( type == null || expType.isAssignableFrom ( type ) ) + { + return obj; + } + else if ( isNumberClass ( expType ) ) + { + if ( expType.equals ( Integer.TYPE ) || expType.equals ( Integer.class ) ) + { + return new Integer ( ( ( Number ) obj ).intValue () ); + } + else if ( expType.equals ( Double.TYPE ) || expType.equals ( Double.class ) ) + { + return new Double ( ( ( Number ) obj ).doubleValue () ); + } + else if ( expType.equals ( Short.TYPE ) || expType.equals ( Short.class ) ) + { + return new Short ( ( ( Number ) obj ).shortValue () ); + } + else if ( expType.equals ( Long.TYPE ) || expType.equals ( Long.class ) ) + { + return new Long ( ( ( Number ) obj ).longValue () ); + } + } + else if ( isBooleanClass ( expType ) ) + { + return new Boolean ( ( ( Number ) obj ).intValue () != 0 ); + } + else if ( isCharClass ( expType ) ) + { + String s = obj.toString (); + if ( s.length () != 1 ) + { + throw new ClassCastException ( "cannot cast " + s + " to character" ); + } + return new Character ( s.charAt ( 0 ) ); + } + else if ( expType.isArray () && type.isArray () ) + { + return castArray ( obj, type.getComponentType (), + expType.getComponentType () ); + } + else if ( type.isPrimitive () ) + { + return obj; + } + return null; + } + + + private static Object castArray ( Object obj, Class elemType, + Class elemExpType ) + { + int len = Array.getLength ( obj ); + Object result = Array.newInstance ( elemExpType, len ); + for ( int i = 0; i < len; i++ ) + { + Array.set ( result, i, + castArgument ( Array.get ( obj, i ), elemType, elemExpType ) ); + } + return result; + } + + + private static int getArrayClassNDims ( Class cls ) + { + if ( cls != null && cls.isArray () ) + { + return ( 1 + getArrayClassNDims ( cls.getComponentType () ) ); + } + else + { + return 0; + } + } + + + private static Class getArrayElemClass ( Class cls ) + { + if ( cls.isArray () ) + { + return getArrayElemClass ( cls.getComponentType () ); + } + else + { + return cls; + } + } + + + private static Object getArrayElements ( Object array, int[][] idx, + int offset, + int ndims, Class elemType ) + { + if ( offset >= ndims ) + { + Object elem = Array.get ( array, idx[offset][0] ); + if ( offset < idx.length - 1 ) + { + return getArrayElements ( elem, idx, offset + 1, ndims, elemType ); + } + else + { + return elem; + } + } + else + { + Class compType = elemType.getComponentType (); + Object retval = Array.newInstance ( compType, idx[offset].length ); + for ( int i = 0; i < idx[offset].length; i++ ) + { + Object elem = Array.get ( array, idx[offset][i] ); + if ( offset < idx.length - 1 ) + { + elem = getArrayElements ( elem, idx, offset + 1, ndims, compType ); + } + Array.set ( retval, i, elem ); + } + return retval; + } + } + + + public static Object arraySubsref ( Object obj, int[][] idx ) + throws Exception + { + if ( !obj.getClass ().isArray () ) + { + throw new IllegalArgumentException ( "not a Java array" ); + } + + if ( idx.length == 1 ) + { + if ( idx[0].length == 1 ) + { + return Array.get ( obj, idx[0][0] ); + } + else + { + Object retval = Array.newInstance ( obj.getClass (). + getComponentType (), + idx[0].length ); + for ( int i = 0; i < idx[0].length; i++ ) + { + Array.set ( retval, i, Array.get ( obj, idx[0][i] ) ); + } + return retval; + } + } + else + { + int[] dims = new int[idx.length]; + for ( int i = 0; i < idx.length; i++ ) + { + dims[i] = idx[i].length; + } + + if ( dims.length != getArrayClassNDims ( obj.getClass () ) ) + { + throw new IllegalArgumentException ( "index size mismatch" ); + } + + /* resolve leading singletons */ + Object theObj = obj; + int offset = 0; + while ( dims[offset] == 1 ) + { + theObj = Array.get ( theObj, idx[offset][0] ); + offset = offset + 1; + if ( offset >= dims.length ) + { + return theObj; + } + } + if ( offset > 0 ) + { + int[][] new_idx = new int[idx.length - offset][]; + System.arraycopy ( idx, offset, new_idx, 0, idx.length - offset ); + return arraySubsref ( theObj, new_idx ); + } + + /* chop trailing singletons */ + int ndims = dims.length; + while ( ndims > 1 && dims[ndims - 1] == 1 ) + { + ndims--; + } + + /* create result array */ + Class elemClass = theObj.getClass (); + for ( int i = 0; i <= ( dims.length - ndims ); i++ ) + { + elemClass = elemClass.getComponentType (); + } + Object retval = Array.newInstance ( elemClass, dims[0] ); + + /* fill-in array */ + for ( int i = 0; i < idx[0].length; i++ ) + { + Object elem = getArrayElements ( Array.get ( theObj, idx[0][i] ), + idx, 1, ndims, elemClass ); + Array.set ( retval, i, elem ); + } + + return retval; + } + } + + + private static Object setArrayElements ( Object array, int[][] idx, + int offset, int ndims, Object rhs ) + throws Exception + { + if ( offset >= ndims ) + { + if ( offset < idx.length - 1 ) + { + setArrayElements ( Array.get ( array, idx[offset][0] ), idx, + offset + 1, ndims, rhs ); + } + else + { + Array.set ( array, idx[offset][0], rhs ); + } + return array; + } + else + { + for ( int i = 0; i < idx[offset].length; i++ ) + { + if ( offset < idx.length - 1 ) + { + setArrayElements ( Array.get ( array, idx[offset][i] ), idx, + offset + 1, ndims, Array.get ( rhs, i ) ); + } + else + { + Array.set ( array, idx[offset][i], Array.get ( rhs, i ) ); + } + } + return array; + } + } + + + public static Object arraySubsasgn ( Object obj, int[][] idx, Object rhs ) + throws Exception + { + if ( !obj.getClass ().isArray () ) + { + throw new IllegalArgumentException ( "not a Java array" ); + } + + if ( idx.length == 1 ) + { + if ( idx[0].length == 1 ) + { + Array.set ( obj, idx[0][0], rhs ); + } + else + { + for ( int i = 0; i < idx[0].length; i++ ) + { + Array.set ( obj, idx[0][i], Array.get ( rhs, i ) ); + } + } + return obj; + } + else + { + int[] dims = new int[idx.length]; + for ( int i = 0; i < idx.length; i++ ) + { + dims[i] = idx[i].length; + } + + if ( dims.length != getArrayClassNDims ( obj.getClass () ) ) + { + throw new IllegalArgumentException ( "index size mismatch" ); + } + + /* resolve leading singletons */ + Object theObj = obj; + int offset = 0; + while ( dims[offset] == 1 && offset < ( dims.length - 1 ) ) + { + theObj = Array.get ( theObj, idx[offset][0] ); + offset = offset + 1; + } + if ( offset > 0 ) + { + int[][] new_idx = new int[idx.length - offset][]; + System.arraycopy ( idx, offset, new_idx, 0, idx.length - offset ); + arraySubsasgn ( theObj, new_idx, rhs ); + return obj; + } + + /* chop trailing singletons */ + int ndims = dims.length; + while ( ndims > 1 && dims[ndims - 1] == 1 ) + { + ndims--; + } + + for ( int i = 0; i < idx[0].length; i++ ) + { + setArrayElements ( Array.get ( theObj, idx[0][i] ), idx, 1, ndims, + Array.get ( rhs, i ) ); + } + + return obj; + } + } + + + public static Object createArray ( Object cls, int[] dims ) + throws Exception + { + Class theClass; + if ( cls instanceof Class ) + { + theClass = ( Class ) cls; + } + else if ( cls instanceof String ) + { + theClass = Class.forName ( ( String ) cls, true, loader ); + } + else + { + throw new IllegalArgumentException ( "invalid class specification " + + cls ); + } + + return Array.newInstance ( theClass, dims ); + } + + + public static Object createArray ( Object cls, int length ) + throws Exception + { + return createArray ( cls, new int[] + {length} ); + } + +}
new file mode 100755 --- /dev/null +++ b/scripts/java/org/octave/DlgListener.java @@ -0,0 +1,159 @@ +/* + ** Copyright (C) 2010 Martin Hepperle + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with this program; If not, see <http://www.gnu.org/licenses/>. + */ + +package org.octave; + +import java.awt.event.*; +import javax.swing.*; + +/** + * <p>Implements button click actions for dialog box functions</p> + * + * <p>Copyright (c) 2010 Martin Hepperle</p> + * + * @author Martin Hepperle + * @version 1.0 + */ +public class DlgListener + extends WindowAdapter implements ActionListener, KeyListener +{ + // the parent frame of the dialog + JDialogBox m_Parent; + + public DlgListener ( JDialogBox d ) + { + m_Parent = d; + } + + + // + // --- extension of the WindowAdapter class --- + // + /** + * Called when the user clicks the close button on the window frame. + * + * @param e WindowEvent + */ + public void windowClosing ( WindowEvent e ) + { + m_Parent.closeDialog ( JDialogBox.CLOSE_CANCEL ); + } + + public void windowOpened( WindowEvent e ) + { + m_Parent.setFocus(); + } + + + // + // --- implementation of the ActionListener interface --- + // + /** + * Called when the user clicks a button in the dialog. + * Closes the dialog when either a button with an + * action command OK, CANCEL or NO is pressed. + * + * @param e ActionEvent + */ + public void actionPerformed ( ActionEvent e ) + { + if ( e.getActionCommand ().equals ( "OK" ) ) + { + m_Parent.closeDialog ( JDialogBox.CLOSE_OK ); + } + else if ( e.getActionCommand ().equals ( "CANCEL" ) ) + { + m_Parent.closeDialog ( JDialogBox.CLOSE_CANCEL ); + } + else if ( e.getActionCommand ().equals ( "NO" ) ) + { + m_Parent.closeDialog ( JDialogBox.CLOSE_NO ); + } + else if ( e.getActionCommand ().equals ( "SELALL" ) ) + { + m_Parent.SelectAll (); + } + } + + + // + // --- implementation of the KeyListener interface --- + // + /** + * Closes the dialog when the ENTER or ESCAPE keys are released. + * + * @param e KeyEvent + */ + public void keyTyped ( KeyEvent e ) + { + if ( e.getKeyCode () == KeyEvent.VK_ESCAPE ) + { + m_Parent.closeDialog ( JDialogBox.CLOSE_CANCEL ); + } + } + + + /** + * @param e KeyEvent + */ + public void keyPressed ( KeyEvent e ) + { + if ( e.getSource ().getClass ().equals ( JTextArea.class ) ) + { + JTextArea ta = ( JTextArea ) e.getSource (); + if ( e.getKeyCode () == KeyEvent.VK_ENTER ) + { + char c[] = ta.getText ().toCharArray (); + int nLines = 1; + for ( int i = 0; i < c.length; i++ ) + { + if ( c[i] == '\n' ) + { + nLines++; + } + } + + if ( nLines >= ta.getRows () ) + { + e.consume (); + } + } + else if ( e.getKeyCode () == KeyEvent.VK_TAB ) + { + e.consume (); + + if ( ( e.getModifiersEx () & KeyEvent.SHIFT_DOWN_MASK ) == + KeyEvent.SHIFT_DOWN_MASK ) + { + ta.transferFocusBackward(); + } + else + { + ta.transferFocus (); + } + } + } + } + + + /** + * @param e KeyEvent + */ + public void keyReleased ( KeyEvent e ) + { + } +}
new file mode 100755 --- /dev/null +++ b/scripts/java/org/octave/JDialogBox.java @@ -0,0 +1,986 @@ + /* + ** Copyright (C) 2010 Martin Hepperle + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with this program; If not, see <http://www.gnu.org/licenses/>. + */ + +package org.octave; + +import java.net.*; +import java.util.*; + +import java.awt.*; +import javax.swing.*; + +/** + * <p>Implementation of various dialog box functions</p> + * + * <p>The following functions are provided for being called via + * Octave script files:</p> + * <ul> + * <li>errordlg</li> + * <li>helpdlg</li> + * <li>inputdlg</li> + * </ul> + * + * <p>Copyright (c) 2010 Martin Hepperle</p> + * + * @author Martin Hepperle + * @version 1.0 + */ +public class JDialogBox +{ + public static final int CLOSE_OK = 1; + public static final int CLOSE_NO = 2; + public static final int CLOSE_CANCEL = 3; + + // dialog type + public static int FLAG_LABEL = 1; + public static int FLAG_TEXT = 2; + public static int FLAG_INPUT = 4; + public static int FLAG_LIST = 8; + // icon selection + public static int FLAG_QUESTION = 32; + public static int FLAG_ERROR = 64; + public static int FLAG_WARNING = 128; + public static int FLAG_INFORMATION = 256; + + public static int DLG_QUEST = FLAG_QUESTION | FLAG_TEXT; + public static int DLG_INPUT = FLAG_QUESTION | FLAG_INPUT; + public static int DLG_LIST = FLAG_QUESTION | FLAG_LIST; + + private final static String m_OK = "OK"; + private final static String m_Yes = "Yes"; + private final static String m_No = "No"; + private final static String m_Cancel = "Cancel"; + + private JButton m_ButtonNO; + private JButton m_ButtonOK; + private JButton m_ButtonCANCEL; + private JButton m_Focus; + private JTextArea m_TextField[]; + private JList m_List; + private JFrame m_ParentFrame; + private int m_CloseMethod; + + // ------------------------------------ + // implementation of listdlg function + // ------------------------------------ + + /** + * + * @param listcell String[] - a array of strings, one for each list entry + * @param selmode String + * @param sizecell Object[] + * @param initialcell Object[] + * @param name String + * @param promptcell String[] + * @param okstring String + * @param cancelstring String + * @return String[] + */ + public static int[] listdlg ( String[] listcell, + String selmode, + Object[] sizecell, + Object[] initialcell, + String name, + String[] promptcell, + String okstring, + String cancelstring ) + { + JDialogBox d = new JDialogBox (); + d.genericdlg ( promptcell, listcell, name, selmode, + DLG_LIST, + sizecell, initialcell, okstring, null, cancelstring ); + return ( d.getSelectedIndices () ); + } + + + // ------------------------------------ + // implementation of inputdlg function + // ------------------------------------- + + /** + * Implements a variation of the inputdlg function. + * + * @param prompt String[] - an array of text strings to be used as labels. + * @param title String - a text string to be used to label the dialog caption. + * @param RowsCols int - defines the width of the text fields in columns. + * @param defaults Object[] - an array of text strings or numbers to be + * placed into the text fields as default values. + * @return String[] - an array of text strings containing the content of the + * text fields. + */ + public static String[] inputdlg ( String[] prompt, + String title, + Object[] RowsCols, + Object[] defaults ) + { + JDialogBox d = new JDialogBox (); + d.genericdlg ( prompt, null, title, "on", + FLAG_INPUT | FLAG_QUESTION, + RowsCols, defaults, m_OK, null, m_Cancel ); + return ( d.getInput () ); + } + + + /** + * Extract the current content from the text fields of an inputdlg. + * + * @return String[] - the text contained in the fields of an inputdlg. + * null if the dialog was cancelled. + */ + private String[] getInput () + { + String s[] = null; + + if ( m_CloseMethod == CLOSE_OK ) + { + s = new String[m_TextField.length]; + + for ( int i = 0; i < s.length; i++ ) + { + s[i] = new String ( m_TextField[i].getText () ); + } + } + + return ( s ); + } + + + private String getResult () + { + String s = null; + + if ( m_CloseMethod == CLOSE_OK ) + { + s = m_ButtonOK.getText (); + } + else if ( m_CloseMethod == CLOSE_CANCEL ) + { + s = m_ButtonCANCEL.getText (); + } + else + { + s = m_ButtonNO.getText (); + } + + return ( s ); + } + + + /** + * Extract the current content from the text fields of an inputdlg. + * + * @return String[] - the text contained in the fields of an inputdlg. + * null if the dialog was cancelled. + */ + private String[] getSelection () + { + String s[] = null; + + if ( m_CloseMethod == CLOSE_OK ) + { + int selection[] = m_List.getSelectedIndices (); + + s = new String[selection.length]; + + for ( int i = 0; i < s.length; i++ ) + { + + // s[i] = new String ( Integer.toString(selection[i]) ); + s[i] = ( m_List.getSelectedValues ()[i] ).toString (); + } + } + + return ( s ); + } + + + private int[] getSelectedIndices () + { + int s[] = null; + + if ( m_CloseMethod == CLOSE_OK ) + { + s = m_List.getSelectedIndices (); + for ( int i = 0; i < s.length; i++ ) + { + + // translate to 1 based indices + s[i] = s[i] + 1; + } + } + + return ( s ); + } + + + public void SelectAll () + { + if ( null != m_List ) + { + m_List.setSelectionInterval ( 0, m_List.getModel ().getSize () - 1 ); + } + } + + + // ------------------------------------- + // implementation of helpdlg function + // ------------------------------------- + + /** + * Implements a simple helpdlg with default text and caption. Not very useful. + * + * Octave > helpdlg('helpstring','title') + * + * Called via helpdlg.m. + * + * @param helpstring String - a message string to be presented to the user. + * The string can have embedded newline (\n) characters to break the message + * into multiple lines. + * @param title String - a text string to be used to label the dialog caption. + * @return int - always 1 + */ + public static int helpdlg ( String helpstring, String title ) + { + JDialogBox d = new JDialogBox (); + String s[] = new String[1]; + s[0] = helpstring; + return ( d.genericdlg ( s, null, title, "on", + FLAG_TEXT | FLAG_INFORMATION, null, null, + m_OK, null, m_Cancel ) ); + } + + + // ------------------------------------- + // implementation of emptydlg function + // ------------------------------------- + + /** + * Implements a simple helpdlg with default text and caption. Not very useful. + * + * Octave > emptydlg('messagestring','title') + * + * Called via dlgbox.m. + * + * @param messagestring String - a message string to be presented to the user. + * The string can have embedded newline (\n) characters to break the message + * into multiple lines. + * @param title String - a text string to be used to label the dialog caption. + * @return int - always 1 + */ + public static int emptydlg ( String helpstring, String title ) + { + JDialogBox d = new JDialogBox (); + String s[] = new String[1]; + s[0] = helpstring; + return ( d.genericdlg ( s, null, title, "on", + FLAG_TEXT, null, null, + m_OK, null, m_Cancel ) ); + } + + + // ------------------------------------------- + // implementation of questdlg related functions + // ------------------------------------------- + + /** + * Implements a simple questdlg with default text and caption. Not very useful. + * + * @param question String - the question to be presented + * @param title String - the caption + * @param options String[] - 'str1', 'str2', 'str3', 'default' + * @return String - the caption of the button pressed by the user + */ + public static String questdlg ( String question, + String title, + String[] options ) + { + JDialogBox d = new JDialogBox (); + String s[] = new String[1]; + s[0] = question; + d.genericdlg ( s, options, title, "on", + DLG_QUEST, null, null, + options[0], options[1], options[2] ); + return ( d.getResult () ); + } + + + // ------------------------------------- + // implementation of errordlg function + // ------------------------------------- + + /** + * Implements a simple errordlg with default text and caption. Not very useful. + * + * @param errorstring String - the error message to display. + * @param dlgname String - the caption of the dialog box. + * @return int - always 1 + */ + public static int errordlg ( String errorstring, String dlgname ) + { + JDialogBox d = new JDialogBox (); + String s[] = new String[1]; + s[0] = errorstring; + return ( d.genericdlg ( s, null, dlgname, "on", FLAG_TEXT | FLAG_ERROR, + null, null, + m_OK, null, m_Cancel ) ); + } + + + // ------------------------------------------- + // implementation of warndlg related functions + // ------------------------------------------- + + /** + * Implements a simple warndlg with default text and caption. Not very useful. + * + * Called via warndlg.m. + * + * @param errorstring String - the message to be presented to the user. + * @param dlgname String - the caption of the dialog box. + * @return int - always 1 + */ + public static int warndlg ( String errorstring, String dlgname ) + { + JDialogBox d = new JDialogBox (); + String s[] = new String[1]; + s[0] = errorstring; + return ( d.genericdlg ( s, null, dlgname, "on", FLAG_TEXT | FLAG_WARNING, + null, null, + m_OK, null, m_Cancel ) ); + } + + + // ------------------------------------- + // generic dlg function + // ------------------------------------- + /** + * A generic dialog creation and display function. + * + * @param message String[] + * @param list String[] + * @param caption String + * @param on String + * @param flag int + * @param RowsCols Object[] + * @param defaults Object[] + * @param okstring String + * @param nostring String + * @param cancelstring String + * @return int + */ + public int genericdlg ( String message[], + String list[], + String caption, + String on, + int flag, + Object[] RowsCols, + Object[] defaults, + String okstring, + String nostring, + String cancelstring ) + { + TeXtranslator theTranslator = new TeXtranslator (); + setSystemLnF ( true ); + + caption = theTranslator.replace ( caption ); + + m_ButtonNO = null; + m_ButtonOK = null; + m_ButtonCANCEL = null; + + // create a modal dialog with an empty frame as its parent + m_ParentFrame = new JFrame (); + + // --- trick to bring dialog to the front + // In Windows, the dialog is not brought to the foreground, but hidden + // behind the Octave window as long as the parent frame is not visible. + // To avoid that the frame is visible, we move it outside of the screen. + m_ParentFrame.setBounds ( Toolkit.getDefaultToolkit ().getScreenSize (). + width + 100, + Toolkit.getDefaultToolkit ().getScreenSize (). + height + 100, 1, 1 ); + m_ParentFrame.setVisible ( true ); + //-- end of trick + + JDialog dlg; + dlg = new JDialog ( m_ParentFrame ); + dlg.setTitle ( caption ); + + dlg.setModal ( true ); + dlg.setDefaultCloseOperation ( JDialog.DISPOSE_ON_CLOSE ); + + DlgListener theListener = new DlgListener ( this ); + + Container d = dlg.getContentPane (); + d.setLayout ( new BorderLayout ( 8, 8 ) ); + + // spacer + d.add ( new JLabel ( " " ), BorderLayout.NORTH ); + d.add ( new JLabel ( " " ), BorderLayout.EAST ); + + JPanel p = new JPanel (); + + if ( FLAG_LABEL == ( FLAG_LABEL & flag ) ) + { + // a single line label + JLabel l = new JLabel ( theTranslator.replace ( message[0] ) ); + p.add ( l ); + } + else if ( FLAG_TEXT == ( FLAG_TEXT & flag ) ) + { + String msg = theTranslator.replace ( message[0] ); + // a multi-line text display for helpdlg + StringTokenizer st = new StringTokenizer ( msg, "\n" ); + + int nRows = ( null == RowsCols ) ? 1 : + Integer.parseInt ( RowsCols[0].toString () ); + nRows = Math.max ( nRows, st.countTokens () ); + int nCols = Math.max ( 1, msg.length () / nRows ); + + p.setLayout ( new GridLayout ( message.length, 1 ) ); + JTextArea ta = new JTextArea ( msg, nRows, nCols ); + ta.setEditable ( false ); + ta.setFocusable ( false ); + ta.setOpaque ( false ); + // replace ugly monospaced font + ta.setFont ( p.getFont () ); + p.add ( ta ); + } + else if ( FLAG_INPUT == ( FLAG_INPUT & flag ) ) + { + // a multi label/textfield entry dialog for inputdlg + GridBagConstraints gbc = new GridBagConstraints (); + gbc.insets.top = 4; + gbc.insets.left = 8; + gbc.gridx = 0; + gbc.anchor = GridBagConstraints.NORTHWEST; + + p.setLayout ( new GridBagLayout () ); + m_TextField = new JTextArea[message.length]; + + // default values + int nRows = 1; + int nCols = 10; + + for ( int i = 0; i < message.length; i++ ) + { + String msg = theTranslator.replace ( message[i] ); + JLabel l = new JLabel ( msg ); + l.setHorizontalAlignment ( Label.LEFT ); + gbc.gridy = 2 * i; + p.add ( l, gbc ); + /** + * @todo CHECK handling of RowsCols for inputdlg + */ + if ( RowsCols != null ) + { + if ( RowsCols.length == 2 * message.length ) + { + nRows = Integer.parseInt ( RowsCols[i].toString () ); + nCols = Integer.parseInt ( RowsCols[RowsCols.length / 2 + + i].toString () ); + } + } + + m_TextField[i] = new JTextArea ( "", Math.max ( nRows, 1 ), nCols ); + // avoid resizing + m_TextField[i].setPreferredSize ( new Dimension ( Math.max ( nRows, + 1 ), nCols ) ); + m_TextField[i].setAutoscrolls ( false ); + m_TextField[i].setFont ( p.getFont () ); + m_TextField[i].setBorder ( new javax.swing.border.EtchedBorder () ); + m_TextField[i].addKeyListener ( theListener ); + + gbc.gridy = 2 * i + 1; + p.add ( m_TextField[i], gbc ); + } + + if ( defaults != null ) + { + if ( defaults.length == message.length ) + { + for ( int i = 0; i < message.length; i++ ) + { + String def = theTranslator.replace ( defaults[i].toString () ); + m_TextField[i].setText ( def ); + } + } + } + } + else if ( DLG_LIST == ( DLG_LIST & flag ) ) + { + GridBagConstraints gbc = new GridBagConstraints (); + gbc.insets.top = 4; + gbc.insets.left = 8; + gbc.gridx = 0; + gbc.anchor = GridBagConstraints.NORTHWEST; + + p.setLayout ( new GridBagLayout () ); + + for ( int i = 0; i < message.length; i++ ) + { + // a single line label + String msg = theTranslator.replace ( message[i] ); + JLabel l = new JLabel ( msg ); + gbc.gridy = i; + p.add ( l, gbc ); + } + + String lst[] = new String[list.length]; + + for ( int i = 0; i < list.length; i++ ) + { + lst[i] = theTranslator.replace ( list[i] ); + } + m_List = new JList ( lst ); + + // replace ugly monospaced font + m_List.setFont ( p.getFont () ); + + m_List.setMinimumSize ( new Dimension ( Math.max ( 1, + Integer.parseInt ( RowsCols[0].toString () ) ), + Math.max ( 1, + Integer.parseInt ( RowsCols[1].toString () ) ) ) ); + m_List.setPreferredSize ( new Dimension ( Math.max ( 1, + Integer.parseInt ( RowsCols[1].toString () ) ), + Math.max ( 1, + Integer.parseInt ( RowsCols[0].toString () ) ) ) ); + m_List.setBorder ( new javax.swing.border.EtchedBorder () ); + + gbc.gridy = message.length; + gbc.fill = GridBagConstraints.HORIZONTAL; + p.add ( m_List, gbc ); + + if ( on.toLowerCase ().equals ( "single" ) ) + { + // single selection list + m_List.setSelectionMode ( ListSelectionModel.SINGLE_SELECTION ); + + m_List.setSelectedIndex ( Integer.parseInt ( + defaults[0].toString () ) - 1 ); + } + else + { + // multiple selection possible + m_List.setSelectionMode ( ListSelectionModel. + MULTIPLE_INTERVAL_SELECTION ); + + int selection[] = new int[defaults.length]; + for ( int i = 0; i < defaults.length; i++ ) + { + selection[i] = Integer.parseInt ( defaults[i].toString () ) - 1; + } + m_List.setSelectedIndices ( selection ); + + JButton b = new JButton ( "Select All" ); + b.setActionCommand ( "SELALL" ); + b.addActionListener ( theListener ); + gbc.gridy = message.length + 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + p.add ( b, gbc ); + } + + } + + // prepare icon, if any + String sIconFile = null; + String sIconResource = null; + Icon theIcon = null; + + if ( FLAG_ERROR == ( FLAG_ERROR & flag ) ) + { + sIconFile = "images/error.png"; + // Java for Windows + sIconResource = "OptionPane.errorIcon"; + // Java for Linux does not offer these standard icons... + } + else if ( FLAG_WARNING == ( FLAG_WARNING & flag ) ) + { + sIconFile = "images/warning.png"; + // Java for Windows + sIconResource = "OptionPane.warningIcon"; + // Java for Linux does not offer these standard icons... + } + else if ( FLAG_QUESTION == ( FLAG_QUESTION & flag ) ) + { + sIconFile = "images/question.png"; + // Java for Windows + sIconResource = "OptionPane.questionIcon"; + // Java for Linux does not offer these standard icons... + } + else if ( FLAG_INFORMATION == ( FLAG_INFORMATION & flag ) ) + { + sIconFile = "images/information.png"; + // Java for Windows + sIconResource = "OptionPane.informationIcon"; + // Java for Linux does not offer these standard icons... + } + + // first try to find the UIManager specific icon to fit look and feel + // Note: the Windows XP look and feel offers 50 icons. + if ( sIconResource != null ) + { + UIDefaults df = UIManager.getLookAndFeelDefaults (); + theIcon = df.getIcon ( sIconResource ); + } + + // fallback on bitmap image resource if icon was not found + if ( theIcon == null && + sIconFile != null ) + { + URL theResource = JDialogBox.class.getResource ( sIconFile ); + if ( theResource != null ) + { + theIcon = new ImageIcon ( theResource ); + } + } + + if ( theIcon != null ) + { + // dummy panel to provide space around icon + JPanel pi = new JPanel ( new GridLayout ( 1, 3 ) ); + pi.add ( new JLabel () ); + pi.add ( new JLabel ( theIcon ) ); + pi.add ( new JLabel () ); + d.add ( pi, BorderLayout.WEST ); + + // use Octave icon if available. otherwise use dialog icon + Icon theOctaveIcon = getOctaveIcon (); + prepareFrameIcon ( m_ParentFrame, + theOctaveIcon == null ? theIcon : theOctaveIcon ); + } + + d.add ( p, BorderLayout.CENTER ); + + // button bar (2 rows of 3 columns each + + p = new JPanel (); + p.setLayout ( new java.awt.GridLayout ( 2, 3 ) ); + + // spacer row + p.add ( new JLabel () ); + p.add ( new JLabel () ); + p.add ( new JLabel () ); + + if ( DLG_QUEST == ( DLG_QUEST & flag ) ) + { + // questdlg with empty option[2]: only two buttons + if ( nostring.length () < 1 ) + { + // spacer: left + p.add ( new JLabel () ); + } + } + else + { + // spacer: left + p.add ( new JLabel () ); + } + + m_ButtonOK = new JButton ( theTranslator.replace ( okstring ) ); + m_ButtonOK.setActionCommand ( "OK" ); + m_ButtonOK.addActionListener ( theListener ); + m_Focus = m_ButtonOK; + p.add ( m_ButtonOK ); + + if ( DLG_QUEST == ( DLG_QUEST & flag ) ) + { + // questdlg with empty option[2]: only two buttons + if ( nostring.length () > 01 ) + { + // questdlg has three buttons + m_ButtonNO = new JButton ( theTranslator.replace ( nostring ) ); + m_ButtonNO.setActionCommand ( "NO" ); + m_ButtonNO.addActionListener ( theListener ); + p.add ( m_ButtonNO ); + if ( DLG_QUEST == ( DLG_QUEST & flag ) ) + { + // select default button + if ( list[3].equals ( nostring ) ) + { + m_Focus = m_ButtonNO; + } + } + } + } + + if ( DLG_INPUT == ( DLG_INPUT & flag ) || + DLG_LIST == ( DLG_LIST & flag ) || + DLG_QUEST == ( DLG_QUEST & flag ) ) + { + m_ButtonCANCEL = new JButton ( theTranslator.replace ( cancelstring ) ); + m_ButtonCANCEL.setActionCommand ( "CANCEL" ); + m_ButtonCANCEL.addActionListener ( theListener ); + p.add ( m_ButtonCANCEL ); + if ( DLG_QUEST == ( DLG_QUEST & flag ) ) + { + // select default button + if ( list[3].equals ( cancelstring ) ) + { + m_Focus = m_ButtonCANCEL; + } + } + } + else + { + // spacer: right + p.add ( new JLabel () ); + } + + d.add ( p, BorderLayout.SOUTH ); + dlg.pack (); + + dlg.addWindowListener ( theListener ); + + if ( on.equals ( "on" ) ) + { + m_ParentFrame.setAlwaysOnTop ( true ); + } + + // center dialog on screen + Dimension dlgSize = dlg.getSize (); + Dimension screenSize = Toolkit.getDefaultToolkit ().getScreenSize (); + + dlg.setLocation ( ( screenSize.width - dlgSize.width ) / 2, + ( screenSize.height - dlgSize.height ) / 2 ); + + dlg.setVisible ( true ); + dlg.requestFocus (); + + m_ParentFrame.setVisible ( false ); + + return ( 1 ); + } + + + /** + * + * @return Icon - null if icon was not found + */ + private Icon getOctaveIcon () + { + Icon theIcon = null; + URL theResource = JDialogBox.class.getResource ( "images/octave.png" ); + if ( theResource != null ) + { + theIcon = new ImageIcon ( theResource ); + } + return theIcon; + } + + + /** + * Replace the standard Java frame icon with an Octave Icon. + * + * @param theFrame Frame - the Frame to decorate + * @param theIcon Icon - the icon to use if octave icon is not found. + */ + private void prepareFrameIcon ( Frame theFrame, Icon theIcon ) + { + // prepare icon for upper left corner of Frame window + // maybe there is a simpler way to achieve this + int w = theIcon.getIconWidth (); + int h = theIcon.getIconHeight (); + // Frame must be made displayable by packing it for createImage() to succeed + theFrame.pack (); + Image theImage = theFrame.createImage ( w, h ); + theIcon.paintIcon ( theFrame, theImage.getGraphics (), 0, 0 ); + theFrame.setIconImage ( theImage ); + } + + + /** + * Select Look and Feel + * + * @param bSystemLnF boolean - if true, the current systesm Look&Feel is used, + * otherwise the Swing/Metal cross platform Look&Feel is used. + */ + private void setSystemLnF ( boolean bSystemLnF ) + { + try + { + if ( bSystemLnF ) + { + // switch from Swing LnF to local system LnF + UIManager.setLookAndFeel ( UIManager. + getSystemLookAndFeelClassName () ); + } + else + { + // use Swing LnF + UIManager.setLookAndFeel ( UIManager. + getCrossPlatformLookAndFeelClassName () ); + } + } + catch ( Exception exception ) + { + exception.printStackTrace (); + } + } + + + /** + * Called when the dialog is closed. Allows for specific cleanup actions. + * + * @param closeMethod int - OctaveDialog.CLOSE_OK, OctaveDialog.CLOSE_CANCEL + */ + public void closeDialog ( int closeMethod ) + { + m_CloseMethod = closeMethod; + m_ParentFrame.dispose (); + } + + + public void setFocus () + { + if ( null != m_Focus ) + { + m_Focus.requestFocus (); + m_ParentFrame.getRootPane ().setDefaultButton ( m_Focus ); + m_ParentFrame.setAlwaysOnTop ( true ); + } + } + + + /** + * Tests the dialogs + * + * @param args String[] - not used. + */ + public static void main ( String[] args ) + { + TeXtranslator t = new TeXtranslator(); + + if(false) + { + // find out key names of icon UI resources + UIDefaults df = UIManager.getLookAndFeelDefaults (); + + for ( Enumeration e = df.keys (); e.hasMoreElements (); ) + { + String s = e.nextElement ().toString (); + + if ( s.toLowerCase ().contains ( "icon" ) ) + { + System.out.println ( s ); + } + } + } + + try + { + Class[] argTypes = new Class[1]; + argTypes[0] = String.class; + + java.lang.reflect.Constructor c = ClassHelper.findConstructor ( java.lang.StringBuffer.class, + argTypes ); + Object argValues[] = new Object[1]; + argValues[0] = new String("initial value"); + Object sb = c.newInstance(argValues); + System.out.println(sb.toString()); + + ClassHelper.invokeMethod(sb,"append",argValues,argTypes); + System.out.println(sb.toString()); + + argValues = new Object[2]; + argTypes = new Class[2]; + argTypes[0] = Integer.class; + argTypes[1] = String.class; + argValues[0] = new Integer(0); + argValues[1] = new String("inserted"); + + ClassHelper.invokeMethod(sb,"insert",argValues,argTypes); + System.out.println(sb.toString()); + } + catch ( Throwable e ) + {} + + if ( true ) + { + return; + } + + helpdlg ( "If you need help\nyou should ask for help\nif someone is around\notherwise you are on your own.", + "Information" ); + + String[] options = new String[4]; + options[0] = "Yeah \\vartheta is too low"; + options[1] = "Maybe"; + options[2] = "Nay \\vartheta is too high"; + options[3] = "Maybe"; + + System.out.println ( questdlg ( "Is it too cold?", "Temperature", options ) ); + + // test variants of errordlg + // does not affect layering of dialog + errordlg ( "Background error!", "Error" ); + + // test variants of helpdlg + + // test variants of inputdlg + String prompt[] = new String[2]; + prompt[0] = "Question 1"; + prompt[1] = "Question 2"; + String defaults[] = new String[2]; + defaults[0] = "1.1"; + defaults[1] = "2.2"; + String title = "Enter values"; + + Integer rc[] = new Integer[2 * 2]; + rc[0] = new Integer ( 1 ); + rc[1] = new Integer ( 2 ); + rc[2] = new Integer ( 10 ); + rc[3] = new Integer ( 20 ); + + inputdlg ( prompt, title, rc, defaults ); + + String listcell[] = new String[4]; + listcell[0] = "a \\alpha"; + listcell[1] = "b \\beta"; + listcell[2] = "c \\gamma"; + listcell[3] = "d \\delta"; + + Integer size[] = new Integer[2]; + size[0] = new Integer ( 80 ); + size[1] = new Integer ( 100 ); + + Integer initial[] = new Integer[2]; + initial[0] = new Integer ( 4 ); + initial[1] = new Integer ( 2 ); + + String promptcell[] = new String[2]; + promptcell[0] = "Select something"; + promptcell[1] = "(or even more than one thing)"; + + int idx[] = listdlg ( listcell, + "Multiple", + size, + initial, + "name", + promptcell, + "okstring", + "cancelstring" ); + + if ( idx != null ) + { + for ( int i = 0; i < idx.length; i++ ) + { + System.out.println ( idx[i] ); + } + } + } +}
new file mode 100644 --- /dev/null +++ b/scripts/java/org/octave/Matrix.java @@ -0,0 +1,355 @@ +/* Copyright (C) 2007 Michael Goffioul +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; If not, see <http://www.gnu.org/licenses/>. +*/ + +package org.octave; + +import java.nio.*; +import java.text.DecimalFormat; + +public class Matrix +{ + private int[] dims; + private Buffer data; + private Object cache = null; + + public Matrix() + { + this(new double[0], new int[] {0, 0}); + } + + public Matrix(double[] data) + { + this(data, new int[] {1, data.length}); + } + + public Matrix(double[][] data) + { + int m = data.length; + int n = (m > 0 ? data[0].length : 0); + int idx = 0; + double[] buf = new double[m*n]; + + for (int j=0; j<n; j++) + for (int i=0; i<m; i++) + buf[idx++] = data[i][j]; + this.data = DoubleBuffer.wrap(buf); + this.dims = new int[] {m, n}; + this.cache = data; + } + + public Matrix(double[][][] data) + { + int m = data.length; + int n = (m > 0 ? data[0].length : 0); + int p = (n > 0 ? data[0][0].length : 0); + int idx = 0; + double[] buf = new double[m*n*p]; + + for (int k=0; k<p; k++) + for (int j=0; j<n; j++) + for (int i=0; i<m; i++) + buf[idx++] = data[i][j][k]; + this.data = DoubleBuffer.wrap(buf); + this.dims = new int[] {m, n, p}; + this.cache = data; + } + + public Matrix(double[] data, int[] dims) + { + this.dims = dims; + this.data = DoubleBuffer.wrap(data); + } + + public Matrix(byte[] data, int[] dims) + { + this.dims = dims; + this.data = ByteBuffer.wrap(data); + } + + public Matrix(int[] data, int[] dims) + { + this.dims = dims; + this.data = IntBuffer.wrap(data); + } + + public double[] toDouble() + { + if (data instanceof DoubleBuffer) + return ((DoubleBuffer)data).array(); + else + throw new ClassCastException("matrix is not of type `double'"); + } + + public byte[] toByte() + { + if (data instanceof ByteBuffer) + return ((ByteBuffer)data).array(); + else + throw new ClassCastException("matrix is not of type `byte'"); + } + + public int[] toInt() + { + if (data instanceof IntBuffer) + return ((IntBuffer)data).array(); + else + throw new ClassCastException("matrix is not of type `integer'"); + } + + public int getNDims() + { + return (dims == null ? 0 : dims.length); + } + + public int getDim(int index) + { + return (dims == null || index < 0 || index >= dims.length ? -1 : dims[index]); + } + + public int[] getDims() + { + return dims; + } + + public String getClassName() + { + if (data instanceof DoubleBuffer) + return "double"; + else if (data instanceof IntBuffer) + return "integer"; + else if (data instanceof ByteBuffer) + return "byte"; + else + return "unknown"; + } + + public String toString() + { + if (dims == null || data == null) + return "null"; + + String s = ""; + + if (dims.length == 2 && dims[0] == 1 && dims[1] <= 5) + { + if (data instanceof DoubleBuffer) + { + DoubleBuffer b = (DoubleBuffer)data; + DecimalFormat fmt = new DecimalFormat("0.0000 "); + for (int i=0; i<b.capacity(); i++) + s += fmt.format(b.get(i)); + } + else if (data instanceof IntBuffer) + { + IntBuffer b = (IntBuffer)data; + for (int i=0; i<b.capacity(); i++) + s += (Integer.toString(b.get(i)) + " "); + } + else if (data instanceof ByteBuffer) + { + ByteBuffer b = (ByteBuffer)data; + for (int i=0; i<b.capacity(); i++) + s += (Byte.toString(b.get(i)) + " "); + } + s = ("[ " + s + "]"); + } + else if (dims.length == 2 && dims[0] == 0 && dims[1] == 0) + s = "[ ]"; + else + { + for (int i=0; i<dims.length; i++) + if (i == 0) + s = Integer.toString(dims[i]); + else + s += (" by " + Integer.toString(dims[i])); + s = ("[ (" + s + ") array of " + getClassName() + " ]"); + } + + return s; + } + + public static Object ident(Object o) + { + System.out.println(o); + return o; + } + + public boolean equals(Object value) + { + if (value instanceof Matrix) + { + Matrix m = (Matrix)value; + if (!java.util.Arrays.equals(dims, m.dims)) + return false; + return data.equals(m.data); + } + else + return false; + } + + public boolean isEmpty() + { + return (data == null || dims == null || data.capacity() == 0); + } + + public boolean isVector() + { + return (dims.length == 1 || + (dims.length == 2 && (dims[0] == 1 || dims[1] == 1 || + (dims[0] == 0 && dims[1] == 0)))); + } + + public int getLength() + { + return data.capacity(); + } + + public double[] asDoubleVector() + { + if (data instanceof DoubleBuffer) + return toDouble(); + else + System.out.println("Warning: invalid conversion to double vector"); + return null; + } + + public double[][] asDoubleMatrix() + { + if (cache != null) + { + try { return (double[][])cache; } + catch (ClassCastException e) { } + } + + if (data instanceof DoubleBuffer && dims.length == 2) + { + double[][] m = new double[dims[0]][dims[1]]; + double[] data = ((DoubleBuffer)this.data).array(); + int idx = 0; + if (data.length > 0) + for (int j=0; j<m[0].length; j++) + for (int i=0; i<m.length; i++) + m[i][j] = data[idx++]; + cache = m; + return m; + } + else + System.out.println("Warning: invalid conversion to double matrix"); + + return null; + } + + public double[][][] asDoubleMatrix3() + { + if (cache != null) + { + try { return (double[][][])cache; } + catch (ClassCastException e) { } + } + + if (data instanceof DoubleBuffer && dims.length == 3) + { + double[][][] m = new double[dims[0]][dims[1]][dims[2]]; + double[] data = ((DoubleBuffer)this.data).array(); + int idx = 0; + if (data.length > 0) + for (int k=0; k<dims[2]; k++) + for (int j=0; j<dims[1]; j++) + for (int i=0; i<dims[0]; i++) + m[i][j][k] = data[idx++]; + cache = m; + return m; + } + else + System.out.println("Warning: invalid conversion to double array"); + + return null; + } + + public int[][] asIntMatrix() + { + if (cache != null) + { + try { return (int[][])cache; } + catch (ClassCastException e) { } + } + + if (data instanceof IntBuffer && dims.length == 2) + { + int[][] m = new int[dims[0]][dims[1]]; + int[] data = ((IntBuffer)this.data).array(); + int idx = 0; + if (data.length > 0) + for (int j=0; j<m[0].length; j++) + for (int i=0; i<m.length; i++) + m[i][j] = data[idx++]; + cache = m; + return m; + } + else + System.out.println("Warning: invalid conversion to integer matrix"); + + return null; + } + + public double minValue() + { + double val = Double.POSITIVE_INFINITY; + + if (data instanceof DoubleBuffer) + { + double[] buf = ((DoubleBuffer)data).array(); + for (int i=0; i<buf.length; i++) + if (buf[i] < val) + val = buf[i]; + } + else if (data instanceof ByteBuffer) + { + byte[] buf = ((ByteBuffer)data).array(); + for (int i=0; i<buf.length; i++) + if (buf[i] < val) + val = buf[i]; + } + else + System.out.println("Warning: cannot compute min value for array of type `" + getClassName() + "'"); + + return val; + } + + public double maxValue() + { + double val = Double.NEGATIVE_INFINITY; + + if (data instanceof DoubleBuffer) + { + double[] buf = ((DoubleBuffer)data).array(); + for (int i=0; i<buf.length; i++) + if (buf[i] > val) + val = buf[i]; + } + else if (data instanceof ByteBuffer) + { + byte[] buf = ((ByteBuffer)data).array(); + for (int i=0; i<buf.length; i++) + if (buf[i] > val) + val = buf[i]; + } + else + System.out.println("Warning: cannot compute max value for array of type `" + getClassName() + "'"); + + return val; + } +}
new file mode 100644 --- /dev/null +++ b/scripts/java/org/octave/OctClassLoader.java @@ -0,0 +1,68 @@ +/* Copyright (C) 2007 Michael Goffioul +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; If not, see <http://www.gnu.org/licenses/>. +*/ + +package org.octave; + +import java.io.File; + +public class OctClassLoader extends java.net.URLClassLoader +{ + public OctClassLoader () + { + super (new java.net.URL[0]); + } + + public OctClassLoader (ClassLoader parent) + { + super (new java.net.URL[0], parent); + } + + protected Class findClass (String name) throws ClassNotFoundException + { + //System.out.println ("Looking for class " + name); + return super.findClass (name); + } + + protected String findLibrary (String libname) + { + // Look dynamically into java.library.path, because Sun VM does + // not do it (seems to cache initial java.library.path instead) + + String[] paths = System.getProperty ("java.library.path").split (File.pathSeparator); + + libname = System.mapLibraryName (libname); + for (int i=0; i<paths.length; i++) + { + File f = new File (paths[i], libname); + if (f.exists ()) + return f.getAbsolutePath(); + } + + return null; + } + + public void addClassPath (String name) throws Exception + { + java.io.File f = new java.io.File (name); + addURL (f.toURI ().toURL ()); + } + + // new -MH- + public void addURL (java.net.URL url) + { + super.addURL (url); + } +}
new file mode 100644 --- /dev/null +++ b/scripts/java/org/octave/Octave.java @@ -0,0 +1,219 @@ +/* Copyright (C) 2007 Michael Goffioul +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; If not, see <http://www.gnu.org/licenses/>. +*/ + +package org.octave; + +import java.util.*; + +public class Octave +{ + static + { + System.load (System.getProperty ("octave.java.path") + java.io.File.separator + "__java__.oct"); + } + + private static Object notifyObject = null; + private static Object[] args = null; + private static LinkedList invokeList = new LinkedList(); + private static LinkedList waitList = new LinkedList(); + + public native static boolean call (String name, Object[] argin, Object[] argout); + public native static void doInvoke(int ID, Object[] args); + public native static void doEvalString(String cmd); + public native static boolean needThreadedInvokation(); + + public static void checkPendingAction() + { + if (notifyObject != null) + { + synchronized(notifyObject) + { + if (notifyObject instanceof OctaveReference) + doInvoke(((OctaveReference)notifyObject).getID(), args); + else if (notifyObject instanceof String) + doEvalString((String)notifyObject); + notifyObject.notifyAll(); + } + notifyObject = null; + args = null; + } + + Object obj; + Object[] objArgs; + + while (true) + { + obj = null; + objArgs = null; + + synchronized (invokeList) + { + if (invokeList.size() > 0) + { + obj = invokeList.remove(); + if (obj instanceof OctaveReference) + objArgs = (Object[])invokeList.remove(); + } + } + + if (obj != null) + { + if (obj instanceof Runnable) + ((Runnable)obj).run(); + else if (obj instanceof OctaveReference) + doInvoke(((OctaveReference)obj).getID(), objArgs); + else if (obj instanceof String) + doEvalString((String)obj); + } + else + break; + } + /* + synchronized(invokeList) + { + while (invokeList.size() > 0) + { + Object obj = invokeList.remove(); + if (obj instanceof Runnable) + ((Runnable)obj).run(); + if (obj instanceof OctaveReference) + { + Object[] objArgs = (Object[])invokeList.remove(); + doInvoke(((OctaveReference)obj).getID(), objArgs); + } + else if (obj instanceof String) + doEvalString((String)obj); + } + } + */ + } + + private static void checkWaitState() + { + if (waitList.size() > 0) + { + Object wObj = waitList.getFirst(); + synchronized (wObj) + { + wObj.notifyAll(); + } + } + } + + public static void invokeAndWait(OctaveReference ref, Object[] invokeArgs) + { + if (needThreadedInvokation()) + { + synchronized(ref) + { + notifyObject = ref; + args = invokeArgs; + try { checkWaitState(); ref.wait(); } + catch (InterruptedException e) {} + } + } + else + doInvoke(ref.getID(), invokeArgs); + } + + public static void evalAndWait(String cmd) + { + if (needThreadedInvokation()) + { + synchronized(cmd) + { + notifyObject = cmd; + args = null; + try { checkWaitState(); cmd.wait(); } + catch (InterruptedException e) {} + } + } + else + doEvalString(cmd); + } + + public static void invokeLater(Runnable r) + { + if (needThreadedInvokation()) + synchronized(invokeList) + { + invokeList.add(r); + checkWaitState(); + } + else + r.run(); + } + + public static void invokeLater(OctaveReference ref, Object[] invokeArgs) + { + if (needThreadedInvokation()) + synchronized(invokeList) + { + invokeList.add(ref); + invokeList.add(invokeArgs); + checkWaitState(); + } + else + doInvoke(ref.getID(), invokeArgs); + } + + public static void evalLater(String cmd) + { + if (needThreadedInvokation()) + synchronized(invokeList) + { + invokeList.add(cmd); + checkWaitState(); + } + else + doEvalString(cmd); + } + + public static void waitFor(Object wObj) + { + waitList.add(0, wObj); + synchronized (wObj) + { + while (waitList.size() > 0 && waitList.getFirst() == wObj) + { + try { wObj.wait(); } + catch (InterruptedException e) {} + checkPendingAction(); + } + } + } + + public static void endWaitFor(Object obj) + { + boolean isCurrentWaitObject = (waitList.size() > 0 && waitList.getFirst() == obj); + + waitList.remove(obj); + if (needThreadedInvokation() && isCurrentWaitObject) + synchronized (obj) + { + obj.notifyAll(); + } + } + + public static Object do_test (String name, Object arg0) throws Exception + { + Object[] argin = new Object[] { arg0 }; + Object[] argout = new Object[1]; + if (call (name, argin, argout)) + return argout[0]; + throw new Exception ("octave call failed"); + } +}
new file mode 100644 --- /dev/null +++ b/scripts/java/org/octave/OctaveReference.java @@ -0,0 +1,63 @@ +/* Copyright (C) 2007 Michael Goffioul +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; If not, see <http://www.gnu.org/licenses/>. +*/ + +package org.octave; + +public class OctaveReference +{ + static + { + System.load (System.getProperty ("octave.java.path") + java.io.File.separator + "__java__.oct"); + } + + private int ID; + + public OctaveReference(int ID) + { + this.ID = ID; + } + + private native static void doFinalize(int ID); + + protected void finalize() throws Throwable + { + doFinalize(this.ID); + } + + public String toString() + { + return ("<octave reference " + this.ID + ">"); + } + + public int getID() + { + return this.ID; + } + + public Object invoke(Object[] args) + { + //System.out.println("OctaveReference::invoke"); + Octave.doInvoke(this.ID, args); + return null; + } + + public synchronized Object invokeAndWait(Object[] args) + { + //System.out.println("OctaveReference::invokeandWait"); + Octave.invokeAndWait(this, args); + return null; + } +}
new file mode 100755 --- /dev/null +++ b/scripts/java/org/octave/TeXcode.java @@ -0,0 +1,35 @@ +/** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see <http://www.gnu.org/licenses/>. + * + * A class to hold a TeX character code -> Unicode translation pair. + * + * <p>Copyright (c) 2010 Martin Hepperle</p> + * + * @author Martin Hepperle + * @version 1.0 + */ +package org.octave; + +public class TeXcode +{ + protected String tex; + protected char ucode; + + public TeXcode ( String t, char u ) + { + tex = t; + ucode = u; + } +}
new file mode 100755 --- /dev/null +++ b/scripts/java/org/octave/TeXtranslator.java @@ -0,0 +1,264 @@ +/** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see <http://www.gnu.org/licenses/>. + * + * + * A primitive TeX character translator. + * Provides methods to translate a subset of TeX symbol strings + * into their aequivalent Unicode representation. + * + * Note that not all Unicode character sets contain all these characters. + * Suitable Windows fonts are e.g.:<br> + * - Lucida Sans Unicode<br> + * - Arial Unicode MS<br> + * - MS Mincho<br> + * + * <p>Copyright (c) 2010 Martin Hepperle</p> + * + * @author Martin Hepperle + * @version 1.0 + */ +package org.octave; + +public class TeXtranslator +{ + private TeXcode m_texTable[] = + { + // lower case + new TeXcode ( "alpha", '\u03B1' ), + new TeXcode ( "beta", '\u03B2' ), + new TeXcode ( "gamma", '\u03B3' ), + new TeXcode ( "delta", '\u03B4' ), + new TeXcode ( "epsilon", '\u03B5' ), + new TeXcode ( "zeta", '\u03B6' ), + new TeXcode ( "eta", '\u03B7' ), + new TeXcode ( "theta", '\u03B8' ), + new TeXcode ( "vartheta", '\u03D1' ), + new TeXcode ( "iota", '\u03B9' ), + new TeXcode ( "kappa", '\u03BA' ), + new TeXcode ( "lambda", '\u03BB' ), + new TeXcode ( "mu", '\u03BC' ), + new TeXcode ( "nu", '\u03BD' ), + new TeXcode ( "xi", '\u03BE' ), + new TeXcode ( "pi", '\u03C0' ), + new TeXcode ( "rho", '\u03C1' ), + new TeXcode ( "sigma", '\u03C3' ), + new TeXcode ( "varsigma", '\u03C2' ), + new TeXcode ( "tau", '\u03C4' ), + new TeXcode ( "phi", '\u03C6' ), + new TeXcode ( "chi", '\u03C7' ), + new TeXcode ( "psi", '\u03C8' ), + new TeXcode ( "omega", '\u03C9' ), + new TeXcode ( "upsilon", '\u03C5' ), + // upper case + new TeXcode ( "Gamma", '\u0393' ), + new TeXcode ( "Delta", '\u0394' ), + new TeXcode ( "Theta", '\u0398' ), + new TeXcode ( "Lambda", '\u039B' ), + new TeXcode ( "Pi", '\u03A0' ), + new TeXcode ( "Xi", '\u039E' ), + new TeXcode ( "Sigma", '\u03A3' ), + new TeXcode ( "Upsilon", '\u03A5' ), + new TeXcode ( "Phi", '\u03A6' ), + new TeXcode ( "Psi", '\u03A8' ), + new TeXcode ( "Omega", '\u03A9' ), + // complex + new TeXcode ( "Im", '\u2111' ), + new TeXcode ( "Re", '\u211c' ), + // special + new TeXcode ( "leq", '\u2264' ), + new TeXcode ( "geq", '\u2265' ), + new TeXcode ( "neq", '\u2260' ), + new TeXcode ( "pm", '\u00B1' ), + new TeXcode ( "infty", '\u221E' ), + new TeXcode ( "partial", '\u2202' ), + new TeXcode ( "approx", '\u2248' ), + new TeXcode ( "circ", '\u2218' ), + new TeXcode ( "bullet", '\u2022' ), + new TeXcode ( "times", '\u00D7' ), + new TeXcode ( "sim", '\u007E' ), + new TeXcode ( "nabla", '\u2207' ), + new TeXcode ( "ldots", '\u2026' ), + new TeXcode ( "exists", '\u2203' ), + new TeXcode ( "neg", '\u00AC' ), + new TeXcode ( "aleph", '\u2135' ), + new TeXcode ( "forall", '\u2200' ), + new TeXcode ( "cong", '\u2245' ), + new TeXcode ( "wp", '\u2118' ), + new TeXcode ( "propto", '\u221D' ), + new TeXcode ( "otimes", '\u2297' ), + new TeXcode ( "oplus", '\u2295' ), + new TeXcode ( "oslash", '\u2298' ), + new TeXcode ( "cap", '\u2229' ), + new TeXcode ( "cup", '\u222A' ), + new TeXcode ( "ni", '\u220B' ), + new TeXcode ( "in", '\u2208' ), + new TeXcode ( "div", '\u00F7' ), + new TeXcode ( "equiv", '\u2261' ), + new TeXcode ( "int", '\u222B' ), + new TeXcode ( "perp", '\u22A5' ), + new TeXcode ( "wedge", '\u2227' ), + new TeXcode ( "vee", '\u2228' ), + // sets + new TeXcode ( "supseteq", '\u2287' ), + new TeXcode ( "supset", '\u2283' ), + new TeXcode ( "subseteq", '\u2286' ), + new TeXcode ( "subset", '\u2282' ), + // cards + new TeXcode ( "clubsuit", '\u2663' ), + new TeXcode ( "spadesuit", '\u2660' ), + new TeXcode ( "heartsuit", '\u2665' ), + new TeXcode ( "diamondsuit", '\u2666' ), + new TeXcode ( "copyright", '\u00A9' ), + // arrows + new TeXcode ( "leftarrow", '\u2190' ), + new TeXcode ( "uparrow", '\u2191' ), + new TeXcode ( "rightarrow", '\u2192' ), + new TeXcode ( "downarrow", '\u2193' ), + new TeXcode ( "leftrightarrow", '\u2194' ), + new TeXcode ( "updownarrow", '\u2195' ), + }; + + public TeXtranslator () + { + /* DEBUG: output table to file + try + { + java.io.PrintWriter pwTeX = new java.io.PrintWriter ( "z:/tex.txt", + "UTF-8" ); + java.io.PrintWriter pwHTML = new java.io.PrintWriter ( "z:/html.txt", + "UTF-8" ); + java.io.PrintWriter pwOctave = new java.io.PrintWriter ( "z:/octave.txt", + "UTF-8" ); + pwOctave.print ( "msgbox ( [" ); + int i = 0; + for ( int k = 0; k < m_texTable.length; k++ ) + { + if ( i++ == 0 ) + { + pwTeX.print ( "@item " ); + pwHTML.print ( "@item " ); + pwOctave.print ( " '" ); + } + else + { + pwTeX.print ( "@tab " ); + pwHTML.print ( "@tab " ); + pwOctave.print ( " " ); + } + pwTeX.println ( "\\" + m_texTable[k].tex ); + pwTeX.println ( "@tab '@math{\\" + m_texTable[k].tex + "}'" ); + pwHTML.println ( "\\" + m_texTable[k].tex ); + pwHTML.println ( "@tab '" + m_texTable[k].ucode + "'" ); + pwOctave.print ( "\\\\" + m_texTable[k].tex+" " ); + pwOctave.print ( " = ''\\" + m_texTable[k].tex + " ''" ); + if ( i == 3 ) + { + pwTeX.println ( "@c ----------" ); + pwHTML.println ( "@c ----------" ); + pwOctave.println ( "', 10, ..." ); + i=0; + } + else + { + pwTeX.println ( "@tab" ); + pwHTML.println ( "@tab" ); + pwOctave.print ( " " ); + } + } + pwOctave.print ( "']);" ); + pwTeX.close (); + pwHTML.close (); + pwOctave.close (); + } + catch ( Exception e ) + { + ; + } + /* */ + } + + + /* + NOT YET TRANSLATED + o + rfloor + lceil + lfloor + cdot + prime + 0 + rceil + surd + mid + varpi + langle + rangle + */ + + public String replace ( String s ) + { + StringBuffer sb = new StringBuffer ( s ); + // append trailing blank + sb.append ( ' ' ); + + int i = 0; + do + { + /* 26 08 2010 MH szatt search at index i */ + i = sb.indexOf ( "\\", i ); + if ( i > -1 ) + { + int j = sb.indexOf ( " ", i ); + if ( j > i ) + { + String token = sb.substring ( i + 1, j ); + + for ( int k = 0; k < m_texTable.length; k++ ) + { + if ( m_texTable[k].tex.equals ( token ) ) + { + sb.replace ( i, j + 1, + Character.toString ( m_texTable[k].ucode ) ); + break; + } + } + if ( sb.charAt ( i ) == '\\' ) + { + // backslash sztill there: not found + if ( sb.charAt ( i + 1 ) == 'n' ) + { + // newline + sb.replace ( i, i + 2, "\n" ); + } + else if ( sb.charAt ( i + 1 ) == '\\' ) + { + // backslash + sb.replace ( i, i + 2, "\\" ); + } + } + /* 26 08 2010 MH + advance i to avoid deadlock in case of incorrect escape + sequences like \\\\alpha (double backslash) or + \\bogus (unknown escape sequence) + */ + i++; + } + } + } + while ( i > -1 ); + // finall: remove trailing blank + return ( sb.substring ( 0, sb.length () - 1 ).toString () ); + } +}
new file mode 100755 index 0000000000000000000000000000000000000000..75fe9106973d938e3b7849f7dd1916dd674d72ba GIT binary patch literal 1205 zc$~#ji%(Nm82@hHrEP3Qy0)-!A#513AZ3sdWbwA;O=Zxs&^SP7s2~Oq#EDwrQen_y zT`_B*KwQUbz)%@knA;%UATKA$B%{jIMbw!v#~gE8(j|kl<Mv1F<ecC4``%y9Irg0F zG)aIe001Nz>B$BxDSSu)8>3ryei92#nP$HR;L75gT*psXSJtJN>WtNg>Q0o@T0m1; zZMKjZl_g~sgQcYOWX%mr5&%Kx=<`xm0SpGi69A!5h}digz~=ywk&!<GTmUEn$O6y< zAiNO<Km_3jz`eEs&S6z1o5h%zh)$nI(a}jsNlvE|1qLE6_b#@}<?8^yU=kjV#A3wf zqxkqQ0Y1R#+uL|hR8-X8-#-oD_xsV=v&dv}VWUJch%q#DWMpK0eSHCQp>PTy4U@RI zGXP#py1P+G2x@6THrqJB7ue!<F9XzIa`2!LBSj4k4x-M^Va%n{j*bpKpZ_c798OnP zm&fCwF)t`Uxw*(-xC8JuRyCRyfO`N-05nZ|z23&gMpRaYIy#U@gzD>2VWCc^TLEx5 z90<Dx22fSi7EZL=QB)MNT9L;ilgW@)iz+HAD=W*(%aPZMdU{Z7EXvPEt*uC@JOc0o zP6-P`sj2urr_D<jv7qY=*+%sLE=b^Jl>xB!WF%|y>hGF|7r1`U_k&*2{aJ*(GnNK3 zGqNv{x{(>eO47D(uxp0d0<wU&xz{(o`Xp0Joh-?`cr4_-79g6hLqoNCXd@z5DR5m0 zI&p0A&iv?3k{%Ccst2xnckf;jaamE%M-QBuH0=ig$qWDEaXdlNiniq)Z+yHIXjD^B zqNX44bo*ACzcB=geYoafxJCpIHM9wZc8}sU;7H#m{`U1Aa(tz-TBoeV%*}T4uZXD_ z8?F;0S$m}a&Ic81+{3n=#g938et)g)mXFPm4iV3K#VYI3GwHm|fX&}5{=QH70#eVe z7yrnp)CJHNF|hn!-2JDu)||jLHQ>2bj3~ZI!3LJ#Yhr3P7^GB!ggM70Z!N@O_fZ9N zv-MSZy?b1NJzYH0M6BR<vom#!2QLa~Z>w#p1o3csc3S=pDP<C`)yDaP=DS@V&P+V| zx0#&XY@5>`k6&vNd@Ev2WF8NjTYpNh1X)$PCU(h;%!QXNZs(<N<+2+GPd=yG`0YY! ztM8rp4aF!9J7RC1<G31fKVs?U@I_7QXJd%52QFp%0UBm<qxwDcyNz#A@No2{96i&2 z?G-%nZN2vXn7mfsO)?MnESjsHwHAiqh|9q(S1(nru29U(>%BTxXlvq&S1;TvO1YY9 tr|Bk1k0^TUPu$}keX609HU?2N0Ws;HWLGTB1><iF87bMxm$k*Ve*if99-ROH
new file mode 100755 index 0000000000000000000000000000000000000000..4246920a6171aaa8d30190391e4403789217012c GIT binary patch literal 963 zc%17D@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QY`6?zK#qG>ra@ocD)4hB}-f* zN`mv#O3D+9QW+dm@{>{(JaZG%Q-e|yQz{EjrrIztFop&Agt+opuugf?>V4mM=G$)h zDLi5soEm!t=DzE1dsQkJ!0vKSyWwTNNFqnVV{i5C{Jb`-7I$R3URCMe5^j1~l>aok z|8>LC_cKjyODas`(LODxb6zm@Nr2o0p2=@oA|5(!{J7lho^I`nZ1o-dQq^4U_w<*& zpVjfI!sxcR`#rtbNA60CdA;r%l{`ya`(e?vHyxo5?JJ+BmpxD6b72d5U@hRsrm~i= z^<`=BLz|LkN$R`!B?>reUS#QB6H=JLE8V~y_sE0CidAVoZ^5$|y<0*B&tkRD3T8hI zce<zP_rT2co{m&4m*yb>$Ghsv%lP<R*$i%ph{SOS$8aoqKW*ZhrlyyLYFqh5;yDC^ z*!kVr)_hpF=-pK9bAr*2TxD9h`JCA#iaDL{X*t|g(>g9N|J@|18ZO-{LUMgPigS21 zj|vn%i<6(sll~+)@{yD32L8~8cI!VbvAwGd4FA8I&3*%^qLLuL;Q#an3^mtJzW~N> zsi%u$NX4xrjU@sMECS3+*?^=Svx?D<q>5OVqaUOg1RQ?wa7+-mbloIn`tfXFs(NVL z(0J7-@OH1I(0WD&#+K_0!tT<AmIoE~fb_;OE9ESm(`z~DBS>onZ%1;WsF8UxM5k$k zz3(M^{~3}{jcqqnKFTE8f;HZ2IWpmq?t#+>JFYV{FdWKvu!(lurtohH2hah$2~R%@ z3Leb|nPIMAF#WWW#D0(o_Zj@+{h1^Gfb`cf|G6Y8^07Tp5u~VLzH96328bFq{Zc_w zu$q5Nt%^ERG=)K$T@EnF=`u2@3OO(Y#w=lE5jYBQe##=-CC-aVpw3Tt>b>E)*lDQq z4`^tI9`1}31v}qfHe#liQRHKPPoQB6`Wl-z7`}X9%AnBjLHdEfx#Z<f`am98WFf`K h)RDx@fJE>xG$lk{-#7cq7hv==c)I$ztaD0e0su9Tqz(W8
new file mode 100755 index 0000000000000000000000000000000000000000..030f44d2584ef9f0cfaec03d68ebd16642fe1302 GIT binary patch literal 1463 zc$^(m2~<-@6n+0gAcUlXEV5Wl5fDL95ELrq{78t2Y+(zF6ax}A2`IAb@gPWLvn(Ql zwU%(iMoIxwR6xW)0izXK(c)56h=@wvSZkwX`stiA^UlnBGxxsx<`waMcQ9yXGyq`m zxa<JZGM6S*gIw9?iU&xe8OQQr0kkN#Qi@-Zd($+}(6qpm*tE>3R1vUZQldpno;WH_ z6d;O<$=-ic<OYD{^1XvRv3tlk3_<L3NVvc57!uSXZUJ&hN9NTCI10>54Pp1e<L;JY z2ws20rq#f|2~JYj(hdm0wm#Dm1a9{rZ30F=!o1op9^pfaSm`3LrCwDC!Y84B3UU_d zClUOs2GJsx_-V}^1a?J?KqQnP{A)GtuQpFd@Y_6f1c5{L%4h_v8d?&9qc0$R)?0#> zry}rpvsa2Bc+Tt~33_q^dBRZzmY@|65N#B}@Vwn&1T!-bG0TWRz#g~AL0JALd<=nC z2W1+8Z9K5&4U!RY2x-hA*pLQ$rosLM%&XSMB5N@+mLSa!B;o?}%^F4_;LYe3AaFVY zum8~*N8tN3t{&n07hz*PbUoJbLvZk2YBQo|ASj(Pi$|bR!SqM)o1#V|YAMnt$vB9! zWe98{A>@kvUi5_oxmF-(c@I~|p&KzH5x75vhaU{GP~3C3JpdZlcx+Zs)}v^J!p456 zl{*}BG9Ls2fsfDNIZK~9E~O;cngEATc*twYNK(Hh#@_utFc7PaB_*lX3pkB{^$8^j zDJi!GB8?l*8z(-S=+niM)P#KKt^Ht~LQ{{RpKe-MFxui=nqbx(Tc7iUSr;;-46-(A zoLsv>+)F0|nlie4qs$_@t68h)Sg)R*<c8!|Ma}s)7C+bk=}uLPv=X{66)8JE5vJuB zQ*_p`G2-%MvYSODi7q!EP>3S!<W0KE1+w8g7s^E7Xl0Rqdv8DcXbgrI_S|F+c2yf# z>>i5~%B7M9YJh*-ZAR6KDhidUl^OC^xC2Hhw>DkF;cyuCySxl`Fz;8?8c5}O%v_VS zw!wav+Ghm?9<m@OVkW{Nxk%YTbYBE6Mru-%@ZD@KL%R7+hO^`F$Y+&)6XPQkb1Z=5 zEToJIHQL%}rj5aQwx9P?vIx#Z@d5lX>0(lflmw-t!nS~Z*0DNU`E9xqA3fCDTglu; z(xpn7oK-P(N249{WtEM(23OjDS#zb!NfBV}s~?sN(SO_-qv5t83yQ7EW#zo;jF{+* z&!ToZ`5PNg`e|z!lB`~~=NWNrJ8>gJ%h?y399)kTzMxF!8(Pj}VVZjR2iv}(aamDq zwVAmAl5?#^S%os*SsM4qj#XtqUUs?QV1~Kgq8$D*M}K^$ey?Mg>n-c*V!{r0n;F#v zQq6U@<;x~4{QNWhuNCG}c|4vd;Y18Sew$%<rw(Z9X|x;<&%id}8ZJpm?D@GWnu$qF z(4|V2zxms^zpcsi2}(es;0d!iu=e;>-^)K07h9bYtPk~a;x8%sUUrK2>LteT7GA8N zISaj?DP_+caUGY!PSyXfb6N2<Hhd3uM_@d|#!)Qp(PCF!{jqj-DYXYQ=R$pXnpVX| zO>=p)JlM`cmqgnw{c}_7jl5tR(}V;4eW7^<bbj{fj+*lIBwD-1-EvO&;ifdOv9i{t zP#QK9mEzMaHRW~AOV#a2Jn&GZ3UAEf&gy#2V65g=%lv>?_Z9r>!hI{r0BJaGkSP}b zysN&e-F~&nOEc}T0XWfA-V}AlopftDc)m(4q3Y-q74D-E*xE7^mmWcbnekE;+%l`S zUl7tvsI<J+Iws$>ydnAfMq%huvy7gJl#TREQT6E9)YK7omFkE)`N^43Ri+^$h}F1K iN#O48R#sN-o`7k=qr&T7xzciAY4ALK+0EO9dH(_6kXd;E
new file mode 100755 index 0000000000000000000000000000000000000000..3098763a86700200907fe01a2adb0b8820ee6451 GIT binary patch literal 1778 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 AV*mgE
new file mode 100755 index 0000000000000000000000000000000000000000..3c7edfb31faf7dba138ec6d3014dfa4bd91dbb8d GIT binary patch literal 1508 zc$~$Qi&Ila6o>cTn*<UPNdl$`qLZpT1VmmUttgieP*i9DEl?Qckq4n;5lRI+T7mM2 zf(}AZ5L6zKLJ>+MYQbuGh=@`}Ml_;r6|F_9)u93*xw*H?U(ub}bLPyM^V{#t+1*33 z$W0uU0}BAa3EwP@h8~AoY>h!%6>{_<bTn0PL@)q9+*n6H{1V2Z?9jOEm<(lhPI8t4 z1j{p06yosR$tp#(B3ZsKb661w0Fo!$wmsC(k3tYKcOQ+QmQK%LBvqM~MiHcMY#fw7 z1VB4MZXwA10Nf$S(Ajy+LaB>NPz#y$>;+~fS6C>yL_(2NAwhZo5CTBD*%JNg4NRdi zF;s3YHBT@}>LfuSZSClsiDo7_WA`wEVgv@#Cmz$v%Bb$k=<W=RAQMa$%w$;{A5Re! zIz7WKETs5+s<DwWlk~UKSY{@aqSe;Ivl_NVU@u-ml7RjDsiw1#x%6ruYN3K|-A2u% z)wlsmNkz0;>h@jOLi~5FC_%9aie<9Uj#Z)qgP76G17NE56xwwWn<rpMGnyeVVl>ln z9N8Fznk)!G+5P?m^4Q+`)%xjkj!KQbdAmlXwmDr7;f2SmQKM;t(X=!~$~0MmDk`C6 z9Qej|o?y%x6R-SYKWkj8Yi7-vJg*Pi&&(-*Jin;5&HnyF>r36JVM1UuGoqrgwst0* z)Yv_BHFSB|(UCFK|GPi{eX9xpY-hMMczf<dO3M&dQCaF^)Y;s8*NRw+8FfD6Vfi)7 zonAkDJl2Cs0t2cL8rKtJxhs}qGu^qOK|@))F0|-crU-EH0JiI#y|Oh*RzAr}DWCJI z+H-#~Up3gl7w2^@kvVcz9ejuMRl~zJKKR;*f&@H~*A|@z`qS}9O)cBT0M>Zg`KQ|Y z#_r&$kWJ^D0gdaAO*<yajROPyk`O1Sk3^i;7e?}&y&f?;KTC~bbMZL#X5Kx4l4(mv zS`fWbsl2MbEiu%Ah0G}PQ;ZI{Q~8|o2Nm>__5a-RSbcPm36MfHzB)$Zbugfxo+Y@> z)9Z_iUv1<Y0+EF(Znk$Uv!oh$_ikJ+Vag>A>jW+kq#1GSJ4rmn?IaEPu0u+mon3=Y zo;Ee$Sy&?ksPzEg<R}srdx5ZTbvpY|I*%vDwCwSkue_UJ^ImMt-Ut4+R<9T$;1|pi zYV<rD_<VSLiSGt<K{`Cr!>v~e5F9g<DHIJ1W5B;jLfC_lA$6j67KX4jW$eoLET7I2 zQN8X9m*<*}Wl)r}C#OKjW%=V3C-Nf%a?}9!B4vq8E?&L!NsEt_s2<JCUwPtC-Lg>- zAMX@WjtJ=(4w4;`nmn*M3B<esHk2d1+9#<lhm+y|k{p(*J?QAl=rgSdekr2ijOx~* zk4sq%ZC2LekwW{y=ly)vm&hn>YdNA9V~I8MQg1D`fPeQwua?#&k^`4cseV*nP@UB5 z*4JLz;J5%es^Pz<{q>?#wl(b-W47pA&BpbY{ED;S*egyoeSYOxTzw5QS{ILAd8%r5 zOBpI@b%2*eSkF6)xkcg5o4-bUD}NS@f}kM!0p4B@Ity~TkNGuL*NGJsD_dmtspq@8 zMs{daf>nKuLRc#J{%%x3WTpq46_$6}i+8?jBvy9h!JTW(0+{{aZ+x9=+e7_3j8i^2 zxfbaGLRMH@6`aD+!=Wo~{<bS2BCfdTOi<mKGlPlO@B8yEZ-JycE~urCri||EyIa)h z={?=8`<%6tGHWjWlY8uusfm@&eebthWhnmaVb$FPs0P_Jeo8TLOgC^%Tk;79&qF{` W>LQS{6Z-?cdJrBODeaIX75oP~Ex-c+
new file mode 100644 --- /dev/null +++ b/scripts/java/questdlg.m @@ -0,0 +1,81 @@ +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{P} =} questdlg (@var{MESSAGE}, @var{TITLE}) +## @deftypefnx {Function file} @var{P} = questdlg (@var{MESSAGE}, @var{TITLE}, @var{DEFAULT}) +## @deftypefnx {Function file} @var{P} = questdlg (@var{MESSAGE}, @var{TITLE}, @var{BTN1}, @var{BTN2}, @var{DEFAULT}) +## @deftypefnx {Function file} @var{P} = questdlg (@var{MESSAGE}, @var{TITLE}, @var{BTN1}, @var{BTN2}, @var{BTN3}, @var{DEFAULT}) +## +## Displays the @var{MESSAGE} using a question dialog box. +## The dialog contains two or three buttons which all close the dialog. +## It returns the caption of the activated button. +## +## The @var{TITLE} can be used optionally to decorate the dialog caption. +## The string @var{DEFAULT} identifies the default button, +## which is activated by pressing the ENTER key. +## It must match one of the strings given in @var{BTN1}, @var{BTN2} or @var{BTN3}. +## +## If only @var{MESSAGE} and @var{TITLE} are specified, three buttons with +## the default captions "Yes", "No", "Cancel" are used. +## +## If only two button captions @var{BTN1} and @var{BTN2} are specified, +## the dialog will have only these two buttons. +## +## @end deftypefn +## @seealso{errordlg, helpdlg, inputdlg, listdlg, warndlg} + +function ret = questdlg(question,varargin) + + if length(varargin) < 1 + print_usage(); + end + + options{1} = 'Yes'; % button1 + options{2} = 'No'; % button2 + options{3} = 'Cancel'; % button3 + options{4} = 'Yes'; % default + + + switch length(varargin) + case 1 + % title was given + title = varargin{1}; + case 2 + % title and default button string + title = varargin{1}; + options{4} = varargin{2}; % default + case 4 + % title, two buttons and default button string + title = varargin{1}; + options{1} = varargin{2}; % button1 + options{2} = ''; % not used, no middle button + options{3} = varargin{3}; % button3 + options{4} = varargin{4}; % default + case 5 + % title, three buttons and default button string + title = varargin{1}; + options{1} = varargin{2}; % button1 + options{2} = varargin{3}; % button2 + options{3} = varargin{4}; % button3 + options{4} = varargin{5}; % default + otherwise + print_usage(); + end + + + ret = java_invoke ('org.octave.JDialogBox', 'questdlg', question, title, options); + +end
new file mode 100644 --- /dev/null +++ b/scripts/java/warndlg.m @@ -0,0 +1,36 @@ +## Copyright (C) 2010 Martin Hepperle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function file} {@var{P} =} warndlg (@var{MESSAGE} [,@var{TITLE}]) +## +## Displays the @var{MESSAGE} using a warning dialog box. +## The @var{TITLE} can be used optionally to decorate the dialog caption. +## +## @end deftypefn +## @seealso{helpdlg, inputdlg, listdlg, questiondlg} + +function ret = warndlg(message,varargin) + + switch length (varargin) + case 0 + title = 'Warning Dialog'; + otherwise + title = varargin{1}; + endswitch + + ret = java_invoke ('org.octave.JDialogBox', 'warndlg', message, title); + +endfunction