Mercurial > hg > octave-lojdl
changeset 16553:2ed5bc680c71 classdef
maint: periodic merge of default to classdef
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Mon, 22 Apr 2013 16:37:53 -0400 |
parents | bde729ba8381 (current diff) 8fc1f6535380 (diff) |
children | 8abae9ea4cb5 |
files | libgui/default-qt-settings libgui/qterminal/libqterminal/QTerminal libgui/src/documentation-dockwidget.cc libgui/src/documentation-dockwidget.h libgui/src/files-dockwidget.cc libgui/src/files-dockwidget.h libgui/src/history-dockwidget.cc libgui/src/history-dockwidget.h libgui/src/octave-adapter/octave-event-listener.h libgui/src/octave-adapter/octave-link.cc libgui/src/octave-adapter/octave-link.h libgui/src/octave-adapter/octave-main-thread.cc libgui/src/octave-adapter/octave-main-thread.h libgui/src/octave-qt-event-listener.cc libgui/src/octave-qt-event-listener.h libgui/src/symbol-information.cc libgui/src/symbol-information.h libgui/src/terminal-dockwidget.cc libgui/src/terminal-dockwidget.h libinterp/Makefile.am libinterp/interp-core/pt-jit.cc libinterp/interpfcn/symtab.cc libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/octave-value/ov.cc libinterp/octave.cc libinterp/parse-tree/lex.h libinterp/parse-tree/lex.ll libinterp/parse-tree/module.mk libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/parse-private.h libinterp/parse-tree/parse.h libinterp/parse-tree/pt-bp.cc libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-id.cc libinterp/parse-tree/pt-id.h libinterp/parse-tree/token.cc libinterp/parse-tree/token.h scripts/java/dlgtest.m scripts/java/errordlg.m scripts/java/helpdlg.m scripts/java/inputdlg.m scripts/java/listdlg.m scripts/java/msgbox.m scripts/java/questdlg.m scripts/java/warndlg.m test/Makefile.am test/classes/module.mk |
diffstat | 272 files changed, 10714 insertions(+), 5193 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgsubstate +++ b/.hgsubstate @@ -1,1 +1,1 @@ -cec099cbf54f2d3a49367c03df101f3cf35c20c7 gnulib-hg +5a51fb7777a9950502965a043a70bd6ca5e0498b gnulib-hg
--- a/Makefile.am +++ b/Makefile.am @@ -69,8 +69,16 @@ include m4/module.mk -# Subdirectories in which to run `make all'. -SUBDIRS = libgnu liboctave libinterp @GUIDIR@ src scripts @DOCDIR@ examples test +# Subdirectories in which to run `make all'. Including "." here +# is an attempt to force all preceding directories in the list to +# be processed before the current directory so that the +# scripts/DOCSTRINGS libinterp/DOCSTRINGS files are built before +# attempting to build AUTHORS and BUGS. +SUBDIRS = libgnu liboctave libinterp +if AMCOND_BUILD_GUI +SUBDIRS += libgui +endif +SUBDIRS += src scripts . @DOCDIR@ examples test if ! AMCOND_BUILD_DOCS dist-hook: @@ -97,6 +105,7 @@ CONFIG_FILES = @ac_config_headers@ @ac_config_files@ nodist_octinclude_HEADERS = config.h +octinclude_HEADERS = oct-conf-post.h all-local: $(noinst_SCRIPTS) $(INFO_FILES) .gdbinit @echo ""
--- a/NEWS +++ b/NEWS @@ -17,6 +17,41 @@ Summary of important user-visible changes for version 3.8: --------------------------------------------------------- + ** strsplit has been modified to be compatible with Matlab. There + are two instances where backward compatibility is broken. + + (1) Delimiters are now string vectors, not scalars. + + Octave's legacy behavior + + strsplit ("1 2, 3", ", ") + ans = + { + [1,1] = 1 + [1,2] = 2 + [1,3] = + [1,4] = 3 + } + + Matlab compatible behavior + + strsplit ("1 2, 3", ", ") + ans = + { + [1,1] = 1 2 + [1,2] = 3 + } + + (2) By default, Matlab treats consecutive delimiters are as a single + delimiter. By default, Octave's legacy behavior was to return an + empty string for the part between the delmiters. + + Where the legacy behavior is desired, the call to strsplit() should + specify that the delimitertype is "legacy". + + strsplit (str, del, "collapsedelimiters", false, + "delimitertype", "legacy") + ** Octave now supports nested functions with scoping rules that are compatible with Matlab. A nested function is one declared and defined within the body of another function. The nested function is only @@ -118,20 +153,21 @@ ** The default name of the Octave crash dump file is now called octave-workspace instead of octave-core. + ** A citation command has been added to display information on how to + cite Octave and packages in publications. The package system will + look for and install CITATION files from packages. + ** The java package from Octave Forge is now part of core 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 + debug_java java_matrix_autoconversion + isjava java_unsigned_autoconversion + java2mat javaaddpath + javaArray javaclasspath + javaMethod javamem + javaObject javarmpath + usejava In addition, the following functions that use the Java interface are now available (provided that Octave is compiled with support for @@ -142,8 +178,8 @@ ** Other new functions added in 3.8.0: - betaincinv dawson fminsearch polyeig tetramesh - cmpermute erfcinv importdata rgbplot + betaincinv dawson fminsearch polyeig strjoin + cmpermute erfcinv importdata rgbplot tetramesh cmunique erfi iscolormap shrinkfaces colorcube findfigs lines splinefit @@ -162,7 +198,15 @@ be removed from Octave 3.12 (or whatever version is the second major release after 3.8): - <none yet> + java_convert_matrix + java_debug + java_get + java_invoke + java_new + java_set + java_unsigned_conversion + javafields + javamethods The following keywords have been deprecated in Octave 3.8 and will be removed from Octave 3.12 (or whatever version is the second major @@ -177,10 +221,6 @@ CC_VERSION (now GCC_VERSION) CXX_VERSION (now GXX_VERSION) - ** A citation command has been added to display information on how to - cite Octave and packages in publications. The package system will - look for and install CITATION files from packages. - Summary of important user-visible changes for version 3.6: ---------------------------------------------------------
--- a/build-aux/common.mk +++ b/build-aux/common.mk @@ -67,6 +67,9 @@ DEFAULT_PAGER = @DEFAULT_PAGER@ +DEFAULT_TERMINAL_FONT = @DEFAULT_TERMINAL_FONT@ +DEFAULT_TERMINAL_FONT_SIZE = @DEFAULT_TERMINAL_FONT_SIZE@ + ENABLE_DYNAMIC_LINKING = @ENABLE_DYNAMIC_LINKING@ SHLEXT = @SHLEXT@ @@ -702,6 +705,14 @@ $(simple_move_if_change_rule) endef +define do_subst_qt_settings +echo "making $@ from $<" +$(SED) < $< \ + -e "s|%DEFAULT_TERMINAL_FONT%|${DEFAULT_TERMINAL_FONT}|" \ + -e "s|%DEFAULT_TERMINAL_FONT_SIZE%|${DEFAULT_TERMINAL_FONT_SIZE}|" > $@-t +$(simple_move_if_change_rule) +endef + define test-file-commands ( echo "## DO NOT EDIT! Generated automatically from $(<F) by Make."; $(GREP) '^%!' $< ) > $@-t mv $@-t $@
--- a/configure.ac +++ b/configure.ac @@ -19,13 +19,13 @@ ### <http://www.gnu.org/licenses/>. AC_PREREQ([2.62]) -AC_INIT([GNU Octave], [3.7.2+], [http://octave.org/bugs.html], [octave]) +AC_INIT([GNU Octave], [3.7.3+], [http://octave.org/bugs.html], [octave]) dnl PACKAGE_VERSION is set by the AC_INIT VERSION arg OCTAVE_VERSION="$PACKAGE_VERSION" OCTAVE_API_VERSION_NUMBER="48" OCTAVE_API_VERSION="api-v$OCTAVE_API_VERSION_NUMBER+" -OCTAVE_RELEASE_DATE="2013-02-09" +OCTAVE_RELEASE_DATE="2013-04-22" OCTAVE_COPYRIGHT="Copyright (C) 2013 John W. Eaton and others." AC_SUBST(OCTAVE_VERSION) AC_SUBST(OCTAVE_API_VERSION_NUMBER) @@ -37,7 +37,7 @@ dnl AC_REVISION field whenever configure.ac is modified. dnl AC_REVISION($Revision: 1.603 $) AC_CONFIG_SRCDIR([libinterp/octave.cc]) -AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_HEADERS([config.h:config.in.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) @@ -130,6 +130,19 @@ OCTAVE_PROG_PAGER OCTAVE_PROG_PYTHON +### Default terminal font for the GUI +case $host_os in + mingw* | msdosmsvc) + DEFAULT_TERMINAL_FONT="Lucida Console" + ;; + *) + DEFAULT_TERMINAL_FONT="Courier" + ;; +esac +DEFAULT_TERMINAL_FONT_SIZE=10 +AC_SUBST(DEFAULT_TERMINAL_FONT) +AC_SUBST(DEFAULT_TERMINAL_FONT_SIZE) + ### Path separator. sepchar=':' @@ -190,17 +203,6 @@ AC_DEFINE(BOUNDS_CHECKING, 1, [Define to 1 to use internal bounds checking.]) fi -### Enable experimental push parser. - -OCTAVE_USE_PUSH_PARSER=no -AC_ARG_ENABLE([push-parser], - [AS_HELP_STRING([--enable-push-parser], - [enable experimental push parser])], - [if test "$enableval" = yes; then OCTAVE_USE_PUSH_PARSER=yes; fi], []) -if test $OCTAVE_USE_PUSH_PARSER = yes; then - AC_DEFINE(OCTAVE_USE_PUSH_PARSER, 1, [Define to 1 to use experimental push parser.]) -fi - ### Use Octave's built-in memory allocator rather than straightforward malloc. ### Disabled by default. @@ -254,17 +256,9 @@ AC_CHECK_SIZEOF([void *]) AC_CHECK_SIZEOF([int]) AC_CHECK_SIZEOF([long]) + AC_CHECK_SIZEOF([int64_t]) if test $ac_cv_sizeof_void_p -eq 8; then - if test $ac_cv_sizeof_int -eq 8; then - OCTAVE_IDX_TYPE=int - elif test $ac_cv_sizeof_long -eq 8; then - OCTAVE_IDX_TYPE=long - AC_DEFINE(IDX_TYPE_LONG, 1, [Define to 1 if octave index type is long.]) - else - warn_64_bit="no suitable type found for octave_idx_type so disabling 64-bit features" - OCTAVE_CONFIGURE_WARNING([warn_64_bit]) - USE_64_BIT_IDX_T=no - fi + OCTAVE_IDX_TYPE=int64_t else warn_64_bit="pointers are not 64-bits wide; disabling 64-bit features" OCTAVE_CONFIGURE_WARNING([warn_64_bit]) @@ -713,6 +707,11 @@ [ZLIB library not found. Octave will not be able to save or load compressed data files or HDF5 files.], [zlib.h], [gzclearerr]) +### Also define HAVE_ZLIB if libz is found. +if test $octave_cv_lib_z = yes; then + AC_DEFINE(HAVE_ZLIB, 1, [Define to 1 if ZLIB is available.]) +fi + ### Check for the LLVM library build_jit=no @@ -842,9 +841,16 @@ OCTAVE_CHECK_FFTW_THREADS(fftw3f, fftwf_plan_with_nthreads) fi +## Octave is currently unable to use FFTW unless both float +## and double versions are available. + AM_CONDITIONAL([AMCOND_HAVE_FFTW], [test -n "$FFTW3_LIBS" && test -n "$FFTW3F_LIBS"]) +if test -n "$FFTW3_LIBS" && test -n "$FFTW3F_LIBS"; then + AC_DEFINE(HAVE_FFTW, 1, [Define if you have both FFTW3 and FFTW3F libraries.]) +fi + ## Subdirectory of liboctave/cruft to build if FFTW is not found. FFT_DIR="fftpack" AC_SUBST(FFT_DIR) @@ -1295,6 +1301,16 @@ fi LIBS="$save_LIBS" +if test $USE_64_BIT_IDX_T = yes; then + CHOLMOD_TAG="_l_" + CXSPARSE_TAG="_dl_" + UMFPACK_TAG="_zl_" +else + CHOLMOD_TAG="_" + CXSPARSE_TAG="_di_" + UMFPACK_TAG="_zi_" +fi + ### Check for AMD library OCTAVE_CHECK_LIB(amd, AMD, @@ -1336,7 +1352,7 @@ OCTAVE_CHECK_LIB(cholmod, CHOLMOD, [CHOLMOD library not found. This will result in some lack of functionality for sparse matrices.], [suitesparse/cholmod.h ufsparse/cholmod.h cholmod/cholmod.h cholmod.h], - [cholmod_start], + [cholmod${CHOLMOD_TAG}start], [], [don't use CHOLMOD library, disable some sparse matrix functionality]) LIBS="$save_LIBS" @@ -1345,7 +1361,7 @@ OCTAVE_CHECK_LIB(cxsparse, CXSparse, [CXSparse library not found. This will result in some lack of functionality for sparse matrices.], [suitesparse/cs.h ufsparse/cs.h cxsparse/cs.h cs.h], - [cs_di_sqr], + [cs${CXSPARSE_TAG}sqr], [C++], [don't use CXSparse library, disable some sparse matrix functionality]) ### Check for UMFPACK library. @@ -1357,21 +1373,21 @@ OCTAVE_CHECK_LIB([umfpack], UMFPACK, [UMFPACK not found. This will result in some lack of functionality for sparse matrices.], [suitesparse/umfpack.h ufsparse/umfpack.h umfpack/umfpack.h umfpack.h], - [umfpack_zi_get_determinant], + [umfpack${UMFPACK_TAG}get_determinant], [], [don't use UMFPACK, disable some sparse matrix functionality]) CPPFLAGS="$save_CPPFLAGS" LIBS="$save_LIBS" if test -z "$UMFPACK_LIBS"; then ## Invalidate the cache and try again with -lcblas. - $as_unset ac_cv_lib_umfpack_umfpack_zi_get_determinant + $as_unset ac_cv_lib_umfpack_umfpack${UMFPACK_TAG}get_determinant $as_unset octave_cv_lib_umfpack save_LIBS="$LIBS" LIBS="-lcblas $AMD_LDFLAGS $AMD_LIBS $BLAS_LIBS $FLIBS $LIBS" OCTAVE_CHECK_LIB([umfpack], UMFPACK, [UMFPACK not found. This will result in some lack of functionality for sparse matrices.], [suitesparse/umfpack.h ufsparse/umfpack.h umfpack/umfpack.h umfpack.h], - [umfpack_zi_get_determinant], + [umfpack${UMFPACK_TAG}get_determinant], [], [don't use UMFPACK, disable some sparse matrix functionality]) if test -n "$UMFPACK_LIBS"; then UMFPACK_LIBS="$UMFPACK_LIBS -lcblas" @@ -2382,7 +2398,7 @@ ## Check Java version is recent enough. AC_MSG_CHECKING([for Java version]) - java_version=[`"$JAVA" -version 2>&1 | sed -n -e 's/^java version[^0-9"]*"\([^"]*\)"/\1/p'`] + java_version=[`"$JAVA" -version 2>&1 | sed -n -e 's/^[^ ]* version[^0-9"]*"\([^"]*\)"/\1/p'`] AC_MSG_RESULT([$java_version]) java_major=[`echo $java_version | sed -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\)\..*$/\1/'`] java_minor=[`echo $java_version | sed -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\)\..*$/\2/'`] @@ -2558,7 +2574,6 @@ QT_LIBS= win32_terminal=no build_gui=yes -GUIDIR=libgui AC_ARG_ENABLE([gui], [AS_HELP_STRING([--disable-gui], [don't build the GUI])], [if test "$enableval" = no; then build_gui=no; fi], []) @@ -2587,7 +2602,7 @@ AC_CHECK_PROGS(MOC, [moc-qt5 moc-qt4 moc]) AC_CHECK_PROGS(UIC, [uic-qt5 uic-qt4 uic]) AC_CHECK_PROGS(RCC, [rcc]) - AC_CHECK_PROGS(LRELEASE, [lrelease]) + AC_CHECK_PROGS(LRELEASE, [lrelease-qt5 lrelease-qt4 lrelease]) if test -n "$MOC" && test -n "$UIC" && test -n "$RCC" && test -n "$LRELEASE"; then AC_DEFINE(HAVE_QT, 1, [Define to 1 if Qt is available (libraries, developer header files, utility programs (moc, uic, rcc, and lrelease))]) @@ -2659,16 +2674,12 @@ fi fi -if test $build_gui = no; then - ## GUI disabled. Eliminate building GUIDIR directory - GUIDIR= -fi AM_CONDITIONAL([AMCOND_BUILD_GUI], [test $build_gui = yes]) +AM_CONDITIONAL([AMCOND_HAVE_QSCINTILLA], [test "$octave_cv_lib_qscintilla" = yes]) AM_CONDITIONAL([WIN32_TERMINAL], [test $win32_terminal = yes]) AC_SUBST(QT_CPPFLAGS) AC_SUBST(QT_LDFLAGS) AC_SUBST(QT_LIBS) -AC_SUBST(GUIDIR) ### Run configure in subdirectories. @@ -2676,172 +2687,7 @@ export CXX export F77 -### Some things to add to the bottom of config.h. - -dnl ------------------------------------------------------------ - -AH_BOTTOM([ -#if !defined (GNULIB_NAMESPACE) -#define GNULIB_NAMESPACE gnulib -#endif - -#if defined (__GNUC__) -#define GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__)) -#define HAVE_ATTR_DEPRECATED - -#define GCC_ATTR_NORETURN __attribute__ ((__noreturn__)) -#define HAVE_ATTR_NORETURN - -#define GCC_ATTR_UNUSED __attribute__ ((__unused__)) -#define HAVE_ATTR_UNUSED -#else -#define GCC_ATTR_DEPRECATED -#define GCC_ATTR_NORETURN -#define GCC_ATTR_UNUSED -#endif - -#define X_CAST(T, E) (T) (E) - -#if defined (CXX_BROKEN_REINTERPRET_CAST) -#define FCN_PTR_CAST(T, E) (T) (E) -#else -#define FCN_PTR_CAST(T, E) reinterpret_cast<T> (E) -#endif - -#if ! defined (HAVE_DEV_T) -typedef short dev_t; -#endif - -#if ! defined (HAVE_INO_T) -typedef unsigned long ino_t; -#endif - -#if defined (_MSC_VER) -#define __WIN32__ -#define WIN32 -/* missing parameters in macros */ -#pragma warning (disable: 4003) -/* missing implementations in template instantiation */ -#pragma warning (disable: 4996) -/* deprecated function names (FIXME?) */ -#pragma warning (disable: 4661) -#endif - -#if defined (__WIN32__) && ! defined (__CYGWIN__) -#define OCTAVE_HAVE_WINDOWS_FILESYSTEM 1 -#elif defined (__CYGWIN__) -#define OCTAVE_HAVE_WINDOWS_FILESYSTEM 1 -#define OCTAVE_HAVE_POSIX_FILESYSTEM 1 -#else -#define OCTAVE_HAVE_POSIX_FILESYSTEM 1 -#endif - -/* Define to 1 if we expect to have <windows.h>, Sleep, etc. */ -#if defined (__WIN32__) && ! defined (__CYGWIN__) -#define OCTAVE_USE_WINDOWS_API 1 -#endif - -#if defined (__APPLE__) && defined (__MACH__) -#define OCTAVE_USE_OS_X_API 1 -#endif - -/* sigsetjmp is a macro, not a function. */ -#if defined (sigsetjmp) && defined (HAVE_SIGLONGJMP) -#define OCTAVE_HAVE_SIG_JUMP -#endif - -#if defined (_UNICOS) -#define F77_USES_CRAY_CALLING_CONVENTION -#endif - -#if 0 -#define F77_USES_VISUAL_FORTRAN_CALLING_CONVENTION -#endif - -#ifdef USE_64_BIT_IDX_T -#define SIZEOF_OCTAVE_IDX_TYPE 8 -#else -#define SIZEOF_OCTAVE_IDX_TYPE SIZEOF_INT -#endif - -/* To be able to use long doubles for 64-bit mixed arithmetics, we need - them at least 80 bits wide and we need roundl declared in math.h. - FIXME: Maybe substitute this by a more precise check in the future? */ -#if (SIZEOF_LONG_DOUBLE >= 10) && defined (HAVE_ROUNDL) -#define OCTAVE_INT_USE_LONG_DOUBLE -#endif - -#define OCTAVE_EMPTY_CPP_ARG - -/* Octave is currently unable to use FFTW unless both float - and double versions are available. */ -#if defined (HAVE_FFTW3) && defined (HAVE_FFTW3F) -#define HAVE_FFTW -#endif - -/* Backward compatibility. */ -#if defined (HAVE_Z) -#define HAVE_ZLIB -#endif - -/* oct-dlldefs.h */ - -#if defined (_MSC_VER) -#define OCTAVE_EXPORT __declspec(dllexport) -#define OCTAVE_IMPORT __declspec(dllimport) -#else -/* All other compilers, at least for now. */ -#define OCTAVE_EXPORT -#define OCTAVE_IMPORT -#endif - -/* API macro for libcruft */ -#ifdef CRUFT_DLL -#define CRUFT_API OCTAVE_EXPORT -#else -#define CRUFT_API OCTAVE_IMPORT -#endif - -/* API macro for liboctave */ -#ifdef OCTAVE_DLL -#define OCTAVE_API OCTAVE_EXPORT -#else -#define OCTAVE_API OCTAVE_IMPORT -#endif - -/* API macro for libinterp */ -#ifdef OCTINTERP_DLL -#define OCTINTERP_API OCTAVE_EXPORT -#else -#define OCTINTERP_API OCTAVE_IMPORT -#endif - -/* API macro for libinterp/graphics */ -#ifdef OCTGRAPHICS_DLL -#define OCTGRAPHICS_API OCTAVE_EXPORT -#else -#define OCTGRAPHICS_API OCTAVE_IMPORT -#endif - -/* API macro for libgui */ -#ifdef OCTGUI_DLL -#define OCTGUI_API OCTAVE_EXPORT -#else -#define OCTGUI_API OCTAVE_IMPORT -#endif - -/* oct-types.h */ - -typedef OCTAVE_IDX_TYPE octave_idx_type; - -#include <stdint.h> - -/* Tag indicating Octave config.h has been included */ -#define OCTAVE_CONFIG_INCLUDED 1 -]) - -dnl end of AH_BOTTOM -dnl ------------------------------------------------------------ +AH_BOTTOM([#include "oct-conf-post.h"]) ### Make all AC_DEFINES available to testif feature of test.m function. ### This must reside at the bottom of configure.ac after all AC_DEFINES @@ -2855,6 +2701,7 @@ AC_SUBST(ac_config_headers) AC_CONFIG_FILES([ + oct-conf-post.h:oct-conf-post.in.h Makefile doc/Makefile doc/doxyhtml/Makefile @@ -2978,7 +2825,6 @@ Build Java interface: $build_java Do internal array bounds checking: $BOUNDS_CHECKING Use octave_allocator: $USE_OCTAVE_ALLOCATOR - Use push parser: $OCTAVE_USE_PUSH_PARSER Build static libraries: $STATIC_LIBS Build shared libraries: $SHARED_LIBS Dynamic Linking: $ENABLE_DYNAMIC_LINKING $DL_API_MSG
--- a/doc/interpreter/contributors.in +++ b/doc/interpreter/contributors.in @@ -51,6 +51,7 @@ Christos Dimitrakakis Pantxo Diribarne Vivek Dogra +John Donoghue David M. Doolin Carnë Draug Pascal A. Dupuis
--- a/doc/interpreter/doccheck/aspell-octave.en.pws +++ b/doc/interpreter/doccheck/aspell-octave.en.pws @@ -126,6 +126,8 @@ circ circshift circum +classpath +classpaths Clenshaw clim cloglog @@ -263,6 +265,7 @@ errorbar Errorbars errorbars +errordlg ErrorHandler Esmond et @@ -385,6 +388,7 @@ hdf headerlines heartsuit +helpdlg Helvetica Hermitian Hessenberg @@ -432,6 +436,7 @@ inline Inline inpolygon +inputdlg internet interp interpderiv @@ -455,12 +460,15 @@ iy Jacobian Jacobians +javaaddpath +javamem ji JIT jpeg JPEG jpg jvm +JVM's keybindings keypress Kolmogorov @@ -506,6 +514,7 @@ linespec linespoints linkprop +listdlg literalspacing Liu LLVM @@ -592,6 +601,7 @@ mpower mput mrdivide +msgbox MSYS mtimes Multi @@ -746,6 +756,7 @@ quantile Quantile quantiles +questdlg Quickhull qz QZ @@ -796,6 +807,7 @@ rpath RPMs rr +runtime sa Saad Sandia @@ -931,6 +943,7 @@ texinfo Texinfo TextAlphaBits +textfield textscan th ths @@ -1029,6 +1042,7 @@ waitbar waitbars wallis +warndlg wblcdf wblinv wblpdf
--- a/doc/interpreter/java.txi +++ b/doc/interpreter/java.txi @@ -24,18 +24,18 @@ @cindex calling Java from Octave @cindex Java, calling from Octave @cindex calling Octave from Java -@cindex Octave, calling from Java +@cindex Octave, calling from Java The Java Interface is designed for calling Java functions from within Octave. If you want to do the reverse, and call Octave from within Java, try -a library like +a library like @code{javaOctave} (@url{http://kenai.com/projects/javaOctave}) or -@code{joPas} (@url{http://jopas.sourceforge.net}). +@code{joPas} (@url{http://jopas.sourceforge.net}). @menu -* Java Interface Functions:: -* Dialog Box Functions:: -* FAQ - Frequently asked Questions:: +* Java Interface Functions:: +* Dialog Box Functions:: +* FAQ - Frequently asked Questions:: @end menu @node Java Interface Functions @@ -43,21 +43,21 @@ The following functions are the core of the Java Interface. They provide a way to create a Java object, get and set its data fields, and call Java -methods which return results to Octave. +methods which return results to Octave. @cindex object, creating a Java object @DOCSTRING(javaObject) @cindex fields, displaying available fields of a Java object -FIXME: Need documentation on how fieldnames() is overloaded to return +@strong{FIXME:} Need documentation on how fieldnames() is overloaded to return the methods of a Java object. @cindex field, returning value of Java object field -FIXME: Need documentation on how to use structure-like indexing +@strong{FIXME:} Need documentation on how to use structure-like indexing to get fields from Java object. @cindex field, setting value of Java object field -FIXME: Need documentation on how to use structure-like indexing +@strong{FIXME:} Need documentation on how to use structure-like indexing to set fields from Java object. @DOCSTRING(isjava) @@ -69,7 +69,7 @@ @DOCSTRING(javaMethod) @cindex methods, displaying available methods of a Java object -FIXME: Need documentation on how methods() is overloaded to return +@strong{FIXME:} Need documentation on how methods() is overloaded to return the methods of a Java object. The following three functions are used to display and modify the @@ -141,44 +141,43 @@ @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?:: +* 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?:: +* 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? +@subsection How to distinguish between Octave and Matlab? @anchor{doc-FAQ} @c - index - -@cindex Octave and Matlab, how to distinguish between +@cindex Octave and @sc{matlab}, how to distinguish between @c - index - -Octave and @sc{matlab} are very similar, but handle Java slightly different. +Octave and @sc{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. +performance hit. -Example: +Example: @example @group %% -%% Return: true if the environment is Octave. +%% Return: true if the environment is Octave. %% -function ret = isOctave - persistent retval; % speeds up repeated calls +function retval = isOctave + persistent cacheval; % speeds up repeated calls - if isempty(retval) - retval = (exist('Octave_VERSION','builtin') > 0); - end + if isempty (cacheval) + cacheval = (exist ('OCTAVE_VERSION', 'builtin') > 0); + end - ret = retval; -end + retval = cacheval; +end @end group @end example @@ -190,13 +189,14 @@ @cindex classpath, difference between static and dynamic @cindex static classpath @cindex dynamic classpath +@cindex @file{javaclasspath.txt} @cindex @file{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 -@sc{matlab} the @var{classpath} is composed of two parts: +archive files and/or directories containing class files. In Octave +the @var{classpath} is composed of two parts: @itemize @item the @var{static classpath} is initialized once at startup of the JVM, and @@ -207,66 +207,74 @@ 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 +and loaded from this location. Classes which will be used frequently 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 @file{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. +named @file{javaclasspath.txt} (or @file{classpath.txt} historically) 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 @samp{#} or a +@samp{%} character are ignored. -The search rules for the file @file{classpath.txt} are: +The search rules for the file @file{javaclasspath.txt} +(or @file{classpath.txt}) are: @itemize -@item First, Octave searches for the file @file{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 First, Octave tries to locate it in the current directory (where Octave +was started from). If such a file is found, it is read and defines the initial +@var{static classpath}. Thus, it is possible to define a static classpath on a +'per Octave invocation' basis. -@item Next, Octave looks for another file @file{classpath.txt} in the package -installation directory. This is where @file{javaclasspath.m} resides, usually -something like @file{@dots{}\share\Octave\packages\java-1.2.8}. You can find -this directory by executing the command +@item Next, Octave searches in the user's home directory. If a file +@file{javaclasspath.txt} exists here, its contents are appended to the static +classpath (if any). Thus, it is possible to build an initial static classpath +on a 'per user' basis. + +@item Finally, Octave looks for a next occurrence of file +@file{javaclasspath.txt} in the m-files directory where Octave Java functions +live. This is where @file{javaclasspath.m} resides, usually something like +@file{@env{OCTAVE_HOME}/share/octave/@env{OCTAVE_VERSION}/m/java/}. You can +find this directory by executing the command @example -pkg list +which javaclasspath @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. +If this file exists here, its contents are also appended to the static +classpath. Note that the archives and class directories defined in this last +step 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. +runtime using the @code{javaaddpath} and @code{javarmpath} functions. -Example: +Example: @example -octave> base_path = 'C:/Octave/java_files'; +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> % 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@}); +octave> % check the dynamic classpath +octave> p = javaclasspath; +octave> disp (p@{1@}); C:/Octave/java_files/someclasses.jar -octave> disp(p@{2@}); +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@}); +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. +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 @@ -274,13 +282,13 @@ directory. All Octave commands in this file are executed each time you start a new instance of Octave. The following example adds the directory @file{octave} to Octave's search path and the archive @file{myclasses.jar} in this directory -to the Java search path. +to the Java search path. @example @group -% content of .octaverc: -addpath('~/octave'); -javaaddpath('~/octave/myclasses.jar'); +% contents of .octaverc: +addpath ('~/octave'); +javaaddpath ('~/octave/myclasses.jar'); @end group @end example @@ -292,21 +300,12 @@ @cindex instance, how to create @c - index - -If your code shall work under Octave as well as @sc{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 @sc{matlab} -environment. +The function @code{javaObject} can be used to create Java objects.. -Example 1, suitable for Octave but not for @sc{matlab}: +Example: @example - Passenger = java_new('package.FirstClass', row, seat); -@end example - -Example 2, which works in Octave as well as in @sc{matlab}: - -@example - Passenger = javaObject('package.FirstClass', row, seat); +Passenger = javaObject ('package.FirstClass', row, seat); @end example @c ------------------------------------------------------------------------ @@ -314,42 +313,36 @@ @subsection How can I handle memory limitations? @cindex memory, limitations -In order to execute Java code Octave creates a Java Virtual Machine (JVM). +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 +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 @sc{matlab}, you can specify options for the creation -of the JVM inside a file named @file{java.opts}. This is a text file where you -can enter lines containing @option{-X} and @option{-D} options handed to the -JVM during initialization. +You can specify options for the creation of the JVM inside a file named +@file{java.opts}. This is a text file where you can enter lines containing +@option{-X} and @option{-D} options handed to the JVM during initialization. -In Octave, the Java options file must be located in the directory where -@file{javaclasspath.m} resides, i.e., the package installation directory, -usually something like @file{@dots{}\share\Octave\packages\java-1.2.8}. You can -find this directory by executing +The directory where the Java options file is located is specified by the +environment variable @w{@env{OCTAVE_JAVA_DIR}}. If unset the directory where +@file{javaclasspath.m} resides is used instead (typically +@file{@env{OCTAVE_HOME}/share/octave/@env{OCTAVE_VERSION}/m/java/}). You can +find this directory by executing @example -pkg list +which javaclasspath @end example -In @sc{matlab}, the options file goes into the @file{MATLABROOT/bin/ARCH} -directory or in your personal @sc{matlab} startup directory (can be determined -by a @samp{pwd} command). @var{MATLABROOT} is the @sc{matlab} root directory -and @var{ARCH} is your system architecture, which you find by issuing the -commands @samp{matlabroot} respectively @samp{computer('arch')}. - The @option{-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 -@file{java.opts} file: +available to the JVM@. The following example allows up to 256 Megabytes to +be used by adding the following line to the @file{java.opts} file: @example --Xmx256m +-Xmx256m @end example The maximum possible amount of memory depends on your system. On a Windows @@ -359,33 +352,32 @@ 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 @file{java.opts} file starts the JVM with 64 -Megabytes of initial memory: +Megabytes of initial memory: @example --Xms64m +-Xms64m @end example For more details on the available @option{-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 @option{-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. +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}. +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: +or in Octave: @example @group -octave> javaMethod('java.lang.System', 'getProperty', 'MyProperty'); +octave> javaMethod ('getProperty', 'java.lang.System', 'MyProperty'); ans = 12.34 @end group @end example @@ -393,197 +385,6 @@ @seealso{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 -@group -octave> pkg list -Package Name | Version | Installation directory ---------------+---------+----------------------- - java *| 1.2.8 | /home/octavio/octave/java-1.2.8 -octave> -@end group -@end example - -@noindent -If the @var{java} package appears in the list you must uninstall it first by -issuing the command - -@example -@group -octave> pkg uninstall java -octave> pkg list -@end group -@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 -@w{@env{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 @w{@env{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 @file{z:} drive the -command would be: - -@example -Octave> pkg install -verbose z:/java-1.2.8.tar.gz -@end example - -@noindent -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 @option{-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 -@group -octave> pkg list -Package Name | Version | Installation directory ---------------+---------+----------------------- - java *| 1.2.8 | /home/octavio/octave/java-1.2.8 -octave> -@end group -@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 -@group -octave> s = javaObject('java.lang.String', 'Hello OctaveString') -s = Hello OctaveString -@end group -@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 -@group -octave> v = javaObject('java.util.Vector') -v = -<Java object: java.util.Vector> -octave> v.add(12); -octave> v.get(0) -ans = 12 -@end group -@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 -@group -% 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 group -@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 - @@ -592,7 +393,7 @@ @cindex translation table for @TeX{} symbols @c - index - -The dialog functions contain a translation table for @TeX{} like symbol codes. +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 @@ -611,7 +412,7 @@ @ifhtml @float Table The table below shows each @TeX{} character code and the corresponding Unicode -character: +character: @multitable @columnfractions 0.18 0.1 0.05 0.18 0.1 0.05 0.18 0.1 @item \alpha @tab 'α' @@ -879,7 +680,8 @@ @c --------------------------------- @iftex @float Table -The table below shows each @TeX{} character code and the corresponding Unicode character: +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
--- a/doc/interpreter/octave.texi +++ b/doc/interpreter/octave.texi @@ -379,16 +379,17 @@ * The try Statement:: * Continuation Lines:: -The @code{switch} Statement +The switch Statement * Notes for the C Programmer:: -The @code{for} Statement +The for Statement * Looping Over Structure Elements:: Functions and Scripts +* Introduction to Function and Script Files:: * Defining Functions:: * Multiple Return Values:: * Variable-length Argument Lists:: @@ -407,6 +408,7 @@ * Manipulating the Load Path:: * Subfunctions:: * Private Functions:: +* Nested Functions:: * Overloading and Autoloading:: * Function Locking:: * Function Precedence:: @@ -761,6 +763,20 @@ * FTP Objects:: * URL Manipulation:: +Java Interface + +* Java Interface Functions:: +* Dialog Box Functions:: +* FAQ - Frequently asked Questions:: + +FAQ - Frequently asked Questions + +* 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?:: +* Which @TeX{} symbols are implemented in the dialog functions?:: + Packages * Installing and Removing Packages::
--- a/doc/interpreter/strings.txi +++ b/doc/interpreter/strings.txi @@ -427,6 +427,8 @@ @DOCSTRING(strfind) +@DOCSTRING(strjoin) + @DOCSTRING(strmatch) @DOCSTRING(strtok)
--- a/doc/liboctave/liboctave.texi +++ b/doc/liboctave/liboctave.texi @@ -80,10 +80,10 @@ @end ifnottex @titlepage -@title{Octave C++ Classes} -@subtitle{Edition 1.0 for Octave version @value{VERSION}} -@subtitle{September 1993} -@author{John W. Eaton} +@title Octave C++ Classes +@subtitle Edition 1.0 for Octave version @value{VERSION} +@subtitle September 1993 +@author John W. Eaton @page @vskip 0pt plus 1filll Copyright @copyright{} 1996, 1997 John W. Eaton.
--- a/examples/embedded.cc +++ b/examples/embedded.cc @@ -16,7 +16,7 @@ octave_value_list in; for (octave_idx_type i = 0; i < n; i++) - in(i) = octave_value (5 * (i + 1)); + in(i) = octave_value (5 * (i + 2)); octave_value_list out = feval ("gcd", in, 1);
--- a/libgui/Makefile.am +++ b/libgui/Makefile.am @@ -26,17 +26,19 @@ octlib_LTLIBRARIES = liboctgui.la -locales = \ - languages/be_BY.qm \ - languages/de_DE.qm \ - languages/en_US.qm \ - languages/es_ES.qm \ - languages/nl_NL.qm \ - languages/pt_BR.qm \ - languages/ru_RU.qm \ - languages/uk_UA.qm +TRANSLATIONS = \ + languages/be_BY.ts \ + languages/de_DE.ts \ + languages/en_US.ts \ + languages/es_ES.ts \ + languages/nl_NL.ts \ + languages/pt_BR.ts \ + languages/ru_RU.ts \ + languages/uk_UA.ts -EXTRA_DIST = default-qt-settings $(locales) +LOCALES = $(patsubst languages/%.ts, languages/%.qm, $(TRANSLATIONS)) + +EXTRA_DIST = default-qt-settings.in $(TRANSLATIONS) CLEANFILES = BUILT_SOURCES = @@ -79,16 +81,24 @@ octetc_DATA = default-qt-settings -octlocale_DATA = $(locales) +octlocale_DATA = $(LOCALES) + +default-qt-settings: default-qt-settings.in + $(do_subst_qt_settings) moc-%.cc: %.h - @MOC@ -o$@ $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(MOC_CPPFLAGS) $(liboctgui_la_CPPFLAGS) $< + $(MOC) -o$@ $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(MOC_CPPFLAGS) $(liboctgui_la_CPPFLAGS) $< ui-%.h: %.ui - @UIC@ -o $@ $< + $(UIC) -o $@ $< qrc-%.cc: %.qrc - @RCC@ -o $@ $< + $(RCC) -o $@ $< %.qm: %.ts - @LRELEASE@ $< + $(MKDIR_P) languages + $(LRELEASE) -qm $@ $< + +DISTCLEANFILES = \ + $(LOCALES) +
rename from libgui/default-qt-settings rename to libgui/default-qt-settings.in --- a/libgui/default-qt-settings +++ b/libgui/default-qt-settings.in @@ -5,12 +5,6 @@ autoIdentification=false useCustomFileEditor=false customFileEditor=emacs -showFilenames=true -showFileSize=false -showFileType=false -showLastModified=false -showHiddenFiles=false -useAlternatingRowColors=true useProxyServer=false proxyType= proxyHostName=none @@ -22,15 +16,13 @@ showLineNumbers=true highlightCurrentLine=true codeCompletion=true -fontName=Courier -fontSize=10 longWindowTitle=false restoreSession=false savedSessionTabs=@Invalid() [terminal] -fontSize=10 -fontName=Courier +fontSize=%DEFAULT_TERMINAL_FONT_SIZE% +fontName=%DEFAULT_TERMINAL_FONT% cursorBlinking=true cursorType=ibeam @@ -69,3 +61,10 @@ sort_files_by_column=0 sort_files_by_order=0 column_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x4\xe\0\0\0\x3\0\0\0\x3\0\0\0\x64\0\0\0\x2\0\0\0\x64\0\0\0\x1\0\0\0\x64\0\0\0\xd4\0\0\0\x4\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x2\0\0\0\xd4\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x3\0\0\0\0) +showFilenames=true +showFileSize=false +showFileType=false +showLastModified=false +showHiddenFiles=false +sync_octave_directory=true +useAlternatingRowColors=true
--- a/libgui/qterminal-module.mk +++ b/libgui/qterminal-module.mk @@ -46,7 +46,8 @@ qterminal_libqterminal_la_SOURCES = \ qterminal/libqterminal/win32/QTerminalColors.cpp \ - qterminal/libqterminal/win32/QWinTerminalImpl.cpp + qterminal/libqterminal/win32/QWinTerminalImpl.cpp \ + qterminal/libqterminal/QTerminal.cc qterminal_libqterminal_la_MOC += \ qterminal/libqterminal/win32/moc-QWinTerminalImpl.cc @@ -73,7 +74,8 @@ qterminal/libqterminal/unix/Vt102Emulation.cpp \ qterminal/libqterminal/unix/SelfListener.cpp \ qterminal/libqterminal/unix/TerminalModel.cpp \ - qterminal/libqterminal/unix/TerminalView.cpp + qterminal/libqterminal/unix/TerminalView.cpp \ + qterminal/libqterminal/QTerminal.cc qterminal_libqterminal_la_MOC += \ qterminal/libqterminal/unix/moc-Emulation.cc \
deleted file mode 100644 --- a/libgui/qterminal/libqterminal/QTerminal +++ /dev/null @@ -1,23 +0,0 @@ -/* - -Copyright (C) 2012 Michael Goffioul. -Copyright (C) 2012 Jacob Dawid. - -This file is part of QTerminal. - -Foobar 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 3 of the License, or -(at your option) any later version. - -QTerminal 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 Foobar. If not, see <http://www.gnu.org/licenses/>. - -*/ - -#include "QTerminal.h"
new file mode 100644 --- /dev/null +++ b/libgui/qterminal/libqterminal/QTerminal.cc @@ -0,0 +1,50 @@ +/* + +Copyright (C) 2012 Michael Goffioul. +Copyright (C) 2012 Jacob Dawid. + +This file is part of QTerminal. + +Foobar 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 3 of the License, or +(at your option) any later version. + +QTerminal 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 Foobar. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "QTerminal.h" + +void +QTerminal::notice_settings (const QSettings *settings) +{ + // QSettings pointer is checked before emitting. + + // Set terminal font: + QFont term_font = QFont(); + term_font.setFamily(settings->value("terminal/fontName","Courier New").toString()); + term_font.setPointSize(settings->value("terminal/fontSize",10).toInt ()); + setTerminalFont (term_font); + + QString cursorType = settings->value ("terminal/cursorType","ibeam").toString (); + bool cursorBlinking = settings->value ("terminal/cursorBlinking",true).toBool (); + if (cursorType == "ibeam") + setCursorType(QTerminalInterface::IBeamCursor, cursorBlinking); + else if (cursorType == "block") + setCursorType(QTerminalInterface::BlockCursor, cursorBlinking); + else if (cursorType == "underline") + setCursorType(QTerminalInterface::UnderlineCursor, cursorBlinking); +} + +void +QTerminal::relay_command (const QString& command) +{ + sendText (command); +}
--- a/libgui/qterminal/libqterminal/QTerminal.h +++ b/libgui/qterminal/libqterminal/QTerminal.h @@ -23,6 +23,7 @@ #ifndef QTERMINAL_H #define QTERMINAL_H +#include <QSettings> #include <QtGlobal> #ifdef Q_OS_WIN32 @@ -34,6 +35,10 @@ QTerminal(QWidget *xparent = 0) : QWinTerminalImpl(xparent) { } ~QTerminal() { } + + public slots: + void notice_settings (const QSettings *settings); + void relay_command (const QString& text); }; #else #include "unix/QUnixTerminalImpl.h" @@ -44,6 +49,10 @@ QTerminal(QWidget *xparent = 0) : QUnixTerminalImpl(xparent) { } ~QTerminal() { } + + public slots: + void notice_settings (const QSettings *settings); + void relay_command (const QString& command); }; #endif
--- a/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp +++ b/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp @@ -75,6 +75,10 @@ void QUnixTerminalImpl::connectToPty() { + // Store the file descriptor associated with the STDERR stream onto + // another temporary file descriptor for reconnect in the destructor. + fdstderr = dup (STDERR_FILENO); + int fds = m_kpty->slaveFd(); dup2 (fds, STDIN_FILENO); @@ -96,6 +100,9 @@ QUnixTerminalImpl::~QUnixTerminalImpl() { + // Restore stderr so that any errors at exit might appear somewhere. + dup2 (fdstderr, STDERR_FILENO); + emit destroyed(); }
--- a/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h +++ b/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h @@ -30,10 +30,13 @@ class QUnixTerminalImpl : public QTerminalInterface { Q_OBJECT + + int fdstderr; + public: QUnixTerminalImpl(QWidget *parent = 0); virtual ~QUnixTerminalImpl(); - + void setTerminalFont(const QFont &font); void setSize(int h, int v); void sendText(const QString& text); @@ -43,12 +46,12 @@ public slots: void copyClipboard(); void pasteClipboard(); - + protected: void focusInEvent(QFocusEvent *focusEvent); void showEvent(QShowEvent *); virtual void resizeEvent(QResizeEvent *); - + private: void initialize(); void connectToPty();
--- a/libgui/qterminal/libqterminal/unix/SelfListener.cpp +++ b/libgui/qterminal/libqterminal/unix/SelfListener.cpp @@ -23,7 +23,7 @@ } void SelfListener::run() { - char buf[4096]; + char buf[4096 + 1]; int len; bool running = true; while(running) {
--- a/libgui/qterminal/libqterminal/unix/TerminalView.cpp +++ b/libgui/qterminal/libqterminal/unix/TerminalView.cpp @@ -49,6 +49,8 @@ #include "unix/ScreenWindow.h" #include "unix/TerminalCharacterDecoder.h" +#include <signal.h> + #ifndef loc #define loc(X,Y) ((Y)*_columns+(X)) #endif @@ -1408,6 +1410,9 @@ { //qDebug("%s %d updateImageSize", __FILE__, __LINE__); showResizeNotification(); +#if defined (SIGWINCH) + ::raise (SIGWINCH); +#endif emit changedContentSizeSignal(_contentHeight, _contentWidth); // expose resizeEvent } //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
--- a/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp +++ b/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp @@ -116,6 +116,7 @@ private: QFont m_font; QColor m_backgroundColor; + QColor m_foregroundColor; QString m_command; QConsoleColors m_colors; bool m_inWheelEvent; @@ -224,10 +225,13 @@ GetConsoleTitleW (titleBuf, sizeof (titleBuf)); q->setWindowTitle (QString::fromWCharArray (titleBuf)); + m_backgroundColor = Qt::white; + m_foregroundColor = Qt::black; + SetConsoleTextAttribute (m_stdOut, 0xF0); + m_font.setFamily ("Lucida Console"); m_font.setPointSize (9); m_font.setStyleHint (QFont::TypeWriter); - m_backgroundColor = Qt::black; m_buffer = m_tmpBuffer = 0; @@ -748,7 +752,7 @@ return; p.setFont (d->m_font); - p.setPen (Qt::black); + p.setPen (d->m_foregroundColor); ascent = p.fontMetrics ().ascent (); stride = d->m_consoleRect.width ();
new file mode 100644 --- /dev/null +++ b/libgui/src/color-picker.cc @@ -0,0 +1,55 @@ +// +// This class provides a simple color picker based on tQColorButton +// by Harald Jedele, 23.03.01, GPL version 2 or any later version. +// +// Copyright (C) FZI Forschungszentrum Informatik Karlsruhe +// Copyright (C) 2013 Torsten <ttl@justmail.de> +// +// This file is part of Octave. +// +// Octave 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 3 of the License, or (at your +// option) any later version. +// +// Octave 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/>. +// + +#include "color-picker.h" + +// constuctor with initial color as parameter +color_picker::color_picker (QColor old_color, QWidget* p) : QPushButton (p) +{ + _color = old_color; + setFlat (true); + update_button (); + connect(this, SIGNAL (clicked ()), SLOT (select_color ())); +} + +// slot for bitton clicked: selct a new color using QColorDialog +void +color_picker::select_color () +{ + QColor new_color = QColorDialog::getColor (_color); + if (new_color.isValid () && new_color != _color) + { + _color = new_color; + update_button (); + } +} + +// draw the button with the actual color (using a stylesheet) +void color_picker::update_button () +{ + QString css = QString("background-color: %1; border: none;" ) + .arg(_color.name()); + setStyleSheet(css); + repaint (); +}
new file mode 100644 --- /dev/null +++ b/libgui/src/color-picker.h @@ -0,0 +1,47 @@ +// +// This class provides a simple color picker based on tQColorButton +// by Harald Jedele, 23.03.01, GPL version 2 or any later version. +// +// Copyright (C) FZI Forschungszentrum Informatik Karlsruhe +// Copyright (C) 2013 Torsten <ttl@justmail.de> +// +// This file is part of Octave. +// +// Octave 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 3 of the License, or (at your +// option) any later version. +// +// Octave 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/>. +// + +#ifndef COLORPICKER_H +#define COLORPICKER_H + +#include <QPushButton> +#include <QColorDialog> + +class color_picker: public QPushButton +{ + Q_OBJECT + +public: + color_picker (QColor color = QColor(0,0,0), QWidget *parent = 0); + QColor color () const { return _color; } + +private slots: + void select_color (); + +private: + virtual void update_button (); + QColor _color; +}; + +#endif
new file mode 100644 --- /dev/null +++ b/libgui/src/dialog.cc @@ -0,0 +1,486 @@ +/* + +Copyright (C) 2013 John W. Eaton +Copyright (C) 2013 Daniel J. Sebald + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "dialog.h" + +#include <QString> +#include <QStringList> +#include <QStringListModel> +#include <QListView> +// Could replace most of these with #include <QtGui> +#include <QMessageBox> +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QPushButton> +#include <QGroupBox> +#include <QGridLayout> +#include <QLabel> + +QUIWidgetCreator uiwidget_creator; + + +QUIWidgetCreator::QUIWidgetCreator (void) + : QObject (), dialog_result (-1), dialog_button (), + string_list (new QStringList ()), list_index (new QIntList ()) +{ } + + +QUIWidgetCreator::~QUIWidgetCreator (void) +{ + delete string_list; + delete list_index; +} + + +void +QUIWidgetCreator::dialog_button_clicked (QAbstractButton *button) +{ + // Store the value so that builtin functions can retrieve. + if (button) + dialog_button = button->text (); + + // The value should always be 1 for the Octave functions. + dialog_result = 1; + + // Wake up Octave process so that it continues. + waitcondition.wakeAll (); +} + + +void +QUIWidgetCreator::list_select_finished (const QIntList& selected, const int button_pressed) +{ + // Store the value so that builtin functions can retrieve. + *list_index = selected; + dialog_result = button_pressed; + + // Wake up Octave process so that it continues. + waitcondition.wakeAll (); +} + + +void +QUIWidgetCreator::input_finished (const QStringList& input, const int button_pressed) +{ + // Store the value so that builtin functions can retrieve. + *string_list = input; + dialog_result = button_pressed; + + // Wake up Octave process so that it continues. + waitcondition.wakeAll (); +} + + +MessageDialog::MessageDialog (const QString& message, + const QString& title, + const QString& qsicon, + const QStringList& qsbutton, + const QString& defbutton, + const QStringList& role) + : QMessageBox (QMessageBox::NoIcon, title.isEmpty () ? " " : title, + message, 0, 0) +{ + // Create a NonModal message. + setWindowModality (Qt::NonModal); + + // Interpret the icon string, because enumeration QMessageBox::Icon can't + // easily be made to pass through a signal. + QMessageBox::Icon eicon = QMessageBox::NoIcon; + if (qsicon == "error") + eicon = QMessageBox::Critical; + else if (qsicon == "warn") + eicon = QMessageBox::Warning; + else if (qsicon == "help") + eicon = QMessageBox::Information; + else if (qsicon == "quest") + eicon = QMessageBox::Question; + setIcon (eicon); + + int N = qsbutton.size () < role.size () ? qsbutton.size () : role.size (); + if (N == 0) + addButton (QMessageBox::Ok); + else + { + for (int i = N-1; i >= 0; i--) + { + // Interpret the button role string, because enumeration + // QMessageBox::ButtonRole can't be made to pass through a signal. + QString srole = role.at (i); + QMessageBox::ButtonRole erole = QMessageBox::InvalidRole; + if (srole == "YesRole") + erole = QMessageBox::YesRole; + else if (srole == "NoRole") + erole = QMessageBox::NoRole; + else if (srole == "RejectRole") + erole = QMessageBox::RejectRole; + else if (srole == "AcceptRole") + erole = QMessageBox::AcceptRole; + + QPushButton *pbutton = addButton (qsbutton.at (i), erole); + if (qsbutton.at (i) == defbutton) + setDefaultButton (pbutton); + // Make the last button the button pressed when <esc> key activated. + if (i == N-1) + { +#define ACTIVE_ESCAPE true +#if ACTIVE_ESCAPE + setEscapeButton (pbutton); +#else + setEscapeButton (0); +#endif +#undef ACTIVE_ESCAPE + } + } + } + + connect (this, SIGNAL (buttonClicked (QAbstractButton *)), + &uiwidget_creator, SLOT (dialog_button_clicked (QAbstractButton *))); +} + + +ListDialog::ListDialog (const QStringList& list, const QString& mode, + int wd, int ht, const QList<int>& initial, + const QString& title, const QStringList& prompt, + const QString& ok_string, const QString& cancel_string) + : QDialog () +{ + // Put the list of items into a model. Keep this off of the stack + // because this conceivably could be a very large list. + QAbstractItemModel *model = new QStringListModel (list); + + QListView *view = new QListView; + view->setModel (model); + + if (mode == "Single") + view->setSelectionMode (QAbstractItemView::SingleSelection); + else if (mode == "Multiple") + view->setSelectionMode (QAbstractItemView::ExtendedSelection); +// else if () +// view->setSelectionMode (QAbstractItemView::ContiguousSelection); +// else if () +// view->setSelectionMode (QAbstractItemView::MultiSelection); + else + view->setSelectionMode (QAbstractItemView::NoSelection); + + selector = view->selectionModel (); + int i = 0; + for (QList<int>::const_iterator it = initial.begin (); + it != initial.end (); it++) + { + QModelIndex idx = model->index (initial.value (i++) - 1, 0, + QModelIndex ()); + selector->select (idx, QItemSelectionModel::Select); + } + + bool fixed_layout = false; + if (wd > 0 && ht > 0) + { + view->setFixedSize (wd, ht); + fixed_layout = true; + } + + view->setEditTriggers (QAbstractItemView::NoEditTriggers); + + QVBoxLayout *listLayout = new QVBoxLayout; + if (! prompt.isEmpty ()) + { + // For now, assume html-like Rich Text. May be incompatible + // with something down the road, but just testing capability. + QString prompt_string; + for (int j = 0; j < prompt.length (); j++) + { + if (j > 0) +#define RICH_TEXT true +#if RICH_TEXT + prompt_string.append ("<br>"); +#else + prompt_string.append ("\n"); +#endif + prompt_string.append (prompt.at (j)); + } + QLabel *plabel = new QLabel (prompt_string); +#if RICH_TEXT + plabel->setTextFormat (Qt::RichText); +#endif +#undef RICH_TEXT + listLayout->addWidget (plabel); + } + listLayout->addWidget (view); + QPushButton *select_all = new QPushButton (tr ("Select All")); + select_all->setEnabled (mode == "Multiple"); + listLayout->addWidget (select_all); + + QPushButton *buttonOk = new QPushButton (ok_string); + QPushButton *buttonCancel = new QPushButton (cancel_string); + QHBoxLayout *buttonsLayout = new QHBoxLayout; + buttonsLayout->addStretch (1); + buttonsLayout->addWidget (buttonOk); + buttonsLayout->addWidget (buttonCancel); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout (listLayout); + mainLayout->addSpacing (12); + mainLayout->addLayout (buttonsLayout); + setLayout (mainLayout); + if (fixed_layout) + layout()->setSizeConstraint (QLayout::SetFixedSize); + + // If empty, make blank rather than use default OS behavior. + setWindowTitle (title.isEmpty () ? " " : title); + + connect (select_all, SIGNAL (clicked ()), + view, SLOT (selectAll ())); + + connect (buttonOk, SIGNAL (clicked ()), + this, SLOT (buttonOk_clicked ())); + + connect (buttonCancel, SIGNAL (clicked ()), + this, SLOT (buttonCancel_clicked ())); + + connect (this, SIGNAL (finish_selection (const QIntList&, const int)), + &uiwidget_creator, + SLOT (list_select_finished (const QIntList&, const int))); +} + + +void +ListDialog::buttonOk_clicked (void) +{ + // Store information about what button was pressed so that builtin + // functions can retrieve. + QModelIndexList selected_index = selector->selectedIndexes (); + QIntList selected_int; + + for (int i = 0; i < selected_index.size (); i++) + selected_int << selected_index.at (i).row () + 1; + + emit finish_selection (selected_int, 1); + + done (QDialog::Accepted); +} + + +void +ListDialog::buttonCancel_clicked (void) +{ + // Store information about what button was pressed so that builtin + // functions can retrieve. + QIntList empty; + + emit finish_selection (empty, 0); + + done (QDialog::Rejected); +} + + +void +ListDialog::reject (void) +{ + buttonCancel_clicked (); +} + + +InputDialog::InputDialog (const QStringList& prompt, const QString& title, + const QFloatList& nr, const QFloatList& nc, + const QStringList& defaults) + : QDialog () +{ + +#define LINE_EDIT_FOLLOWS_PROMPT false + +#if LINE_EDIT_FOLLOWS_PROMPT + // Prompt on left followed by input on right. + QGridLayout *promptInputLayout = new QGridLayout; +#else + // Prompt aligned above input. + QVBoxLayout *promptInputLayout = new QVBoxLayout; +#endif + int N_gridrows = prompt.size (); + for (int i = 0; i < N_gridrows; i++) + { + QLabel *label = new QLabel (prompt.at (i)); + QLineEdit *line_edit = new QLineEdit (defaults.at (i)); + if (nr.at (i) > 0) + { + QSize qsize = line_edit->sizeHint (); + int intval = qsize.height () * nr.at (i); + line_edit->setFixedHeight (intval); + if (nc.at (i) > 0) + { + intval = qsize.height () * nc.at (i) / 2; + line_edit->setFixedWidth (intval); + } + } + input_line << line_edit; +#if LINE_EDIT_FOLLOWS_PROMPT + promptInputLayout->addWidget (label, i + 1, 0); + promptInputLayout->addWidget (line_edit, i + 1, 1); +#else + promptInputLayout->addWidget (label); + promptInputLayout->addWidget (line_edit); +#endif + } +#undef LINE_EDIT_FOLLOWS_PROMPT + + QPushButton *buttonOk = new QPushButton("OK"); + QPushButton *buttonCancel = new QPushButton("Cancel"); + QHBoxLayout *buttonsLayout = new QHBoxLayout; + buttonsLayout->addStretch (1); + buttonsLayout->addWidget (buttonOk); + buttonsLayout->addWidget (buttonCancel); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout (promptInputLayout); + mainLayout->addSpacing (12); + mainLayout->addLayout (buttonsLayout); + setLayout (mainLayout); + + // If empty, make blank rather than use default OS behavior. + setWindowTitle (title.isEmpty () ? " " : title); + + connect (buttonOk, SIGNAL (clicked ()), + this, SLOT (buttonOk_clicked ())); + + connect (buttonCancel, SIGNAL (clicked ()), + this, SLOT (buttonCancel_clicked ())); + + connect (this, SIGNAL (finish_input (const QStringList&, const int)), + &uiwidget_creator, + SLOT (input_finished (const QStringList&, const int))); +} + + +void +InputDialog::buttonOk_clicked (void) +{ + // Store information about what button was pressed so that builtin + // functions can retrieve. + QStringList string_result; + for (int i = 0; i < input_line.size (); i++) + string_result << input_line.at (i)->text (); + emit finish_input (string_result, 1); + done (QDialog::Accepted); +} + + +void +InputDialog::buttonCancel_clicked (void) +{ + // Store information about what button was pressed so that builtin + // functions can retrieve. + QStringList empty; + emit finish_input (empty, 0); + done (QDialog::Rejected); +} + + +void +InputDialog::reject (void) +{ + buttonCancel_clicked (); +} + + +cd_or_addpath_dialog::cd_or_addpath_dialog (const QString& file, + const QString& dir, + bool addpath_option) + : QDialog () +{ + QString prompt_string + = (addpath_option + ? tr ("The file %1 does not exist in the load path. To debug the function you are editing, you must either change to the directory %2 or add that directory to the load path.").arg(file).arg(dir) + : tr ("The file %1 is shadowed by a file with the same name in the load path. To debug the function you are editing, change to the directory %2.").arg(file).arg(dir)); + + QLabel *label = new QLabel (prompt_string); + label->setFixedWidth (500); + label->setWordWrap (true); + // QIcon *question_mark = new QIcon; + QHBoxLayout *horizontalLayout = new QHBoxLayout; + // horizontalLayout->addWidget (question_mark); + horizontalLayout->addWidget (label); + + QPushButton *buttonCd = new QPushButton (tr ("Change directory")); + QPushButton *buttonAddpath = 0; + if (addpath_option) + buttonAddpath = new QPushButton (tr ("Add directory to load path")); + QPushButton *buttonCancel = new QPushButton (tr ("Cancel")); + + QHBoxLayout *buttonsLayout = new QHBoxLayout; + buttonsLayout->addStretch (1); + buttonsLayout->addWidget (buttonCd); + if (addpath_option) + buttonsLayout->addWidget (buttonAddpath); + buttonsLayout->addWidget (buttonCancel); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout (horizontalLayout); + mainLayout->addSpacing (12); + mainLayout->addLayout (buttonsLayout); + setLayout (mainLayout); + + setWindowTitle (tr ("Change Directory or Add Directory to Load Path")); + + connect (buttonCd, SIGNAL (clicked ()), + this, SLOT (buttonCd_clicked ())); + + if (addpath_option) + connect (buttonAddpath, SIGNAL (clicked ()), + this, SLOT (buttonAddpath_clicked ())); + + connect (buttonCancel, SIGNAL (clicked ()), + this, SLOT (buttonCancel_clicked ())); + + connect (this, SIGNAL (finished (int)), + &uiwidget_creator, SLOT (dialog_finished (int))); +} + +void +cd_or_addpath_dialog::buttonCd_clicked (void) +{ + emit finished (1); + done (QDialog::Accepted); +} + +void +cd_or_addpath_dialog::buttonAddpath_clicked (void) +{ + emit finished (2); + done (QDialog::Accepted); +} + +void +cd_or_addpath_dialog::buttonCancel_clicked (void) +{ + emit finished (-1); + done (QDialog::Rejected); +} + +void +cd_or_addpath_dialog::reject (void) +{ + buttonCancel_clicked (); +}
new file mode 100644 --- /dev/null +++ b/libgui/src/dialog.h @@ -0,0 +1,263 @@ +/* + +Copyright (C) 2013 John W. Eaton +Copyright (C) 2013 Daniel J. Sebald + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#if !defined (octave_guifcn_dialog_h) +#define octave_guifcn_dialog_h 1 + +#include <QMutex> +#include <QWaitCondition> +#include <QAbstractButton> +#include <QList> +#include <QItemSelectionModel> +#include <QDialog> +#include <QMessageBox> +#include <QLineEdit> + +// Defined for purposes of sending QList<int> as part of signal. +typedef QList<int> QIntList; + +// Defined for purposes of sending QList<float> as part of signal. +typedef QList<float> QFloatList; + + +class QUIWidgetCreator : public QObject +{ + Q_OBJECT + +public: + + QUIWidgetCreator (void); + + ~QUIWidgetCreator (void); + +public: + + void signal_dialog (const QString& message, const QString& title, + const QString& icon, const QStringList& button, + const QString& defbutton, const QStringList& role) + { + + // Use the last button in the list as the reject result, i.e., when no + // button is pressed such as in the case of the upper right close tab. + if (!button.isEmpty ()) + dialog_button = button.last (); + + QString xicon = icon; + if (xicon.isEmpty ()) + xicon = "none"; + + emit create_dialog (message, title, xicon, button, defbutton, role); + }; + + int get_dialog_result (void) { return dialog_result; } + + const QString *get_dialog_button (void) { return &dialog_button; } + + bool signal_listview (const QStringList& list, const QString& mode, + int wd, int ht, const QList<int>& initial, + const QString& name, const QStringList& prompt, + const QString& ok_string, const QString& cancel_string) + { + if (list.isEmpty ()) + return false; + + emit create_listview (list, mode, wd, ht, initial, name, + prompt, ok_string, cancel_string); + + return true; + }; + + const QIntList *get_list_index (void) { return list_index; } + + bool signal_inputlayout (const QStringList& prompt, const QString& title, + const QFloatList& nr, const QFloatList& nc, + const QStringList& defaults) + { + if (prompt.isEmpty ()) + return false; + + emit create_inputlayout (prompt, title, nr, nc, defaults); + + return true; + }; + + // The debug dialog functionality may not really belong here, but it + // seems like the easiest thing to do at the moment. + + bool signal_debug_cd_or_addpath (const QString& file, const QString& dir, + bool addpath_option) + { + emit create_debug_cd_or_addpath_dialog (file, dir, addpath_option); + + return true; + } + + const QStringList *get_string_list (void) { return string_list; } + + void wait (void) + { + // Wait while the user is responding to message box. + waitcondition.wait (&mutex); + } + +signals: + + void create_dialog (const QString&, const QString&, const QString&, + const QStringList&, const QString&, const QStringList&); + + void create_listview (const QStringList&, const QString&, int, int, + const QIntList&, const QString&, const QStringList&, + const QString&, const QString&); + + void create_inputlayout (const QStringList&, const QString&, + const QFloatList&, const QFloatList&, + const QStringList&); + + void create_debug_cd_or_addpath_dialog (const QString&, const QString&, bool); + +public slots: + + void dialog_button_clicked (QAbstractButton *button); + + void list_select_finished (const QIntList& selected, + const int button_pressed); + + void input_finished (const QStringList& input, const int button_pressed); + +private: + + int dialog_result; + QString dialog_button; + + // The list could conceivably be big. Not sure how things are + // stored internally, so keep off of the stack. + QStringList *string_list; + QIntList *list_index; + + // GUI objects cannot be accessed in the non-GUI thread. However, + // signals can be sent to slots across threads with proper + // synchronization. Hence, the use of QWaitCondition. + + QMutex mutex; + + QWaitCondition waitcondition; +}; + +extern QUIWidgetCreator uiwidget_creator; + + +class MessageDialog : public QMessageBox +{ + Q_OBJECT + +public: + + explicit MessageDialog (const QString& message, const QString& title, + const QString& icon, const QStringList& button, + const QString& defbutton, + const QStringList& role); + +private: + + void closeEvent (QCloseEvent *) + { + // Reroute the close tab to a button click so there is only a single + // route to waking the wait condition. + emit buttonClicked (0); + } +}; + + +class ListDialog : public QDialog +{ + Q_OBJECT + + QItemSelectionModel *selector; + +public: + + explicit ListDialog (const QStringList& list, const QString& mode, + int width, int height, const QList<int>& initial, + const QString& name, const QStringList& prompt, + const QString& ok_string, const QString& cancel_string); + +signals: + + void finish_selection (const QIntList&, const int); + +public slots: + + void buttonOk_clicked (void); + + void buttonCancel_clicked (void); + + void reject (void); +}; + + +class InputDialog : public QDialog +{ + Q_OBJECT + + QList<QLineEdit *> input_line; + +public: + + explicit InputDialog (const QStringList& prompt, const QString& title, + const QFloatList& nr, const QFloatList& nc, + const QStringList& defaults); + +signals: + + void finish_input (const QStringList&, const int); + +public slots: + + void buttonOk_clicked (void); + + void buttonCancel_clicked (void); + + void reject (void); +}; + +class cd_or_addpath_dialog : public QDialog +{ + Q_OBJECT + +public: + + cd_or_addpath_dialog (const QString& file, const QString& dir, + bool addpath_option); + +public slots: + + void buttonCd_clicked (void); + + void buttonAddpath_clicked (void); + + void buttonCancel_clicked (void); + + void reject (void); +}; + +#endif
rename from libgui/src/documentation-dockwidget.cc rename to libgui/src/documentation-dock-widget.cc --- a/libgui/src/documentation-dockwidget.cc +++ b/libgui/src/documentation-dock-widget.cc @@ -24,45 +24,16 @@ #include <config.h> #endif -#include "documentation-dockwidget.h" +#include "documentation-dock-widget.h" documentation_dock_widget::documentation_dock_widget (QWidget *p) - : QDockWidget (p) + : octave_dock_widget (p) { setObjectName ("DocumentationDockWidget"); - setWindowIcon (QIcon(":/actions/icons/logo.png")); + setWindowIcon (QIcon (":/actions/icons/logo.png")); setWindowTitle (tr ("Documentation")); - - connect (this, SIGNAL (visibilityChanged (bool)), - this, SLOT (handle_visibility_changed (bool))); - // topLevelChanged is emitted when floating property changes (floating = true) - connect (this, SIGNAL (topLevelChanged(bool)), this, SLOT(top_level_changed(bool))); + setStatusTip (tr ("See the documentation for help.")); _webinfo = new webinfo (this); setWidget (_webinfo); } - -void -documentation_dock_widget::handle_visibility_changed (bool visible) -{ - if (visible) - emit active_changed (true); -} - -void -documentation_dock_widget::closeEvent (QCloseEvent *e) -{ - emit active_changed (false); - QDockWidget::closeEvent (e); -} - -// slot for signal that is emitted when floating property changes -void -documentation_dock_widget::top_level_changed (bool floating) -{ - if(floating) - { - setWindowFlags(Qt::Window); // make a window from the widget when floating - show(); // make it visible again since setWindowFlags hides it - } -}
rename from libgui/src/documentation-dockwidget.h rename to libgui/src/documentation-dock-widget.h --- a/libgui/src/documentation-dockwidget.h +++ b/libgui/src/documentation-dock-widget.h @@ -23,30 +23,20 @@ #ifndef DOCUMENTATIONDOCKWIDGET_H #define DOCUMENTATIONDOCKWIDGET_H -#include <QObject> -#include <QDockWidget> +#include "octave-dock-widget.h" + #include "webinfo.h" -class documentation_dock_widget : public QDockWidget +class documentation_dock_widget : public octave_dock_widget { Q_OBJECT - public: + +public: + documentation_dock_widget (QWidget *parent = 0); -public slots: - /** Slot to steer changing visibility from outside. */ - void handle_visibility_changed (bool visible); - /** Slot when floating property changes */ - void top_level_changed (bool floating); +private: -signals: - /** Custom signal that tells if a user has clicked away that dock widget. */ - void active_changed (bool active); - -protected: - void closeEvent (QCloseEvent *event); - -private: webinfo *_webinfo; };
rename from libgui/src/files-dockwidget.cc rename to libgui/src/files-dock-widget.cc --- a/libgui/src/files-dockwidget.cc +++ b/libgui/src/files-dock-widget.cc @@ -25,7 +25,7 @@ #endif #include "resource-manager.h" -#include "files-dockwidget.h" +#include "files-dock-widget.h" #include <QApplication> #include <QFileInfo> @@ -34,54 +34,105 @@ #include <QProcess> #include <QDebug> #include <QHeaderView> +#include <QLineEdit> +#include <QSizePolicy> +#include <QMenu> +#include <QInputDialog> +#include <QMessageBox> +#include <QToolButton> files_dock_widget::files_dock_widget (QWidget *p) : octave_dock_widget (p) { setObjectName ("FilesDockWidget"); setWindowIcon (QIcon(":/actions/icons/logo.png")); - setWindowTitle (tr ("Current Directory")); - setWidget (new QWidget (this)); + setWindowTitle (tr ("File Browser")); + setToolTip (tr ("Browse your files.")); + + QWidget *container = new QWidget (this); + + setWidget (container); + + connect (this, SIGNAL (open_file (const QString&)), + parent (), SLOT (open_file (const QString&))); + + connect (this, SIGNAL (displayed_directory_changed (const QString&)), + parent (), SLOT (set_current_working_directory (const QString&))); + + connect (parent (), SIGNAL (settings_changed (const QSettings *)), + this, SLOT (notice_settings (const QSettings *))); // Create a toolbar - _navigation_tool_bar = new QToolBar ("", widget ()); + _navigation_tool_bar = new QToolBar ("", container); _navigation_tool_bar->setAllowedAreas (Qt::TopToolBarArea); _navigation_tool_bar->setMovable (false); - _navigation_tool_bar->setIconSize (QSize (20, 20)); + + _current_directory = new QComboBox (_navigation_tool_bar); + _current_directory->setToolTip (tr ("Enter the path or filename")); + _current_directory->setEditable(true); + _current_directory->setMaxCount(MaxMRUDirs); + _current_directory->setInsertPolicy(QComboBox::NoInsert); + _current_directory->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon); + QSizePolicy sizePol(QSizePolicy::Expanding, QSizePolicy::Preferred); + _current_directory->setSizePolicy(sizePol); - _directory_icon = QIcon(":/actions/icons/up.png"); - _directory_up_action = new QAction (_directory_icon, "", _navigation_tool_bar); - _directory_up_action->setStatusTip (tr ("Move up one directory.")); + QAction *directory_up_action = new QAction (QIcon(":/actions/icons/up.png"), + "", _navigation_tool_bar); + directory_up_action->setToolTip (tr ("Move up one directory")); - _last_current_directory = ""; - _current_directory = new QLineEdit (_navigation_tool_bar); - _current_directory->setStatusTip (tr ("Enter the path or filename.")); + _sync_browser_directory_action = new QAction (QIcon(":/actions/icons/reload.png"), + tr("Show octave directory"), _navigation_tool_bar); + _sync_browser_directory_action->setToolTip (tr ("Goto current octave directory")); + _sync_browser_directory_action->setEnabled ("false"); + + _sync_octave_directory_action = new QAction (QIcon(":/actions/icons/ok.png"), + tr("Set octave directory"), _navigation_tool_bar); + _sync_octave_directory_action->setToolTip (tr ("Set octave directroy to current browser directory")); + _sync_octave_directory_action->setEnabled ("false"); - _navigation_tool_bar->addAction (_directory_up_action); - _navigation_tool_bar->addWidget (_current_directory); - connect (_directory_up_action, SIGNAL (triggered ()), this, - SLOT (do_up_directory ())); + QToolButton * popdown_button = new QToolButton(); + popdown_button->setToolTip(tr ("Actions on current directory")); + QMenu * popdown_menu = new QMenu(); + popdown_menu->addAction(_sync_browser_directory_action); + popdown_menu->addAction(_sync_octave_directory_action); + popdown_button->setMenu(popdown_menu); + popdown_button->setPopupMode(QToolButton::InstantPopup); + popdown_button->setDefaultAction(new QAction(QIcon(":/actions/icons/gear.png"),"", _navigation_tool_bar)); - // TODO: Add other buttons for creating directories + popdown_menu->addSeparator(); + popdown_menu->addAction(QIcon(":/actions/icons/filenew.png"), + tr ("New File"), + this, SLOT(popdownmenu_newfile(bool))); + popdown_menu->addAction(QIcon(":/actions/icons/folder_new.png"), + tr ("New Directory"), + this, SLOT(popdownmenu_newdir(bool))); - // Create the QFileSystemModel starting in the home directory - QString homePath = QDir::homePath (); + _navigation_tool_bar->addWidget (_current_directory); + _navigation_tool_bar->addAction (directory_up_action); + _navigation_tool_bar->addWidget (popdown_button); + connect (directory_up_action, SIGNAL (triggered ()), this, + SLOT (change_directory_up ())); + connect (_sync_octave_directory_action, SIGNAL (triggered ()), this, + SLOT (do_sync_octave_directory ())); + connect (_sync_browser_directory_action, SIGNAL (triggered ()), this, + SLOT (do_sync_browser_directory ())); + + // Create the QFileSystemModel starting in the actual directory + QDir curr_dir; _file_system_model = new QFileSystemModel (this); _file_system_model->setFilter (QDir::NoDotAndDotDot | QDir::AllEntries); - QModelIndex rootPathIndex = _file_system_model->setRootPath (homePath); + QModelIndex rootPathIndex = _file_system_model->setRootPath ( + curr_dir.absolutePath ()); // Attach the model to the QTreeView and set the root index - _file_tree_view = new QTreeView (widget ()); + _file_tree_view = new QTreeView (container); _file_tree_view->setModel (_file_system_model); _file_tree_view->setRootIndex (rootPathIndex); _file_tree_view->setSortingEnabled (true); _file_tree_view->setAlternatingRowColors (true); _file_tree_view->setAnimated (true); - _file_tree_view->setColumnHidden (1, true); - _file_tree_view->setColumnHidden (2, true); - _file_tree_view->setColumnHidden (3, true); - _file_tree_view->setStatusTip (tr ("Doubleclick a file to open it.")); + _file_tree_view->setToolTip (tr ("Doubleclick a file to open it")); // get sort column and order as well as cloumn state (order and width) QSettings *settings = resource_manager::get_settings (); @@ -92,11 +143,19 @@ ); _file_tree_view->header ()->restoreState (settings->value ("filesdockwidget/column_state").toByteArray ()); - _current_directory->setText(_file_system_model->fileInfo (rootPathIndex). + QStringList mru_dirs = settings->value ("filesdockwidget/mru_dir_list").toStringList (); + _current_directory->addItems(mru_dirs); + + _current_directory->setEditText(_file_system_model->fileInfo (rootPathIndex). absoluteFilePath ()); - connect (_file_tree_view, SIGNAL (doubleClicked (const QModelIndex &)), this, - SLOT (item_double_clicked (const QModelIndex &))); + connect (_file_tree_view, SIGNAL (doubleClicked (const QModelIndex &)), + this, SLOT (item_double_clicked (const QModelIndex &))); + + // add context menu to tree_view + _file_tree_view->setContextMenuPolicy(Qt::CustomContextMenu); + connect(_file_tree_view, SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(contextmenu_requested(const QPoint &))); // Layout the widgets vertically with the toolbar on top QVBoxLayout *vbox_layout = new QVBoxLayout (); @@ -104,17 +163,27 @@ vbox_layout->addWidget (_navigation_tool_bar); vbox_layout->addWidget (_file_tree_view); vbox_layout->setMargin (1); - widget ()->setLayout (vbox_layout); + + container->setLayout (vbox_layout); + // TODO: Add right-click contextual menus for copying, pasting, deleting files (and others) - connect (_current_directory, SIGNAL (returnPressed ()), - this, SLOT (handle_directory_entered ())); + connect (_current_directory->lineEdit(), SIGNAL (returnPressed ()), + this, SLOT (accept_directory_line_edit ())); - QCompleter * - completer = new QCompleter (_file_system_model, this); + connect (_current_directory, SIGNAL (activated (const QString &)), + this, SLOT (set_current_directory (const QString &))); + + connect (this, SIGNAL (run_file_signal (const QString&)), + parent (), SLOT (handle_command_double_clicked (const QString&))); + + QCompleter *completer = new QCompleter (_file_system_model, this); _current_directory->setCompleter (completer); setFocusProxy (_current_directory); + + _sync_octave_dir = true; // default, overwirtten with notice_settings () + _octave_dir = ""; } files_dock_widget::~files_dock_widget () @@ -125,31 +194,39 @@ settings->setValue ("filesdockwidget/sort_files_by_column", sort_column); settings->setValue ("filesdockwidget/sort_files_by_order", sort_order); settings->setValue ("filesdockwidget/column_state", _file_tree_view->header ()->saveState ()); + + QStringList dirs; + for(int i=0; i< _current_directory->count(); i++) + { + dirs.append(_current_directory->itemText(i)); + } + settings->setValue ("filesdockwidget/mru_dir_list", dirs); + settings->sync (); } void -files_dock_widget::item_double_clicked (const QModelIndex & index) +files_dock_widget::item_double_clicked (const QModelIndex& index) { // Retrieve the file info associated with the model index. QFileInfo fileInfo = _file_system_model->fileInfo (index); - display_directory (fileInfo.absoluteFilePath ()); + set_current_directory (fileInfo.absoluteFilePath ()); } void -files_dock_widget::set_current_directory (const QString& currentDirectory) +files_dock_widget::set_current_directory (const QString& dir) { - display_directory (currentDirectory); + display_directory (dir); } void -files_dock_widget::handle_directory_entered () +files_dock_widget::accept_directory_line_edit (void) { - display_directory (_current_directory->text ()); + display_directory (_current_directory->currentText ()); } void -files_dock_widget::do_up_directory () +files_dock_widget::change_directory_up (void) { QDir dir = QDir (_file_system_model->filePath (_file_tree_view->rootIndex ())); dir.cdUp (); @@ -157,9 +234,30 @@ } void -files_dock_widget::display_directory (const QString& directory) +files_dock_widget::do_sync_octave_directory (void) +{ + QDir dir = QDir (_file_system_model->filePath (_file_tree_view->rootIndex ())); + emit displayed_directory_changed (dir.absolutePath ()); +} + +void +files_dock_widget::do_sync_browser_directory (void) { - QFileInfo fileInfo (directory); + display_directory (_octave_dir,false); // false: no sync of octave dir +} + +void +files_dock_widget::update_octave_directory (const QString& dir) +{ + _octave_dir = dir; + if (_sync_octave_dir) + display_directory (_octave_dir,false); // false: no sync of octave dir +} + +void +files_dock_widget::display_directory (const QString& dir, bool set_octave_dir) +{ + QFileInfo fileInfo (dir); if (fileInfo.exists ()) { if (fileInfo.isDir ()) @@ -167,14 +265,18 @@ _file_tree_view->setRootIndex (_file_system_model-> index (fileInfo.absoluteFilePath ())); _file_system_model->setRootPath (fileInfo.absoluteFilePath ()); - _current_directory->setText (fileInfo.absoluteFilePath ()); + _file_system_model->sort (0, Qt::AscendingOrder); + if (_sync_octave_dir && set_octave_dir) + process_set_current_dir(fileInfo.absoluteFilePath ()); - if (_last_current_directory != fileInfo.absoluteFilePath ()) - { - emit displayed_directory_changed (fileInfo.absoluteFilePath ()); - } - - _last_current_directory = fileInfo.absoluteFilePath (); + // see if its in the list, and if it is, remove it and then, put at top of the list + int index = _current_directory->findText(fileInfo.absoluteFilePath ()); + if(index != -1) + { + _current_directory->removeItem(index); + } + _current_directory->insertItem(0, fileInfo.absoluteFilePath ()); + _current_directory->setCurrentIndex(0); } else { @@ -184,18 +286,301 @@ } } +void +files_dock_widget::contextmenu_requested (const QPoint& mpos) +{ + + QMenu menu(this); + + QModelIndex index = _file_tree_view->indexAt (mpos); + //QAbstractItemModel *m = _file_tree_view->model (); + + if (index.isValid()) + { + QFileInfo info = _file_system_model->fileInfo(index); + + menu.addAction (QIcon (":/actions/icons/fileopen.png"), tr("Open"), + this, SLOT(contextmenu_open(bool))); + if (info.isFile () && info.suffix () == "m") + menu.addAction (QIcon (":/actions/icons/artsbuilderexecute.png"), + tr("Run"), this, SLOT(contextmenu_run(bool))); + if (info.isFile ()) + menu.addAction (tr("Load Data"), this, SLOT(contextmenu_load(bool))); + + if (info.isDir ()) + { + menu.addSeparator (); + menu.addAction (QIcon (":/actions/icons/ok.png"), + tr ("Set Current Directory"), + this, SLOT (contextmenu_setcurrentdir (bool))); + } + + menu.addSeparator(); + menu.addAction (tr ("Rename"), this, SLOT(contextmenu_rename(bool))); + menu.addAction (QIcon(":/actions/icons/editdelete.png"), tr("Delete"), + this, SLOT(contextmenu_delete(bool))); + + if (info.isDir()) + { + menu.addSeparator(); + menu.addAction (QIcon (":/actions/icons/filenew.png"), + tr ("New File"), + this, SLOT(contextmenu_newfile(bool))); + menu.addAction (QIcon (":/actions/icons/folder_new.png"), + tr("New Directory"), + this, SLOT(contextmenu_newdir(bool))); + } + + menu.exec(_file_tree_view->mapToGlobal(mpos)); + + } +} + void -files_dock_widget::notice_settings () +files_dock_widget::contextmenu_open (bool) +{ + + QItemSelectionModel *m = _file_tree_view->selectionModel (); + QModelIndexList rows = m->selectedRows (); + + for( QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++) + { + item_double_clicked(*it); + } +} + +void +files_dock_widget::contextmenu_load (bool) { - QSettings *settings = resource_manager::get_settings (); + QItemSelectionModel *m = _file_tree_view->selectionModel (); + QModelIndexList rows = m->selectedRows (); + + if (rows.size () > 0) + { + QModelIndex index = rows[0]; + + QFileInfo info = _file_system_model->fileInfo(index); + + emit load_file_signal (info.fileName ()); + } +} + +void +files_dock_widget::contextmenu_run (bool) +{ + QItemSelectionModel *m = _file_tree_view->selectionModel (); + QModelIndexList rows = m->selectedRows (); + + if (rows.size () > 0) + { + QModelIndex index = rows[0]; + + QFileInfo info = _file_system_model->fileInfo(index); + + QString function_name = info.fileName (); + // We have to cut off the suffix, because octave appends it. + function_name.chop (info.suffix ().length () + 1); + emit run_file_signal (QString ("cd \'%1\'\n%2\n") + .arg(info.absolutePath ()).arg (function_name)); + } +} - // FIXME -- what should happen if settings is 0? +void +files_dock_widget::contextmenu_rename (bool) +{ + QItemSelectionModel *m = _file_tree_view->selectionModel (); + QModelIndexList rows = m->selectedRows (); + if(rows.size() > 0) + { + QModelIndex index = rows[0]; + + QFileInfo info = _file_system_model->fileInfo(index); + QDir path = info.absoluteDir(); + QString old_name = info.fileName(); + bool ok; + + QString new_name = QInputDialog::getText (this, tr("Rename file/directory"), + tr("Rename file/directory:\n") + old_name + tr("\n to: "), + QLineEdit::Normal, old_name, &ok); + if(ok && new_name.length()>0) + { + new_name = path.absolutePath() + "/" + new_name; + old_name = path.absolutePath() + "/" + old_name; + path.rename(old_name, new_name); + _file_system_model->revert(); + } + } + +} + +void +files_dock_widget::contextmenu_delete (bool) +{ + QItemSelectionModel *m = _file_tree_view->selectionModel (); + QModelIndexList rows = m->selectedRows (); + + for( QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++) + { + QModelIndex index = *it; + + QFileInfo info = _file_system_model->fileInfo(index); + + if(QMessageBox::question(this, tr("Delete file/directory"), + tr("Are you sre you want to delete\n") + info.filePath(), + QMessageBox::Yes|QMessageBox::No) == QMessageBox::Yes) + { + if(info.isDir()) + { + // see if direcory is empty + QDir path(info.absoluteFilePath()); + QList<QFileInfo> fileLst = path.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); - _file_tree_view->setColumnHidden (0, !settings->value ("showFilenames").toBool ()); - _file_tree_view->setColumnHidden (1, !settings->value ("showFileSize").toBool ()); - _file_tree_view->setColumnHidden (2, !settings->value ("showFileType").toBool ()); - _file_tree_view->setColumnHidden (3, !settings->value ("showLastModified").toBool ()); - _file_tree_view->setAlternatingRowColors (settings->value ("useAlternatingRowColors").toBool ()); - //if (settings.value ("showHiddenFiles").toBool ()) - // TODO: React on option for hidden files. + if(fileLst.count() != 0) + QMessageBox::warning(this, tr("Delete file/directory"), + tr("Can not delete a directory that is not empty")); + else + _file_system_model->rmdir(index); + } + else + { + _file_system_model->remove(index); + } + + _file_system_model->revert(); + + } + } +} + +void +files_dock_widget::contextmenu_newfile (bool) +{ + QItemSelectionModel *m = _file_tree_view->selectionModel (); + QModelIndexList rows = m->selectedRows (); + + if(rows.size() > 0) + { + QModelIndex index = rows[0]; + + QFileInfo info = _file_system_model->fileInfo(index); + QString parent_dir = info.filePath(); + + process_new_file(parent_dir); + } +} + +void +files_dock_widget::contextmenu_newdir (bool) +{ + QItemSelectionModel *m = _file_tree_view->selectionModel (); + QModelIndexList rows = m->selectedRows (); + + if(rows.size() > 0) + { + QModelIndex index = rows[0]; + + QFileInfo info = _file_system_model->fileInfo(index); + QString parent_dir = info.filePath(); + + process_new_dir(parent_dir); + } +} + +void +files_dock_widget::contextmenu_setcurrentdir (bool) +{ + QItemSelectionModel *m = _file_tree_view->selectionModel (); + QModelIndexList rows = m->selectedRows (); + + if(rows.size() > 0) + { + QModelIndex index = rows[0]; + + QFileInfo info = _file_system_model->fileInfo(index); + + if(info.isDir()) + { + process_set_current_dir(info.absoluteFilePath ()); + } + } } + +void +files_dock_widget::notice_settings (const QSettings *settings) +{ + // Qsettings pointer is checked before emitting. + + int icon_size = settings->value ("toolbar_icon_size",24).toInt (); + if (icon_size > 16) + icon_size = icon_size - 4; + _navigation_tool_bar->setIconSize (QSize (icon_size,icon_size)); + + // file names are always shown, other columns can be hidden by settings + _file_tree_view->setColumnHidden (0, false); + _file_tree_view->setColumnHidden (1, !settings->value ("filesdockwidget/showFileSize",false).toBool ()); + _file_tree_view->setColumnHidden (2, !settings->value ("filesdockwidget/showFileType",false).toBool ()); + _file_tree_view->setColumnHidden (3, !settings->value ("filesdockwidget/showLastModified",false).toBool ()); + _file_tree_view->setAlternatingRowColors (settings->value ("filesdockwidget/useAlternatingRowColors",true).toBool ()); + if (settings->value ("filesdockwidget/showHiddenFiles",false).toBool ()) + { + // TODO: React on option for hidden files. + } + // enalbe the buttons to sync octave/browser dir only if this is not done by default + _sync_octave_dir = settings->value ("filesdockwidget/sync_octave_directory",false).toBool (); + _sync_octave_directory_action->setEnabled (!_sync_octave_dir); + _sync_browser_directory_action->setEnabled (!_sync_octave_dir); + + if (_sync_octave_dir) + display_directory (_octave_dir); // sync browser to octave dir + +} + +void +files_dock_widget::popdownmenu_newdir (bool) +{ + process_new_dir(_file_system_model->rootPath()); +} + +void +files_dock_widget::popdownmenu_newfile (bool) +{ + process_new_file(_file_system_model->rootPath()); +} + +void +files_dock_widget::process_new_file (const QString &parent_dir) +{ + bool ok; + + QString name = QInputDialog::getText (this, tr("Create File"), tr("Create file in\n") + parent_dir, + QLineEdit::Normal, "New File.txt", &ok); + if(ok && name.length()>0) + { + name = parent_dir + "/" + name; + + QFile file(name); + file.open(QIODevice::WriteOnly); + _file_system_model->revert(); + } +} + +void +files_dock_widget::process_new_dir (const QString &parent_dir) +{ + bool ok; + + QString name = QInputDialog::getText (this, tr("Create Directory"), tr("Create folder in\n") + parent_dir, + QLineEdit::Normal, "New Directory", &ok); + if(ok && name.length()>0) + { + QDir dir(parent_dir); + dir.mkdir(name); + _file_system_model->revert(); + } +} + +void files_dock_widget::process_set_current_dir(const QString & dir) +{ + emit displayed_directory_changed (dir); +} +
rename from libgui/src/files-dockwidget.h rename to libgui/src/files-dock-widget.h --- a/libgui/src/files-dockwidget.h +++ b/libgui/src/files-dock-widget.h @@ -34,8 +34,9 @@ #include <QVBoxLayout> #include <QAction> #include <QTreeView> +#include <QSettings> -#include <QLineEdit> +#include <QComboBox> #include "octave-dock-widget.h" /** @@ -45,9 +46,11 @@ class files_dock_widget : public octave_dock_widget { Q_OBJECT - public: - /** Constructs a new files_dock_widget. */ + +public: + files_dock_widget (QWidget *parent = 0); + ~files_dock_widget (); public slots: @@ -56,47 +59,83 @@ void item_double_clicked (const QModelIndex & index); /** Slot for handling the up-directory button in the toolbar. */ - void do_up_directory (); + void change_directory_up (); + + /** Slot for handling the sync octave directory button in the toolbar. */ + void do_sync_octave_directory (); + + /** Slot for handling the sync browser directory button in the toolbar. */ + void do_sync_browser_directory (); /** Sets the current directory being displayed. */ - void set_current_directory (const QString& currentDirectory); + void set_current_directory (const QString& dir); /** Accepts user input a the line edit for the current directory. */ - void handle_directory_entered (); + void accept_directory_line_edit (); - void display_directory (const QString& directory); + /** set the internal variable that holds the actual octave variable **/ + void update_octave_directory (const QString& dir); /** Tells the widget to react on changed settings. */ - void notice_settings (); + void notice_settings (const QSettings *settings); + +private slots: + /** context menu wanted */ + void contextmenu_requested (const QPoint& pos); + + /* context menu actions */ + void contextmenu_open (bool); + void contextmenu_run (bool); + void contextmenu_load (bool); + void contextmenu_rename (bool); + void contextmenu_delete (bool); + void contextmenu_newfile (bool); + void contextmenu_newdir (bool); + void contextmenu_setcurrentdir (bool); + + /* popdown menu options */ + void popdownmenu_newfile(bool); + void popdownmenu_newdir(bool); signals: + /** Emitted, whenever the user requested to open a file. */ void open_file (const QString& fileName); /** Emitted, whenever the currently displayed directory changed. */ - void displayed_directory_changed (const QString& directory); + void displayed_directory_changed (const QString& dir); -protected: + /** Emitted, whenever the user requested to load a file. */ + void load_file_signal (const QString& fileName); + + /** Emitted, whenever the user requested to run a file. */ + void run_file_signal (const QString& fileName); private: - // TODO: Add toolbar with buttons for navigating the path, creating dirs, etc + void process_new_file(const QString &parent_name); + void process_new_dir(const QString &parent_name); + void process_set_current_dir(const QString &parent_name); - QString _last_current_directory; + /** set a new directory or open a file **/ + void display_directory (const QString& dir, bool set_octave_dir = true); - /** Toolbar for file and directory manipulation. */ + /** Variables for the actions **/ QToolBar * _navigation_tool_bar; - - /** Variables for the up-directory action. */ - QIcon _directory_icon; - QAction * _directory_up_action; - QToolButton * _up_directory_button; + QAction * _sync_octave_directory_action; + QAction * _sync_browser_directory_action; /** The file system model. */ QFileSystemModel *_file_system_model; /** The file system view. */ QTreeView * _file_tree_view; - QLineEdit * _current_directory; + QComboBox * _current_directory; + + /** Internal variables **/ + bool _sync_octave_dir; // flag if syncing with octave + QString _octave_dir; // the actual octave dir + + enum { MaxMRUDirs = 10 }; }; #endif // FILESDOCKWIDGET_H
new file mode 100644 --- /dev/null +++ b/libgui/src/find-files-dialog.cc @@ -0,0 +1,376 @@ +/* + +Copyright (C) 2013 John Donoghue + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#include "find-files-dialog.h" +#include "find-files-model.h" +#include "resource-manager.h" +#include <QPushButton> +#include <QDialogButtonBox> +#include <QGridLayout> +#include <QLabel> +#include <QLineEdit> +#include <QComboBox> +#include <QCheckBox> +#include <QHeaderView> +#include <QTableView> +#include <QFileDialog> +#include <QStatusBar> +#include <QIcon> +#include <QFileInfo> +#include <QTimer> +#include <QDirIterator> +#include <QTextStream> +#include <QGroupBox> + +find_files_dialog::find_files_dialog (QWidget * p) + : QDialog (p) +{ + setWindowTitle (tr("Find Files")); + setWindowIcon (QIcon (":/actions/icons/search.png")); + + _dir_iterator = 0; + + _timer = new QTimer (this); + connect(_timer, SIGNAL(timeout()), this, SLOT(look_for_files())); + + QSettings *settings = resource_manager::get_settings (); + + QLabel * file_name_label = new QLabel (tr ("Named:")); + _file_name_edit = new QLineEdit; + _file_name_edit->setToolTip (tr ("Enter the filename expression")); + + _file_name_edit->setText (settings->value ("findfiles/file_name","*").toString ()); + file_name_label->setBuddy (_file_name_edit); + + QLabel * start_dir_label = new QLabel (tr ("Start in:")); + + _start_dir_edit = new QLineEdit; + _start_dir_edit->setText (settings->value ("findfiles/start_dir",QDir::currentPath()).toString()); + _start_dir_edit->setToolTip (tr ("Enter the start directory")); + start_dir_label->setBuddy (_start_dir_edit); + + _browse_button = new QPushButton (tr ("Browse...")); + _browse_button->setToolTip (tr ("Browse for start directory")); + connect(_browse_button, SIGNAL(clicked()), this, SLOT(browse_folders())); + + _recurse_dirs_check = new QCheckBox (tr ("Recurse directories")); + _recurse_dirs_check->setChecked (settings->value ("findfiles/recurse_dirs", false).toBool()); + _recurse_dirs_check->setToolTip (tr ("Search recursively through directories for matching files")); + + _include_dirs_check = new QCheckBox (tr ("Include directories")); + _include_dirs_check->setChecked (settings->value ("findfiles/include_dirs", false).toBool()); + _include_dirs_check->setToolTip (tr ("Include matching directories in search results")); + + _name_case_check = new QCheckBox (tr ("Name case insensitive")); + _name_case_check->setChecked (settings->value ("findfiles/name_case", false).toBool()); + _name_case_check->setToolTip (tr ("Set matching name is case insensitive")); + + _contains_text_check = new QCheckBox (tr("Contains text:")); + _contains_text_check->setToolTip (tr ("Search must match text")); + _contains_text_check->setChecked (settings->value ("findfiles/check_text", false).toBool()); + + _contains_text_edit = new QLineEdit (); + _contains_text_edit->setToolTip (tr ("Text to match")); + _contains_text_edit->setText (settings->value ("findfiles/contains_text", "").toString()); + + _content_case_check = new QCheckBox (tr("Text case insensitive")); + _content_case_check->setChecked (settings->value ("findfiles/content_case", false).toBool()); + _content_case_check->setToolTip (tr ("Set text content is case insensitive")); + + find_files_model * model = new find_files_model (); + _file_list = new QTableView; + _file_list->setWordWrap (false); + _file_list->setModel (model); + _file_list->setShowGrid (false); + _file_list->setSelectionBehavior(QAbstractItemView::SelectRows); + _file_list->setSelectionMode(QAbstractItemView::SingleSelection); + _file_list->setAlternatingRowColors(true); + _file_list->setToolTip (tr ("Search results")); + _file_list->horizontalHeader ()->restoreState (settings->value ("findfiles/column_state").toByteArray ()); + _file_list->sortByColumn ( + settings->value ("findfiles/sort_files_by_column",0).toInt (), + static_cast<Qt::SortOrder>(settings->value ("findfiles/sort_files_by_order",Qt::AscendingOrder).toUInt ())); + + connect (_file_list, SIGNAL(doubleClicked(const QModelIndex&)), + this, SLOT(item_double_clicked(const QModelIndex &))); + + _status_bar = new QStatusBar; + _status_bar->showMessage (tr("Idle.")); + + _find_button = new QPushButton (tr("Find")); + _find_button->setToolTip (tr ("Start search for matching files")); + connect (_find_button, SIGNAL(clicked()), this, SLOT(start_find())); + + _stop_button = new QPushButton (tr("Stop")); + _stop_button->setToolTip (tr ("Stop searching")); + _stop_button->setEnabled (false); + connect (_stop_button, SIGNAL(clicked()), this, SLOT(stop_find())); + + // layout everything + QDialogButtonBox * button_box = new QDialogButtonBox (Qt::Vertical); + button_box->addButton (_find_button, QDialogButtonBox::ActionRole); + button_box->addButton (_stop_button, QDialogButtonBox::ActionRole); + + // add dialog close button + _close_button = button_box->addButton (QDialogButtonBox::Close); + connect (button_box, SIGNAL (rejected ()), + this, SLOT (close ())); + + // name options + QGroupBox * name_group = new QGroupBox(tr("File name/location")); + QGridLayout * name_layout = new QGridLayout; + name_group->setLayout(name_layout); + + name_layout->addWidget (file_name_label,1,1, 1,1); + name_layout->addWidget (_file_name_edit,1,2, 1,-1); + + name_layout->addWidget (start_dir_label,2,1); + name_layout->addWidget (_start_dir_edit,2,2,1,3); + name_layout->addWidget (_browse_button,2,5); + name_layout->setColumnStretch (2,1); + + name_layout->addWidget (_recurse_dirs_check,3,1); + name_layout->addWidget (_include_dirs_check,3,2); + name_layout->addWidget (_name_case_check,3,3); + + // content options + QGroupBox * content_group = new QGroupBox(tr("File contents")); + QGridLayout * content_layout = new QGridLayout; + content_group->setLayout(content_layout); + content_layout->addWidget (_contains_text_check,4,1); + content_layout->addWidget (_contains_text_edit,4,2,1,3); + content_layout->setColumnStretch (2,1); + content_layout->addWidget (_content_case_check,5,1); + + + QGridLayout *main_layout = new QGridLayout; + main_layout->setSizeConstraint (QLayout::SetFixedSize); + main_layout->addWidget (name_group, 0, 0); + main_layout->addWidget (content_group, 1, 0); + main_layout->addWidget (button_box, 0, 1,3,1); + main_layout->addWidget (_file_list,2,0); + main_layout->setRowStretch (2,1); + main_layout->addWidget (_status_bar,3,0,1,-1); + + + setLayout (main_layout); + + connect (this, SIGNAL(finished(int)), this, SLOT(handle_done(int))); +} + +find_files_dialog::~find_files_dialog () +{ + QSettings *settings = resource_manager::get_settings (); + + int sort_column = _file_list->horizontalHeader ()->sortIndicatorSection (); + Qt::SortOrder sort_order = _file_list->horizontalHeader ()->sortIndicatorOrder (); + settings->setValue ("findfiles/sort_files_by_column", sort_column); + settings->setValue ("findfiles/sort_files_by_order", sort_order); + settings->setValue ("findfiles/column_state", _file_list->horizontalHeader ()->saveState ()); + + settings->setValue ("findfiles/file_name", _file_name_edit->text()); + + settings->setValue ("findfiles/start_dir", _start_dir_edit->text()); + + settings->setValue ("findfiles/recurse_dirs", _recurse_dirs_check->text()); + settings->setValue ("findfiles/include_dirs", _include_dirs_check->text()); + settings->setValue ("findfiles/name_case", _name_case_check->text()); + + settings->setValue ("findfiles/contains_text", _contains_text_edit->text()); + settings->setValue ("findfiles/check_text", _contains_text_check->isChecked ()); + settings->setValue ("findfiles/content_case", _content_case_check->isChecked ()); + + settings->sync (); + + if(_dir_iterator) + delete _dir_iterator; +} + +void find_files_dialog::handle_done (int button) +{ + // make sure we stopped processing + stop_find (); +} + +void find_files_dialog::set_search_dir(const QString &dir) +{ + stop_find(); + _start_dir_edit->setText(dir); +} + +void +find_files_dialog::start_find () +{ + stop_find(); + + find_files_model *m = static_cast<find_files_model *> (_file_list->model()); + m->clear(); + + QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags; + if (_recurse_dirs_check->isChecked ()) flags |= QDirIterator::Subdirectories; + + QDir::Filters filters = QDir::Dirs|QDir::NoDotAndDotDot|QDir::Files; + if (!_name_case_check->isChecked ()) + filters |= QDir::CaseSensitive; + + QStringList nameFilters; + nameFilters.append (_file_name_edit->text()); + + if (_dir_iterator) delete _dir_iterator; + + _dir_iterator = new QDirIterator (_start_dir_edit->text(), nameFilters, filters, flags); + + // enable/disable widgets + _find_button->setEnabled (false); + _stop_button->setEnabled (true); + _close_button->setEnabled (false); + _browse_button->setEnabled (false); + _start_dir_edit->setEnabled (false); + _file_name_edit->setEnabled (false); + _recurse_dirs_check->setEnabled (false); + _include_dirs_check->setEnabled (false); + _name_case_check->setEnabled (false); + _contains_text_check->setEnabled (false); + _content_case_check->setEnabled (false); + _contains_text_edit->setEnabled (false); + + _status_bar->showMessage (tr("Searching...")); + _timer->start (0); +} + +void +find_files_dialog::stop_find () +{ + _timer->stop (); + + _find_button->setEnabled (true); + _stop_button->setEnabled (false); + _close_button->setEnabled (true); + _browse_button->setEnabled (true); + _start_dir_edit->setEnabled (true); + _file_name_edit->setEnabled (true); + _recurse_dirs_check->setEnabled (true); + _include_dirs_check->setEnabled (true); + _name_case_check->setEnabled (true); + _contains_text_check->setEnabled (true); + _content_case_check->setEnabled (true); + _contains_text_edit->setEnabled (true); + + find_files_model *m = static_cast<find_files_model *> (_file_list->model()); + QString res_str = QString ("%1 matches").arg(m->rowCount()); + + _status_bar->showMessage (res_str); +} + +void +find_files_dialog::browse_folders () +{ + QString dir = + QFileDialog::getExistingDirectory (this, tr ("Set search directory"), + _start_dir_edit->text()); + + if (! dir.isEmpty ()) + { + _start_dir_edit->setText (dir); + } +} + +void +find_files_dialog::item_double_clicked (const QModelIndex &idx) +{ + find_files_model *m = static_cast<find_files_model *> (_file_list->model ()); + + QFileInfo info = m->fileInfo (idx); + + if(idx.column () == 1) + { + // clicked in directory part + emit dir_selected (info.absolutePath()); + } + else + { + // clicked in filename part + if(info.isDir ()) + emit dir_selected (info.absoluteFilePath()); + else + emit file_selected (info.absoluteFilePath()); + } +} + +void +find_files_dialog::look_for_files () +{ + if(_dir_iterator && _dir_iterator->hasNext ()) + { + QFileInfo info (_dir_iterator->next ()); + + find_files_model *m = static_cast<find_files_model *> (_file_list->model ()); + + if(is_match (info)) + m->addFile (info); + } + else + { + stop_find (); + } +} + +bool find_files_dialog::is_match (const QFileInfo &info) +{ + bool match = true; + if (info.isDir ()) + { + if(!_include_dirs_check->isChecked ()) match = false; + if(_contains_text_check->isChecked ()) match = false; + } + else + { + // a file + if (_contains_text_check->isChecked ()) + { + match = false; + + QFile file(info.absoluteFilePath ()); + if (file.open (QIODevice::ReadOnly)) + { + QTextStream stream (&file); + + QString line; + QString match_str = _contains_text_edit->text (); + + Qt::CaseSensitivity cs = _content_case_check->isChecked () ? + Qt::CaseInsensitive : Qt::CaseSensitive; + + do + { + line = stream.readLine (); + match = line.contains (match_str, cs); + } + while(!line.isNull () && match == false); + } + + } + } + + return match; +} +
new file mode 100644 --- /dev/null +++ b/libgui/src/find-files-dialog.h @@ -0,0 +1,79 @@ +/* + +Copyright (C) 2013 John Donoghue + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ +#if !defined (find_files_dialog_h) +#define find_files_dialog_h + +#include <QDialog> +#include <QModelIndex> +#include <QFileInfo> + +class QLineEdit; +class QPushButton; +class QTableView; +class QTimer; +class QDirIterator; +class QCheckBox; +class QStatusBar; + +class find_files_dialog : public QDialog +{ + Q_OBJECT +public: + find_files_dialog (QWidget * parent=0); + virtual ~find_files_dialog (); + +signals: + void file_selected (const QString &fileName); + void dir_selected (const QString &fileName); + +public slots: + void set_search_dir(const QString &dir); + +private slots: + void start_find (); + void stop_find (); + void browse_folders (); + void look_for_files (); + void item_double_clicked (const QModelIndex&); + void handle_done(int); +private: + bool is_match(const QFileInfo &info); + QLineEdit * _start_dir_edit; + QLineEdit * _file_name_edit; + QPushButton * _stop_button; + QPushButton * _find_button; + QPushButton * _close_button; + QPushButton * _browse_button; + QTableView * _file_list; + QTimer * _timer; + QCheckBox * _recurse_dirs_check; + QCheckBox * _include_dirs_check; + QCheckBox * _name_case_check; + QCheckBox * _contains_text_check; + QCheckBox * _content_case_check; + QLineEdit * _contains_text_edit; + QDirIterator * _dir_iterator; + QStatusBar * _status_bar; +}; + +#endif // find_files_dialog_h +
new file mode 100644 --- /dev/null +++ b/libgui/src/find-files-model.cc @@ -0,0 +1,135 @@ +/* + +Copyright (C) 2013 John Donoghue + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#include "find-files-model.h" +#include <QFileIconProvider> + +find_files_model::find_files_model (QObject *p) + : QAbstractListModel(p) +{ + _columnNames.append (tr ("Filename")); + _columnNames.append (tr ("Directory")); +} + +find_files_model::~find_files_model () +{ +} + +void +find_files_model::clear () +{ + beginResetModel(); + + _files.clear(); + + endResetModel (); +} + +void +find_files_model::addFile (const QFileInfo &info) +{ + beginInsertRows(QModelIndex(), _files.size(), _files.size() ); + + _files.append(info); + + endInsertRows(); +} + +int +find_files_model::rowCount (const QModelIndex & p) const +{ + return _files.size(); +} + +int +find_files_model::columnCount (const QModelIndex & p) const +{ + return _columnNames.size (); +} + +QVariant +find_files_model::data (const QModelIndex& idx, int role) const +{ + QVariant retval; + + if (idx.isValid ()) + { + if(role == Qt::DisplayRole) + { + switch (idx.column ()) + { + case 0: + retval = QVariant (_files[idx.row()].fileName()); + break; + + case 1: + retval = QVariant (_files[idx.row()].absolutePath()); + break; + + default: + break; + } + } + else if(role == Qt:: DecorationRole) + { + switch (idx.column()) + { + case 0: + retval = fileIcon(idx); + default: + break; + } + } + } + + return retval; +} + +QVariant +find_files_model::headerData (int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return _columnNames[section]; + else + return QVariant (); +} + +QFileInfo +find_files_model::fileInfo (const QModelIndex & p) const +{ + if(p.isValid ()) + { + return _files[p.row()]; + } + return QFileInfo (); +} + +QIcon +find_files_model::fileIcon (const QModelIndex &p) const +{ + QFileIconProvider icon_provider; + if(p.isValid ()) + { + return icon_provider.icon (_files[p.row()]); + } + return QIcon (); +}
new file mode 100644 --- /dev/null +++ b/libgui/src/find-files-model.h @@ -0,0 +1,59 @@ +/* + +Copyright (C) 2013 John Donoghue + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ +#if !defined (find_files_model_h) +#define find_files_model_h + +#include <QAbstractListModel> +#include <QStringList> +#include <QList> +#include <QFileInfo> +#include <QIcon> + + +class find_files_model : public QAbstractListModel +{ +public: + find_files_model(QObject *p=0); + ~find_files_model (); + + void clear(); + + void addFile(const QFileInfo &info); + + int rowCount(const QModelIndex & p=QModelIndex()) const; + + int columnCount(const QModelIndex & p=QModelIndex()) const; + + QVariant data (const QModelIndex& idx, int role) const; + + QVariant headerData (int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + QFileInfo fileInfo (const QModelIndex & p) const; + QIcon fileIcon (const QModelIndex &p) const; +private: + QList<QFileInfo> _files; + QStringList _columnNames; +}; + +#endif // find_files_model_h +
rename from libgui/src/history-dockwidget.cc rename to libgui/src/history-dock-widget.cc --- a/libgui/src/history-dockwidget.cc +++ b/libgui/src/history-dock-widget.cc @@ -33,13 +33,23 @@ #include "cmd-hist.h" -#include "history-dockwidget.h" -#include "octave-link.h" +#include "history-dock-widget.h" -history_dock_widget::history_dock_widget (QWidget * p) +history_dock_widget::history_dock_widget (QWidget *p) : octave_dock_widget (p) { setObjectName ("HistoryDockWidget"); + setStatusTip (tr ("Browse and search the command history.")); + + connect (this, SIGNAL (command_create_script (const QString&)), + p, SLOT (new_file (const QString&))); + + connect (this, SIGNAL (information (const QString&)), + p, SLOT (report_status_message (const QString&))); + + connect (this, SIGNAL (command_double_clicked (const QString&)), + p, SLOT (handle_command_double_clicked (const QString&))); + construct (); } @@ -77,25 +87,15 @@ connect (_history_list_view, SIGNAL (doubleClicked (QModelIndex)), this, SLOT (handle_double_click (QModelIndex))); - _update_event_enabled = true; - _update_history_model_timer.setInterval (500); - _update_history_model_timer.setSingleShot (false); - - connect (&_update_history_model_timer, - SIGNAL (timeout ()), - this, - SLOT (request_history_model_update ())); - - _update_history_model_timer.start (); - setFocusProxy (_filter_line_edit); } void history_dock_widget::ctxMenu(const QPoint &xpos) { - QMenu *menu = new QMenu; - menu->addAction(tr("Copy"), this, SLOT(handle_contextmenu_copy(bool))); - menu->addAction(tr("Evaluate"), this, SLOT(handle_contextmenu_evaluate(bool))); - menu->exec(_history_list_view->mapToGlobal(xpos)); + QMenu menu(this); + menu.addAction(tr("Copy"), this, SLOT(handle_contextmenu_copy(bool))); + menu.addAction(tr("Evaluate"), this, SLOT(handle_contextmenu_evaluate(bool))); + menu.addAction(tr("Create script"), this, SLOT(handle_contextmenu_create_script(bool))); + menu.exec(_history_list_view->mapToGlobal(xpos)); } void history_dock_widget::handle_contextmenu_copy(bool) @@ -125,68 +125,47 @@ } void +history_dock_widget::handle_contextmenu_create_script (bool) +{ + QString text; + QItemSelectionModel *selectionModel = _history_list_view->selectionModel (); + QModelIndexList rows = selectionModel->selectedRows (); + + for (QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++) + { + if ((*it).isValid ()) + text += (*it).data().toString() + "\n"; + } + + if (text.length () > 0) + emit command_create_script (text); +} + + +void history_dock_widget::handle_double_click (QModelIndex modelIndex) { emit command_double_clicked (modelIndex.data().toString()+"\n"); } void -history_dock_widget::request_history_model_update () +history_dock_widget::set_history (const QStringList& hist) { - if (_update_event_enabled) - { - _update_event_enabled = false; // no more update until this one is processed - octave_link::post_event (this, &history_dock_widget::update_history_callback); - } -} - -void -history_dock_widget::reset_model () -{ - _history_model->setStringList (QStringList ()); + _history_model->setStringList (hist); + _history_list_view->scrollToBottom (); } void -history_dock_widget::update_history_callback (void) +history_dock_widget::append_history (const QString& hist_entry) { - static bool scroll_window = false; - - // Determine the client's (our) history length and the one of the server. - int clientHistoryLength = _history_model->rowCount (); - int serverHistoryLength = command_history::length (); - - // If were behind the server, iterate through all new entries and add - // them to our history. - if (clientHistoryLength < serverHistoryLength) - { - int elts_to_add = serverHistoryLength - clientHistoryLength; - - _history_model->insertRows (clientHistoryLength, elts_to_add); - - for (int i = clientHistoryLength; i < serverHistoryLength; i++) - { - std::string entry = command_history::get_entry (i); + QStringList lst = _history_model->stringList (); + lst.append (hist_entry); + _history_model->setStringList (lst); + _history_list_view->scrollToBottom (); +} - _history_model->setData (_history_model->index (i), - QString::fromUtf8 (entry.data (), entry.size ())); - } - - // FIXME -- does this behavior make sense? Calling - // _history_list_view->scrollToBottom () here doesn't seem to - // have any effect. Instead, we need to request that action - // and wait until the next event occurs in which no items - // are added to the history list. - - scroll_window = true; - } - else if (scroll_window) - { - scroll_window = false; - - _history_list_view->scrollToBottom (); - } - - // update is processed, re-enable further updates events triggered by timer - _update_event_enabled = true; - +void +history_dock_widget::clear_history (void) +{ + _history_model->setStringList (QStringList ()); }
rename from libgui/src/history-dockwidget.h rename to libgui/src/history-dock-widget.h --- a/libgui/src/history-dockwidget.h +++ b/libgui/src/history-dock-widget.h @@ -27,34 +27,43 @@ #include <QListView> #include <QSortFilterProxyModel> #include <QStringListModel> -#include <QTimer> #include "octave-dock-widget.h" class history_dock_widget : public octave_dock_widget { Q_OBJECT - public: + +public: + history_dock_widget (QWidget *parent = 0); public slots: - void request_history_model_update (); - void reset_model (); + + void set_history (const QStringList& hist); + void append_history (const QString& hist_entry); + void clear_history (void); signals: + void information (const QString& message); /** Emitted, whenever the user double-clicked a command in the history. */ void command_double_clicked (const QString& command); -protected: + /** Emitted whenever the user selects command and chooses Create + script from popupmenu. */ + void command_create_script (const QString& commands); private slots: + void handle_double_click (QModelIndex modelIndex); void handle_contextmenu_copy(bool flag); void handle_contextmenu_evaluate(bool flag); + void handle_contextmenu_create_script(bool flag); void ctxMenu(const QPoint &pos); private: + void construct (); QListView *_history_list_view; QLineEdit *_filter_line_edit; @@ -62,11 +71,6 @@ /** Stores the current history_model. */ QStringListModel *_history_model; - - QTimer _update_history_model_timer; - - void update_history_callback (void); - bool _update_event_enabled; }; #endif // HISTORYDOCKWIDGET_H
new file mode 100755 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1b2e691c8a564d007b29d5d7af5a04098b4f56a5 GIT binary patch literal 2552 zc$@+F2?zFxP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000TUNkl<ZScR3B zYiu0Xb;p1A-kI4qx#W@}DN2+`N~UVbisM90WY@Cn3Xz-`N!l1qQ}=^iz)hPJbrH8f zTeMAp_DkCUMd3c+#BFM~FdFw2Cz4}FmKEEQqBLpUSQcba7Af(q-Q~WxkJ+7>d-{Q^ zn06A^J-}ej9bnG?Kj)tFzjM@|^H$S<>0TO$13~xR59A?jV26Q81vvo($|1}~Fg*yh z0?=N6P6)KR>vlJmvjK0T|4x<wJ|*zL?reJhz}RM!8r@8yH%lbYS*uZBSz&c{p5^k| zY2XRqNud6J1y=7O1E1TPiGN}0)>|{1k9-8@z-=(J6;KfRU_rD(b=pX+LiC+8EFU|{ z`BUF%U8=Xf5Wt`L?~s9aB5=c?=HG5Pc>A7-U-}e!awpPg5S1&?2|x*00c){hP_9A6 zJxnHpGA_~b91BnW6DMCdeQ8<vxi*~t{}8xiJd-?m*Ms+~)NKcld;!1FKr4--HDV0f zIAB1D0#OJNQE0JI2m(5h#2xO#fB7`u{L<g^gL?CxHXM651a6<))brAj-}p`3z9Aa< zC9DXJQkYnbH4zqyMOF%V%Jmu+AstUL+?Qp0Uyi;+lE_-D6_h|?c!;R9$k9i>#CHpo zj|A|{I}sQg>PgQ0{HK4##Jx1dY8g;Cu7e+obK%k@UVr7kxwf=Sy&YCMLM;M8lhvN? z9hjWpmOVFd>(DSB5CPUgHk&1ERQcz}zQSv3ttkhluLHiN3yh=w^}vTeWM~U>3s(>W zZY<8Vj^dT0$C$Y^>(9ei=i%#lxDdb^0G3qFx08FPuiQJh`<4fyz8sCqmk_NHV5wYT zXt0kDA3ns@uO0i3R%mzskU+cZSh(+}ci*sYQ*V~pnHhWqp6AhuB7X4fbDS^NUi`k| z56%gv_PuS}P5_U=#lw#KJ2xhi<fktXHX4Z1hzOz-Gqo}kLz_9cYy8H?U%UL782k-@ z`jc)DFX7Gq@{vPZYNaYmA~+&=n>I21;)|RqR-QTzzdoWUofFsx6o794NuUF<SS<eS z;P9aj773728H>RxLA0S`Eghgw8-{ulJaYVGCEp510AKrn4|i@I9o!<TH7*xRl*?s0 zTC;lbBCi%J-+vB%4Jcjz;@{Qqc-I#N*65S9J8u2pQn^TL_6mNZL8p{QZ{NoJ-o31q zOEhaWW=pF?)h0I$4`eHFqyjh!2o#?fNv2s?UZ&7#<0!~vGR$4R%y;4Uf%0|mM-A&5 z3kZs)QAh19H}B6E^4LlVQ5q8kn28;HYhi(_3rkG-Eyg3u8Zgre8BeE3C_ec=!q*%C z6LUV)+i7z-U!)>JCY_?Qy2|-haP(C;ejWUC&U&$2x3)3Q$kdLzudOUXy^7#KXz_OL z<f+9goVmRCSADVAa5drFo3n~0a5*gUo?MPWPamRfjpIXK+H)p*8$L_5Iu!-UM2xj^ znQ8c!>tMef@Ag$U0Zn6`ZEqVoTwlD3_$@$TLLX;h3tufQ^U^~8v8%#Ew>8^8TTtP> z*F>YkkV+_YoEm+O8F1Tnn{LCfbsU|FIy8Zf0#H<apLzJtQDF3KRqs3IxIdCRTq@>? z8ZE3+Xe+2~qdeX6d3i4Xcdtf#7O-33LWH91IRqlKH26_O+!$OK)jssB7{h81a-myk z?I@xVMt&ShG2n0lR2RIV_47KLKGdm}QJnzmD3k~?GR)H*pHnNvM_&^@3v}+Y;J_-d z+IBr6fl$C&i&YRo!m$t;5nRV5&-&S&=(O34nAn@R0IH$&3;n6sLDi@eg%L_C908T< z=Y-$ld#lyIea-TaT0e6LufM6aX}jz3R|WD~u^@s4t0SoSQ9y6pWn3Vopcw=h#0?>r zTh~fmQ|g50>Vxf8o7FI)rl2W;pYGvYv%`NCs(=0J2Ji>$x)Z=A<vQ7>(#%Ke(&;*y zmbKl4!b-yrn+3;ZyM}%RItl?{$mo3lO~uJxxHB1s1Y!xhC{aAlYRBj7TKzB2!b5by z0UB>!`!ks|=`bXwU`!xo99p5J2G_KLTG$EBy&hR^a5eov+=BHy_U)Mbtxf$sC$@<? zutkJ8kYZi^dR>=PJLGJ={TI(hJp5*lz(?(yKQt}PXU4Mqr0Z++7}#YLYp$XkgtHZx z*8n!+*mS4KP3a6<ETlBpR*PMGZoGM4B5~JPD5QXlKuT+}#$l)(ak3qL@hRb92O<R= zvG9ovIsx3>GctJlco^Zd0tSFxi5PEmENc<Z0f8>AGd=oxsgBp*%MCz}f;d9sxnuOK zTqC6+rZw7iNNU4`A96adk3S*&p6=@6{ci;ZNaN}!_KuH}oSP?MU>q3CB)QaVQHG~S z0H=E%zf$yrQ!hoq&)k(sP;0bk8HfiVNd=BJpoAXar`qsz#FKxjc+i9J4uRN@U^Cz; zp5ODnn+LWo&a>L`$!YjN%;9^Hu+j=%UxAnCZW92Z@Q2SX6=`o7;(c0?0}@){8H3h} z%<wSVZraCJqVS6^!+rM%!CmsB$iOd7CgN`#xa|Y)nW|M`VVPbBb}NO+_4DoO8jHdo z15E(4qgy==T&ah4cv+(N-?M3u_-c(c*MKoNO5tYvSQ**OY^}bv+^A;^coyOUgAUvr zhx>PV?w8*`G4bH;J-gyPOAE9Y=5ZXumX2lTNRBU88k}!*{{0+$J_HE?_0bK~i>RI< z<mH3I1ABip8)NzEGIO3s;5sM~9M{EUdQldFFhqqGPidS)0=KsZ)sv!KuhE*jN~h!F zq8SQ8w)SOt!f$gtU!8vi4piU@tgGDH2b0>OQum&^R(w8UVC>UVJJ__i#HC26dme5g zM#?qBlL@?d0>|^vS`z`CRtvwdLc3naC`HydjA>1Bcz}N>RC%FTEnI+KP;h0Vyqc*E zizW(DlnSV48ja@ui_PZdonu>>OeD#w5I3GAo=TBOBuT_$#2g3D7~Ckr2)IU*R+=%# zVQVH$DW2ldxfRY<8`I}dpVV+R0{jh_Z{GqU1s$LP{S)v<qgp+5`(QsG-@TJeDhsZl zL?f=#oedO-AYlYyMA)daTqyD4+#;t|%e-ObAE$-SCls?<gf>w5aRd}lcq;)KB8(_? z=P2^<uu^wV#S;3x+cvX(beLR!KW-`m%HlT~R0^xSv9!X)<vbVab>^*{yrR@2Ga_Hl zqN0R?A4}k48x}u-05c+LSgHL3$dR0IM;}b3p)aPC2M~w^H7HkMx(KINl={}P$l2{m zHD^S~qWDP!-qm!xK74V;z?l=^^ubU}shs>!@>S46sx>IQx7*+E*8Uf{j)$PBSZZnj O0000<MNUMnLSTY)1k%C)
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bbbac94c15b45ab65c0148ddd5169d196eada9bf GIT binary patch literal 1482 zc$@*s1vUDKP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000G%Nkl<ZScUCZ z%WqUw82_Df?#$dfcV3-=zMv1FFGD0@L+!XRK{2h7r0GHuDmz1ruISo70ax;JTQ^iT zKtN2a8?XzYX(GW;5ef>ewjJ6sGxv2~E~f9!RB4TF{3YL=`<?IH`~ALe&i9>jiPjpG z(A(SFS5;M&7D9^kHbN>swhYD?b6qc(p8jKSczC$HBdv8=>Fetwmo8nJ(OPSz^p?@x z-F^J><twz3AEOd`&N+PF^RxyW$61VeW7y@!mJkky(ca$PaP;W=s?r=<$v_B!)}>Sv zLMl3{6xotwvu}P@k>O?p{w@4ZpdtazIbyMx+^&OIET#ts2P^uiXsEBRXSQu`sQ*`m zX_`29?tDdiMFJljJC+HBLiL<)or9DThG9fbocNHvGJ#OYumdhEr7D*2U!qis$~biB z(4O0OZkMg&HI3-}`3vUc<RmkrrfzI#Ac=SqQc7^nL4Y;=SFgIR8(ew0VIc4Wj6WYI zH*emGUcdGY>gwv{$&(*>OLNH5Uhu`4b8T&HE!V43RlEJb_ob8uB_!I~+6JXm>D^ib zq~xfitF=BiC<H&=y9d)W11UJt>5R(da!()r@~HdMPd=VlL!hUpr)O~Rt81~CjhBT2 zz8<;=-}k{NgVH6Bgb+~1KxruxOTS7gXlN*<A*Fy`oUc(@2c~JFzrP=LG>UvakN*DS zhi}~Y_WLz|K{A<4QcB>u9t!z9cJFRLYfBp<kuV6QfYzXlVRmK~gaGMu)pC0lLL!%& zg^&uhwY88!f-I9{c>e4+<nwt@LO>}+B9TmPSOazSyQ&GLP)dP-KyZ#nj~*hO&cL!P z5K0gUM_}7ggu`J(!V!4B2O%VE+eS@o9fS~2QleNaqEN`gaa<JhdCbgCqp`6ON^4L` zQNL?f^#%g*c&wID3MCal03ifi$HC0>G=va~sV%JoLMaFcT+am$I84)o9|Z7R2cGM} z_kB37gTN2qxh|}zjl*xh1E7?FSS(h%hQO(T0ovT$+)OA12tYvaa()4v2arlZ2m!$b zgy7(ugL47FIh0Zmk|Xc~2q7V*gcJf&Do9n*xd`CR2XGt*=}ZQcQe-ljJ*Nf+=;x<T ztN(m2FaRKC$7nK<Y-E&zF$Sd-ip9cmL|n*H7DOova+S^nU(C*;NDd(sq~H)jAm9Ol zAb{f(VHgaQF(ebo#yNYA0#F73jEs!X*AE=XFveg2a2*#Tw|;=u8cHcBtstd>k`hv> z(wJ0GYL&hyQb}m3AeDkv3PMVFu7ibz1sI_a7$Gn%YsbjQ2wl#A;}qH4+>3<gd6=2a z;n}n2@P&Y3gaAgt05Ah<I^p`xxN=LDj941-eGdyS^O&6c9Xm5sn45c%betkvCcrtz z<Hr+rzEH%Ir@!LCg9n(OUw~y=*wA0M0MGaF<jGTHcI<>131ed7iOo4*Sp!Ndy(5#h z48uTsYYX<j){bn~8&F!|Z=Ak2g$6(=1tAnQwKXsdhICcRR9fj}0+wZo(b3V1<3Eq@ zHzOt~7K@QcB+`;jr$bV1?@U4|#pKkah}rhI2DtD0x=<*LS(YV$ReQm~g9nM@I?+%l zL|n(UdwY8?_xJaA77B$;kKUU`uQlTFI4*p7;r7)lSKmveQeMCV9krv**yz|w1^{4e zY)k_vE~<s0p&_THrUtfcZ;L=8kwCU9JA3xb+1YY)%6^zoN)vbQ-fgI^u0}i_-;(ns zSeAu-`}Q>vLZVu0r!33$($v({k;~-@TmK+ii>axpxtiLVz2$tBZN=Gawl$SX+1m<z z71HT+s;jGOZ#i380-c?m9hCla+eA1VMz$;4QO>qp1*>u7-6LHc?HzAPDZMh!yfPSL kk^4X0A0Ga0_|AIUpYQdhxg}6*(*OVf07*qoM6N<$f{dBDfdBvi
new file mode 100755 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cf189f4696a1d30580c10e6850ce6e5d95a71ed0 GIT binary patch literal 1713 zc$@*T22S~jP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000JfNkl<ZScSEg zPi$OQ6~=$}y*ux{dGp6k98aAzvEwWnxh)AoO;I2fMu4IUb;%Z~NR`?JMJ(8KMa2RM zkl1vA0I8q?LWm+jYE_`rO+`ovQYG3Zp|PE`Y2u`@-DGC$nfK@3b6GskcpS%-iP|f@ z(HrU9d%knN?>p}*=NzBJnwgpLYqeTENs`9!(9oEOohVnT`<tuz<mklyzfBC6e*>WI z6u`{Pj9;(U>q(L{>h=1VF=k)AUf-{j8n09;6I$!tQ524aK`<nE!Aj;xj3X>5PM?|m z{liD@{ThJYZo(5MPTV~<Hum)(2oA(?JbviVq1{mwjcKiiwAO*|`<wPS;KpiBC$s3l zrxKTNVgV<;m~8_X85#N3!Gj0Cv)%aRm5h~4D3vsEB?JXVz*&bC`fc~Nd!X<8A;2JI zThX_g8m_i;;!1=LG`WDWVBPxje*+Mae%qXL{p7v(-eZlS)m~xg`U<(*oY*?BvVQKi zDHzDV<x10(G)c(P6mj4=$OM$?L&u5340PaQ10W(KNrH$)DTSj*WCRp|0_Onv1UjIU z>Qhh@>yWip=dJ+YxwSI{to@h)+&131f^X|k3Is4l@ReZKUATP!b`5q<d}^K8O-oU< zTLi2W0Gt!774Sf0T?BXBfk7aHt{99rA{giJ99UxuirgInu!F?i0;Jas=N!1AdM6HR z1#7{GAR>J+X66nk*uDlFJrRn7+z4U~io%Y@IaagvVzvYjKN9~q_QD5S?KUol`}f^9 z`PFwG;ps=8-VirPLEi;xO@snjZommjfv2F8IlB2aDDZs7pZ(FZpA&0P&Lb#=Jon3A zZLW8Kg5G~z0U*nBa$|~dtH4*V+!4fXgMvhL%|EaFgNk1!NJ8?=aqph{H;C<{oM4S5 zHx{#ILtjBBcQm^>ZaX%tP&urtK3R~^?RN3<fVZ!l-BkVHdr`e3&$A-ADTLUY10S>v z#>n<uF#XW<cvuf{zM)%bp}K(DXti70FCyew3S#k<W4UAS5j>?>?if~5!BgM{1ij_g zFbIQ^j(xm9k?D+7CFqjgAh;d~5h2fWvMj?`A=EyfnG9%MTgC%EXl2}7H6VgDwirmg z4t)9XuefG*gT!?qa8LqOQkZJaQGJA)S&NQYVOQmD<}S~2<go`B85*G$RFNDiQOx4a zW&ZGk=ZT_d?Smwguq0{1wYH(%Eo@jA)NQb|zHXQJ(i5L$qIQ5ry}?j*h<TaCQ_wXj zOUp|%S6al`FpoX?4Xm*!<>5Jn?`dpe`N>azfl`Vf2*|PwYb_4QtwW5(iLic|C`NQ2 zK$>J^i#gw$dy2{NN%r40Nu$=FWJ6Y)tK9hT2Hoo!7jDjSdFfrEYDAy|0z%4O%-Ha5 z(j>d>ICkO?EB%(cwV%PMs+|>F2FW?g#pEK3%ZrrD5uWw&JDOT^n5Y{QjA??M9y<0Y z`97X=7?&bgoZUPn3quqm*bbIl%;~;zb>M~6hN_fzl~I|a+fGT-jB>e*pU1p+?hGUM z4fEi>qcnm&;6X`gunI8{g=GRS95{bKpcI!-X9dp#PpN{Mfh&>TyL*DaKKD9z$w8D4 zcwiAmM|Kb&i@DmkjM<UW@tVB&yEDYpS-if;7Y-lA8MrP>?A<-FA+b^ltu?+^h%PtQ zv=UifZ08HtTKUq4o#Eg10lf6XKW!LiQ}^6c13ta<MfF-eO^8N)cI_CY6qYEtGAEyU ztzYTJmOFgkr&_JjYBjTkg@w8E?{{n~(u;3hZeM68(n>`sCGv{a>V-alP2|BUa6#pu zJcTZ6%H=XqP+q%eY`%(TS!R<YnVp}XKlS&QUq1EroBw%p?!EUfaQMk@k9}%*=VCK! zD_sixwE5!2XC8iOaPKAn=gyxO;L4##9{>xUr|>)vg+hBpc(d80)oRUlI-P&F+wE74 zF{c`h#`)>#>1=v>n#p~8Lls1onnz%*L{<f9IRBUDFaGhnCvMHR<tR?ODY2Bu$w?(4 zHyP<_#=^qFH!oefbP_mw{P^+oc6+tfMrm!7A4KP_W-GzmpMQPvh3}ufZR}P6s!`1N z_)bRcF?{Fa8_iHS#MIQ(GgDJjTWtg2<iAeahmL)IMd$Cn9>4YK+4)y~{>E0ZTLRd# zXCHGvyF@!}qe7_FDvXaF_{hY))#-Hj?>py3DYf|mam)H24%*=sTwet500000NkvXX Hu0mjfM9NfX
new file mode 100755 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..430a62341c613b35c9dddc9bfa359615b2e60b39 GIT binary patch literal 2373 zc$@)63A*-)P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3labT3lag+-G2N4000McNliru(+U>~B^h21PFDZ`2+~PJ zK~#9!)mLe3T-6o+?!9lFeesO#7~Am{3~mCXNk~G{B0^dyEvPJ|i>NA9T~rl;P^GF; zDXj`ENTm`jC8(v)0zxzp$_|0BxdfclByr+8n={^*u|1n-dGoe=`(wtzAt4E<e|rAR z%$s}P`OZ1t`OduzXRxlX{e*DaQv7vGy`E@;X693ta2@=wjGbx0>hJ&dvI}qg=}nCr zZn&xG(yxEn%B6bKgCFFUU2~gf_05lLrcCiWW^vBUCHbcTKtB2)*whI^Da#HIxbd#_ zWc4q$y*#)ye#LZzAXWt0cOTwv92>Y#i??~pt*!T#H5O*a61$zz;d>8nz2mLi@SgG~ z0U&+!!4>zsyhK*LS08+S%iF{6y)f$7q4;D!LH-K_1qEO$+BO9nmn=s~Sfh37lF2$* ziq(B)Q;SJ+vK}}9U;=>nR3*6Z+qZ{m)^C1zxHf#N|NM(@Xk32TTEic_a5OCIZj?X} zARVA|DyI6!Yt&HA!)N-9t@<HUo37FpK9`vXlY_4aG-s)M8y3S)cuS(PBXw2OW5 zuIIj!Sk}5_Ux>&u2cl&mibNpor36AiowMLel%QozNUnhJO0eP@N;L|EBB5@~Flzcn zcDS-aT+J6O^>^QY@R4tA6Wn#rTmnKgs`=I>dLUaJfYl5X6+%D=XwgNidlsSL9Awu5 zNF^vjDWt;;vaZ5x3}B|kug_iD@fBMk5FBXqTz*k|>Cc|TGq?Q1H4Db60MO%KD3MDh z>a7U?Zv#jJZ~<E82=`_Y8_PoXI*@}DazKI{kidKtLKm=6hB}o&TYn1if&)uqDEcML zM|B^Qd>bJ|@GLSwg>W6irwJ5F1RMYyK%FcjJ~9t~qw2b5DeIO?a}eC6s>e?it%l07 z4%dYc0uBr`i~}`>AA8R6LQ9*-kMB9ex$T~ogdJD?Kwo?FpKfH1)fSIv=VdfTip>-d zKwz|lxNTUa@tx17_P+AB*<ITn%lzk!=dA3+JFb!LR|39}T2oWQG>K7_g3Ex90~%E@ z8B!26VqqDcU4_y2$3K>YUDw~XzTt=WzIlkcDi;D7iJ~Y`fC2S=DOY*@@kd9VzV&VZ zvjB<!cy%w+Ynvj?*WI$Y{<7=tkUYL-!Cfi<_@UyE*NbG*6v6#N33qa6hseynI{w^u zU#Jv!Q3=#Qw0<TJbu7pr7K&n5mN}|KWUA$>&U01g3uYV1(dofQ?s!rO`{(O6UU{by z2%gWm3&9E692bdNos`yhw&~f9R{y@ije5hHK4W6{$ijPAxP2vA^}XM3IyS3anbm0} zE?&jx0*p!|l6OUJ&(^27W0g)JGJ-pnJG1kpqjJEzE52_1RkC0A6Awj*P)wE?a*V+Y zFv46d=FQ3lW1^>5I3*JRC;=ft2*&dO1^^rZFbu$`kgzN>pn2Jfy4BxYdAivlICm3| z{c(>mJ@}9uV1^t}fFMIiR00u60<*{<1zT4UNe?fSpBd>X5oqe_aN{e#nx3vEd9IoT zKfpm?Yl_?wYHd<g@1D%yd&!Rj;hJR;=;$1Ybe+47Y2GHqrI=0=%vgXnQAY5<(W&hF zciwF#KR8n5Qbh-{BLkUe1c=4}PY7TE0hFpsTp-URq|a$tQ-8@fejaLF6+NA_PQCf+ zlr>*^mry`<fkKr_o=nQLhqgao8rt3iAb&y|Ql=FmHF2|6OpP|Gx%rS^i6p762vVh~ z3(U*1B!}YXb#!f9QGedriA-Yem|e`CG;|6h#~e>XQ*G15Yp*R%0==_<;{Xs;Qbe>- z^DQ5S>^bVB2g=6*6laDCGy8Y!p6PpSr;$u_$6GGy$Oj|shFTR$4scG869mK;X{oJm z-q3QvB~X2VRCZ(_%N^@Dka*{3Y3G$Ut_eijuiiZhOqVMAU5^Yq680$~wu+iGWe&g4 z2Y@d$oiMY>yqQhrn>YPfa+oTEiV6>`MKuONf=FzFL^{rG`P_Z=ZEJqneEn^2IqBg+ zNhUc$94*j#(P~2uZFq4XFuh3q1tqX`73EkkE^)IBfCoVSr1L<aeckeGw032N$`$8} zk1V3{+XT>W0Xo&fL9O{(e|<A&6fU8l^J%bj2`D;?_GndiHb4r7!}C+=g?2s(fF<yy zRLmO`GJxqS5p@8u>VmmSi*f-J2~aE_A8PcZAuj;<0Mu1Hv8)A_Oioz2(V<F{f2eyO zrrEJtp%98700lr6K%@$S0|-<n<<zMp>BLL{0C8Oq&Oyoo`oBgEXW!OG?TOd=s#<%p zu+(&HN`?_xIp5%k+ffR?uuwmkHe^>YJHiMLQXpK-j<YCQAAn%>QwC73{3oXj__~K7 z_l-|GyPkN^*niK%!YPg~u<IlMPI-P@W5H~|+k80_RE_lvP4Ty%eNvw(XT5f4i5XX9 z$H#!tMF2Q}P5{dQ)B=bDn5o1lBnCQfLG-`=bot-|j|w|KQiXTwW4SSxaA*7ec_12G zQ3{S0?Xf3*^sD5qzi!LzfA%Ro!}mt4mJLRO&+nw9;~hc>ht%MJ3Kzmh0i9GxmjZ|; zz~+jMIM(yBGx^#Z5KiW-?gdtE@?iSlOWlRB-a!Cq;ad4}>d+DIit9dK?uak5gHnYf z4A8Shgx(!YtGzQt9`bpdxLV;%1W<?4obBBCp1JQg4+t|gabjbiq6-!*KhiV5NHPTg zIK?@;JU=!eqzi!7ib6_rHatgWi^W%deY;akCUkoL7AM-Vl<N%A2RY83>Fzf7-g7rE zjvZRi|FZ({5neA!4d==nhZ*H?eH7lFw1t1a^J*#a?3;qyW7^=6hqM<%KjZm%N9=w7 z9qaHDe{nOt2dcsFPYU29<6}eH^~ZOFv{0<m^?AeM=)k_*?%(}EaC;m;$r$+igHn1b zV-0N`cTzq5;P%{yW9=-iW@o<4QI%39q&IGEWO`kVnK_U#r+X3=%7KGW0uT+tl~55) r`*b&@PY&S3BRxAlCQgyw{|oysGyMwz%l5^H00000NkvXXu0mjfR3chC
new file mode 100755 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ab86df2f5872b0126a27b09d5e711db515d4e301 GIT binary patch literal 1518 zc$@+51rhp*P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000HGNkl<ZScT=+ zeQXnT9LMp`@9uiP>$Tmw2iCFe=4e6OSa}o((1hRv0i6W?5DkW?(Fkfx{6~!vgNc6; zC5G@INVhRiL?9THASxn4Kv>z6o23QT0UKjX+O6B#Zg<!F`3C_(7#qlg3E$-R-~I0W z%01+AgfWKuIoy4%KQI8>XGFYjfD|uLdQae(Yen|Zdk(Ob5=A&IRc?BFll!3yBb!Gr zcTKow09zSRgeK}MU9=%P<Zr}d)28!$SUMuVNv=WM6@aab<ntlwD_vCXsHv>QUurwf zb+kaV@d6(ef2RxnLELeG%}W%%kye&2DtA;Lt3{U)MZ$<<U*lfXU8u(pm)(>m*$>mF z$+$ZXu&pBsAEG|*;xb2dO*Oh%6bZzz|J*M)qc?-g0FcFy%_*W0<GSfALT(7i-D=}< zx2E*_>fA8?IZ?PKlh6A`nWNfYg>E5=1dZcB=RTYfnjz)@mK+I|h73HM>nfJ4d{f^Z z#)N;LD0_?99IrAq8^p-Vf&5(S{CH@fcxo9@$QhH*`&OBws<9G1v<H2x7l+z^LyOP? zIg5u`kdgdJfJlVmgMkCV?p<mU0Lazfg0ynZ9BW`({7Zv#B+iVH%kurw!+c42q2APA ze8^@|(M}NG`o*P=>a)iXOU9tGJ{%1n#<@f@BuZfxWJI<n5O3`%CL#&;e6Q=5_g?|n zR}iT;gl`TmIWniGrxO;=2D?2S?q!93Td`1b@dfQVMDBL0(ibp%YhPRMsB5i3EE$7l zs5sVn6m7ldK&4CZ)-NOIYVLAFWP!vkreA#y!We_&6WN>|9=c`a>#OFdstUq5#Pk>h zo=3Jl2am1v`0ZollGbNqR}cj|)0E!h$;vgauFL+Ttqutz29>F(?W)2B^*ku0kT?k; zZyTcR9mO1nVEnsl;{ZUc9}$yy*1EO)-3@c8D1s0UomvMpra^}WffrygS@B}|0)NK1 zl#<Y#aMOt0SxVfm`&PcZ+Tp+0fP@i;1`YK+HE7o^K%x|sGvm*dO^C)LZeBznw(<Hn z0B}r$%z<<HnvdY)h9&UF{(wm|!QhifaynwH2a#kL6|a0<6s?bcH|giX1=d53x;3w^ zbp)fwq46r1iQ$CqN4L-gd#W9FOB#-Q&md}!xJ4)FHx2;2X(}|w(9GIaU-)U4%W2)& zwGBMaBhRY9;0)+QhelK+NDR-9U6{2m^y|D&7cQ6UyK12k6-hpclX?JA(gBNXfmO1i zYE1yq)QfJZfCQuO8~w(wc?d@?&G*<k(kn8jraI5(oW^j=Bbc7?I4pt{y(|Hp=n#ki zi(x|>-vR~(ooG0z1`sjApdy9DOE|Qq7TvapTYQKG&(BY2H;Z2b0D#<g(x&NQY;r!S z3^R=)FcUK-rA$K}RiF|TI&=`8Kw~O&q9LT8L?<E;g-h}M-b$$HF}JLkg29<>1IDid z0D%1i!K1dbjblsP!?MQNp(a&0=?Dy$MuO*fXhcJj=s0aOB8m=BfkNad_EsDQ$xFJ^ zvn;_QlLLc_-w*%*_T`+X?-Z$+@Z>nBYepUtdK{^|9R=cW$efI`tO;GD6I7ruaUyn? z?T1vzyK^!!gFhA>9dx{3003l`n>=wJDkjaE;2br3IQsNn2%HErXNJo4fpQcgD0Y<o zfK<2aF38IbZp;1Ymf|-B06_k?DbqUkX`3cKHGbIS*`uLB2L~Q9WKbqyW9c?zPt0(S zaOMZUux-8N_<#Ta81-|Wr)77f!ZUY@bLR9J000xCSXWk#;;BXMqC(fHC0N#bJ8=L2 zV{E`RrLxeI_MSB~Z%+x^+~;MFmX2Ys9e=5K2m6W+X8+CBpbwncFxiv+Vdm*ctH-lv z0#6igV5|OfoG~`=Ex0_hf>VfDmZx$==qSihLd!Yt?O*n*X3&7UH4nzG+5Z~wHz#We UggAPbj{pDw07*qoM6N<$f})Gi!vFvP
new file mode 100755 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0b7754cdcb36186295ff86c50d1f3560a0cf0674 GIT binary patch literal 2013 zc$@*<2O{{1P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000N1Nkl<ZScScp zX^dZ06~KS@-naah**epOb~>e{3~f<Lq<|)XMNqb4)k+1FXp~6!fPOI&(HQxp32M;R zB_&Xd5s3?nh}udNMbv^Mgn|Jq(@q_rlv)4VTkpNc4^wK%6zYeGC%JhidFS2pduO}v zAtKD@TEF&`&%OJc4R`;q_VemoM7VlM?>*1_<8j&Wj?=c+73xIxnt7J0@$$}7mvR3+ zJ8nAXtTp#6R?57c{k#KIjHf-imleH=pM3Y$YtLM}@<&Uq58l$xyaPnaNj`p%#^^uk zml?i)>kZdkw72JxMR!*f!1~)xQA=;^QE%7>Zzxxuy*#Xh^kq}8&|B5iL#TyN31(Mh zAk<(KO6gf}5rr3U0;Pve=DHRyTfVfIIYi+t&RKdx%@;nt^&)rsy}S7|m+ZZHzpVTA z;86f2A^=={{)(@EWN6(jl!;dg6dt8OtJ$kk9;F08DFhJk4iUk7!8^fPPZ(9zxtrFI zb~4J+VQood6fYkx+5W(vcR%#6^s-|kb~FMtl?{II`i+D((N0RVc9_7T1B*5ev;_sI zBagTeTnc3Zc}|g8^30QUGCGZYxWtkrj!tSR%aT~bHSbw@>DD#fzxl<Btxa<Px<l`q zukDA{G@>j~?1*AZ7&)TAVnQIOgQ)@r#DmMAXhJrP$y!8NhD#k$=E)O_v>ip;(`Y-2 z(h(`)!r=v1Y*|~o@BSB(kG=_@9(p<xV@PA1AhJkgAu0(fB|7#{>4%DeFyaW!EQm1> z1{kX`Iwh1Tw6j=&eAWWzp_zh0k&0qr$5!U1AaJxN#xU(ysni@Z9mhbIrmsIlb)N*$ zG6<GKZ3)DE5L7{F5DP^I(n;tXLI?ZkPM^cN4lM^o35^_HNi<duFg-H!yF12;xhbdy zLY_@iu?=w0g<{c)(>X9&N%sEgKo(VIl-AFpf(T5&(GC`mc#roETNJ);a9Qob3(lza z%X1)Y@)FWqQK|u+d3JKwj)U%s;}>Cw!YE7#aR9w_MHtul!_S}IbK^*HadES%s0cz2 zL>ja@QU`*w(6P{Sn`C#ci5}m$dFy$~W%SC6EY>BBU@?z9Huc9HBkuBLKOU&})?)ws zRj;OR0;mKO$|wRuS`DBpuA}0fsu9};h;EaNw-5vL9MQvoQY}~oHbeOiS=ICC-<p5_ z>jP`9iyu&H7U_Niw16=<W)j8$uW7|-U>K<xMofKRL{|q6dZ!A2jZa^^W!<*bcfA$F zQ5bDdy+hEyn(1he?>*ccop|)hTXbR10)|lxi^$-d6vT!xr5FhmNn|us2O#dPb(~4w zw`c8pS5KdPpB`xMIS~LRf`zBT$W#9A9Zx*<@YW@hSLA+!wdIlNr$X<24D5MR1VY0k zaKON*Hqj_??<hgfGwBEVdL=t)_qCT_P0$^?6ZscWI(c$8cYJB*!~3=kZxO48iy}X> zD9bbOoPp;|XWgnf5ip7wFC0`tt_eU_I=@zj&fE2|6`Rkwa9E8pLT1ww2B2OskNxb6 z+gdk_x(}VV|NQlpC|Q{0*@isNMJ$M=Do8R1Kx-P#F(!^uiEce)U%B`z<NK~T<@^<D zx;4RA_dybu9N+6PvgL`%ufC!Cq*YZ$_a#ZEH%oJo0wfa+9Gn9HGz-hCammz!&R+ic z_Mw~lR(I+4%nXs%jK_z`n`ylMw<m|yh1F^hhAIdRMr)MPpdeL1=_tL&&ZJ3rzz^XJ z&303zom@!<Bp`~p$FT@aWBm(1&CTX-q~X`n<&(xV3gW<EjK+k9)$!1~Mqhk=%8$he z5uyS-29#jMAy^6#tS_-8^k#iQb&;acY>;+xqz%#liT?Z6M*%k7**yH^&o2GsFKa`$ z+k7gBCj*Mu(FqeY2JeN%?_Xpt=-JR!i|cfoZfbN95+VpW8BLnB%O<T(i*~0?D{V71 zKE?RNBzeQ4rhpDe^*8{ZxU{-?@9C%RT)Aw}3}z_~kIhRYvxxF^T*>}?jFG8>NbHcv z;zNhm9;X}*i!Dov!cn9pMZ3hdJmri~P78h<WE_Y<GMNkTdWX8Vm^ciP(xNg8(_j_g z9o~ajkIz9O!AIa@!3Q3v9S)Ckg13U?AO&~};y`j>8c2Z{<d|kUItLzkJiT{#-)q<J zdufEI8lzC?jzW)Xm{dqZ;hGB72_cEld4w(^Oc`NpjJ6TlM;ITW3DG)2DT7k8MXGx= zYJo;Y8rMEf3IHD5HNNwbbA#Z3(K}9FIYgEu=v3nijY>ReCzqLaLogy}nLPv)palUu ze)ea>YrG3F&Va=SRuBt;3Z%a>5CujZngj5?s|M7B>f`rM+B-gcVV8MH>mLjbokW(V zXseM%z{L3Yzw^rU1%yN@P)Y@WR;VLQB_5OmWcD+G638eeMSKcbTX;E3br;=}a{wj| zx9MNJU^WteYX9&vm(_wNQQMXdEh0-&G>S&EmE_y~81pDc0dD<EF2~;3xhvUTUspH5 zCT?H2Y=F$>Xs_n(Fkb-2lg{&<@AM3J2W*mW4xB!Kl=61w^A7;f+}HY6ZAo=%&8O5| vwX`<#e+K|a4yQX;4X>)zPOER6Z-D;*^=ohDk=S=*00000NkvXXu0mjf^Q5|F
--- a/libgui/src/m-editor/file-editor-interface.h +++ b/libgui/src/m-editor/file-editor-interface.h @@ -44,15 +44,32 @@ virtual QMenu *debug_menu () = 0; virtual QToolBar *toolbar () = 0; - virtual void handle_entered_debug_mode () = 0; - virtual void handle_quit_debug_mode () = 0; + virtual void handle_enter_debug_mode (void) = 0; + virtual void handle_exit_debug_mode (void) = 0; + + virtual void + handle_insert_debugger_pointer_request (const QString& file, int line) = 0; + + virtual void + handle_delete_debugger_pointer_request (const QString& file, int line) = 0; + + virtual void + handle_update_breakpoint_marker_request (bool insert, const QString& file, + int line) = 0; + + virtual void handle_edit_file_request (const QString& file) = 0; + virtual void set_focus () = 0; + virtual void connect_visibility_changed (void) = 0; + public slots: - virtual void request_new_file () = 0; + virtual void request_new_file (const QString& command = QString ()) = 0; virtual void request_open_file () = 0; - virtual void request_open_file (const QString& fileName) = 0; - + virtual void request_open_file (const QString& openFileName, int line = -1, + bool debug_pointer = false, + bool breakpoint_marker = false, + bool insert = true) = 0; //signals: //protected:
--- a/libgui/src/m-editor/file-editor-tab.cc +++ b/libgui/src/m-editor/file-editor-tab.cc @@ -35,19 +35,25 @@ #include <Qsci/qscilexerperl.h> #include <Qsci/qscilexerbatch.h> #include <Qsci/qscilexerdiff.h> +#include <Qsci/qsciprinter.h> #include "resource-manager.h" #include <QApplication> #include <QFileDialog> #include <QMessageBox> #include <QTextStream> #include <QVBoxLayout> +#include <QInputDialog> +#include <QPrintDialog> #include "file-editor-tab.h" #include "file-editor.h" + +#include "builtin-defun-decls.h" +#include "debug.h" +#include "load-path.h" #include "octave-link.h" - -#include "debug.h" #include "oct-env.h" +#include "utils.h" // Make parent null for the file editor tab so that warning // WindowModal messages don't affect grandparents. @@ -115,7 +121,9 @@ connect (&_file_system_watcher, SIGNAL (fileChanged (QString)), this, SLOT (file_has_changed (QString))); - notice_settings (); + QSettings *settings = resource_manager::get_settings (); + if (settings) + notice_settings (settings); } file_editor_tab::~file_editor_tab () @@ -190,13 +198,9 @@ else { if (markers_mask && (1 << breakpoint)) - { - request_remove_breakpoint (line); - } + request_remove_breakpoint (line); else - { - request_add_breakpoint (line); - } + request_add_breakpoint (line); } } } @@ -241,21 +245,10 @@ } QSettings *settings = resource_manager::get_settings (); + if (settings) + lexer->readSettings (*settings); + _edit_area->setLexer (lexer); - // Editor font (default or from settings) - if (settings) - lexer->setDefaultFont (QFont ( - settings->value ("editor/fontName", - "Courier").toString (), - settings->value ("editor/fontSize", - 10).toInt ())); - - // TODO: Autoindent not working as it should - lexer->setAutoIndentStyle (QsciScintilla::AiMaintain || - QsciScintilla::AiOpening || - QsciScintilla::AiClosing); - - _edit_area->setLexer (lexer); } // slot for fetab_set_focus: sets the focus to the current edit area @@ -340,6 +333,24 @@ } void +file_editor_tab::print_file (const QWidget* ID) +{ + if (ID != this) + return; + + QsciPrinter * printer = new QsciPrinter( QPrinter::HighResolution ); + + QPrintDialog printDlg(printer, this); + + if(printDlg.exec() == QDialog::Accepted) + { + printer->printRange(_edit_area); + } + delete printer; +} + + +void file_editor_tab::run_file_callback (void) { // Maybe someday we will do something here? @@ -356,8 +367,6 @@ QFileInfo file_info (_file_name); QString path = file_info.absolutePath (); - QString current_path - = QString::fromStdString (octave_link::last_working_directory ()); QString function_name = file_info.fileName (); // We have to cut off the suffix, because octave appends it. @@ -421,56 +430,96 @@ _edit_area->markerDeleteAll (bookmark); } +bool +file_editor_tab::file_in_path (const bp_info& info) +{ + bool ok = false; + bool addpath_option = true; + + std::string curr_dir = octave_env::get_current_directory (); + + if (curr_dir == info.path) + ok = true; + else + { + bool dir_in_load_path = load_path::contains_canonical (info.path); + + std::string base_file = octave_env::base_pathname (info.file); + std::string lp_file = load_path::find_file (base_file); + + if (dir_in_load_path) + { + if (same_file (lp_file, info.file)) + ok = true; + } + else + { + // File directory is not in path. Is the file in the path in + // the current directory? If so, then changing the current + // directory will be needed. Adding directory to path is + // not enough because the file in the current directory would + // still be found. + + if (same_file (lp_file, base_file)) + { + if (same_file (curr_dir, info.path)) + ok = true; + else + addpath_option = false; + } + } + } + + if (! ok) + { + int action + = octave_link::debug_cd_or_addpath_error (info.file, info.path, + addpath_option); + switch (action) + { + case 1: + Fcd (ovl (info.path)); + ok = true; + break; + + case 2: + load_path::prepend (info.path); + ok = true; + break; + + default: + break; + } + } + + return ok; +} + void file_editor_tab::add_breakpoint_callback (const bp_info& info) { - bp_table::intmap intmap; - intmap[0] = info.line + 1; + bp_table::intmap line_info; + line_info[0] = info.line; - std::string previous_directory = octave_env::get_current_directory (); - octave_env::chdir (info.path); - intmap = bp_table::add_breakpoint (info.function_name, intmap); - octave_env::chdir (previous_directory); - - if (intmap.size () > 0) - { - // FIXME -- Check file. - _edit_area->markerAdd (info.line, breakpoint); - } + if (file_in_path (info)) + bp_table::add_breakpoint (info.function_name, line_info); } void file_editor_tab::remove_breakpoint_callback (const bp_info& info) { - bp_table::intmap intmap; - intmap[0] = info.line; - - std::string previous_directory = octave_env::get_current_directory (); - octave_env::chdir (info.path); - bp_table::remove_breakpoint (info.function_name, intmap); - octave_env::chdir (previous_directory); + bp_table::intmap line_info; + line_info[0] = info.line; - // FIXME -- check result - bool success = true; - - if (success) - { - // FIXME -- check file. - _edit_area->markerDelete (info.line, breakpoint); - } + if (file_in_path (info)) + bp_table::remove_breakpoint (info.function_name, line_info); } void file_editor_tab::remove_all_breakpoints_callback (const bp_info& info) { - bp_table::intmap intmap; - std::string previous_directory = octave_env::get_current_directory (); - octave_env::chdir (info.path); - intmap = bp_table::remove_all_breakpoints_in_file (info.function_name, true); - octave_env::chdir (previous_directory); - - if (intmap.size() > 0) - _edit_area->markerDeleteAll (breakpoint); + if (file_in_path (info)) + bp_table::remove_all_breakpoints_in_file (info.function_name, true); } void @@ -483,7 +532,7 @@ // We have to cut off the suffix, because octave appends it. function_name.chop (file_info.suffix ().length () + 1); - bp_info info (path, function_name, line); + bp_info info (_file_name, path, function_name, line+1); octave_link::post_event (this, &file_editor_tab::add_breakpoint_callback, info); @@ -499,7 +548,7 @@ // We have to cut off the suffix, because octave appends it. function_name.chop (file_info.suffix ().length () + 1); - bp_info info (path, function_name, line); + bp_info info (_file_name, path, function_name, line+1); octave_link::post_event (this, &file_editor_tab::remove_breakpoint_callback, info); @@ -560,7 +609,7 @@ // We have to cut off the suffix, because octave appends it. function_name.chop (file_info.suffix ().length () + 1); - bp_info info (path, function_name, 0); + bp_info info (_file_name, path, function_name, 0); octave_link::post_event (this, &file_editor_tab::remove_all_breakpoints_callback, info); @@ -608,7 +657,8 @@ if (!_find_dialog) { - _find_dialog = new find_dialog (_edit_area); + _find_dialog = new find_dialog (_edit_area, + qobject_cast<QWidget *>(sender ())); connect (_find_dialog, SIGNAL (finished (int)), this, SLOT (handle_find_dialog_finished (int))); _find_dialog->setWindowModality (Qt::NonModal); @@ -628,6 +678,32 @@ } void +file_editor_tab::goto_line (const QWidget* ID, int line) +{ + if (ID != this) + return; + + if (line <= 0) // ask for desired line + { + bool ok = false; + int index; + _edit_area->getCursorPosition(&line, &index); + line = QInputDialog::getInt (_edit_area, tr("Goto line"), tr("Line number"), + line+1, 1, _edit_area->lines(), 1, &ok); + if (ok) + { + _edit_area->setCursorPosition (line-1, 0); + center_current_line (); + } + } + else // go to given line without dialog + { + _edit_area->setCursorPosition (line-1, 0); + } +} + + +void file_editor_tab::do_comment_selected_text (bool comment) { if ( _edit_area->hasSelectedText() ) @@ -772,10 +848,10 @@ } void -file_editor_tab::new_file () +file_editor_tab::new_file (const QString &commands) { update_window_title (false); // window title (no modification) - _edit_area->setText (""); + _edit_area->setText (commands); _edit_area->setModified (false); // new file is not modified yet } @@ -1002,12 +1078,12 @@ } void -file_editor_tab::notice_settings () +file_editor_tab::notice_settings (const QSettings *settings) { - QSettings *settings = resource_manager::get_settings (); + // QSettings pointer is checked before emitting. - if (settings==NULL) - return; // this shouldn't happen! + update_lexer (); + QFontMetrics lexer_font_metrics (_edit_area->lexer ()->defaultFont (0)); _edit_area->setCaretLineVisible(settings->value ("editor/highlightCurrentLine",true).toBool ()); @@ -1016,15 +1092,10 @@ else _edit_area->setAutoCompletionThreshold (-1); - QFont xfont (settings->value ("editor/fontName","Courier").toString (), - settings->value ("editor/fontSize",10).toInt ()); - if (settings->value ("editor/showLineNumbers",true).toBool ()) { _edit_area->setMarginLineNumbers (2, true); - _edit_area->setMarginsFont (xfont); - QFontMetrics metrics (xfont); - _edit_area->setMarginWidth(2, metrics.width("9999")); + _edit_area->setMarginWidth(2, lexer_font_metrics.width("9999")); } else { @@ -1032,8 +1103,6 @@ _edit_area->setMarginWidth(2, 0); } - update_lexer (); - _long_title = settings->value ("editor/longWindowTitle",false).toBool (); update_window_title (false); @@ -1083,7 +1152,7 @@ // Unnamed files shouldn't be transmitted. if (!_file_name.isEmpty ()) - emit add_filename_to_list (_file_name); + emit add_filename_to_list (_file_name, this); } void @@ -1120,12 +1189,56 @@ } void -file_editor_tab::set_debugger_position (int line) +file_editor_tab::insert_debugger_pointer (const QWidget *ID, int line) { - _edit_area->markerDeleteAll (debugger_position); + if (ID != this || ID == 0) + return; + if (line > 0) { - _edit_area->markerAdd (line, debugger_position); + _edit_area->markerAdd (line-1, debugger_position); + center_current_line (); + } +} + +void +file_editor_tab::delete_debugger_pointer (const QWidget *ID, int line) +{ + if (ID != this || ID == 0) + return; + + if (line > 0) + _edit_area->markerDelete (line-1, debugger_position); +} + +void +file_editor_tab::do_breakpoint_marker (bool insert, const QWidget *ID, int line) +{ + if (ID != this || ID == 0) + return; + + if (line > 0) + { + if (insert) + _edit_area->markerAdd (line-1, breakpoint); + else + _edit_area->markerDelete (line-1, breakpoint); + } +} + + +void +file_editor_tab::center_current_line () +{ + long int visible_lines = _edit_area->SendScintilla + (QsciScintillaBase::SCI_LINESONSCREEN); + if (visible_lines > 2) + { + int line, index; + _edit_area->getCursorPosition(&line,&index); + int first_line = _edit_area->firstVisibleLine (); + first_line = first_line + (line - first_line - (visible_lines-1)/2); + _edit_area->setFirstVisibleLine (first_line); } }
--- a/libgui/src/m-editor/file-editor-tab.h +++ b/libgui/src/m-editor/file-editor-tab.h @@ -27,6 +27,7 @@ #include <QWidget> #include <QCloseEvent> #include <QFileSystemWatcher> +#include <QSettings> #include "find-dialog.h" @@ -44,7 +45,7 @@ void handle_margin_clicked (int line, int margin, Qt::KeyboardModifiers state); /** Tells the editor tab to react on changed settings. */ - void notice_settings (); + void notice_settings (const QSettings *settings); /** Will initiate close if associated with the identifier tag. */ void conditional_close (const QWidget* ID); /** Change to a different editor tab by identifier tag. */ @@ -61,6 +62,7 @@ void save_file (const QWidget* ID); void save_file (const QWidget* ID, const QString& fileName, bool remove_on_success); void save_file_as (const QWidget* ID); + void print_file (const QWidget* ID); void run_file (const QWidget* ID); void toggle_bookmark (const QWidget* ID); void next_bookmark (const QWidget* ID); @@ -75,13 +77,17 @@ void comment_selected_text (const QWidget* ID); void uncomment_selected_text (const QWidget* ID); void find (const QWidget* ID); + void goto_line (const QWidget* ID, int line = -1); - void set_debugger_position (int line); + void insert_debugger_pointer (const QWidget *ID, int line = -1); + void delete_debugger_pointer (const QWidget *ID, int line = -1); + + void do_breakpoint_marker (bool insert, const QWidget *ID, int line = -1); void set_modified (bool modified = true); QString load_file (const QString& fileName); - void new_file (); + void new_file (const QString& commands = QString ()); void file_has_changed (const QString& fileName); @@ -89,7 +95,7 @@ void file_name_changed (const QString& fileName, const QString& toolTip); void editor_state_changed (bool copy_available, const QString& fileName); void tab_remove_request (); - void add_filename_to_list (const QString& fileName); + void add_filename_to_list (const QString&, QWidget *); void mru_add_file (const QString& file_name); void editor_check_conflict_save (const QString& saveFileName, bool remove_on_success); void process_octave_code (const QString& command); @@ -116,10 +122,12 @@ struct bp_info { - bp_info (const QString& p, const QString& fn, int l) - : path (p.toStdString ()), function_name (fn.toStdString ()), line (l) + bp_info (const QString& f, const QString& p, const QString& fn, int l) + : file (f.toStdString ()), path (p.toStdString ()), + function_name (fn.toStdString ()), line (l) { } + std::string file; std::string path; std::string function_name; int line; @@ -137,9 +145,13 @@ void do_comment_selected_text (bool comment); void run_file_callback (void); + + bool file_in_path (const bp_info& info); + void add_breakpoint_callback (const bp_info& info); void remove_breakpoint_callback (const bp_info& info); void remove_all_breakpoints_callback (const bp_info& info); + void center_current_line (); QsciScintilla * _edit_area;
--- a/libgui/src/m-editor/file-editor.cc +++ b/libgui/src/m-editor/file-editor.cc @@ -36,8 +36,10 @@ #include <QMessageBox> #include <QStyle> #include <QTextStream> +#include <QProcess> #include "octave-link.h" +#include "utils.h" file_editor::file_editor (QWidget *p) : file_editor_interface (p) @@ -54,12 +56,17 @@ file_editor::~file_editor () { QSettings *settings = resource_manager::get_settings (); - fetFileNames.clear (); + editor_tab_map.clear (); if (settings->value ("editor/restoreSession",true).toBool ()) { // Have all file editor tabs signal what their file names are. emit fetab_file_name_query (0); } + QStringList fetFileNames; + for (editor_tab_map_const_iterator p = editor_tab_map.begin (); + p != editor_tab_map.end (); p++) + fetFileNames.append (p->first); + settings->setValue ("editor/savedSessionTabs", fetFileNames); settings->sync (); @@ -67,6 +74,26 @@ delete _mru_file_menu; } +void +file_editor::focus (void) +{ + set_focus (); +} + +void +file_editor::handle_visibility (bool visible) +{ + if (visible && ! isFloating ()) + focus (); +} + +void +file_editor::connect_visibility_changed (void) +{ + connect (this, SIGNAL (visibilityChanged (bool)), + this, SLOT (handle_visibility (bool))); +} + // set focus to editor and its current tab void file_editor::set_focus () @@ -94,19 +121,19 @@ } void -file_editor::handle_entered_debug_mode () +file_editor::handle_enter_debug_mode (void) { _run_action->setEnabled (false); } void -file_editor::handle_quit_debug_mode () +file_editor::handle_exit_debug_mode (void) { _run_action->setEnabled (true); } void -file_editor::request_new_file () +file_editor::request_new_file (const QString& commands) { // New file isn't a file_editor_tab function since the file // editor tab has yet to be created and there is no object to @@ -116,7 +143,7 @@ if (fileEditorTab) { add_file_editor_tab (fileEditorTab, ""); // new tab with empty title - fileEditorTab->new_file (); // title is updated here + fileEditorTab->new_file (commands); // title is updated here set_focus (); // focus editor and new tab } } @@ -141,9 +168,45 @@ fileDialog->show (); } +// Check whether this file is already open in the editor. +QWidget * +file_editor::find_tab_widget (const QString& file) const +{ + QWidget *retval = 0; + + for (editor_tab_map_const_iterator p = editor_tab_map.begin (); + p != editor_tab_map.end (); p++) + { + QString tab_file = p->first; + + if (same_file (file.toStdString (), tab_file.toStdString ())) + { + retval = p->second; + break; + } + } + + return retval; +} + void -file_editor::request_open_file (const QString& openFileName) +file_editor::request_open_file (const QString& openFileName, int line, + bool debug_pointer, + bool breakpoint_marker, bool insert) { + // Check if the user wants to use a custom file editor. + QSettings *settings = resource_manager::get_settings (); + if (settings->value ("useCustomFileEditor").toBool ()) + { + QString editor = settings->value ("customFileEditor").toString (); + editor.replace ("%f",openFileName); + editor.replace ("%l",QString::number (line)); + QProcess::startDetached (editor); + if (line < 0) + handle_mru_add_file(QDir::cleanPath (openFileName)); + return; + } + if (openFileName.isEmpty ()) { // ?? Not sure this will happen. This routine isn't even called @@ -152,63 +215,74 @@ else { // Have all file editor tabs signal what their file names are. - fetFileNames.clear (); + editor_tab_map.clear (); emit fetab_file_name_query (0); // Check whether this file is already open in the editor. - if (fetFileNames.contains (openFileName, Qt::CaseSensitive)) + QWidget *tab = find_tab_widget (openFileName); + + if (tab) + { + _tab_widget->setCurrentWidget (tab); + + if (line > 0) + { + emit fetab_goto_line (tab, line); + + if (debug_pointer) + emit fetab_insert_debugger_pointer (tab, line); + + if (breakpoint_marker) + emit fetab_do_breakpoint_marker (insert, tab, line); + } + + emit fetab_set_focus (tab); + } + else { - // Create a NonModal message so nothing is blocked and - // bring the existing file forward. - QMessageBox* msgBox = new QMessageBox ( - QMessageBox::Critical, tr ("Octave Editor"), - tr ("File %1 is already open in the editor."). - arg (openFileName), QMessageBox::Ok, 0); - msgBox->setWindowModality (Qt::NonModal); - msgBox->setAttribute (Qt::WA_DeleteOnClose); - msgBox->show (); - QFileInfo file(openFileName); - QString short_openFileName = file.fileName(); // get file name only - for(int i = 0; i < _tab_widget->count (); i++) - { // check whether tab title is file name (long or short) - if (_tab_widget->tabText (i) == openFileName || - _tab_widget->tabText (i) == short_openFileName) + file_editor_tab *fileEditorTab = new file_editor_tab (); + if (fileEditorTab) + { + QString result = fileEditorTab->load_file(openFileName); + if (result == "") { - _tab_widget->setCurrentIndex (i); - break; + // Supply empty title then have the file_editor_tab update + // with full or short name. + add_file_editor_tab (fileEditorTab, ""); + fileEditorTab->update_window_title (false); + // file already loaded, add file to mru list here + handle_mru_add_file(QDir::cleanPath (openFileName)); + + if (line > 0) + { + emit fetab_goto_line (fileEditorTab, line); + + if (debug_pointer) + emit fetab_insert_debugger_pointer (fileEditorTab, + line); + if (breakpoint_marker) + emit fetab_do_breakpoint_marker (insert, fileEditorTab, + line); + } + } + else + { + delete fileEditorTab; + // Create a NonModal message about error. + QMessageBox* msgBox = new QMessageBox ( + QMessageBox::Critical, tr ("Octave Editor"), + tr ("Could not open file %1 for read:\n%2."). + arg (openFileName).arg (result), + QMessageBox::Ok, 0); + msgBox->setWindowModality (Qt::NonModal); + msgBox->setAttribute (Qt::WA_DeleteOnClose); + msgBox->show (); } } - return; + + // really show editor and the current editor tab + set_focus (); } - - file_editor_tab *fileEditorTab = new file_editor_tab (); - if (fileEditorTab) - { - QString result = fileEditorTab->load_file(openFileName); - if (result == "") - { - // Supply empty title then have the file_editor_tab update - // with full or short name. - add_file_editor_tab (fileEditorTab, ""); - fileEditorTab->update_window_title (false); - // file already loaded, add file to mru list here - handle_mru_add_file(QDir::cleanPath (openFileName)); - } - else - { - delete fileEditorTab; - // Create a NonModal message about error. - QMessageBox* msgBox = new QMessageBox ( - QMessageBox::Critical, tr ("Octave Editor"), - tr ("Could not open file %1 for read:\n%2."). - arg (openFileName).arg (result), - QMessageBox::Ok, 0); - msgBox->setWindowModality (Qt::NonModal); - msgBox->setAttribute (Qt::WA_DeleteOnClose); - msgBox->show (); - } - } - set_focus (); // really show editor and the current editor tab } } @@ -228,11 +302,13 @@ file_editor::check_conflict_save (const QString& saveFileName, bool remove_on_success) { // Have all file editor tabs signal what their file names are. - fetFileNames.clear (); + editor_tab_map.clear (); emit fetab_file_name_query (0); - // If one of those names matches the desired name, that's a conflict. - if (fetFileNames.contains (saveFileName, Qt::CaseSensitive)) + // Check whether this file is already open in the editor. + QWidget *tab = find_tab_widget (saveFileName); + + if (tab) { // Note: to overwrite the contents of some other file editor tab // with the same name requires identifying which file editor tab @@ -283,6 +359,49 @@ } void +file_editor::handle_insert_debugger_pointer_request (const QString& file, int line) +{ + request_open_file (file, line, true); +} + +void +file_editor::handle_delete_debugger_pointer_request (const QString& file, int line) +{ + if (! file.isEmpty ()) + { + // Have all file editor tabs signal what their file names are. + editor_tab_map.clear (); + emit fetab_file_name_query (0); + + // Check whether this file is already open in the editor. + QWidget *tab = find_tab_widget (file); + + if (tab) + { + _tab_widget->setCurrentWidget (tab); + + if (line > 0) + emit fetab_delete_debugger_pointer (tab, line); + + emit fetab_set_focus (tab); + } + } +} + +void +file_editor::handle_update_breakpoint_marker_request (bool insert, + const QString& file, int line) +{ + request_open_file (file, line, false, true, insert); +} + +void +file_editor::handle_edit_file_request (const QString& file) +{ + request_open_file (file); +} + +void file_editor::request_undo () { emit fetab_undo (_tab_widget->currentWidget ()); @@ -325,6 +444,13 @@ } void +file_editor::request_print_file () +{ + emit fetab_print_file (_tab_widget->currentWidget ()); +} + + +void file_editor::request_run_file () { emit fetab_run_file (_tab_widget->currentWidget ()); @@ -397,6 +523,13 @@ } void +file_editor::request_goto_line () +{ + emit fetab_goto_line (_tab_widget->currentWidget ()); +} + + +void file_editor::handle_mru_add_file (const QString& file_name) { _mru_files.removeAll (file_name); @@ -431,7 +564,8 @@ } void -file_editor::handle_file_name_changed (const QString& fileName, const QString& toolTip) +file_editor::handle_file_name_changed (const QString& fname, + const QString& tip) { QObject *fileEditorTab = sender(); if (fileEditorTab) @@ -440,8 +574,8 @@ { if (_tab_widget->widget (i) == fileEditorTab) { - _tab_widget->setTabText (i, fileName); - _tab_widget->setTabToolTip (i, toolTip); + _tab_widget->setTabText (i, fname); + _tab_widget->setTabToolTip (i, tip); } } } @@ -476,9 +610,11 @@ } void -file_editor::handle_add_filename_to_list (const QString& fileName) +file_editor::handle_add_filename_to_list (const QString& fileName, QWidget *ID) { - fetFileNames.append (fileName); + // Should we allow multiple tabs for a single file? + + editor_tab_map[fileName] = ID; } void @@ -512,10 +648,12 @@ } void -file_editor::notice_settings () +file_editor::notice_settings (const QSettings *settings) { + int icon_size = settings->value ("toolbar_icon_size",24).toInt (); + _tool_bar->setIconSize (QSize (icon_size,icon_size)); // Relay signal to file editor tabs. - emit fetab_settings_changed (); + emit fetab_settings_changed (settings); } void @@ -544,6 +682,10 @@ = new QAction (QIcon(":/actions/icons/filesaveas.png"), tr("Save File &As"), _tool_bar); + QAction *print_action + = new QAction ( QIcon(":/actions/icons/fileprint.png"), + tr ("Print"), _tool_bar); + QAction *undo_action = new QAction (QIcon(":/actions/icons/undo.png"), tr("&Undo"), _tool_bar); @@ -580,12 +722,14 @@ QAction *comment_selection_action = new QAction (tr ("&Comment Selected Text"),_tool_bar); QAction *uncomment_selection_action = new QAction (tr ("&Uncomment Selected Text"),_tool_bar); - QAction *find_action = new QAction (QIcon(":/actions/icons/find.png"), + QAction *find_action = new QAction (QIcon(":/actions/icons/search.png"), tr ("&Find and Replace"), _tool_bar); _run_action = new QAction (QIcon(":/actions/icons/artsbuilderexecute.png"), tr("Save File And Run"), _tool_bar); + QAction *goto_line_action = new QAction (tr ("Go&to Line"), _tool_bar); + // the mru-list and an empty array of actions QSettings *settings = resource_manager::get_settings (); // FIXME -- what should happen if settings is 0? @@ -605,6 +749,10 @@ save_action->setShortcutContext (Qt::WindowShortcut); save_as_action->setShortcut (QKeySequence::SaveAs); save_as_action->setShortcutContext (Qt::WindowShortcut); + + print_action->setShortcut (QKeySequence::Print); + print_action->setShortcutContext (Qt::WindowShortcut); + next_bookmark_action->setShortcut (Qt::Key_F2); next_bookmark_action->setShortcutContext (Qt::WindowShortcut); previous_bookmark_action->setShortcut (Qt::SHIFT + Qt::Key_F2); @@ -617,6 +765,8 @@ uncomment_selection_action->setShortcutContext(Qt::WindowShortcut); find_action->setShortcut (QKeySequence::Find); find_action->setShortcutContext (Qt::WindowShortcut); + goto_line_action->setShortcut (Qt::ControlModifier+ Qt::Key_G); + goto_line_action->setShortcutContext (Qt::WindowShortcut); // toolbar _tool_bar->addAction (new_action); @@ -624,6 +774,8 @@ _tool_bar->addAction (save_action); _tool_bar->addAction (save_as_action); _tool_bar->addSeparator (); + _tool_bar->addAction(print_action); + _tool_bar->addSeparator (); _tool_bar->addAction (undo_action); _tool_bar->addAction (redo_action); _tool_bar->addAction (_copy_action); @@ -653,6 +805,9 @@ fileMenu->addMenu (_mru_file_menu); _menu_bar->addMenu (fileMenu); + fileMenu->addSeparator (); + fileMenu->addAction (print_action); + QMenu *editMenu = new QMenu (tr ("&Edit"), _menu_bar); editMenu->addAction (undo_action); editMenu->addAction (redo_action); @@ -670,6 +825,8 @@ editMenu->addAction (next_bookmark_action); editMenu->addAction (previous_bookmark_action); editMenu->addAction (remove_bookmark_action); + editMenu->addSeparator (); + editMenu->addAction (goto_line_action); _menu_bar->addMenu (editMenu); _debug_menu = new QMenu (tr ("&Debug"), _menu_bar); @@ -693,6 +850,15 @@ editor_widget->setLayout (vbox_layout); setWidget (editor_widget); + connect (parent (), SIGNAL (settings_changed (const QSettings *)), + this, SLOT (notice_settings (const QSettings *))); + + connect (parent (), SIGNAL (new_file_signal (const QString&)), + this, SLOT (request_new_file (const QString&))); + + connect (parent (), SIGNAL (open_file_signal (const QString&)), + this, SLOT (request_open_file (const QString&))); + connect (new_action, SIGNAL (triggered ()), this, SLOT (request_new_file ())); connect (open_action, @@ -711,6 +877,8 @@ SIGNAL (triggered ()), this, SLOT (request_save_file ())); connect (save_as_action, SIGNAL (triggered ()), this, SLOT (request_save_file_as ())); + connect (print_action, + SIGNAL (triggered ()), this, SLOT (request_print_file ())); connect (_run_action, SIGNAL (triggered ()), this, SLOT (request_run_file ())); connect (toggle_bookmark_action, @@ -735,6 +903,10 @@ SIGNAL (triggered ()), this, SLOT (request_uncomment_selected_text ())); connect (find_action, SIGNAL (triggered ()), this, SLOT (request_find ())); + + connect (goto_line_action, + SIGNAL (triggered ()), this, SLOT (request_goto_line ())); + // The actions of the mru file menu for (int i = 0; i < MaxMRUFiles; ++i) { @@ -772,8 +944,8 @@ this, SLOT (handle_editor_state_changed (bool, const QString&))); connect (f, SIGNAL (tab_remove_request ()), this, SLOT (handle_tab_remove_request ())); - connect (f, SIGNAL (add_filename_to_list (const QString&)), - this, SLOT (handle_add_filename_to_list (const QString&))); + connect (f, SIGNAL (add_filename_to_list (const QString&, QWidget *)), + this, SLOT (handle_add_filename_to_list (const QString&, QWidget *))); connect (f, SIGNAL (editor_check_conflict_save (const QString&, bool)), this, SLOT (check_conflict_save (const QString&, bool))); connect (f, SIGNAL (mru_add_file (const QString&)), @@ -782,8 +954,8 @@ parent (), SLOT (handle_command_double_clicked (const QString&))); // Signals from the file_editor non-trivial operations - connect (this, SIGNAL (fetab_settings_changed ()), - f, SLOT (notice_settings ())); + connect (this, SIGNAL (fetab_settings_changed (const QSettings *)), + f, SLOT (notice_settings (const QSettings *))); connect (this, SIGNAL (fetab_close_request (const QWidget*)), f, SLOT (conditional_close (const QWidget*))); connect (this, SIGNAL (fetab_change_request (const QWidget*)), @@ -807,6 +979,8 @@ f, SLOT (save_file (const QWidget*))); connect (this, SIGNAL (fetab_save_file_as (const QWidget*)), f, SLOT (save_file_as (const QWidget*))); + connect (this, SIGNAL (fetab_print_file (const QWidget*)), + f, SLOT (print_file (const QWidget*))); connect (this, SIGNAL (fetab_run_file (const QWidget*)), f, SLOT (run_file (const QWidget*))); connect (this, SIGNAL (fetab_toggle_bookmark (const QWidget*)), @@ -831,8 +1005,16 @@ f, SLOT (uncomment_selected_text (const QWidget*))); connect (this, SIGNAL (fetab_find (const QWidget*)), f, SLOT (find (const QWidget*))); + connect (this, SIGNAL (fetab_goto_line (const QWidget *, int)), + f, SLOT (goto_line (const QWidget *, int))); connect (this, SIGNAL (fetab_set_focus (const QWidget*)), f, SLOT (set_focus (const QWidget*))); + connect (this, SIGNAL (fetab_insert_debugger_pointer (const QWidget *, int)), + f, SLOT (insert_debugger_pointer (const QWidget *, int))); + connect (this, SIGNAL (fetab_delete_debugger_pointer (const QWidget *, int)), + f, SLOT (delete_debugger_pointer (const QWidget *, int))); + connect (this, SIGNAL (fetab_do_breakpoint_marker (bool, const QWidget *, int)), + f, SLOT (do_breakpoint_marker (bool, const QWidget *, int))); _tab_widget->setCurrentWidget (f); }
--- a/libgui/src/m-editor/file-editor.h +++ b/libgui/src/m-editor/file-editor.h @@ -29,6 +29,9 @@ #include <QStatusBar> #include <QCloseEvent> #include <QTabWidget> +#include <QSettings> + +#include <map> #include "file-editor-interface.h" #include "file-editor-tab.h" @@ -44,9 +47,16 @@ { Q_OBJECT - public: +public: + + typedef std::map<QString, QWidget *>::iterator editor_tab_map_iterator; + typedef std::map<QString, QWidget *>::const_iterator editor_tab_map_const_iterator; + file_editor (QWidget *p); ~file_editor (); + + void connect_visibility_changed (void); + void loadFile (const QString& fileName); QMenu * get_mru_menu ( ) { return _mru_file_menu; } @@ -54,11 +64,11 @@ QToolBar * toolbar (); void set_focus (); - void handle_entered_debug_mode (); - void handle_quit_debug_mode (); + void handle_enter_debug_mode (void); + void handle_exit_debug_mode (void); signals: - void fetab_settings_changed (); + void fetab_settings_changed (const QSettings *settings); void fetab_close_request (const QWidget* ID); void fetab_change_request (const QWidget* ID); void fetab_file_name_query (const QWidget* ID); @@ -73,6 +83,7 @@ void fetab_paste (const QWidget* ID); void fetab_save_file (const QWidget* ID); void fetab_save_file_as (const QWidget* ID); + void fetab_print_file (const QWidget* ID); void fetab_run_file (const QWidget* ID); void fetab_toggle_bookmark (const QWidget* ID); void fetab_next_bookmark (const QWidget* ID); @@ -85,12 +96,20 @@ void fetab_comment_selected_text (const QWidget* ID); void fetab_uncomment_selected_text (const QWidget* ID); void fetab_find (const QWidget* ID); + void fetab_goto_line (const QWidget* ID, int line = -1); + void fetab_insert_debugger_pointer (const QWidget* ID, int line = -1); + void fetab_delete_debugger_pointer (const QWidget* ID, int line = -1); + void fetab_do_breakpoint_marker (bool insert, const QWidget* ID, int line = -1); void fetab_set_focus (const QWidget* ID); public slots: - void request_new_file (); + void focus (void); + void handle_visibility (bool visible); + + void request_new_file (const QString& commands); void request_open_file (); void request_mru_open_file (); + void request_print_file (); void request_undo (); void request_redo (); @@ -114,20 +133,30 @@ void request_uncomment_selected_text (); void request_find (); + void request_goto_line (); + void handle_file_name_changed (const QString& fileName, const QString& toolTip); void handle_tab_close_request (int index); void handle_tab_remove_request (); - void handle_add_filename_to_list (const QString& fileName); + void handle_add_filename_to_list (const QString& fileName, QWidget *ID); void active_tab_changed (int index); void handle_editor_state_changed (bool enableCopy, const QString& fileName); void handle_mru_add_file (const QString& file_name); void check_conflict_save (const QString& fileName, bool remove_on_success); + void handle_insert_debugger_pointer_request (const QString& file, int line); + void handle_delete_debugger_pointer_request (const QString& file, int line); + void handle_update_breakpoint_marker_request (bool insert, const QString& file, + int line); + void handle_edit_file_request (const QString& file); + /** Tells the editor to react on changed settings. */ - void notice_settings (); + void notice_settings (const QSettings *settings); private slots: - void request_open_file (const QString& fileName); + void request_open_file (const QString& fileName, int line = -1, + bool debug_pointer = false, + bool breakpoint_marker = false, bool insert = true); private: void construct (); @@ -135,7 +164,10 @@ void save_file_as (QWidget *fetabID = 0); void mru_menu_update (); - QStringList fetFileNames; + QWidget *find_tab_widget (const QString& openFileName) const; + + std::map<QString, QWidget *> editor_tab_map; + QString ced; QMenuBar * _menu_bar;
--- a/libgui/src/m-editor/find-dialog.cc +++ b/libgui/src/m-editor/find-dialog.cc @@ -1,9 +1,28 @@ /**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** + +Find dialog derived from an example from Qt Toolkit (license below (**)) + +Copyright (C) 2012-2013 Torsten <ttl@justmail.de> +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Nokia Corporation (qt-info@nokia.com) + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ @@ -53,7 +72,7 @@ : QDialog (p) { setWindowTitle ("Find and Replace"); - setWindowIcon (QIcon(":/actions/icons/logo.png")); + setWindowIcon (QIcon(":/actions/icons/search.png")); _search_label = new QLabel (tr ("Find &what:")); _search_line_edit = new QLineEdit; @@ -67,7 +86,7 @@ _wrap_check_box = new QCheckBox (tr ("&Wrap while searching")); _wrap_check_box->setChecked(true); _find_next_button = new QPushButton (tr ("&Find Next")); - _find_next_button->setDefault (true); + _find_prev_button = new QPushButton (tr ("Find &Previous")); _replace_button = new QPushButton (tr ("&Replace")); _replace_all_button = new QPushButton (tr ("Replace &All")); @@ -77,9 +96,11 @@ _button_box = new QDialogButtonBox (Qt::Vertical); _button_box->addButton (_find_next_button, QDialogButtonBox::ActionRole); + _button_box->addButton (_find_prev_button, QDialogButtonBox::ActionRole); _button_box->addButton (_replace_button, QDialogButtonBox::ActionRole); _button_box->addButton (_replace_all_button, QDialogButtonBox::ActionRole); _button_box->addButton (_more_button, QDialogButtonBox::ActionRole); + _button_box->addButton (QDialogButtonBox::Close); _extension = new QWidget (this); _whole_words_check_box = new QCheckBox (tr ("&Whole words")); @@ -91,13 +112,19 @@ _edit_area = edit_area; connect (_find_next_button, SIGNAL (clicked ()), - this, SLOT (search_next ())); + this, SLOT (find_next ())); + connect (_find_prev_button, SIGNAL (clicked ()), + this, SLOT (find_prev ())); connect (_more_button, SIGNAL (toggled (bool)), _extension, SLOT (setVisible (bool))); connect (_replace_button, SIGNAL (clicked ()), this, SLOT (replace ())); connect (_replace_all_button, SIGNAL (clicked ()), this, SLOT (replace_all ())); + connect (_backward_check_box, SIGNAL (stateChanged (int)), + this, SLOT (handle_backward_search_changed (int))); + connect (_button_box, SIGNAL (rejected ()), + this, SLOT (close ())); QVBoxLayout *extension_layout = new QVBoxLayout (); extension_layout->setMargin (0); @@ -124,12 +151,26 @@ main_layout->setSizeConstraint (QLayout::SetFixedSize); main_layout->addLayout (left_layout, 0, 0); main_layout->addWidget (_button_box, 0, 1); - main_layout->addWidget (_extension, 1, 0, 1, 2); + main_layout->addWidget (_extension, 1, 0); setLayout (main_layout); _extension->hide (); + _find_next_button->setDefault (true); + _find_result_available = false; + + move (p->x() + p->frameGeometry ().width (), p->y()); + } +// set text of "search from start" depending on backward search +void +find_dialog::handle_backward_search_changed (int backward) +{ + if (backward) + _from_start_check_box->setText (tr ("Search from end")); + else + _from_start_check_box->setText (tr ("Search from start")); +} // initialize search text with selected text if this is in one single line void @@ -144,17 +185,44 @@ } } +void +find_dialog::find_next () +{ + find (!_backward_check_box->isChecked ()); +} void -find_dialog::search_next () +find_dialog::find_prev () +{ + find (_backward_check_box->isChecked ()); +} + +void +find_dialog::find (bool forward) { int line = -1, col = -1; + bool do_wrap = _wrap_check_box->isChecked (); + bool do_forward = true; + + if (_find_result_available) + { // we found a match last time, cursor is at the end of the match + if (!forward) + { // backward: go back one position or we will find the same again + do_forward = false; + _edit_area->getCursorPosition (&line,&col); + if (col > 0) + _edit_area->setCursorPosition (line,--col); + } + } _find_result_available = false; + if (_from_start_check_box->isChecked ()) { - line = 1; - col = 1; + line = 0; + col = 0; + if (_backward_check_box->isChecked ()) + do_wrap = true; } if (_edit_area) @@ -163,8 +231,8 @@ _regex_check_box->isChecked (), _case_check_box->isChecked (), _whole_words_check_box->isChecked (), - _wrap_check_box->isChecked (), - !_backward_check_box->isChecked (), + do_wrap, + do_forward, line,col, true #ifdef HAVE_FINDFIRST_MODERN @@ -172,6 +240,10 @@ #endif ); } + if (_find_result_available) + _from_start_check_box->setChecked (0); + else + no_matches_message (); } @@ -181,7 +253,8 @@ if (_edit_area) { _edit_area->replace (_replace_line_edit->text ()); - _edit_area->findNext(); + if (!_edit_area->findNext()) + no_matches_message (); } } @@ -206,15 +279,28 @@ // replace all if strings are different if (_edit_area && strDiff ) { - search_next (); // find first occurence + find (!_backward_check_box->isChecked ()); // find first occurence while (_find_result_available) // while search string is found { _edit_area->replace (_replace_line_edit->text ()); // replace count++; // inc counter - _find_result_available = _edit_area->findNext(); // and find next + _find_result_available = _edit_area->findNext(); // and find next } + QMessageBox msg_box (QMessageBox::Information, tr ("Replace Result"), + tr ("%1 items replaced").arg(count), + QMessageBox::Ok, this); + msg_box.exec (); } // TODO: Show number of replaced strings } +void +find_dialog::no_matches_message () +{ + QMessageBox msg_box (QMessageBox::Information, tr ("Find Result"), + tr ("No more matches found"), QMessageBox::Ok, this); + msg_box.exec (); +} + + #endif
--- a/libgui/src/m-editor/find-dialog.h +++ b/libgui/src/m-editor/find-dialog.h @@ -1,9 +1,28 @@ /**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** + +Find dialog derived from an example from Qt Toolkit (license below (**)) + +Copyright (C) 2012-2013 Torsten <ttl@justmail.de> +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Nokia Corporation (qt-info@nokia.com) + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ @@ -60,11 +79,15 @@ void init_search_text (); private slots: - void search_next (); + void handle_backward_search_changed (int); + void find (bool forward = true); + void find_next (); + void find_prev (); void replace (); void replace_all (); private: + void no_matches_message (); QLabel *_search_label; QLineEdit *_search_line_edit; QLabel *_replace_label; @@ -78,6 +101,7 @@ QCheckBox *_backward_check_box; QDialogButtonBox *_button_box; QPushButton *_find_next_button; + QPushButton *_find_prev_button; QPushButton *_replace_button; QPushButton *_replace_all_button; QPushButton *_more_button;
--- a/libgui/src/m-editor/lexer-octave-gui.cc +++ b/libgui/src/m-editor/lexer-octave-gui.cc @@ -41,25 +41,16 @@ // TODO: Also provide infos on octave-forge functions? // TODO: Also provide infos on function parameters? // By now, use the keywords-list from syntax highlighting - QString keyword; QStringList keywordList; - - // get whole string with all keywords - keyword = this->keywords (1); - // split into single strings - keywordList = keyword.split (QRegExp ("\\s+")); - + keyword = this->keywords (1); // get whole string with all keywords + keywordList = keyword.split (QRegExp ("\\s+")); // split into single strings lexer_api = new QsciAPIs (this); if (lexer_api) { - for (int i = 0; i < keywordList.size (); i++) - { - // add single strings to the API - lexer_api->add (keywordList.at (i)); - } - // prepare API info ... this may take some time - lexer_api->prepare (); + for (int i = 0; i < keywordList.size (); i++) // add all keywords to API + lexer_api->add (keywordList.at (i)); + lexer_api->prepare (); // prepare API info ... this may take some time } } @@ -69,6 +60,13 @@ delete lexer_api; } +// ----------------------------------------------------------------------------- +// Redefined functions to make an octave lexer from the abtract class Qscilexer. +// Scintilla has an octave/matlab-lexer but the interface in Qscintilla is +// only available in version 2.5.1. Redefining the following purely virtual +// functions of the class QsciLexer () and the enum of available styles (see +// lexer-octave-gui.h provides the functionality of the octave lexer. +// ----------------------------------------------------------------------------- const char *lexer_octave_gui::language() const { return "Octave"; // return the name of the language @@ -79,101 +77,40 @@ return "octave"; // return the name of the lexer } -// ----------------------------------------------------- -// The colors for syntax highlighting -// ----------------------------------------------------- -QColor lexer_octave_gui::defaultColor(int style) const -{ - switch (style) - { - case Default: // black - return QColor(0x00,0x00,0x00); - case Operator: // red - return QColor(0xef,0x00,0x00); - case Comment: // gray - return QColor(0x7f,0x7f,0x7f); - case Command: // blue-green - return QColor(0x00,0x7f,0x7f); - case Number: // orange - return QColor(0x7f,0x7f,0x00); - case Keyword: // blue - return QColor(0x00,0x00,0xbf); - case SingleQuotedString: // green - return QColor(0x00,0x7f,0x00); - case DoubleQuotedString: // green-yellow - return QColor(0x4f,0x7f,0x00); - } - return QsciLexer::defaultColor(style); -} - - -// ----------------------------------------------------- -// The font decorations for highlighting -// ----------------------------------------------------- -QFont lexer_octave_gui::defaultFont(int style) const -{ - QFont f; - - switch (style) - { - case Comment: // default but italic - f = QsciLexer::defaultFont(style); - f.setItalic(true); - break; - case Keyword: // default - f = QsciLexer::defaultFont(style); - break; - case Operator: // default - f = QsciLexer::defaultFont(style); - break; - default: // default - f = QsciLexer::defaultFont(style); - break; - } - return f; // return the selected font -} - - -// ----------------------------------------------------- -// Style names -// ----------------------------------------------------- QString lexer_octave_gui::description(int style) const { - switch (style) + switch (style) { case Default: - return tr("Default"); + return tr("Default"); case Comment: - return tr("Comment"); + return tr("Comment"); case Command: - return tr("Command"); + return tr("Command"); case Number: - return tr("Number"); + return tr("Number"); case Keyword: - return tr("Keyword"); + return tr("Keyword"); case SingleQuotedString: - return tr("Single-quoted string"); + return tr("Single-quoted string"); case Operator: - return tr("Operator"); + return tr("Operator"); case Identifier: - return tr("Identifier"); + return tr("Identifier"); case DoubleQuotedString: - return tr("Double-quoted string"); + return tr("Double-quoted string"); } - return QString(); + return QString(); // no valid style, return empty string } - // ----------------------------------------------------- // The set of keywords for highlighting -// TODO: How to define a second set? // ----------------------------------------------------- const char *lexer_octave_gui::keywords(int set) const { if (set == 1) - { return resource_manager::octave_keywords (); - } + return 0; }
--- a/libgui/src/m-editor/lexer-octave-gui.h +++ b/libgui/src/m-editor/lexer-octave-gui.h @@ -33,29 +33,27 @@ { Q_OBJECT - public: - // the used styles - enum - { - Default = 0, - Comment = 1, - Command = 2, - Number = 3, - Keyword = 4, - SingleQuotedString = 5, - Operator = 6, - Identifier = 7, - DoubleQuotedString = 8 +public: + + enum { + Default = 0, + Comment = 1, + Command = 2, + Number = 3, + Keyword = 4, + SingleQuotedString = 5, + Operator = 6, + Identifier = 7, + DoubleQuotedString = 8 }; + lexer_octave_gui (QObject *parent = 0); ~lexer_octave_gui (); - const char *language () const; - const char *lexer () const; - QColor defaultColor (int style) const; - QFont defaultFont (int style) const; - const char *keywords (int set) const; - QString description (int style) const; + virtual const char *keywords (int set) const; + virtual const char *lexer () const; + virtual const char *language () const; + QString description(int style) const; private: lexer_octave_gui (const lexer_octave_gui &);
--- a/libgui/src/main-window.cc +++ b/libgui/src/main-window.cc @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -33,128 +34,155 @@ #include <QStyle> #include <QToolBar> #include <QDesktopServices> +#include <QDesktopWidget> #include <QFileDialog> #include <QMessageBox> #include <QIcon> +#include <utility> + +#ifdef HAVE_QSCINTILLA #include "file-editor.h" +#endif #include "main-window.h" -#include "octave-link.h" #include "settings-dialog.h" -#include "builtins.h" +#include "cmd-edit.h" + +#include "builtin-defun-decls.h" #include "defaults.h" -#include "load-save.h" -#include "toplev.h" +#include "symtab.h" #include "version.h" -#include "cmd-hist.h" -#include "oct-env.h" +static file_editor_interface * +create_default_editor (QWidget *p) +{ +#ifdef HAVE_QSCINTILLA + return new file_editor (p); +#else + return 0; +#endif +} main_window::main_window (QWidget *p) - : QMainWindow (p) + : QMainWindow (p), + _workspace_model (new workspace_model ()), + status_bar (new QStatusBar ()), + command_window (new terminal_dock_widget (this)), + history_window (new history_dock_widget (this)), + file_browser_window (new files_dock_widget (this)), + doc_browser_window (new documentation_dock_widget (this)), + editor_window (create_default_editor (this)), + workspace_window (new workspace_view (this)), + find_files_dlg (0), + _octave_main_thread (0), + _octave_qt_link (0) { // We have to set up all our windows, before we finally launch octave. construct (); - octave_link::launch_octave (); } -main_window::~main_window () +main_window::~main_window (void) { - // Clean up all dynamically created objects to ensure they are - // deleted before this main_window is. Otherwise, some will be - // attached to a non-existent parent. - - if (_octave_qt_event_listener) - delete _octave_qt_event_listener; - -#ifdef HAVE_QSCINTILLA - if (_file_editor) - delete _file_editor; -#endif - - if (_terminal_dock_widget) - delete _terminal_dock_widget; + // Destroy the terminal first so that STDERR stream is redirected back + // to its original pipe to capture error messages at exit. - if (_terminal) - delete _terminal; - - if (_status_bar) - delete _status_bar; - - if (_documentation_dock_widget) - delete _documentation_dock_widget; - - if (_files_dock_widget) - delete _files_dock_widget; - - if (_history_dock_widget) - delete _history_dock_widget; - - if (_workspace_view) - delete _workspace_view; + delete command_window; + delete workspace_window; + delete editor_window; + delete doc_browser_window; + delete file_browser_window; + delete history_window; + delete status_bar; + delete _workspace_model; + if (find_files_dlg) + { + delete find_files_dlg; + find_files_dlg = 0; + } + delete _octave_main_thread; + delete _octave_qt_link; } void -main_window::new_file () +main_window::focus_command_window (void) { -#ifdef HAVE_QSCINTILLA - _file_editor->request_new_file (); -#endif + command_window->focus (); } void -main_window::open_file () +main_window::new_file (const QString& commands) { -#ifdef HAVE_QSCINTILLA - _file_editor->request_open_file (); -#endif + emit new_file_signal (commands); } void main_window::open_file (const QString& file_name) { -#ifdef HAVE_QSCINTILLA - _file_editor->request_open_file (file_name); -#endif + emit open_file_signal (file_name); } void main_window::report_status_message (const QString& statusMessage) { - _status_bar->showMessage (statusMessage, 1000); + status_bar->showMessage (statusMessage, 1000); +} + +void +main_window::handle_save_workspace_request (void) +{ + QString file = + QFileDialog::getSaveFileName (this, tr ("Save Workspace As"), "."); + + if (! file.isEmpty ()) + octave_link::post_event (this, &main_window::save_workspace_callback, + file.toStdString ()); } void -main_window::handle_save_workspace_request () +main_window::handle_load_workspace_request (const QString& file_arg) { - QString selectedFile = - QFileDialog::getSaveFileName (this, tr ("Save Workspace As"), - resource_manager::get_home_path ()); - if (!selectedFile.isEmpty ()) - octave_link::post_event (this, &main_window::save_workspace_callback, - selectedFile.toStdString ()); + QString file = file_arg; + + if (file.isEmpty ()) + file = QFileDialog::getOpenFileName (this, tr ("Load Workspace"), "."); + + if (! file.isEmpty ()) + octave_link::post_event (this, &main_window::load_workspace_callback, + file.toStdString ()); } void -main_window::handle_load_workspace_request () -{ - QString selectedFile = - QFileDialog::getOpenFileName (this, tr ("Load Workspace"), - resource_manager::get_home_path ()); - if (!selectedFile.isEmpty ()) - octave_link::post_event (this, &main_window::load_workspace_callback, - selectedFile.toStdString ()); -} - -void -main_window::handle_clear_workspace_request () +main_window::handle_clear_workspace_request (void) { octave_link::post_event (this, &main_window::clear_workspace_callback); } void -main_window::handle_clear_history_request() +main_window::handle_rename_variable_request (const QString& old_name, + const QString& new_name) + +{ + name_pair names (old_name.toStdString (), new_name.toStdString ()); + + octave_link::post_event (this, &main_window::rename_variable_callback, + names); +} + +void +main_window::handle_undo_request (void) +{ + octave_link::post_event (this, &main_window::command_window_undo_callback); +} + +void +main_window::handle_clear_command_window_request (void) +{ + octave_link::post_event (this, &main_window::clear_command_window_callback); +} + +void +main_window::handle_clear_history_request (void) { octave_link::post_event (this, &main_window::clear_history_callback); } @@ -162,79 +190,66 @@ void main_window::handle_command_double_clicked (const QString& command) { - _terminal->sendText (command); - focus_command_window (); + emit relay_command_signal (command); + + command_window->focus (); } void -main_window::open_online_documentation_page () +main_window::open_online_documentation_page (void) { QDesktopServices::openUrl (QUrl ("http://gnu.org/software/octave/doc/interpreter")); } void -main_window::open_bug_tracker_page () +main_window::open_bug_tracker_page (void) { QDesktopServices::openUrl (QUrl ("http://bugs.octave.org")); } void -main_window::open_octave_forge_page () +main_window::open_octave_forge_page (void) { QDesktopServices::openUrl (QUrl ("http://octave.sourceforge.net/")); } void -main_window::open_agora_page () +main_window::open_agora_page (void) { QDesktopServices::openUrl (QUrl ("http://agora.octave.org/")); } void -main_window::process_settings_dialog_request () +main_window::process_settings_dialog_request (void) { settings_dialog *settingsDialog = new settings_dialog (this); int change_settings = settingsDialog->exec (); if (change_settings == QDialog::Accepted) { settingsDialog->write_changed_settings (); - emit settings_changed (); + QSettings *settings = resource_manager::get_settings (); + if (settings) + emit settings_changed (settings); } delete settingsDialog; } void -main_window::notice_settings () +main_window::notice_settings (const QSettings *settings) { - QSettings *settings = resource_manager::get_settings (); - - // FIXME -- what should happen if settings is 0? - - // Set terminal font: - QFont term_font = QFont(); - term_font.setFamily(settings->value("terminal/fontName").toString()); - term_font.setPointSize(settings->value("terminal/fontSize").toInt ()); - _terminal->setTerminalFont (term_font); - - QString cursorType = settings->value ("terminal/cursorType").toString (); - bool cursorBlinking = settings->value ("terminal/cursorBlinking").toBool (); - if (cursorType == "ibeam") - _terminal->setCursorType(QTerminalInterface::IBeamCursor, cursorBlinking); - else if (cursorType == "block") - _terminal->setCursorType(QTerminalInterface::BlockCursor, cursorBlinking); - else if (cursorType == "underline") - _terminal->setCursorType(QTerminalInterface::UnderlineCursor, - cursorBlinking); + // QSettings pointer is checked before emitting. // the widget's icons (when floating) - QString icon_set = settings->value ("DockWidgets/widget_icon_set","NONE"). - toString (); + QString icon_set + = settings->value ("DockWidgets/widget_icon_set", "NONE").toString (); + static struct { QString name; QString path; } + widget_icon_data[] = { // array of possible icon sets (name, path (complete for NONE)) // the first entry here is the default! @@ -243,8 +258,10 @@ {"LETTER", ":/actions/icons/letter_logo_"}, {"", ""} // end marker has empty name }; + int count = 0; int icon_set_found = 0; // default + while (!widget_icon_data[count].name.isEmpty ()) { // while not end of data if (widget_icon_data[count].name == icon_set) @@ -254,12 +271,13 @@ } count++; } + QString icon; foreach (QObject *obj, children ()) { QString name = obj->objectName (); - if (obj->inherits("QDockWidget") && ! name.isEmpty ()) - { // if children is a dockwidget with a name + if (obj->inherits ("QDockWidget") && ! name.isEmpty ()) + { // if children is a dock widget with a name QDockWidget *widget = qobject_cast<QDockWidget *> (obj); icon = widget_icon_data[icon_set_found].path; // prefix or octave-logo if (widget_icon_data[icon_set_found].name != "NONE") @@ -268,267 +286,164 @@ } } + int icon_size = settings->value ("toolbar_icon_size",24).toInt (); + _main_tool_bar->setIconSize (QSize (icon_size,icon_size)); + resource_manager::update_network_settings (); } void -main_window::prepare_for_quit () +main_window::prepare_to_exit (void) { write_settings (); } void +main_window::exit (int status) +{ + qApp->exit (status); +} + +void main_window::reset_windows () { // TODO: Implement. } void -main_window::current_working_directory_has_changed (const QString& directory) +main_window::change_directory (const QString& dir) { - int index = _current_directory_combo_box->findText (directory); - if ( index >= 0 ) // directory already in list -> remove it - { - _current_directory_combo_box->removeItem (index); - } - _current_directory_combo_box->insertItem (0,directory); // add (on top) - _current_directory_combo_box->setCurrentIndex (0); // top is actual - _files_dock_widget->set_current_directory (directory); + // Remove existing entry, if any, then add new directory at top and + // mark it as the current directory. Finally, update the file list + // widget. + + int index = _current_directory_combo_box->findText (dir); + + if (index >= 0) + _current_directory_combo_box->removeItem (index); + + _current_directory_combo_box->insertItem (0, dir); + _current_directory_combo_box->setCurrentIndex (0); + + file_browser_window->update_octave_directory (dir); } void -main_window::change_current_working_directory () +main_window::browse_for_directory (void) { - QString directory = - QFileDialog::getExistingDirectory(this, tr ("Set working direcotry")); + QString dir = + QFileDialog::getExistingDirectory (this, tr ("Set working directory")); - if (!directory.isEmpty ()) - { - std::string dir = directory.toUtf8 ().data (); - octave_link::post_event (this, &main_window::change_directory_callback,dir); - } + if (! dir.isEmpty ()) + octave_link::post_event (this, + &main_window::change_directory_callback, + dir.toStdString ()); } void -main_window::set_current_working_directory (const QString& directory) +main_window::set_current_working_directory (const QString& dir) { - QFileInfo fileInfo (directory); // check whether this is an existing dir - if (fileInfo.exists () && fileInfo.isDir ()) // is dir and exists - { - std::string dir = directory.toUtf8 ().data (); - octave_link::post_event (this, &main_window::change_directory_callback,dir); - } + // Change to dir if it is an existing directory. + + QString xdir = dir.isEmpty () ? "." : dir; + + QFileInfo fileInfo (xdir); + + if (fileInfo.exists () && fileInfo.isDir ()) + octave_link::post_event (this, &main_window::change_directory_callback, + xdir.toStdString ()); } void -main_window::current_working_directory_up () +main_window::change_directory_up (void) { set_current_working_directory (".."); } -// Slot that is called if return is pressed in the line edit of the combobox -// -> a new or a directory that is already in the drop down list was entered -void -main_window::current_working_directory_entered () -{ - QString dir = _current_directory_line_edit->text (); // get new directory - int index = _current_directory_combo_box->findText (dir); // already in list? - if ( index < 0 ) // directory not yet in list -> set directory - set_current_working_directory (dir); - // if directory already in list, combobox triggers signal activated () - // to change directory -} +// Slot that is called if return is pressed in the line edit of the +// combobox to change to a new directory or a directory that is already +// in the drop down list. void -main_window::focus_command_window () -{ - if (!_terminal_dock_widget->isVisible ()) - { - _terminal_dock_widget->setVisible (true); - } - - _terminal_dock_widget->setFocus (); - _terminal_dock_widget->activateWindow (); - _terminal_dock_widget->raise (); - - _terminal->setFocus (); - _terminal->activateWindow (); - _terminal->raise (); -} - -void -main_window::focus_command_history () +main_window::accept_directory_line_edit (void) { - if (!_history_dock_widget->isVisible ()) - { - _history_dock_widget->setVisible (true); - } - - _history_dock_widget->setFocus (); - _history_dock_widget->activateWindow (); - _history_dock_widget->raise (); -} + // Get new directory name, and change to it if it is new. Otherwise, + // the combo box will triggers the "activated" signal to change to the + // directory. -void -main_window::focus_current_directory () -{ - if (!_files_dock_widget->isVisible ()) - { - _files_dock_widget->setVisible (true); - } + QString dir = _current_directory_combo_box->currentText (); - _files_dock_widget->setFocus (); - _files_dock_widget->activateWindow (); - _files_dock_widget->raise (); + int index = _current_directory_combo_box->findText (dir); + + if (index < 0) + set_current_working_directory (dir); } void -main_window::focus_workspace () -{ - if (!_workspace_view->isVisible ()) - { - _workspace_view->setVisible (true); - } - - _workspace_view->setFocus (); - _workspace_view->activateWindow (); - _workspace_view->raise (); -} - - -void -main_window::focus_editor () -{ -#ifdef HAVE_QSCINTILLA - // call own function of editor in order to set focus to the current editor tab - _file_editor->set_focus (); -#endif -} - -void -main_window::focus_documentation () -{ - if (!_documentation_dock_widget->isVisible ()) - { - _documentation_dock_widget->setVisible (true); - } - - _documentation_dock_widget->setFocus (); - _documentation_dock_widget->activateWindow (); - _documentation_dock_widget->raise (); -} - -void -main_window::handle_command_window_visible (bool visible) -{ - // if widget is changed to visible and is not floating - if (visible && !_terminal_dock_widget->isFloating ()) - focus_command_window (); -} - -void -main_window::handle_command_history_visible (bool visible) -{ - // if changed to visible and widget is not floating - if (visible && !_history_dock_widget->isFloating ()) - focus_command_history (); -} - -void -main_window::handle_current_directory_visible (bool visible) -{ - // if changed to visible and widget is not floating - if (visible && !_files_dock_widget->isFloating ()) - focus_current_directory (); -} - -void -main_window::handle_workspace_visible (bool visible) -{ - // if changed to visible and widget is not floating - if (visible && !_workspace_view->isFloating ()) - focus_workspace (); -} - -void -main_window::handle_editor_visible (bool visible) -{ - // if changed to visible and widget is not floating -#ifdef HAVE_QSCINTILLA - if (visible && !_file_editor->isFloating ()) - focus_editor (); -#endif -} - -void -main_window::handle_documentation_visible (bool visible) -{ - // if changed to visible and widget is not floating - if (visible && !_documentation_dock_widget->isFloating ()) - focus_documentation (); -} - -void -main_window::handle_entered_debug_mode () +main_window::handle_enter_debugger (void) { setWindowTitle ("Octave (Debugging)"); + _debug_continue->setEnabled (true); _debug_step_into->setEnabled (true); _debug_step_over->setEnabled (true); _debug_step_out->setEnabled (true); _debug_quit->setEnabled (true); + #ifdef HAVE_QSCINTILLA - _file_editor->handle_entered_debug_mode (); + editor_window->handle_enter_debug_mode (); #endif } void -main_window::handle_quit_debug_mode () +main_window::handle_exit_debugger (void) { setWindowTitle ("Octave"); + _debug_continue->setEnabled (false); _debug_step_into->setEnabled (false); _debug_step_over->setEnabled (false); _debug_step_out->setEnabled (false); _debug_quit->setEnabled (false); + #ifdef HAVE_QSCINTILLA - _file_editor->handle_quit_debug_mode (); + editor_window->handle_exit_debug_mode (); #endif } void -main_window::debug_continue () +main_window::debug_continue (void) { octave_link::post_event (this, &main_window::debug_continue_callback); } void -main_window::debug_step_into () +main_window::debug_step_into (void) { octave_link::post_event (this, &main_window::debug_step_into_callback); } void -main_window::debug_step_over () +main_window::debug_step_over (void) { octave_link::post_event (this, &main_window::debug_step_over_callback); } void -main_window::debug_step_out () +main_window::debug_step_out (void) { octave_link::post_event (this, &main_window::debug_step_out_callback); } void -main_window::debug_quit () +main_window::debug_quit (void) { octave_link::post_event (this, &main_window::debug_quit_callback); } void -main_window::show_about_octave () +main_window::show_about_octave (void) { QString message = OCTAVE_STARTUP_MESSAGE; @@ -543,11 +458,14 @@ } void -main_window::read_settings () +main_window::read_settings (void) { QSettings *settings = resource_manager::get_settings (); - - // FIXME -- what should happen if settings is 0? + if (!settings) + { + qDebug("Error: QSettings pointer from resource manager is NULL."); + return; + } restoreState (settings->value ("MainWindow/windowState").toByteArray ()); settings->beginGroup ("DockWidgets"); @@ -555,13 +473,13 @@ foreach (QObject *obj, children ()) { QString name = obj->objectName (); - if (obj->inherits("QDockWidget") && ! name.isEmpty ()) + if (obj->inherits ("QDockWidget") && ! name.isEmpty ()) { QDockWidget *widget = qobject_cast<QDockWidget *> (obj); QVariant val = settings->value (name); widget->restoreGeometry (val.toByteArray ()); - bool floating = settings->value (name+"Floating",false).toBool (); - bool visible = settings->value (name+"Visible",true).toBool (); + bool floating = settings->value (name+"Floating", false).toBool (); + bool visible = settings->value (name+"Visible", true).toBool (); if (floating) widget->setWindowFlags (Qt::Window); // if floating, make window from widget widget->setVisible (visible); // make widget visible if desired (setWindowFlags hides widget) @@ -575,15 +493,18 @@ { _current_directory_combo_box->addItem (curr_dirs.at (i)); } - emit settings_changed (); + emit settings_changed (settings); } void -main_window::write_settings () +main_window::write_settings (void) { QSettings *settings = resource_manager::get_settings (); - - // FIXME -- what should happen if settings is 0? + if (!settings) + { + qDebug("Error: QSettings pointer from resource manager is NULL."); + return; + } settings->setValue ("MainWindow/geometry", saveGeometry ()); settings->beginGroup ("DockWidgets"); @@ -597,10 +518,10 @@ settings->setValue (name, widget->saveGeometry ()); bool floating = widget->isFloating (); bool visible = widget->isVisible (); - settings->setValue (name+"Floating",floating); // store floating state - settings->setValue (name+"Visible",visible); // store visibility + settings->setValue (name+"Floating", floating); // store floating state + settings->setValue (name+"Visible", visible); // store visibility if (floating) - widget->setWindowFlags(Qt::Widget); // if floating, recover the widget state such that the widget's + widget->setWindowFlags (Qt::Widget); // if floating, recover the widget state such that the widget's } // state is correctly saved by the saveSate () below } settings->endGroup(); @@ -611,7 +532,7 @@ { curr_dirs.append (_current_directory_combo_box->itemText (i)); } - settings->setValue ("MainWindow/current_directory_list",curr_dirs); + settings->setValue ("MainWindow/current_directory_list", curr_dirs); settings->sync (); } @@ -619,68 +540,148 @@ // Connecting the signals emitted when the visibility of a widget changes. // This has to be done after the window is shown (see octave-gui.cc) void -main_window::connect_visibility_changed () +main_window::connect_visibility_changed (void) +{ + command_window->connect_visibility_changed (); + history_window->connect_visibility_changed (); + file_browser_window->connect_visibility_changed (); + doc_browser_window->connect_visibility_changed (); +#ifdef HAVE_QSCINTILLA + editor_window->connect_visibility_changed (); +#endif + workspace_window->connect_visibility_changed (); +} + +// Connect the signals emitted when the Octave thread wants to create +// a dialog box of some sort. Perhaps a better place for this would be +// as part of the QUIWidgetCreator class. However, mainWindow currently +// is not a global variable and not accessible for connecting. + +void +main_window::connect_uiwidget_links () { - connect (_terminal_dock_widget, SIGNAL (visibilityChanged (bool)), - this, SLOT (handle_command_window_visible (bool))); - connect (_workspace_view, SIGNAL (visibilityChanged (bool)), - this, SLOT (handle_workspace_visible (bool))); - connect (_history_dock_widget, SIGNAL (visibilityChanged (bool)), - this, SLOT (handle_command_history_visible (bool))); - connect (_files_dock_widget, SIGNAL (visibilityChanged (bool)), - this, SLOT (handle_current_directory_visible (bool))); -#ifdef HAVE_QSCINTILLA - connect (_file_editor, SIGNAL (visibilityChanged (bool)), - this, SLOT (handle_editor_visible (bool))); -#endif - connect (_documentation_dock_widget, SIGNAL (visibilityChanged (bool)), - this, SLOT (handle_documentation_visible (bool))); + connect (&uiwidget_creator, + SIGNAL (create_dialog (const QString&, const QString&, + const QString&, const QStringList&, + const QString&, const QStringList&)), + this, + SLOT (handle_create_dialog (const QString&, const QString&, + const QString&, const QStringList&, + const QString&, const QStringList&))); + + // Register QIntList so that list of ints may be part of a signal. + qRegisterMetaType<QIntList> ("QIntList"); + connect (&uiwidget_creator, + SIGNAL (create_listview (const QStringList&, const QString&, + int, int, const QIntList&, + const QString&, const QStringList&, + const QString&, const QString&)), + this, + SLOT (handle_create_listview (const QStringList&, const QString&, + int, int, const QIntList&, + const QString&, const QStringList&, + const QString&, const QString&))); + + // Register QFloatList so that list of floats may be part of a signal. + qRegisterMetaType<QFloatList> ("QFloatList"); + connect (&uiwidget_creator, + SIGNAL (create_inputlayout (const QStringList&, const QString&, + const QFloatList&, const QFloatList&, + const QStringList&)), + this, + SLOT (handle_create_inputlayout (const QStringList&, const QString&, + const QFloatList&, const QFloatList&, + const QStringList&))); + + connect (&uiwidget_creator, + SIGNAL (create_debug_cd_or_addpath_dialog (const QString&, + const QString&, bool)), + this, + SLOT (handle_create_debug_cd_or_addpath_dialog (const QString&, + const QString&, + bool))); } +// Create a message dialog with specified string, buttons and decorative +// text. + +void +main_window::handle_create_dialog (const QString& message, + const QString& title, + const QString& icon, + const QStringList& button, + const QString& defbutton, + const QStringList& role) +{ + MessageDialog *message_dialog = new MessageDialog (message, title, icon, + button, defbutton, role); + message_dialog->setAttribute (Qt::WA_DeleteOnClose); + message_dialog->show (); +} + +// Create a list dialog with specified list, initially selected, mode, +// view size and decorative text. + +void +main_window::handle_create_listview (const QStringList& list, + const QString& mode, + int wd, int ht, + const QIntList& initial, + const QString& name, + const QStringList& prompt, + const QString& ok_string, + const QString& cancel_string) +{ + ListDialog *list_dialog = new ListDialog (list, mode, wd, ht, + initial, name, prompt, + ok_string, cancel_string); + + list_dialog->setAttribute (Qt::WA_DeleteOnClose); + list_dialog->show (); +} + +// Create an input dialog with specified prompts and defaults, title and +// row/column size specifications. +void +main_window::handle_create_inputlayout (const QStringList& prompt, + const QString& title, + const QFloatList& nr, + const QFloatList& nc, + const QStringList& defaults) +{ + InputDialog *input_dialog = new InputDialog (prompt, title, nr, nc, + defaults); + + input_dialog->setAttribute (Qt::WA_DeleteOnClose); + input_dialog->show (); +} + +void +main_window::handle_create_debug_cd_or_addpath_dialog (const QString& file, + const QString& dir, + bool addpath_option) + +{ + cd_or_addpath_dialog *dialog + = new cd_or_addpath_dialog (file, dir, addpath_option); + + dialog->setAttribute (Qt::WA_DeleteOnClose); + dialog->show (); +} // Main subroutine of the constructor void -main_window::construct () +main_window::construct (void) { _closing = false; // flag for editor files when closed - setWindowIcon (QIcon(":/actions/icons/logo.png")); - - // Setup dockable widgets and the status bar. - _workspace_view = new workspace_view (this); - _workspace_view->setStatusTip (tr ("View the variables in the active workspace.")); - _history_dock_widget = new history_dock_widget (this); - _history_dock_widget->setStatusTip (tr ("Browse and search the command history.")); - _files_dock_widget = new files_dock_widget (this); - _files_dock_widget->setStatusTip (tr ("Browse your files.")); - _documentation_dock_widget= new documentation_dock_widget (this); - _documentation_dock_widget->setStatusTip (tr ("See the documentation for help.")); - _status_bar = new QStatusBar (this); + setWindowIcon (QIcon (":/actions/icons/logo.png")); - _current_directory_line_edit = new QLineEdit (this); - _current_directory_combo_box = new QComboBox (this); - _current_directory_combo_box->setFixedWidth (current_directory_width); - _current_directory_combo_box->setEditable (true); - // setLineEdit takes ownership -> no need to delete line_edit in ~main_window - _current_directory_combo_box->setLineEdit (_current_directory_line_edit); - _current_directory_combo_box->setInsertPolicy (QComboBox::InsertAtTop); - _current_directory_combo_box->setMaxVisibleItems (current_directory_max_visible); - _current_directory_combo_box->setMaxCount (current_directory_max_count); - - QToolButton *current_directory_tool_button = new QToolButton (this); - current_directory_tool_button->setIcon (QIcon(":/actions/icons/search.png")); - - QToolButton *current_directory_up_tool_button = new QToolButton (this); - current_directory_up_tool_button->setIcon (QIcon(":/actions/icons/up.png")); - - // Octave Terminal subwindow. - _terminal = new QTerminal (this); - _terminal->setObjectName ("OctaveTerminal"); - _terminal->setFocusPolicy (Qt::StrongFocus); - _terminal_dock_widget = new terminal_dock_widget (_terminal, this); + workspace_window->setModel (_workspace_model); // Create and set the central widget. QMainWindow takes ownership of // the widget (pointer) so there is no need to delete the object upon // destroying this main_window. + QWidget *dummyWidget = new QWidget (); dummyWidget->setObjectName ("CentralDummyWidget"); dummyWidget->resize (10, 10); @@ -688,47 +689,178 @@ dummyWidget->hide (); setCentralWidget (dummyWidget); + construct_menu_bar (); + + construct_tool_bar (); + + connect (qApp, SIGNAL (aboutToQuit ()), + this, SLOT (prepare_to_exit ())); + + connect (this, SIGNAL (settings_changed (const QSettings *)), + this, SLOT (notice_settings (const QSettings *))); + + connect (file_browser_window, SIGNAL (load_file_signal (const QString&)), + this, SLOT (handle_load_workspace_request (const QString&))); + + connect_uiwidget_links (); + + setWindowTitle ("Octave"); + + setDockOptions (QMainWindow::AnimatedDocks + | QMainWindow::AllowNestedDocks + | QMainWindow::AllowTabbedDocks); + + addDockWidget (Qt::RightDockWidgetArea, command_window); + addDockWidget (Qt::RightDockWidgetArea, doc_browser_window); + tabifyDockWidget (command_window, doc_browser_window); + #ifdef HAVE_QSCINTILLA - _file_editor = new file_editor (this); + addDockWidget (Qt::RightDockWidgetArea, editor_window); + tabifyDockWidget (command_window, editor_window); #endif - QMenu *file_menu = menuBar ()->addMenu (tr ("&File")); + addDockWidget (Qt::LeftDockWidgetArea, file_browser_window); + addDockWidget (Qt::LeftDockWidgetArea, workspace_window); + addDockWidget (Qt::LeftDockWidgetArea, history_window); + + int win_x = QApplication::desktop()->width(); + int win_y = QApplication::desktop()->height(); + + if (win_x > 960) + win_x = 960; + + if (win_y > 720) + win_y = 720; + + setGeometry (0, 0, win_x, win_y); - QMenu *new_menu = file_menu->addMenu(tr ("New")); + setStatusBar (status_bar); + + construct_octave_qt_link (); + + QDir curr_dir; + set_current_working_directory (curr_dir.absolutePath ()); + + octave_link::post_event (this, &main_window::resize_command_window_callback); +} + +void +main_window::construct_octave_qt_link (void) +{ + _octave_main_thread = new octave_main_thread (); + + _octave_qt_link = new octave_qt_link (_octave_main_thread); - QAction *new_script_action - = new_menu->addAction (QIcon(":/actions/icons/filenew.png"), tr ("Script")); - new_script_action->setShortcut (QKeySequence::New); - new_script_action->setShortcutContext (Qt::ApplicationShortcut); + connect (_octave_qt_link, SIGNAL (exit_signal (int)), + this, SLOT (exit (int))); + + connect (_octave_qt_link, + SIGNAL (set_workspace_signal + (bool, const QString&, const QStringList&, + const QStringList&, const QStringList&, + const QStringList&)), + _workspace_model, + SLOT (set_workspace + (bool, const QString&, const QStringList&, + const QStringList&, const QStringList&, + const QStringList&))); + + connect (_octave_qt_link, SIGNAL (clear_workspace_signal ()), + _workspace_model, SLOT (clear_workspace ())); + + connect (_octave_qt_link, SIGNAL (change_directory_signal (QString)), + this, SLOT (change_directory (QString))); + + connect (_octave_qt_link, + SIGNAL (set_history_signal (const QStringList&)), + history_window, SLOT (set_history (const QStringList&))); + + connect (_octave_qt_link, + SIGNAL (append_history_signal (const QString&)), + history_window, SLOT (append_history (const QString&))); + + connect (_octave_qt_link, + SIGNAL (clear_history_signal (void)), + history_window, SLOT (clear_history (void))); + + connect (_octave_qt_link, SIGNAL (enter_debugger_signal ()), + this, SLOT (handle_enter_debugger ())); - QAction *new_function_action = new_menu->addAction (tr ("Function")); - new_function_action->setEnabled (false); // TODO: Make this work. - QAction *new_class_action = new_menu->addAction (tr ("Class")); - new_class_action->setEnabled (false); // TODO: Make this work. - QAction *new_enumeration_action = new_menu->addAction (tr ("Enumeration")); - new_enumeration_action->setEnabled (false); // TODO: Make this work. - QAction *new_figure_action = new_menu->addAction (tr ("Figure")); - new_figure_action->setEnabled (false); // TODO: Make this work. - QAction *new_variable_action = new_menu->addAction (tr ("Variable")); - new_variable_action->setEnabled (false); // TODO: Make this work. - QAction *new_model_action = new_menu->addAction (tr ("Model")); - new_model_action->setEnabled (false); // TODO: Make this work. - QAction *new_gui_action = new_menu->addAction (tr ("GUI")); - new_gui_action->setEnabled (false); // TODO: Make this work. + connect (_octave_qt_link, SIGNAL (exit_debugger_signal ()), + this, SLOT (handle_exit_debugger ())); + + connect (_octave_qt_link, + SIGNAL (update_breakpoint_marker_signal (bool, const QString&, int)), + editor_window, + SLOT (handle_update_breakpoint_marker_request (bool, const QString&, int))); + + connect (_octave_qt_link, + SIGNAL (edit_file_signal (const QString&)), + editor_window, + SLOT (handle_edit_file_request (const QString&))); + + connect (_octave_qt_link, + SIGNAL (insert_debugger_pointer_signal (const QString&, int)), + editor_window, + SLOT (handle_insert_debugger_pointer_request (const QString&, int))); + + connect (_octave_qt_link, + SIGNAL (delete_debugger_pointer_signal (const QString&, int)), + editor_window, + SLOT (handle_delete_debugger_pointer_request (const QString&, int))); + + connect (_workspace_model, + SIGNAL (rename_variable (const QString&, const QString&)), + this, + SLOT (handle_rename_variable_request (const QString&, + const QString&))); + + _octave_qt_link->execute_interpreter (); + + octave_link::connect_link (_octave_qt_link); +} - QAction *open_action - = file_menu->addAction (QIcon(":/actions/icons/fileopen.png"), tr ("Open...")); - open_action->setShortcut (QKeySequence::Open); - open_action->setShortcutContext (Qt::ApplicationShortcut); +void +main_window::construct_menu_bar (void) +{ + QMenuBar *menu_bar = menuBar (); + + construct_file_menu (menu_bar); + + construct_edit_menu (menu_bar); + + construct_debug_menu (menu_bar); + + construct_desktop_menu (menu_bar); + + construct_window_menu (menu_bar); - file_menu->addMenu(_file_editor->get_mru_menu ()); + construct_help_menu (menu_bar); +} + +void +main_window::construct_file_menu (QMenuBar *p) +{ + QMenu *file_menu = p->addMenu (tr ("&File")); + + construct_new_menu (file_menu); + + _open_action + = file_menu->addAction (QIcon (":/actions/icons/fileopen.png"), + tr ("Open...")); + _open_action->setShortcut (QKeySequence::Open); + _open_action->setShortcutContext (Qt::ApplicationShortcut); + +#ifdef HAVE_QSCINTILLA + file_menu->addMenu (editor_window->get_mru_menu ()); +#endif QAction *close_command_window_action = file_menu->addAction (tr ("Close Command Window")); close_command_window_action->setShortcut (QKeySequence::Close); close_command_window_action->setEnabled (false); // TODO: Make this work. - file_menu->addSeparator (); ///// + file_menu->addSeparator (); QAction *import_data_action = file_menu->addAction (tr ("Import Data")); @@ -737,398 +869,466 @@ QAction *save_workspace_action = file_menu->addAction (tr ("Save Workspace As")); - file_menu->addSeparator (); ///// + file_menu->addSeparator (); QAction *preferences_action - = file_menu->addAction (QIcon(":/actions/icons/configure.png"), + = file_menu->addAction (QIcon (":/actions/icons/configure.png"), tr ("Preferences...")); - file_menu->addSeparator (); ///// + file_menu->addSeparator (); QAction *page_setup_action = file_menu->addAction (tr ("Page Setup...")); page_setup_action->setEnabled (false); // TODO: Make this work. + QAction *print_action = file_menu->addAction (tr ("Print")); print_action->setShortcut (QKeySequence::Print); print_action->setEnabled (false); // TODO: Make this work. + QAction *print_selection_action = file_menu->addAction (tr ("Print Selection...")); print_selection_action->setEnabled (false); // TODO: Make this work. - file_menu->addSeparator (); ///// + file_menu->addSeparator (); QAction *exit_action = file_menu->addAction (tr ("Exit")); exit_action->setShortcut (QKeySequence::Quit); + connect (preferences_action, SIGNAL (triggered ()), + this, SLOT (process_settings_dialog_request ())); - QMenu *edit_menu = menuBar ()->addMenu (tr ("&Edit")); - QAction *undo_action - = edit_menu->addAction (QIcon(":/actions/icons/undo.png"), tr ("Undo")); - undo_action->setShortcut (QKeySequence::Undo); + connect (_open_action, SIGNAL (triggered ()), + editor_window, SLOT (request_open_file ())); + + connect (save_workspace_action, SIGNAL (triggered ()), + this, SLOT (handle_save_workspace_request ())); + + connect (exit_action, SIGNAL (triggered ()), + this, SLOT (close ())); +} - QAction *redo_action - = edit_menu->addAction (QIcon(":/actions/icons/redo.png"), tr ("Redo")); - redo_action->setShortcut (QKeySequence::Redo); +void +main_window::construct_new_menu (QMenu *p) +{ + QMenu *new_menu = p->addMenu (tr ("New")); + + _new_script_action + = new_menu->addAction (QIcon (":/actions/icons/filenew.png"), tr ("Script")); + _new_script_action->setShortcut (QKeySequence::New); + _new_script_action->setShortcutContext (Qt::ApplicationShortcut); - edit_menu->addSeparator (); ///// + QAction *new_function_action = new_menu->addAction (tr ("Function")); + new_function_action->setEnabled (false); // TODO: Make this work. + + QAction *new_class_action = new_menu->addAction (tr ("Class")); + new_class_action->setEnabled (false); // TODO: Make this work. + + QAction *new_enumeration_action = new_menu->addAction (tr ("Enumeration")); + new_enumeration_action->setEnabled (false); // TODO: Make this work. + + QAction *new_figure_action = new_menu->addAction (tr ("Figure")); + new_figure_action->setEnabled (false); // TODO: Make this work. - QAction *cut_action - = edit_menu->addAction (QIcon(":/actions/icons/editcut.png"), tr ("Cut")); - cut_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier + Qt::Key_X); + QAction *new_variable_action = new_menu->addAction (tr ("Variable")); + new_variable_action->setEnabled (false); // TODO: Make this work. + + QAction *new_model_action = new_menu->addAction (tr ("Model")); + new_model_action->setEnabled (false); // TODO: Make this work. + + QAction *new_gui_action = new_menu->addAction (tr ("GUI")); + new_gui_action->setEnabled (false); // TODO: Make this work. + + connect (_new_script_action, SIGNAL (triggered ()), + editor_window, SLOT (request_new_file ())); +} + +void +main_window::construct_edit_menu (QMenuBar *p) +{ + QMenu *edit_menu = p->addMenu (tr ("&Edit")); - QAction *copy_action - = edit_menu->addAction (QIcon(":/actions/icons/editcopy.png"), tr ("Copy")); - copy_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier + Qt::Key_C); + QKeySequence ctrl_shift = Qt::ControlModifier + Qt::ShiftModifier; + + _undo_action + = edit_menu->addAction (QIcon (":/actions/icons/undo.png"), tr ("Undo")); + _undo_action->setShortcut (QKeySequence::Undo); + + edit_menu->addSeparator (); - QAction *paste_action - = edit_menu->addAction (QIcon(":/actions/icons/editpaste.png"), tr ("Paste")); - paste_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier + Qt::Key_V); + _cut_action + = edit_menu->addAction (QIcon (":/actions/icons/editcut.png"), tr ("Cut")); + _cut_action->setShortcut (ctrl_shift + Qt::Key_X); + + _copy_action + = edit_menu->addAction (QIcon (":/actions/icons/editcopy.png"), tr ("Copy")); + _copy_action->setShortcut (ctrl_shift + Qt::Key_C); + + _paste_action + = edit_menu->addAction (QIcon (":/actions/icons/editpaste.png"), tr ("Paste")); + _paste_action->setShortcut (ctrl_shift + Qt::Key_V); QAction *paste_to_workspace_action = edit_menu->addAction (tr ("Paste To Workspace...")); paste_to_workspace_action->setEnabled (false); // TODO: Make this work. - edit_menu->addSeparator (); ///// + edit_menu->addSeparator (); QAction *select_all_action = edit_menu->addAction (tr ("Select All")); select_all_action->setEnabled (false); // TODO: Make this work. + QAction *delete_action = edit_menu->addAction (tr ("Delete")); delete_action->setShortcut (Qt::Key_Delete); delete_action->setEnabled (false); // TODO: Make this work. - edit_menu->addSeparator (); ///// + edit_menu->addSeparator (); QAction *find_action = edit_menu->addAction (tr ("Find...")); find_action->setEnabled (false); // TODO: Make this work. + QAction *find_files_action = edit_menu->addAction (tr ("Find Files...")); - find_files_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier - + Qt::Key_F); - find_files_action->setEnabled (false); // TODO: Make this work. + find_files_action->setShortcut (ctrl_shift + Qt::Key_F); - edit_menu->addSeparator (); ///// + edit_menu->addSeparator (); QAction *clear_command_window_action = edit_menu->addAction (tr ("Clear Command Window")); - clear_command_window_action->setEnabled (false); // TODO: Make this work. + QAction *clear_command_history = edit_menu->addAction(tr ("Clear Command History")); - QAction * clear_workspace_action + + QAction *clear_workspace_action = edit_menu->addAction (tr ("Clear Workspace")); - _debug_menu = menuBar ()->addMenu (tr ("De&bug")); + connect (_copy_action, SIGNAL (triggered()), + command_window, SLOT (copyClipboard ())); + + connect (_paste_action, SIGNAL (triggered()), + command_window, SLOT (pasteClipboard ())); + + connect (find_files_action, SIGNAL (triggered()), + this, SLOT (find_files ())); + + connect (clear_command_window_action, SIGNAL (triggered ()), + this, SLOT (handle_clear_command_window_request ())); - _debug_step_over = _debug_menu->addAction (QIcon (":/actions/icons/db_step.png"), tr ("Step")); - _debug_step_over->setEnabled (false); -#ifdef HAVE_QSCINTILLA - _file_editor->debug_menu ()->addAction (_debug_step_over); - _file_editor->toolbar ()->addAction (_debug_step_over); -#endif - _debug_step_over->setShortcut (Qt::Key_F10); + connect (clear_command_history, SIGNAL (triggered ()), + this, SLOT (handle_clear_history_request ())); + + connect (clear_workspace_action, SIGNAL (triggered ()), + this, SLOT (handle_clear_workspace_request ())); +} - _debug_step_into = _debug_menu->addAction (QIcon (":/actions/icons/db_step_in.png"), tr ("Step in")); - _debug_step_into->setEnabled (false); -#ifdef HAVE_QSCINTILLA - _file_editor->debug_menu ()->addAction (_debug_step_into); - _file_editor->toolbar ()->addAction (_debug_step_into); -#endif - _debug_step_into->setShortcut (Qt::Key_F11); +QAction * +main_window::construct_debug_menu_item (const char *icon_file, + const QString& item, + const QKeySequence& key) +{ + QAction *action = _debug_menu->addAction (QIcon (icon_file), item); + + action->setEnabled (false); + action->setShortcut (key); - _debug_step_out = _debug_menu->addAction (QIcon (":/actions/icons/db_step_out.png"), tr ("Step out")); - _debug_step_out->setEnabled (false); #ifdef HAVE_QSCINTILLA - _file_editor->debug_menu ()->addAction (_debug_step_out); - _file_editor->toolbar ()->addAction (_debug_step_out); + editor_window->debug_menu ()->addAction (action); + editor_window->toolbar ()->addAction (action); #endif - _debug_step_out->setShortcut (Qt::ShiftModifier + Qt::Key_F11); + + return action; +} + +void +main_window::construct_debug_menu (QMenuBar *p) +{ + _debug_menu = p->addMenu (tr ("De&bug")); - _debug_continue = _debug_menu->addAction (QIcon (":/actions/icons/db_cont.png"), tr ("Continue")); - _debug_continue->setEnabled (false); + _debug_step_over = construct_debug_menu_item + (":/actions/icons/db_step.png", tr ("Step"), Qt::Key_F10); + + _debug_step_into = construct_debug_menu_item + (":/actions/icons/db_step_in.png", tr ("Step in"), Qt::Key_F11); + + _debug_step_out = construct_debug_menu_item + (":/actions/icons/db_step_out.png", tr ("Step out"), + Qt::ShiftModifier + Qt::Key_F11); + + _debug_continue = construct_debug_menu_item + (":/actions/icons/db_cont.png", tr ("Continue"), Qt::Key_F5); + + _debug_menu->addSeparator (); #ifdef HAVE_QSCINTILLA - _file_editor->debug_menu ()->addAction (_debug_continue); - _file_editor->toolbar ()->addAction (_debug_continue); -#endif - _debug_continue->setShortcut (Qt::Key_F5); - - _debug_menu->addSeparator (); ///// -#ifdef HAVE_QSCINTILLA - _file_editor->debug_menu ()->addSeparator (); ///// + editor_window->debug_menu ()->addSeparator (); #endif - _debug_quit = _debug_menu->addAction (QIcon (":/actions/icons/db_stop.png"), tr ("Exit Debug Mode")); - _debug_quit->setEnabled (false); -#ifdef HAVE_QSCINTILLA - _file_editor->debug_menu ()->addAction (_debug_quit); - _file_editor->toolbar ()->addAction (_debug_quit); -#endif - _debug_quit->setShortcut (Qt::ShiftModifier + Qt::Key_F5); + _debug_quit = construct_debug_menu_item + (":/actions/icons/db_stop.png", tr ("Exit Debug Mode"), + Qt::ShiftModifier + Qt::Key_F5); + + connect (_debug_step_over, SIGNAL (triggered ()), + this, SLOT (debug_step_over ())); + + connect (_debug_step_into, SIGNAL (triggered ()), + this, SLOT (debug_step_into ())); + + connect (_debug_step_out, SIGNAL (triggered ()), + this, SLOT (debug_step_out ())); + + connect (_debug_continue, SIGNAL (triggered ()), + this, SLOT (debug_continue ())); + + connect (_debug_quit, SIGNAL (triggered ()), + this, SLOT (debug_quit ())); +} - //QMenu *parallelMenu = menuBar ()->addMenu (tr ("&Parallel")); +void +main_window::construct_desktop_menu (QMenuBar *p) +{ + QMenu *desktop_menu = p->addMenu (tr ("&Desktop")); + + QAction *load_workspace_action = desktop_menu->addAction (tr ("Load workspace")); + + connect (load_workspace_action, SIGNAL (triggered ()), + this, SLOT (handle_load_workspace_request ())); +} - QMenu * desktop_menu = menuBar ()->addMenu (tr ("&Desktop")); - QAction * load_workspace_action = desktop_menu->addAction (tr ("Load workspace")); +QAction * +main_window::construct_window_menu_item (QMenu *p, const QString& item, + bool checkable, + const QKeySequence& key) +{ + QAction *action = p->addAction (item); + action->setCheckable (checkable); + action->setShortcut (key); + action->setShortcutContext (Qt::ApplicationShortcut); + + return action; +} - // Window menu - QMenu * window_menu = menuBar ()->addMenu (tr ("&Window")); - QAction * show_command_window_action - = window_menu->addAction (tr ("Show Command Window")); - show_command_window_action->setCheckable (true); - show_command_window_action->setShortcut (Qt::ControlModifier - + Qt::ShiftModifier + Qt::Key_0); - show_command_window_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * show_history_action - = window_menu->addAction (tr ("Show Command History")); - show_history_action->setCheckable (true); - show_history_action->setShortcut (Qt::ControlModifier - + Qt::ShiftModifier + Qt::Key_1); - show_history_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * show_file_browser_action - = window_menu->addAction (tr ("Show Current Directory")); - show_file_browser_action->setCheckable (true); - show_file_browser_action->setShortcut (Qt::ControlModifier - + Qt::ShiftModifier + Qt::Key_2); - show_file_browser_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * show_workspace_action - = window_menu->addAction (tr ("Show Workspace")); - show_workspace_action->setCheckable (true); - show_workspace_action->setShortcut (Qt::ControlModifier - + Qt::ShiftModifier + Qt::Key_3); - show_workspace_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * show_editor_action = window_menu->addAction (tr ("Show Editor")); - show_editor_action->setCheckable (true); - show_editor_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier - + Qt::Key_4); - show_editor_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * show_documentation_action = window_menu->addAction (tr ("Show Documentation")); - show_documentation_action->setCheckable (true); - show_documentation_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier - + Qt::Key_5); - show_documentation_action->setShortcutContext (Qt::ApplicationShortcut); - window_menu->addSeparator (); ///// +void +main_window::construct_window_menu (QMenuBar *p) +{ + QMenu *window_menu = p->addMenu (tr ("&Window")); + + QKeySequence ctrl = Qt::ControlModifier; + QKeySequence ctrl_shift = Qt::ControlModifier + Qt::ShiftModifier; + + QAction *show_command_window_action = construct_window_menu_item + (window_menu, tr ("Show Command Window"), true, ctrl_shift + Qt::Key_0); + + QAction *show_history_action = construct_window_menu_item + (window_menu, tr ("Show Command History"), true, ctrl_shift + Qt::Key_1); + + QAction *show_file_browser_action = construct_window_menu_item + (window_menu, tr ("Show File Browser"), true, ctrl_shift + Qt::Key_2); + + QAction *show_workspace_action = construct_window_menu_item + (window_menu, tr ("Show Workspace"), true, ctrl_shift + Qt::Key_3); + + QAction *show_editor_action = construct_window_menu_item + (window_menu, tr ("Show Editor"), true, ctrl_shift + Qt::Key_4); + + QAction *show_documentation_action = construct_window_menu_item + (window_menu, tr ("Show Documentation"), true, ctrl_shift + Qt::Key_5); - QAction * command_window_action - = window_menu->addAction (tr ("Command Window")); - command_window_action->setShortcut (Qt::ControlModifier + Qt::Key_0); - command_window_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * history_action - = window_menu->addAction (tr ("Command History")); - history_action->setShortcut (Qt::ControlModifier + Qt::Key_1); - history_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * file_browser_action - = window_menu->addAction (tr ("Current Directory")); - file_browser_action->setShortcut (Qt::ControlModifier + Qt::Key_2); - file_browser_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * workspace_action - = window_menu->addAction (tr ("Workspace")); - workspace_action->setShortcut (Qt::ControlModifier + Qt::Key_3); - workspace_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * editor_action - = window_menu->addAction (tr ("Editor")); - editor_action->setShortcut (Qt::ControlModifier + Qt::Key_4); - editor_action->setShortcutContext (Qt::ApplicationShortcut); - QAction * documentation_action - = window_menu->addAction (tr ("Documentation")); - documentation_action->setShortcut (Qt::ControlModifier + Qt::Key_5); - documentation_action->setShortcutContext (Qt::ApplicationShortcut); + window_menu->addSeparator (); + + QAction *command_window_action = construct_window_menu_item + (window_menu, tr ("Command Window"), false, ctrl + Qt::Key_0); + + QAction *history_action = construct_window_menu_item + (window_menu, tr ("Command History"), false, ctrl + Qt::Key_1); + + QAction *file_browser_action = construct_window_menu_item + (window_menu, tr ("File Browser"), false, ctrl + Qt::Key_2); - window_menu->addSeparator (); ///// + QAction *workspace_action = construct_window_menu_item + (window_menu, tr ("Workspace"), false, ctrl + Qt::Key_3); + + QAction *editor_action = construct_window_menu_item + (window_menu, tr ("Editor"), false, ctrl + Qt::Key_4); - QAction * reset_windows_action + QAction *documentation_action = construct_window_menu_item + (window_menu, tr ("Documentation"), false, ctrl + Qt::Key_5); + + window_menu->addSeparator (); + + QAction *reset_windows_action = window_menu->addAction (tr ("Reset Windows")); + reset_windows_action->setEnabled (false); // TODO: Make this work. - // Help menu - QMenu * help_menu = menuBar ()->addMenu (tr ("&Help")); - QMenu * documentation_menu - = help_menu->addMenu (tr ("Documentation")); - QAction * ondisk_documentation_action - = documentation_menu->addAction (tr ("On Disk")); - QAction * online_documentation_action - = documentation_menu->addAction (tr ("Online")); + connect (show_command_window_action, SIGNAL (toggled (bool)), + command_window, SLOT (setVisible (bool))); + + connect (command_window, SIGNAL (active_changed (bool)), + show_command_window_action, SLOT (setChecked (bool))); + + connect (show_workspace_action, SIGNAL (toggled (bool)), + workspace_window, SLOT (setVisible (bool))); + + connect (workspace_window, SIGNAL (active_changed (bool)), + show_workspace_action, SLOT (setChecked (bool))); + + connect (show_history_action, SIGNAL (toggled (bool)), + history_window, SLOT (setVisible (bool))); + + connect (history_window, SIGNAL (active_changed (bool)), + show_history_action, SLOT (setChecked (bool))); + + connect (show_file_browser_action, SIGNAL (toggled (bool)), + file_browser_window, SLOT (setVisible (bool))); + + connect (file_browser_window, SIGNAL (active_changed (bool)), + show_file_browser_action, SLOT (setChecked (bool))); + +#ifdef HAVE_QSCINTILLA + connect (show_editor_action, SIGNAL (toggled (bool)), + editor_window, SLOT (setVisible (bool))); + + connect (editor_window, SIGNAL (active_changed (bool)), + show_editor_action, SLOT (setChecked (bool))); +#endif + + connect (show_documentation_action, SIGNAL (toggled (bool)), + doc_browser_window, SLOT (setVisible (bool))); + + connect (doc_browser_window, SIGNAL (active_changed (bool)), + show_documentation_action, SLOT (setChecked (bool))); - help_menu->addSeparator (); ///// + connect (command_window_action, SIGNAL (triggered ()), + command_window, SLOT (focus ())); + + connect (workspace_action, SIGNAL (triggered ()), + workspace_window, SLOT (focus ())); + + connect (history_action, SIGNAL (triggered ()), + history_window, SLOT (focus ())); + + connect (file_browser_action, SIGNAL (triggered ()), + file_browser_window, SLOT (focus ())); + + connect (editor_action, SIGNAL (triggered ()), + editor_window, SLOT (focus ())); - QAction * report_bug_action + connect (documentation_action, SIGNAL (triggered ()), + doc_browser_window, SLOT (focus ())); + + connect (reset_windows_action, SIGNAL (triggered ()), + this, SLOT (reset_windows ())); +} + +void +main_window::construct_help_menu (QMenuBar *p) +{ + QMenu *help_menu = p->addMenu (tr ("&Help")); + + construct_documentation_menu (help_menu); + + help_menu->addSeparator (); + + QAction *report_bug_action = help_menu->addAction (tr ("Report Bug")); - QAction * octave_forge_action + + QAction *octave_forge_action = help_menu->addAction (tr ("Visit Octave Forge")); - QAction * agora_action + + QAction *agora_action = help_menu->addAction (tr ("Visit Agora")); - help_menu->addSeparator (); ///// + help_menu->addSeparator (); - QAction * about_octave_action + QAction *about_octave_action = help_menu->addAction (tr ("About Octave")); - // Toolbars - QToolBar *main_tool_bar = addToolBar ("Main"); - main_tool_bar->setObjectName ("MainToolBar"); - main_tool_bar->addAction (new_script_action); - main_tool_bar->addAction (open_action); + connect (report_bug_action, SIGNAL (triggered ()), + this, SLOT (open_bug_tracker_page ())); + + connect (octave_forge_action, SIGNAL (triggered ()), + this, SLOT (open_octave_forge_page ())); + + connect (agora_action, SIGNAL (triggered ()), + this, SLOT (open_agora_page ())); + + connect (about_octave_action, SIGNAL (triggered ()), + this, SLOT (show_about_octave ())); +} - main_tool_bar->addSeparator (); ///// +void +main_window::construct_documentation_menu (QMenu *p) +{ + QMenu *documentation_menu = p->addMenu (tr ("Documentation")); + + QAction *ondisk_documentation_action + = documentation_menu->addAction (tr ("On Disk")); + + QAction *online_documentation_action + = documentation_menu->addAction (tr ("Online")); + + connect (ondisk_documentation_action, SIGNAL (triggered ()), + doc_browser_window, SLOT (focus ())); - main_tool_bar->addAction (cut_action); - main_tool_bar->addAction (copy_action); - main_tool_bar->addAction (paste_action); - main_tool_bar->addAction (undo_action); - main_tool_bar->addAction (redo_action); + connect (online_documentation_action, SIGNAL (triggered ()), + this, SLOT (open_online_documentation_page ())); +} + +void +main_window::construct_tool_bar (void) +{ + _main_tool_bar = addToolBar ("Main"); + + _main_tool_bar->setObjectName ("MainToolBar"); + _main_tool_bar->addAction (_new_script_action); + _main_tool_bar->addAction (_open_action); + + _main_tool_bar->addSeparator (); - main_tool_bar->addSeparator (); ///// + _main_tool_bar->addAction (_cut_action); + _main_tool_bar->addAction (_copy_action); + _main_tool_bar->addAction (_paste_action); + _main_tool_bar->addAction (_undo_action); + + _main_tool_bar->addSeparator (); + + _current_directory_combo_box = new QComboBox (this); + _current_directory_combo_box->setFixedWidth (current_directory_width); + _current_directory_combo_box->setEditable (true); + _current_directory_combo_box->setInsertPolicy(QComboBox::NoInsert); + _current_directory_combo_box->setToolTip (tr ("Enter directory name")); + _current_directory_combo_box->setMaxVisibleItems (current_directory_max_visible); + _current_directory_combo_box->setMaxCount (current_directory_max_count); + QSizePolicy sizePol(QSizePolicy::Expanding, QSizePolicy::Preferred); + _current_directory_combo_box->setSizePolicy(sizePol); // addWidget takes ownership of the objects so there is no // need to delete these upon destroying this main_window. - main_tool_bar->addWidget (new QLabel (tr ("Current Directory:"))); - main_tool_bar->addWidget (_current_directory_combo_box); - main_tool_bar->addWidget (current_directory_tool_button); - main_tool_bar->addWidget (current_directory_up_tool_button); + _main_tool_bar->addWidget (new QLabel (tr ("Current Directory: "))); + _main_tool_bar->addWidget (_current_directory_combo_box); + QAction *current_dir_up = _main_tool_bar->addAction ( + QIcon (":/actions/icons/up.png"), + tr ("One directory up")); + QAction *current_dir_search = _main_tool_bar->addAction ( + QIcon (":/actions/icons/search.png"), + tr ("Browse directories")); - connect (qApp, SIGNAL (aboutToQuit ()), - this, SLOT (prepare_for_quit ())); - connect (preferences_action, SIGNAL (triggered ()), - this, SLOT (process_settings_dialog_request ())); - connect (exit_action, SIGNAL (triggered ()), - this, SLOT (close ())); - connect (new_script_action, SIGNAL (triggered ()), - this, SLOT (new_file ())); - connect (open_action, SIGNAL (triggered ()), - this, SLOT (open_file ())); - connect (online_documentation_action, SIGNAL (triggered ()), - this, SLOT (open_online_documentation_page ())); - connect (report_bug_action, SIGNAL (triggered ()), - this, SLOT (open_bug_tracker_page ())); - connect (octave_forge_action, SIGNAL (triggered ()), - this, SLOT (open_octave_forge_page ())); - connect (agora_action, SIGNAL (triggered ()), - this, SLOT (open_agora_page ())); - connect (about_octave_action, SIGNAL (triggered ()), - this, SLOT (show_about_octave ())); - connect (show_command_window_action, SIGNAL (toggled (bool)), - _terminal_dock_widget, SLOT (setVisible (bool))); - connect (_terminal_dock_widget, SIGNAL (active_changed (bool)), - show_command_window_action, SLOT (setChecked (bool))); - connect (show_workspace_action, SIGNAL (toggled (bool)), - _workspace_view, SLOT (setVisible (bool))); - connect (_workspace_view, SIGNAL (active_changed (bool)), - show_workspace_action, SLOT (setChecked (bool))); - connect (show_history_action, SIGNAL (toggled (bool)), - _history_dock_widget, SLOT (setVisible (bool))); - connect (_history_dock_widget, SIGNAL (active_changed (bool)), - show_history_action, SLOT (setChecked (bool))); - connect (show_file_browser_action, SIGNAL (toggled (bool)), - _files_dock_widget, SLOT (setVisible (bool))); - connect (_files_dock_widget, SIGNAL (active_changed (bool)), - show_file_browser_action, SLOT (setChecked (bool))); -#ifdef HAVE_QSCINTILLA - connect (show_editor_action, SIGNAL (toggled (bool)), - _file_editor, SLOT (setVisible (bool))); - connect (_file_editor, SIGNAL (active_changed (bool)), - show_editor_action, SLOT (setChecked (bool))); -#endif - connect (show_documentation_action, SIGNAL (toggled (bool)), - _documentation_dock_widget, SLOT (setVisible (bool))); - connect (_documentation_dock_widget, SIGNAL (active_changed (bool)), - show_documentation_action, SLOT (setChecked (bool))); - - connect (command_window_action, SIGNAL (triggered ()), - this, SLOT (focus_command_window ())); - connect (workspace_action, SIGNAL (triggered ()), - this, SLOT (focus_workspace ())); - connect (history_action, SIGNAL (triggered ()), - this, SLOT (focus_command_history ())); - connect (file_browser_action, SIGNAL (triggered ()), - this, SLOT (focus_current_directory ())); - connect (editor_action, SIGNAL (triggered ()), - this, SLOT (focus_editor ())); - connect (documentation_action, SIGNAL (triggered ()), - this, SLOT (focus_documentation ())); - connect (ondisk_documentation_action, SIGNAL (triggered ()), - this, SLOT (focus_documentation ())); + connect (_current_directory_combo_box, SIGNAL (activated (QString)), + this, SLOT (set_current_working_directory (QString))); - connect (reset_windows_action, SIGNAL (triggered ()), - this, SLOT (reset_windows ())); -#ifdef HAVE_QSCINTILLA - connect (this, SIGNAL (settings_changed ()), - _file_editor, SLOT (notice_settings ())); -#endif - connect (this, SIGNAL (settings_changed ()), - _files_dock_widget, SLOT (notice_settings ())); - connect (this, SIGNAL (settings_changed ()), - this, SLOT (notice_settings ())); - connect (_files_dock_widget, SIGNAL (open_file (QString)), - this, SLOT (open_file (QString))); - connect (_files_dock_widget, SIGNAL (displayed_directory_changed(QString)), - this, SLOT (set_current_working_directory(QString))); - connect (_history_dock_widget, SIGNAL (information (QString)), - this, SLOT (report_status_message (QString))); - connect (_history_dock_widget, SIGNAL (command_double_clicked (QString)), - this, SLOT (handle_command_double_clicked (QString))); - connect (save_workspace_action, SIGNAL (triggered ()), - this, SLOT (handle_save_workspace_request ())); - connect (load_workspace_action, SIGNAL (triggered ()), - this, SLOT (handle_load_workspace_request ())); - connect (clear_workspace_action, SIGNAL (triggered ()), - this, SLOT (handle_clear_workspace_request ())); - connect (current_directory_tool_button, SIGNAL (clicked ()), - this, SLOT (change_current_working_directory ())); - connect (current_directory_up_tool_button, SIGNAL (clicked ()), - this, SLOT (current_working_directory_up())); - connect (copy_action, SIGNAL (triggered()), - _terminal, SLOT (copyClipboard ())); - connect (paste_action, SIGNAL (triggered()), - _terminal, SLOT (pasteClipboard ())); - connect (_current_directory_combo_box, SIGNAL (activated (QString)), - this, SLOT (set_current_working_directory (QString))); - connect (_current_directory_line_edit, SIGNAL (returnPressed ()), - this, SLOT (current_working_directory_entered ())); - connect (_debug_continue, SIGNAL (triggered ()), - this, SLOT (debug_continue ())); - connect (_debug_step_into, SIGNAL (triggered ()), - this, SLOT (debug_step_into ())); - connect (_debug_step_over, SIGNAL (triggered ()), - this, SLOT (debug_step_over ())); - connect (_debug_step_out, SIGNAL (triggered ()), - this, SLOT (debug_step_out ())); - connect (_debug_quit, SIGNAL (triggered ()), - this, SLOT (debug_quit ())); + connect (_current_directory_combo_box->lineEdit(), SIGNAL (returnPressed ()), + this, SLOT (accept_directory_line_edit ())); + + connect (current_dir_search, SIGNAL (triggered ()), + this, SLOT (browse_for_directory ())); - connect (clear_command_history, SIGNAL (triggered ()), - this, SLOT (handle_clear_history_request ())); - - setWindowTitle ("Octave"); - setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks); - addDockWidget (Qt::LeftDockWidgetArea, _workspace_view); - addDockWidget (Qt::LeftDockWidgetArea, _history_dock_widget); - addDockWidget (Qt::RightDockWidgetArea, _files_dock_widget); -#ifdef HAVE_QSCINTILLA - addDockWidget (Qt::RightDockWidgetArea, _file_editor); -#endif - addDockWidget (Qt::BottomDockWidgetArea, _terminal_dock_widget); - addDockWidget (Qt::RightDockWidgetArea, _documentation_dock_widget); - setStatusBar (_status_bar); + connect (current_dir_up, SIGNAL (triggered ()), + this, SLOT (change_directory_up ())); - _octave_qt_event_listener = new octave_qt_event_listener (); - octave_link::register_event_listener (_octave_qt_event_listener); - - connect (_octave_qt_event_listener, - SIGNAL (current_directory_has_changed_signal (QString)), - this, - SLOT (current_working_directory_has_changed (QString))); - - connect (_octave_qt_event_listener, - SIGNAL (entered_debug_mode_signal ()), - this, - SLOT(handle_entered_debug_mode ())); - - connect (_octave_qt_event_listener, - SIGNAL (quit_debug_mode_signal ()), - this, - SLOT (handle_quit_debug_mode ())); + connect (_undo_action, SIGNAL (triggered ()), + this, SLOT (handle_undo_request ())); } void @@ -1141,6 +1341,8 @@ main_window::load_workspace_callback (const std::string& file) { Fload (ovl (file)); + + octave_link::set_workspace (true, symbol_table::workspace_info ()); } void @@ -1150,11 +1352,41 @@ } void +main_window::rename_variable_callback (const main_window::name_pair& names) +{ + /* bool status = */ symbol_table::rename (names.first, names.second); + + // if (status) + octave_link::set_workspace (true, symbol_table::workspace_info ()); + + // else + // ; // we need an octave_link action that runs a GUI error option. +} + +void +main_window::command_window_undo_callback (void) +{ + command_editor::undo (); + command_editor::redisplay (); +} + +void +main_window::clear_command_window_callback (void) +{ + Fclc (); + command_editor::interrupt (true); +} + +void +main_window::resize_command_window_callback (void) +{ + command_editor::resize_terminal (); +} + +void main_window::clear_history_callback (void) { - command_history::clear (); - - _history_dock_widget->reset_model (); + Fhistory (ovl ("-c")); } void @@ -1167,30 +1399,47 @@ main_window::debug_continue_callback (void) { Fdbcont (); + + command_editor::interrupt (true); } +// The next three callbacks are invoked by GUI buttons. Those buttons +// should only be active when we are doing debugging, which means that +// Octave is waiting for input in get_debug_input. Calling +// command_editor::interrupt will force readline to return even if it +// has not read any input, and then get_debug_input will return, +// allowing the evaluator to continue and execute the next statement. + void main_window::debug_step_into_callback (void) { Fdbstep (ovl ("in")); + + command_editor::interrupt (true); } void main_window::debug_step_over_callback (void) { Fdbstep (); + + command_editor::interrupt (true); } void main_window::debug_step_out_callback (void) { Fdbstep (ovl ("out")); + + command_editor::interrupt (true); } void main_window::debug_quit_callback (void) { Fdbquit (); + + command_editor::interrupt (true); } void @@ -1198,3 +1447,41 @@ { Fquit (); } + +void +main_window::find_files(const QString &start_dir) +{ + + if (! find_files_dlg) + { + find_files_dlg = new find_files_dialog (this); + + connect (find_files_dlg, SIGNAL (finished (int)), + this, SLOT (find_files_finished (int))); + + connect (find_files_dlg, SIGNAL (dir_selected(const QString &)), + file_browser_window, SLOT(set_current_directory(const QString&))); + + connect (find_files_dlg, SIGNAL (file_selected(const QString &)), + this, SLOT(open_file(const QString &))); + + find_files_dlg->setWindowModality (Qt::NonModal); + } + + if (! find_files_dlg->isVisible ()) + { + find_files_dlg->show (); + } + + find_files_dlg->set_search_dir(start_dir); + + find_files_dlg->activateWindow (); + +} + +void +main_window::find_files_finished(int) +{ + +} +
--- a/libgui/src/main-window.h +++ b/libgui/src/main-window.h @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -20,8 +21,8 @@ */ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H +#if !defined (main_window_h) +#define main_window_h 1 // Qt includes #include <QtGui/QMainWindow> @@ -43,13 +44,16 @@ #include "QTerminal.h" // Own includes +#include "dialog.h" #include "resource-manager.h" +#include "workspace-model.h" #include "workspace-view.h" -#include "history-dockwidget.h" -#include "files-dockwidget.h" -#include "terminal-dockwidget.h" -#include "documentation-dockwidget.h" -#include "octave-qt-event-listener.h" +#include "history-dock-widget.h" +#include "files-dock-widget.h" +#include "terminal-dock-widget.h" +#include "documentation-dock-widget.h" +#include "octave-qt-link.h" +#include "find-files-dialog.h" /** * \class MainWindow @@ -58,85 +62,135 @@ */ class main_window : public QMainWindow { - Q_OBJECT public: - main_window (QWidget * parent = 0); - ~main_window (); + Q_OBJECT + +public: + + typedef std::pair <std::string, std::string> name_pair; - QTerminal *get_terminal_view () { return _terminal; } - history_dock_widget *get_history_dock_widget () - { - return _history_dock_widget; - } - files_dock_widget *get_files_dock_widget () - { - return _files_dock_widget; - } - bool is_closing () { return _closing; } + main_window (QWidget *parent = 0); + + ~main_window (void); + + void focus_command_window (void); signals: - void settings_changed (); + void settings_changed (const QSettings *); + void relay_command_signal (const QString&); + void new_file_signal (const QString&); + void open_file_signal (const QString&); public slots: void report_status_message (const QString& statusMessage); - void handle_save_workspace_request (); - void handle_load_workspace_request (); - void handle_clear_workspace_request (); - void handle_clear_history_request (); + void handle_save_workspace_request (void); + void handle_load_workspace_request (const QString& file = QString ()); + void handle_clear_command_window_request (void); + void handle_clear_workspace_request (void); + void handle_clear_history_request (void); + void handle_rename_variable_request (const QString& old_name, + const QString& new_name); + void handle_undo_request (void); + void new_file (const QString& commands = QString ()); + void open_file (const QString& file_name = QString ()); + void open_online_documentation_page (void); + void open_bug_tracker_page (void); + void open_octave_forge_page (void); + void open_agora_page (void); + void process_settings_dialog_request (void); + void show_about_octave (void); + void notice_settings (const QSettings *settings); + void prepare_to_exit (void); + void exit (int status); + void reset_windows (void); + + void change_directory (const QString& dir); + void browse_for_directory (void); + void set_current_working_directory (const QString& dir); + void change_directory_up (void); + void accept_directory_line_edit (void); + void handle_command_double_clicked (const QString& command); - void new_file (); - void open_file (); - void open_file (const QString& file_name); - void open_online_documentation_page (); - void open_bug_tracker_page (); - void open_octave_forge_page (); - void open_agora_page (); - void process_settings_dialog_request (); - void show_about_octave (); - void notice_settings (); - void prepare_for_quit (); - void reset_windows (); - void current_working_directory_has_changed (const QString& directory); - void change_current_working_directory (); - void set_current_working_directory (const QString& directory); - void current_working_directory_up (); - void current_working_directory_entered (); - void focus_command_window (); - void focus_command_history (); - void focus_current_directory (); - void focus_workspace (); - void focus_editor (); - void focus_documentation (); - void handle_command_window_visible (bool); - void handle_command_history_visible (bool); - void handle_current_directory_visible (bool); - void handle_workspace_visible (bool); - void handle_editor_visible (bool); - void handle_documentation_visible (bool); + void handle_enter_debugger (void); + void handle_exit_debugger (void); + void debug_continue (void); + void debug_step_into (void); + void debug_step_over (void); + void debug_step_out (void); + void debug_quit (void); + + void read_settings (void); + void write_settings (void); + void connect_visibility_changed (void); + + void connect_uiwidget_links (); + + void handle_create_dialog (const QString& message, const QString& title, + const QString& icon, const QStringList& button, + const QString& defbutton, + const QStringList& role); - void handle_entered_debug_mode (); - void handle_quit_debug_mode (); - void debug_continue (); - void debug_step_into (); - void debug_step_over (); - void debug_step_out (); - void debug_quit (); + void handle_create_listview (const QStringList& list, const QString& mode, + int width, int height, + const QIntList& initial, + const QString& name, + const QStringList& prompt, + const QString& ok_string, + const QString& cancel_string); - void read_settings (); - void write_settings (); - void connect_visibility_changed (); + void handle_create_inputlayout (const QStringList&, const QString&, + const QFloatList&, const QFloatList&, + const QStringList&); + void handle_create_debug_cd_or_addpath_dialog (const QString& file, + const QString& dir, + bool addpath_option); + // find files dialog + void find_files(const QString &startdir=QDir::currentPath()); + void find_files_finished(int); protected: void closeEvent (QCloseEvent * closeEvent); private: - void construct (); - void establish_octave_link (); + + void construct (void); + + void construct_octave_qt_link (void); + + void construct_menu_bar (void); + void construct_file_menu (QMenuBar *p); + void construct_new_menu (QMenu *p); + void construct_edit_menu (QMenuBar *p); + void construct_debug_menu_item (QMenu *p, const QString& item, + const QKeySequence& key); + QAction *construct_debug_menu_item (const char *icon_file, + const QString& item, + const QKeySequence& key); + void construct_debug_menu (QMenuBar *p); + void construct_desktop_menu (QMenuBar *p); + QAction *construct_window_menu_item (QMenu *p, const QString& item, + bool checkable, + const QKeySequence& key); + void construct_window_menu (QMenuBar *p); + void construct_help_menu (QMenuBar *p); + void construct_documentation_menu (QMenu *p); + + void construct_tool_bar (void); + + void establish_octave_link (void); void save_workspace_callback (const std::string& file); void load_workspace_callback (const std::string& file); + void rename_variable_callback (const name_pair& names); + + void command_window_undo_callback (void); + + void clear_command_window_callback (void); + + void resize_command_window_callback (void); + void clear_workspace_callback (void); void clear_history_callback (void); @@ -155,37 +209,53 @@ void exit_callback (void); - QTerminal * _terminal; -#ifdef HAVE_QSCINTILLA - file_editor_interface * _file_editor; -#endif - QMenu * _debug_menu; - - QAction * _debug_continue; - QAction * _debug_step_into; - QAction * _debug_step_over; - QAction * _debug_step_out; - QAction * _debug_quit; - - // Dock widgets. - workspace_view * _workspace_view; - history_dock_widget * _history_dock_widget; - files_dock_widget * _files_dock_widget; - terminal_dock_widget * _terminal_dock_widget; - documentation_dock_widget*_documentation_dock_widget; + // Data models. + workspace_model *_workspace_model; // Toolbars. - QStatusBar * _status_bar; - QComboBox * _current_directory_combo_box; - static const int current_directory_width = 300; - static const int current_directory_max_visible = 16; - static const int current_directory_max_count = 16; - QLineEdit * _current_directory_line_edit; + QStatusBar *status_bar; + + // Subwindows. + terminal_dock_widget *command_window; + history_dock_widget *history_window; + files_dock_widget *file_browser_window; + documentation_dock_widget *doc_browser_window; + file_editor_interface *editor_window; + workspace_view *workspace_window; + + QToolBar *_main_tool_bar; + QMenu *_debug_menu; + + QAction *_debug_continue; + QAction *_debug_step_into; + QAction *_debug_step_over; + QAction *_debug_step_out; + QAction *_debug_quit; + + QAction *_new_script_action; + QAction *_open_action; - octave_qt_event_listener *_octave_qt_event_listener; + QAction *_cut_action; + QAction *_copy_action; + QAction *_paste_action; + QAction *_undo_action; - // Flag for closing whole application - bool _closing; + // Toolbars. + QComboBox *_current_directory_combo_box; + static const int current_directory_width = 300; + static const int current_directory_max_visible = 16; + static const int current_directory_max_count = 16; + QLineEdit *_current_directory_line_edit; + + // Find files dialog + find_files_dialog * find_files_dlg; + + octave_main_thread *_octave_main_thread; + + octave_qt_link *_octave_qt_link; + + // Flag for closing whole application. + bool _closing; }; #endif // MAINWINDOW_H
--- a/libgui/src/module.mk +++ b/libgui/src/module.mk @@ -21,12 +21,16 @@ src/icons/db_stop.png \ src/icons/editcopy.png \ src/icons/editcut.png \ + src/icons/editdelete.png \ src/icons/editpaste.png \ src/icons/filenew.png \ src/icons/fileopen.png \ + src/icons/fileprint.png \ src/icons/filesaveas.png \ src/icons/filesave.png \ src/icons/find.png \ + src/icons/gear.png \ + src/icons/folder_new.png \ src/icons/graphic_logo_DocumentationDockWidget.png \ src/icons/graphic_logo_FileEditor.png \ src/icons/graphic_logo_FilesDockWidget.png \ @@ -43,9 +47,11 @@ src/icons/letter_logo_TerminalDockWidget.png \ src/icons/letter_logo_WorkspaceView.png \ src/icons/logo.png \ + src/icons/ok.png \ src/icons/question.png \ src/icons/redled.png \ src/icons/redo.png \ + src/icons/reload.png \ src/icons/search.png \ src/icons/star.png \ src/icons/stop.png \ @@ -55,23 +61,31 @@ src/icons/zoom-in.png \ src/icons/zoom-out.png -octave_gui_MOC = \ +octave_gui_MOC = + +if AMCOND_HAVE_QSCINTILLA +octave_gui_MOC += \ src/m-editor/moc-file-editor-interface.cc \ src/m-editor/moc-file-editor-tab.cc \ src/m-editor/moc-file-editor.cc \ src/m-editor/moc-find-dialog.cc \ - src/m-editor/moc-lexer-octave-gui.cc \ - src/moc-documentation-dockwidget.cc \ - src/moc-files-dockwidget.cc \ - src/moc-history-dockwidget.cc \ + src/m-editor/moc-lexer-octave-gui.cc +endif + +octave_gui_MOC += \ + src/moc-dialog.cc \ + src/moc-documentation-dock-widget.cc \ + src/moc-files-dock-widget.cc \ + src/moc-history-dock-widget.cc \ src/moc-main-window.cc \ - src/moc-octave-qt-event-listener.cc \ + src/moc-octave-qt-link.cc \ src/moc-settings-dialog.cc \ - src/moc-terminal-dockwidget.cc \ + src/moc-terminal-dock-widget.cc \ + src/moc-color-picker.cc \ src/moc-welcome-wizard.cc \ src/moc-workspace-model.cc \ src/moc-workspace-view.cc \ - src/octave-adapter/moc-octave-main-thread.cc \ + src/moc-find-files-dialog.cc \ src/qtinfo/moc-parser.cc \ src/qtinfo/moc-webinfo.cc \ src/moc-octave-dock-widget.cc @@ -87,51 +101,54 @@ BUILT_SOURCES += $(octave_gui_UI_H) noinst_HEADERS += \ + src/dialog.h \ src/octave-dock-widget.h \ - src/documentation-dockwidget.h \ - src/files-dockwidget.h \ - src/history-dockwidget.h \ + src/documentation-dock-widget.h \ + src/files-dock-widget.h \ + src/history-dock-widget.h \ src/m-editor/file-editor-interface.h \ src/m-editor/file-editor-tab.h \ src/m-editor/file-editor.h \ src/m-editor/find-dialog.h \ src/m-editor/lexer-octave-gui.h \ src/main-window.h \ - src/octave-adapter/octave-event-listener.h \ - src/octave-adapter/octave-link.h \ - src/octave-adapter/octave-main-thread.h \ src/octave-gui.h \ - src/octave-qt-event-listener.h \ + src/octave-main-thread.h \ + src/octave-qt-link.h \ src/qtinfo/parser.h \ src/qtinfo/webinfo.h \ src/resource-manager.h \ src/settings-dialog.h \ - src/symbol-information.h \ - src/terminal-dockwidget.h \ + src/terminal-dock-widget.h \ + src/color-picker.h \ src/welcome-wizard.h \ + src/find-files-dialog.h \ + src/find-files-model.h \ src/workspace-model.h \ src/workspace-view.h src_libgui_src_la_SOURCES = \ - src/documentation-dockwidget.cc \ - src/files-dockwidget.cc \ - src/history-dockwidget.cc \ + src/dialog.cc \ + src/documentation-dock-widget.cc \ + src/files-dock-widget.cc \ + src/history-dock-widget.cc \ src/m-editor/file-editor-tab.cc \ src/m-editor/file-editor.cc \ src/m-editor/find-dialog.cc \ src/m-editor/lexer-octave-gui.cc \ src/main-window.cc \ - src/octave-adapter/octave-link.cc \ - src/octave-adapter/octave-main-thread.cc \ src/octave-gui.cc \ - src/octave-qt-event-listener.cc \ + src/octave-main-thread.cc \ + src/octave-qt-link.cc \ src/qtinfo/parser.cc \ src/qtinfo/webinfo.cc \ src/resource-manager.cc \ src/settings-dialog.cc \ - src/symbol-information.cc \ - src/terminal-dockwidget.cc \ + src/terminal-dock-widget.cc \ + src/color-picker.cc \ src/welcome-wizard.cc \ + src/find-files-dialog.cc \ + src/find-files-model.cc \ src/workspace-model.cc \ src/workspace-view.cc @@ -144,7 +161,6 @@ -I$(srcdir)/qterminal/libqterminal \ -Isrc -I$(srcdir)/src \ -I$(srcdir)/src/m-editor \ - -I$(srcdir)/src/octave-adapter \ -I$(srcdir)/src/qtinfo \ -I$(top_srcdir)/liboctave/cruft/misc \ -I$(top_srcdir)/liboctave/array \
deleted file mode 100644 --- a/libgui/src/octave-adapter/octave-event-listener.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - -Copyright (C) 2011-2012 Jacob Dawid - -This file is part of Octave. - -Octave 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 3 of the License, or (at your -option) any later version. - -Octave 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/>. - -*/ - -#ifndef OCTAVEEVENTLISTENER_H -#define OCTAVEEVENTLISTENER_H - -#include <string> - -class octave_event_listener -{ - public: - octave_event_listener () { } - virtual ~octave_event_listener () { } - - virtual void - current_directory_has_changed (const std::string& directory) = 0; - - virtual void about_to_exit () = 0; - - virtual void entered_debug_mode () = 0; - virtual void quit_debug_mode () = 0; -}; - -#endif // OCTAVEEVENTLISTENER_H
--- a/libgui/src/octave-dock-widget.h +++ b/libgui/src/octave-dock-widget.h @@ -20,43 +20,68 @@ */ -#ifndef OCTAVEDOCKWIDGET_H -#define OCTAVEDOCKWIDGET_H +#if !defined (octave_dock_widget_h) +#define octave_dock_widget_h 1 #include <QDockWidget> -//#include <QMenu> -//#include <QToolBar> class octave_dock_widget : public QDockWidget { Q_OBJECT - public: +public: + octave_dock_widget (QWidget *p) : QDockWidget (p) { connect (this, SIGNAL (visibilityChanged (bool)), this, SLOT (handle_visibility_changed (bool))); - connect (this, SIGNAL (topLevelChanged(bool)), - this, SLOT(top_level_changed(bool))); + connect (this, SIGNAL (topLevelChanged (bool)), + this, SLOT (top_level_changed (bool))); } virtual ~octave_dock_widget () { } + virtual void connect_visibility_changed (void) + { + connect (this, SIGNAL (visibilityChanged (bool)), + this, SLOT (handle_visibility (bool))); + } + signals: - /** Custom signal that tells if a user has clicked away + + /** Custom signal that tells whether a user has clicked away * that dock widget, i.e the active dock widget has * changed. */ - virtual void active_changed (bool active); + void active_changed (bool active); protected: + virtual void closeEvent (QCloseEvent *e) { emit active_changed (false); QDockWidget::closeEvent (e); } +public slots: + + virtual void focus (void) + { + if (! isVisible ()) + setVisible (true); + + setFocus (); + activateWindow (); + raise (); + } + + virtual void handle_visibility (bool visible) + { + if (visible && ! isFloating ()) + focus (); + } + protected slots: /** Slot to steer changing visibility from outside. */ @@ -69,13 +94,14 @@ /** Slot when floating property changes */ virtual void top_level_changed (bool floating) { - if(floating) + if (floating) { - setWindowFlags(Qt::Window); // make a window from the widget when floating - show(); // make it visible again since setWindowFlags hides it + // Make a window from the widget when floating and make it + // visible again since setWindowFlags hides it. + setWindowFlags (Qt::Window); + show(); } } - }; -#endif // OCTAVEDOCKWIDGET_H +#endif
rename from libgui/src/octave-adapter/octave-main-thread.cc rename to libgui/src/octave-main-thread.cc --- a/libgui/src/octave-adapter/octave-main-thread.cc +++ b/libgui/src/octave-main-thread.cc @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -27,25 +28,28 @@ #include <clocale> #include <string> +#include "builtin-defun-decls.h" #include "octave.h" +#include "ov-builtin.h" +#include "ov-fcn-handle.h" #include "octave-main-thread.h" #include "octave-link.h" -octave_main_thread::octave_main_thread () : QThread () -{ -} - void -octave_main_thread::run () +octave_main_thread::run (void) { // Matlab uses "C" locale for LC_NUMERIC class regardless of local setting setlocale (LC_NUMERIC, "C"); - emit ready (); - octave_initialize_interpreter (octave_cmdline_argc, octave_cmdline_argv, octave_embedded); octave_execute_interpreter (); } + +void +octave_main_thread::execute_interpreter (void) +{ + start (); +}
rename from libgui/src/octave-adapter/octave-main-thread.h rename to libgui/src/octave-main-thread.h --- a/libgui/src/octave-adapter/octave-main-thread.h +++ b/libgui/src/octave-main-thread.h @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -32,19 +33,17 @@ */ class octave_main_thread : public QThread { - Q_OBJECT public: - /** Creates a new thread running octave_main. */ - octave_main_thread (); + // Create a new thread for running the octave interpreter. + octave_main_thread (void) : QThread () { } -signals: - /** This signal will be emitted when the thread is about to actually - * run octave_main. */ - void ready(); + // Start the thread and initialize and execute the octave + // interpreter. + void execute_interpreter (void); protected: - /** Runs octave_main. */ - void run (); + // Avoid exec. Run the octave interpreter in the new thread. + void run (void); }; #endif // OCTAVEMAINTHREAD_H
deleted file mode 100644 --- a/libgui/src/octave-qt-event-listener.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - -Copyright (C) 2011-2012 Jacob Dawid - -This file is part of Octave. - -Octave 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 3 of the License, or (at your -option) any later version. - -Octave 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/>. - -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "octave-qt-event-listener.h" -#include <QApplication> - -octave_qt_event_listener::octave_qt_event_listener (QObject *p) - : QObject (p), octave_event_listener () -{ -} - -void -octave_qt_event_listener::current_directory_has_changed (const std::string& directory) -{ - emit current_directory_has_changed_signal - (QString::fromUtf8 (directory.data (), directory.size ())); -} - -void -octave_qt_event_listener::about_to_exit () -{ - qApp->quit (); -} - -void -octave_qt_event_listener::entered_debug_mode () -{ emit entered_debug_mode_signal (); } - -void -octave_qt_event_listener::quit_debug_mode () -{ emit quit_debug_mode_signal (); } -
deleted file mode 100644 --- a/libgui/src/octave-qt-event-listener.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - -Copyright (C) 2011-2012 Jacob Dawid - -This file is part of Octave. - -Octave 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 3 of the License, or (at your -option) any later version. - -Octave 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/>. - -*/ - -#ifndef OCTAVEQTEVENTLISTENER_H -#define OCTAVEQTEVENTLISTENER_H - -#include <QObject> -#include <QString> -#include "octave-event-listener.h" - -class octave_qt_event_listener - : public QObject, public octave_event_listener -{ - Q_OBJECT - public: - octave_qt_event_listener (QObject *parent = 0); - - void current_directory_has_changed (const std::string& directory); - void about_to_exit (); - - void entered_debug_mode (); - void quit_debug_mode (); - -signals: - void current_directory_has_changed_signal (const QString& directory); - void entered_debug_mode_signal (); - void quit_debug_mode_signal (); -}; - -#endif // OCTAVEQTEVENTLISTENER_H
new file mode 100644 --- /dev/null +++ b/libgui/src/octave-qt-link.cc @@ -0,0 +1,321 @@ +/* + +Copyright (C) 2013 John W. Eaton +Copyright (C) 2011-2012 Jacob Dawid +Copyright (C) 2011-2012 John P. Swensen + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <QStringList> + +#include "str-vec.h" + +#include "dialog.h" +#include "error.h" +#include "workspace-element.h" + +#include "octave-qt-link.h" + +octave_qt_link::octave_qt_link (octave_main_thread *mt) + : octave_link (), main_thread (mt) +{ } + +octave_qt_link::~octave_qt_link (void) { } + +void +octave_qt_link::execute_interpreter (void) +{ + main_thread->execute_interpreter (); +} + +bool +octave_qt_link::do_exit (int status) +{ + emit exit_signal (status); + + return true; +} + +bool +octave_qt_link::do_edit_file (const std::string& file) +{ + emit edit_file_signal (QString::fromStdString (file)); + + return true; +} + +int +octave_qt_link::do_message_dialog (const std::string& dlg, + const std::string& msg, + const std::string& title) +{ + uiwidget_creator.signal_dialog (QString::fromStdString (msg), + QString::fromStdString (title), + QString::fromStdString (dlg), + QStringList (), QString (), + QStringList ()); + + // Wait while the user is responding to message box. + uiwidget_creator.wait (); + + // The GUI has sent a signal and the process has been awakened. + return uiwidget_creator.get_dialog_result (); +} + +std::string +octave_qt_link::do_question_dialog (const std::string& msg, + const std::string& title, + const std::string& btn1, + const std::string& btn2, + const std::string& btn3, + const std::string& btndef) +{ + QStringList btn; + QStringList role; + role << "AcceptRole" << "AcceptRole" << "AcceptRole"; + btn << QString::fromStdString (btn1); + if (btn2 == "") + role.removeAt (0); + else + btn << QString::fromStdString (btn2); + btn << QString::fromStdString (btn3); + + uiwidget_creator.signal_dialog (QString::fromStdString (msg), + QString::fromStdString (title), + "quest", + btn, + QString::fromStdString (btndef), + role); + + // Wait while the user is responding to message box. + uiwidget_creator.wait (); + + // The GUI has sent a signal and the process has been awakened. + return uiwidget_creator.get_dialog_button ()->toStdString (); +} + +static QStringList +make_qstring_list (const std::list<std::string>& lst) +{ + QStringList retval; + + for (std::list<std::string>::const_iterator it = lst.begin (); + it != lst.end (); it++) + { + retval.append (QString::fromStdString (*it)); + } + + return retval; +} + + +std::pair<std::list<int>, int> +octave_qt_link::do_list_dialog (const std::list<std::string>& list, + const std::string& mode, + int width, int height, + const std::list<int>& initial, + const std::string& name, + const std::list<std::string>& prompt, + const std::string& ok_string, + const std::string& cancel_string) +{ + uiwidget_creator.signal_listview (make_qstring_list (list), + QString::fromStdString (mode), + width, height, + QList<int>::fromStdList (initial), + QString::fromStdString (name), + make_qstring_list (prompt), + QString::fromStdString (ok_string), + QString::fromStdString (cancel_string)); + + // Wait while the user is responding to message box. + uiwidget_creator.wait (); + + // The GUI has sent a signal and the process has been awakened. + const QIntList *selected = uiwidget_creator.get_list_index (); + int ok = uiwidget_creator.get_dialog_result (); + + return std::pair<std::list<int>, int> (selected->toStdList (), ok); +} + +std::list<std::string> +octave_qt_link::do_input_dialog (const std::list<std::string>& prompt, + const std::string& title, + const std::list<float>& nr, + const std::list<float>& nc, + const std::list<std::string>& defaults) +{ + std::list<std::string> retval; + + uiwidget_creator.signal_inputlayout (make_qstring_list (prompt), + QString::fromStdString (title), + QFloatList::fromStdList (nr), + QFloatList::fromStdList (nc), + make_qstring_list (defaults)); + + // Wait while the user is responding to message box. + uiwidget_creator.wait (); + + // The GUI has sent a signal and the process has been awakened. + const QStringList *inputLine = uiwidget_creator.get_string_list (); + + for (QStringList::const_iterator it = inputLine->begin (); + it != inputLine->end (); it++) + { + retval.push_back (it->toStdString ()); + } + + return retval; +} + +int +octave_qt_link::do_debug_cd_or_addpath_error (const std::string& file, + const std::string& dir, + bool addpath_option) +{ + uiwidget_creator.signal_debug_cd_or_addpath (QString::fromStdString (file), + QString::fromStdString (dir), + addpath_option); + + uiwidget_creator.wait (); + + return uiwidget_creator.get_dialog_result (); +} + +void +octave_qt_link::do_change_directory (const std::string& dir) +{ + emit change_directory_signal (QString::fromStdString (dir)); +} + +void +octave_qt_link::do_set_workspace (bool top_level, + const std::list<workspace_element>& ws) +{ + QString scopes; + QStringList symbols; + QStringList class_names; + QStringList dimensions; + QStringList values; + + for (std::list<workspace_element>::const_iterator it = ws.begin (); + it != ws.end (); it++) + { + scopes.append (it->scope ()); + symbols.append (QString::fromStdString (it->symbol ())); + class_names.append (QString::fromStdString (it->class_name ())); + dimensions.append (QString::fromStdString (it->dimension ())); + values.append (QString::fromStdString (it->value ())); + } + + emit set_workspace_signal (top_level, scopes, symbols, class_names, + dimensions, values); +} + +void +octave_qt_link::do_clear_workspace (void) +{ + emit clear_workspace_signal (); +} + +void +octave_qt_link::do_set_history (const string_vector& hist) +{ + QStringList qt_hist; + + for (octave_idx_type i = 0; i < hist.length (); i++) + qt_hist.append (QString::fromStdString (hist[i])); + + emit set_history_signal (qt_hist); +} + +void +octave_qt_link::do_append_history (const std::string& hist_entry) +{ + emit append_history_signal (QString::fromStdString (hist_entry)); +} + +void +octave_qt_link::do_clear_history (void) +{ + emit clear_history_signal (); +} + +void +octave_qt_link::do_pre_input_event (void) +{ +} + +void +octave_qt_link::do_post_input_event (void) +{ +} + +void +octave_qt_link::do_enter_debugger_event (const std::string& file, int line) +{ + do_insert_debugger_pointer (file, line); + + emit enter_debugger_signal (); +} + +void +octave_qt_link::do_execute_in_debugger_event (const std::string& file, int line) +{ + do_delete_debugger_pointer (file, line); +} + +void +octave_qt_link::do_exit_debugger_event (void) +{ + emit exit_debugger_signal (); +} + +void +octave_qt_link::do_update_breakpoint (bool insert, + const std::string& file, int line) +{ + emit update_breakpoint_marker_signal (insert, QString::fromStdString (file), line); +} + +void +octave_qt_link::do_set_default_prompts (std::string& ps1, std::string& ps2, + std::string& ps4) +{ + ps1 = ">> "; + ps2 = ""; + ps4 = ""; +} + + +void +octave_qt_link::do_insert_debugger_pointer (const std::string& file, int line) +{ + emit insert_debugger_pointer_signal (QString::fromStdString (file), line); +} + +void +octave_qt_link::do_delete_debugger_pointer (const std::string& file, int line) +{ + emit delete_debugger_pointer_signal (QString::fromStdString (file), line); +}
new file mode 100644 --- /dev/null +++ b/libgui/src/octave-qt-link.h @@ -0,0 +1,160 @@ +/* + +Copyright (C) 2013 John W. Eaton +Copyright (C) 2011-2012 Jacob Dawid +Copyright (C) 2011-2012 John P. Swensen + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#ifndef OCTAVE_QT_LINK_H +#define OCTAVE_QT_LINK_H + +#include <list> +#include <string> + +#include <QList> +#include <QObject> +#include <QString> + +#include "octave-link.h" +#include "octave-main-thread.h" + +// \class OctaveLink +// \brief Provides threadsafe access to octave. +// \author Jacob Dawid +// +// This class is a wrapper around octave and provides thread safety by +// buffering access operations to octave and executing them in the +// readline event hook, which lives in the octave thread. + +class octave_qt_link : public QObject, public octave_link +{ + Q_OBJECT + +public: + + octave_qt_link (octave_main_thread *mt); + + ~octave_qt_link (void); + + void execute_interpreter (void); + + bool do_exit (int status); + + bool do_edit_file (const std::string& file); + + int do_message_dialog (const std::string& dlg, const std::string& msg, + const std::string& title); + + std::string + do_question_dialog (const std::string& msg, const std::string& title, + const std::string& btn1, const std::string& btn2, + const std::string& btn3, const std::string& btndef); + + std::pair<std::list<int>, int> + do_list_dialog (const std::list<std::string>& list, + const std::string& mode, + int width, int height, + const std::list<int>& initial_value, + const std::string& name, + const std::list<std::string>& prompt, + const std::string& ok_string, + const std::string& cancel_string); + + std::list<std::string> + do_input_dialog (const std::list<std::string>& prompt, + const std::string& title, + const std::list<float>& nr, + const std::list<float>& nc, + const std::list<std::string>& defaults); + + int + do_debug_cd_or_addpath_error (const std::string& file, + const std::string& dir, + bool addpath_option); + + void do_change_directory (const std::string& dir); + + void do_set_workspace (bool top_level, + const std::list<workspace_element>& ws); + + void do_clear_workspace (void); + + void do_set_history (const string_vector& hist); + void do_append_history (const std::string& hist_entry); + void do_clear_history (void); + + void do_pre_input_event (void); + void do_post_input_event (void); + + void do_enter_debugger_event (const std::string& file, int line); + void do_execute_in_debugger_event (const std::string& file, int line); + void do_exit_debugger_event (void); + + void do_update_breakpoint (bool insert, const std::string& file, int line); + + void do_set_default_prompts (std::string& ps1, std::string& ps2, + std::string& ps4); + +private: + + // No copying! + + octave_qt_link (const octave_qt_link&); + + octave_qt_link& operator = (const octave_qt_link&); + + void do_insert_debugger_pointer (const std::string& file, int line); + void do_delete_debugger_pointer (const std::string& file, int line); + + // Thread running octave_main. + octave_main_thread *main_thread; + +signals: + + void exit_signal (int status); + + void edit_file_signal (const QString& file); + + void change_directory_signal (const QString& dir); + + void set_workspace_signal (bool top_level, + const QString& scopes, + const QStringList& symbols, + const QStringList& class_names, + const QStringList& dimensions, + const QStringList& values); + + void clear_workspace_signal (void); + + void set_history_signal (const QStringList& hist); + void append_history_signal (const QString& hist_entry); + void clear_history_signal (void); + + void enter_debugger_signal (void); + void exit_debugger_signal (void); + + void update_breakpoint_marker_signal (bool insert, const QString& file, + int line); + + void insert_debugger_pointer_signal (const QString&, int); + void delete_debugger_pointer_signal (const QString&, int); +}; + +#endif
--- a/libgui/src/qtinfo/webinfo.cc +++ b/libgui/src/qtinfo/webinfo.cc @@ -43,14 +43,11 @@ hbox_layout->setMargin (2); vbox_layout->addLayout (hbox_layout); - _close_tab_button = new QPushButton (this); - _close_tab_button->setSizePolicy (QSizePolicy::Fixed,QSizePolicy::Preferred); - _close_tab_button->setIcon (QIcon (":/actions/icons/stop.png")); - hbox_layout->addWidget (_close_tab_button); - _tab_bar = new QTabBar (this); _tab_bar->setSizePolicy (QSizePolicy::Preferred,QSizePolicy::Preferred); _tab_bar->setExpanding (false); + _tab_bar->setTabsClosable (true); + _tab_bar->setMovable (true); hbox_layout->addWidget (_tab_bar); _zoom_in_button = new QToolButton (this); @@ -78,7 +75,7 @@ _search_check_box = new QCheckBox (tr ("Global search")); hbox_layout->addWidget (_search_check_box); - connect (_close_tab_button, SIGNAL (clicked ()), this, SLOT (close_tab ())); + connect (_tab_bar, SIGNAL (tabCloseRequested (int)), this, SLOT (close_tab (int))); connect (_tab_bar, SIGNAL (currentChanged (int)), this, SLOT (current_tab_changed (int))); connect (_zoom_in_button, SIGNAL (clicked ()), this, SLOT (zoom_in ())); connect (_zoom_out_button, SIGNAL (clicked ()), this, SLOT (zoom_out ())); @@ -170,22 +167,17 @@ } void -webinfo::close_tab () +webinfo::close_tab (int index) { - int index = _tab_bar->currentIndex (); - if (_tab_bar->tabText (index) != "Top") - closeTab (index); -} + if (_tab_bar->count () > 1) + { + QVariant tab_data = _tab_bar->tabData (index); + QWidget *w = static_cast<QWidget*> (tab_data.value<void*> ()); + _stacked_widget->removeWidget (w); + delete w; -void -webinfo::closeTab (int index) -{ - QVariant tab_data = _tab_bar->tabData (index); - QWidget *w = static_cast<QWidget*> (tab_data.value<void*> ()); - _stacked_widget->removeWidget (w); - delete w; - - _tab_bar->removeTab (index); + _tab_bar->removeTab (index); + } } void
--- a/libgui/src/qtinfo/webinfo.h +++ b/libgui/src/qtinfo/webinfo.h @@ -37,7 +37,7 @@ public slots: void link_clicked (const QUrl& link); void current_tab_changed (int index); - void close_tab (); + void close_tab (int index); void search (); void zoom_in (); void zoom_out (); @@ -46,7 +46,6 @@ QTextBrowser *_text_browser; QTabBar *_tab_bar; QStackedWidget *_stacked_widget; - QPushButton *_close_tab_button; QLineEdit *_search_line_edit; QCheckBox *_search_check_box; QToolButton *_zoom_in_button; @@ -56,5 +55,4 @@ QFont _font_web; QTextBrowser *addNewTab (const QString& name); - void closeTab(int index); };
--- a/libgui/src/resource-manager.cc +++ b/libgui/src/resource-manager.cc @@ -165,7 +165,7 @@ { QNetworkProxy::ProxyType proxyType = QNetworkProxy::NoProxy; - if (settings->value ("useProxyServer").toBool ()) + if (settings->value ("useProxyServer",false).toBool ()) { QString proxyTypeString = settings->value ("proxyType").toString (); @@ -179,7 +179,7 @@ proxy.setType (proxyType); proxy.setHostName (settings->value ("proxyHostName").toString ()); - proxy.setPort (settings->value ("proxyPort").toInt ()); + proxy.setPort (settings->value ("proxyPort",80).toInt ()); proxy.setUser (settings->value ("proxyUserName").toString ()); proxy.setPassword (settings->value ("proxyPassword").toString ());
--- a/libgui/src/resource.qrc +++ b/libgui/src/resource.qrc @@ -3,11 +3,16 @@ <file>icons/artsbuilderexecute.png</file> <file>icons/editcopy.png</file> <file>icons/editcut.png</file> + <file>icons/editdelete.png</file> <file>icons/editpaste.png</file> <file>icons/filenew.png</file> <file>icons/fileopen.png</file> <file>icons/filesave.png</file> + <file>icons/fileprint.png</file> + <file>icons/folder_new.png</file> + <file>icons/ok.png</file> <file>icons/redo.png</file> + <file>icons/reload.png</file> <file>icons/search.png</file> <file>icons/undo.png</file> <file>icons/up.png</file> @@ -22,6 +27,7 @@ <file>icons/zoom-in.png</file> <file>icons/zoom-out.png</file> <file>icons/find.png</file> + <file>icons/gear.png</file> <file>icons/chat.png</file> <file>icons/help_index.png</file> <file>icons/jabber_protocol.png</file>
--- a/libgui/src/settings-dialog.cc +++ b/libgui/src/settings-dialog.cc @@ -31,6 +31,16 @@ #include <QDir> #include <QFileInfo> +#ifdef HAVE_QSCINTILLA +#include <QScrollArea> +#include "color-picker.h" +#include <Qsci/qscilexercpp.h> +#include <Qsci/qscilexerbash.h> +#include <Qsci/qscilexerperl.h> +#include <Qsci/qscilexerbatch.h> +#include <Qsci/qscilexerdiff.h> +#endif + settings_dialog::settings_dialog (QWidget *p): QDialog (p), ui (new Ui::settings_dialog) { @@ -58,6 +68,8 @@ else ui->comboBox_language->setCurrentIndex (0); // System is default + ui->toolbar_icon_size->setValue (settings->value ("toolbar_icon_size",24).toInt ()); + // which icon has to be selected QString widget_icon_set = settings->value ("DockWidgets/widget_icon_set","NONE").toString (); @@ -66,28 +78,26 @@ ui->general_icon_graphic-> setChecked (widget_icon_set == "GRAPHIC"); ui->general_icon_letter-> setChecked (widget_icon_set == "LETTER"); - ui->useCustomFileEditor->setChecked (settings->value ("useCustomFileEditor").toBool ()); + ui->useCustomFileEditor->setChecked (settings->value ("useCustomFileEditor",false).toBool ()); ui->customFileEditor->setText (settings->value ("customFileEditor").toString ()); ui->editor_showLineNumbers->setChecked (settings->value ("editor/showLineNumbers",true).toBool () ); ui->editor_highlightCurrentLine->setChecked (settings->value ("editor/highlightCurrentLine",true).toBool () ); ui->editor_codeCompletion->setChecked (settings->value ("editor/codeCompletion",true).toBool () ); - ui->editor_fontName->setCurrentFont (QFont (settings->value ("editor/fontName","Courier").toString()) ); - ui->editor_fontSize->setValue (settings->value ("editor/fontSize",10).toInt ()); ui->editor_longWindowTitle->setChecked (settings->value ("editor/longWindowTitle",false).toBool ()); ui->editor_restoreSession->setChecked (settings->value ("editor/restoreSession",true).toBool ()); - ui->terminal_fontName->setCurrentFont (QFont (settings->value ("terminal/fontName","Courier").toString()) ); + ui->terminal_fontName->setCurrentFont (QFont (settings->value ("terminal/fontName","Courier New").toString()) ); ui->terminal_fontSize->setValue (settings->value ("terminal/fontSize",10).toInt ()); - ui->showFilenames->setChecked (settings->value ("showFilenames").toBool()); - ui->showFileSize->setChecked (settings->value ("showFileSize").toBool()); - ui->showFileType->setChecked (settings->value ("showFileType").toBool()); - ui->showLastModified->setChecked (settings->value ("showLastModified").toBool()); - ui->showHiddenFiles->setChecked (settings->value ("showHiddenFiles").toBool()); - ui->useAlternatingRowColors->setChecked (settings->value ("useAlternatingRowColors").toBool()); - ui->useProxyServer->setChecked (settings->value ("useProxyServer").toBool ()); + ui->showFileSize->setChecked (settings->value ("filesdockwidget/showFileSize",false).toBool()); + ui->showFileType->setChecked (settings->value ("filesdockwidget/showFileType",false).toBool()); + ui->showLastModified->setChecked (settings->value ("filesdockwidget/showLastModified",false).toBool()); + ui->showHiddenFiles->setChecked (settings->value ("filesdockwidget/showHiddenFiles",false).toBool()); + ui->useAlternatingRowColors->setChecked (settings->value ("filesdockwidget/useAlternatingRowColors",true).toBool()); + ui->sync_octave_directory->setChecked (settings->value ("filesdockwidget/sync_octave_directory",true).toBool()); + ui->useProxyServer->setChecked (settings->value ("useProxyServer",false).toBool ()); ui->proxyHostName->setText (settings->value ("proxyHostName").toString ()); - ui->terminal_cursorBlinking->setChecked (settings->value ("terminal/cursorBlinking").toBool ()); + ui->terminal_cursorBlinking->setChecked (settings->value ("terminal/cursorBlinking",true).toBool ()); - QString cursorType = settings->value ("terminal/cursorType").toString (); + QString cursorType = settings->value ("terminal/cursorType","ibeam").toString (); QStringList items; items << QString("0") << QString("1") << QString("2"); @@ -114,6 +124,29 @@ ui->proxyPort->setText (settings->value ("proxyPort").toString ()); ui->proxyUserName->setText (settings->value ("proxyUserName").toString ()); ui->proxyPassword->setText (settings->value ("proxyPassword").toString ()); + +#ifdef HAVE_QSCINTILLA + // editor styles: create lexer, read settings, and create dialog elements + QsciLexer *lexer; + lexer = new lexer_octave_gui (); + read_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerCPP (); + read_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerPerl (); + read_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerBatch (); + read_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerDiff (); + read_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerBash (); + read_lexer_settings (lexer,settings); + delete lexer; +#endif } settings_dialog::~settings_dialog () @@ -121,6 +154,96 @@ delete ui; } + +#ifdef HAVE_QSCINTILLA +int +settings_dialog::get_valid_lexer_styles (QsciLexer *lexer, int styles[]) +{ + int max_style = 0; + int actual_style = 0; + while (actual_style < MaxStyleNumber && max_style < MaxLexerStyles) + { + if ((lexer->description(actual_style)) != "") // valid style + styles[max_style++] = actual_style; + actual_style++; + } + return max_style; +} + +void +settings_dialog::read_lexer_settings (QsciLexer *lexer, QSettings *settings) +{ + lexer->readSettings (*settings); + int styles[MaxLexerStyles]; // array for saving valid styles (enum is not continuous) + int max_style = get_valid_lexer_styles (lexer, styles); + QGridLayout *style_grid = new QGridLayout (); + QLabel *description[max_style]; + QFontComboBox *select_font[max_style]; + QSpinBox *font_size[max_style]; + QCheckBox *attrib_font[3][max_style]; + color_picker *color[max_style]; + int default_size = 10; + QFont default_font = QFont (); + for (int i = 0; i < max_style; i++) // create dialog elements for all styles + { + QString actual_name = lexer->description (styles[i]); + QFont actual_font = lexer->font (styles[i]); + description[i] = new QLabel (actual_name); + description[i]->setWordWrap (true); + description[i]->setMaximumSize (180,QWIDGETSIZE_MAX); + description[i]->setMinimumSize (180,1); + select_font[i] = new QFontComboBox (); + select_font[i]->setObjectName (actual_name+"_font"); + font_size[i] = new QSpinBox (); + font_size[i]->setObjectName (actual_name+"_size"); + if (styles[i] == 0) // the default + { + select_font[i]->setCurrentFont (actual_font); + default_font = actual_font; + font_size[i]->setRange (6,24); + default_size = actual_font.pointSize (); + font_size[i]->setValue (default_size); + } + else // other styles + { + select_font[i]->setCurrentFont (actual_font); + if (actual_font.family () == default_font.family ()) + select_font[i]->setEditText (lexer->description (0)); + font_size[i]->setRange (-4,4); + font_size[i]->setValue (actual_font.pointSize ()-default_size); + font_size[i]->setToolTip ("Difference to the defalt size"); + } + attrib_font[0][i] = new QCheckBox (tr("b")); + attrib_font[1][i] = new QCheckBox (tr("i")); + attrib_font[2][i] = new QCheckBox (tr("u")); + attrib_font[0][i]->setChecked(Qt::Checked && actual_font.bold ()); + attrib_font[0][i]->setObjectName (actual_name+"_bold"); + attrib_font[1][i]->setChecked(Qt::Checked && actual_font.italic ()); + attrib_font[1][i]->setObjectName (actual_name+"_italic"); + attrib_font[2][i]->setChecked(Qt::Checked && actual_font.underline ()); + attrib_font[2][i]->setObjectName (actual_name+"_underline"); + color[i] = new color_picker (lexer->color (styles[i])); + color[i]->setObjectName (actual_name+"_color"); + int column = 1; + style_grid->addWidget (description[i], i,column++); + style_grid->addWidget (select_font[i], i,column++); + style_grid->addWidget (font_size[i], i,column++); + style_grid->addWidget (attrib_font[0][i],i,column++); + style_grid->addWidget (attrib_font[1][i],i,column++); + style_grid->addWidget (attrib_font[2][i],i,column++); + style_grid->addWidget (color[i], i,column++); + } + // place grid with elements into the tab + QScrollArea *scroll_area = new QScrollArea (); + QWidget *scroll_area_contents = new QWidget (); + scroll_area_contents->setObjectName (QString (lexer->language ())+"_styles"); + scroll_area_contents->setLayout (style_grid); + scroll_area->setWidget (scroll_area_contents); + ui->tabs_editor_styles->addTab (scroll_area,lexer->language ()); +} +#endif + + void settings_dialog::write_changed_settings () { @@ -142,23 +265,22 @@ settings->setValue ("language", language); // other settings + settings->setValue ("toolbar_icon_size", ui->toolbar_icon_size->value ()); settings->setValue ("useCustomFileEditor", ui->useCustomFileEditor->isChecked ()); settings->setValue ("customFileEditor", ui->customFileEditor->text ()); settings->setValue ("editor/showLineNumbers", ui->editor_showLineNumbers->isChecked ()); settings->setValue ("editor/highlightCurrentLine", ui->editor_highlightCurrentLine->isChecked ()); settings->setValue ("editor/codeCompletion", ui->editor_codeCompletion->isChecked ()); - settings->setValue ("editor/fontName", ui->editor_fontName->currentFont().family()); - settings->setValue ("editor/fontSize", ui->editor_fontSize->value()); settings->setValue ("editor/longWindowTitle", ui->editor_longWindowTitle->isChecked()); settings->setValue ("editor/restoreSession", ui->editor_restoreSession->isChecked ()); settings->setValue ("terminal/fontSize", ui->terminal_fontSize->value()); settings->setValue ("terminal/fontName", ui->terminal_fontName->currentFont().family()); - settings->setValue ("showFilenames", ui->showFilenames->isChecked ()); - settings->setValue ("showFileSize", ui->showFileSize->isChecked ()); - settings->setValue ("showFileType", ui->showFileType->isChecked ()); - settings->setValue ("showLastModified", ui->showLastModified->isChecked ()); - settings->setValue ("showHiddenFiles", ui->showHiddenFiles->isChecked ()); - settings->setValue ("useAlternatingRowColors", ui->useAlternatingRowColors->isChecked ()); + settings->setValue ("filesdockwidget/showFileSize", ui->showFileSize->isChecked ()); + settings->setValue ("filesdockwidget/showFileType", ui->showFileType->isChecked ()); + settings->setValue ("filesdockwidget/showLastModified", ui->showLastModified->isChecked ()); + settings->setValue ("filesdockwidget/showHiddenFiles", ui->showHiddenFiles->isChecked ()); + settings->setValue ("filesdockwidget/useAlternatingRowColors", ui->useAlternatingRowColors->isChecked ()); + settings->setValue ("filesdockwidget/sync_octave_directory", ui->sync_octave_directory->isChecked ()); settings->setValue ("useProxyServer", ui->useProxyServer->isChecked ()); settings->setValue ("proxyType", ui->proxyType->currentText ()); settings->setValue ("proxyHostName", ui->proxyHostName->text ()); @@ -177,4 +299,86 @@ } settings->setValue ("terminal/cursorType", cursorType); settings->sync (); + +#ifdef HAVE_QSCINTILLA + // editor styles: create lexer, get dialog contents, and write settings + QsciLexer *lexer; + lexer = new lexer_octave_gui (); + write_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerCPP (); + write_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerPerl (); + write_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerBatch (); + write_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerDiff (); + write_lexer_settings (lexer,settings); + delete lexer; + lexer = new QsciLexerBash (); + write_lexer_settings (lexer,settings); + delete lexer; +#endif } + +#ifdef HAVE_QSCINTILLA +void +settings_dialog::write_lexer_settings (QsciLexer *lexer, QSettings *settings) +{ + QWidget *tab = ui->tabs_editor_styles-> + findChild <QWidget *>(QString (lexer->language ())+"_styles"); + int styles[MaxLexerStyles]; // array for saving valid styles (enum is not continuous) + int max_style = get_valid_lexer_styles (lexer, styles); + QFontComboBox *select_font; + QSpinBox *font_size; + QCheckBox *attrib_font[3]; + color_picker *color; + int default_size = 10; + QFont default_font = QFont ("Courier New",10,-1,0); + for (int i = 0; i < max_style; i++) // get dialog elements and their contents + { + QString actual_name = lexer->description (styles[i]); + select_font = tab->findChild <QFontComboBox *>(actual_name+"_font"); + font_size = tab->findChild <QSpinBox *>(actual_name+"_size"); + attrib_font[0] = tab->findChild <QCheckBox *>(actual_name+"_bold"); + attrib_font[1] = tab->findChild <QCheckBox *>(actual_name+"_italic"); + attrib_font[2] = tab->findChild <QCheckBox *>(actual_name+"_underline"); + color = tab->findChild <color_picker *>(actual_name+"_color"); + QFont new_font = default_font; + if (select_font) + { + new_font = select_font->currentFont (); + if (styles[i] == 0) + default_font = new_font; + else + if (select_font->currentText () == lexer->description (0)) + new_font = default_font; + } + if (font_size) + { + if (styles[i] == 0) + { + default_size = font_size->value (); + new_font.setPointSize (font_size->value ()); + } + else + new_font.setPointSize (font_size->value ()+default_size); + } + if (attrib_font[0]) + new_font.setBold (attrib_font[0]->isChecked ()); + if (attrib_font[1]) + new_font.setItalic (attrib_font[1]->isChecked ()); + if (attrib_font[2]) + new_font.setUnderline (attrib_font[2]->isChecked ()); + lexer->setFont (new_font,styles[i]); + if (styles[i] == 0) + lexer->setDefaultFont (new_font); + if (color) + lexer->setColor (color->color (),styles[i]); + } + lexer->writeSettings (*settings); +} +#endif
--- a/libgui/src/settings-dialog.h +++ b/libgui/src/settings-dialog.h @@ -24,6 +24,9 @@ #define SETTINGSDIALOG_H #include <QDialog> +#ifdef HAVE_QSCINTILLA +#include "lexer-octave-gui.h" +#endif namespace Ui { @@ -39,6 +42,13 @@ private: Ui::settings_dialog * ui; +#ifdef HAVE_QSCINTILLA + void read_lexer_settings (QsciLexer *lexer, QSettings *settings); + void write_lexer_settings (QsciLexer *lexer, QSettings *settings); + int get_valid_lexer_styles (QsciLexer *lexer, int styles[]); + enum { MaxLexerStyles = 64, + MaxStyleNumber = 128 }; +#endif }; #endif // SETTINGSDIALOG_H
--- a/libgui/src/settings-dialog.ui +++ b/libgui/src/settings-dialog.ui @@ -9,20 +9,20 @@ <rect> <x>0</x> <y>0</y> - <width>600</width> - <height>400</height> + <width>700</width> + <height>480</height> </rect> </property> <property name="minimumSize"> <size> - <width>600</width> - <height>400</height> + <width>700</width> + <height>480</height> </size> </property> <property name="maximumSize"> <size> - <width>600</width> - <height>400</height> + <width>700</width> + <height>480</height> </size> </property> <property name="windowTitle"> @@ -46,105 +46,146 @@ <rect> <x>9</x> <y>10</y> - <width>561</width> - <height>131</height> + <width>651</width> + <height>371</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout_7"> <item> - <layout class="QHBoxLayout" name="horizontalLayout_6"> - <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="3" column="0"> + <widget class="QLabel" name="label_9"> + <property name="text"> + <string>Icon set for dock widgets</string> + </property> + </widget> + </item> + <item row="1" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>Language (requires restart)</string> </property> </widget> </item> - <item> - <widget class="QComboBox" name="comboBox_language"> - <property name="insertPolicy"> - <enum>QComboBox::InsertAtBottom</enum> + <item row="2" column="0"> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Icon size</string> </property> </widget> </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> + <item row="2" column="2"> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <item> + <widget class="QSpinBox" name="toolbar_icon_size"> + <property name="minimum"> + <number>16</number> + </property> + <property name="maximum"> + <number>32</number> + </property> + <property name="singleStep"> + <number>4</number> + </property> + <property name="value"> + <number>24</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="1" column="2"> + <layout class="QHBoxLayout" name="horizontalLayout_8"> + <item> + <widget class="QComboBox" name="comboBox_language"> + <property name="insertPolicy"> + <enum>QComboBox::InsertAtBottom</enum> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="3" column="2"> + <layout class="QHBoxLayout" name="horizontalLayout_9"> + <item> + <widget class="QRadioButton" name="general_icon_octave"> + <property name="text"> + <string>Octave logo only</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="general_icon_letter"> + <property name="text"> + <string>Letter icons</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="general_icon_graphic"> + <property name="text"> + <string>Graphic icons</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> </item> </layout> </item> <item> - <widget class="QGroupBox" name="groupBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="title"> - <string>Icon set for dock widgets</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> - </property> - <property name="flat"> - <bool>false</bool> - </property> - <property name="checkable"> - <bool>false</bool> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> </property> - <widget class="QRadioButton" name="general_icon_octave"> - <property name="geometry"> - <rect> - <x>0</x> - <y>20</y> - <width>151</width> - <height>21</height> - </rect> - </property> - <property name="text"> - <string>Octave logo only</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - <widget class="QRadioButton" name="general_icon_letter"> - <property name="geometry"> - <rect> - <x>0</x> - <y>40</y> - <width>151</width> - <height>21</height> - </rect> - </property> - <property name="text"> - <string>Letter icons</string> - </property> - </widget> - <widget class="QRadioButton" name="general_icon_graphic"> - <property name="geometry"> - <rect> - <x>0</x> - <y>60</y> - <width>151</width> - <height>21</height> - </rect> - </property> - <property name="text"> - <string>Graphic icons</string> - </property> - </widget> - </widget> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> </item> </layout> </widget> @@ -157,58 +198,7 @@ <item> <layout class="QVBoxLayout" name="verticalLayout_5"> <item> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QLabel" name="label_8"> - <property name="text"> - <string>Font</string> - </property> - </widget> - </item> - <item> - <widget class="QFontComboBox" name="editor_fontName"> - <property name="editable"> - <bool>false</bool> - </property> - <property name="fontFilters"> - <set>QFontComboBox::MonospacedFonts</set> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_9"> - <property name="text"> - <string>Font Size</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="editor_fontSize"> - <property name="minimum"> - <number>2</number> - </property> - <property name="maximum"> - <number>96</number> - </property> - <property name="value"> - <number>10</number> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> + <layout class="QHBoxLayout" name="horizontalLayout_4"/> </item> <item> <widget class="QCheckBox" name="editor_showLineNumbers"> @@ -273,14 +263,24 @@ </spacer> </item> <item> + <widget class="QCheckBox" name="useCustomFileEditor"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Use custom file editor</string> + </property> + </widget> + </item> + <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QCheckBox" name="useCustomFileEditor"> + <widget class="QLabel" name="customEditorLabel"> <property name="enabled"> - <bool>true</bool> + <bool>false</bool> </property> <property name="text"> - <string>Use custom file editor:</string> + <string>Command line (%f=file, %l=line):</string> </property> </widget> </item> @@ -298,6 +298,21 @@ </item> </layout> </widget> + <widget class="QWidget" name="tab_6"> + <attribute name="title"> + <string>Editor Styles</string> + </attribute> + <widget class="QTabWidget" name="tabs_editor_styles"> + <property name="geometry"> + <rect> + <x>2</x> + <y>9</y> + <width>671</width> + <height>381</height> + </rect> + </property> + </widget> + </widget> <widget class="QWidget" name="tab_5"> <attribute name="title"> <string>Terminal</string> @@ -429,13 +444,6 @@ </attribute> <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QCheckBox" name="showFilenames"> - <property name="text"> - <string>Show filenames</string> - </property> - </widget> - </item> - <item> <widget class="QCheckBox" name="showFileSize"> <property name="text"> <string>Show file size</string> @@ -464,6 +472,13 @@ </widget> </item> <item> + <widget class="QCheckBox" name="sync_octave_directory"> + <property name="text"> + <string>Synchronize octave directory with the file browser</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="useAlternatingRowColors"> <property name="text"> <string>Alternating row colors</string> @@ -822,5 +837,21 @@ </hint> </hints> </connection> + <connection> + <sender>useCustomFileEditor</sender> + <signal>toggled(bool)</signal> + <receiver>customEditorLabel</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>349</x> + <y>383</y> + </hint> + <hint type="destinationlabel"> + <x>111</x> + <y>413</y> + </hint> + </hints> + </connection> </connections> </ui>
deleted file mode 100644 --- a/libgui/src/symbol-information.cc +++ /dev/null @@ -1,113 +0,0 @@ -/* - -Copyright (C) 2011-2012 Jacob Dawid - -This file is part of Octave. - -Octave 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 3 of the License, or (at your -option) any later version. - -Octave 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/>. - -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <QString> - -#include "ov.h" -#include "symtab.h" - -#include "symbol-information.h" - -symbol_information::symbol_information (const symbol_table::symbol_record& sr) -{ - if (sr.is_local () && !sr.is_global () && !sr.is_hidden ()) - _scope = local; - else if (sr.is_global ()) - _scope = global; - else if (sr.is_persistent ()) - _scope = persistent; - else - _scope = unknown; - - _symbol = QString (sr.name ().c_str ()); - _class_name = QString (sr.varval ().class_name ().c_str ()); - octave_value ov = sr.varval (); - dim_vector dv = ov.dims (); - - // In case we have really large matrices or strings, cut them down - // for performance reasons. - QString short_value_string; - bool use_short_value_string = false; - - if (ov.is_range ()) - { - use_short_value_string = true; - - Range r = ov.range_value (); - - double base = r.base (); - double increment = r.inc (); - double limit = r.limit (); - - std::stringstream buffer; - - buffer << base << ":"; - if (increment != 1 ) - buffer << increment << ":"; - buffer << limit; - - short_value_string = QString::fromStdString (buffer.str ()); - } - else if (ov.is_matrix_type () || ov.is_cell ()) - { - if (ov.is_string ()) // a string? - { - if (ov.string_value ().length () > 30) - { - use_short_value_string = true; - short_value_string = QString ("\"") - + QString::fromStdString (ov.string_value ().substr (0, 30)) - + QString (" ... \""); - } - } - else // arrays and cell arrays - { - if (ov.numel () > 10) - { - use_short_value_string = true; - short_value_string = QString("..."); - // TODO: what kind of short version can be printed for arrays? - } - } - } - - if (use_short_value_string) - { - _value = short_value_string; - } - else - { - std::stringstream buffer; - ov.print (buffer, true); - _value = QString::fromStdString (buffer.str ()); - } - _value.replace("\n", " "); - - _dimension = QString::fromStdString (dv.str ()); - - _hash = _scope + qHash (_symbol) + qHash (_class_name) + qHash (_value) - + qHash (_dimension); -}
deleted file mode 100644 --- a/libgui/src/symbol-information.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - -Copyright (C) 2011-2012 Jacob Dawid - -This file is part of Octave. - -Octave 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 3 of the License, or (at your -option) any later version. - -Octave 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/>. - -*/ - -#ifndef SYMBOLINFORMATION_H -#define SYMBOLINFORMATION_H - -// FIXME -- we should not be including config.h in header files. - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <QString> -#include <QHash> - -#include "symtab.h" - -/** - * \struct symbol_information - * \brief Meta-information over a symbol-table entry. - * \author Jacob Dawid - * This struct is used to store meta information over a symbol entry. - * It reduces memory consumption, since it only stores relevant data - * about a symbol-table entry that will be used in the model for the - * graphical user interface. - */ -class symbol_information -{ -public: - - enum Scope - { - unknown = 0, - local = 1, - global = 2, - persistent = 3 - }; - - symbol_information (const symbol_table::symbol_record& symbol_record); - - symbol_information (const symbol_information& x) - : _scope (x._scope), _symbol (x._symbol), _class_name (x._class_name), - _value (x._value), _dimension (x._dimension), _hash (x._hash) - { } - - symbol_information operator = (const symbol_information& x) - { - if (this != &x) - { - _scope = x._scope; - _symbol = x._symbol; - _class_name = x._class_name; - _value = x._value; - _dimension = x._dimension; - _hash = x._hash; - } - - return *this; - } - - ~symbol_information (void) { } - - QString symbol (void) const { return _symbol; } - QString class_name (void) const { return _class_name; } - QString value (void) const - { - return QString::fromUtf8 (_value.toStdString ().data (), - _value.toStdString ().size ()); - } - QString dimension (void) const { return _dimension; } - Scope scope (void) const { return _scope; } - - friend bool - operator == (const symbol_information& a, const symbol_information& b) - { - return (a.hash () == b.hash () - && a.scope () == b.scope () - && a.symbol () == b.symbol () - && a.class_name () == b.class_name () - && a.value () == b.value () - && a.dimension () == b.dimension ()); - } - -private: - - // FIXME -- this is not really the scope of the symbol. - Scope _scope; - - QString _symbol; - QString _class_name; - QString _value; - QString _dimension; - - int _hash; - - int hash (void) const { return _hash; } -}; - -#endif // SYMBOLINFORMATION_H
rename from libgui/src/terminal-dockwidget.cc rename to libgui/src/terminal-dock-widget.cc --- a/libgui/src/terminal-dockwidget.cc +++ b/libgui/src/terminal-dock-widget.cc @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -24,18 +25,75 @@ #include <config.h> #endif -#include "terminal-dockwidget.h" +#include "terminal-dock-widget.h" -terminal_dock_widget::terminal_dock_widget (QTerminal *terminal, QWidget *p) - : octave_dock_widget (p) +terminal_dock_widget::terminal_dock_widget (QWidget *p) + : octave_dock_widget (p), terminal (new QTerminal (p)) { + terminal->setObjectName ("OctaveTerminal"); + terminal->setFocusPolicy (Qt::StrongFocus); + setObjectName ("TerminalDockWidget"); setWindowIcon (QIcon(":/actions/icons/logo.png")); setWindowTitle (tr ("Command Window")); setWidget (terminal); - connect (this, SIGNAL (visibilityChanged (bool)), this, SLOT (handle_visibility_changed (bool))); - // topLevelChanged is emitted when floating property changes (floating = true) - connect (this, SIGNAL (topLevelChanged(bool)), this, SLOT(top_level_changed(bool))); + connect (parent (), SIGNAL (settings_changed (const QSettings *)), + this, SLOT (notice_settings (const QSettings *))); + + connect (this, SIGNAL (visibilityChanged (bool)), + this, SLOT (handle_visibility (bool))); + + connect (parent (), SIGNAL (relay_command_signal (const QString&)), + this, SLOT (relay_command (const QString&))); + + // Forward signals to QTerminal widget. + + connect (this, SIGNAL (notice_settings_signal (const QSettings *)), + terminal, SLOT (notice_settings (const QSettings *))); + + connect (this, SIGNAL (relay_command_signal (const QString&)), + terminal, SLOT (relay_command (const QString&))); + + connect (this, SIGNAL (copyClipboard_signal (void)), + terminal, SLOT (copyClipboard (void))); + + connect (this, SIGNAL (pasteClipboard_signal (void)), + terminal, SLOT (pasteClipboard (void))); +} + +void +terminal_dock_widget::notice_settings (const QSettings *settings) +{ + emit notice_settings_signal (settings); } +void +terminal_dock_widget::relay_command (const QString& command) +{ + emit relay_command_signal (command); +} + +void +terminal_dock_widget::copyClipboard (void) +{ + emit copyClipboard_signal (); +} + +void +terminal_dock_widget::pasteClipboard (void) +{ + emit pasteClipboard_signal (); +} + +void +terminal_dock_widget::focus (void) +{ + octave_dock_widget::focus (); + + QWidget *w = widget (); + + w->setFocus (); + w->activateWindow (); + w->raise (); +}
rename from libgui/src/terminal-dockwidget.h rename to libgui/src/terminal-dock-widget.h --- a/libgui/src/terminal-dockwidget.h +++ b/libgui/src/terminal-dock-widget.h @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -23,22 +24,46 @@ #ifndef TERMINALDOCKWIDGET_H #define TERMINALDOCKWIDGET_H +#include <QString> + #include "QTerminal.h" #include "octave-dock-widget.h" class terminal_dock_widget : public octave_dock_widget { Q_OBJECT - public: - terminal_dock_widget (QTerminal *terminal, QWidget *parent = 0); + +public: + + terminal_dock_widget (QWidget *parent = 0); signals: public slots: -protected: + void notice_settings (const QSettings *settings); + + void relay_command (const QString& command); + + void copyClipboard (void); + + void pasteClipboard (void); + + void focus (void); + +signals: + void notice_settings_signal (const QSettings *settings); + + void relay_command_signal (const QString& command); + + void copyClipboard_signal (void); + + void pasteClipboard_signal (void); + +private: + + QTerminal *terminal; }; - #endif // TERMINALDOCKWIDGET_H
--- a/libgui/src/workspace-model.cc +++ b/libgui/src/workspace-model.cc @@ -1,6 +1,6 @@ - /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -26,209 +26,190 @@ #endif #include <QTreeWidget> -#include <QTime> -#include <list> - -#include "symtab.h" -#include "variables.h" +#include "utils.h" #include "workspace-model.h" -#include "octave-link.h" -workspace_model::workspace_model(QObject *p) - : QAbstractItemModel (p) +workspace_model::workspace_model (QObject *p) + : QAbstractTableModel (p) { - QList<QVariant> rootData; - rootData << tr ("Name") << tr ("Class") << tr("Dimension") << tr ("Value"); - _rootItem = new tree_item(rootData); - - insert_top_level_item(0, new tree_item ("Local")); - insert_top_level_item(1, new tree_item ("Global")); - insert_top_level_item(2, new tree_item ("Persistent")); - - connect(&_update_workspace_model_timer, - SIGNAL (timeout ()), - this, - SLOT (request_update_workspace())); - - _update_event_enabled = true; - _update_workspace_model_timer.setInterval (500); - _update_workspace_model_timer.setSingleShot (false); - _update_workspace_model_timer.start (); -} - -workspace_model::~workspace_model() -{ - delete _rootItem; + _columnNames.append (tr ("Name")); + _columnNames.append (tr ("Class")); + _columnNames.append (tr ("Dimension")); + _columnNames.append (tr ("Value")); + _columnNames.append (tr ("Storage Class")); } -void -workspace_model::request_update_workspace () -{ - if (_update_event_enabled) - { - _update_event_enabled = false; // no more update until this one is processed - octave_link::post_event (this, &workspace_model::update_workspace_callback); - } -} - -QModelIndex -workspace_model::index(int row, int column, const QModelIndex &p) const +int +workspace_model::rowCount(const QModelIndex& p) const { - if (!hasIndex(row, column, p)) - return QModelIndex(); - - tree_item *parentItem; - - if (!p.isValid()) - parentItem = _rootItem; - else - parentItem = static_cast<tree_item*>(p.internalPointer()); - - tree_item *childItem = parentItem->child(row); - if (childItem) - return createIndex(row, column, childItem); - else - return QModelIndex(); -} - -QModelIndex -workspace_model::parent(const QModelIndex &idx) const -{ - if (!idx.isValid()) - return QModelIndex(); - - tree_item *childItem = static_cast<tree_item*>(idx.internalPointer()); - - if (childItem) - { - tree_item *parentItem = childItem->parent(); - - if (! parentItem || parentItem == _rootItem) - return QModelIndex(); - - return createIndex(parentItem->row(), 0, parentItem); - } - else - return QModelIndex (); + return _symbols.size (); } int -workspace_model::rowCount(const QModelIndex &p) const -{ - tree_item *parentItem; - if (p.column() > 0) - return 0; - - if (!p.isValid()) - parentItem = _rootItem; - else - parentItem = static_cast<tree_item*>(p.internalPointer()); - - return parentItem->child_count(); -} - -int -workspace_model::columnCount(const QModelIndex &p) const +workspace_model::columnCount (const QModelIndex& p) const { - if (p.isValid()) - return static_cast<tree_item*>(p.internalPointer())->column_count(); - else - return _rootItem->column_count(); -} - -void -workspace_model::insert_top_level_item(int at, tree_item *treeItem) -{ - _rootItem->insert_child_item(at, treeItem); -} - -tree_item * -workspace_model::top_level_item (int at) -{ - return _rootItem->child(at); + return _columnNames.size (); } Qt::ItemFlags -workspace_model::flags(const QModelIndex &idx) const +workspace_model::flags (const QModelIndex& idx) const { - if (!idx.isValid()) - return 0; + Qt::ItemFlags retval = 0; + + if (idx.isValid ()) + { + retval |= Qt::ItemIsEnabled; + + if (_top_level && idx.column () == 0) + retval |= Qt::ItemIsSelectable; + } - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + return retval; +} + +QVariant +workspace_model::headerData (int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return _columnNames[section]; + else + return QVariant(); } QVariant -workspace_model::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return _rootItem->data(section); - - return QVariant(); -} - -QVariant -workspace_model::data(const QModelIndex &idx, int role) const -{ - if (!idx.isValid()) - return QVariant(); - - if (role != Qt::DisplayRole) - return QVariant(); - - tree_item *item = static_cast<tree_item*>(idx.internalPointer()); - - return item->data(idx.column()); -} - -void -workspace_model::update_workspace_callback (void) +workspace_model::data (const QModelIndex& idx, int role) const { - std::list < symbol_table::symbol_record > symbolTable = symbol_table::all_variables (); - - _symbol_information.clear (); - for (std::list < symbol_table::symbol_record > ::iterator iterator = symbolTable.begin (); - iterator != symbolTable.end (); iterator++) - _symbol_information.push_back (symbol_information (*iterator)); - - beginResetModel(); - top_level_item (0)->delete_child_items (); - top_level_item (1)->delete_child_items (); - top_level_item (2)->delete_child_items (); + QVariant retval; - foreach (const symbol_information& s, _symbol_information) + if (idx.isValid () + && (role == Qt::DisplayRole + || (idx.column () == 0 && (role == Qt::EditRole + || role == Qt::ToolTipRole)))) { - tree_item *child = new tree_item (); + switch (idx.column ()) + { + case 0: + if (role == Qt::ToolTipRole) + retval = QVariant (tr ("Right click to copy, rename, or display")); + else + retval = QVariant (_symbols[idx.row()]); + break; - child->set_data (0, s.symbol ()); - child->set_data (1, s.class_name ()); - child->set_data (2, s.dimension ()); - child->set_data (3, s.value ()); - - switch (s.scope ()) - { - case symbol_information::local: - top_level_item (0)->add_child (child); + case 1: + retval = QVariant (_class_names[idx.row()]); break; - case symbol_information::global: - top_level_item (1)->add_child (child); + case 2: + retval = QVariant (_dimensions[idx.row()]); + break; + + case 3: + retval = QVariant (_values[idx.row()]); break; - case symbol_information::persistent: - top_level_item (2)->add_child (child); - break; + case 4: + { + QChar c = _scopes[idx.row()]; + + if (c == 'g') + retval = QVariant (tr ("global")); + else if (c == 'p') + retval = QVariant (tr ("persistent")); + else if (c == 'a') + retval = QVariant (tr ("automatic")); + else if (c == 'f') + retval = QVariant (tr ("function parameter")); + else if (c == 'h') + retval = QVariant (tr ("hidden")); + else if (c == 'i') + retval = QVariant (tr ("inherited")); + } default: break; } } - endResetModel(); - emit model_changed(); + return retval; +} + +bool +workspace_model::setData (const QModelIndex& idx, const QVariant& value, + int role) +{ + bool retval = false; + + if (idx.column () == 0 && role == Qt::EditRole) + { + QString qold_name = _symbols[idx.row()]; + + QString qnew_name = value.toString (); + + std::string new_name = qnew_name.toStdString (); + + if (valid_identifier (new_name)) + { + emit rename_variable (qold_name, qnew_name); + + retval = true; + } + } + + return retval; +} + - // update is processed, re-enable further updates events triggered by timer - _update_event_enabled = true; +void +workspace_model::set_workspace (bool top_level, + const QString& scopes, + const QStringList& symbols, + const QStringList& class_names, + const QStringList& dimensions, + const QStringList& values) +{ + _top_level = top_level; + _scopes = scopes; + _symbols = symbols; + _class_names = class_names; + _dimensions = dimensions; + _values = values; + + update_table (); + + emit model_changed (); +} + +void +workspace_model::clear_workspace (void) +{ + clear_data (); + update_table (); + emit model_changed (); } + +void +workspace_model::clear_data (void) +{ + _top_level = false; + _scopes = QString (); + _symbols = QStringList (); + _class_names = QStringList (); + _dimensions = QStringList (); + _values = QStringList (); +} + +void +workspace_model::update_table (void) +{ + beginResetModel(); + + // Nothing to do except tell the world to recalc. + + endResetModel (); + + emit model_changed (); +}
--- a/libgui/src/workspace-model.h +++ b/libgui/src/workspace-model.h @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -20,137 +21,71 @@ */ -#ifndef WORKSPACEMODEL_H -#define WORKSPACEMODEL_H +#if !defined (workspace_model_h) +#define workspace_model_h 1 -// Qt includes -#include <QAbstractItemModel> +#include <QAbstractTableModel> #include <QVector> #include <QSemaphore> -#include <QTimer> - -#include "symbol-information.h" - -class tree_item -{ -public: - tree_item (const QList<QVariant> &d, tree_item *p = 0) { - _parent_item = p; - _item_data = d; - } - - tree_item (QVariant d = QVariant(), tree_item *p = 0) { - QList<QVariant> variantList; - variantList << d << QVariant () << QVariant () << QVariant (); - _parent_item = p; - _item_data = variantList; - } - - ~tree_item () { - qDeleteAll (_child_items); - } - - void insert_child_item (int at, tree_item *item) { - item->_parent_item = this; - _child_items.insert (at, item); - } - - void add_child (tree_item *item) { - item->_parent_item = this; - _child_items.append (item); - } - - void delete_child_items () { - qDeleteAll (_child_items); - _child_items.clear (); - } - - void remove_child (tree_item *item) { - _child_items.removeAll (item); - } - - QVariant data (int column) const - { - return _item_data[column]; - } - - void set_data (int column, QVariant d) - { - _item_data[column] = d; - } - - tree_item *child (int r) { - return _child_items[r]; - } - - int child_count () const { - return _child_items.count(); - } - - int column_count () const - { - return _item_data.count(); - } - - int row () const { - if (_parent_item) - return _parent_item->_child_items.indexOf (const_cast<tree_item*>(this)); - - return 0; - } - - tree_item *parent () - { - return _parent_item; - } - -private: - QList<tree_item*> _child_items; - QList<QVariant> _item_data; - tree_item *_parent_item; -}; +#include <QStringList> class workspace_model - : public QAbstractItemModel + : public QAbstractTableModel { Q_OBJECT - public: +public: + workspace_model (QObject *parent = 0); - ~workspace_model (); + + ~workspace_model (void) { } + + QVariant data (const QModelIndex& index, int role) const; - QVariant data (const QModelIndex &index, int role) const; - Qt::ItemFlags flags (const QModelIndex &index) const; + bool setData (const QModelIndex& index, const QVariant& value, + int role = Qt::EditRole); + + Qt::ItemFlags flags (const QModelIndex& index) const; + QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - QModelIndex index (int row, int column, - const QModelIndex &parent = QModelIndex ()) const; - QModelIndex parent (const QModelIndex &index) const; - int rowCount (const QModelIndex &parent = QModelIndex ()) const; - int columnCount (const QModelIndex &parent = QModelIndex ()) const; + + int rowCount (const QModelIndex& parent = QModelIndex ()) const; - void insert_top_level_item (int at, tree_item *treeItem); - tree_item *top_level_item (int at); + int columnCount (const QModelIndex& parent = QModelIndex ()) const; + + bool is_top_level (void) const { return _top_level; } public slots: - void request_update_workspace (); + + void set_workspace (bool top_level, + const QString& scopes, + const QStringList& symbols, + const QStringList& class_names, + const QStringList& dimensions, + const QStringList& values); + + void clear_workspace (void); signals: - void model_changed (); + + void model_changed (void); + + void rename_variable (const QString& old_name, const QString& new_name); private: - bool _update_event_enabled; - - void update_workspace_callback (void); + void clear_data (void); + void update_table (void); - /** Timer for periodically updating the workspace model from the current - * symbol information. */ - QTimer _update_workspace_model_timer; + bool _top_level; + QString _scopes; + QStringList _symbols; + QStringList _class_names; + QStringList _dimensions; + QStringList _values; - /** Stores the current symbol information. */ - QList <symbol_information> _symbol_information; - tree_item *_rootItem; + QStringList _columnNames; }; -#endif // WORKSPACEMODEL_H +#endif
--- a/libgui/src/workspace-view.cc +++ b/libgui/src/workspace-view.cc @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -24,37 +25,37 @@ #include <config.h> #endif -#include "workspace-view.h" -#include "resource-manager.h" +#include <QInputDialog> +#include <QApplication> +#include <QClipboard> +#include <QMessageBox> +#include <QLineEdit> #include <QHeaderView> #include <QHBoxLayout> #include <QVBoxLayout> #include <QPushButton> +#include <QMenu> + +#include "workspace-view.h" +#include "resource-manager.h" workspace_view::workspace_view (QWidget *p) - : QDockWidget (p) + : octave_dock_widget (p), view (new QTableView (this)) { setObjectName ("WorkspaceView"); - setWindowIcon (QIcon(":/actions/icons/logo.png")); + setWindowIcon (QIcon (":/actions/icons/logo.png")); setWindowTitle (tr ("Workspace")); - - // Create a new workspace model. - _workspace_model = new workspace_model (); + setStatusTip (tr ("View the variables in the active workspace.")); - _workspace_tree_view = new QTreeView (this); // Create a new tree view. - _workspace_tree_view->setHeaderHidden (false); // Do not show header columns. - _workspace_tree_view->setAlternatingRowColors (true); // Activate alternating row colors. - _workspace_tree_view->setAnimated (false); // Deactivate animations because of strange glitches. - _workspace_tree_view->setTextElideMode (Qt::ElideRight);// Elide text to the right side of the cells. - _workspace_tree_view->setWordWrap (false); // No wordwrapping in cells. - _workspace_tree_view->setModel (_workspace_model); // Assign model. + view->setWordWrap (false); + view->setContextMenuPolicy (Qt::CustomContextMenu); // Set an empty widget, so we can assign a layout to it. setWidget (new QWidget (this)); // Create a new layout and add widgets to it. QVBoxLayout *vbox_layout = new QVBoxLayout (); - vbox_layout->addWidget (_workspace_tree_view); + vbox_layout->addWidget (view); vbox_layout->setMargin (2); // Set the empty widget to have our layout. @@ -64,151 +65,27 @@ QSettings *settings = resource_manager::get_settings (); - // FIXME -- what should happen if settings is 0? - - _explicit_collapse.local = settings->value ("workspaceview/local_collapsed", false).toBool (); - _explicit_collapse.global = settings->value ("workspaceview/global_collapsed", false).toBool ();; - _explicit_collapse.persistent = settings->value ("workspaceview/persistent_collapsed", false).toBool ();; - // Initialize column order and width of the workspace - _workspace_tree_view->header ()->restoreState (settings->value("workspaceview/column_state").toByteArray ()); + view->horizontalHeader ()->restoreState (settings->value ("workspaceview/column_state").toByteArray ()); // Connect signals and slots. - connect (this, SIGNAL (visibilityChanged (bool)), - this, SLOT(handle_visibility_changed (bool))); - - connect (_workspace_model, SIGNAL (model_changed ()), - this, SLOT (model_changed ())); - - connect (_workspace_tree_view, SIGNAL (collapsed (QModelIndex)), - this, SLOT (collapse_requested (QModelIndex))); - connect (_workspace_tree_view, SIGNAL (expanded (QModelIndex)), - this, SLOT (expand_requested (QModelIndex))); - - connect (_workspace_tree_view, SIGNAL (doubleClicked (QModelIndex)), - this, SLOT (item_double_clicked (QModelIndex))); - - // topLevelChanged is emitted when floating property changes (floating = true) - connect (this, SIGNAL (topLevelChanged(bool)), this, SLOT(top_level_changed(bool))); -} + connect (view, SIGNAL (customContextMenuRequested (const QPoint&)), + this, SLOT(contextmenu_requested (const QPoint&))); -workspace_view::~workspace_view () -{ - QSettings *settings = resource_manager::get_settings (); - settings->setValue("workspaceview/local_collapsed", _explicit_collapse.local); - settings->setValue("workspaceview/global_collapsed", _explicit_collapse.global); - settings->setValue("workspaceview/persistent_collapsed", _explicit_collapse.persistent); - settings->setValue("workspaceview/column_state", _workspace_tree_view->header ()->saveState ()); - settings->sync (); -} - -void -workspace_view::handle_visibility_changed (bool visible) -{ - if (visible) - emit active_changed (true); + connect (this, SIGNAL (command_requested (const QString&)), + p, SLOT (handle_command_double_clicked (const QString&))); } -void -workspace_view::model_changed () -{ - // This code is very quirky and requires some explanation. - // Usually, we should not deal with collapsing or expanding ourselves, - // because the view itself determines (based on the model) whether it - // is appropriate to collapse or expand items. - // - // Now, the logic requires that we update our model item by item, which - // would make it work correctly, but this is extremely slow and scales - // very bad (O(n^2)). That's why we throw away our model and rebuild it - // completely from scratch (O(n)), which is why the view renders all - // displayed data as invalid. - // - // In order to make collapsing/expanding work again, we need to set - // flags ourselves here. - - QModelIndex local_model_index = _workspace_model->index (0, 0); - QModelIndex global_model_index = _workspace_model->index (1, 0); - QModelIndex persistent_model_index = _workspace_model->index (2, 0); - - if (_explicit_collapse.local) { - _workspace_tree_view->collapse (local_model_index); - } else { - _workspace_tree_view->expand (local_model_index); - } - - if (_explicit_collapse.global) { - _workspace_tree_view->collapse (global_model_index); - } else { - _workspace_tree_view->expand (global_model_index); - } - - if (_explicit_collapse.persistent) { - _workspace_tree_view->collapse (persistent_model_index); - } else { - _workspace_tree_view->expand (persistent_model_index); - } -} - -void -workspace_view::collapse_requested (QModelIndex index) +workspace_view::~workspace_view (void) { - // This code is very quirky and requires some explanation. - // Usually, we should not deal with collapsing or expanding ourselves, - // because the view itself determines (based on the model) whether it - // is appropriate to collapse or expand items. - // - // Now, the logic requires that we update our model item by item, which - // would make it work correctly, but this is extremely slow and scales - // very bad (O(n^2)). That's why we throw away our model and rebuild it - // completely from scratch (O(n)), which is why the view renders all - // displayed data as invalid. - // - // In order to make collapsing/expanding work again, we need to set - // flags ourselves here. - QMap<int, QVariant> item_data - = _workspace_model->itemData (index); - - if (item_data[0] == "Local") - _explicit_collapse.local = true; - if (item_data[0] == "Global") - _explicit_collapse.global = true; - if (item_data[0] == "Persistent") - _explicit_collapse.persistent = true; -} + QSettings *settings = resource_manager::get_settings (); -void -workspace_view::expand_requested (QModelIndex index) -{ - // This code is very quirky and requires some explanation. - // Usually, we should not deal with collapsing or expanding ourselves, - // because the view itself determines (based on the model) whether it - // is appropriate to collapse or expand items. - // - // Now, the logic requires that we update our model item by item, which - // would make it work correctly, but this is extremely slow and scales - // very bad (O(n^2)). That's why we throw away our model and rebuild it - // completely from scratch (O(n)), which is why the view renders all - // displayed data as invalid. - // - // In order to make collapsing/expanding work again, we need to do set - // flags ourselves here. - QMap<int, QVariant> item_data - = _workspace_model->itemData (index); + settings->setValue("workspaceview/column_state", + view->horizontalHeader ()->saveState ()); - if (item_data[0] == "Local") - _explicit_collapse.local = false; - if (item_data[0] == "Global") - _explicit_collapse.global = false; - if (item_data[0] == "Persistent") - _explicit_collapse.persistent = false; -} - -void -workspace_view::item_double_clicked (QModelIndex) -{ - // TODO: Implement opening a dialog that allows the user to change a variable in the workspace. + settings->sync (); } void @@ -218,13 +95,136 @@ QDockWidget::closeEvent (e); } -// slot for signal that is emitted when floating property changes void -workspace_view::top_level_changed (bool floating) +workspace_view::contextmenu_requested (const QPoint& pos) { - if(floating) + QMenu menu (this); + + QModelIndex index = view->indexAt (pos); + QAbstractItemModel *m = view->model (); + + // if it isnt Local, Glocal etc, allow the ctx menu + if (index.isValid() && index.column () == 0) { - setWindowFlags(Qt::Window); // make a window from the widget when floating - show(); // make it visible again since setWindowFlags hides it + index = index.sibling (index.row(), 0); + + QMap<int, QVariant> item_data = m->itemData (index); + + QString var_name = item_data[0].toString (); + + menu.addAction (tr ("Copy"), this, + SLOT (handle_contextmenu_copy ())); + + QAction *rename = menu.addAction (tr ("Rename"), this, + SLOT (handle_contextmenu_rename ())); + + const workspace_model *wm = static_cast<const workspace_model *> (m); + + if (! wm->is_top_level ()) + { + rename->setDisabled (true); + rename->setToolTip (tr ("Only top-level symbols may be renamed.")); + } + + menu.addSeparator (); + + menu.addAction ("disp(" + var_name + ")", this, + SLOT (handle_contextmenu_disp ())); + + menu.addAction ("plot(" + var_name + ")", this, + SLOT (handle_contextmenu_plot ())); + + menu.addAction ("stem(" + var_name + ")", this, + SLOT (handle_contextmenu_stem ())); + + menu.exec (view->mapToGlobal (pos)); + } +} + +void +workspace_view::handle_contextmenu_copy (void) +{ + QModelIndex index = view->currentIndex (); + + if (index.isValid ()) + { + index = index.sibling(index.row(), 0); + + QAbstractItemModel *m = view->model (); + + QMap<int, QVariant> item_data = m->itemData (index); + + QString var_name = item_data[0].toString (); + + QClipboard *clipboard = QApplication::clipboard (); + + clipboard->setText (var_name); } } + +void +workspace_view::handle_contextmenu_rename (void) +{ + QModelIndex index = view->currentIndex (); + + if (index.isValid ()) + { + index = index.sibling(index.row(), 0); + + QAbstractItemModel *m = view->model (); + + QMap<int, QVariant> item_data = m->itemData (index); + + QString var_name = item_data[0].toString (); + + QInputDialog* inputDialog = new QInputDialog (); + + inputDialog->setOptions (QInputDialog::NoButtons); + + bool ok = false; + + QString new_name + = inputDialog->getText (0, "Rename Variable", "New name:", + QLineEdit::Normal, var_name, &ok); + + if (ok && ! new_name.isEmpty ()) + m->setData (index, new_name, Qt::EditRole); + } +} + +void +workspace_view::handle_contextmenu_disp (void) +{ + relay_contextmenu_command ("disp"); +} + +void +workspace_view::handle_contextmenu_plot (void) +{ + relay_contextmenu_command ("figure;\nplot"); +} + +void +workspace_view::handle_contextmenu_stem (void) +{ + relay_contextmenu_command ("figure;\nstem"); +} + +void +workspace_view::relay_contextmenu_command (const QString& cmdname) +{ + QModelIndex index = view->currentIndex (); + + if (index.isValid ()) + { + index = index.sibling(index.row(), 0); + + QAbstractItemModel *m = view->model (); + + QMap<int, QVariant> item_data = m->itemData (index); + + QString var_name = item_data[0].toString (); + + emit command_requested (cmdname + "(" + var_name + ")\n"); + } +}
--- a/libgui/src/workspace-view.h +++ b/libgui/src/workspace-view.h @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid This file is part of Octave. @@ -20,52 +21,55 @@ */ -#ifndef WORKSPACEVIEW_H -#define WORKSPACEVIEW_H +#if !defined (workspace_view_h) +#define workspace_view_h 1 -#include <QDockWidget> -#include <QTreeView> +#include <QItemDelegate> +#include <QTableView> #include <QSemaphore> +#include "octave-dock-widget.h" #include "workspace-model.h" -class workspace_view : public QDockWidget +class workspace_view : public octave_dock_widget { Q_OBJECT - public: - workspace_view (QWidget * parent = 0); - ~workspace_view (); + +public: + + workspace_view (QWidget *parent = 0); -public slots: - void handle_visibility_changed (bool visible); - void model_changed (); - /** Slot when floating property changes */ - void top_level_changed (bool floating); + ~workspace_view (void); + +public: + + void setModel (workspace_model *model) { view->setModel (model); } signals: - /** Custom signal that tells if a user has clicke away that dock widget. */ - void active_changed (bool active); + + /** signal that user had requested a command on a variable */ + void command_requested (const QString& cmd); protected: + void closeEvent (QCloseEvent *event); protected slots: - void collapse_requested (QModelIndex index); - void expand_requested (QModelIndex index); - void item_double_clicked (QModelIndex index); + + void contextmenu_requested (const QPoint& pos); + + // context menu slots + void handle_contextmenu_copy (void); + void handle_contextmenu_rename (void); + void handle_contextmenu_disp (void); + void handle_contextmenu_plot (void); + void handle_contextmenu_stem (void); private: - QTreeView *_workspace_tree_view; - - /** Stores the current workspace model. */ - workspace_model *_workspace_model; - struct - { - bool local; - bool global; - bool persistent; - } _explicit_collapse; + void relay_contextmenu_command (const QString& cmdname); + + QTableView *view; }; -#endif // WORKSPACEVIEW_H +#endif
--- a/libinterp/Makefile.am +++ b/libinterp/Makefile.am @@ -110,6 +110,7 @@ octave.h \ $(OCTAVE_VALUE_INC) \ $(PARSE_TREE_INC) \ + $(PARSER_INC) \ $(OPERATORS_INC) \ $(INTERP_CORE_INC) \ $(INTERPFCN_INC) @@ -125,6 +126,7 @@ octave.cc \ $(OCTAVE_VALUE_SRC) \ $(PARSE_TREE_SRC) \ + $(PARSER_SRC) \ $(INTERP_CORE_SRC) \ $(INTERPFCN_SRC) \ $(COREFCN_SRC) @@ -178,6 +180,7 @@ liboctinterp_la_LIBADD = \ octave-value/liboctave-value.la \ parse-tree/libparse-tree.la \ + parse-tree/libparser.la \ interp-core/libinterp-core.la \ interpfcn/libinterpfcn.la \ corefcn/libcorefcn.la \
--- a/libinterp/corefcn/max.cc +++ b/libinterp/corefcn/max.cc @@ -74,6 +74,47 @@ return retval; } +// Matlab returns double arrays for min/max operations on character +// arrays, so we specialize here to get that behavior. Other possible +// solutions are to convert the argument to double here and call the +// code for double, but that could waste memory, or to have the +// underlying charNDArray::min/max functions return NDArray instead of +// charNDArray, but that is inconsistent with the way other min/max +// functions work. + +template <> +octave_value_list +do_minmax_red_op<charNDArray> (const octave_value& arg, + int nargout, int dim, bool ismin) +{ + octave_value_list retval; + charNDArray array = octave_value_extract<charNDArray> (arg); + + if (error_state) + return retval; + + if (nargout == 2) + { + retval.resize (2); + Array<octave_idx_type> idx; + if (ismin) + retval(0) = NDArray (array.min (idx, dim)); + else + retval(0) = NDArray (array.max (idx, dim)); + + retval(1) = octave_value (idx, true, true); + } + else + { + if (ismin) + retval(0) = NDArray (array.min (dim)); + else + retval(0) = NDArray (array.max (dim)); + } + + return retval; +} + // Specialization for bool arrays. template <> octave_value_list @@ -154,6 +195,61 @@ return retval; } +// Matlab returns double arrays for min/max operations on character +// arrays, so we specialize here to get that behavior. Other possible +// solutions are to convert the arguments to double here and call the +// code for double, but that could waste a lot of memory, or to have the +// underlying charNDArray::min/max functions return NDArray instead of +// charNDArray, but that is inconsistent with the way other min/max +// functions work. + +template <> +octave_value +do_minmax_bin_op<charNDArray> (const octave_value& argx, + const octave_value& argy, bool ismin) +{ + octave_value retval; + + if (argx.is_scalar_type () == 1) + { + char x = octave_value_extract<char> (argx); + charNDArray y = octave_value_extract<charNDArray> (argy); + + if (error_state) + ; + else if (ismin) + retval = NDArray (min (x, y)); + else + retval = NDArray (max (x, y)); + } + else if (argy.is_scalar_type () == 1) + { + charNDArray x = octave_value_extract<charNDArray> (argx); + char y = octave_value_extract<char> (argy); + + if (error_state) + ; + else if (ismin) + retval = NDArray (min (x, y)); + else + retval = NDArray (max (x, y)); + } + else + { + charNDArray x = octave_value_extract<charNDArray> (argx); + charNDArray y = octave_value_extract<charNDArray> (argy); + + if (error_state) + ; + else if (ismin) + retval = NDArray (min (x, y)); + else + retval = NDArray (max (x, y)); + } + + return retval; +} + static octave_value_list do_minmax_body (const octave_value_list& args, int nargout, bool ismin) @@ -227,6 +323,9 @@ case btyp_float_complex: retval = do_minmax_red_op<FloatComplexNDArray> (arg, nargout, dim, ismin); break; + case btyp_char: + retval = do_minmax_red_op<charNDArray> (arg, nargout, dim, ismin); + break; #define MAKE_INT_BRANCH(X) \ case btyp_ ## X: \ retval = do_minmax_red_op<X ## NDArray> (arg, nargout, dim, ismin); \ @@ -251,7 +350,11 @@ { octave_value argx = args(0), argy = args(1); builtin_type_t xtyp = argx.builtin_type (), ytyp = argy.builtin_type (); - builtin_type_t rtyp = btyp_mixed_numeric (xtyp, ytyp); + builtin_type_t rtyp; + if (xtyp == btyp_char && ytyp == btyp_char) + rtyp = btyp_char; + else + rtyp = btyp_mixed_numeric (xtyp, ytyp); switch (rtyp) { @@ -281,6 +384,9 @@ case btyp_float_complex: retval = do_minmax_bin_op<FloatComplexNDArray> (argx, argy, ismin); break; + case btyp_char: + retval = do_minmax_bin_op<charNDArray> (argx, argy, ismin); + break; #define MAKE_INT_BRANCH(X) \ case btyp_ ## X: \ retval = do_minmax_bin_op<X ## NDArray> (argx, argy, ismin); \ @@ -361,6 +467,10 @@ %!assert (min ([1, 4, 2, 3]), 1) %!assert (min ([1; -10; 5; -2]), -10) %!assert (min ([4, i; -2, 2]), [-2, i]) +%!assert (min (char(42)), 42) +%!assert (min (char(21), char(3)), 3) +%!assert (min([char(21), char(3)]), 3) +%!assert (min([char(100) char(3)], [char(42) char(42)]), [42 3]) %!test %! x = reshape (1:8, [2,2,2]);
--- a/libinterp/dldfcn/__init_fltk__.cc +++ b/libinterp/dldfcn/__init_fltk__.cc @@ -35,8 +35,10 @@ #include <config.h> #endif +#include "builtin-defun-decls.h" #include "defun-dld.h" #include "error.h" +#include "ov-fcn-handle.h" #ifdef HAVE_FLTK @@ -1834,7 +1836,9 @@ { public: fltk_graphics_toolkit (void) - : base_graphics_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME) { } + : base_graphics_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME), + input_event_hook_fcn_id () + { } ~fltk_graphics_toolkit (void) { } @@ -1971,21 +1975,44 @@ munlock ("__init_fltk__"); figure_manager::close_all (); - gtk_manager::unload_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME); - toolkit_loaded = false; - octave_value_list args; - args(0) = "__fltk_redraw__"; - feval ("remove_input_event_hook", args, 0); + octave_value_list args = input_event_hook_fcn_id; + args.append (false); + Fremove_input_event_hook (args, 0); + + input_event_hook_fcn_id = octave_value_list (); // FIXME ??? Fl::wait (fltk_maxtime); } } + + void set_input_event_hook_id (const octave_value_list& id) + { + input_event_hook_fcn_id = id; + } + +private: + octave_value_list input_event_hook_fcn_id; }; #endif +DEFUN_DLD (__fltk_redraw__, , , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __fltk_redraw__ ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ +#ifdef HAVE_FLTK + __fltk_redraw__ (); +#else + error ("__fltk_redraw__: not available without OpenGL and FLTK libraries"); +#endif + + return octave_value (); +} + // Initialize the fltk graphics toolkit. DEFUN_DLD (__init_fltk__, , , @@ -1999,13 +2026,16 @@ { mlock (); - graphics_toolkit tk (new fltk_graphics_toolkit ()); + fltk_graphics_toolkit *fltk = new fltk_graphics_toolkit (); + graphics_toolkit tk (fltk); gtk_manager::load_toolkit (tk); toolkit_loaded = true; - octave_value_list args; - args(0) = "__fltk_redraw__"; - feval ("add_input_event_hook", args, 0); + octave_value fcn (new octave_builtin (F__fltk_redraw__)); + octave_value fcn_handle (new octave_fcn_handle (fcn, "@__fltk_redraw__")); + octave_value_list id = Fadd_input_event_hook (fcn_handle, 1); + + fltk->set_input_event_hook_id (id); } #else error ("__init_fltk__: not available without OpenGL and FLTK libraries"); @@ -2014,21 +2044,6 @@ return octave_value (); } -DEFUN_DLD (__fltk_redraw__, , , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __fltk_redraw__ ()\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ -#ifdef HAVE_FLTK - __fltk_redraw__ (); -#else - error ("__fltk_redraw__: not available without OpenGL and FLTK libraries"); -#endif - - return octave_value (); -} - DEFUN_DLD (__fltk_maxtime__, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{maxtime} =} __fltk_maxtime__ ()\n\
--- a/libinterp/dldfcn/__magick_read__.cc +++ b/libinterp/dldfcn/__magick_read__.cc @@ -403,9 +403,9 @@ DEFUN_DLD (__magick_read__, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Function File} {@var{m} =} __magick_read__ (@var{fname}, @var{index})\n\ -@deftypefnx {Function File} {[@var{m}, @var{colormap}] =} __magick_read__ (@var{fname}, @var{index})\n\ -@deftypefnx {Function File} {[@var{m}, @var{colormap}, @var{alpha}] =} __magick_read__ (@var{fname}, @var{index})\n\ +@deftypefn {Loadable Function} {@var{m} =} __magick_read__ (@var{fname}, @var{index})\n\ +@deftypefnx {Loadable Function} {[@var{m}, @var{colormap}] =} __magick_read__ (@var{fname}, @var{index})\n\ +@deftypefnx {Loadable Function} {[@var{m}, @var{colormap}, @var{alpha}] =} __magick_read__ (@var{fname}, @var{index})\n\ Read images with ImageMagick++. In general you should not be using this\n\ function. Instead use @code{imread}.\n\ @seealso{imread}\n\ @@ -871,8 +871,8 @@ DEFUN_DLD (__magick_write__, args, , "-*- texinfo -*-\n\ -@deftypefn {Function File} {} __magick_write__ (@var{fname}, @var{fmt}, @var{img})\n\ -@deftypefnx {Function File} {} __magick_write__ (@var{fname}, @var{fmt}, @var{img}, @var{map})\n\ +@deftypefn {Loadable Function} {} __magick_write__ (@var{fname}, @var{fmt}, @var{img})\n\ +@deftypefnx {Loadable Function} {} __magick_write__ (@var{fname}, @var{fmt}, @var{img}, @var{map})\n\ Write images with ImageMagick++. In general you should not be using this\n\ function. Instead use @code{imwrite}.\n\ @seealso{imread}\n\ @@ -1159,7 +1159,7 @@ DEFUN_DLD (__magick_format_list__, args, , "-*- texinfo -*-\n\ -@deftypefn {Function File} {} __magick_format_list__ (@var{formats})\n\ +@deftypefn {Loadable Function} {} __magick_format_list__ (@var{formats})\n\ Undocumented internal function.\n\ @end deftypefn") {
--- a/libinterp/dldfcn/__voronoi__.cc +++ b/libinterp/dldfcn/__voronoi__.cc @@ -90,7 +90,7 @@ std::string options; - if (dim <= 4) + if (dim <= 3) options = " Qbb"; else options = " Qbb Qx";
--- a/libinterp/dldfcn/amd.cc +++ b/libinterp/dldfcn/amd.cc @@ -44,7 +44,7 @@ #include "oct-sparse.h" #include "oct-locbuf.h" -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define AMD_NAME(name) amd_l ## name #else #define AMD_NAME(name) amd ## name
--- a/libinterp/dldfcn/ccolamd.cc +++ b/libinterp/dldfcn/ccolamd.cc @@ -43,7 +43,7 @@ #include "oct-sparse.h" #include "oct-locbuf.h" -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define CCOLAMD_NAME(name) ccolamd_l ## name #define CSYMAMD_NAME(name) csymamd_l ## name #else
--- a/libinterp/dldfcn/colamd.cc +++ b/libinterp/dldfcn/colamd.cc @@ -44,7 +44,7 @@ #include "oct-sparse.h" #include "oct-locbuf.h" -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define COLAMD_NAME(name) colamd_l ## name #define SYMAMD_NAME(name) symamd_l ## name #else
--- a/libinterp/dldfcn/dmperm.cc +++ b/libinterp/dldfcn/dmperm.cc @@ -37,7 +37,7 @@ #include "SparseQR.h" #include "SparseCmplxQR.h" -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define CXSPARSE_NAME(name) cs_dl ## name #else #define CXSPARSE_NAME(name) cs_di ## name
--- a/libinterp/dldfcn/symbfact.cc +++ b/libinterp/dldfcn/symbfact.cc @@ -132,7 +132,7 @@ A->packed = true; A->sorted = true; A->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T A->itype = CHOLMOD_LONG; #else A->itype = CHOLMOD_INT; @@ -292,8 +292,9 @@ W[j] = L.xcidx (j); // get workspace for computing one row of L - cholmod_sparse *R = cholmod_allocate_sparse (n, 1, n, false, true, - 0, CHOLMOD_PATTERN, cm); + cholmod_sparse *R + = CHOLMOD_NAME (allocate_sparse) (n, 1, n, false, true, + 0, CHOLMOD_PATTERN, cm); octave_idx_type *Rp = static_cast<octave_idx_type *>(R->p); octave_idx_type *Ri = static_cast<octave_idx_type *>(R->i); @@ -310,7 +311,7 @@ } // free workspace - cholmod_free_sparse (&R, cm) ; + CHOLMOD_NAME (free_sparse) (&R, cm) ; // transpose L to get R, or leave as is
--- a/libinterp/interp-core/ls-hdf5.h +++ b/libinterp/interp-core/ls-hdf5.h @@ -202,7 +202,7 @@ hdf5_add_scalar_attr (hid_t loc_id, hid_t type_id, const char *attr_name, void *buf); -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define H5T_NATIVE_IDX H5T_NATIVE_LONG #else #define H5T_NATIVE_IDX H5T_NATIVE_INT
--- a/libinterp/interp-core/ls-mat5.cc +++ b/libinterp/interp-core/ls-mat5.cc @@ -82,6 +82,7 @@ #endif #define PAD(l) (((l) > 0 && (l) <= 4) ? 4 : (((l)+7)/8)*8) +#define INT8(l) ((l) == miINT8 || (l) == miUINT8 || (l) == miUTF8) // The subsystem data block @@ -674,7 +675,7 @@ dims(1) = 1; } - if (read_mat5_tag (is, swap, type, len) || type != miINT8) + if (read_mat5_tag (is, swap, type, len) || !INT8(type)) { error ("load: invalid array name subelement"); goto early_read_error; @@ -1012,7 +1013,7 @@ std::string key = m2.key (p0); octave_value val = m2.contents (p0)(0); - symbol_table::varref (key, local_scope, 0) = val; + symbol_table::assign (key, val, local_scope, 0); } } @@ -1059,7 +1060,7 @@ { int32_t fn_type; int32_t fn_len; - if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8) + if (read_mat5_tag (is, swap, fn_type, fn_len) || !INT8(fn_type)) { error ("load: invalid field name subelement"); goto data_read_error; @@ -1120,7 +1121,7 @@ { isclass = true; - if (read_mat5_tag (is, swap, type, len) || type != miINT8) + if (read_mat5_tag (is, swap, type, len) || !INT8(type)) { error ("load: invalid class name"); goto skip_ahead; @@ -1170,7 +1171,7 @@ // field name subelement. The length of this subelement tells // us how many fields there are. - if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8) + if (read_mat5_tag (is, swap, fn_type, fn_len) || !INT8(fn_type)) { error ("load: invalid field name subelement"); goto data_read_error; @@ -2102,7 +2103,7 @@ save_mat5_element_length (const octave_value& tc, const std::string& name, bool save_as_floats, bool mat7_format) { - size_t max_namelen = (mat7_format ? 63 : 31); + size_t max_namelen = 63; size_t len = name.length (); std::string cname = tc.class_name (); int ret = 32; @@ -2286,7 +2287,7 @@ int32_t flags = 0; int32_t nnz_32 = 0; std::string cname = tc.class_name (); - size_t max_namelen = (mat7_format ? 63 : 31); + size_t max_namelen = 63; dim_vector dv = tc.dims (); int nd = tc.ndims (); @@ -2456,7 +2457,7 @@ size_t namelen = name.length (); if (namelen > max_namelen) - namelen = max_namelen; // only 31 or 63 char names permitted in mat file + namelen = max_namelen; // Truncate names if necessary int paddedlength = PAD (namelen); @@ -2634,7 +2635,7 @@ size_t namelen = classname.length (); if (namelen > max_namelen) - namelen = max_namelen; // only 31 or 63 char names permitted + namelen = max_namelen; // Truncate names if necessary int paddedlength = PAD (namelen);
--- a/libinterp/interp-core/mex.cc +++ b/libinterp/interp-core/mex.cc @@ -3250,7 +3250,7 @@ if (! error_state) frame.add_fcn (octave_call_stack::pop); - symbol_table::varref (name) = mxArray::as_octave_value (ptr); + symbol_table::assign (name, mxArray::as_octave_value (ptr)); } else mexErrMsgTxt ("mexPutVariable: symbol table does not exist");
--- a/libinterp/interp-core/oct-lvalue.cc +++ b/libinterp/interp-core/oct-lvalue.cc @@ -32,12 +32,12 @@ void octave_lvalue::assign (octave_value::assign_op op, const octave_value& rhs) { - if (val) + if (! is_black_hole ()) { if (idx.empty ()) - val->assign (op, rhs); + sym->assign (op, rhs); else - val->assign (op, type, idx, rhs); + sym->assign (op, type, idx, rhs); } } @@ -57,33 +57,33 @@ void octave_lvalue::do_unary_op (octave_value::unary_op op) { - if (val) + if (! is_black_hole ()) { if (idx.empty ()) - val->do_non_const_unary_op (op); + sym->do_non_const_unary_op (op); else - val->do_non_const_unary_op (op, type, idx); + sym->do_non_const_unary_op (op, type, idx); } - else - error ("internal: invalid operation on ~"); } octave_value -octave_lvalue::value (void) +octave_lvalue::value (void) const { octave_value retval; - if (val) + if (! is_black_hole ()) { + octave_value val = sym->varval (); + if (idx.empty ()) - retval = *val; + retval = val; else { - if (val->is_constant ()) - retval = val->subsref (type, idx); + if (val.is_constant ()) + retval = val.subsref (type, idx); else { - octave_value_list t = val->subsref (type, idx, 1); + octave_value_list t = val.subsref (type, idx, 1); if (t.length () > 0) retval = t(0); }
--- a/libinterp/interp-core/oct-lvalue.h +++ b/libinterp/interp-core/oct-lvalue.h @@ -30,26 +30,27 @@ #include "oct-obj.h" #include "pt-idx.h" +#include "symtab.h" class octave_lvalue { public: - octave_lvalue (octave_value *v = 0) - : val (v), type (), idx (), nel (1) - { } + octave_lvalue (const symbol_table::symbol_reference& s + = symbol_table::symbol_reference ()) + : sym (s), type (), idx (), nel (1) + { } octave_lvalue (const octave_lvalue& vr) - : val (vr.val), type (vr.type), idx (vr.idx), nel (vr.nel) - { - } + : sym (vr.sym), type (vr.type), idx (vr.idx), nel (vr.nel) + { } octave_lvalue& operator = (const octave_lvalue& vr) { if (this != &vr) { - val = vr.val; + sym = vr.sym; type = vr.type; idx = vr.idx; nel = vr.nel; @@ -60,19 +61,24 @@ ~octave_lvalue (void) { } - bool is_black_hole (void) const { return val == 0; } + bool is_black_hole (void) const { return sym.is_black_hole (); } - bool is_defined (void) const { return val && val->is_defined (); } - - bool is_undefined (void) const { return ! val || val->is_undefined (); } + bool is_defined (void) const + { + return ! is_black_hole () && sym->is_defined (); + } - bool is_map (void) const { return val && val->is_map (); } + bool is_undefined (void) const + { + return is_black_hole () || sym->is_undefined (); + } - void define (const octave_value& v) - { - if (val) - *val = v; - } + bool is_map (void) const + { + return value().is_map (); + } + + void define (const octave_value& v) { sym->assign (v); } void assign (octave_value::assign_op, const octave_value&); @@ -86,13 +92,11 @@ void do_unary_op (octave_value::unary_op op); - octave_value value (void); - - const octave_value *object (void) const { return val; } + octave_value value (void) const; private: - octave_value *val; + symbol_table::symbol_reference sym; std::string type;
--- a/libinterp/interp-core/pt-jit.cc +++ b/libinterp/interp-core/pt-jit.cc @@ -2188,7 +2188,7 @@ // do not store for loop bounds temporary if (name.size () && name[0] != '#') - symbol_table::varref (arguments[i].first) = real_arguments[i]; + symbol_table::assign (arguments[i].first, real_arguments[i]); } octave_quit ();
--- a/libinterp/interpfcn/debug.cc +++ b/libinterp/interpfcn/debug.cc @@ -39,6 +39,7 @@ #include "help.h" #include "input.h" #include "pager.h" +#include "octave-link.h" #include "oct-obj.h" #include "utils.h" #include "parse.h" @@ -279,30 +280,24 @@ { intmap retval; - octave_idx_type len = line.size (); - octave_user_code *dbg_fcn = get_user_code (fname); if (dbg_fcn) { tree_statement_list *cmds = dbg_fcn->body (); + std::string file = dbg_fcn->fcn_file_name (); + if (cmds) { - for (int i = 0; i < len; i++) + retval = cmds->add_breakpoint (file, line); + + for (intmap_iterator p = retval.begin (); p != retval.end (); p++) { - const_intmap_iterator p = line.find (i); - - if (p != line.end ()) + if (p->second != 0) { - int lineno = p->second; - - retval[i] = cmds->set_breakpoint (lineno); - - if (retval[i] != 0) - { - bp_set.insert (fname); - } + bp_set.insert (fname); + break; } } } @@ -335,8 +330,12 @@ if (dbg_fcn) { + std::string file = dbg_fcn->fcn_file_name (); + tree_statement_list *cmds = dbg_fcn->body (); + // FIXME -- move the operation on cmds to the + // tree_statement_list class? if (cmds) { octave_value_list results = cmds->list_breakpoints (); @@ -348,7 +347,14 @@ const_intmap_iterator p = line.find (i); if (p != line.end ()) - cmds->delete_breakpoint (p->second); + { + int lineno = p->second; + + cmds->delete_breakpoint (lineno); + + if (! file.empty ()) + octave_link::update_breakpoint (false, file, lineno); + } } results = cmds->list_breakpoints (); @@ -356,7 +362,6 @@ bp_set_iterator it = bp_set.find (fname); if (results.length () == 0 && it != bp_set.end ()) bp_set.erase (it); - } retval = results.length (); @@ -382,23 +387,17 @@ if (dbg_fcn) { + std::string file = dbg_fcn->fcn_file_name (); + tree_statement_list *cmds = dbg_fcn->body (); if (cmds) { - octave_value_list bkpts = cmds->list_breakpoints (); - - for (int i = 0; i < bkpts.length (); i++) - { - int lineno = static_cast<int> (bkpts(i).int_value ()); - cmds->delete_breakpoint (lineno); - retval[i] = lineno; - } + retval = cmds->remove_all_breakpoints (file); bp_set_iterator it = bp_set.find (fname); if (it != bp_set.end ()) bp_set.erase (it); - } } else if (! silent) @@ -455,6 +454,8 @@ { tree_statement_list *cmds = f->body (); + // FIXME -- move the operation on cmds to the + // tree_statement_list class? if (cmds) { octave_value_list bkpts = cmds->list_breakpoints (); @@ -764,13 +765,18 @@ { char ch; int line = 1; - - if (line >= start && line <= end) - os << line << "\t"; + bool isnewline = true; - while (fs.get (ch)) + // FIXME: Why not use line-oriented input here [getline()]? + while (fs.get (ch) && line <= end) { - if (line >= start && line <= end) + if (isnewline && line >= start) + { + os << line << "\t"; + isnewline = false; + } + + if (line >= start) { os << ch; } @@ -778,8 +784,7 @@ if (ch == '\n') { line++; - if (line >= start && line <= end) - os << line << "\t"; + isnewline = true; } } }
--- a/libinterp/interpfcn/dirfns.cc +++ b/libinterp/interpfcn/dirfns.cc @@ -51,6 +51,7 @@ #include "gripes.h" #include "input.h" #include "load-path.h" +#include "octave-link.h" #include "oct-obj.h" #include "pager.h" #include "procstream.h" @@ -70,16 +71,20 @@ static int octave_change_to_directory (const std::string& newdir) { - int cd_ok = octave_env::chdir (file_ops::tilde_expand (newdir)); + std::string xdir = file_ops::tilde_expand (newdir); + + int cd_ok = octave_env::chdir (xdir); if (cd_ok) { Vlast_chdir_time.stamp (); - // FIXME -- should this be handled as a list of functions + // FIXME -- should these actions be handled as a list of functions // to call so users can add their own chdir handlers? load_path::update (); + + octave_link::change_directory (octave_env::get_current_directory ()); } else error ("%s: %s", newdir.c_str (), gnulib::strerror (errno));
--- a/libinterp/interpfcn/error.cc +++ b/libinterp/interpfcn/error.cc @@ -1345,8 +1345,8 @@ m.contents ("identifier") = ids; m.contents ("state") = states; - symbol_table::varref - (".saved_warning_states.", scope, context) = m; + symbol_table::assign + (".saved_warning_states.", m, scope, context); // Now ignore the "local" argument and continue to // handle the current setting. @@ -1703,6 +1703,7 @@ else if (args(0).is_map ()) { octave_scalar_map new_err = args(0).scalar_map_value (); + octave_scalar_map new_err_stack; std::string new_error_message; std::string new_error_id; std::string new_error_file; @@ -1726,7 +1727,7 @@ if (! error_state && new_err.contains ("stack")) { - octave_scalar_map new_err_stack = + new_err_stack = new_err.getfield ("stack").scalar_map_value (); if (! error_state && new_err_stack.contains ("file")) @@ -1763,10 +1764,22 @@ Vlast_error_message = new_error_message; Vlast_error_id = new_error_id; - octave_idx_type curr_frame = -1; + if (new_err.contains ("stack")) + { + new_err_stack.setfield ("file", new_error_file); + new_err_stack.setfield ("name", new_error_name); + new_err_stack.setfield ("line", new_error_line); + new_err_stack.setfield ("column", new_error_column); + Vlast_error_stack = new_err_stack; + } + else + { + // No stack field. Fill it in with backtrace info. + octave_idx_type curr_frame = -1; - Vlast_error_stack - = octave_call_stack::backtrace (0, curr_frame); + Vlast_error_stack + = octave_call_stack::backtrace (0, curr_frame); + } } } else
--- a/libinterp/interpfcn/file-io.cc +++ b/libinterp/interpfcn/file-io.cc @@ -1876,7 +1876,7 @@ return retval; } -DEFUN (pclose, args, , +DEFUNX ("pclose", Fpclose, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} pclose (@var{fid})\n\ Close a file identifier that was opened by @code{popen}. You may also\n\
--- a/libinterp/interpfcn/graphics.cc +++ b/libinterp/interpfcn/graphics.cc @@ -1789,9 +1789,9 @@ bool remove = false; if (val.is_string ()) { - caseless_str tval = val.string_value (); - - remove = tval.compare ("remove"); + std::string tval = val.string_value (); + + remove = (tval.compare ("remove") == 0); } pval_map_type& pval_map = plist_map[pfx]; @@ -2105,11 +2105,11 @@ { if (val.is_string ()) { - caseless_str tval = val.string_value (); + std::string tval = val.string_value (); octave_value default_val; - if (tval.compare ("default")) + if (tval.compare ("default") == 0) { default_val = get_default (name); @@ -2118,7 +2118,7 @@ rep->set (name, default_val); } - else if (tval.compare ("factory")) + else if (tval.compare ("factory") == 0) { default_val = get_factory_default (name); @@ -2128,7 +2128,15 @@ rep->set (name, default_val); } else - rep->set (name, val); + { + // Matlab specifically uses "\default" to escape string setting + if (tval.compare ("\\default") == 0) + rep->set (name, "default"); + else if (tval.compare ("\\factory") == 0) + rep->set (name, "factory"); + else + rep->set (name, val); + } } else rep->set (name, val);
new file mode 100644 --- /dev/null +++ b/libinterp/interpfcn/hook-fcn.cc @@ -0,0 +1,41 @@ +/* + +Copyright (C) 2013 John W. Eaton + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#include <config.h> + +#include "hook-fcn.h" + +hook_function::hook_function (const octave_value& f, const octave_value& d) +{ + if (f.is_string ()) + { + std::string name = f.string_value (); + + rep = new named_hook_function (name, d); + } + else if (f.is_function_handle ()) + { + rep = new fcn_handle_hook_function (f, d); + } + else + error ("invalid hook function"); +}
new file mode 100644 --- /dev/null +++ b/libinterp/interpfcn/hook-fcn.h @@ -0,0 +1,262 @@ +/* + +Copyright (C) 2013 John W. Eaton + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#if !defined (octave_hook_fcn_h) +#define octave_hook_fcn_h 1 + +#include <string> + +#include "oct-obj.h" +#include "ov.h" +#include "ov-fcn-handle.h" +#include "parse.h" +#include "variables.h" + +class +base_hook_function +{ +public: + + friend class hook_function; + + base_hook_function (void) : count (1) { } + + base_hook_function (const base_hook_function&) : count (1) { } + + virtual ~base_hook_function (void) { } + + virtual std::string id (void) { return std::string (); } + + virtual bool is_valid (void) { return false; } + + virtual void eval (const octave_value_list&) { } + +protected: + + size_t count; +}; + +class +hook_function +{ +public: + + hook_function (void) + { + static base_hook_function nil_rep; + rep = &nil_rep; + rep->count++; + } + + hook_function (const octave_value& f, + const octave_value& d = octave_value ()); + + ~hook_function (void) + { + if (--rep->count == 0) + delete rep; + } + + hook_function (const hook_function& hf) + : rep (hf.rep) + { + rep->count++; + } + + hook_function& operator = (const hook_function& hf) + { + if (rep != hf.rep) + { + if (--rep->count == 0) + delete rep; + + rep = hf.rep; + rep->count++; + } + + return *this; + } + + std::string id (void) { return rep->id (); } + + bool is_valid (void) { return rep->is_valid (); } + + void eval (const octave_value_list& initial_args) + { + rep->eval (initial_args); + } + +private: + + base_hook_function *rep; +}; + +class +named_hook_function : public base_hook_function +{ +public: + + named_hook_function (const std::string& n, const octave_value& d) + : name (n), data (d) + { } + + void eval (const octave_value_list& initial_args) + { + octave_value_list args = initial_args; + + if (data.is_defined ()) + args.append (data); + + feval (name, args, 0); + } + + std::string id (void) { return name; } + + bool is_valid (void) { return is_valid_function (name); } + +private: + + std::string name; + + octave_value data; +}; + +class +fcn_handle_hook_function : public base_hook_function +{ +public: + + fcn_handle_hook_function (const octave_value& fh_arg, const octave_value& d) + : ident (), valid (false), fcn_handle (fh_arg), data (d) + { + octave_fcn_handle *fh = fcn_handle.fcn_handle_value (true); + + if (fh) + { + valid = true; + + std::ostringstream buf; + buf << fh; + ident = fh->fcn_name () + ":" + buf.str (); + } + } + + void eval (const octave_value_list& initial_args) + { + octave_value_list args = initial_args; + + if (data.is_defined ()) + args.append (data); + + fcn_handle.do_multi_index_op (0, args); + } + + std::string id (void) { return ident; } + + bool is_valid (void) { return valid; } + +private: + + std::string ident; + + bool valid; + + octave_value fcn_handle; + + octave_value data; +}; + +class +hook_function_list +{ +public: + + typedef std::map<std::string, hook_function> map_type; + + typedef map_type::iterator iterator; + typedef map_type::const_iterator const_iterator; + + hook_function_list (void) : fcn_map () { } + + ~hook_function_list (void) { } + + hook_function_list (const hook_function_list& lst) + : fcn_map (lst.fcn_map) + { } + + hook_function_list& operator = (const hook_function_list& lst) + { + if (&lst != this) + fcn_map = lst.fcn_map; + + return *this; + } + + bool empty (void) const { return fcn_map.empty (); } + + void clear (void) { fcn_map.clear (); } + + void insert (const std::string& id, const hook_function& f) + { + fcn_map[id] = f; + } + + iterator find (const std::string& id) + { + return fcn_map.find (id); + } + + const_iterator find (const std::string& id) const + { + return fcn_map.find (id); + } + + iterator end (void) { return fcn_map.end (); } + + const_iterator end (void) const { return fcn_map.end (); } + + void erase (iterator p) { fcn_map.erase (p); } + + void run (const octave_value_list& initial_args = octave_value_list ()) + { + iterator p = fcn_map.begin (); + + while (p != fcn_map.end ()) + { + std::string hook_fcn_id = p->first; + hook_function hook_fcn = p->second; + + iterator q = p++; + + if (hook_fcn.is_valid ()) + hook_fcn.eval (initial_args); + else + fcn_map.erase (q); + } + } + +private: + + map_type fcn_map; +}; + +#endif
--- a/libinterp/interpfcn/input.cc +++ b/libinterp/interpfcn/input.cc @@ -49,13 +49,17 @@ #include "error.h" #include "gripes.h" #include "help.h" +#include "hook-fcn.h" #include "input.h" #include "lex.h" #include "load-path.h" +#include "octave-link.h" #include "oct-map.h" #include "oct-hist.h" #include "toplev.h" +#include "octave-link.h" #include "oct-obj.h" +#include "ov-fcn-handle.h" #include "pager.h" #include "parse.h" #include "pathlen.h" @@ -64,6 +68,7 @@ #include "pt-eval.h" #include "pt-stmt.h" #include "sighandlers.h" +#include "symtab.h" #include "sysdep.h" #include "toplev.h" #include "unwind-prot.h" @@ -71,10 +76,10 @@ #include "variables.h" // Primary prompt string. -static std::string VPS1 = "\\s:\\#> "; +static std::string VPS1; // Secondary prompt string. -static std::string VPS2 = "> "; +static std::string VPS2; // String printed before echoed input (enabled by --echo-input). std::string VPS4 = "+ "; @@ -112,7 +117,7 @@ // If we are in debugging mode, this is the last command entered, so // that we can repeat the previous command if the user just types RET. -static std::string last_debugging_command; +static std::string last_debugging_command = "\n"; // TRUE if we are running in the Emacs GUD mode. static bool Vgud_mode = false; @@ -120,6 +125,25 @@ // The filemarker used to separate filenames from subfunction names char Vfilemarker = '>'; +static hook_function_list input_event_hook_functions; + +// For octave_quit. +void +remove_input_event_hook_functions (void) +{ + input_event_hook_functions.clear (); +} + +void +set_default_prompts (void) +{ + VPS1 = "\\s:\\#> "; + VPS2 = "> "; + VPS4 = "+ "; + + octave_link::set_default_prompts (VPS1, VPS2, VPS4); +} + void octave_base_reader::do_input_echo (const std::string& input_string) const { @@ -196,6 +220,19 @@ std::string retval; + // Process pre input event hook function prior to flushing output and + // printing the prompt. + + if (interactive || forced_interactive) + { + if (! Vdebugging) + octave_link::exit_debugger_event (); + + octave_link::pre_input_event (); + + octave_link::set_workspace (); + } + bool history_skip_auto_repeated_debugging_command = false; std::string ps = (pflag > 0) ? VPS1 : VPS2; @@ -215,7 +252,7 @@ // There is no need to update the load_path cache if there is no // user input. - if (! retval.empty () + if (retval != "\n" && retval.find_first_not_of (" \t\n\r") != std::string::npos) { load_path::update (); @@ -223,7 +260,7 @@ if (Vdebugging) last_debugging_command = retval; else - last_debugging_command = std::string (); + last_debugging_command = "\n"; } else if (Vdebugging) { @@ -231,10 +268,15 @@ history_skip_auto_repeated_debugging_command = true; } - if (! retval.empty ()) + if (retval != "\n") { if (! history_skip_auto_repeated_debugging_command) - command_history::add (retval); + { + command_history::add (retval); + + if (! command_history::ignoring_entries ()) + octave_link::append_history (retval); + } octave_diary << retval; @@ -246,6 +288,12 @@ else octave_diary << "\n"; + // Process post input event hook function after the internal history + // list has been updated. + + if (interactive || forced_interactive) + octave_link::post_input_event (); + return retval; } @@ -431,8 +479,16 @@ } static void +execute_in_debugger_handler (const std::pair<std::string, int>& arg) +{ + octave_link::execute_in_debugger_event (arg.first, arg.second); +} + +static void get_debug_input (const std::string& prompt) { + unwind_protect frame; + octave_user_code *caller = octave_call_stack::caller_user_code (); std::string nm; @@ -475,6 +531,13 @@ if (have_file) { + octave_link::enter_debugger_event (nm, curr_debug_line); + + octave_link::set_workspace (); + + frame.add_fcn (execute_in_debugger_handler, + std::pair<std::string, int> (nm, curr_debug_line)); + std::string line_buf = get_file_line (nm, curr_debug_line); @@ -489,8 +552,6 @@ if (! msg.empty ()) std::cerr << msg << std::endl; - unwind_protect frame; - frame.protect_var (VPS1); VPS1 = prompt; @@ -519,15 +580,20 @@ int retval = curr_parser.run (); - if (retval == 0 && curr_parser.stmt_list) + if (command_editor::interrupt (false)) + break; + else { - curr_parser.stmt_list->accept (*current_evaluator); + if (retval == 0 && curr_parser.stmt_list) + { + curr_parser.stmt_list->accept (*current_evaluator); - if (octave_completion_matches_called) - octave_completion_matches_called = false; + if (octave_completion_matches_called) + octave_completion_matches_called = false; + } + + octave_quit (); } - - octave_quit (); } } @@ -1047,44 +1113,22 @@ return retval; } -typedef std::map<std::string, octave_value> hook_fcn_map_type; - -static hook_fcn_map_type hook_fcn_map; - static int -input_event_hook (void) +internal_input_event_hook_fcn (void) { - hook_fcn_map_type::iterator p = hook_fcn_map.begin (); - - while (p != hook_fcn_map.end ()) - { - std::string hook_fcn = p->first; - octave_value user_data = p->second; + input_event_hook_functions.run (); - hook_fcn_map_type::iterator q = p++; - - if (is_valid_function (hook_fcn)) - { - if (user_data.is_defined ()) - feval (hook_fcn, user_data, 0); - else - feval (hook_fcn, octave_value_list (), 0); - } - else - hook_fcn_map.erase (q); - } - - if (hook_fcn_map.empty ()) - command_editor::remove_event_hook (input_event_hook); + if (input_event_hook_functions.empty ()) + command_editor::remove_event_hook (internal_input_event_hook_fcn); return 0; } DEFUN (add_input_event_hook, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} add_input_event_hook (@var{fcn})\n\ -@deftypefnx {Built-in Function} {} add_input_event_hook (@var{fcn}, @var{data})\n\ -Add the named function @var{fcn} to the list of functions to call\n\ +@deftypefn {Built-in Function} {@var{id} =} add_input_event_hook (@var{fcn})\n\ +@deftypefnx {Built-in Function} {@var{id} =} add_input_event_hook (@var{fcn}, @var{data})\n\ +Add the named function or function handle @var{fcn} to the list of functions to call\n\ periodically when Octave is waiting for input. The function should\n\ have the form\n\ \n\ @@ -1094,10 +1138,13 @@ \n\ If @var{data} is omitted, Octave calls the function without any\n\ arguments.\n\ +\n\ +The returned identifier may be used to remove the function handle from\n\ +the list of input hook functions.\n\ @seealso{remove_input_event_hook}\n\ @end deftypefn") { - octave_value_list retval; + octave_value retval; int nargin = args.length (); @@ -1108,17 +1155,19 @@ if (nargin == 2) user_data = args(1); - std::string hook_fcn = args(0).string_value (); + hook_function hook_fcn (args(0), user_data); if (! error_state) { - if (hook_fcn_map.empty ()) - command_editor::add_event_hook (input_event_hook); + if (input_event_hook_functions.empty ()) + command_editor::add_event_hook (internal_input_event_hook_fcn); - hook_fcn_map[hook_fcn] = user_data; + input_event_hook_functions.insert (hook_fcn.id (), hook_fcn); + + retval = hook_fcn.id (); } else - error ("add_input_event_hook: expecting string as first arg"); + error ("add_input_event_hook: expecting function handle or character string as first argument"); } else print_usage (); @@ -1128,9 +1177,11 @@ DEFUN (remove_input_event_hook, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} remove_input_event_hook (@var{fcn})\n\ -Remove the named function @var{fcn} from the list of functions to call\n\ -periodically when Octave is waiting for input.\n\ +@deftypefn {Built-in Function} {} remove_input_event_hook (@var{name})\n\ +@deftypefnx {Built-in Function} {} remove_input_event_hook (@var{fcn_id})\n\ +Remove the named function or function handle with the given identifier\n\ +from the list of functions to call periodically when Octave is waiting\n\ +for input.\n\ @seealso{add_input_event_hook}\n\ @end deftypefn") { @@ -1138,25 +1189,28 @@ int nargin = args.length (); - if (nargin == 1) + if (nargin == 1 || nargin == 2) { - std::string hook_fcn = args(0).string_value (); + std::string hook_fcn_id = args(0).string_value (); + + bool warn = (nargin < 2); if (! error_state) { - hook_fcn_map_type::iterator p = hook_fcn_map.find (hook_fcn); + hook_function_list::iterator p + = input_event_hook_functions.find (hook_fcn_id); - if (p != hook_fcn_map.end ()) - hook_fcn_map.erase (p); - else - error ("remove_input_event_hook: %s not found in list", - hook_fcn.c_str ()); + if (p != input_event_hook_functions.end ()) + input_event_hook_functions.erase (p); + else if (warn) + warning ("remove_input_event_hook: %s not found in list", + hook_fcn_id.c_str ()); - if (hook_fcn_map.empty ()) - command_editor::remove_event_hook (input_event_hook); + if (input_event_hook_functions.empty ()) + command_editor::remove_event_hook (internal_input_event_hook_fcn); } else - error ("remove_input_event_hook: expecting string as first arg"); + error ("remove_input_event_hook: argument not valid as a hook function name or id"); } else print_usage ();
--- a/libinterp/interpfcn/input.h +++ b/libinterp/interpfcn/input.h @@ -59,6 +59,10 @@ extern octave_value do_keyboard (const octave_value_list& args = octave_value_list ()); +extern void remove_input_event_hook_functions (void); + +extern void set_default_prompts (void); + extern std::string VPS4; extern char Vfilemarker;
--- a/libinterp/interpfcn/load-path.cc +++ b/libinterp/interpfcn/load-path.cc @@ -353,6 +353,25 @@ return find_dir_info (dir) != dir_info_list.end (); } +bool +load_path::do_contains_canonical (const std::string& dir) const +{ + bool retval = false; + + for (const_dir_info_list_iterator i = dir_info_list.begin (); + i != dir_info_list.end (); + i++) + { + if (same_file (dir, i->dir_name)) + { + retval = true; + break; + } + } + + return retval; +} + void load_path::move_fcn_map (const std::string& dir_name, const string_vector& fcn_files, bool at_end)
--- a/libinterp/interpfcn/load-path.h +++ b/libinterp/interpfcn/load-path.h @@ -89,6 +89,11 @@ instance->do_update (); } + static bool contains_canonical (const std::string& dir_name) + { + return instance_ok () ? instance->do_contains_canonical (dir_name) : false; + } + static std::string find_method (const std::string& class_name, const std::string& meth, std::string& dir_name) @@ -465,6 +470,8 @@ bool contains (const std::string& dir) const; + bool do_contains_canonical (const std::string& dir) const; + void move_fcn_map (const std::string& dir, const string_vector& fcn_files, bool at_end);
--- a/libinterp/interpfcn/load-save.cc +++ b/libinterp/interpfcn/load-save.cc @@ -146,13 +146,12 @@ { if (global) { - symbol_table::symbol_record& sr = symbol_table::insert (name); - sr.clear (); - sr.mark_global (); - sr.varref () = val; + symbol_table::clear (name); + symbol_table::mark_global (name); + symbol_table::global_assign (name, val); } else - symbol_table::varref (name) = val; + symbol_table::assign (name, val); } // Return TRUE if NAME matches one of the given globbing PATTERNS. @@ -1281,7 +1280,7 @@ return; } - octave_value struct_var = symbol_table::varref (struct_name); + octave_value struct_var = symbol_table::varval (struct_name); if (! struct_var.is_map () || struct_var.numel () != 1) {
--- a/libinterp/interpfcn/module.mk +++ b/libinterp/interpfcn/module.mk @@ -11,10 +11,12 @@ interpfcn/error.h \ interpfcn/file-io.h \ interpfcn/help.h \ + interpfcn/hook-fcn.h \ interpfcn/input.h \ interpfcn/load-path.h \ interpfcn/load-save.h \ interpfcn/ls-oct-ascii.h \ + interpfcn/octave-link.h \ interpfcn/oct-hist.h \ interpfcn/pager.h \ interpfcn/pr-output.h \ @@ -24,7 +26,8 @@ interpfcn/sysdep.h \ interpfcn/toplev.h \ interpfcn/utils.h \ - interpfcn/variables.h + interpfcn/variables.h \ + interpfcn/workspace-element.h INTERPFCN_SRC = \ interpfcn/data.cc \ @@ -36,10 +39,12 @@ interpfcn/file-io.cc \ interpfcn/graphics.cc \ interpfcn/help.cc \ + interpfcn/hook-fcn.cc \ interpfcn/input.cc \ interpfcn/load-path.cc \ interpfcn/load-save.cc \ interpfcn/ls-oct-ascii.cc \ + interpfcn/octave-link.cc \ interpfcn/oct-hist.cc \ interpfcn/pager.cc \ interpfcn/pr-output.cc \
--- a/libinterp/interpfcn/oct-hist.cc +++ b/libinterp/interpfcn/oct-hist.cc @@ -48,6 +48,7 @@ #include "cmd-hist.h" #include "file-ops.h" #include "lo-mappers.h" +#include "octave-link.h" #include "oct-env.h" #include "oct-time.h" #include "str-vec.h" @@ -186,18 +187,29 @@ command_history::write (); else if (option == "-r") - // Read entire file. - command_history::read (); + { + // Read entire file. + command_history::read (); + octave_link::set_history (command_history::list ()); + } else if (option == "-n") - // Read 'new' history from file. - command_history::read_range (); + { + // Read 'new' history from file. + command_history::read_range (); + octave_link::set_history (command_history::list ()); + } else panic_impossible (); return hlist; } + else if (option == "-c") + { + command_history::clear (); + octave_link::clear_history (); + } else if (option == "-q") numbered_output = false; else if (option == "--") @@ -354,7 +366,10 @@ tmp.resize (len - 1); if (! tmp.empty ()) - command_history::add (tmp); + { + command_history::add (tmp); + octave_link::append_history (tmp); + } } } @@ -601,6 +616,8 @@ default_history_file (), default_history_size (), octave_env::getenv ("OCTAVE_HISTCONTROL")); + + octave_link::set_history (command_history::list ()); } void @@ -611,7 +628,10 @@ std::string timestamp = now.strftime (Vhistory_timestamp_format_string); if (! timestamp.empty ()) - command_history::add (timestamp); + { + command_history::add (timestamp); + octave_link::append_history (timestamp); + } } DEFUN (edit_history, args, , @@ -671,6 +691,9 @@ @itemx -@var{n}\n\ Display only the most recent @var{n} lines of history.\n\ \n\ +@item -c\n\ +Clear the history list.\n\ +\n\ @item -q\n\ Don't number the displayed lines of history. This is useful for cutting\n\ and pasting commands using the X Window System.\n\
rename from libgui/src/octave-adapter/octave-link.cc rename to libinterp/interpfcn/octave-link.cc --- a/libgui/src/octave-adapter/octave-link.cc +++ b/libinterp/interpfcn/octave-link.cc @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid Copyright (C) 2011-2012 John P. Swensen @@ -26,10 +27,10 @@ #endif #include "cmd-edit.h" +#include "defun.h" #include "oct-env.h" #include "oct-mutex.h" #include "singleton-cleanup.h" -#include "symtab.h" #include "toplev.h" #include "octave-link.h" @@ -45,64 +46,40 @@ return 0; } -static void -octave_exit_hook (int) -{ - octave_link::about_to_exit (); -} - octave_link *octave_link::instance = 0; octave_link::octave_link (void) - : event_listener (0), event_queue_mutex (new octave_mutex ()), - gui_event_queue (), last_cwd (), debugging (false) -{ } - -void -octave_link::do_launch_octave (void) + : event_queue_mutex (new octave_mutex ()), gui_event_queue (), + debugging (false), link_enabled (true) { - // Create both threads. - main_thread = new octave_main_thread (); - command_editor::add_event_hook (octave_readline_hook); - - octave_exit = octave_exit_hook; - - // Start the first one. - main_thread->start (); } void -octave_link::do_register_event_listener (octave_event_listener *el) +octave_link::set_workspace (void) { - event_listener = el; + if (enabled ()) + instance->do_set_workspace ((symbol_table::current_scope () + == symbol_table::top_scope ()), + symbol_table::workspace_info ()); +} + +// OBJ should be an object of a class that is derived from the base +// class octave_link, or 0 to disconnect the link. It is the +// responsibility of the caller to delete obj. + +void +octave_link::connect_link (octave_link* obj) +{ + if (obj && instance) + ::error ("octave_link is already linked!"); + else + instance = obj; } void octave_link::do_generate_events (void) { - std::string current_working_directory = octave_env::get_current_directory (); - - if (current_working_directory != last_cwd) - { - last_cwd = current_working_directory; - - if (event_listener) - event_listener->current_directory_has_changed (last_cwd); - } - - if (debugging != Vdebugging) - { - debugging = Vdebugging; - - if (event_listener) - { - if (debugging) - event_listener->entered_debug_mode (); - else - event_listener->quit_debug_mode (); - } - } } void @@ -116,43 +93,232 @@ } void -octave_link::do_about_to_exit (void) +octave_link::do_discard_events (void) { event_queue_mutex->lock (); gui_event_queue.discard (); event_queue_mutex->unlock (); +} - if (event_listener) - event_listener->about_to_exit (); +DEFUN (__octave_link_enabled__, , , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __octave_link_enabled__ ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + return octave_value (octave_link::enabled ()); } -std::string -octave_link::do_last_working_directory (void) +DEFUN (__octave_link_edit_file__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __octave_link_edit_file__ (@var{file})\n\ +Undocumented internal function.\n\ +@end deftypefn") { - return last_cwd; + octave_value retval; + + if (args.length () == 1) + { + std::string file = args(0).string_value (); + + if (! error_state) + { + flush_octave_stdout (); + + retval = octave_link::edit_file (file); + } + else + error ("expecting file name as argument"); + } + + return retval; } -bool -octave_link::instance_ok (void) +DEFUN (__octave_link_message_dialog__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __octave_link_message_dialog__ (@var{dlg}, @var{msg}, @var{title})\n\ +Undocumented internal function.\n\ +@end deftypefn") { - bool retval = true; + octave_value retval; - if (! instance) + if (args.length () == 3) { - instance = new octave_link (); + std::string dlg = args(0).string_value (); + std::string msg = args(1).string_value (); + std::string title = args(2).string_value (); - if (instance) - singleton_cleanup_list::add (cleanup_instance); + if (! error_state) + { + flush_octave_stdout (); + + retval = octave_link::message_dialog (dlg, msg, title); + } + else + error ("invalid arguments"); } - if (! instance) + return retval; +} + +DEFUN (__octave_link_question_dialog__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __octave_link_question_dialog__ (@var{msg}, @var{title}, @var{btn1}, @var{btn2}, @var{btn3}, @var{default})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 6) { - ::error ("unable to create octave_link object!"); + std::string msg = args(0).string_value (); + std::string title = args(1).string_value (); + std::string btn1 = args(2).string_value (); + std::string btn2 = args(3).string_value (); + std::string btn3 = args(4).string_value (); + std::string btndef = args(5).string_value (); - retval = false; + if (! error_state) + { + flush_octave_stdout (); + + retval = octave_link::question_dialog (msg, title, btn1, btn2, btn3, btndef); + } + else + error ("invalid arguments"); } return retval; } + +DEFUN (__octave_link_list_dialog__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __octave_link_list_dialog__ (@var{list}, @var{mode}, @var{size}, @var{intial}, @var{name}, @var{prompt}, @var{ok_string}, @var{cancel_string})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value_list retval; + + if (args.length () == 8) + { + Cell list = args(0).cell_value (); + const Array<std::string> tlist = list.cellstr_value (); + octave_idx_type nel = tlist.numel (); + std::list<std::string> list_lst; + for (octave_idx_type i = 0; i < nel; i++) + list_lst.push_back (tlist(i)); + + std::string mode = args(1).string_value (); + + Matrix size_matrix = args(2).matrix_value (); + int width = size_matrix(0); + int height = size_matrix(1); + + Matrix initial_matrix = args(3).matrix_value (); + nel = initial_matrix.numel (); + std::list<int> initial_lst; + for (octave_idx_type i = 0; i < nel; i++) + initial_lst.push_back (initial_matrix(i)); + + std::string name = args(4).string_value (); + list = args(5).cell_value (); + const Array<std::string> plist = list.cellstr_value (); + nel = plist.numel (); + std::list<std::string> prompt_lst; + for (octave_idx_type i = 0; i < nel; i++) + prompt_lst.push_back (plist(i)); + std::string ok_string = args(6).string_value (); + std::string cancel_string = args(7).string_value (); + + if (! error_state) + { + flush_octave_stdout (); + + std::pair<std::list<int>, int> result + = octave_link::list_dialog (list_lst, mode, width, height, + initial_lst, name, prompt_lst, + ok_string, cancel_string); + + std::list<int> items_lst = result.first; + nel = items_lst.size (); + Matrix items (dim_vector (1, nel)); + octave_idx_type i = 0; + for (std::list<int>::iterator it = items_lst.begin (); + it != items_lst.end (); it++) + { + items.xelem(i++) = *it; + } + + retval(1) = result.second; + retval(0) = items; + } + else + error ("invalid arguments"); + } + + return retval; +} + +DEFUN (__octave_link_input_dialog__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __octave_link_input_dialog__ (@var{prompt}, @var{title}, @var{rowscols}, @var{defaults})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 4) + { + Cell prompt = args(0).cell_value (); + Array<std::string> tmp = prompt.cellstr_value (); + octave_idx_type nel = tmp.numel (); + std::list<std::string> prompt_lst; + for (octave_idx_type i = 0; i < nel; i++) + prompt_lst.push_back (tmp(i)); + + std::string title = args(1).string_value (); + + Matrix rc = args(2).matrix_value (); + nel = rc.rows (); + std::list<float> nr; + std::list<float> nc; + for (octave_idx_type i = 0; i < nel; i++) + { + nr.push_back (rc(i,0)); + nc.push_back (rc(i,1)); + } + + Cell defaults = args(3).cell_value (); + tmp = defaults.cellstr_value (); + nel = tmp.numel (); + std::list<std::string> defaults_lst; + for (octave_idx_type i = 0; i < nel; i++) + defaults_lst.push_back (tmp(i)); + + if (! error_state) + { + flush_octave_stdout (); + + std::list<std::string> items_lst + = octave_link::input_dialog (prompt_lst, title, nr, nc, + defaults_lst); + + nel = items_lst.size (); + Cell items (dim_vector (1, nel)); + octave_idx_type i = 0; + for (std::list<std::string>::iterator it = items_lst.begin (); + it != items_lst.end (); it++) + { + items.xelem(i++) = *it; + } + + retval = items; + } + else + error ("invalid arguments"); + } + + return retval; +}
rename from libgui/src/octave-adapter/octave-link.h rename to libinterp/interpfcn/octave-link.h --- a/libgui/src/octave-adapter/octave-link.h +++ b/libinterp/interpfcn/octave-link.h @@ -1,5 +1,6 @@ /* +Copyright (C) 2013 John W. Eaton Copyright (C) 2011-2012 Jacob Dawid Copyright (C) 2011-2012 John P. Swensen @@ -21,17 +22,16 @@ */ -#ifndef OCTAVELINK_H -#define OCTAVELINK_H +#if !defined (octave_link_h) +#define octave_link_h 1 #include <string> -class octave_mutex; - #include "event-queue.h" -#include "octave-main-thread.h" -#include "octave-event-listener.h" +class octave_mutex; +class string_vector; +class workspace_element; // \class OctaveLink // \brief Provides threadsafe access to octave. @@ -49,95 +49,255 @@ public: - ~octave_link (void) { } - - static void launch_octave (void) - { - if (instance_ok ()) - instance->do_launch_octave (); - } - - static void register_event_listener (octave_event_listener *el) - { - if (instance_ok ()) - instance->do_register_event_listener (el); - } + virtual ~octave_link (void) { } static void generate_events (void) { - if (instance_ok ()) + if (enabled ()) instance->do_generate_events (); } - static void process_events (void) + // If disable is TRUE, then no additional events will be processed + // other than exit. + + static void process_events (bool disable = false) { + if (enabled ()) + { + if (disable) + instance->link_enabled = false; + + instance->do_process_events (); + } + } + + static void discard_events (void) + { + if (enabled ()) + instance->do_discard_events (); + } + + static bool exit (int status) + { + bool retval = false; + if (instance_ok ()) - instance->do_process_events (); + retval = instance->do_exit (status); + + return retval; } template <class T> static void post_event (T *obj, void (T::*method) (void)) { - if (instance_ok ()) + if (enabled ()) instance->do_post_event (obj, method); } template <class T, class A> static void post_event (T *obj, void (T::*method) (A), A arg) { - if (instance_ok ()) + if (enabled ()) instance->do_post_event (obj, method, arg); } template <class T, class A> static void post_event (T *obj, void (T::*method) (const A&), const A& arg) { - if (instance_ok ()) + if (enabled ()) instance->do_post_event (obj, method, arg); } - static void about_to_exit (void) + template <class T, class A, class B> + static void post_event (T *obj, void (T::*method) (const A&, const B&), + const A& arg_a, const B& arg_b) { - if (instance_ok ()) - instance->do_about_to_exit (); + if (enabled ()) + instance->do_post_event (obj, method, arg_a, arg_b); } static void entered_readline_hook (void) { - if (instance_ok ()) + if (enabled ()) instance->do_entered_readline_hook (); } static void finished_readline_hook (void) { - if (instance_ok ()) + if (enabled ()) instance->do_finished_readline_hook (); } - static std::string last_working_directory (void) + static bool + edit_file (const std::string& file) + { + return enabled () ? instance->do_edit_file (file) : false; + } + + static int + message_dialog (const std::string& dlg, const std::string& msg, + const std::string& title) + { + return enabled () ? instance->do_message_dialog (dlg, msg, title) : 0; + } + + static std::string + question_dialog (const std::string& msg, const std::string& title, + const std::string& btn1, const std::string& btn2, + const std::string& btn3, const std::string& btndef) + { + return enabled () ? instance->do_question_dialog (msg, title, btn1, + btn2, btn3, btndef) : 0; + } + + static std::pair<std::list<int>, int> + list_dialog (const std::list<std::string>& list, + const std::string& mode, + int width, int height, + const std::list<int>& initial_value, + const std::string& name, + const std::list<std::string>& prompt, + const std::string& ok_string, + const std::string& cancel_string) + { + return enabled () + ? instance->do_list_dialog (list, mode, width, height, + initial_value, name, prompt, + ok_string, cancel_string) + : std::pair<std::list<int>, int> (); + } + + static std::list<std::string> + input_dialog (const std::list<std::string>& prompt, + const std::string& title, + const std::list<float>& nr, + const std::list<float>& nc, + const std::list<std::string>& defaults) + { + return enabled () + ? instance->do_input_dialog (prompt, title, nr, nc, defaults) + : std::list<std::string> (); + } + + static int debug_cd_or_addpath_error (const std::string& file, + const std::string& dir, + bool addpath_option) + { + return enabled () + ? instance->do_debug_cd_or_addpath_error (file, dir, addpath_option) : 0; + } + + static void change_directory (const std::string& dir) + { + if (enabled ()) + instance->do_change_directory (dir); + } + + static void set_workspace (void); + + static void set_workspace (bool top_level, + const std::list<workspace_element>& ws) + { + if (enabled ()) + instance->do_set_workspace (top_level, ws); + } + + static void clear_workspace (void) { - return instance_ok () - ? instance->do_last_working_directory () : std::string (); + if (enabled ()) + instance->do_clear_workspace (); + } + + static void set_history (const string_vector& hist) + { + if (enabled ()) + instance->do_set_history (hist); + } + + static void append_history (const std::string& hist_entry) + { + if (enabled ()) + instance->do_append_history (hist_entry); + } + + static void clear_history (void) + { + if (enabled ()) + instance->do_clear_history (); + } + + static void pre_input_event (void) + { + if (enabled ()) + instance->do_pre_input_event (); + } + + static void post_input_event (void) + { + if (enabled ()) + instance->do_post_input_event (); + } + + static void enter_debugger_event (const std::string& file, int line) + { + if (enabled ()) + { + instance->debugging = true; + + instance->do_enter_debugger_event (file, line); + } + } + + static void execute_in_debugger_event (const std::string& file, int line) + { + if (enabled ()) + instance->do_execute_in_debugger_event (file, line); + } + + static void exit_debugger_event (void) + { + if (enabled () && instance->debugging) + { + instance->debugging = false; + + instance->do_exit_debugger_event (); + } + } + + static void + update_breakpoint (bool insert, const std::string& file, int line) + { + if (enabled ()) + instance->do_update_breakpoint (insert, file, line); + } + + static void connect_link (octave_link *); + + static void set_default_prompts (std::string& ps1, std::string& ps2, + std::string& ps4) + { + if (enabled ()) + instance->do_set_default_prompts (ps1, ps2, ps4); + } + + static bool enabled (void) + { + return instance_ok () ? instance->link_enabled : false; } private: static octave_link *instance; - static void cleanup_instance (void) { delete instance; instance = 0; } - // No copying! octave_link (const octave_link&); octave_link& operator = (const octave_link&); - static bool instance_ok (void); + static bool instance_ok (void) { return instance != 0; } - octave_event_listener *event_listener; - - // Thread running octave_main. - octave_main_thread *main_thread; +protected: // Semaphore to lock access to the event queue. octave_mutex *event_queue_mutex; @@ -145,16 +305,12 @@ // Event Queue. event_queue gui_event_queue; - // Stores the last known current working directory of octave. - std::string last_cwd; - bool debugging; - - void do_launch_octave (void); - void do_register_event_listener (octave_event_listener *oel); + bool link_enabled; void do_generate_events (void); void do_process_events (void); + void do_discard_events (void); template <class T> void do_post_event (T *obj, void (T::*method) (void)) @@ -174,12 +330,72 @@ gui_event_queue.add_method (obj, method, arg); } - void do_about_to_exit (void); - void do_entered_readline_hook (void) { } void do_finished_readline_hook (void) { } - std::string do_last_working_directory (void); + virtual bool do_exit (int status) = 0; + + virtual bool do_edit_file (const std::string& file) = 0; + + virtual int + do_message_dialog (const std::string& dlg, const std::string& msg, + const std::string& title) = 0; + + virtual std::string + do_question_dialog (const std::string& msg, const std::string& title, + const std::string& btn1, const std::string& btn2, + const std::string& btn3, const std::string& btndef) = 0; + + virtual std::pair<std::list<int>, int> + do_list_dialog (const std::list<std::string>& list, + const std::string& mode, + int width, int height, + const std::list<int>& initial_value, + const std::string& name, + const std::list<std::string>& prompt, + const std::string& ok_string, + const std::string& cancel_string) = 0; + + virtual std::list<std::string> + do_input_dialog (const std::list<std::string>& prompt, + const std::string& title, + const std::list<float>& nr, + const std::list<float>& nc, + const std::list<std::string>& defaults) = 0; + + virtual int + do_debug_cd_or_addpath_error (const std::string& file, + const std::string& dir, + bool addpath_option) = 0; + + virtual void do_change_directory (const std::string& dir) = 0; + + virtual void + do_set_workspace (bool top_level, + const std::list<workspace_element>& ws) = 0; + + virtual void do_clear_workspace (void) = 0; + + virtual void do_set_history (const string_vector& hist) = 0; + virtual void do_append_history (const std::string& hist_entry) = 0; + virtual void do_clear_history (void) = 0; + + virtual void do_pre_input_event (void) = 0; + virtual void do_post_input_event (void) = 0; + + virtual void + do_enter_debugger_event (const std::string& file, int line) = 0; + + virtual void + do_execute_in_debugger_event (const std::string& file, int line) = 0; + + virtual void do_exit_debugger_event (void) = 0; + + virtual void do_update_breakpoint (bool insert, + const std::string& file, int line) = 0; + + virtual void do_set_default_prompts (std::string& ps1, std::string& ps2, + std::string& ps4) = 0; }; #endif // OCTAVELINK_H
--- a/libinterp/interpfcn/pr-output.cc +++ b/libinterp/interpfcn/pr-output.cc @@ -605,23 +605,24 @@ fmt = float_format (); else { - int ex = 4; - if (digits > 100) - ex++; + // e+ddd + int ex = 5; if (print_eng) { - fw = 4 + prec + ex; + // -ddd. + fw = 5 + prec + ex; if (inf_or_nan && fw < 6) fw = 6; fmt = float_format (fw, ex, prec - 1, std::ios::fixed); } else { - fw = 2 + prec + ex; + // -d. + fw = 3 + prec + ex; if (inf_or_nan && fw < 4) fw = 4; - fmt = float_format (fw, prec - 1, std::ios::scientific); + fmt = float_format (fw, ex, prec - 1, std::ios::scientific); } }
--- a/libinterp/interpfcn/sighandlers.cc +++ b/libinterp/interpfcn/sighandlers.cc @@ -378,14 +378,7 @@ static void sigint_handler (int sig) { -#ifdef USE_W32_SIGINT - if (w32_in_main_thread ()) - user_abort (strsignal (sig), sig); - else - w32_raise (sig); -#else user_abort (strsignal (sig), sig); -#endif } #ifdef SIGPIPE @@ -403,62 +396,6 @@ } #endif /* defined (SIGPIPE) */ -#ifdef USE_W32_SIGINT -static BOOL CALLBACK -w32_sigint_handler (DWORD sig) -{ - const char *sig_name; - - switch (sig) - { - case CTRL_BREAK_EVENT: - sig_name = "Ctrl-Break"; - break; - case CTRL_C_EVENT: - sig_name = "Ctrl-C"; - break; - case CTRL_CLOSE_EVENT: - sig_name = "close console"; - break; - case CTRL_LOGOFF_EVENT: - sig_name = "logoff"; - break; - case CTRL_SHUTDOWN_EVENT: - sig_name = "shutdown"; - break; - default: - sig_name = "unknown console event"; - break; - } - - switch (sig) - { - case CTRL_BREAK_EVENT: - case CTRL_C_EVENT: - w32_raise (SIGINT); - break; - - case CTRL_CLOSE_EVENT: - clean_up_and_exit (0); - break; - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - default: - // We should do the following: - // clean_up_and_exit (0); - // We can't because we aren't running in the normal Octave thread. - user_abort (sig_name, sig); - break; - } - - // Return TRUE if the event was handled, or FALSE if another handler - // should be called. - // FIXME check that windows terminates the thread. - return TRUE; -} -#endif /* w32_sigint_handler */ - - octave_interrupt_handler octave_catch_interrupts (void) { @@ -472,22 +409,6 @@ retval.brk_handler = octave_set_signal_handler (SIGBREAK, sigint_handler); #endif -#ifdef USE_W32_SIGINT - - // Intercept windows console control events. - // Note that the windows console signal handlers chain, so if - // install_signal_handlers is called more than once in the same program, - // then first call the following to avoid duplicates: - // - // SetConsoleCtrlHandler (w32_sigint_handler, FALSE); - - if (! SetConsoleCtrlHandler (w32_sigint_handler, TRUE)) - error ("SetConsoleCtrlHandler failed with %ld\n", GetLastError ()); - - w32_set_quiet_shutdown (); - -#endif - return retval; }
--- a/libinterp/interpfcn/symtab.cc +++ b/libinterp/interpfcn/symtab.cc @@ -124,7 +124,7 @@ octave_value retval; if (is_global ()) - retval = symbol_table::global_varref (name ()); + retval = symbol_table::global_varval (name ()); else { retval = varval (); @@ -1361,13 +1361,11 @@ { symbol_record sr = p->second; - // FIXME -- should we be using something other than varref here? - if (sr.is_global ()) - return symbol_table::global_varref (name); + return symbol_table::global_varval (name); else { - octave_value& val = sr.varref (); + octave_value val = sr.varval (); if (val.is_defined ()) return val; @@ -1418,6 +1416,49 @@ return retval; } +std::list<workspace_element> +symbol_table::do_workspace_info (void) const +{ + std::list<workspace_element> retval; + + for (table_const_iterator p = table.begin (); p != table.end (); p++) + { + std::string nm = p->first; + symbol_record sr = p->second; + + if (! sr.is_hidden ()) + { + octave_value val = sr.varval (); + + if (val.is_defined ()) + { + dim_vector dv = val.dims (); + + char storage = ' '; + if (sr.is_global ()) + storage = 'g'; + else if (sr.is_persistent ()) + storage = 'p'; + else if (sr.is_automatic ()) + storage = 'a'; + else if (sr.is_formal ()) + storage = 'f'; + else if (sr.is_hidden ()) + storage = 'h'; + else if (sr.is_inherited ()) + storage = 'i'; + + workspace_element elt (storage, nm, val.class_name (), + val.short_disp (), dv.str ()); + + retval.push_back (elt); + } + } + } + + return retval; +} + void symbol_table::do_dump (std::ostream& os) { @@ -1703,7 +1744,7 @@ std::string name = args(0).string_value (); if (! error_state) - symbol_table::varref (name) = args(1); + symbol_table::assign (name, args(1)); else error ("set_variable: expecting variable name as first argument"); }
--- a/libinterp/interpfcn/symtab.h +++ b/libinterp/interpfcn/symtab.h @@ -37,6 +37,7 @@ class octave_user_function; #include "oct-obj.h" +#include "workspace-element.h" #include "oct-refcount.h" #include "ov.h" @@ -215,12 +216,63 @@ value_stack.push_back (v); } + void assign (const octave_value& value, + context_id context = xdefault_context) + { + varref (context) = value; + } + + void assign (octave_value::assign_op op, + const std::string& type, + const std::list<octave_value_list>& idx, + const octave_value& value, + context_id context = xdefault_context) + { + varref(context).assign (op, type, idx, value); + } + + void assign (octave_value::assign_op op, const octave_value& value, + context_id context = xdefault_context) + { + varref(context).assign (op, value); + } + + void do_non_const_unary_op (octave_value::unary_op op, + context_id context = xdefault_context) + { + varref(context).do_non_const_unary_op (op); + } + + void do_non_const_unary_op (octave_value::unary_op op, + const std::string& type, + const std::list<octave_value_list>& idx, + context_id context = xdefault_context) + { + varref(context).do_non_const_unary_op (op, type, idx); + } + octave_value& varref (context_id context = xdefault_context) { + // We duplicate global_varref and persistent_varref here to + // avoid calling deprecated functions. + if (is_global ()) - return symbol_table::global_varref (name); + { + symbol_table::global_table_iterator p + = symbol_table::global_table.find (name); + + return (p == symbol_table::global_table.end ()) + ? symbol_table::global_table[name] : p->second; + } else if (is_persistent ()) - return symbol_table::persistent_varref (name); + { + static octave_value foobar; + + symbol_table *inst + = symbol_table::get_instance (symbol_table::current_scope ()); + + return inst ? inst->do_persistent_varref (name) : foobar; + } else { if (context == xdefault_context) @@ -299,13 +351,12 @@ if (is_persistent ()) { - symbol_table::persistent_varref (name) - = varval (); + symbol_table::persistent_assign (name, varval ()); unmark_persistent (); } - varref () = octave_value (); + assign (octave_value ()); } } @@ -375,7 +426,7 @@ { mark_persistent (); - varref () = symbol_table::persistent_varval (name); + assign (symbol_table::persistent_varval (name)); } // FIXME -- this causes trouble with recursive calls. // else @@ -476,9 +527,45 @@ const std::string& name (void) const { return rep->name; } + void rename (const std::string& new_name) { rep->name = new_name; } + octave_value find (const octave_value_list& args = octave_value_list ()) const; + void assign (const octave_value& value, + context_id context = xdefault_context) + { + rep->assign (value, context); + } + + void assign (octave_value::assign_op op, + const std::string& type, + const std::list<octave_value_list>& idx, + const octave_value& value, + context_id context = xdefault_context) + { + rep->assign (op, type, idx, value, context); + } + + void assign (octave_value::assign_op op, const octave_value& value, + context_id context = xdefault_context) + { + rep->assign (op, value, context); + } + + void do_non_const_unary_op (octave_value::unary_op op) + { + rep->do_non_const_unary_op (op); + } + + void do_non_const_unary_op (octave_value::unary_op op, + const std::string& type, + const std::list<octave_value_list>& idx) + { + rep->do_non_const_unary_op (op, type, idx); + } + + // Delete when deprecated varref functions are removed. octave_value& varref (context_id context = xdefault_context) { return rep->varref (context); @@ -502,6 +589,11 @@ return rep->is_defined (context); } + bool is_undefined (context_id context = xdefault_context) const + { + return ! rep->is_defined (context); + } + bool is_valid (void) const { return rep->is_valid (); @@ -572,20 +664,30 @@ symbol_reference { public: - symbol_reference (void) : scope (-1) {} - - symbol_reference (symbol_record record, - scope_id curr_scope = symbol_table::current_scope ()) + + symbol_reference (void) : scope (-1) { } + + symbol_reference (const symbol_record& record, + scope_id curr_scope = symbol_table::current_scope ()) : scope (curr_scope), sym (record) - {} + { } + + symbol_reference (const symbol_reference& ref) + : scope (ref.scope), sym (ref.sym) + { } symbol_reference& operator = (const symbol_reference& ref) { - scope = ref.scope; - sym = ref.sym; + if (this != &ref) + { + scope = ref.scope; + sym = ref.sym; + } return *this; } + bool is_black_hole (void) const { return scope < 0; } + // The name is the same regardless of scope. const std::string& name (void) const { return sym.name (); } @@ -612,9 +714,11 @@ } }; private: + void update (void) const { scope_id curr_scope = symbol_table::current_scope (); + if (scope != curr_scope || ! sym.is_valid ()) { scope = curr_scope; @@ -1171,19 +1275,45 @@ static octave_value builtin_find (const std::string& name); // Insert a new name in the table. - static symbol_record& insert (const std::string& name) + static symbol_record& insert (const std::string& name, + scope_id scope = xcurrent_scope) { static symbol_record foobar; - symbol_table *inst = get_instance (xcurrent_scope); + symbol_table *inst = get_instance (scope); return inst ? inst->do_insert (name) : foobar; } - static octave_value& varref (const std::string& name, - scope_id scope = xcurrent_scope, - context_id context = xdefault_context, - bool force_add = false) + static void rename (const std::string& old_name, + const std::string& new_name, + scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_rename (old_name, new_name); + } + + static void assign (const std::string& name, + const octave_value& value = octave_value (), + scope_id scope = xcurrent_scope, + context_id context = xdefault_context, + bool force_add = false) + { + static octave_value foobar; + + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_assign (name, value, context, force_add); + } + + // Use assign (name, value, scope, context, force_add) instead. + static octave_value& + varref (const std::string& name, scope_id scope = xcurrent_scope, + context_id context = xdefault_context, bool force_add = false) + GCC_ATTR_DEPRECATED { static octave_value foobar; @@ -1192,13 +1322,27 @@ return inst ? inst->do_varref (name, context, force_add) : foobar; } - // Convenience function to greatly simplify + // Convenience function to simplify // octave_user_function::bind_automatic_vars - static octave_value& force_varref (const std::string& name, - scope_id scope = xcurrent_scope, - context_id context = xdefault_context) + + static void force_assign (const std::string& name, + const octave_value& value = octave_value (), + scope_id scope = xcurrent_scope, + context_id context = xdefault_context) { - return varref (name, scope, context, true); + assign (name, value, scope, context, true); + } + + // Use force_assign (name, value, scope, context) instead. + static octave_value& + force_varref (const std::string& name, scope_id scope = xcurrent_scope, + context_id context = xdefault_context) GCC_ATTR_DEPRECATED + { + static octave_value foobar; + + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_varref (name, context, true) : foobar; } static octave_value varval (const std::string& name, @@ -1210,8 +1354,23 @@ return inst ? inst->do_varval (name, context) : octave_value (); } + static void + global_assign (const std::string& name, + const octave_value& value = octave_value ()) + + { + global_table_iterator p = global_table.find (name); + + if (p == global_table.end ()) + global_table[name] = value; + else + p->second = value; + } + + // Use global_assign (name, value) instead. static octave_value& - global_varref (const std::string& name) + global_varref (const std::string& name) GCC_ATTR_DEPRECATED + { global_table_iterator p = global_table.find (name); @@ -1226,10 +1385,22 @@ return (p != global_table.end ()) ? p->second : octave_value (); } + static void + top_level_assign (const std::string& name, + const octave_value& value = octave_value ()) + { + assign (name, value, top_scope (), 0); + } + + // Use top_level_assign (name, value) instead. static octave_value& - top_level_varref (const std::string& name) + top_level_varref (const std::string& name) GCC_ATTR_DEPRECATED { - return varref (name, top_scope (), 0); + static octave_value foobar; + + symbol_table *inst = get_instance (top_scope ()); + + return inst ? inst->do_varref (name, 0, true) : foobar; } static octave_value @@ -1238,7 +1409,19 @@ return varval (name, top_scope (), 0); } + static void + persistent_assign (const std::string& name, + const octave_value& value = octave_value ()) + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_persistent_assign (name, value); + } + + // Use persistent_assign (name, value) instead. static octave_value& persistent_varref (const std::string& name) + GCC_ATTR_DEPRECATED { static octave_value foobar; @@ -1956,6 +2139,14 @@ } } + static std::list<workspace_element> workspace_info (void) + { + symbol_table *inst = get_instance (xcurrent_scope); + + return inst + ? inst->do_workspace_info () : std::list<workspace_element> (); + } + static void dump (std::ostream& os, scope_id scope = xcurrent_scope); static void dump_global (std::ostream& os); @@ -2240,7 +2431,7 @@ if (val.is_defined ()) { - sr.varref (0) = val; + sr.assign (val, 0); sr.mark_inherited (); } @@ -2283,7 +2474,41 @@ return p->second; } - octave_value& do_varref (const std::string& name, context_id context, bool force_add) + void do_rename (const std::string& old_name, const std::string& new_name) + { + table_iterator p = table.find (old_name); + + if (p != table.end ()) + { + symbol_record sr = p->second; + + sr.rename (new_name); + + table.erase (p); + + table[new_name] = sr; + } + } + + void do_assign (const std::string& name, const octave_value& value, + context_id context, bool force_add) + { + table_iterator p = table.find (name); + + if (p == table.end ()) + { + symbol_record& sr = do_insert (name, force_add); + + sr.assign (value, context); + } + else + p->second.assign (value, context); + } + + // Use do_assign (name, value, context, force_add) instead. + // Delete when deprecated varref functions are removed. + octave_value& do_varref (const std::string& name, context_id context, + bool force_add) { table_iterator p = table.find (name); @@ -2304,6 +2529,19 @@ return (p != table.end ()) ? p->second.varval (context) : octave_value (); } + void do_persistent_assign (const std::string& name, + const octave_value& value) + { + persistent_table_iterator p = persistent_table.find (name); + + if (p == persistent_table.end ()) + persistent_table[name] = value; + else + p->second = value; + } + + // Use do_persistent_assign (name, value) instead. + // Delete when deprecated varref functions are removed. octave_value& do_persistent_varref (const std::string& name) { persistent_table_iterator p = persistent_table.find (name); @@ -2371,7 +2609,7 @@ for (table_iterator p = table.begin (); p != table.end (); p++) { symbol_record& sr = p->second; - octave_value& val = sr.varref (); + octave_value val = sr.varval (); if (val.is_object ()) p->second.clear (my_scope); } @@ -2594,6 +2832,8 @@ return p != table.end () && p->second.is_global (); } + std::list<workspace_element> do_workspace_info (void) const; + void do_dump (std::ostream& os); void do_cache_name (const std::string& name) { table_name = name; }
--- a/libinterp/interpfcn/sysdep.cc +++ b/libinterp/interpfcn/sysdep.cc @@ -167,8 +167,6 @@ MINGW_signal_cleanup (void) { w32_set_quiet_shutdown (); - - w32_raise_final (); } #endif @@ -177,11 +175,6 @@ MINGW_init (void) { w32_set_octave_home (); - - // Init mutex to protect setjmp/longjmp and get main thread context - w32_sigint_init (); - - w32_set_quiet_shutdown (); } #endif @@ -190,11 +183,6 @@ MSVC_init (void) { w32_set_octave_home (); - - // Init mutex to protect setjmp/longjmp and get main thread context - w32_sigint_init (); - - w32_set_quiet_shutdown (); } #endif @@ -535,7 +523,9 @@ Clear the terminal screen and move the cursor to the upper left corner.\n\ @end deftypefn") { - command_editor::clear_screen (); + bool skip_redisplay = true; + + command_editor::clear_screen (skip_redisplay); return octave_value_list (); }
--- a/libinterp/interpfcn/sysdep.h +++ b/libinterp/interpfcn/sysdep.h @@ -47,7 +47,6 @@ #if defined (__WIN32__) && ! defined (_POSIX_VERSION) extern void MINGW_signal_cleanup (void); -#define USE_W32_SIGINT 1 #define MINGW_SIGNAL_CLEANUP() MINGW_signal_cleanup () #else #define MINGW_SIGNAL_CLEANUP() do { } while (0)
--- a/libinterp/interpfcn/toplev.cc +++ b/libinterp/interpfcn/toplev.cc @@ -35,6 +35,7 @@ #include <sstream> #include <string> +#include <sys/select.h> #include <sys/types.h> #include <unistd.h> @@ -56,6 +57,7 @@ #include "graphics.h" #include "input.h" #include "lex.h" +#include "octave-link.h" #include "oct-conf.h" #include "oct-conf-features.h" #include "oct-hist.h" @@ -117,17 +119,29 @@ int octave_call_stack::do_current_line (void) const { - tree_statement *stmt = do_current_statement (); + int retval = -1; - return stmt ? stmt->line () : -1; + if (! cs.empty ()) + { + const call_stack_elt& elt = cs[curr_frame]; + retval = elt.line; + } + + return retval; } int octave_call_stack::do_current_column (void) const { - tree_statement *stmt = do_current_statement (); + int retval = -1; - return stmt ? stmt->column () : -1; + if (! cs.empty ()) + { + const call_stack_elt& elt = cs[curr_frame]; + retval = elt.column; + } + + return retval; } int @@ -145,11 +159,9 @@ if (f && f->is_user_code ()) { - tree_statement *stmt = elt.stmt; - - if (stmt) + if (elt.line > 0) { - retval = stmt->line (); + retval = elt.line; break; } } @@ -173,11 +185,9 @@ if (f && f->is_user_code ()) { - tree_statement *stmt = elt.stmt; - - if (stmt) + if (elt.column) { - retval = stmt->column (); + retval = elt.column; break; } } @@ -309,18 +319,8 @@ else name(k) = f->parent_fcn_name () + Vfilemarker + f->name (); - tree_statement *stmt = elt.stmt; - - if (stmt) - { - line(k) = stmt->line (); - column(k) = stmt->column (); - } - else - { - line(k) = -1; - column(k) = -1; - } + line(k) = elt.line; + column(k) = elt.column; k++; } @@ -351,17 +351,9 @@ octave_function *f = elt.fcn; std::string nm = f ? f->name () : std::string ("<unknown>"); - tree_statement *s = elt.stmt; - int l = -1; - int c = -1; - if (s) - { - l = s->line (); - c = s->column (); - } - octave_stdout << "stopped in " << nm - << " at line " << l << " column " << c + << " at line " << elt.line + << " column " << elt.column << " (" << elt.scope << "[" << elt.context << "])" << std::endl; } @@ -415,14 +407,8 @@ std::ostringstream buf; if (f) - { - tree_statement *s = elt.stmt; - - int l = s ? s->line () : -1; - - buf << "stopped in " << f->name () - << " at line " << l << std::endl; - } + buf << "stopped in " << f->name () + << " at line " << elt.line << std::endl; else buf << "at top level" << std::endl; @@ -508,7 +494,6 @@ const call_stack_elt& elt = cs.back (); octave_function *fcn = elt.fcn; - tree_statement *stmt = elt.stmt; std::string fcn_name = "?unknown?"; @@ -520,11 +505,8 @@ fcn_name = fcn->name (); } - int line = stmt ? stmt->line () : -1; - int column = stmt ? stmt->column () : -1; - error (" %s at line %d, column %d", - fcn_name.c_str (), line, column); + fcn_name.c_str (), elt.line, elt.column); } } @@ -562,7 +544,11 @@ // octave_parser constructor sets this for us. frame.protect_var (LEXER); - octave_parser parser; + octave_lexer *lxr = ((interactive || forced_interactive) + ? new octave_lexer () + : new octave_lexer (stdin)); + + octave_parser parser (*lxr); int retval = 0; do @@ -629,10 +615,7 @@ recover_from_exception (); octave_stdout << "\n"; if (quitting_gracefully) - { - clean_up_and_exit (exit_status); - break; // If user has overriden the exit func. - } + return exit_status; } catch (octave_execution_exception) { @@ -656,13 +639,120 @@ // Fix up things before exiting. +static std::list<std::string> octave_atexit_functions; + +static void +do_octave_atexit (void) +{ + static bool deja_vu = false; + + OCTAVE_SAFE_CALL (remove_input_event_hook_functions, ()); + + while (! octave_atexit_functions.empty ()) + { + std::string fcn = octave_atexit_functions.front (); + + octave_atexit_functions.pop_front (); + + OCTAVE_SAFE_CALL (reset_error_handler, ()); + + OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0)); + + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); + } + + if (! deja_vu) + { + deja_vu = true; + + // Process pending events and disasble octave_link event + // processing with this call. + + octave_link::process_events (true); + + // Do this explicitly so that destructors for mex file objects + // are called, so that functions registered with mexAtExit are + // called. + OCTAVE_SAFE_CALL (clear_mex_functions, ()); + + OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ()); + + // FIXME -- is this needed? Can it cause any trouble? + OCTAVE_SAFE_CALL (raw_mode, (0)); + + OCTAVE_SAFE_CALL (octave_history_write_timestamp, ()); + + if (! command_history::ignoring_entries ()) + OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ()); + + OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ()); + + OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ()); + + OCTAVE_SAFE_CALL (close_files, ()); + + OCTAVE_SAFE_CALL (cleanup_tmp_files, ()); + + OCTAVE_SAFE_CALL (symbol_table::cleanup, ()); + + OCTAVE_SAFE_CALL (sysdep_cleanup, ()); + + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); + + if (! quitting_gracefully && (interactive || forced_interactive)) + { + octave_stdout << "\n"; + + // Yes, we want this to be separate from the call to + // flush_octave_stdout above. + + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); + } + + // Don't call singleton_cleanup_list::cleanup until we have the + // problems with registering/unregistering types worked out. For + // example, uncomment the following line, then use the make_int + // function from the examples directory to create an integer + // object and then exit Octave. Octave should crash with a + // segfault when cleaning up the typinfo singleton. We need some + // way to force new octave_value_X types that are created in + // .oct files to be unregistered when the .oct file shared library + // is unloaded. + // + // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ()); + + OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ()); + } +} + void -clean_up_and_exit (int retval) +clean_up_and_exit (int retval, bool safe_to_return) { do_octave_atexit (); - if (octave_exit) - (*octave_exit) (retval == EOF ? 0 : retval); + if (octave_link::exit (retval)) + { + if (safe_to_return) + return; + else + { + // What should we do here? We might be called from some + // location other than the end of octave_execute_interpreter, + // so it might not be safe to return. + + // We have nothing else to do at this point, and the + // octave_link::exit function is supposed to take care of + // exiting for us. Assume that job won't take more than a + // day... + + gnulib::sleep (86400); + } + } + else + { + if (octave_exit) + (*octave_exit) (retval == EOF ? 0 : retval); + } } DEFUN (quit, args, , @@ -1007,89 +1097,6 @@ %!error system (1, 2, 3) */ -// FIXME -- this should really be static, but that causes -// problems on some systems. -std::list<std::string> octave_atexit_functions; - -void -do_octave_atexit (void) -{ - static bool deja_vu = false; - - while (! octave_atexit_functions.empty ()) - { - std::string fcn = octave_atexit_functions.front (); - - octave_atexit_functions.pop_front (); - - OCTAVE_SAFE_CALL (reset_error_handler, ()); - - OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0)); - - OCTAVE_SAFE_CALL (flush_octave_stdout, ()); - } - - if (! deja_vu) - { - deja_vu = true; - - // Do this explicitly so that destructors for mex file objects - // are called, so that functions registered with mexAtExit are - // called. - OCTAVE_SAFE_CALL (clear_mex_functions, ()); - - OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ()); - - // FIXME -- is this needed? Can it cause any trouble? - OCTAVE_SAFE_CALL (raw_mode, (0)); - - OCTAVE_SAFE_CALL (octave_history_write_timestamp, ()); - - if (! command_history::ignoring_entries ()) - OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ()); - - OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ()); - - OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ()); - - OCTAVE_SAFE_CALL (close_files, ()); - - OCTAVE_SAFE_CALL (cleanup_tmp_files, ()); - - OCTAVE_SAFE_CALL (symbol_table::cleanup, ()); - - OCTAVE_SAFE_CALL (cleanup_parser, ()); - - OCTAVE_SAFE_CALL (sysdep_cleanup, ()); - - OCTAVE_SAFE_CALL (flush_octave_stdout, ()); - - if (! quitting_gracefully && (interactive || forced_interactive)) - { - octave_stdout << "\n"; - - // Yes, we want this to be separate from the call to - // flush_octave_stdout above. - - OCTAVE_SAFE_CALL (flush_octave_stdout, ()); - } - - // Don't call singleton_cleanup_list::cleanup until we have the - // problems with registering/unregistering types worked out. For - // example, uncomment the following line, then use the make_int - // function from the examples directory to create an integer - // object and then exit Octave. Octave should crash with a - // segfault when cleaning up the typinfo singleton. We need some - // way to force new octave_value_X types that are created in - // .oct files to be unregistered when the .oct file shared library - // is unloaded. - // - // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ()); - - OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ()); - } -} - void octave_add_atexit_function (const std::string& fname) {
--- a/libinterp/interpfcn/toplev.h +++ b/libinterp/interpfcn/toplev.h @@ -52,16 +52,13 @@ extern OCTINTERP_API int exit_status; extern OCTINTERP_API void -clean_up_and_exit (int); +clean_up_and_exit (int status, bool safe_to_return = false); extern OCTINTERP_API void recover_from_exception (void); extern OCTINTERP_API int main_loop (void); extern OCTINTERP_API void -do_octave_atexit (void); - -extern OCTINTERP_API void octave_add_atexit_function (const std::string& fname); extern OCTINTERP_API bool @@ -84,14 +81,17 @@ { call_stack_elt (octave_function *f, symbol_table::scope_id s, symbol_table::context_id c, size_t p = 0) - : fcn (f), stmt (0), scope (s), context (c), prev (p) { } + : fcn (f), line (-1), column (-1), scope (s), context (c), prev (p) + { } call_stack_elt (const call_stack_elt& elt) - : fcn (elt.fcn), stmt (elt.stmt), scope (elt.scope), - context (elt.context), prev (elt.prev) { } + : fcn (elt.fcn), line (elt.line), column (elt.column), + scope (elt.scope), context (elt.context), prev (elt.prev) + { } octave_function *fcn; - tree_statement *stmt; + int line; + int column; symbol_table::scope_id scope; symbol_table::context_id context; size_t prev; @@ -134,12 +134,6 @@ return instance_ok () ? instance->do_current () : 0; } - // Current statement (top of stack). - static tree_statement *current_statement (void) - { - return instance_ok () ? instance->do_current_statement () : 0; - } - // Current line in current function. static int current_line (void) { @@ -226,10 +220,22 @@ instance->do_push (0, scope, context); } - static void set_statement (tree_statement *s) + static void set_location (int l, int c) { if (instance_ok ()) - instance->do_set_statement (s); + instance->do_set_location (l, c); + } + + static void set_line (int l) + { + if (instance_ok ()) + instance->do_set_line (l); + } + + static void set_column (int c) + { + if (instance_ok ()) + instance->do_set_column (c); } static bool goto_frame (size_t n = 0, bool verbose = false) @@ -365,25 +371,34 @@ return retval; } - tree_statement *do_current_statement (void) const - { - tree_statement *retval = 0; - - if (! cs.empty ()) - { - const call_stack_elt& elt = cs[curr_frame]; - retval = elt.stmt; - } - - return retval; - } - - void do_set_statement (tree_statement *s) + void do_set_location (int l, int c) { if (! cs.empty ()) { call_stack_elt& elt = cs.back (); - elt.stmt = s; + + elt.line = l; + elt.column = c; + } + } + + void do_set_line (int l) + { + if (! cs.empty ()) + { + call_stack_elt& elt = cs.back (); + + elt.line = l; + } + } + + void do_set_column (int c) + { + if (! cs.empty ()) + { + call_stack_elt& elt = cs.back (); + + elt.column = c; } }
--- a/libinterp/interpfcn/variables.cc +++ b/libinterp/interpfcn/variables.cc @@ -49,6 +49,7 @@ #include "input.h" #include "lex.h" #include "load-path.h" +#include "octave-link.h" #include "oct-map.h" #include "oct-obj.h" #include "ov.h" @@ -616,7 +617,7 @@ void set_global_value (const std::string& nm, const octave_value& val) { - symbol_table::global_varref (nm) = val; + symbol_table::global_assign (nm, val); } octave_value @@ -633,7 +634,7 @@ void set_top_level_value (const std::string& nm, const octave_value& val) { - symbol_table::top_level_varref (nm) = val; + symbol_table::top_level_assign (nm, val); } // Variable values. @@ -1881,7 +1882,7 @@ } else { - symbol_table::force_varref (ans) = val; + symbol_table::force_assign (ans, val); if (print) val.print_with_name (octave_stdout, ans); @@ -2342,6 +2343,8 @@ { do_clear_globals (argv, argc, true); do_clear_variables (argv, argc, true); + + octave_link::clear_workspace (); } else { @@ -2453,6 +2456,8 @@ do_clear_symbols (argv, argc, idx, exclusive); } } + + octave_link::set_workspace (); } } }
new file mode 100644 --- /dev/null +++ b/libinterp/interpfcn/workspace-element.h @@ -0,0 +1,84 @@ +/* + +Copyright (C) 2013 John W. Eaton + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#if !defined (octave_workspace_element_h) +#define octave_workspace_element_h 1 + +#include <string> + +class workspace_element +{ +public: + + workspace_element (char scope_arg = 'l', + const std::string& symbol_arg = "<name>", + const std::string& class_name_arg = "<class>", + const std::string& value_arg = "<value>", + const std::string& dimension_arg = "<dimension>") + : xscope (scope_arg), xsymbol (symbol_arg), + xclass_name (class_name_arg), xvalue (value_arg), + xdimension (dimension_arg) + { } + + workspace_element (const workspace_element& ws_elt) + : xscope (ws_elt.xscope), xsymbol (ws_elt.xsymbol), + xclass_name (ws_elt.xclass_name), xvalue (ws_elt.xvalue), + xdimension (ws_elt.xdimension) + { } + + workspace_element operator = (const workspace_element& ws_elt) + { + if (this != &ws_elt) + { + xscope = ws_elt.xscope; + xsymbol = ws_elt.xsymbol; + xclass_name = ws_elt.xclass_name; + xvalue = ws_elt.xvalue; + xdimension = ws_elt.xdimension; + } + + return *this; + } + + ~workspace_element (void) { } + + char scope (void) const { return xscope; } + + std::string symbol (void) const { return xsymbol; } + + std::string class_name (void) const { return xclass_name; } + + std::string value (void) const { return xvalue; } + + std::string dimension (void) const { return xdimension; } + +private: + + // [g]lobal, [p]ersistent, [l]ocal + char xscope; + std::string xsymbol; + std::string xclass_name; + std::string xvalue; + std::string xdimension; +}; + +#endif
--- a/libinterp/octave-value/ov-base-scalar.cc +++ b/libinterp/octave-value/ov-base-scalar.cc @@ -169,6 +169,15 @@ } template <class ST> +std::string +octave_base_scalar<ST>::short_disp (void) const +{ + std::ostringstream buf; + octave_print_internal (buf, scalar); + return buf.str (); +} + +template <class ST> bool octave_base_scalar<ST>::fast_elem_insert_self (void *where, builtin_type_t btyp) const {
--- a/libinterp/octave-value/ov-base-scalar.h +++ b/libinterp/octave-value/ov-base-scalar.h @@ -138,6 +138,8 @@ bool print_name_tag (std::ostream& os, const std::string& name) const; + std::string short_disp (void) const; + // Unsafe. This function exists to support the MEX interface. // You should not use it anywhere else. void *mex_get_data (void) const { return const_cast<ST *> (&scalar); }
--- a/libinterp/octave-value/ov-base.cc +++ b/libinterp/octave-value/ov-base.cc @@ -484,6 +484,9 @@ INT_CONV_METHOD (long int, long) INT_CONV_METHOD (unsigned long int, ulong) +INT_CONV_METHOD (int64_t, int64) +INT_CONV_METHOD (uint64_t, uint64) + int octave_base_value::nint_value (bool frc_str_conv) const {
--- a/libinterp/octave-value/ov-base.h +++ b/libinterp/octave-value/ov-base.h @@ -461,6 +461,10 @@ virtual unsigned long int ulong_value (bool = false, bool = false) const; + virtual int64_t int64_value (bool = false, bool = false) const; + + virtual uint64_t uint64_value (bool = false, bool = false) const; + virtual double double_value (bool = false) const; virtual float float_value (bool = false) const; @@ -612,6 +616,8 @@ print_with_name (std::ostream& output_buf, const std::string& name, bool print_padding = true); + virtual std::string short_disp (void) const { return "..."; } + virtual void print_info (std::ostream& os, const std::string& prefix) const; virtual bool save_ascii (std::ostream& os);
--- a/libinterp/octave-value/ov-fcn-handle.cc +++ b/libinterp/octave-value/ov-fcn-handle.cc @@ -466,7 +466,7 @@ break; } - symbol_table::varref (name, local_scope, 0) = t2; + symbol_table::assign (name, t2, local_scope, 0); } } } @@ -651,7 +651,7 @@ break; } - symbol_table::varref (name, local_scope) = t2; + symbol_table::assign (name, t2, local_scope); } } @@ -1159,7 +1159,7 @@ break; } - symbol_table::varref (dsub.name, local_scope) = dsub.tc; + symbol_table::assign (dsub.name, dsub.tc, local_scope); } } }
--- a/libinterp/octave-value/ov-float.cc +++ b/libinterp/octave-value/ov-float.cc @@ -306,7 +306,7 @@ SCALAR_MAPPER (exp, ::expf); SCALAR_MAPPER (expm1, ::expm1f); SCALAR_MAPPER (fix, ::fix); - SCALAR_MAPPER (floor, ::floorf); + SCALAR_MAPPER (floor, gnulib::floorf); SCALAR_MAPPER (log, rc_log); SCALAR_MAPPER (log2, rc_log2); SCALAR_MAPPER (log10, rc_log10);
--- a/libinterp/octave-value/ov-java.cc +++ b/libinterp/octave-value/ov-java.cc @@ -1224,6 +1224,15 @@ jcls = reinterpret_cast<jclass> (jni_env->GetStaticObjectField (dcls, fid)); jobj = jni_env->NewObject (dcls, mid, dval); } + else if (val.is_bool_type ()) + { + 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 { float fval = val.float_scalar_value (); @@ -1243,15 +1252,6 @@ jcls = reinterpret_cast<jclass> (jni_env->GetStaticObjectField (icls, fid)); jobj = jni_env->NewObject (icls, mid, ival); } - 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_empty ()) { jobj = 0;
--- a/libinterp/octave-value/ov-range.cc +++ b/libinterp/octave-value/ov-range.cc @@ -387,6 +387,31 @@ return retval; } +std::string +octave_range::short_disp (void) const +{ + std::ostringstream buf; + + octave_idx_type len = range.nelem (); + + if (len == 0) + buf << "[]"; + else + { + buf << range.base () << ":"; + + if (len > 1) + { + if (range.inc () != 1) + buf << range.inc () << ":"; + + buf << range.limit (); + } + } + + return buf.str (); +} + // Skip white space and comments on stream IS. static void
--- a/libinterp/octave-value/ov-range.h +++ b/libinterp/octave-value/ov-range.h @@ -255,6 +255,8 @@ bool print_name_tag (std::ostream& os, const std::string& name) const; + std::string short_disp (void) const; + bool save_ascii (std::ostream& os); bool load_ascii (std::istream& is);
--- a/libinterp/octave-value/ov-usr-fcn.cc +++ b/libinterp/octave-value/ov-usr-fcn.cc @@ -97,6 +97,9 @@ octave_user_script::~octave_user_script (void) { + if (cmd_list) + cmd_list->remove_all_breakpoints (file_name); + delete cmd_list; } @@ -207,6 +210,9 @@ octave_user_function::~octave_user_function (void) { + if (cmd_list) + cmd_list->remove_all_breakpoints (file_name); + delete param_list; delete ret_list; delete cmd_list; @@ -637,8 +643,8 @@ // which might be redefined in a function. Keep the old argn name // for backward compatibility of functions that use it directly. - symbol_table::force_varref ("argn") = arg_names; - symbol_table::force_varref (".argn.") = Cell (arg_names); + symbol_table::force_assign ("argn", arg_names); + symbol_table::force_assign (".argn.", Cell (arg_names)); symbol_table::mark_hidden (".argn."); @@ -646,8 +652,8 @@ symbol_table::mark_automatic (".argn."); } - symbol_table::force_varref (".nargin.") = nargin; - symbol_table::force_varref (".nargout.") = nargout; + symbol_table::force_assign (".nargin.", nargin); + symbol_table::force_assign (".nargout.", nargout); symbol_table::mark_hidden (".nargin."); symbol_table::mark_hidden (".nargout."); @@ -655,16 +661,16 @@ symbol_table::mark_automatic (".nargin."); symbol_table::mark_automatic (".nargout."); - symbol_table::varref (".saved_warning_states.") = octave_value (); + symbol_table::assign (".saved_warning_states."); symbol_table::mark_automatic (".saved_warning_states."); symbol_table::mark_automatic (".saved_warning_states."); if (takes_varargs ()) - symbol_table::varref ("varargin") = va_args.cell_value (); + symbol_table::assign ("varargin", va_args.cell_value ()); // Force .ignored. variable to be undefined by default. - symbol_table::varref (".ignored.") = octave_value (); + symbol_table::assign (".ignored."); if (lvalue_list) { @@ -686,7 +692,7 @@ k += p->numel (); } - symbol_table::varref (".ignored.") = bh; + symbol_table::assign (".ignored.", bh); } }
--- a/libinterp/octave-value/ov-usr-fcn.h +++ b/libinterp/octave-value/ov-usr-fcn.h @@ -469,20 +469,6 @@ jit_function_info *jit_info; #endif -#if 0 - // The symbol record for argn in the local symbol table. - octave_value& argn_varref; - - // The symbol record for nargin in the local symbol table. - octave_value& nargin_varref; - - // The symbol record for nargout in the local symbol table. - octave_value& nargout_varref; - - // The symbol record for varargin in the local symbol table. - octave_value& varargin_varref; -#endif - void print_code_function_header (void); void print_code_function_trailer (void);
--- a/libinterp/octave-value/ov.cc +++ b/libinterp/octave-value/ov.cc @@ -1541,12 +1541,10 @@ octave_idx_type octave_value::idx_type_value (bool req_int, bool frc_str_conv) const { -#if SIZEOF_OCTAVE_IDX_TYPE == SIZEOF_LONG - return long_value (req_int, frc_str_conv); -#elif SIZEOF_OCTAVE_IDX_TYPE == SIZEOF_INT +#if defined (USE_64_BIT_IDX_T) + return int64_value (req_int, frc_str_conv); +#else return int_value (req_int, frc_str_conv); -#else -#error "no octave_value extractor for octave_idx_type" #endif }
--- a/libinterp/octave-value/ov.h +++ b/libinterp/octave-value/ov.h @@ -734,6 +734,14 @@ ulong_value (bool req_int = false, bool frc_str_conv = false) const { return rep->ulong_value (req_int, frc_str_conv); } + int64_t + int64_value (bool req_int = false, bool frc_str_conv = false) const + { return rep->int64_value (req_int, frc_str_conv); } + + uint64_t + uint64_value (bool req_int = false, bool frc_str_conv = false) const + { return rep->uint64_value (req_int, frc_str_conv); } + octave_idx_type idx_type_value (bool req_int = false, bool frc_str_conv = false) const; @@ -1014,6 +1022,8 @@ void print_with_name (std::ostream& os, const std::string& name) const { rep->print_with_name (os, name, true); } + std::string short_disp (void) const { return rep->short_disp (); } + int type_id (void) const { return rep->type_id (); } std::string type_name (void) const { return rep->type_name (); }
--- a/libinterp/octave.cc +++ b/libinterp/octave.cc @@ -179,6 +179,9 @@ // If TRUE, the GUI should be started. static bool start_gui = false; +// If TRUE use traditional settings (--traditional) +static bool traditional = false; + // Long options. See the comments in getopt.h for the meanings of the // fields in this structure. #define BUILT_IN_DOCSTRINGS_FILE_OPTION 1 @@ -244,7 +247,7 @@ { assert (symbol_table::at_top_level ()); - symbol_table::varref (".nargin.") = argc - 1; + symbol_table::assign (".nargin.", argc - 1); symbol_table::mark_hidden (".nargin."); @@ -815,7 +818,7 @@ break; case TRADITIONAL_OPTION: - maximum_braindamage (); + traditional = true; break; default: @@ -850,6 +853,11 @@ octave_thread::init (); + set_default_prompts (); + + if (traditional) + maximum_braindamage (); + init_signals (); octave_ieee_init (); @@ -894,12 +902,6 @@ if (no_window_system) display_info::no_window_system (); - // Make sure we clean up when we exit. Also allow users to register - // functions. If we don't have atexit or on_exit, we're going to - // leave some junk files around if we exit abnormally. - - atexit (do_octave_atexit); - // Is input coming from a terminal? If so, we are probably // interactive. @@ -1011,14 +1013,11 @@ int retval = main_loop (); - if (retval == 1 && ! error_state) - retval = 0; - quitting_gracefully = true; - clean_up_and_exit (retval); + clean_up_and_exit (retval, true); - return 0; + return retval; } static bool
--- a/libinterp/parse-tree/lex.h +++ b/libinterp/parse-tree/lex.h @@ -33,29 +33,9 @@ #include "input.h" #include "token.h" -extern OCTINTERP_API void cleanup_parser (void); - // Is the given string a keyword? extern bool is_keyword (const std::string& s); -class -stream_reader -{ -public: - virtual int getc (void) = 0; - virtual int ungetc (int c) = 0; - -protected: - stream_reader (void) { } - ~stream_reader (void) { } - -private: - - // No copying! - stream_reader (const stream_reader&); - stream_reader& operator = (const stream_reader&); -}; - // For communication between the lexer and parser. class @@ -63,6 +43,55 @@ { public: + // Track symbol table information when parsing functions. + + class symbol_table_context + { + public: + + symbol_table_context (void) + : frame_stack (), init_scope (symbol_table::current_scope ()) + { + push (init_scope); + } + + void clear (void) + { + while (! frame_stack.empty ()) + frame_stack.pop (); + + push (init_scope); + } + + bool empty (void) const { return frame_stack.empty (); } + + void pop (void) + { + frame_stack.pop (); + } + + void push (symbol_table::scope_id scope) + { + frame_stack.push (scope); + } + + void push (void) + { + push (symbol_table::current_scope ()); + } + + symbol_table::scope_id curr_scope (void) const + { + return frame_stack.top (); + } + + private: + + std::stack<symbol_table::scope_id> frame_stack; + + symbol_table::scope_id init_scope; + }; + // Track nesting of square brackets, curly braces, and parentheses. class bbp_nesting_level @@ -255,7 +284,7 @@ current_input_line (), comment_text (), help_text (), fcn_file_name (), fcn_file_full_name (), looking_at_object_index (), parsed_function_name (), pending_local_variables (), - nesting_level (), tokens () + symtab_context (), nesting_level (), tokens () { init (); } @@ -280,6 +309,11 @@ bool previous_token_may_be_command (void) const; + void maybe_mark_previous_token_as_variable (void); + + void mark_as_variable (const std::string& nm); + void mark_as_variables (const std::list<std::string>& lst); + // true means that we have encountered eof on the input stream. bool end_of_input; @@ -403,6 +437,9 @@ // set of identifiers that might be local variable names. std::set<std::string> pending_local_variables; + // Track current symbol table scope and context. + symbol_table_context symtab_context; + // is the closest nesting level a square bracket, squiggly brace, // a paren, or an anonymous function body? bbp_nesting_level nesting_level; @@ -419,13 +456,13 @@ lexical_feedback& operator = (const lexical_feedback&); }; -// octave_lexer inherits from lexical_feedback because we will +// octave_base_lexer inherits from lexical_feedback because we will // eventually have several different constructors and it is easier to // intialize if everything is grouped in a parent class rather than -// listing all the members in the octave_lexer class. +// listing all the members in the octave_base_lexer class. class -octave_lexer : public lexical_feedback +octave_base_lexer : public lexical_feedback { public: @@ -456,35 +493,27 @@ bool eof; }; - octave_lexer (void) - : lexical_feedback (), scanner (0), input_buf (), input_reader () - { - init (); - } - - octave_lexer (FILE *file) - : lexical_feedback (), scanner (0), input_buf (), - input_reader (file) + octave_base_lexer (void) + : lexical_feedback (), scanner (0), input_buf () { init (); } - octave_lexer (const std::string& eval_string) - : lexical_feedback (), scanner (0), input_buf (), - input_reader (eval_string) - { - init (); - } - - ~octave_lexer (void); + virtual ~octave_base_lexer (void); void init (void); - void reset (void); + virtual bool is_push_lexer (void) const { return false; } + + virtual void reset (void); void prep_for_file (void); - int read (char *buf, unsigned int max_size); + virtual int fill_flex_buffer (char *buf, unsigned int max_size) = 0; + + bool at_end_of_buffer (void) const { return input_buf.empty (); } + + bool at_end_of_file (void) const { return input_buf.at_eof (); } int handle_end_of_input (void); @@ -502,6 +531,8 @@ bool inside_any_object_index (void); + bool is_variable (const std::string& name); + int is_keyword_token (const std::string& s); bool whitespace_is_significant (void); @@ -510,8 +541,7 @@ void handle_continuation (void); - void finish_comment (octave_comment_elt::comment_type typ, - bool looking_at_continuation = false); + void finish_comment (octave_comment_elt::comment_type typ); bool have_continuation (bool trailing_comments_ok = true); @@ -557,35 +587,21 @@ // Object that reads and buffers input. input_buffer input_buf; - octave_input_reader input_reader; + virtual void increment_promptflag (void) = 0; - void increment_promptflag (void) { input_reader.increment_promptflag (); } - - void decrement_promptflag (void) { input_reader.decrement_promptflag (); } + virtual void decrement_promptflag (void) = 0; - int promptflag (void) const { return input_reader.promptflag (); } - - int promptflag (int n) { return input_reader.promptflag (n); } + virtual int promptflag (void) const = 0; - std::string input_source (void) const - { - return input_reader.input_source (); - } + virtual int promptflag (int) = 0; - bool input_from_terminal (void) const - { - return input_source () == "terminal"; - } + virtual std::string input_source (void) const { return "unknown"; } + + virtual bool input_from_terminal (void) const { return false; } - bool input_from_file (void) const - { - return input_source () == "file"; - } + virtual bool input_from_file (void) const { return false; } - bool input_from_eval_string (void) const - { - return input_source () == "eval_string"; - } + virtual bool input_from_eval_string (void) const { return false; } void push_start_state (int state); @@ -624,17 +640,136 @@ int show_token (int tok); // For unwind protect. - static void cleanup (octave_lexer *lexer) { delete lexer; } + static void cleanup (octave_base_lexer *lexer) { delete lexer; } -private: +protected: std::stack<int> start_state_stack; // No copying! + octave_base_lexer (const octave_base_lexer&); + + octave_base_lexer& operator = (const octave_base_lexer&); +}; + +class +octave_lexer : public octave_base_lexer +{ +public: + + octave_lexer (void) + : octave_base_lexer (), input_reader () + { } + + octave_lexer (FILE *file) + : octave_base_lexer (), input_reader (file) + { } + + octave_lexer (const std::string& eval_string) + : octave_base_lexer (), input_reader (eval_string) + { } + + void reset (void) + { + input_reader.reset (); + + octave_base_lexer::reset (); + } + + void increment_promptflag (void) { input_reader.increment_promptflag (); } + + void decrement_promptflag (void) { input_reader.decrement_promptflag (); } + + int promptflag (void) const { return input_reader.promptflag (); } + + int promptflag (int n) { return input_reader.promptflag (n); } + + std::string input_source (void) const + { + return input_reader.input_source (); + } + + bool input_from_terminal (void) const + { + return input_source () == "terminal"; + } + + bool input_from_file (void) const + { + return input_source () == "file"; + } + + bool input_from_eval_string (void) const + { + return input_source () == "eval_string"; + } + + int fill_flex_buffer (char *buf, unsigned int max_size); + + octave_input_reader input_reader; + +protected: + + // No copying! + octave_lexer (const octave_lexer&); octave_lexer& operator = (const octave_lexer&); }; +class +octave_push_lexer : public octave_base_lexer +{ +public: + + octave_push_lexer (const std::string& input = std::string (), + bool eof = false) + : octave_base_lexer (), pflag (1) + { + append_input (input, eof); + } + + bool is_push_lexer (void) const { return true; } + + void reset (void) + { + promptflag (1); + + octave_base_lexer::reset (); + } + + void append_input (const std::string& input, bool eof) + { + input_buf.fill (input, eof); + } + + void increment_promptflag (void) { pflag++; } + + void decrement_promptflag (void) { pflag--; } + + int promptflag (void) const { return pflag; } + + int promptflag (int n) + { + int retval = pflag; + pflag = n; + return retval; + } + + std::string input_source (void) const { return "push buffer"; } + + int fill_flex_buffer (char *buf, unsigned int max_size); + +protected: + + int pflag; + + // No copying! + + octave_push_lexer (const octave_push_lexer&); + + octave_push_lexer& operator = (const octave_push_lexer&); +}; + #endif
--- a/libinterp/parse-tree/lex.ll +++ b/libinterp/parse-tree/lex.ll @@ -84,7 +84,6 @@ #include "lex.h" #include "ov.h" #include "parse.h" -#include "parse-private.h" #include "pt-all.h" #include "symtab.h" #include "token.h" @@ -111,7 +110,7 @@ #error lex.l requires flex version 2.5.4 or later #endif -#define YY_EXTRA_TYPE octave_lexer * +#define YY_EXTRA_TYPE octave_base_lexer * #define curr_lexer yyextra // Arrange to get input via readline. @@ -120,7 +119,7 @@ #undef YY_INPUT #endif #define YY_INPUT(buf, result, max_size) \ - result = curr_lexer->read (buf, max_size) + result = curr_lexer->fill_flex_buffer (buf, max_size) // Try to avoid crashing out completely on fatal scanner errors. @@ -331,7 +330,7 @@ curr_lexer->looking_for_object_index = true; curr_lexer->at_beginning_of_statement = false; - int tok_to_return = curr_lexer->handle_close_bracket (']'); + curr_lexer->handle_close_bracket (']'); return curr_lexer->count_token (']'); } @@ -348,7 +347,7 @@ curr_lexer->looking_for_object_index = true; curr_lexer->at_beginning_of_statement = false; - int tok_to_return = curr_lexer->handle_close_bracket ('}'); + curr_lexer->handle_close_bracket ('}'); return curr_lexer->count_token ('}'); } @@ -437,6 +436,8 @@ curr_lexer->pop_start_state (); } + curr_lexer->decrement_promptflag (); + curr_lexer->push_start_state (BLOCK_COMMENT_START); } @@ -471,7 +472,13 @@ curr_lexer->finish_comment (octave_comment_elt::block); curr_lexer->block_comment_nesting_level--; - curr_lexer->pop_start_state (); + + if (curr_lexer->block_comment_nesting_level == 0) + { + curr_lexer->increment_promptflag (); + + curr_lexer->pop_start_state (); + } } %{ @@ -519,18 +526,49 @@ break; } + size_t num_comment_chars = 0; + while (i < len) { char c = yytext[i]; if (c == '#' || c == '%') - i++; + { + num_comment_chars++; + i++; + } else break; } - + curr_lexer->comment_text += &yytext[i]; - if (! full_line_comment) + if (full_line_comment) + { + if (yytext[i++] == '{') + { + bool looks_like_block_comment = true; + + while (i < len) + { + char c = yytext[i++]; + if (! (c == ' ' || c == '\t' || c == '\n')) + { + looks_like_block_comment = false; + break; + } + } + + if (looks_like_block_comment) + { + yyless (0); + + curr_lexer->finish_comment (octave_comment_elt::full_line); + + curr_lexer->pop_start_state (); + } + } + } + else { if (have_space) curr_lexer->mark_previous_token_trailing_space (); @@ -538,6 +576,9 @@ curr_lexer->finish_comment (octave_comment_elt::end_of_line); curr_lexer->pop_start_state (); + + curr_lexer->xunput ('\n'); + curr_lexer->input_line_number--; } } @@ -562,20 +603,29 @@ {NUMBER}{Im} { curr_lexer->lexer_debug ("{NUMBER}{Im}"); - int tok = curr_lexer->previous_token_value (); - - if (curr_lexer->whitespace_is_significant () - && curr_lexer->space_follows_previous_token () - && ! (tok == '[' || tok == '{' - || curr_lexer->previous_token_is_binop ())) + if (curr_lexer->previous_token_may_be_command () + && curr_lexer->space_follows_previous_token ()) { yyless (0); - unput (','); + curr_lexer->push_start_state (COMMAND_START); } else { - curr_lexer->handle_number (); - return curr_lexer->count_token_internal (IMAG_NUM); + int tok = curr_lexer->previous_token_value (); + + if (curr_lexer->whitespace_is_significant () + && curr_lexer->space_follows_previous_token () + && ! (tok == '[' || tok == '{' + || curr_lexer->previous_token_is_binop ())) + { + yyless (0); + unput (','); + } + else + { + curr_lexer->handle_number (); + return curr_lexer->count_token_internal (IMAG_NUM); + } } } @@ -588,21 +638,30 @@ {NUMBER} { curr_lexer->lexer_debug ("{D}+/\\.[\\*/\\^\\']|{NUMBER}"); - int tok = curr_lexer->previous_token_value (); - - if (curr_lexer->whitespace_is_significant () - && curr_lexer->space_follows_previous_token () - && ! (tok == '[' || tok == '{' - || curr_lexer->previous_token_is_binop ())) - { - yyless (0); - unput (','); - } - else - { - curr_lexer->handle_number (); - return curr_lexer->count_token_internal (NUM); - } + if (curr_lexer->previous_token_may_be_command () + && curr_lexer->space_follows_previous_token ()) + { + yyless (0); + curr_lexer->push_start_state (COMMAND_START); + } + else + { + int tok = curr_lexer->previous_token_value (); + + if (curr_lexer->whitespace_is_significant () + && curr_lexer->space_follows_previous_token () + && ! (tok == '[' || tok == '{' + || curr_lexer->previous_token_is_binop ())) + { + yyless (0); + unput (','); + } + else + { + curr_lexer->handle_number (); + return curr_lexer->count_token_internal (NUM); + } + } } %{ @@ -610,7 +669,7 @@ // the <MATRIX_START> start state code above. %} -{S}* { +{S}+ { curr_lexer->current_input_column += yyleng; curr_lexer->mark_previous_token_trailing_space (); @@ -707,15 +766,24 @@ } "@" { - curr_lexer->lexer_debug ("@"); - - curr_lexer->current_input_column++; - - curr_lexer->looking_at_function_handle++; - curr_lexer->looking_for_object_index = false; - curr_lexer->at_beginning_of_statement = false; - - return curr_lexer->count_token ('@'); + if (curr_lexer->previous_token_may_be_command () + && curr_lexer->space_follows_previous_token ()) + { + yyless (0); + curr_lexer->push_start_state (COMMAND_START); + } + else + { + curr_lexer->lexer_debug ("@"); + + curr_lexer->current_input_column++; + + curr_lexer->looking_at_function_handle++; + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; + + return curr_lexer->count_token ('@'); + } } %{ @@ -730,16 +798,18 @@ curr_lexer->input_line_number++; curr_lexer->current_input_column = 1; - if (curr_lexer->nesting_level.none ()) + if (curr_lexer->nesting_level.is_paren ()) + { + curr_lexer->at_beginning_of_statement = false; + curr_lexer->gripe_matlab_incompatible + ("bare newline inside parentheses"); + } + else if (curr_lexer->nesting_level.none () + || curr_lexer->nesting_level.is_anon_fcn_body ()) { curr_lexer->at_beginning_of_statement = true; return curr_lexer->count_token ('\n'); } - else if (curr_lexer->nesting_level.is_paren ()) - { - curr_lexer->at_beginning_of_statement = false; - curr_lexer->gripe_matlab_incompatible ("bare newline inside parentheses"); - } else if (curr_lexer->nesting_level.is_bracket_or_brace ()) return LEXICAL_ERROR; } @@ -762,8 +832,6 @@ { int tok = curr_lexer->previous_token_value (); - bool transpose = false; - if (curr_lexer->whitespace_is_significant ()) { if (curr_lexer->space_follows_previous_token ()) @@ -830,8 +898,6 @@ { int tok = curr_lexer->previous_token_value (); - bool transpose = false; - if (curr_lexer->whitespace_is_significant ()) { if (curr_lexer->space_follows_previous_token ()) @@ -1028,17 +1094,31 @@ "." { curr_lexer->lexer_debug ("."); - curr_lexer->looking_for_object_index = false; - curr_lexer->at_beginning_of_statement = false; - - return curr_lexer->handle_token ('.'); + if (curr_lexer->previous_token_may_be_command () + && curr_lexer->space_follows_previous_token ()) + { + yyless (0); + curr_lexer->push_start_state (COMMAND_START); + } + else + { + curr_lexer->looking_for_object_index = false; + curr_lexer->at_beginning_of_statement = false; + + return curr_lexer->handle_token ('.'); + } } %{ // = and op= operators. %} -"=" { return curr_lexer->handle_op ("=", '='); } +"=" { + curr_lexer->maybe_mark_previous_token_as_variable (); + + return curr_lexer->handle_op ("=", '='); + } + "+=" { return curr_lexer->handle_incompatible_op ("+=", ADD_EQ); } "-=" { return curr_lexer->handle_incompatible_op ("-=", SUB_EQ); } "*=" { return curr_lexer->handle_incompatible_op ("*=", MUL_EQ); } @@ -1129,7 +1209,11 @@ int c = curr_lexer->text_yyinput (); - if (c != EOF) + if (c == 1) + return -1; + else if (c == EOF) + return curr_lexer->handle_end_of_input (); + else { curr_lexer->current_input_column++; @@ -1139,8 +1223,6 @@ return LEXICAL_ERROR; } - else - return curr_lexer->handle_end_of_input (); } %% @@ -1291,26 +1373,6 @@ } } -void -cleanup_parser (void) -{ -} - -// Return 1 if the given character matches any character in the given -// string. - -static bool -match_any (char c, const char *s) -{ - char tmp; - while ((tmp = *s++) != '\0') - { - if (c == tmp) - return true; - } - return false; -} - bool is_keyword (const std::string& s) { @@ -1553,6 +1615,24 @@ return tok ? tok->may_be_command () : false; } +void +lexical_feedback::maybe_mark_previous_token_as_variable (void) +{ + token *tok = tokens.front (); + if (tok->is_symbol ()) + pending_local_variables.insert (tok->symbol_name ()); +} + +void +lexical_feedback::mark_as_variables (const std::list<std::string>& lst) +{ + for (std::list<std::string>::const_iterator p = lst.begin (); + p != lst.end (); p++) + { + pending_local_variables.insert (*p); + } +} + static bool looks_like_copyright (const std::string& s) { @@ -1569,7 +1649,7 @@ } void -octave_lexer::input_buffer::fill (const std::string& input, bool eof_arg) +octave_base_lexer::input_buffer::fill (const std::string& input, bool eof_arg) { buffer = input; chars_left = buffer.length (); @@ -1578,7 +1658,7 @@ } int -octave_lexer::input_buffer::copy_chunk (char *buf, size_t max_size) +octave_base_lexer::input_buffer::copy_chunk (char *buf, size_t max_size) { static const char * const eol = "\n"; @@ -1603,7 +1683,7 @@ { // There isn't enough room to plug the newline character // in the buffer so arrange to have it returned on the next - // call to octave_lexer::read. + // call to octave_base_lexer::read. pos = eol; chars_left = 1; } @@ -1612,17 +1692,17 @@ return len; } -octave_lexer::~octave_lexer (void) +octave_base_lexer::~octave_base_lexer (void) { yylex_destroy (scanner); } void -octave_lexer::init (void) +octave_base_lexer::init (void) { yylex_init (&scanner); - // Make octave_lexer object available through yyextra in + // Make octave_base_lexer object available through yyextra in // flex-generated lexer. yyset_extra (this, scanner); @@ -1630,7 +1710,7 @@ } // Inside Flex-generated functions, yyg is the scanner cast to its real -// type. Some flex macros that we use in octave_lexer member functions +// type. Some flex macros that we use in octave_base_lexer member functions // (for example, BEGIN) use yyg. If we could perform the actions of // these macros with functions instead, we could eliminate the // OCTAVE_YYG macro. @@ -1639,12 +1719,12 @@ struct yyguts_t *yyg = static_cast<struct yyguts_t*> (scanner) void -octave_lexer::reset (void) +octave_base_lexer::reset (void) { // Start off on the right foot. clear_start_state (); - parser_symtab_context.clear (); + symtab_context.clear (); // We do want a prompt by default. promptflag (1); @@ -1660,13 +1740,11 @@ || input_from_eval_string ())) yyrestart (stdin, scanner); - input_reader.reset (); - lexical_feedback::reset (); } void -octave_lexer::prep_for_file (void) +octave_base_lexer::prep_for_file (void) { reading_script_file = true; @@ -1674,32 +1752,7 @@ } int -octave_lexer::read (char *buf, unsigned max_size) -{ - int status = 0; - - if (input_buf.empty ()) - { - bool eof = false; - current_input_line = input_reader.get_input (eof); - input_buf.fill (current_input_line, eof); - } - - if (! input_buf.empty ()) - status = input_buf.copy_chunk (buf, max_size); - else - { - status = YY_NULL; - - if (! input_buf.at_eof ()) - fatal_error ("octave_lexer::read () in flex scanner failed"); - } - - return status; -} - -int -octave_lexer::handle_end_of_input (void) +octave_base_lexer::handle_end_of_input (void) { lexer_debug ("<<EOF>>"); @@ -1717,19 +1770,19 @@ } char * -octave_lexer::flex_yytext (void) +octave_base_lexer::flex_yytext (void) { return yyget_text (scanner); } int -octave_lexer::flex_yyleng (void) +octave_base_lexer::flex_yyleng (void) { return yyget_leng (scanner); } int -octave_lexer::text_yyinput (void) +octave_base_lexer::text_yyinput (void) { int c = yyinput (scanner); @@ -1764,7 +1817,7 @@ } void -octave_lexer::xunput (char c, char *buf) +octave_base_lexer::xunput (char c, char *buf) { if (c != EOF) { @@ -1780,7 +1833,7 @@ } void -octave_lexer::xunput (char c) +octave_base_lexer::xunput (char c) { char *yytxt = flex_yytext (); @@ -1788,7 +1841,7 @@ } bool -octave_lexer::looking_at_space (void) +octave_base_lexer::looking_at_space (void) { int c = text_yyinput (); xunput (c); @@ -1796,7 +1849,7 @@ } bool -octave_lexer::inside_any_object_index (void) +octave_base_lexer::inside_any_object_index (void) { bool retval = false; @@ -1813,10 +1866,18 @@ return retval; } +bool +octave_base_lexer::is_variable (const std::string& name) +{ + return (symbol_table::is_variable (name) + || (pending_local_variables.find (name) + != pending_local_variables.end ())); +} + // Handle keywords. Return -1 if the keyword should be ignored. int -octave_lexer::is_keyword_token (const std::string& s) +octave_base_lexer::is_keyword_token (const std::string& s) { int l = input_line_number; int c = current_input_column; @@ -2047,7 +2108,7 @@ } bool -octave_lexer::whitespace_is_significant (void) +octave_base_lexer::whitespace_is_significant (void) { return (nesting_level.is_bracket () || (nesting_level.is_brace () @@ -2061,7 +2122,7 @@ } void -octave_lexer::handle_number (void) +octave_base_lexer::handle_number (void) { double value = 0.0; int nread = 0; @@ -2104,7 +2165,7 @@ } void -octave_lexer::handle_continuation (void) +octave_base_lexer::handle_continuation (void) { char *yytxt = flex_yytext (); int yylng = flex_yyleng (); @@ -2148,7 +2209,7 @@ { comment_text = &yytxt[offset]; - finish_comment (octave_comment_elt::end_of_line, true); + finish_comment (octave_comment_elt::end_of_line); } decrement_promptflag (); @@ -2157,8 +2218,7 @@ } void -octave_lexer::finish_comment (octave_comment_elt::comment_type typ, - bool looking_at_continuation) +octave_base_lexer::finish_comment (octave_comment_elt::comment_type typ) { bool copyright = looks_like_copyright (comment_text); @@ -2174,13 +2234,6 @@ comment_text = ""; at_beginning_of_statement = true; - - if (! looking_at_continuation) - { - xunput ('\n'); - // Adjust for newline that was not really in the input stream. - input_line_number--; - } } // We have seen a backslash and need to find out if it should be @@ -2195,7 +2248,7 @@ // FIXME -- we need to handle block comments here. bool -octave_lexer::have_continuation (bool trailing_comments_ok) +octave_base_lexer::have_continuation (bool trailing_comments_ok) { std::ostringstream buf; @@ -2283,7 +2336,7 @@ // line character. bool -octave_lexer::have_ellipsis_continuation (bool trailing_comments_ok) +octave_base_lexer::have_ellipsis_continuation (bool trailing_comments_ok) { char c1 = text_yyinput (); if (c1 == '.') @@ -2304,7 +2357,7 @@ } int -octave_lexer::handle_string (char delim) +octave_base_lexer::handle_string (char delim) { std::ostringstream buf; @@ -2396,7 +2449,7 @@ } int -octave_lexer::handle_close_bracket (int bracket_type) +octave_base_lexer::handle_close_bracket (int bracket_type) { int retval = bracket_type; @@ -2418,7 +2471,7 @@ } bool -octave_lexer::looks_like_command_arg (void) +octave_base_lexer::looks_like_command_arg (void) { bool space_before = space_follows_previous_token (); bool space_after = looking_at_space (); @@ -2428,7 +2481,7 @@ } int -octave_lexer::handle_superclass_identifier (void) +octave_base_lexer::handle_superclass_identifier (void) { std::string meth = flex_yytext (); @@ -2461,7 +2514,7 @@ } int -octave_lexer::handle_meta_identifier (void) +octave_base_lexer::handle_meta_identifier (void) { std::string cls = std::string(flex_yytext ()).substr (1); @@ -2493,7 +2546,7 @@ // should be ignored. int -octave_lexer::handle_identifier (void) +octave_base_lexer::handle_identifier (void) { char *yytxt = flex_yytext (); @@ -2570,11 +2623,14 @@ if (tok == "end") tok = "__end__"; - token *tok_val = new token (NAME, &(symbol_table::insert (tok)), + symbol_table::scope_id sid = symtab_context.curr_scope (); + + token *tok_val = new token (NAME, &(symbol_table::insert (tok, sid)), input_line_number, current_input_column); if (at_beginning_of_statement - && (! (tok == "e" + && (! (is_variable (tok) + || tok == "e" || tok == "I" || tok == "i" || tok == "J" || tok == "j" || tok == "Inf" || tok == "inf" @@ -2594,7 +2650,7 @@ } void -octave_lexer::maybe_warn_separator_insert (char sep) +octave_base_lexer::maybe_warn_separator_insert (char sep) { std::string nm = fcn_file_full_name; @@ -2609,7 +2665,7 @@ } void -octave_lexer::gripe_single_quote_string (void) +octave_base_lexer::gripe_single_quote_string (void) { std::string nm = fcn_file_full_name; @@ -2624,7 +2680,7 @@ } void -octave_lexer::gripe_matlab_incompatible (const std::string& msg) +octave_base_lexer::gripe_matlab_incompatible (const std::string& msg) { std::string nm = fcn_file_full_name; @@ -2639,20 +2695,20 @@ } void -octave_lexer::maybe_gripe_matlab_incompatible_comment (char c) +octave_base_lexer::maybe_gripe_matlab_incompatible_comment (char c) { if (c == '#') gripe_matlab_incompatible ("# used as comment character"); } void -octave_lexer::gripe_matlab_incompatible_continuation (void) +octave_base_lexer::gripe_matlab_incompatible_continuation (void) { gripe_matlab_incompatible ("\\ used as line continuation marker"); } void -octave_lexer::gripe_matlab_incompatible_operator (const std::string& op) +octave_base_lexer::gripe_matlab_incompatible_operator (const std::string& op) { std::string t = op; int n = t.length (); @@ -2662,7 +2718,7 @@ } void -octave_lexer::push_token (token *tok) +octave_base_lexer::push_token (token *tok) { YYSTYPE *lval = yyget_lval (scanner); lval->tok_val = tok; @@ -2670,14 +2726,14 @@ } token * -octave_lexer::current_token (void) +octave_base_lexer::current_token (void) { YYSTYPE *lval = yyget_lval (scanner); return lval->tok_val; } void -octave_lexer::display_token (int tok) +octave_base_lexer::display_token (int tok) { switch (tok) { @@ -2813,7 +2869,7 @@ } void -octave_lexer::fatal_error (const char *msg) +octave_base_lexer::fatal_error (const char *msg) { error (msg); @@ -2823,7 +2879,7 @@ } void -octave_lexer::lexer_debug (const char *pattern) +octave_base_lexer::lexer_debug (const char *pattern) { if (lexer_debug_flag) { @@ -2837,7 +2893,7 @@ } void -octave_lexer::push_start_state (int state) +octave_base_lexer::push_start_state (int state) { OCTAVE_YYG; @@ -2847,7 +2903,7 @@ } void -octave_lexer::pop_start_state (void) +octave_base_lexer::pop_start_state (void) { OCTAVE_YYG; @@ -2857,7 +2913,7 @@ } void -octave_lexer::clear_start_state (void) +octave_base_lexer::clear_start_state (void) { while (! start_state_stack.empty ()) start_state_stack.pop (); @@ -2866,7 +2922,7 @@ } void -octave_lexer::display_start_state (void) const +octave_base_lexer::display_start_state (void) const { std::cerr << "S: "; @@ -2903,7 +2959,7 @@ } int -octave_lexer::handle_op (const char *pattern, int tok, bool bos) +octave_base_lexer::handle_op (const char *pattern, int tok, bool bos) { lexer_debug (pattern); @@ -2911,7 +2967,8 @@ } int -octave_lexer::handle_incompatible_op (const char *pattern, int tok, bool bos) +octave_base_lexer::handle_incompatible_op (const char *pattern, int tok, + bool bos) { lexer_debug (pattern); @@ -2919,7 +2976,7 @@ } bool -octave_lexer::maybe_unput_comma_before_unary_op (int tok) +octave_base_lexer::maybe_unput_comma_before_unary_op (int tok) { int prev_tok = previous_token_value (); @@ -2942,21 +2999,21 @@ } int -octave_lexer::handle_unary_op (int tok, bool bos) +octave_base_lexer::handle_unary_op (int tok, bool bos) { return maybe_unput_comma_before_unary_op (tok) ? -1 : handle_op_internal (tok, bos, true); } int -octave_lexer::handle_incompatible_unary_op (int tok, bool bos) +octave_base_lexer::handle_incompatible_unary_op (int tok, bool bos) { return maybe_unput_comma_before_unary_op (tok) ? -1 : handle_op_internal (tok, bos, false); } int -octave_lexer::handle_op_internal (int tok, bool bos, bool compat) +octave_base_lexer::handle_op_internal (int tok, bool bos, bool compat) { if (! compat) gripe_matlab_incompatible_operator (flex_yytext ()); @@ -2971,7 +3028,7 @@ } int -octave_lexer::handle_token (const std::string& name, int tok) +octave_base_lexer::handle_token (const std::string& name, int tok) { token *tok_val = new token (tok, name, input_line_number, current_input_column); @@ -2980,7 +3037,7 @@ } int -octave_lexer::handle_token (int tok, token *tok_val) +octave_base_lexer::handle_token (int tok, token *tok_val) { if (! tok_val) tok_val = new token (tok, input_line_number, current_input_column); @@ -2993,7 +3050,7 @@ } int -octave_lexer::count_token (int tok) +octave_base_lexer::count_token (int tok) { token *tok_val = new token (tok, input_line_number, current_input_column); @@ -3003,7 +3060,7 @@ } int -octave_lexer::count_token_internal (int tok) +octave_base_lexer::count_token_internal (int tok) { if (tok != '\n') { @@ -3015,7 +3072,7 @@ } int -octave_lexer::show_token (int tok) +octave_base_lexer::show_token (int tok) { if (Vdisplay_tokens) display_token (tok); @@ -3029,3 +3086,49 @@ return tok; } + +int +octave_lexer::fill_flex_buffer (char *buf, unsigned max_size) +{ + int status = 0; + + if (input_buf.empty ()) + { + bool eof = false; + current_input_line = input_reader.get_input (eof); + input_buf.fill (current_input_line, eof); + } + + if (! input_buf.empty ()) + status = input_buf.copy_chunk (buf, max_size); + else + { + status = YY_NULL; + + if (! input_buf.at_eof ()) + fatal_error ("octave_base_lexer::fill_flex_buffer failed"); + } + + return status; +} + +int +octave_push_lexer::fill_flex_buffer (char *buf, unsigned max_size) +{ + int status = 0; + + if (input_buf.empty () && ! input_buf.at_eof ()) + input_buf.fill (std::string (1, static_cast<char> (1)), false); + + if (! input_buf.empty ()) + status = input_buf.copy_chunk (buf, max_size); + else + { + status = YY_NULL; + + if (! input_buf.at_eof ()) + fatal_error ("octave_base_lexer::fill_flex_buffer failed"); + } + + return status; +}
--- a/libinterp/parse-tree/module.mk +++ b/libinterp/parse-tree/module.mk @@ -4,20 +4,12 @@ PARSER_INC = \ parse-tree/lex.h \ - parse-tree/parse.h \ - parse-tree/parse-private.h + parse-tree/parse.h PARSER_SRC = \ parse-tree/lex.ll \ parse-tree/oct-parse.yy -## FIXME: Automake does not support per-object rules. -## These rules could be emulated by creating a new convenience -## library and using per-library rules. Or we can just live -## with the extra warnings about old-sytle-casts. (09/18/2012) -#lex.lo lex.o oct-parse.lo oct-parse.o: \ -# AM_CXXFLAGS := $(filter-out -Wold-style-cast, $(AM_CXXFLAGS)) - PARSE_TREE_INC = \ parse-tree/pt-all.h \ parse-tree/pt-arg-list.h \ @@ -50,8 +42,7 @@ parse-tree/pt-unop.h \ parse-tree/pt-walk.h \ parse-tree/pt.h \ - parse-tree/token.h \ - $(PARSER_INC) + parse-tree/token.h PARSE_TREE_SRC = \ parse-tree/pt-arg-list.cc \ @@ -83,8 +74,7 @@ parse-tree/pt-stmt.cc \ parse-tree/pt-unop.cc \ parse-tree/pt.cc \ - parse-tree/token.cc \ - $(PARSER_SRC) + parse-tree/token.cc ## Special rules for sources which must be built before rest of compilation. @@ -110,7 +100,14 @@ $(SED) "s/%PUSH_PULL_DECL%/$$decl/" $< > $@-t mv $@-t $@ -noinst_LTLIBRARIES += parse-tree/libparse-tree.la +noinst_LTLIBRARIES += \ + parse-tree/libparse-tree.la \ + parse-tree/libparser.la parse_tree_libparse_tree_la_SOURCES = $(PARSE_TREE_SRC) parse_tree_libparse_tree_la_CPPFLAGS = $(liboctinterp_la_CPPFLAGS) + +parse_tree_libparser_la_SOURCES = $(PARSER_SRC) +parse_tree_libparser_la_CPPFLAGS = $(liboctinterp_la_CPPFLAGS) +parse_tree_libparser_la_CXXFLAGS = \ + $(filter-out -Wold-style-cast, $(AM_CXXFLAGS))
--- a/libinterp/parse-tree/oct-parse.in.yy +++ b/libinterp/parse-tree/oct-parse.in.yy @@ -69,7 +69,6 @@ #include "toplev.h" #include "pager.h" #include "parse.h" -#include "parse-private.h" #include "pt-all.h" #include "pt-eval.h" #include "pt-funcall.h" @@ -86,7 +85,7 @@ // Global access to currently active lexer. // FIXME -- to be removed after more parser+lexer refactoring. -octave_lexer *LEXER = 0; +octave_base_lexer *LEXER = 0; #if defined (GNULIB_NAMESPACE) // Calls to the following functions appear in the generated output from @@ -100,9 +99,6 @@ // TRUE means we printed messages about reading startup files. bool reading_startup_message_printed = false; -// Keep track of symbol table information when parsing functions. -symtab_context parser_symtab_context; - // List of autoloads (function -> file mapping). static std::map<std::string, std::string> autoload_map; @@ -125,9 +121,7 @@ do \ { \ yyerrok; \ - if (! parser_symtab_context.empty ()) \ - parser_symtab_context.pop (); \ - if ((interactive || forced_interactive) \ + if ((interactive || forced_interactive) \ && ! lexer.input_from_eval_string ()) \ YYACCEPT; \ else \ @@ -405,7 +399,11 @@ // WHILE, etc. word_list_cmd : identifier word_list - { $$ = parser.make_index_expression ($1, $2, '('); } + { + $$ = parser.make_index_expression ($1, $2, '('); + if (! $$) + ABORT_PARSE; + } ; word_list : string @@ -603,13 +601,29 @@ | oper_expr MINUS_MINUS { $$ = parser.make_postfix_op (MINUS_MINUS, $1, $2); } | oper_expr '(' ')' - { $$ = parser.make_index_expression ($1, 0, '('); } + { + $$ = parser.make_index_expression ($1, 0, '('); + if (! $$) + ABORT_PARSE; + } | oper_expr '(' arg_list ')' - { $$ = parser.make_index_expression ($1, $3, '('); } + { + $$ = parser.make_index_expression ($1, $3, '('); + if (! $$) + ABORT_PARSE; + } | oper_expr '{' '}' - { $$ = parser.make_index_expression ($1, 0, '{'); } + { + $$ = parser.make_index_expression ($1, 0, '{'); + if (! $$) + ABORT_PARSE; + } | oper_expr '{' arg_list '}' - { $$ = parser.make_index_expression ($1, $3, '{'); } + { + $$ = parser.make_index_expression ($1, $3, '{'); + if (! $$) + ABORT_PARSE; + } | oper_expr HERMITIAN { $$ = parser.make_postfix_op (HERMITIAN, $1, $2); } | oper_expr TRANSPOSE @@ -1018,16 +1032,16 @@ if (parser.max_fcn_depth < parser.curr_fcn_depth) parser.max_fcn_depth = parser.curr_fcn_depth; - parser_symtab_context.push (); - - symbol_table::set_scope (symbol_table::alloc_scope ()); - - parser.function_scopes.push_back (symbol_table::current_scope ()); + lexer.symtab_context.push (symbol_table::alloc_scope ()); + + parser.function_scopes.push_back + (lexer.symtab_context.curr_scope ()); if (! lexer.reading_script_file && parser.curr_fcn_depth == 1 && ! parser.parsing_subfunctions) - parser.primary_fcn_scope = symbol_table::current_scope (); + parser.primary_fcn_scope + = lexer.symtab_context.curr_scope (); if (lexer.reading_script_file && parser.curr_fcn_depth > 1) @@ -1045,8 +1059,7 @@ if (lexer.looking_at_function_handle) { - parser_symtab_context.push (); - symbol_table::set_scope (symbol_table::alloc_scope ()); + lexer.symtab_context.push (symbol_table::alloc_scope ()); lexer.looking_at_function_handle--; lexer.looking_at_anon_fcn_args = true; } @@ -1061,7 +1074,12 @@ ; param_list : param_list_beg param_list1 param_list_end - { $$ = $2; } + { + if ($2) + lexer.mark_as_variables ($2->variable_names ()); + + $$ = $2; + } | param_list_beg error { parser.bison_error ("invalid parameter list"); @@ -1076,7 +1094,10 @@ { $1->mark_as_formal_parameters (); if ($1->validate (tree_parameter_list::in)) - $$ = $1; + { + lexer.mark_as_variables ($1->variable_names ()); + $$ = $1; + } else ABORT_PARSE; } @@ -1541,10 +1562,6 @@ octave_base_parser::~octave_base_parser (void) { -#if defined (OCTAVE_USE_PUSH_PARSER) - yypstate_delete (static_cast<yypstate *> (parser_state)); -#endif - delete stmt_list; delete &lexer; @@ -1552,10 +1569,6 @@ void octave_base_parser::init (void) { -#if defined (OCTAVE_USE_PUSH_PARSER) - parser_state = yypstate_new (); -#endif - LEXER = &lexer; } @@ -1971,12 +1984,12 @@ tree_parameter_list *ret_list = 0; - symbol_table::scope_id fcn_scope = symbol_table::current_scope (); - - if (parser_symtab_context.empty ()) + symbol_table::scope_id fcn_scope = lexer.symtab_context.curr_scope (); + + if (lexer.symtab_context.empty ()) panic_impossible (); - parser_symtab_context.pop (); + lexer.symtab_context.pop (); stmt->set_print_flag (false); @@ -2658,7 +2671,7 @@ body->append (end_fcn_stmt); octave_user_function *fcn - = new octave_user_function (symbol_table::current_scope (), + = new octave_user_function (lexer.symtab_context.curr_scope (), param_list, 0, body); if (fcn) @@ -2849,10 +2862,10 @@ void octave_base_parser::recover_from_parsing_function (void) { - if (parser_symtab_context.empty ()) + if (lexer.symtab_context.empty ()) panic_impossible (); - parser_symtab_context.pop (); + lexer.symtab_context.pop (); if (lexer.reading_fcn_file && curr_fcn_depth == 1 && ! parsing_subfunctions) @@ -3229,7 +3242,10 @@ tmp = new tree_argument_list (e); if (tmp && tmp->is_valid_lvalue_list ()) - retval = tmp; + { + lexer.mark_as_variables (tmp->variable_names ()); + retval = tmp; + } else { bison_error ("invalid left hand side of assignment"); @@ -3427,6 +3443,53 @@ return octave_parse (*this); } +octave_push_parser::~octave_push_parser (void) +{ + yypstate_delete (static_cast<yypstate *> (parser_state)); +} + +void +octave_push_parser::init (void) +{ + parser_state = yypstate_new (); + + octave_base_parser::init (); +} + +// Parse input from INPUT. Pass TRUE for EOF if the end of INPUT should +// finish the parse. + +int +octave_push_parser::run (const std::string& input, bool eof) +{ + int status = -1; + + dynamic_cast<octave_push_lexer&> (lexer).append_input (input, eof); + + do + { + YYSTYPE lval; + + int token = octave_lex (&lval, scanner); + + if (token < 0) + { + if (! eof && lexer.at_end_of_buffer ()) + { + status = -1; + break; + } + } + + yypstate *pstate = static_cast<yypstate *> (parser_state); + + status = octave_push_parse (pstate, token, &lval, *this); + } + while (status == YYPUSH_MORE); + + return status; +} + static void safe_fclose (FILE *f) { @@ -4441,7 +4504,7 @@ if (! error_state) { if (valid_identifier (nm)) - symbol_table::varref (nm) = args(2); + symbol_table::assign (nm, args(2)); else error ("assignin: invalid variable name in argument VARNAME"); }
deleted file mode 100644 --- a/libinterp/parse-tree/parse-private.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - -Copyright (C) 2012 John W. Eaton - -This file is part of Octave. - -Octave 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 3 of the License, or (at your -option) any later version. - -Octave 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/>. - -*/ - -#if !defined (octave_parse_private_h) -#define octave_parse_private_h 1 - -#include <stack> - -#include "symtab.h" - -// Keep track of symbol table information when parsing functions. -class symtab_context -{ -private: - - class frame - { - public: - frame (symbol_table::scope_id s, symbol_table::scope_id c) - : m_scope (s), m_context (c) { } - - frame (const frame& f) : m_scope (f.m_scope), m_context (f.m_context) { } - - frame& operator = (const frame& f) - { - if (&f != this) - { - m_scope = f.m_scope; - m_context = f.m_context; - } - - return *this; - } - - ~frame (void) { } - - symbol_table::scope_id scope (void) const { return m_scope; } - symbol_table::scope_id context (void) const { return m_context; } - - private: - - symbol_table::scope_id m_scope; - symbol_table::scope_id m_context; - }; - - std::stack<frame> frame_stack; - -public: - symtab_context (void) : frame_stack () { } - - void clear (void) - { - while (! frame_stack.empty ()) - frame_stack.pop (); - } - - bool empty (void) const { return frame_stack.empty (); } - - void pop (void) - { - frame tmp = frame_stack.top (); - - symbol_table::set_scope_and_context (tmp.scope (), tmp.context ()); - - frame_stack.pop (); - } - - void push (void) - { - frame_stack.push (frame (symbol_table::current_scope (), - symbol_table::current_context ())); - } -}; - -extern symtab_context parser_symtab_context; - -#endif
--- a/libinterp/parse-tree/parse.h +++ b/libinterp/parse-tree/parse.h @@ -136,26 +136,26 @@ // Global access to currently active lexer. // FIXME -- to be removed after more parser+lexer refactoring. -extern octave_lexer *LEXER; +extern octave_base_lexer *LEXER; class octave_base_parser { public: - octave_base_parser (octave_lexer& lxr) + octave_base_parser (octave_base_lexer& lxr) : endfunction_found (false), autoloading (false), fcn_file_from_relative_lookup (false), parsing_subfunctions (false), max_fcn_depth (0), curr_fcn_depth (0), primary_fcn_scope (-1), curr_class_name (), function_scopes (), primary_fcn_ptr (0), classdef_object (0), stmt_list (0), - lexer (lxr), parser_state (0) + lexer (lxr) { init (); } - virtual ~octave_base_parser (void); + ~octave_base_parser (void); void init (void); @@ -438,11 +438,7 @@ tree_statement_list *stmt_list; // State of the lexer. - octave_lexer& lexer; - - // Internal state of the parser. Only used if USE_PUSH_PARSER is - // defined. - void *parser_state; + octave_base_lexer& lexer; private: @@ -470,6 +466,10 @@ : octave_base_parser (*(new octave_lexer (eval_string))) { } + octave_parser (octave_lexer& lxr) + : octave_base_parser (lxr) + { } + ~octave_parser (void) { } int run (void); @@ -483,4 +483,33 @@ octave_parser& operator = (const octave_parser&); }; +class +octave_push_parser : public octave_base_parser +{ +public: + + octave_push_parser (void) + : octave_base_parser (*(new octave_push_lexer ())), parser_state (0) + { + init (); + } + + ~octave_push_parser (void); + + void init (void); + + int run (const std::string& input, bool eof); + +private: + + // Internal state of the Bison parser. + void *parser_state; + + // No copying! + + octave_push_parser (const octave_push_parser&); + + octave_push_parser& operator = (const octave_push_parser&); +}; + #endif
--- a/libinterp/parse-tree/pt-arg-list.cc +++ b/libinterp/parse-tree/pt-arg-list.cc @@ -283,6 +283,26 @@ return retval; } +std::list<std::string> +tree_argument_list::variable_names (void) const +{ + std::list<std::string> retval; + + for (const_iterator p = begin (); p != end (); p++) + { + tree_expression *elt = *p; + + if (elt->is_identifier ()) + { + tree_identifier *id = dynamic_cast<tree_identifier *> (elt); + + retval.push_back (id->name ()); + } + } + + return retval; +} + tree_argument_list * tree_argument_list::dup (symbol_table::scope_id scope, symbol_table::context_id context) const
--- a/libinterp/parse-tree/pt-arg-list.h +++ b/libinterp/parse-tree/pt-arg-list.h @@ -85,6 +85,8 @@ string_vector get_arg_names (void) const; + std::list<std::string> variable_names (void) const; + tree_argument_list *dup (symbol_table::scope_id scope, symbol_table::context_id context) const;
--- a/libinterp/parse-tree/pt-array-list.cc +++ b/libinterp/parse-tree/pt-array-list.cc @@ -93,8 +93,8 @@ } tree_expression * -tree_array_list::dup (symbol_table::scope_id scope, - symbol_table::context_id context) const +tree_array_list::dup (symbol_table::scope_id, + symbol_table::context_id) const { panic_impossible (); return 0;
--- a/libinterp/parse-tree/pt-bp.cc +++ b/libinterp/parse-tree/pt-bp.cc @@ -214,16 +214,10 @@ void tree_breakpoint::visit_if_command (tree_if_command& cmd) { - if (cmd.line () >= line) - take_action (cmd); + tree_if_command_list *lst = cmd.cmd_list (); - if (! found) - { - tree_if_command_list *lst = cmd.cmd_list (); - - if (lst) - lst->accept (*this); - } + if (lst) + lst->accept (*this); } void
--- a/libinterp/parse-tree/pt-cbinop.cc +++ b/libinterp/parse-tree/pt-cbinop.cc @@ -190,34 +190,3 @@ return ret; } - -octave_value -tree_compound_binary_expression::rvalue1 (int) -{ - octave_value retval; - - if (error_state) - return retval; - - if (op_lhs) - { - octave_value a = op_lhs->rvalue1 (); - - if (! error_state && a.is_defined () && op_rhs) - { - octave_value b = op_rhs->rvalue1 (); - - if (! error_state && b.is_defined ()) - { - retval = ::do_binary_op (etype, a, b); - - if (error_state) - retval = octave_value (); - } - } - } - - return retval; -} - -
--- a/libinterp/parse-tree/pt-cbinop.h +++ b/libinterp/parse-tree/pt-cbinop.h @@ -50,8 +50,6 @@ : tree_binary_expression (a, b, l, c, t), op_lhs (ca), op_rhs (cb), etype (ct) { } - octave_value rvalue1 (int nargout = 1); - octave_value::compound_binary_op cop_type (void) const { return etype; } private:
--- a/libinterp/parse-tree/pt-eval.cc +++ b/libinterp/parse-tree/pt-eval.cc @@ -538,7 +538,7 @@ // Make sure that any variable with the same name as the new // function is cleared. - symbol_table::varref (nm) = octave_value (); + symbol_table::assign (nm); } } @@ -557,9 +557,6 @@ void tree_evaluator::visit_if_command (tree_if_command& cmd) { - if (debug_mode) - do_breakpoint (cmd.is_breakpoint ()); - tree_if_command_list *lst = cmd.cmd_list (); if (lst) @@ -575,6 +572,9 @@ tree_expression *expr = tic->condition (); + if (statement_context == function || statement_context == script) + octave_call_stack::set_location (tic->line (), tic->column ()); + if (debug_mode && ! tic->is_else_clause ()) do_breakpoint (tic->is_breakpoint ()); @@ -709,7 +709,7 @@ // the state of the program we are debugging. if (! Vdebugging) - octave_call_stack::set_statement (&stmt); + octave_call_stack::set_location (stmt.line (), stmt.column ()); // FIXME -- we need to distinguish functions from scripts to // get this right. @@ -871,9 +871,6 @@ { tree_switch_case *t = *p; - if (debug_mode && ! t->is_default_case ()) - do_breakpoint (t->is_breakpoint ()); - if (t->is_default_case () || t->label_matches (val)) { if (error_state) @@ -952,10 +949,12 @@ frame.protect_var (error_state); error_state = 0; - // We want to preserve the last statement indicator for possible + // We want to preserve the last location info for possible // backtracking. - frame.add_fcn (octave_call_stack::set_statement, - octave_call_stack::current_statement ()); + frame.add_fcn (octave_call_stack::set_line, + octave_call_stack::current_line ()); + frame.add_fcn (octave_call_stack::set_column, + octave_call_stack::current_column ()); // Similarly, if we have seen a return or break statement, allow all // the cleanup code to run before returning or handling the break. @@ -1186,6 +1185,17 @@ } } + else if (dbstep_flag == 1 + && octave_call_stack::current_frame () < current_frame) + { + // We stepped out from the end of a function. + + current_frame = octave_call_stack::current_frame (); + + break_on_this_statement = true; + + dbstep_flag = 0; + } } else if (dbstep_flag == -1) { @@ -1199,9 +1209,14 @@ } else if (dbstep_flag == -2) { - // We get here if we are doing a "dbstep out". + // We get here if we are doing a "dbstep out". Check for end of + // function and whether the current frame is the same as the + // cached value because we want to step out from the frame where + // "dbstep out" was evaluated, not from any functions called from + // that frame. - if (is_end_of_fcn_or_script) + if (is_end_of_fcn_or_script + && octave_call_stack::current_frame () == current_frame) dbstep_flag = -1; }
--- a/libinterp/parse-tree/pt-id.cc +++ b/libinterp/parse-tree/pt-id.cc @@ -132,7 +132,7 @@ if (sym->is_added_static ()) static_workspace_error (); - return octave_lvalue (&(sym->varref ())); + return octave_lvalue (sym); } tree_identifier *
--- a/libinterp/parse-tree/pt-id.h +++ b/libinterp/parse-tree/pt-id.h @@ -161,7 +161,7 @@ octave_lvalue lvalue (void) { - return octave_lvalue (0); // black hole lvalue + return octave_lvalue (); // black hole lvalue } };
--- a/libinterp/parse-tree/pt-idx.cc +++ b/libinterp/parse-tree/pt-idx.cc @@ -443,12 +443,7 @@ if (! error_state) { - const octave_value *tro = retval.object (); - - octave_value tmp; - - if (tro) - tmp = *tro; + octave_value tmp = retval.value (); octave_idx_type tmpi = 0; std::list<octave_value_list> tmpidx;
--- a/libinterp/parse-tree/pt-misc.cc +++ b/libinterp/parse-tree/pt-misc.cc @@ -228,6 +228,21 @@ } } +std::list<std::string> +tree_parameter_list::variable_names (void) const +{ + std::list<std::string> retval; + + for (const_iterator p = begin (); p != end (); p++) + { + tree_decl_elt *elt = *p; + + retval.push_back (elt->name ()); + } + + return retval; +} + octave_value_list tree_parameter_list::convert_to_const_vector (int nargout, const Cell& varargout)
--- a/libinterp/parse-tree/pt-misc.h +++ b/libinterp/parse-tree/pt-misc.h @@ -78,6 +78,8 @@ bool is_defined (void); + std::list<std::string> variable_names (void) const; + octave_value_list convert_to_const_vector (int nargout, const Cell& varargout); tree_parameter_list *dup (symbol_table::scope_id scope,
--- a/libinterp/parse-tree/pt-stmt.cc +++ b/libinterp/parse-tree/pt-stmt.cc @@ -32,6 +32,7 @@ #include "error.h" #include "gripes.h" #include "ov.h" +#include "octave-link.h" #include "oct-lvalue.h" #include "input.h" #include "pager.h" @@ -191,6 +192,55 @@ return tbp.get_list (); } +bp_table::intmap +tree_statement_list::add_breakpoint (const std::string& file, + const bp_table::intmap& line) +{ + bp_table::intmap retval; + + octave_idx_type len = line.size (); + + for (int i = 0; i < len; i++) + { + bp_table::const_intmap_iterator p = line.find (i); + + if (p != line.end ()) + { + int lineno = p->second; + + retval[i] = set_breakpoint (lineno); + + if (retval[i] != 0 && ! file.empty ()) + octave_link::update_breakpoint (true, file, retval[i]); + } + } + + return retval; +} + +bp_table::intmap +tree_statement_list::remove_all_breakpoints (const std::string& file) +{ + bp_table::intmap retval; + + octave_value_list bkpts = list_breakpoints (); + + for (int i = 0; i < bkpts.length (); i++) + { + int lineno = static_cast<int> (bkpts(i).int_value ()); + + delete_breakpoint (lineno); + + retval[i] = lineno; + + if (! file.empty ()) + octave_link::update_breakpoint (false, file, lineno); + } + + return retval; +} + + tree_statement_list * tree_statement_list::dup (symbol_table::scope_id scope, symbol_table::context_id context) const
--- a/libinterp/parse-tree/pt-stmt.h +++ b/libinterp/parse-tree/pt-stmt.h @@ -34,6 +34,7 @@ #include "base-list.h" #include "comment-list.h" +#include "debug.h" #include "symtab.h" #include "pt.h" @@ -160,6 +161,11 @@ octave_value_list list_breakpoints (void); + bp_table::intmap add_breakpoint (const std::string& file, + const bp_table::intmap& line); + + bp_table::intmap remove_all_breakpoints (const std::string& file); + tree_statement_list *dup (symbol_table::scope_id scope, symbol_table::context_id context) const;
--- a/libinterp/parse-tree/token.cc +++ b/libinterp/parse-tree/token.cc @@ -150,6 +150,13 @@ return *str; } +std::string +token::symbol_name (void) const +{ + assert (type_tag == sym_rec_token); + return sr->name (); +} + double token::number (void) const {
--- a/libinterp/parse-tree/token.h +++ b/libinterp/parse-tree/token.h @@ -93,7 +93,13 @@ return type_tag == keyword_token || type_tag == ettype_token; } + bool is_symbol (void) const + { + return type_tag == sym_rec_token; + } + std::string text (void) const; + std::string symbol_name (void) const; double number (void) const; token_type ttype (void) const; end_tok_type ettype (void) const;
--- a/liboctave/array/CMatrix.cc +++ b/liboctave/array/CMatrix.cc @@ -1721,7 +1721,7 @@ rcon = octave_Inf; else { - int typ = mattype.type (); + volatile int typ = mattype.type (); if (typ == MatrixType::Unknown) typ = mattype.type (*this);
--- a/liboctave/array/CSparse.cc +++ b/liboctave/array/CSparse.cc @@ -5661,7 +5661,7 @@ A->packed = true; A->sorted = true; A->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T A->itype = CHOLMOD_LONG; #else A->itype = CHOLMOD_INT; @@ -5904,7 +5904,7 @@ A->packed = true; A->sorted = true; A->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T A->itype = CHOLMOD_LONG; #else A->itype = CHOLMOD_INT; @@ -5928,7 +5928,7 @@ B->packed = true; B->sorted = true; B->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T B->itype = CHOLMOD_LONG; #else B->itype = CHOLMOD_INT; @@ -6195,7 +6195,7 @@ A->packed = true; A->sorted = true; A->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T A->itype = CHOLMOD_LONG; #else A->itype = CHOLMOD_INT; @@ -6417,7 +6417,7 @@ A->packed = true; A->sorted = true; A->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T A->itype = CHOLMOD_LONG; #else A->itype = CHOLMOD_INT; @@ -6441,7 +6441,7 @@ B->packed = true; B->sorted = true; B->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T B->itype = CHOLMOD_LONG; #else B->itype = CHOLMOD_INT;
--- a/liboctave/array/CSparse.h +++ b/liboctave/array/CSparse.h @@ -513,7 +513,7 @@ SPARSE_FORWARD_DEFS (MSparse, SparseComplexMatrix, ComplexMatrix, Complex) -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define UMFPACK_ZNAME(name) umfpack_zl_ ## name #else #define UMFPACK_ZNAME(name) umfpack_zi_ ## name
--- a/liboctave/array/MArray-i.cc +++ b/liboctave/array/MArray-i.cc @@ -32,7 +32,9 @@ #include "MArray.cc" template class OCTAVE_API MArray<int>; -template class OCTAVE_API MArray<long>; +#ifdef USE_64_BIT_IDX_T +template class OCTAVE_API MArray<int64_t>; +#endif // Explicit instantiation, as this seems to be required by weird compilers // like MSVC. This should be harmless on other compilers. @@ -42,7 +44,9 @@ template long xmax<long> (long, long); INSTANTIATE_MARRAY_FRIENDS (int, OCTAVE_API) -INSTANTIATE_MARRAY_FRIENDS (long, OCTAVE_API) +#ifdef USE_64_BIT_IDX_T +INSTANTIATE_MARRAY_FRIENDS (int64_t, OCTAVE_API) +#endif template class OCTAVE_API MArray<octave_int8>; template class OCTAVE_API MArray<octave_int16>;
--- a/liboctave/array/chNDArray.cc +++ b/liboctave/array/chNDArray.cc @@ -92,6 +92,30 @@ return *this; } +charNDArray +charNDArray::max (int dim) const +{ + return do_mx_minmax_op<char> (*this, dim, mx_inline_max); +} + +charNDArray +charNDArray::max (Array<octave_idx_type>& idx_arg, int dim) const +{ + return do_mx_minmax_op<char> (*this, idx_arg, dim, mx_inline_max); +} + +charNDArray +charNDArray::min (int dim) const +{ + return do_mx_minmax_op<char> (*this, dim, mx_inline_min); +} + +charNDArray +charNDArray::min (Array<octave_idx_type>& idx_arg, int dim) const +{ + return do_mx_minmax_op<char> (*this, idx_arg, dim, mx_inline_min); +} + charNDArray& charNDArray::insert (const charNDArray& a, octave_idx_type r, octave_idx_type c) { @@ -139,6 +163,48 @@ return Array<char>::diag (m, n); } +charNDArray +min (char d, const charNDArray& m) +{ + return do_sm_binary_op<charNDArray::element_type, char, charNDArray::element_type> + (d, m, mx_inline_xmin); +} + +charNDArray +min (const charNDArray& m, char d) +{ + return do_ms_binary_op<charNDArray::element_type, charNDArray::element_type, char> + (m, d, mx_inline_xmin); +} + +charNDArray +min (const charNDArray& a, const charNDArray& b) +{ + return do_mm_binary_op<charNDArray::element_type, charNDArray::element_type, charNDArray::element_type> + (a, b, mx_inline_xmin, mx_inline_xmin, mx_inline_xmin, "min"); +} + +charNDArray +max (char d, const charNDArray& m) +{ + return do_sm_binary_op<charNDArray::element_type, char, charNDArray::element_type> + (d, m, mx_inline_xmax); +} + +charNDArray +max (const charNDArray& m, char d) +{ + return do_ms_binary_op<charNDArray::element_type, charNDArray::element_type, char> + (m, d, mx_inline_xmax); +} + +charNDArray +max (const charNDArray& a, const charNDArray& b) +{ + return do_mm_binary_op<charNDArray::element_type, charNDArray::element_type, charNDArray::element_type> + (a, b, mx_inline_xmax, mx_inline_xmax, mx_inline_xmax, "max"); +} + NDS_CMP_OPS (charNDArray, char) NDS_BOOL_OPS (charNDArray, char)
--- a/liboctave/array/chNDArray.h +++ b/liboctave/array/chNDArray.h @@ -73,6 +73,11 @@ charNDArray concat (const charNDArray& rb, const Array<octave_idx_type>& ra_idx); charNDArray concat (const NDArray& rb, const Array<octave_idx_type>& ra_idx); + charNDArray max (int dim = -1) const; + charNDArray max (Array<octave_idx_type>& index, int dim = -1) const; + charNDArray min (int dim = -1) const; + charNDArray min (Array<octave_idx_type>& index, int dim = -1) const; + charNDArray& insert (const charNDArray& a, octave_idx_type r, octave_idx_type c); charNDArray& insert (const charNDArray& a, const Array<octave_idx_type>& ra_idx); @@ -97,6 +102,13 @@ charNDArray diag (octave_idx_type m, octave_idx_type n) const; }; +extern OCTAVE_API charNDArray min (char d, const charNDArray& m); +extern OCTAVE_API charNDArray min (const charNDArray& m, char d); +extern OCTAVE_API charNDArray min (const charNDArray& a, const charNDArray& b); +extern OCTAVE_API charNDArray max (char d, const charNDArray& m); +extern OCTAVE_API charNDArray max (const charNDArray& m, char d); +extern OCTAVE_API charNDArray max (const charNDArray& a, const charNDArray& b); + NDS_CMP_OP_DECLS (charNDArray, char, OCTAVE_API) NDS_BOOL_OP_DECLS (charNDArray, char, OCTAVE_API)
--- a/liboctave/array/dMatrix.cc +++ b/liboctave/array/dMatrix.cc @@ -1389,7 +1389,7 @@ rcon = octave_Inf; else { - int typ = mattype.type (); + volatile int typ = mattype.type (); if (typ == MatrixType::Unknown) typ = mattype.type (*this);
--- a/liboctave/array/dSparse.cc +++ b/liboctave/array/dSparse.cc @@ -5859,7 +5859,7 @@ A->packed = true; A->sorted = true; A->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T A->itype = CHOLMOD_LONG; #else A->itype = CHOLMOD_INT; @@ -6075,7 +6075,7 @@ A->packed = true; A->sorted = true; A->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T A->itype = CHOLMOD_LONG; #else A->itype = CHOLMOD_INT; @@ -6099,7 +6099,7 @@ B->packed = true; B->sorted = true; B->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T B->itype = CHOLMOD_LONG; #else B->itype = CHOLMOD_INT; @@ -6337,7 +6337,7 @@ A->packed = true; A->sorted = true; A->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T A->itype = CHOLMOD_LONG; #else A->itype = CHOLMOD_INT; @@ -6571,7 +6571,7 @@ A->packed = true; A->sorted = true; A->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T A->itype = CHOLMOD_LONG; #else A->itype = CHOLMOD_INT; @@ -6595,7 +6595,7 @@ B->packed = true; B->sorted = true; B->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T B->itype = CHOLMOD_LONG; #else B->itype = CHOLMOD_INT;
--- a/liboctave/array/dSparse.h +++ b/liboctave/array/dSparse.h @@ -469,7 +469,7 @@ SPARSE_FORWARD_DEFS (MSparse, SparseMatrix, Matrix, double) -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define UMFPACK_DNAME(name) umfpack_dl_ ## name #else #define UMFPACK_DNAME(name) umfpack_di_ ## name
--- a/liboctave/array/fCMatrix.cc +++ b/liboctave/array/fCMatrix.cc @@ -1717,7 +1717,7 @@ rcon = octave_Inf; else { - int typ = mattype.type (); + volatile int typ = mattype.type (); if (typ == MatrixType::Unknown) typ = mattype.type (*this);
--- a/liboctave/array/fMatrix.cc +++ b/liboctave/array/fMatrix.cc @@ -1389,7 +1389,7 @@ rcon = octave_Inf; else { - int typ = mattype.type (); + volatile int typ = mattype.type (); if (typ == MatrixType::Unknown) typ = mattype.type (*this);
--- a/liboctave/cruft/misc/cquit.c +++ b/liboctave/cruft/misc/cquit.c @@ -43,176 +43,6 @@ memcpy (current_context, save_buf, sizeof (octave_jmp_buf)); } -#if defined (__WIN32__) && ! defined (_POSIX_VERSION) - -/* FIXME -- eventually remove the debugging */ -#if defined (DEBUG) - -#define PRINT_CURRENT_THREAD() printf ("%lx: ", GetCurrentThreadId ()) - -#define DEBUGs(s) \ - do \ - { \ - PRINT_CURRENT_THREAD (); \ - printf (s "\n"); \ - fflush (stdout); \ - } \ - while (0) - -#define DEBUGd(s, d) \ - do \ - { \ - PRINT_CURRENT_THREAD (); \ - printf (s "\n", d); \ - fflush (stdout); \ - } \ - while (0) - -#else -#define DEBUGs(s) -#define DEBUGd(s, d) -#endif - -CRITICAL_SECTION w32_thread_setjmp_mutex; -static CONTEXT w32_signal_context; -static int w32_signal_to_raise = 0; -static DWORD w32_main_thread_id; -static HANDLE w32_main_thread; -static HANDLE w32_restore_thread = NULL; - -int -w32_in_main_thread(void) -{ - return (GetCurrentThreadId () == w32_main_thread_id); -} - -static DWORD WINAPI -w32_reset_context (LPVOID v) -{ - PCONTEXT context = (PCONTEXT)v; - int ret; - - /* Mutex the setjmp/longjmp */ - EnterCriticalSection (&w32_thread_setjmp_mutex); - - DEBUGs ("enter w32_set_context"); - SuspendThread (w32_main_thread); - DEBUGs ("main suspended"); - if (! SetThreadContext (w32_main_thread, context)) - { - fprintf (stderr, "%lx: context failed: ctrl-c won't work\n", - GetCurrentThreadId ()); - fflush (stderr); - } - DEBUGs ("context captured (or not)"); - ret = ResumeThread (w32_main_thread); - DEBUGd ("main resumed with %d", ret); - - LeaveCriticalSection (&w32_thread_setjmp_mutex); - return 0; -} - -static void -w32_raise_in_main (void) -{ - DWORD threadid; - - DEBUGd ("w32_raise_in_main with signal %d", w32_signal_to_raise); - raise (w32_signal_to_raise); - DEBUGd ("w32_raise_in_main signal %d returned a value", - w32_signal_to_raise); - - DEBUGs ("attempting to restore main to pre-signal configuration"); - if (w32_restore_thread != NULL) /* Catch leaky threads */ - CloseHandle (w32_restore_thread); - w32_restore_thread = CreateThread (NULL, 10000, w32_reset_context, - &w32_signal_context, 0, &threadid); - if (w32_restore_thread == NULL) - { - fprintf (stderr, "w32_raise_in_main couldn't create thread\n"); - fflush (stderr); - } - else - { - DEBUGs ("waiting to restore raise context"); - WaitForSingleObject (w32_restore_thread, INFINITE); - fprintf (stderr, "w32_raise_in_main couldn't restore context\n"); - fflush (stderr); - } -} - -void -w32_raise_final (void) -{ - CloseHandle (w32_main_thread); - if (w32_restore_thread != NULL) /* Catch leaky threads */ - CloseHandle (w32_restore_thread); - w32_main_thread = w32_restore_thread = NULL; -} - -/* Raise the given signal in the main thread. w32_raise_init () - must have been called from the main thread already. */ -void -w32_raise (int sig) -{ - int ret; - - if (w32_in_main_thread ()) - { - /* Called from main thread -- a simple raise () should work. */ - DEBUGd ("raising signal %d within main", signal); - raise (sig); - DEBUGd ("returning from signal %d within main", signal); - } - else - { - /* Called from alternate thread -- call w32_raise_in_main in the - main thread with w32_signal_to_raise set to the signal */ - CONTEXT raise_context; - DEBUGd ("raising signal %d from separate thread", signal); - - /* Suspend main and remember the context. */ - SuspendThread (w32_main_thread); - /* X86 code */ - w32_signal_context.ContextFlags - = CONTEXT_FULL|CONTEXT_FLOATING_POINT|CONTEXT_DEBUG_REGISTERS; - GetThreadContext (w32_main_thread, &w32_signal_context); - - /* Change the context to w32_raise_in_main. The - context.Eip=&fn trick for setting the program counter is - courtesy of - - http://fit.c2.com/files/LispPlatform/lisp/clisp-2.28/src/win32aux.d - - Auxiliary functions for CLISP on Win32, Bruno Haible - 1997-1999. */ - - memcpy (&raise_context, &w32_signal_context, sizeof (CONTEXT)); - raise_context.Eip = (DWORD)&w32_raise_in_main; /* X86 code */ - w32_signal_to_raise = sig; - SetThreadContext (w32_main_thread, &raise_context); - - /* Resume main at w32_raise_in_main */ - ret = ResumeThread (w32_main_thread); - DEBUGd ("main resumed at w32_raise_in_main with suspend count %d", - ret); - } -} - -void -w32_sigint_init (void) -{ - /* Capture main context */ - w32_main_thread_id = GetCurrentThreadId (); - DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), - GetCurrentProcess (), &w32_main_thread, - 0, FALSE, DUPLICATE_SAME_ACCESS); - - InitializeCriticalSectionAndSpinCount (&w32_thread_setjmp_mutex, 0); -} - -#endif /* #if defined (__WIN32__) && ! defined (_POSIX_VERSION) */ - void octave_jump_to_enclosing_context (void) {
--- a/liboctave/numeric/SparseCmplxQR.h +++ b/liboctave/numeric/SparseCmplxQR.h @@ -31,7 +31,7 @@ #include "CSparse.h" #include "oct-sparse.h" -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define CXSPARSE_ZNAME(name) cs_cl ## name #else #define CXSPARSE_ZNAME(name) cs_ci ## name
--- a/liboctave/numeric/SparseQR.h +++ b/liboctave/numeric/SparseQR.h @@ -31,7 +31,7 @@ #include "CSparse.h" #include "oct-sparse.h" -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define CXSPARSE_DNAME(name) cs_dl ## name #else #define CXSPARSE_DNAME(name) cs_di ## name
--- a/liboctave/numeric/sparse-base-chol.cc +++ b/liboctave/numeric/sparse-base-chol.cc @@ -136,7 +136,7 @@ ac->packed = true; ac->sorted = true; ac->nz = 0; -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T ac->itype = CHOLMOD_LONG; #else ac->itype = CHOLMOD_INT;
--- a/liboctave/system/lo-sysdep.cc +++ b/liboctave/system/lo-sysdep.cc @@ -114,8 +114,8 @@ pipeMode = PIPE_NOWAIT; SetNamedPipeHandleState (parentRead, &pipeMode, 0, 0); } - fildes[1] = _open_osfhandle (reinterpret_cast<long> (parentRead), _O_RDONLY | _O_BINARY); - fildes[0] = _open_osfhandle (reinterpret_cast<long> (parentWrite), _O_WRONLY | _O_BINARY); + fildes[1] = _open_osfhandle (reinterpret_cast<intptr_t> (parentRead), _O_RDONLY | _O_BINARY); + fildes[0] = _open_osfhandle (reinterpret_cast<intptr_t> (parentWrite), _O_WRONLY | _O_BINARY); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = childRead; si.hStdOutput = childWrite;
--- a/liboctave/util/cmd-edit.cc +++ b/liboctave/util/cmd-edit.cc @@ -86,11 +86,13 @@ FILE *do_get_output_stream (void); + void do_redisplay (void); + int do_terminal_rows (void); int do_terminal_cols (void); - void do_clear_screen (void); + void do_clear_screen (bool skip_redisplay); void do_resize_terminal (void); @@ -143,6 +145,8 @@ void do_accept_line (void); + bool do_undo (void); + void do_clear_undo_list (void); void set_startup_hook (startup_hook_fcn f); @@ -163,6 +167,8 @@ bool do_filename_quoting_desired (bool); + void do_interrupt (bool); + static int operate_and_get_next (int, int); static int history_search_backward (int, int); @@ -290,6 +296,12 @@ return ::octave_rl_get_output_stream (); } +void +gnu_readline::do_redisplay (void) +{ + ::octave_rl_redisplay (); +} + // GNU readline handles SIGWINCH, so these values have a good chance // of being correct even if the window changes size (they may be // wrong if, for example, the luser changes the window size while the @@ -313,9 +325,9 @@ } void -gnu_readline::do_clear_screen (void) +gnu_readline::do_clear_screen (bool skip_redisplay) { - ::octave_rl_clear_screen (); + ::octave_rl_clear_screen (skip_redisplay); } void @@ -528,6 +540,12 @@ command_accept_line (1, '\n'); } +bool +gnu_readline::do_undo (void) +{ + return ::octave_rl_do_undo (); +} + void gnu_readline::do_clear_undo_list () { @@ -587,6 +605,12 @@ return ::octave_rl_filename_quoting_desired (arg); } +void +gnu_readline::do_interrupt (bool arg) +{ + ::octave_rl_done (arg); +} + int gnu_readline::operate_and_get_next (int /* count */, int /* c */) { @@ -953,6 +977,13 @@ ? instance->do_get_output_stream () : 0; } +void +command_editor::redisplay (void) +{ + if (instance_ok ()) + instance->do_redisplay (); +} + int command_editor::terminal_rows (void) { @@ -968,10 +999,10 @@ } void -command_editor::clear_screen (void) +command_editor::clear_screen (bool skip_redisplay) { if (instance_ok ()) - instance->do_clear_screen (); + instance->do_clear_screen (skip_redisplay); } void @@ -1169,6 +1200,12 @@ instance->do_accept_line (); } +bool +command_editor::undo (void) +{ + return instance_ok () ? instance->do_undo () : false; +} + void command_editor::clear_undo_list (void) { @@ -1270,6 +1307,26 @@ ? instance->do_filename_quoting_desired (arg) : false; } +bool +command_editor::interrupt (bool arg) +{ + bool retval; + + if (instance_ok ()) + { + // Return the current interrupt state. + retval = instance->interrupted; + + instance->do_interrupt (arg); + + instance->interrupted = arg; + } + else + retval = false; + + return retval; +} + // Return a string which will be printed as a prompt. The string may // contain special characters which are decoded as follows: //
--- a/liboctave/util/cmd-edit.h +++ b/liboctave/util/cmd-edit.h @@ -37,7 +37,7 @@ protected: command_editor (void) - : command_number (0) { } + : command_number (0), interrupted (false) { } public: @@ -71,11 +71,13 @@ static FILE *get_output_stream (void); + static void redisplay (void); + static int terminal_rows (void); static int terminal_cols (void); - static void clear_screen (void); + static void clear_screen (bool skip_redisplay = false); static void resize_terminal (void); @@ -127,6 +129,8 @@ static void accept_line (void); + static bool undo (void); + static void clear_undo_list (void); static void add_startup_hook (startup_hook_fcn f); @@ -147,6 +151,8 @@ static bool filename_quoting_desired (bool); + static bool interrupt (bool); + static int current_command_number (void); static void reset_current_command_number (int n); @@ -211,11 +217,13 @@ virtual FILE *do_get_output_stream (void) = 0; + virtual void do_redisplay (void) { } + virtual int do_terminal_rows (void) { return 24; } virtual int do_terminal_cols (void) { return 80; } - virtual void do_clear_screen (void) { } + virtual void do_clear_screen (bool) { } virtual void do_resize_terminal (void) { } @@ -269,6 +277,8 @@ virtual void do_accept_line (void) = 0; + virtual bool do_undo (void) { return false; } + virtual void do_clear_undo_list (void) { } virtual void set_startup_hook (startup_hook_fcn) { } @@ -287,6 +297,8 @@ virtual bool do_filename_quoting_desired (bool) { return false; } + virtual void do_interrupt (bool) { } + int read_octal (const std::string& s); void error (int); @@ -295,6 +307,8 @@ // The current command number. int command_number; + + bool interrupted; }; #endif
--- a/liboctave/util/kpse.cc +++ b/liboctave/util/kpse.cc @@ -364,7 +364,7 @@ if (KPSE_DEBUG_P (KPSE_DEBUG_FOPEN)) DEBUGF3 ("fopen (%s, %s) => 0x%lx\n", filename.c_str (), mode, - reinterpret_cast<unsigned long> (f)); + reinterpret_cast<intptr_t> (f)); return f; }
--- a/liboctave/util/oct-rl-edit.c +++ b/liboctave/util/oct-rl-edit.c @@ -91,17 +91,23 @@ } void -octave_rl_clear_screen (void) +octave_rl_clear_screen (int skip_redisplay) { int ignore1 = 0; int ignore2 = 0; - rl_voidfunc_t *saved_redisplay_function = rl_redisplay_function; - rl_redisplay_function = flush_stdout; + if (skip_redisplay) + { + rl_voidfunc_t *saved_redisplay_function = rl_redisplay_function; + + rl_redisplay_function = flush_stdout; - rl_clear_screen (ignore1, ignore2); + rl_clear_screen (ignore1, ignore2); - rl_redisplay_function = saved_redisplay_function; + rl_redisplay_function = saved_redisplay_function; + } + else + rl_clear_screen (ignore1, ignore2); } void @@ -135,6 +141,12 @@ return rl_line_buffer; } +int +octave_rl_do_undo (void) +{ + return rl_do_undo (); +} + void octave_rl_clear_undo_list (void) { @@ -218,6 +230,12 @@ return retval; } +void +octave_rl_done (int arg) +{ + rl_done = arg; +} + char * octave_rl_filename_completion_function (const char *text, int state) {
--- a/liboctave/util/oct-rl-edit.h +++ b/liboctave/util/oct-rl-edit.h @@ -46,7 +46,7 @@ { #endif - extern void octave_rl_redisplay (void); +extern void octave_rl_redisplay (void); extern int octave_rl_screen_height (void); @@ -56,7 +56,7 @@ extern void octave_rl_init (void); -extern void octave_rl_clear_screen (void); +extern void octave_rl_clear_screen (int skip_redisplay); extern void octave_rl_resize_terminal (void); @@ -68,6 +68,8 @@ extern const char *octave_rl_line_buffer (void); +extern int octave_rl_do_undo (void); + extern void octave_rl_clear_undo_list (void); extern void octave_rl_set_name (const char *); @@ -90,6 +92,8 @@ extern int octave_rl_filename_quoting_desired (int); +extern void octave_rl_done (int); + extern char *octave_rl_filename_completion_function (const char *, int); extern void octave_rl_set_basic_word_break_characters (const char *);
--- a/liboctave/util/oct-sparse.h +++ b/liboctave/util/oct-sparse.h @@ -87,7 +87,7 @@ || defined (HAVE_UFSPARSE_CHOLMOD_H) \ || defined (HAVE_CHOLMOD_CHOLMOD_H) \ || defined (HAVE_CHOLMOD_H)) -#ifdef IDX_TYPE_LONG +#ifdef USE_64_BIT_IDX_T #define CHOLMOD_NAME(name) cholmod_l_ ## name #else #define CHOLMOD_NAME(name) cholmod_ ## name
--- a/m4/acinclude.m4 +++ b/m4/acinclude.m4 @@ -861,13 +861,10 @@ LIBS="fintsize.$ac_objext $[]_AC_LANG_PREFIX[]LIBS" AC_LANG_PUSH(C) AC_RUN_IFELSE([AC_LANG_PROGRAM([[ - #include <assert.h> ]], [[ + #include <assert.h> + #include <stdint.h> ]], [[ #ifdef USE_64_BIT_IDX_T - #if IDX_TYPE_LONG - typedef long octave_idx_type; - #else - typedef int octave_idx_type; - #endif + typedef int64_t octave_idx_type; #else typedef int octave_idx_type; #endif @@ -1795,6 +1792,7 @@ AC_MSG_CHECKING([for UMFPACK separate complex matrix and rhs split]) AC_CACHE_VAL([octave_cv_umfpack_separate_split], [AC_RUN_IFELSE([AC_LANG_SOURCE([[ + #include <stdint.h> #include <stdlib.h> #include <math.h> #if defined (HAVE_SUITESPARSE_UMFPACK_H) @@ -1806,9 +1804,16 @@ #elif defined (HAVE_UMFPACK_H) # include <umfpack.h> #endif - int n = 5; - int Ap[] = {0, 2, 5, 9, 10, 12}; - int Ai[] = {0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4}; + #ifdef USE_64_BIT_IDX_T + typedef uint64_t idx_type; + #define UMFPACK_NAME(name) umfpack_zl_ ## name + #else + typedef int idx_type; + #define UMFPACK_NAME(name) umfpack_zi_ ## name + #endif + idx_type n = 5; + idx_type Ap[] = {0, 2, 5, 9, 10, 12}; + idx_type Ai[] = {0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4}; double Ax[] = {2., 0., 3., 0., 3., 0., -1., 0., 4., 0., 4., 0., -3., 0., 1., 0., 2., 0., 2., 0., 6., 0., 1., 0.}; double br[] = {8., 45., -3., 3., 19.}; @@ -1817,14 +1822,14 @@ { double *null = (double *) NULL ; double *x = (double *)malloc (2 * n * sizeof(double)); - int i ; + idx_type i ; void *Symbolic, *Numeric ; - (void) umfpack_zi_symbolic (n, n, Ap, Ai, Ax, null, &Symbolic, null, null) ; - (void) umfpack_zi_numeric (Ap, Ai, Ax, null, Symbolic, &Numeric, null, null) ; - umfpack_zi_free_symbolic (&Symbolic) ; - (void) umfpack_zi_solve (0, Ap, Ai, Ax, null, x, null, br, bi, + (void) UMFPACK_NAME (symbolic) (n, n, Ap, Ai, Ax, null, &Symbolic, null, null) ; + (void) UMFPACK_NAME (numeric) (Ap, Ai, Ax, null, Symbolic, &Numeric, null, null) ; + UMFPACK_NAME (free_symbolic) (&Symbolic) ; + (void) UMFPACK_NAME (solve) (0, Ap, Ai, Ax, null, x, null, br, bi, Numeric, null, null) ; - umfpack_zi_free_numeric (&Numeric) ; + UMFPACK_NAME (free_numeric) (&Numeric) ; for (i = 0; i < n; i++, x+=2) if (fabs (*x - i - 1.) > 1.e-13) return (1);
--- a/m4/ax_blas_f77_func.m4 +++ b/m4/ax_blas_f77_func.m4 @@ -150,9 +150,9 @@ real s,a(1),b(1),sdot a(1) = 1.0 b(1) = 1.0 -c Generate -2**33 + 1, if possible +c Generate -2**32 + 1, if possible n = 2 - n = -4 * (n ** 30) + n = -4 ** (n ** 30) n = n + 1 if (n >= 0) goto 1 c This means we're on 64-bit integers. Check whether the BLAS is, too.
new file mode 100644 --- /dev/null +++ b/oct-conf-post.in.h @@ -0,0 +1,168 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave 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 3 of the License, or (at your +option) any later version. + +Octave 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/>. + +*/ + +#if !defined (GNULIB_NAMESPACE) +#define GNULIB_NAMESPACE gnulib +#endif + +#if defined (__GNUC__) +#define GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__)) +#define HAVE_ATTR_DEPRECATED + +#define GCC_ATTR_NORETURN __attribute__ ((__noreturn__)) +#define HAVE_ATTR_NORETURN + +#define GCC_ATTR_UNUSED __attribute__ ((__unused__)) +#define HAVE_ATTR_UNUSED +#else +#define GCC_ATTR_DEPRECATED +#define GCC_ATTR_NORETURN +#define GCC_ATTR_UNUSED +#endif + +#define X_CAST(T, E) (T) (E) + +#if defined (CXX_BROKEN_REINTERPRET_CAST) +#define FCN_PTR_CAST(T, E) (T) (E) +#else +#define FCN_PTR_CAST(T, E) reinterpret_cast<T> (E) +#endif + +#if ! defined (HAVE_DEV_T) +typedef short dev_t; +#endif + +#if ! defined (HAVE_INO_T) +typedef unsigned long ino_t; +#endif + +#if defined (_MSC_VER) +#define __WIN32__ +#define WIN32 +/* missing parameters in macros */ +#pragma warning (disable: 4003) +/* missing implementations in template instantiation */ +#pragma warning (disable: 4996) +/* deprecated function names (FIXME?) */ +#pragma warning (disable: 4661) +#endif + +#if defined (__WIN32__) && ! defined (__CYGWIN__) +#define OCTAVE_HAVE_WINDOWS_FILESYSTEM 1 +#elif defined (__CYGWIN__) +#define OCTAVE_HAVE_WINDOWS_FILESYSTEM 1 +#define OCTAVE_HAVE_POSIX_FILESYSTEM 1 +#else +#define OCTAVE_HAVE_POSIX_FILESYSTEM 1 +#endif + +/* Define to 1 if we expect to have <windows.h>, Sleep, etc. */ +#if defined (__WIN32__) && ! defined (__CYGWIN__) +#define OCTAVE_USE_WINDOWS_API 1 +#endif + +#if defined (__APPLE__) && defined (__MACH__) +#define OCTAVE_USE_OS_X_API 1 +#endif + +/* sigsetjmp is a macro, not a function. */ +#if defined (sigsetjmp) && defined (HAVE_SIGLONGJMP) +#define OCTAVE_HAVE_SIG_JUMP +#endif + +#if defined (_UNICOS) +#define F77_USES_CRAY_CALLING_CONVENTION +#endif + +#if 0 +#define F77_USES_VISUAL_FORTRAN_CALLING_CONVENTION +#endif + +#ifdef USE_64_BIT_IDX_T +#define SIZEOF_OCTAVE_IDX_TYPE SIZEOF_INT64_T +#else +#define SIZEOF_OCTAVE_IDX_TYPE SIZEOF_INT +#endif + +/* To be able to use long doubles for 64-bit mixed arithmetics, we need + them at least 80 bits wide and we need roundl declared in math.h. + FIXME: Maybe substitute this by a more precise check in the future? */ +#if (SIZEOF_LONG_DOUBLE >= 10) && defined (HAVE_ROUNDL) +#define OCTAVE_INT_USE_LONG_DOUBLE +#endif + +#define OCTAVE_EMPTY_CPP_ARG + +/* oct-dlldefs.h */ + +#if defined (_MSC_VER) +#define OCTAVE_EXPORT __declspec(dllexport) +#define OCTAVE_IMPORT __declspec(dllimport) +#else +/* All other compilers, at least for now. */ +#define OCTAVE_EXPORT +#define OCTAVE_IMPORT +#endif + +/* API macro for libcruft */ +#ifdef CRUFT_DLL +#define CRUFT_API OCTAVE_EXPORT +#else +#define CRUFT_API OCTAVE_IMPORT +#endif + +/* API macro for liboctave */ +#ifdef OCTAVE_DLL +#define OCTAVE_API OCTAVE_EXPORT +#else +#define OCTAVE_API OCTAVE_IMPORT +#endif + +/* API macro for libinterp */ +#ifdef OCTINTERP_DLL +#define OCTINTERP_API OCTAVE_EXPORT +#else +#define OCTINTERP_API OCTAVE_IMPORT +#endif + +/* API macro for libinterp/graphics */ +#ifdef OCTGRAPHICS_DLL +#define OCTGRAPHICS_API OCTAVE_EXPORT +#else +#define OCTGRAPHICS_API OCTAVE_IMPORT +#endif + +/* API macro for libgui */ +#ifdef OCTGUI_DLL +#define OCTGUI_API OCTAVE_EXPORT +#else +#define OCTGUI_API OCTAVE_IMPORT +#endif + +/* oct-types.h */ + +#include <stdint.h> + +typedef OCTAVE_IDX_TYPE octave_idx_type; + +/* Tag indicating Octave config.h has been included */ +#define OCTAVE_CONFIG_INCLUDED 1
--- a/run-octave.in +++ b/run-octave.in @@ -79,7 +79,7 @@ fi OCTAVE_SITE_INITFILE="$top_srcdir/scripts/startup/main-rcfile" \ -OCTAVE_DEFAULT_QT_SETTINGS="$top_srcdir/libgui/default-qt-settings" \ +OCTAVE_DEFAULT_QT_SETTINGS="$builddir/libgui/default-qt-settings" \ OCTAVE_LOCALE_DIR="$top_srcdir/libgui/languages" \ OCTAVE_JAVA_DIR="$builddir/scripts/java" \ exec $builddir/libtool --mode=execute $driver \
--- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -74,6 +74,7 @@ include strings/module.mk include testfun/module.mk include time/module.mk +include ui/module.mk nobase_fcnfile_DATA = $(FCN_FILES) $(GEN_FCN_FILES) $(JAR_FILES) @@ -213,6 +214,10 @@ $(srcdir)/mk-pkg-add $(srcdir) $(time_FCN_FILES) -- $(time_GEN_FCN_FILES) > $@-t mv $@-t $@ +ui/PKG_ADD: $(ui_FCN_FILES) $(ui_GEN_FCN_FILES) ui/$(octave_dirstamp) mk-pkg-add + $(srcdir)/mk-pkg-add $(srcdir) $(ui_FCN_FILES) -- $(ui_GEN_FCN_FILES) > $@-t + mv $@-t $@ + $(@ftp_GEN_FCN_FILES): @ftp/$(octave_dirstamp) $(audio_GEN_FCN_FILES): audio/$(octave_dirstamp) $(deprecated_GEN_FCN_FILES): deprecated/$(octave_dirstamp) @@ -244,6 +249,7 @@ $(strings_GEN_FCN_FILES): strings/$(octave_dirstamp) $(testfun_GEN_FCN_FILES): testfun/$(octave_dirstamp) $(time_GEN_FCN_FILES): time/$(octave_dirstamp) +$(ui_GEN_FCN_FILES): ui/$(octave_dirstamp) @ftp/$(octave_dirstamp): $(MKDIR_P) @ftp @@ -338,6 +344,9 @@ time/$(octave_dirstamp): $(MKDIR_P) time : > time/$(octave_dirstamp) +ui/$(octave_dirstamp): + $(MKDIR_P) ui + : > ui/$(octave_dirstamp) if AMCOND_BUILD_DOCS @@ -438,6 +447,12 @@ done .PHONY: uninstall-pkg-add +if AMCOND_HAVE_JAVA +else +dist-hook: + @echo "Packaging distribution requires Java." ; exit 1; +endif + EXTRA_DIST += \ $(IMAGES) \ $(FCN_FILES) \ @@ -458,4 +473,3 @@ if [ "x$(srcdir)" != "x." ]; then \ rm $(java_JAVA_IMAGES); \ fi -
--- a/scripts/audio/wavread.m +++ b/scripts/audio/wavread.m @@ -17,23 +17,32 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {@var{y} =} wavread (@var{filename}) +## @deftypefn {Function File} {@var{y} =} wavread (@var{filename}) +## @deftypefnx {Function File} {[@var{y}, @var{Fs}, @var{bps}] =} wavread (@var{filename}) +## @deftypefnx {Function File} {[@dots{}] =} wavread (@var{filename}, @var{n}) +## @deftypefnx {Function File} {[@dots{}] =} wavread (@var{filename}, [@var{n1} @var{n2}]) +## @deftypefnx {Function File} {[@var{samples}, @var{channels}] =} wavread (@var{filename}, "size") +## ## Load the RIFF/WAVE sound file @var{filename}, and return the samples ## in vector @var{y}. If the file contains multichannel data, then ## @var{y} is a matrix with the channels represented as columns. ## -## @deftypefnx {Function File} {[@var{y}, @var{Fs}, @var{bps}] =} wavread (@var{filename}) +## @code{[@var{y}, @var{Fs}, @var{bps}] = wavread (@var{filename})} +## ## Additionally return the sample rate (@var{fs}) in Hz and the number of bits ## per sample (@var{bps}). ## -## @deftypefnx {Function File} {[@dots{}] =} wavread (@var{filename}, @var{n}) +## @code{[@dots{}] = wavread (@var{filename}, @var{n})} +## ## Read only the first @var{n} samples from each channel. ## -## @deftypefnx {Function File} {[@dots{}] =} wavread (@var{filename}, @var{n1} @var{n2}) +## @code{wavread (@var{filename}, [@var{n1} @var{n2}])} +## ## Read only samples @var{n1} through @var{n2} from each channel. ## -## @deftypefnx {Function File} {[@var{samples}, @var{channels}] =} wavread (@var{filename}, "size") -## Return the number of samples (@var{n}) and channels (@var{ch}) +## @code{[@var{samples}, @var{channels}] = wavread (@var{filename}, "size")} +## +## Return the number of samples (@var{n}) and number of channels (@var{ch}) ## instead of the audio data. ## @seealso{wavwrite} ## @end deftypefn
--- a/scripts/deprecated/java_convert_matrix.m +++ b/scripts/deprecated/java_convert_matrix.m @@ -19,11 +19,11 @@ ## -*- texinfo -*- ## @deftypefn {Built-in Function} {@var{val} =} java_convert_matrix () ## @deftypefnx {Built-in Function} {@var{old_val} =} java_convert_matrix (@var{new_val}) -## @deftypefnx {Built-in Function} {} java_convert_matrix (@var{new_val}, \"local\") +## @deftypefnx {Built-in Function} {} java_convert_matrix (@var{new_val}, "local") ## Query or set the internal variable that controls whether Java arrays are ## automatically converted to Octave matrices. The default value is false. ## -## When called from inside a function with the \"local\" option, the variable is +## When called from inside a function with the "local" option, the variable is ## changed locally for the function and any subroutines it calls. The original ## variable value is restored when exiting the function. ## @seealso{java_matrix_autoconversion, java_unsigned_conversion, java_debug}
--- a/scripts/deprecated/java_debug.m +++ b/scripts/deprecated/java_debug.m @@ -19,12 +19,12 @@ ## -*- texinfo -*- ## @deftypefn {Built-in Function} {@var{val} =} java_debug () ## @deftypefnx {Built-in Function} {@var{old_val} =} java_debug (@var{new_val}) -## @deftypefnx {Built-in Function} {} java_debug (@var{new_val}, \"local\") +## @deftypefnx {Built-in Function} {} java_debug (@var{new_val}, "local") ## Query or set the internal variable that determines whether extra debugging ## information regarding the initialization of the JVM and any Java exceptions ## is printed. ## -## When called from inside a function with the \"local\" option, the variable is +## When called from inside a function with the "local" option, the variable is ## changed locally for the function and any subroutines it calls. The original ## variable value is restored when exiting the function. ## @seealso{debug_java, java_convert_matrix, java_unsigned_conversion}
--- a/scripts/deprecated/java_invoke.m +++ b/scripts/deprecated/java_invoke.m @@ -30,8 +30,8 @@ ## ## @example ## @group -## ret = java_invoke (x, \"method1\", 1.0, \"a string\") -## ret = x.method1 (1.0, \"a string\") +## ret = java_invoke (x, "method1", 1.0, "a string") +## ret = x.method1 (1.0, "a string") ## @end group ## @end example ##
--- a/scripts/deprecated/java_unsigned_conversion.m +++ b/scripts/deprecated/java_unsigned_conversion.m @@ -19,13 +19,13 @@ ## -*- texinfo -*- ## @deftypefn {Built-in Function} {@var{val} =} java_unsigned_conversion () ## @deftypefnx {Built-in Function} {@var{old_val} =} java_unsigned_conversion (@var{new_val}) -## @deftypefnx {Built-in Function} {} java_unsigned_conversion (@var{new_val}, \"local\") +## @deftypefnx {Built-in Function} {} java_unsigned_conversion (@var{new_val}, "local") ## Query or set the internal variable that controls how integer classes are ## converted when Java matrix autoconversion is enabled. When enabled, Java ## arrays of class Byte or Integer are converted to matrices of class uint8 or ## uint32 respectively. ## -## When called from inside a function with the \"local\" option, the variable is +## When called from inside a function with the "local" option, the variable is ## changed locally for the function and any subroutines it calls. The original ## variable value is restored when exiting the function. ## @seealso{java_unsigned_autoconversion, java_convert_matrix, debug_java}
--- a/scripts/deprecated/javafields.m +++ b/scripts/deprecated/javafields.m @@ -40,7 +40,7 @@ endif c_methods = javaMethod ("getFields", "org.octave.ClassHelper", javaobj); - method_list = strsplit (c_methods, ';'); + method_list = strsplit (c_methods, ';', false); if (nargout == 0) if (! isempty (method_list))
--- a/scripts/deprecated/javamethods.m +++ b/scripts/deprecated/javamethods.m @@ -40,7 +40,7 @@ endif cls_methods = javaMethod ("getMethods", "org.octave.ClassHelper", classname); - method_list = strsplit (cls_methods, ';'); + method_list = strsplit (cls_methods, ';', false); if (nargout == 0) if (! isempty (method_list))
--- a/scripts/general/fieldnames.m +++ b/scripts/general/fieldnames.m @@ -52,7 +52,7 @@ obj = class (obj); endif names_str = javaMethod ("getFields", "org.octave.ClassHelper", obj); - names = strsplit (names_str, ';'); + names = strsplit (names_str, ';', false); else error ("fieldnames: Invalid input argument"); endif
--- a/scripts/general/int2str.m +++ b/scripts/general/int2str.m @@ -73,7 +73,7 @@ endif tmp = sprintf (fmt, permute (n, [2, 1, 3 : nd])); tmp(end) = ""; - retval = char (strsplit (tmp, "\n")); + retval = char (strsplit (tmp, "\n", false)); endfunction
--- a/scripts/general/methods.m +++ b/scripts/general/methods.m @@ -43,14 +43,14 @@ mtds_list = __methods__ (obj); if (isempty (mtds_list)) mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj); - mtds_list = strsplit (mtds_str, ';'); + mtds_list = strsplit (mtds_str, ';', false); endif elseif (isjava (obj)) ## FIXME: Function prototype that excepts java obj exists, but doesn't ## work if obj is java.lang.String. Convert obj to classname. obj = class (obj); mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj); - mtds_list = strsplit (mtds_str, ';'); + mtds_list = strsplit (mtds_str, ';', false); else error ("methods: Invalid input argument"); endif
--- a/scripts/general/num2str.m +++ b/scripts/general/num2str.m @@ -118,7 +118,7 @@ fmt = cstrcat (deblank (repmat (fmt, 1, columns (x))), "\n"); nd = ndims (x); tmp = sprintf (fmt, permute (x, [2, 1, 3:nd])); - retval = strtrim (char (strsplit (tmp(1:end-1), "\n"))); + retval = strtrim (char (strsplit (tmp(1:end-1), "\n", false))); else # Complex matrix input if (nargin == 2) if (ischar (arg)) @@ -164,7 +164,7 @@ tmp = regexprep (tmp, " +i\n", "i\n"); tmp = regexprep (tmp, "( +)i", "i$1"); - retval = strtrim (char (strsplit (tmp(1:end-1), "\n"))); + retval = strtrim (char (strsplit (tmp(1:end-1), "\n", false))); endif endfunction
--- a/scripts/general/postpad.m +++ b/scripts/general/postpad.m @@ -78,7 +78,7 @@ y = x(idx{:}); else sz (dim) = l - d; - y = cat (dim, x, c * ones (sz)); + y = cat (dim, x, c(ones (sz))); endif endfunction
--- a/scripts/geometry/voronoin.m +++ b/scripts/geometry/voronoin.m @@ -28,6 +28,20 @@ ## contains options passed to the underlying qhull command. ## See the documentation for the Qhull library for details ## @url{http://www.qhull.org/html/qh-quick.htm#options}. +## +## The default options depend on the dimension of the input: +## +## @itemize +## @item 2-D and 3-D: @var{options} = @code{@{"Qbb"@}} +## +## @item 4-D and higher: @var{options} = @code{@{"Qbb", "Qx"@}} +## @end itemize +## +## If @var{options} is not present or @code{[]} then the default arguments are +## used. Otherwise, @var{options} replaces the default argument list. +## To append user options to the defaults it is necessary to repeat the +## default arguments in @var{options}. Use a null string to pass no arguments. +## ## @seealso{voronoi, convhulln, delaunayn} ## @end deftypefn @@ -63,5 +77,7 @@ %% FIXME: Need functional tests -%% FIXME: Need input validation tests +%!error voronoin () +%!error voronoin (1,2,3) +%!error <number of points must be greater than their dimension> voronoin ([1 2])
--- a/scripts/help/gen_doc_cache.m +++ b/scripts/help/gen_doc_cache.m @@ -117,7 +117,7 @@ function cache = gen_doc_cache_in_dir (directory) ## If 'directory' is not in the current path, add it so we search it - dir_in_path = ismember (directory, strsplit (path (), pathsep ())); + dir_in_path = ismember (directory, strsplit (path (), pathsep (), false)); # dirs not in path if (! iscell (directory))
--- a/scripts/help/help.m +++ b/scripts/help/help.m @@ -142,7 +142,7 @@ builtins = sprintf ("*** builtins:\n\n%s\n\n", list_in_columns (__builtins__ ())); - dirs = strsplit (path, pathsep); + dirs = strsplit (path, pathsep, false); flist = ""; for i = 2:numel (dirs) files = sort ({dir(fullfile (dirs{i}, "*.m")).name, ...
--- a/scripts/help/lookfor.m +++ b/scripts/help/lookfor.m @@ -66,10 +66,10 @@ endif ## Search functions in new path dirs. - orig_path = strsplit (__pathorig__ (), pathsep ()); + orig_path = strsplit (__pathorig__ (), pathsep (), false); ## ditto for path. - new_path = strsplit (path (), pathsep ()); + new_path = strsplit (path (), pathsep (), false); ## scratch out directories already covered by orig_path. if (had_core_cache)
--- a/scripts/image/bone.m +++ b/scripts/image/bone.m @@ -44,16 +44,38 @@ endif if (n == 1) - map = [0.125, 0.125, 0.125]; - elseif (n > 1) - x = linspace (0, 1, n)'; - r = (x < 3/4) .* (7/8 * x) ... - + (x >= 3/4) .* (11/8 * x - 3/8); - g = (x < 3/8) .* (7/8 * x) ... - + (x >= 3/8 & x < 3/4) .* (29/24 * x - 1/8) ... - + (x >= 3/4) .* (7/8 * x + 1/8); - b = (x < 3/8) .* (29/24 * x) ... - + (x >= 3/8) .* (7/8 * x + 1/8); + map = [1/8 1/8 1/8]; + elseif (n == 2) + map = [1/16 1/8 1/8 + 1 1 1 ]; + elseif (n > 2) + x = [0:n-1]' / (n-1); + + idx = floor (3/4*n); + nel = n - idx + 1; # number of elements + rem = mod (n, 8); + switch (rem) + case {2, 4} + base = 1 / (16 + 2*(n-rem)); + case {5, 7} + base = 1 / (24 + 2*(n-rem)); + otherwise + base = 0; + endswitch + r(1:idx,1) = 7/8 * x(1:idx); + r(idx:n,1) = linspace (7/8 * x(idx) + base, 1, nel); + + idx = floor (3/8 * n); + nel = idx + 1; + g(1:idx,1) = 7/8 * x(1:idx); + g(idx:2*idx,1) = linspace (7/8 * x(idx), 7/8 * x(2*idx) + 1/8, nel); + g(2*idx+1:n,1) = 7/8 * x(2*idx+1:n) + 1/8; + + base = 1 / (8*idx); + nel = idx; + b(1:idx,1) = linspace (base, 7/8 * x(idx) + 1/8, nel); + b(idx:n,1) = 7/8 * x(idx:n) + 1/8; + map = [r, g, b]; else map = zeros (0, 3);
--- a/scripts/image/copper.m +++ b/scripts/image/copper.m @@ -46,11 +46,11 @@ if (n == 1) map = [0, 0, 0]; elseif (n > 1) - x = linspace (0, 1, n)'; + x = [0:(n-1)]' / (n - 1); r = (x < 4/5) .* (5/4 * x) ... + (x >= 4/5); - g = 4/5 * x; - b = 1/2 * x; + g = 0.7812 * x; + b = 0.4975 * x; map = [r, g, b]; else map = zeros (0, 3);
--- a/scripts/image/hot.m +++ b/scripts/image/hot.m @@ -45,13 +45,26 @@ if (n == 1) map = [1, 1, 1]; - elseif (n > 1) - x = linspace (0, 1, n)'; - r = (x < 2/5) .* (5/2 * x) ... - + (x >= 2/5); - g = (x >= 2/5 & x < 4/5) .* (5/2 * x - 1) ... - + (x >= 4/5); - b = (x >= 4/5) .* (5 * x - 4); + elseif (n == 2) + map = [1, 1, 1/2 + 1, 1, 1 ]; + elseif (n > 2) + idx = floor (3/8 * n); + nel = idx; + + r = ones (n, 1); + r(1:idx, 1) = [1:nel]' / nel; + + g = zeros (n, 1); + g(idx+1:2*idx, 1) = r(1:idx); + g(2*idx+1:end, 1) = 1; + + idx = 2*idx + 1; # approximately 3/4 *n + nel = n - idx + 1; + + b = zeros (n, 1); + b(idx:end, 1) = [1:nel]' / nel; + map = [r, g, b]; else map = zeros (0, 3);
--- a/scripts/image/hsv.m +++ b/scripts/image/hsv.m @@ -23,7 +23,7 @@ ## It is useful for displaying periodic functions. The map is obtained by ## linearly varying the hue through all possible values while keeping constant ## maximum saturation and value. The equivalent code is -## @code{hsv2rgb ([linspace(0,1,N)', ones(N,2)])}. +## @code{hsv2rgb ([(0:N-1)'/N, ones(N,2)])}. ## ## The argument @var{n} must be a scalar. ## If unspecified, the length of the current colormap, or 64, is used. @@ -50,7 +50,7 @@ if (n == 1) map = [1, 0, 0]; elseif (n > 1) - hue = linspace (0, 1, n)'; + hue = [0:n-1]' / n; map = hsv2rgb ([hue, ones(n,1), ones(n,1)]); else map = zeros (0, 3);
--- a/scripts/image/ind2rgb.m +++ b/scripts/image/ind2rgb.m @@ -46,15 +46,14 @@ [x, map] = ind2x ("ind2rgb", x, map); ## Compute result - [row, col] = size (x); - R = reshape (map(x(:), 1), row, col); - G = reshape (map(x(:), 2), row, col); - B = reshape (map(x(:), 3), row, col); + sz = size (x); + R = reshape (map(x(:), 1), sz); + G = reshape (map(x(:), 2), sz); + B = reshape (map(x(:), 3), sz); - ## Use 3D array if only one output is requested. + ## Use ND array if only one output is requested. if (nargout <= 1) - R(:,:,2) = G; - R(:,:,3) = B; + R = reshape ([R(:); G(:); B(:)], [sz, 3]); endif endfunction
--- a/scripts/image/jet.m +++ b/scripts/image/jet.m @@ -45,17 +45,45 @@ if (n == 1) map = [0, 1, 1]; - elseif (n > 1) - x = linspace (0, 1, n)'; - r = (x >= 3/8 & x < 5/8) .* (4 * x - 3/2) ... - + (x >= 5/8 & x < 7/8) ... - + (x >= 7/8) .* (-4 * x + 9/2); - g = (x >= 1/8 & x < 3/8) .* (4 * x - 1/2) ... - + (x >= 3/8 & x < 5/8) ... - + (x >= 5/8 & x < 7/8) .* (-4 * x + 7/2); - b = (x < 1/8) .* (4 * x + 1/2) ... - + (x >= 1/8 & x < 3/8) ... - + (x >= 3/8 & x < 5/8) .* (-4 * x + 5/2); + elseif (n == 2) + map = [0, 0, 1 + 0, 1, 1]; + elseif (n > 2) + nel = ceil (n/4); # number of elements + idx1 = ceil (3/8 * n) + 1; # ~3/8*n for large n + if (mod (n, 8) == 2) + idx1++; + endif + idx2 = idx1 + nel - 1; # ~5/8*n for large n + idx3 = min (idx2 + nel, n); # ~7/8*n for large n + + r = zeros (n, 1); + r(idx1:idx2, 1) = [1:nel] / nel; + r(idx2:idx3, 1) = 1; + nel2 = n - idx3; + r(idx3:(idx3+nel2), 1) = [nel:-1:(nel - nel2)] / nel; + + idx1 = idx1 - nel; # ~1/8*n for large n + idx2 = idx1 + nel - 1; # ~3/8*n for large n + idx3 = min (idx2 + nel, n); # ~5/8*n for large n + + g = zeros (n, 1); + g(idx1:idx2, 1) = [1:nel] / nel; + g(idx2:idx3, 1) = 1; + nel2 = min (nel, n - idx3); + g(idx3:(idx3+nel2), 1) = [nel:-1:(nel - nel2)] / nel; + + idx1 = max (idx2 - nel, 1); # ~1/8*n for large n + idx2 = idx2; # ~3/8*n for large n + idx3 = idx3; # ~5/8*n for large n + + b = zeros (n, 1); + nel2 = min (nel, idx1-1); + b(1:idx1, 1) = [(nel - nel2):nel] / nel; + b(idx1:idx2, 1) = 1; + nel2 = min (nel, n - idx3); + b(idx2:(idx2+nel2), 1) = [nel:-1:(nel - nel2)] / nel; + map = [r, g, b]; else map = zeros (0, 3);
--- a/scripts/image/pink.m +++ b/scripts/image/pink.m @@ -45,15 +45,26 @@ if (n == 1) map = sqrt ([1/3, 1/3, 1/3]); - elseif (n > 1) - x = linspace (0, 1, n)'; - r = (x < 3/8) .* (14/9 * x) ... - + (x >= 3/8) .* (2/3 * x + 1/3); - g = (x < 3/8) .* (2/3 * x) ... - + (x >= 3/8 & x < 3/4) .* (14/9 * x - 1/3) ... - + (x >= 3/4) .* (2/3 * x + 1/3); - b = (x < 3/4) .* (2/3 * x) ... - + (x >= 3/4) .* (2 * x - 1); + elseif (n == 2) + map = sqrt ([1/3, 1/3, 1/6 + 1 1 1 ]); + elseif (n > 2) + x = [0:(n-1)]' / (n-1); + idx = floor (3/8 * n); + base = 1 / (3 * idx); + + nel = idx; # number of elements + r(1:idx,1) = linspace (base, 2/3*x(idx) + 1/3, nel); + r(idx+1:n,1) = 2/3*x(idx+1:n) + 1/3; + + g(1:idx,1) = 2/3*x(1:idx); + g(idx:2*idx,1) = linspace (2/3*x(idx), 2/3*x(2*idx) + 1/3, nel+1); + g(2*idx+1:n,1) = 2/3*x(2*idx+1:n) + 1/3; + + nel = n - 2*idx + 1; + b(1:2*idx,1) = 2/3*x(1:2*idx); + b(2*idx:n,1) = linspace (2/3*x(2*idx), 1, nel); + map = sqrt ([r, g, b]); else map = zeros (0, 3);
--- a/scripts/image/private/ind2x.m +++ b/scripts/image/private/ind2x.m @@ -22,7 +22,7 @@ function [x, map] = ind2x (caller, x, map) ## Check if X is an indexed image. - if (ndims (x) != 2 || issparse (x) || (isfloat (x) && ! isindex (x)) || + if (ndims (x) < 2 || issparse (x) || (isfloat (x) && ! isindex (x)) || ! any (strcmp (class (x), {"uint8", "uint16", "single", "double"}))) error ("%s: X must be an indexed image", caller); endif
--- a/scripts/image/rainbow.m +++ b/scripts/image/rainbow.m @@ -49,17 +49,18 @@ if (n == 1) map = [1, 0, 0]; elseif (n > 1) - x = linspace (0, 1, n)'; + x = [0:(n-1)]' / (n - 1); - r = ((x < 2/5) + r = ( (x < 2/5) + (x >= 2/5 & x < 3/5) .* (-5 * x + 3) + (x >= 4/5) .* (10/3 * x - 8/3)); - g = ((x < 2/5) .* (5/2 * x) + g = ( (x < 2/5) .* (5/2 * x) + (x >= 2/5 & x < 3/5) + (x >= 3/5 & x < 4/5) .* (-5 * x + 4)); - b = (x >= 3/5 & x < 4/5) .* (5 * x - 3) + (x >= 4/5); + b = ( (x >= 3/5 & x < 4/5) .* (5 * x - 3) + + (x >= 4/5)); map = [r, g, b]; else
--- a/scripts/image/rgbplot.m +++ b/scripts/image/rgbplot.m @@ -44,7 +44,7 @@ ## @seealso{colormap} ## @end deftypefn -function h = rgbplot (cmap, style) +function h = rgbplot (cmap, style = "profile") if (nargin < 1 || nargin > 2) print_usage (); @@ -87,4 +87,6 @@ %!error rgbplot () %!error rgbplot (1,2) %!error <CMAP must be a valid colormap> rgbplot ({0 1 0}) +%!error <STYLE must be a string> rgbplot ([0 1 0], 2) +%!error <unknown style `nostyle'> rgbplot ([0 1 0], "nostyle")
--- a/scripts/io/strread.m +++ b/scripts/io/strread.m @@ -291,8 +291,8 @@ ## First parse of FORMAT if (strcmpi (strtrim (format), "%f")) ## Default format specified. Expand it (to desired nargout) - fmt_words = cell (nargout, 1); - fmt_words (1:nargout) = format; + fmt_words = cell (max (nargout, 1), 1); + fmt_words (1:max (nargout, 1)) = format; else ## Determine the number of words per line as a first guess. Forms ## like %f<literal>) (w/o delimiter in between) are fixed further on @@ -621,13 +621,13 @@ strrep (words(icol, jptr), fmt_words{ii}, ... [char(255) char(254)]); wrds(2:2:2*numel (words(icol, jptr))-1) = char (255); - wrds = strsplit ([wrds{:}], char (255)); + wrds = strsplit ([wrds{:}], char (255), false); words(icol, jptr) = ... wrds(find (cellfun ("isempty", strfind (wrds, char (254))))); wrds(find (cellfun ("isempty", strfind (wrds, char (254))))) ... = char (255); words(icol+1, jptr) = strsplit (strrep ([wrds{2:end}], ... - char (254), fmt_words{ii}), char (255)); + char (254), fmt_words{ii}), char (255), false); ## Former trailing literal may now be leading for next specifier --ii; fwptr = [fwptr(1:ii) (++fwptr(ii+1:end))]; @@ -699,7 +699,7 @@ case {"%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", "%8", "%9"} sw = regexp (fmt_words{m}, '\d', "once"); ew = regexp (fmt_words{m}, '[nfudsq]') - 1; - nfmt = strsplit (fmt_words{m}(2:ew), "."); + nfmt = strsplit (fmt_words{m}(2:ew), ".", false); swidth = str2double (nfmt{1}); switch fmt_words{m}(ew+1) case {"d", "u", "f", "n"} @@ -772,7 +772,7 @@ endif ## Split text string along delimiters - out = strsplit (text, sep, mult_dlms_s1); + out = strsplit (text, sep, mult_dlms_s1, "delimitertype", "legacy"); if (index (sep, eol_char)); out = strrep (out, char (255), ''); endif ## In case of trailing delimiter, strip stray last empty word if (!isempty (out) && any (sep == text(end))) @@ -965,6 +965,10 @@ %! assert (a, [1; 2], 1e-15); %! assert (b, [1; 3], 1e-15); +%% Test for no output arg (interactive use) +%!test +%! assert (strread (",2,,4\n5,,7,", "", "delimiter", ","), [NaN; 2; NaN; 4; 5; NaN; 7]); + %% Unsupported format specifiers %!test %!error <format specifiers are not supported> strread ("a", "%c")
--- a/scripts/io/textread.m +++ b/scripts/io/textread.m @@ -44,6 +44,11 @@ ## The optional input @var{n} specifies the number of data lines to read; in ## this sense it differs slightly from the format repeat count in strread. ## +## If the format string is empty (not: omitted) and the file contains only +## numeric data (excluding headerlines), textread will return a rectangular +## matrix with the number of columns matching the number of numeric fields on +## the first data line of the file. Empty fields are returned as zero values. +## ## @seealso{strread, load, dlmread, fscanf, textscan} ## @end deftypefn @@ -116,12 +121,12 @@ ## Determine EOL from file. Search for EOL candidates in first BUFLENGTH chars eol_srch_len = min (length (str), BUFLENGTH); ## First try DOS (CRLF) - if (! isempty (strfind ("\r\n", str(1 : eol_srch_len)))) + if (! isempty (strfind (str(1 : eol_srch_len), "\r\n"))) eol_char = "\r\n"; ## Perhaps old Macintosh? (CR) - elseif (! isempty (strfind ("\r", str(1 : eol_srch_len)))) + elseif (! isempty (strfind (str(1 : eol_srch_len), "\r"))) eol_char = "\r"; - ## Otherwise, use plain UNIX (LF) + ## Otherwise, use plain *nix (LF) else eol_char = "\n"; endif @@ -174,9 +179,46 @@ ## Call strread to make it do the real work [varargout{1:max (nargout, 1)}] = strread (str, format, varargin {:}); + ## Hack to concatenate/reshape numeric output into 2D array (undocumented ML) + ## In ML this only works in case of an empty format string + if (isempty (format)) + ## Get number of fields per line. + ## 1. Get eol_char position + iwhsp = find (strcmpi ("whitespace", varargin)); + whsp = varargin{iwhsp + 1}; + idx = regexp (str, eol_char, "once"); + ## 2. Get first data line til EOL. Avoid corner case of just one line + if (! isempty (idx)) + str = str(1:idx-1); + endif + idelimiter = find (strcmpi (varargin, "delimiter"), 1); + if (isempty (idelimiter)) + ## Assume delimiter = whitespace + ## 3A. whitespace incl. consecutive whitespace => single space + str = regexprep (str, sprintf ("[%s]+", whsp), ' '); + ## 4A. Remove possible leading & trailing spaces + str = strtrim (str); + ## 5A. Count spaces, add one to get nr of data fields per line + ncols = numel (strfind (str, " ")) + 1; + else + ## 3B. Just count delimiters. FIXME: delimiters could occur in literals + delimiter = varargin {idelimiter+1}; + ncols = numel (regexp (str, sprintf ("[%s]", delimiter))) + 1; + endif + ## 6. Reshape; watch out, we need a transpose + nrows = ceil (numel (varargout{1}) / ncols); + pad = mod (numel (varargout{1}), ncols); + if (pad > 0) + pad = ncols - pad; + varargout{1}(end+1 : end+pad) = NaN; + endif + varargout{1} = reshape (varargout{1}, ncols, nrows)'; + ## ML replaces empty values with NaNs + varargout{1}(find (isnan (varargout{1}))) = 0; + endif + endfunction - %!test %! f = tmpnam (); %! d = rand (5, 3); @@ -195,6 +237,76 @@ %! unlink (f); %! assert (a, d(2:7, 1), 1e-2); +%% Test reading 2D matrix with empty format +%!test +%! f = tmpnam (); +%! d = rand (5, 2); +%! dlmwrite (f, d, "precision", "%5.2f"); +%! A = textread (f, "", "headerlines", 3); +%! unlink (f); +%! assert (A, d(4:5, :), 1e-2); + +%% Read multiple lines using empty format string +%!test +%! f = tmpnam (); +%! unlink (f); +%! fid = fopen (f, "w"); +%! d = rand (1, 4); +%! fprintf (fid, " %f %f %f %f ", d); +%! fclose (fid); +%! A = textread (f, ""); +%! unlink (f); +%! assert (A, d, 1e-6); + +%% Empty format, corner case = one line w/o EOL +%!test +%! f = tmpnam (); +%! unlink (f); +%! fid = fopen (f, "w"); +%! d = rand (1, 4); +%! fprintf (fid, " %f %f %f %f ", d); +%! fclose (fid); +%! A = textread (f, ""); +%! unlink (f); +%! assert (A, d, 1e-6); + +%% Read multiple lines using empty format string, missing data (should be 0) +%!test +%! f = tmpnam (); +%! unlink (f); +%! fid = fopen (f, "w"); +%! d = rand (1, 4); +%! fprintf (fid, "%f, %f, , %f, %f ", d); +%! fclose (fid); +%! A = textread (f, ""); +%! unlink (f); +%! assert (A, [ d(1:2) 0 d(3:4)], 1e-6); + +%% Test with empty positions - ML returns 0 for empty fields +%!test +%! f = tmpnam (); +%! unlink (f); +%! fid = fopen (f, "w"); +%! d = rand (1, 4); +%! fprintf (fid, ",2,,4\n5,,7,\n"); +%! fclose (fid); +%! A = textread (f, "", "delimiter", ","); +%! unlink (f); +%! assert (A, [0 2 0 4; 5 0 7 0], 1e-6); + +%% Another test with empty format + positions, now with more incomplete lower +%% row (must be appended with zeros to get rectangular matrix) +%!test +%! f = tmpnam (); +%! unlink (f); +%! fid = fopen (f, "w"); +%! d = rand (1, 4); +%! fprintf (fid, ",2,,4\n5,\n"); +%! fclose (fid); +%! A = textread (f, "", "delimiter", ","); +%! unlink (f); +%! assert (A, [0 2 0 4; 5 0 0 0], 1e-6); + %% Test input validation %!error textread () %!error textread (1)
--- a/scripts/io/textscan.m +++ b/scripts/io/textscan.m @@ -67,19 +67,26 @@ ## The second output, @var{position}, provides the position, in characters, ## from the beginning of the file. ## +## If the format string is empty (not: omitted) and the file contains only +## numeric data (excluding headerlines), textscan will return data in a number +## of columns matching the number of numeric fields on the first data line of +## the file. +## ## @seealso{dlmread, fscanf, load, strread, textread} ## @end deftypefn function [C, position] = textscan (fid, format = "%f", varargin) BUFLENGTH = 4096; ## Read buffer - + emptfmt = 0; ## Signals deliberately empty format string + ## Check input if (nargin < 1) print_usage (); endif if (isempty (format)) + emptfmt = 1; format = "%f"; endif @@ -132,6 +139,9 @@ ## Matlab says default delimiter = whitespace. ## strread() will pick this up further args(end+1:end+2) = {'delimiter', ""}; + delimiter = ""; + else + delimiter = args{find (strcmpi (args, "delimiter")) + 1}; endif collop = false; @@ -157,6 +167,15 @@ args(end+1:end+2) = {"returnonerror", 1}; endif + ## Check if a headerlines argument is specified + headerlines = find (strcmpi (args, "headerlines"), 1); + if (! isempty (headerlines)) + ## Yep. But it is stray when reading from strings... + if (ischar (fid)) + warning ("textscan: 'headerlines' ignored when reading from strings"); + endif + endif + if (ischar (fid)) ## Read from a text string if (nargout == 2) @@ -166,7 +185,6 @@ else st_pos = ftell (fid); ## Skip header lines if requested - headerlines = find (strcmpi (args, "headerlines"), 1); if (! isempty (headerlines)) ## Beware of missing or wrong headerline value if (headerlines == numel (args) @@ -183,7 +201,10 @@ elseif (args{headerlines + 1} < 0) warning ("textscan.m: negative headerline value ignored"); endif - endif + endif + ## Read a first file chunk. Rest follows after endofline processing + [str, count] = fscanf (fid, "%c", BUFLENGTH); + endif ## Check for empty result @@ -208,10 +229,10 @@ ## Determine EOL from file. Search for EOL candidates in first BUFLENGTH chars eol_srch_len = min (length (str), BUFLENGTH); ## First try DOS (CRLF) - if (! isempty (strfind ("\r\n", str(1 : eol_srch_len)))) + if (! isempty (strfind (str(1 : eol_srch_len), "\r\n"))) eol_char = "\r\n"; ## Perhaps old Macintosh? (CR) - elseif (! isempty (strfind ("\r", str(1 : eol_srch_len)))) + elseif (! isempty (strfind (str(1 : eol_srch_len), "\r"))) eol_char = "\r"; ## Otherwise, use plain UNIX (LF) else @@ -264,13 +285,11 @@ endif endif - ## Determine the number of data fields - num_fields = numel (strfind (format, "%")) - numel (strfind (format, "%*")); - ## Strip trailing EOL to avoid returning stray missing values (f. strread). - ## However, in case of CollectOutput request, presence of EOL is required + ## However, in case of CollectOutput request, presence of EOL is required; + ## also in case of deliberately entered empty format string eol_at_end = strcmp (str(end-length (eol_char) + 1 : end), eol_char); - if (collop) + if (collop || emptfmt) if (! eol_at_end) str(end+1 : end+length (eol_char)) = eol_char; endif @@ -284,6 +303,36 @@ C = cell (1, num_fields); [C{:}] = strread (str, format, args{:}); + ## I.c.o. empty format, match nr. of cols to nr. of fields on first read line + if (emptfmt) + ## Find end of first line + eoi = index (str, eol_char); + if (eoi) + ## str contains an EOL, proceed with assessing nr. of columns + ncols = countcols (C, str(1 : eoi-1), delimiter, whitespace); + ## See if lowermost data row must be completed + pad = mod (numel (C{1}), ncols); + if (pad) + ## Textscan returns NaNs for empty fields + C(1) = [C{1}; NaN(ncols - pad, 1)]; + endif + ## Replace NaNs with EmptyValue, if any + ipos = find (strcmpi (args, "emptyvalue")); + if (ipos) + C{1}(find (isnan (C{1}))) = args{ipos+1}; + endif + ## Compute nr. of rows + nrows = floor (numel (C{1}) / ncols); + ## Reshape C; watch out, transpose needed + C(1) = reshape (C{1}, ncols, numel (C{1}) / ncols)'; + ## Distribute columns over C and wipe cols 2:end of C{1} + for ii=2:ncols + C(ii) = C{1}(:, ii); + endfor + C{1} = C{1}(:, 1); + endif + endif + ## If requested, collect output columns of same class if (collop) C = colloutp (C); @@ -297,6 +346,21 @@ endfunction +## Assess nr of data fields on first line of data +function ncols = countcols (C, str, dlm, wsp) + + if (isempty (dlm)) + ## Field separator = whitespace. Fold multiple whitespace into one + str = regexprep (str, sprintf ("[%s]", wsp), " "); + str = strtrim (str); + ncols = numel (strfind (str, " ")) + 1; + else + ncols = numel (regexp (str, sprintf ("[%s]", dlm))) + 1; + endif + +endfunction + + ## Collect consecutive columns of same class into one cell column function C = colloutp (C) @@ -507,6 +571,90 @@ %! assert (strcmp (lh, rh)); %! end -%!error <missing or illegal value for> textread (file_in_loadpath ("textscan.m"), "", "headerlines") -%!error <missing or illegal value for> textread (file_in_loadpath ("textscan.m"), "", "headerlines", 'hh') -%!error <character value required for> textread (file_in_loadpath ("textscan.m"), "", "endofline", true) +%% Test reading from a real file +%!test +%! f = tmpnam (); +%! fid = fopen (f, "w+"); +%! d = rand (1, 4); +%! fprintf (fid, " %f %f %f %f ", d); +%! fseek (fid, 0, "bof"); +%! A = textscan (fid, "%f %f"); +%! fclose (fid); +%! unlink (f); +%! assert (A{1}, [d(1); d(3)], 1e-6); +%! assert (A{2}, [d(2); d(4)], 1e-6); + +%% Tests reading with empty format, should return proper nr of columns +%!test +%! f = tmpnam (); +%! fid = fopen (f, "w+"); +%! fprintf (fid, " 1 2 3 4\n5 6 7 8"); +%! fseek (fid, 0, "bof"); +%! A = textscan (fid, ""); +%! fclose (fid); +%! unlink (f); +%! assert (A{1}, [1 ; 5], 1e-6); +%! assert (A{2}, [2 ; 6], 1e-6); +%! assert (A{3}, [3 ; 7], 1e-6); +%! assert (A{4}, [4 ; 8], 1e-6); + +%% Tests reading with empty format; empty fields & incomplete lower row +%!test +%! f = tmpnam (); +%! fid = fopen (f, "w+"); +%! fprintf (fid, " ,2,,4\n5,6"); +%! fseek (fid, 0, "bof"); +%! A = textscan (fid, "", "delimiter", ",", "EmptyValue", 999, "CollectOutput" , 1); +%! fclose (fid); +%! unlink (f); +%! assert (A{1}, [999, 2, 999, 4; 5, 6, 999, 999], 1e-6); + +%% Error message tests + +%!test +%! f = tmpnam (); +%! fid = fopen (f, "w+"); +%! msg1 = "Missing or illegal value for 'headerlines'"; +%! try +%! A = textscan (fid, "", "headerlines"); +%! end_try_catch; +%! fclose (fid); +%! unlink (f); +%! assert (msg1, lasterr); + +%!test +%! f = tmpnam (); +%! fid = fopen (f, "w+"); +%! msg1 = "Missing or illegal value for 'headerlines'"; +%! try +%! A = textscan (fid, "", "headerlines", "hh"); +%! end_try_catch; +%! fclose (fid); +%! unlink (f); +%! assert (msg1, lasterr); + +%!test +%! f = tmpnam (); +%! fid = fopen (f, "w+"); +%! fprintf (fid,"some_string"); +%! fseek (fid, 0, "bof"); +%! msg1 = "textscan: illegal EndOfLine character value specified"; +%! try +%! A = textscan (fid, "%f", "EndOfLine", "\n\r"); +%! end_try_catch; +%! fclose (fid); +%! unlink (f); +%! assert (msg1, lasterr); + +%!test +%! f = tmpnam (); +%! fid = fopen (f, "w+"); +%! fprintf (fid,"some_string"); +%! fseek (fid, 0, "bof"); +%! msg1 = "textscan: character value required for EndOfLine"; +%! try +%! A = textscan (fid, "%f", "EndOfLine", 33); +%! end_try_catch; +%! fclose (fid); +%! unlink (f); +%! assert (msg1, lasterr);
deleted file mode 100644 --- a/scripts/java/dlgtest.m +++ /dev/null @@ -1,205 +0,0 @@ -% -% Test the dlg... functions of the Octave-Java bridge -% -% Once the Java bridge works OK this function should be dropped from core octave -% -% Author: Martin Hepperle -% Version August 2010 -% Adapted for core Octave Philip Nienhuis 2012 -% -function dlgtest - - 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 = numel (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 = numel (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
--- a/scripts/java/javaclasspath.m +++ b/scripts/java/javaclasspath.m @@ -58,11 +58,11 @@ ## dynamic classpath dynamic_path = javaMethod ("getClassPath", "org.octave.ClassHelper"); - dynamic_path_list = strsplit (dynamic_path, pathsep ()); + dynamic_path_list = strsplit (dynamic_path, pathsep (), false); ## static classpath static_path = javaMethod ("getProperty", "java.lang.System", "java.class.path"); - static_path_list = strsplit (static_path, pathsep ()); + static_path_list = strsplit (static_path, pathsep (), false); if (numel (static_path_list) > 1) ## remove first element (which is .../octave.jar) static_path_list(1) = [];
--- a/scripts/java/javamem.m +++ b/scripts/java/javamem.m @@ -31,13 +31,13 @@ ## your computer's total memory (which comprises physical RAM and ## virtual memory / swap space on hard disk). ## -## The maximum allowable memory usage can be set using the file java.opts -## (in the same subdirectory where javaaddpath.m lives, see -## "which javaaddpath". Usually that is: +## The maximum allowable memory usage can be configured using the file +## @file{java.opts}. The directory where this file resides is +## determined by the environment variable @w{@env{OCTAVE_JAVA_DIR}}. +## If unset, the directory where @file{javaaddpath.m} resides is used instead +## (typically @file{@env{OCTAVE_HOME}/share/octave/@env{OCTAVE_VERSION}/m/java/} ## -## @file{OCTAVE_HOME/share/octave/OCTAVE_VERSION/m/java/} -## -## java.opts is a plain text file with one option per line. The +## @file{java.opts} is a plain text file with one option per line. The ## default initial memory size and default maximum memory size (which ## are both system dependent) can be overridden like so: ## @@ -45,7 +45,7 @@ ## ## @nospell{-Xmx512m} ## -## (in megabytes in this example.) +## (in megabytes in this example). ## You can adapt these values to your own requirements if your system ## has limited available physical memory or if you get Java memory ## errors.
--- a/scripts/java/module.mk +++ b/scripts/java/module.mk @@ -1,20 +1,12 @@ FCN_FILE_DIRS += java java_FCN_FILES = \ - java/dlgtest.m \ - java/errordlg.m \ - java/helpdlg.m \ - java/inputdlg.m \ java/javaArray.m \ java/javaaddpath.m \ java/javaclasspath.m \ java/javamem.m \ java/javarmpath.m \ - java/listdlg.m \ - java/msgbox.m \ - java/questdlg.m \ - java/usejava.m \ - java/warndlg.m + java/usejava.m FCN_FILES += $(java_FCN_FILES)
--- a/scripts/miscellaneous/compare_versions.m +++ b/scripts/miscellaneous/compare_versions.m @@ -113,8 +113,8 @@ v2nochar = v2; endif - v1n = str2num (char (strsplit (v1nochar, "."))); - v2n = str2num (char (strsplit (v2nochar, "."))); + v1n = str2num (char (strsplit (v1nochar, ".", false))); + v2n = str2num (char (strsplit (v2nochar, ".", false))); if ((isempty (v1n) && isempty (v1c)) || (isempty (v2n) && isempty (v2c))) error ("compare_versions: given version strings are not valid: %s %s", v1, v2);
--- a/scripts/miscellaneous/computer.m +++ b/scripts/miscellaneous/computer.m @@ -49,7 +49,7 @@ function [c, maxsize, endian] = computer (a) if (nargin == 1 && ischar (a) && strcmpi (a, "arch")) - tmp = strsplit (octave_config_info ("canonical_host_type"), "-"); + tmp = strsplit (octave_config_info ("canonical_host_type"), "-", false); if (numel (tmp) == 4) c = sprintf ("%s-%s-%s", tmp{4}, tmp{3}, tmp{1}); else
--- a/scripts/miscellaneous/edit.m +++ b/scripts/miscellaneous/edit.m @@ -241,13 +241,16 @@ ## Start the editor without a file if no file is given. if (nargin < 1) - if (exist (FUNCTION.HOME, "dir") == 7 && (isunix () || ! ispc ())) - system (cstrcat ("cd \"", FUNCTION.HOME, "\" ; ", - sprintf (undo_string_escapes (FUNCTION.EDITOR), "")), - [], FUNCTION.MODE); + if (exist (FUNCTION.HOME, "dir") == 7) + curr_dir = pwd (); + unwind_protect + chdir (FUNCTION.HOME); + do_edit (FUNCTION.EDITOR, "", FUNCTION.MODE); + unwind_protect_cleanup + chdir (curr_dir); + end_unwind_protect else - system (sprintf (undo_string_escapes (FUNCTION.EDITOR), ""), - [], FUNCTION.MODE); + do_edit (FUNCTION.EDITOR, "", FUNCTION.MODE); endif return; endif @@ -329,9 +332,7 @@ ## If the file exists, then edit it. if (FUNCTION.EDITINPLACE) ## Edit in place even if it is protected. - system (sprintf (undo_string_escapes (FUNCTION.EDITOR), - cstrcat ("\"", fileandpath, "\"")), - [], FUNCTION.MODE); + do_edit (FUNCTION.EDITOR, fileandpath, FUNCTION.MODE); return; else ## If the file is modifiable in place then edit it, otherwise make @@ -347,9 +348,7 @@ else fclose (fid); endif - system (sprintf (undo_string_escapes (FUNCTION.EDITOR), - cstrcat ("\"", fileandpath, "\"")), - [], FUNCTION.MODE); + do_edit (FUNCTION.EDITOR, fileandpath, FUNCTION.MODE); return; endif endif @@ -364,9 +363,7 @@ case {"cc", "m"} 0; otherwise - system (sprintf (undo_string_escapes (FUNCTION.EDITOR), - cstrcat ("\"", fileandpath, "\"")), - [], FUNCTION.MODE); + do_edit (FUNCTION.EDITOR, fileandpath, FUNCTION.MODE); return; endswitch @@ -515,10 +512,7 @@ fputs (fid, text); fclose (fid); - ## Finally we are ready to edit it! - system (sprintf (undo_string_escapes (FUNCTION.EDITOR), - cstrcat ("\"", fileandpath, "\"")), - [], FUNCTION.MODE); + do_edit (FUNCTION.EDITOR, fileandpath, FUNCTION.MODE); endif @@ -564,6 +558,21 @@ endfunction +function do_edit (editor, file, mode) + + ## Give the hook function a chance. If that fails, fall back + ## on running an editor with the system function. + + status = __octave_link_edit_file__ (file); + + if (! status) + system (sprintf (undo_string_escapes (editor), + cstrcat ("\"", file, "\"")), + [], mode); + endif + +endfunction + %!test %! s.editor = edit ("get", "editor");
--- a/scripts/miscellaneous/fact.m +++ b/scripts/miscellaneous/fact.m @@ -250,7 +250,7 @@ function out = wordwrap (w) cols = terminal_size ()(2); - wc = strsplit (w, " "); + wc = strsplit (w, " ", false); out = "\n"; i = 1; numwords = numel (wc); @@ -265,4 +265,4 @@ i++; endwhile out = cstrcat (out, "\n"); -endfunction \ No newline at end of file +endfunction
--- a/scripts/miscellaneous/getappdata.m +++ b/scripts/miscellaneous/getappdata.m @@ -15,12 +15,14 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {@var{value} =} getappdata (@var{h}, @var{name}) +## @deftypefn {Function File} {@var{value} =} getappdata (@var{h}, @var{name}) +## @deftypefnx {Function File} {@var{appdata} =} getappdata (@var{h}) +## ## Return the @var{value} for named application data for the object(s) with ## handle(s) @var{h}. -## @deftypefnx {Function File} {@var{appdata} =} getappdata (@var{h}) -## Return a structure, @var{appdata}, whose fields correspond to the appdata -## properties. +## +## @code{getappdata(@var{h})} returns a structure, @var{appdata}, whose fields +## correspond to the appdata properties. ## @end deftypefn ## Author: Ben Abbott <bpabbott@mac.com>
--- a/scripts/miscellaneous/license.m +++ b/scripts/miscellaneous/license.m @@ -17,21 +17,31 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} license +## @deftypefn {Command} {} license +## @deftypefnx {Function File} {} license ("inuse") +## @deftypefnx {Function File} {@var{retval} =} license ("inuse") +## @deftypefnx {Function File} {@var{retval} =} license ("test", @var{feature}) +## @deftypefnx {Function File} {} license ("test", @var{feature}, @var{toggle}) +## @deftypefnx {Function File} {@var{retval} =} license ("checkout", @var{feature}) +## ## Display the license of Octave. ## -## @deftypefnx {Function File} {} license ("inuse") +## @code{license ("inuse")} +## ## Display a list of packages currently being used. ## -## @deftypefnx {Function File} {@var{retval} =} license ("inuse") +## @code{@var{retval} = license ("inuse")} +## ## Return a structure containing the fields @code{feature} and @code{user}. ## -## @deftypefnx {Function File} {@var{retval} =} license ("test", @var{feature}) +## @code{@var{retval} = license ("test", @var{feature})} +## ## Return 1 if a license exists for the product identified by the string ## @var{feature} and 0 otherwise. The argument @var{feature} is case ## insensitive and only the first 27 characters are checked. ## -## @deftypefnx {Function File} {} license ("test", @var{feature}, @var{toggle}) +## @code{license ("test", @var{feature}, @var{toggle})} +## ## Enable or disable license testing for @var{feature}, depending on ## @var{toggle}, which may be one of: ## @@ -44,7 +54,8 @@ ## Future tests for the specified license of @var{feature} return 0. ## @end table ## -## @deftypefnx {Function File} {@var{retval} =} license ("checkout", @var{feature}) +## @code{@var{retval} = license ("checkout", @var{feature})} +## ## Check out a license for @var{feature}, returning 1 on success and 0 ## on failure. ##
--- a/scripts/miscellaneous/private/__xzip__.m +++ b/scripts/miscellaneous/private/__xzip__.m @@ -62,9 +62,10 @@ files = glob (files); ## Ignore any file with the compress extension - files(cellfun (@(x) length (x) > length (extension) - && strcmp (x((end - length (extension) + 1):end), extension), - files)) = []; + files(cellfun (@(x) (length (x) > length (extension) + && strcmp (x((end - length (extension) + 1):end), + extension)), + files)) = []; copyfile (files, outdir);
--- a/scripts/miscellaneous/tar.m +++ b/scripts/miscellaneous/tar.m @@ -59,7 +59,7 @@ if (output(end) == "\n") output(end) = []; endif - entries = strsplit (output, "\n"); + entries = strsplit (output, "\n", false); entries = entries'; endif
--- a/scripts/miscellaneous/unpack.m +++ b/scripts/miscellaneous/unpack.m @@ -194,7 +194,7 @@ if (output(length (output)) == "\n") output(length (output)) = []; endif - files = parser (strsplit (output, "\n"))'; + files = parser (strsplit (output, "\n", false))'; ## Move files if necessary if (needmove)
--- a/scripts/miscellaneous/ver.m +++ b/scripts/miscellaneous/ver.m @@ -17,13 +17,18 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} ver () +## @deftypefn {Function File} {} ver () +## @deftypefnx {Function File} {v =} ver () +## @deftypefnx {Function File} {v =} ver ("Octave") +## @deftypefnx {Function File} {v =} ver (@var{package}) +## ## Display a header containing the current Octave version number, license -## string and operating system, followed by the installed package names, +## string, and operating system followed by a list of installed packages, ## versions, and installation directories. ## -## @deftypefnx {Function File} {v =} ver () -## Return a vector of structures, respecting Octave and each installed package. +## @code{v = ver ()} +## +## Return a vector of structures describing Octave and each installed package. ## The structure includes the following fields. ## ## @table @code @@ -37,13 +42,15 @@ ## Revision of the package. ## ## @item Date -## Date respecting the version/revision. +## Date of the version/revision. ## @end table ## -## @deftypefnx {Function File} {v =} ver ("Octave") +## @code{v = ver ("Octave")} +## ## Return version information for Octave only. ## -## @deftypefnx {Function File} {v =} ver (@var{package}) +## @code{v = ver (@var{package})} +## ## Return version information for @var{package}. ## ## @seealso{version, octave_config_info}
--- a/scripts/miscellaneous/what.m +++ b/scripts/miscellaneous/what.m @@ -32,7 +32,7 @@ d = pwd (); elseif (isempty (strfind (d, filesep ()))) ## Find the appropriate directory on the path. - p = strtrim (strsplit (path (), pathsep ())); + p = strtrim (strsplit (path (), pathsep (), false)); d = p{find (cellfun (@(x) ! isempty (strfind (x, d)), p))(end)}; else [status, msg, msgid] = fileattrib (d);
--- a/scripts/miscellaneous/zip.m +++ b/scripts/miscellaneous/zip.m @@ -62,7 +62,7 @@ if (entries(end) == "\n") entries(end) = []; endif - entries = strsplit (entries, "\n"); + entries = strsplit (entries, "\n", false); endif endfunction
--- a/scripts/pkg/pkg.m +++ b/scripts/pkg/pkg.m @@ -263,7 +263,7 @@ function [local_packages, global_packages] = pkg (varargin) ## Installation prefix (FIXME: what should these be on windows?) persistent user_prefix = false; - persistent prefix = -1; + persistent prefix = false; persistent archprefix = -1; persistent local_list = tilde_expand (fullfile ("~", ".octave_packages")); persistent global_list = fullfile (OCTAVE_HOME (), "share", "octave", @@ -277,7 +277,7 @@ ## FIXME: is it OK to set this always true on windows? global_install = ((ispc () && ! isunix ()) || (geteuid () == 0)); - if (prefix == -1) + if (isbool (prefix)) if (global_install) prefix = fullfile (OCTAVE_HOME (), "share", "octave", "packages"); archprefix = fullfile (octave_config_info ("libdir"),
--- a/scripts/pkg/private/configure_make.m +++ b/scripts/pkg/private/configure_make.m @@ -91,7 +91,7 @@ if (filenames(end) == "\n") filenames(end) = []; endif - filenames = strtrim (strsplit (filenames, "\n")); + filenames = strtrim (strsplit (filenames, "\n", false)); delete_idx = []; for i = 1:length (filenames) if (! all (isspace (filenames{i})))
--- a/scripts/pkg/private/fix_depends.m +++ b/scripts/pkg/private/fix_depends.m @@ -26,7 +26,7 @@ ## This function returns a cell of structures with the following fields: ## package, version, operator function deps_cell = fix_depends (depends) - deps = strtrim (strsplit (tolower (depends), ",")); + deps = strtrim (strsplit (tolower (depends), ",", false)); deps_cell = cell (1, length (deps)); ## For each dependency.
--- a/scripts/pkg/private/generate_lookfor_cache.m +++ b/scripts/pkg/private/generate_lookfor_cache.m @@ -23,7 +23,7 @@ ## @end deftypefn function generate_lookfor_cache (desc) - dirs = strtrim (strsplit (genpath (desc.dir), pathsep ())); + dirs = strtrim (strsplit (genpath (desc.dir), pathsep (), false)); for i = 1 : length (dirs) gen_doc_cache (fullfile (dirs{i}, "doc-cache"), dirs{i}); endfor
--- a/scripts/pkg/private/install.m +++ b/scripts/pkg/private/install.m @@ -181,7 +181,7 @@ ## Did we find any unsatisfied dependencies? if (! ok) - error ("the following dependencies where unsatisfied:\n %s", error_text); + error ("the following dependencies were unsatisfied:\n %s", error_text); endif endif
--- a/scripts/pkg/private/list_forge_packages.m +++ b/scripts/pkg/private/list_forge_packages.m @@ -25,7 +25,7 @@ function list = list_forge_packages () [list, succ] = urlread ("http://packages.octave.org/list_packages.php"); if (succ) - list = strsplit (list, " \n\t", true); + list = strsplit (list, " \n\t", true, "delimitertype", "legacy"); else error ("pkg: could not read URL, please verify internet connection"); endif
--- a/scripts/pkg/private/unload_packages.m +++ b/scripts/pkg/private/unload_packages.m @@ -35,7 +35,7 @@ endfor ## Get the current octave path. - p = strtrim (strsplit (path (), pathsep ())); + p = strtrim (strsplit (path (), pathsep (), false)); if (length (files) == 1 && strcmp (files{1}, "all")) ## Unload all.
--- a/scripts/pkg/private/write_index.m +++ b/scripts/pkg/private/write_index.m @@ -74,9 +74,9 @@ if (! isfield (desc, "categories")) error ("the DESCRIPTION file must have a Categories field, when no INDEX file is given"); endif - categories = strtrim (strsplit (desc.categories, ",")); + categories = strtrim (strsplit (desc.categories, ",", false)); if (length (categories) < 1) - error ("the Category field is empty"); + error ("the Category field is empty"); endif ## Write INDEX.
--- a/scripts/plot/daspect.m +++ b/scripts/plot/daspect.m @@ -17,23 +17,28 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} daspect (@var{data_aspect_ratio}) -## Set the data aspect ratio of the current axes. The aspect ratio is -## a normalized 3-element vector representing the span of the x, y, and -## z-axes limits. -## -## @deftypefnx {Function File} {@var{data_aspect_ratio} =} daspect ( ) -## Return the data aspect ratio of the current axes. -## +## @deftypefn {Function File} {@var{data_aspect_ratio} =} daspect () +## @deftypefnx {Function File} {} daspect (@var{data_aspect_ratio}) ## @deftypefnx {Function File} {} daspect (@var{mode}) -## Set the data aspect ratio mode of the current axes. +## @deftypefnx {Function File} {@var{data_aspect_ratio_mode} =} daspect ("mode") +## @deftypefnx {Function File} {} daspect (@var{hax}, @dots{}) +## Query or set the data aspect ratio of the current axes. The aspect +## ratio is a normalized 3-element vector representing the span of the x, y, +## and z-axis limits. +## +## @code{(daspect (@var{mode}))} ## -## @deftypefnx {Function File} {@var{data_aspect_ratio_mode} =} daspect ("mode") +## Set the data aspect ratio mode of the current axes. @var{mode} is +## either "auto" or "manual". +## +## @code{daspect ("mode")} +## ## Return the data aspect ratio mode of the current axes. +## +## @code{daspect (@var{hax}, @dots{})} ## -## @deftypefnx {Function File} {} daspect (@var{hax}, @dots{}) -## Use the axes, with handle @var{hax}, instead of the current axes. -## +## Operate on the axes in handle @var{hax} instead of the current axes. +## ## @seealso{axis, pbaspect, xlim, ylim, zlim} ## @end deftypefn
--- a/scripts/plot/fplot.m +++ b/scripts/plot/fplot.m @@ -42,26 +42,17 @@ ## Author: Paul Kienzle <pkienzle@users.sf.net> -function fplot (fn, limits, n, fmt) +function fplot (fn, limits, n = 0.002, fmt = "") + if (nargin < 2 || nargin > 4) print_usage (); endif - if (!isreal (limits) || (numel (limits) != 2 && numel (limits) != 4)) - error ("fplot: second input argument must be a real vector with 2 or 4 elements"); - endif - - if (nargin < 3) - n = 0.002; - endif - - have_linespec = true; - if (nargin < 4) - have_linespec = false; + if (iscomplex (limits) || (numel (limits) != 2 && numel (limits) != 4)) + error ("fplot: LIMITS must be a real vector with 2 or 4 elements"); endif if (ischar (n)) - have_linespec = true; fmt = n; n = 0.002; endif @@ -74,13 +65,13 @@ elseif (all (isalnum (fn))) nam = fn; elseif (ischar (fn)) - fn = vectorize (inline (fn)); - nam = formula (fn); + fn = vectorize (inline (fn)); + nam = formula (fn); else - error ("fplot: first input argument must be a function handle, inline function or string"); + error ("fplot: FN must be a function handle, inline function, or string"); endif - if (floor (n) != n) + if (n != fix (n)) tol = n; x0 = linspace (limits(1), limits(2), 5)'; y0 = feval (fn, x0); @@ -92,7 +83,7 @@ while (n < 2 .^ 20) y00 = interp1 (x0, y0, x, "linear"); err = 0.5 * max (abs ((y00 - y) ./ (y00 + y))(:)); - if (err == err0 || 0.5 * max (abs ((y00 - y) ./ (y00 + y))(:)) < tol) + if (err == err0 || err < tol) break; endif x0 = x; @@ -107,11 +98,7 @@ y = feval (fn, x); endif - if (have_linespec) - plot (x, y, fmt); - else - plot (x, y); - endif + plot (x, y, fmt); if (length (limits) > 2) axis (limits); @@ -125,6 +112,7 @@ endfor legend (nams{:}); endif + endfunction
--- a/scripts/plot/graphics_toolkit.m +++ b/scripts/plot/graphics_toolkit.m @@ -17,18 +17,28 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {@var{name} =} graphics_toolkit () +## @deftypefn {Function File} {@var{name} =} graphics_toolkit () +## @deftypefnx {Function File} {@var{name} =} graphics_toolkit (@var{hlist}) +## @deftypefnx {Function File} {} graphics_toolkit (@var{name}) +## @deftypefnx {Function File} {} graphics_toolkit (@var{hlist}, @var{name}) ## Return the default graphics toolkit. The default graphics toolkit value ## is assigned to new figures. -## @deftypefnx {Function File} {@var{name} =} graphics_toolkit (@var{hlist}) +## +## @code{graphics_toolkit (@var{hlist})} +## ## Return the graphics toolkits for the figures with handles @var{hlist}. -## @deftypefnx {Function File} {} graphics_toolkit (@var{name}) +## +## @code{graphics_toolkit (@var{name})} +## ## Set the default graphics toolkit to @var{name}. If the toolkit is not ## already loaded, it is initialized by calling the function ## @code{__init_@var{name}__}. -## @deftypefnx {Function File} {} graphics_toolkit (@var{hlist}, @var{name}) +## +## @code{graphics_toolkit (@var{hlist}, @var{name})} +## ## Set the graphics toolkit for the figures with handles @var{hlist} to ## @var{name}. +## ## @seealso{available_graphics_toolkits} ## @end deftypefn
--- a/scripts/plot/pbaspect.m +++ b/scripts/plot/pbaspect.m @@ -17,22 +17,28 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} pbaspect (@var{plot_box_aspect_ratio}) -## Set the plot box aspect ratio of the current axes. The aspect ratio -## is a normalized 3-element vector representing the rendered lengths of -## the x, y, and z-axes. +## @deftypefn {Function File} {@var{plot_box_aspect_ratio} =} pbaspect ( ) +## @deftypefnx {Function File} {} pbaspect (@var{plot_box_aspect_ratio}) +## @deftypefnx {Function File} {} pbaspect (@var{mode}) +## @deftypefnx {Function File} {@var{plot_box_aspect_ratio_mode} =} pbaspect ("mode") +## @deftypefnx {Function File} {} pbaspect (@var{hax}, @dots{}) ## -## @deftypefnx {Function File} {@var{plot_box_aspect_ratio} =} pbaspect ( ) -## Return the plot box aspect ratio of the current axes. +## Query or set the plot box aspect ratio of the current axes. The aspect +## ratio is a normalized 3-element vector representing the rendered lengths of +## the x, y, and z axes. +## +## @code{pbaspect(@var{mode})} ## -## @deftypefnx {Function File} {} pbaspect (@var{mode}) -## Set the plot box aspect ratio mode of the current axes. +## Set the plot box aspect ratio mode of the current axes. @var{mode} is +## either "auto" or "manual". ## -## @deftypefnx {Function File} {@var{plot_box_aspect_ratio_mode} =} pbaspect ("mode") +## @code{pbaspect ("mode")} +## ## Return the plot box aspect ratio mode of the current axes. ## -## @deftypefnx {Function File} {} pbaspect (@var{hax}, @dots{}) -## Use the axes, with handle @var{hax}, instead of the current axes. +## @code{pbaspect (@var{hax}, @dots{})} +## +## Operate on the axes in handle @var{hax} instead of the current axes. ## ## @seealso{axis, daspect, xlim, ylim, zlim} ## @end deftypefn
--- a/scripts/plot/private/__file_filter__.m +++ b/scripts/plot/private/__file_filter__.m @@ -81,7 +81,7 @@ endswitch if (isempty (name)) - extlist = strsplit (filterext, ";"); + extlist = strsplit (filterext, ";", false); extlist = strrep (extlist, "*.", ""); extlist = toupper (extlist); extlist(end+1, :) = repmat ({","}, 1, length (extlist));
--- a/scripts/plot/private/__fltk_file_filter__.m +++ b/scripts/plot/private/__fltk_file_filter__.m @@ -34,7 +34,7 @@ for idx = 1 : r curr_ext = file_filter{idx, 1}; - curr_ext = strsplit (curr_ext, ";"); + curr_ext = strsplit (curr_ext, ";", false); if (length (curr_ext) > 1) curr_ext = regexprep (curr_ext, '\*\.', ',');
--- a/scripts/plot/private/__go_draw_axes__.m +++ b/scripts/plot/private/__go_draw_axes__.m @@ -2229,7 +2229,7 @@ endif if (ischar (ticklabel)) if (rows (ticklabel) == 1 && any (ticklabel == "|")) - ticklabel = strsplit (ticklabel, "|"); + ticklabel = strsplit (ticklabel, "|", false); else ticklabel = cellstr (ticklabel); endif
--- a/scripts/plot/private/__next_line_style__.m +++ b/scripts/plot/private/__next_line_style__.m @@ -41,7 +41,7 @@ elseif (reset || isempty (style_rotation)) style_rotation = get (gca (), "linestyleorder"); if (ischar (style_rotation)) - style_rotation = strsplit (style_rotation, "|"); + style_rotation = strsplit (style_rotation, "|", false); endif num_styles = length (style_rotation); style_index = 1;
--- a/scripts/plot/private/__print_parse_opts__.m +++ b/scripts/plot/private/__print_parse_opts__.m @@ -159,7 +159,7 @@ elseif (length (arg) >= 1 && arg(1) == "-") error ("print: unknown option '%s'", arg); elseif (length (arg) > 0) - arg_st.name = arg; + arg_st.name = tilde_expand (arg); endif elseif (isfigure (arg)) arg_st.figure = arg;
--- a/scripts/plot/text.m +++ b/scripts/plot/text.m @@ -32,6 +32,9 @@ ## Author: jwe +## Note: The following code is rigged for Matlab compatibility and is +## full of hidden assumptions. Be very wary when modifying. + function h = text (varargin) nargs = nargin; @@ -40,7 +43,6 @@ if (nargs > 2 && isnumeric (varargin{1}) && isnumeric (varargin{2})) x = varargin{1}; y = varargin{2}; - offset = 3; if (nargin > 3 && isnumeric (varargin{3})) z = varargin{3}; @@ -56,72 +58,92 @@ nx = numel (x); ny = numel (y); nz = numel (z); - if (ischar (label) || isnumeric (label)) + if (ischar (label)) + + do_keyword_repl = true; nt = rows (label); - if (nx > 1 && nt == 1) - ## Mutiple text objects with same string - label = repmat ({label}, [nx, 1]); - nt = nx; + if (nx == 1 && nt == 1) + ## Single text object with one line + label = {label}; + elseif (nx == 1 && nt > 1) + ## Single text object with multiple lines + ## FIXME: "default" or "factory" as first row + ## should be escaped to "\default" or "\factory" + ## Other rows do not require escaping. + do_keyword_repl = false; + label = {label}; elseif (nx > 1 && nt == nx) ## Mutiple text objects with different strings label = cellstr (label); - elseif (ischar (label)) - ## Single text object with one or more lines - label = {label}; - endif - elseif (iscell (label)) - nt = numel (label); - if (nx > 1 && nt == 1) + else + ## Mutiple text objects with same string label = repmat ({label}, [nx, 1]); nt = nx; - elseif (! (nx > 1 && nt == nx)) + endif + + ## Escape special keywords + if (do_keyword_repl) + label = regexprep (label, '^(default|factory)$', '\\$1'); + endif + + elseif (iscell (label)) + + nt = numel (label); + if (nx == 1) + ## Single text object with one or more lines label = {label}; nt = 1; + elseif (nx > 1 && nt == nx) + ## Mutiple text objects with different strings + else + ## Mutiple text objects with same string + label = repmat ({label}, [nx, 1]); + nt = nx; endif + else - error ("text: expecting LABEL to be a character string or cell array of character strings"); + + error ("text: LABEL must be a character string or cell array of character strings"); + endif - else + else # Only PROP/VALUE pairs x = y = z = 0; nx = ny = nz = 1; label = {""}; nt = 1; endif - if (rem (numel (varargin), 2) == 0) + ## Any remaining inputs must occur as PROPERTY/VALUE pairs + if (rem (numel (varargin), 2) != 0) + print_usage (); + endif - if (nx == ny && nx == nz && (nt == nx || nt == 1 || nx == 1)) - pos = [x(:), y(:), z(:)]; - ca = gca (); - tmp = zeros (nt, 1); - if (nx == 1) - ## TODO - Modify __go_text__() to accept cell-strings - tmp = __go_text__ (ca, "string", "foobar", - varargin{:}, - "position", pos); - set (tmp, "string", label{1}); - elseif (nt == nx) - for n = 1:nt - tmp(n) = __go_text__ (ca, "string", label{n}, - varargin{:}, - "position", pos(n,:)); - endfor - __request_drawnow__ (); - else - error ("text: dimension mismatch for coordinates and LABEL"); - endif - elseif (nt == nx || nt == 1 || nx == 1) - error ("text: dimension mismatch for coordinates"); + if (nx == ny && nx == nz && (nt == nx || nt == 1 || nx == 1)) + pos = [x(:), y(:), z(:)]; + ca = gca (); + htmp = zeros (nt, 1); + if (nx == 1) + htmp = __go_text__ (ca, "string", label{1}, + varargin{:}, + "position", pos); + elseif (nx == nt) + for n = 1:nt + htmp(n) = __go_text__ (ca, "string", label{n}, + varargin{:}, + "position", pos(n,:)); + endfor + __request_drawnow__ (); else - error ("text: mismatch betwween coordinates and strings"); + error ("text: dimension mismatch for coordinates and LABEL"); endif + elseif (nt == nx || nt == 1 || nx == 1) + error ("text: dimension mismatch for coordinates"); + else + error ("text: dimension mismatch between coordinates and strings"); + endif - if (nargout > 0) - h = tmp; - endif - - else - print_usage (); + if (nargout > 0) + h = htmp; endif endfunction @@ -225,30 +247,70 @@ %!test %! hf = figure ("visible", "off"); %! unwind_protect -%! h = text (0.5, 0.3, "char"); -%! assert ("char", class (get (h, "string"))); +%! ## Single object with one line +%! h = text (0.5, 0.3, "single object with one line"); +%! obs = get (h, "string"); +%! assert (class (obs), "char"); +%! assert (obs, "single object with one line"); +%! +%! ## Single object with multiple lines %! h = text (0.5, 0.4, ["char row 1"; "char row 2"]); -%! assert ("char", class (get (h, "string"))); -%! h = text (0.5, 0.6, {"cell2str (1,1)", "cell2str (1,2)"; "cell2str (2,1)", "cell2str (2,2)"}); -%! assert ("cell", class (get (h, "string"))); -%! h = text (0.5, 0.8, "foobar"); -%! set (h, "string", 1:3); -%! h = text ([0.1, 0.1], [0.3, 0.4], "one string & two objects"); -%! assert ("char", class (get (h(1), "string"))); -%! assert ("char", class (get (h(2), "string"))); -%! h = text ([0.1, 0.1], [0.5, 0.6], {"one cellstr & two objects"}); -%! assert ("cell", class (get (h(1), "string"))); -%! assert ("cell", class (get (h(2), "string"))); -%! h = text ([0.1, 0.1], [0.7, 0.8], {"cellstr 1 object 1", "cellstr 2 object 2"}); -%! assert ("char", class (get (h(1), "string"))); -%! assert ("char", class (get (h(2), "string"))); -%! h = text ([0.1, 0.1], [0.1, 0.2], ["1st string & 1st object"; "2nd string & 2nd object"]); -%! assert ("char", class (get (h(1), "string"))); -%! assert ("char", class (get (h(2), "string"))); -%! h = text (0.7, 0.6, "single string"); -%! assert ("char", class (get (h, "string"))); -%! h = text (0.7, 0.5, {"single cell-string"}); -%! assert ("cell", class (get (h, "string"))); +%! obs = get (h, "string"); +%! assert (class (obs), "char"); +%! assert (obs, ["char row 1"; "char row 2"]); +%! +%! ## Multiple objects with single line +%! h = text ([0.1, 0.1], [0.3, 0.4], "two objects with same string"); +%! assert (class (get (h(1), "string")), "char"); +%! assert (class (get (h(2), "string")), "char"); +%! assert (get (h(1), "string"), "two objects with same string"); +%! assert (get (h(2), "string"), "two objects with same string"); +%! +%! ## Multiple objects with multiple lines +%! h = text ([0.1, 0.1], [0.3, 0.4], ["string1"; "string2"]); +%! assert (class (get (h(1), "string")), "char"); +%! assert (class (get (h(2), "string")), "char"); +%! assert (get (h(1), "string"), "string1"); +%! assert (get (h(2), "string"), "string2"); +%! +%! ### Tests repeated with cell input ### +%! +%! ## Single object with one line +%! h = text (0.5, 0.3, {"single object with one line"}); +%! obs = get (h, "string"); +%! assert (class (obs), "cell"); +%! assert (obs, {"single object with one line"}); +%! +%! ## Single object with multiple lines +%! h = text (0.5, 0.6, {"cell2str (1,1)", "cell2str (1,2)"; +%! "cell2str (2,1)", "cell2str (2,2)"}); +%! obs = get (h, "string"); +%! assert (class (obs), "cell"); +%! assert (obs, {"cell2str (1,1)"; "cell2str (2,1)"; +%! "cell2str (1,2)"; "cell2str (2,2)"}); +%! +%! ## Multiple objects with single line +%! h = text ([0.1, 0.1], [0.5, 0.6], {"two objects with same cellstr"}); +%! assert (class (get (h(1), "string")), "cell"); +%! assert (class (get (h(2), "string")), "cell"); +%! ## FIXME: is return value of cellstr, rather than string, Matlab-verified? +%! assert (get (h(1), "string"), {"two objects with same cellstr"}); +%! assert (get (h(2), "string"), {"two objects with same cellstr"}); +%! +%! ## Multiple objects with multiple lines +%! h = text ([0.1, 0.1], [0.7, 0.8], {"cellstr1", "cellstr2"}); +%! ## FIXME: is return value really char in Matlab? +%! assert (class (get (h(1), "string")), "char"); +%! assert (class (get (h(2), "string")), "char"); +%! assert (get (h(1), "string"), "cellstr1"); +%! assert (get (h(2), "string"), "cellstr2"); +%! +%! ## Test special keyword processing +%! h = text (0.5, 0.5, "default"); +%! assert (get (h, "string"), "default") +%! h = text (0.5, 0.5, "factory"); +%! assert (get (h, "string"), "factory") +%! %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect
--- a/scripts/plot/view.m +++ b/scripts/plot/view.m @@ -21,7 +21,8 @@ ## @deftypefnx {Function File} {} view (@var{azimuth}, @var{elevation}) ## @deftypefnx {Function File} {} view ([@var{azimuth} @var{elevation}]) ## @deftypefnx {Function File} {} view ([@var{x} @var{y} @var{z}]) -## @deftypefnx {Function File} {} view (@var{dims}) +## @deftypefnx {Function File} {} view (2) +## @deftypefnx {Function File} {} view (3) ## @deftypefnx {Function File} {} view (@var{ax}, @dots{}) ## Query or set the viewpoint for the current axes. The parameters ## @var{azimuth} and @var{elevation} can be given as two arguments or as
--- a/scripts/polynomial/polyval.m +++ b/scripts/polynomial/polyval.m @@ -19,19 +19,21 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} polyval (@var{p}, @var{x}) ## @deftypefnx {Function File} {@var{y} =} polyval (@var{p}, @var{x}, [], @var{mu}) +## @deftypefnx {Function File} {[@var{y}, @var{dy}] =} polyval (@var{p}, @var{x}, @var{s}) +## @deftypefnx {Function File} {[@var{y}, @var{dy}] =} polyval (@var{p}, @var{x}, @var{s}, @var{mu}) +## ## Evaluate the polynomial @var{p} at the specified values of @var{x}. When ## @var{mu} is present, evaluate the polynomial for ## (@var{x}-@var{mu}(1))/@var{mu}(2). ## If @var{x} is a vector or matrix, the polynomial is evaluated for each of ## the elements of @var{x}. ## -## @deftypefnx {Function File} {[@var{y}, @var{dy}] =} polyval (@var{p}, @var{x}, @var{s}) -## @deftypefnx {Function File} {[@var{y}, @var{dy}] =} polyval (@var{p}, @var{x}, @var{s}, @var{mu}) ## In addition to evaluating the polynomial, the second output ## represents the prediction interval, @var{y} +/- @var{dy}, which ## contains at least 50% of the future predictions. To calculate the ## prediction interval, the structured variable @var{s}, originating ## from @code{polyfit}, must be supplied. +## ## @seealso{polyvalm, polyaffine, polyfit, roots, poly} ## @end deftypefn
--- a/scripts/polynomial/splinefit.m +++ b/scripts/polynomial/splinefit.m @@ -17,26 +17,26 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {@var{pp} =} splinefit (@var{x}, @var{y}, @var{breaks}) +## @deftypefn {Function File} {@var{pp} =} splinefit (@var{x}, @var{y}, @var{breaks}) +## @deftypefnx {Function File} {@var{pp} =} splinefit (@var{x}, @var{y}, @var{p}) +## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "periodic", @var{periodic}) +## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "robust", @var{robust}) +## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "beta", @var{beta}) +## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "order", @var{order}) +## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "constraints", @var{constraints}) +## ## Fit a piecewise cubic spline with breaks (knots) @var{breaks} to the ## noisy data, @var{x} and @var{y}. @var{x} is a vector, and @var{y} -## a vector or N-D array. If @var{y} is an N-D array, then @var{x}(j) +## is a vector or N-D array. If @var{y} is an N-D array, then @var{x}(j) ## is matched to @var{y}(:,@dots{},:,j). ## ## The fitted spline is returned as a piecewise polynomial, @var{pp}, and ## may be evaluated using @code{ppval}. ## -## @deftypefnx {Function File} {@var{pp} =} splinefit (@var{x}, @var{y}, @var{p}) ## @var{p} is a positive integer defining the number of intervals along @var{x}, ## and @var{p}+1 is the number of breaks. The number of points in each interval ## differ by no more than 1. ## -## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "periodic", @var{periodic}) -## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "robust", @var{robust}) -## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "beta", @var{beta}) -## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "order", @var{order}) -## @deftypefnx {Function File} {@var{pp} =} splinefit (@dots{}, "constraints", @var{constraints}) -## ## The optional property @var{periodic} is a logical value which specifies ## whether a periodic boundary condition is applied to the spline. The ## length of the period is @code{max (@var{breaks}) - min (@var{breaks})}. @@ -67,7 +67,7 @@ ## Vector of the x-locations of the constraints. ## ## @item "yc" -## Constraining values at the locations, @var{xc}. +## Constraining values at the locations @var{xc}. ## The default is an array of zeros. ## ## @item "cc" @@ -92,6 +92,59 @@ ## @seealso{interp1, unmkpp, ppval, spline, pchip, ppder, ppint, ppjumps} ## @end deftypefn +function pp = splinefit (x, y, breaks, varargin) + if (nargin > 3) + n = cellfun (@ischar, varargin, "uniformoutput", true); + varargin(n) = lower (varargin(n)); + try + props = struct (varargin{:}); + catch + print_usage (); + end_try_catch + else + props = struct (); + endif + fields = fieldnames (props); + for f = 1:numel (fields) + if (! any (strcmp (fields{f}, + {"periodic", "robust", "beta", "order", "constraints"}))) + error ("splinefit:invalidproperty", + "unrecognized property '%s'", fields{f}); + endif + endfor + args = {}; + if (isfield (props, "periodic") && props.periodic) + args{end+1} = "p"; + endif + if (isfield (props, "robust") && props.robust) + args{end+1} = "r"; + endif + if (isfield (props, "beta")) + if (0 < props.beta && props.beta < 1) + args{end+1} = props.beta; + else + error ("splinefit:invalidbeta", "invalid beta parameter (0 < beta < 1)"); + endif + endif + if (isfield (props, "order")) + if (props.order >= 0) + args{end+1} = props.order + 1; + else + error ("splinefit:invalidorder", "invalid order"); + endif + endif + if (isfield (props, "constraints")) + args{end+1} = props.constraints; + endif + if (nargin < 3) + print_usage (); + elseif (! isnumeric (breaks) || ! isvector (breaks)) + print_usage (); + endif + pp = __splinefit__ (x, y, breaks, args{:}); +endfunction + + %!demo %! % Noisy data %! x = linspace (0, 2*pi, 100); @@ -169,59 +222,6 @@ %! axis tight %! ylim auto -function pp = splinefit (x, y, breaks, varargin) - if (nargin > 3) - n = cellfun (@ischar, varargin, "uniformoutput", true); - varargin(n) = lower (varargin(n)); - try - props = struct (varargin{:}); - catch - print_usage (); - end_try_catch - else - props = struct (); - endif - fields = fieldnames (props); - for f = 1:numel (fields) - if (! any (strcmp (fields{f}, - {"periodic", "robust", "beta", "order", "constraints"}))) - error ("splinefit:invalidproperty", - "unrecognized property '%s'", fields{f}); - endif - endfor - args = {}; - if (isfield (props, "periodic") && props.periodic) - args{end+1} = "p"; - endif - if (isfield (props, "robust") && props.robust) - args{end+1} = "r"; - endif - if (isfield (props, "beta")) - if (0 < props.beta && props.beta < 1) - args{end+1} = props.beta; - else - error ("splinefit:invalidbeta", "invalid beta parameter (0 < beta < 1)"); - endif - endif - if (isfield (props, "order")) - if (props.order >= 0) - args{end+1} = props.order + 1; - else - error ("splinefit:invalidorder", "invalid order"); - endif - endif - if (isfield (props, "constraints")) - args{end+1} = props.constraints; - endif - if (nargin < 3) - print_usage (); - elseif (! isnumeric (breaks) || ! isvector (breaks)) - print_usage (); - endif - pp = __splinefit__ (x, y, breaks, args{:}); -endfunction - - %!shared xb, yb, x %! xb = 0:2:10; %! yb = 2*rand (size (xb)) - 1;
--- a/scripts/set/union.m +++ b/scripts/set/union.m @@ -20,8 +20,10 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} union (@var{a}, @var{b}) ## @deftypefnx {Function File} {} union (@var{a}, @var{b}, "rows") +## @deftypefnx {Function File} {[@var{c}, @var{ia}, @var{ib}] =} union (@var{a}, @var{b}) +## ## Return the set of elements that are in either of the sets @var{a} and -## @var{b}. @var{a}, @var{b} may be cell arrays of string(s). +## @var{b}. @var{a}, @var{b} may be cell arrays of strings. ## For example: ## ## @example @@ -31,8 +33,8 @@ ## @end group ## @end example ## -## If the optional third input argument is the string "rows" each row of -## the matrices @var{a} and @var{b} will be considered an element of sets. +## If the optional third input argument is the string "rows" then each row of +## the matrices @var{a} and @var{b} will be considered as a single set element. ## For example: ## ## @example @@ -44,10 +46,8 @@ ## @end group ## @end example ## -## @deftypefnx {Function File} {[@var{c}, @var{ia}, @var{ib}] =} union (@var{a}, @var{b}) -## -## Return index vectors @var{ia} and @var{ib} such that @code{a(ia)} and -## @code{b(ib)} are disjoint sets whose union is @var{c}. +## The optional outputs @var{ia} and @var{ib} are index vectors such that +## @code{a(ia)} and @code{b(ib)} are disjoint sets whose union is @var{c}. ## ## @seealso{intersect, setdiff, unique} ## @end deftypefn
--- a/scripts/signal/fftfilt.m +++ b/scripts/signal/fftfilt.m @@ -94,53 +94,91 @@ endif y = y(1:r_x, :); - if (transpose) - y = y.'; + + ## Final cleanups: + + ## - If both b and x are real, y should be real. + ## - If b is real and x is imaginary, y should be imaginary. + ## - If b is imaginary and x is real, y should be imaginary. + ## - If both b and x are imaginary, y should be real. + xisreal = all (imag (x) == 0); + xisimag = all (real (x) == 0); + + if (all (imag (b) == 0)) + y (:,xisreal) = real (y (:,xisreal)); + y (:,xisimag) = complex (real (y (:,xisimag)) * 0, imag (y (:,xisimag))); + elseif (all (real (b) == 0)) + y (:,xisreal) = complex (real (y (:,xisreal)) * 0, imag (y (:,xisreal))); + y (:,xisimag) = real (y (:,xisimag)); endif - ## Final cleanups: If both x and b are real, y should be real. - ## If both x and b are integer, y should be integer. + ## - If both x and b are integer in both real and imaginary + ## components, y should be integer. + if (! any (b - fix (b))) + idx = find (! any (x - fix (x))); + y (:, idx) = round (y (:, idx)); + endif - if (isreal (b) && isreal (x)) - y = real (y); - endif - if (! any (b - fix (b))) - idx = !any (x - fix (x)); - y(:, idx) = round (y(:, idx)); + ## Transpose after cleanup, otherwise rounding fails. + if (transpose) + y = y.'; endif endfunction %!shared b, x, r + %!test %! b = [1 1]; %! x = [1, zeros(1,9)]; -%! assert (fftfilt (b, x ), [1 1 0 0 0 0 0 0 0 0] , eps); -%! assert (fftfilt (b, x.'), [1 1 0 0 0 0 0 0 0 0].', eps); -%! assert (fftfilt (b.',x ), [1 1 0 0 0 0 0 0 0 0] , eps); -%! assert (fftfilt (b.',x.'), [1 1 0 0 0 0 0 0 0 0].', eps); +%! assert (fftfilt (b, x ), [1 1 0 0 0 0 0 0 0 0] ); +%! assert (fftfilt (b, x.'), [1 1 0 0 0 0 0 0 0 0].'); +%! assert (fftfilt (b.',x ), [1 1 0 0 0 0 0 0 0 0] ); +%! assert (fftfilt (b.',x.'), [1 1 0 0 0 0 0 0 0 0].'); +%! assert (fftfilt (b, [x.' x.']), [1 1 0 0 0 0 0 0 0 0].'*[1 1]); +%! assert (fftfilt (b, [x.'+eps x.']) == [1 1 0 0 0 0 0 0 0 0].'*[1 1], [false(10, 1) true(10, 1)]); %!test %! r = sqrt (1/2) * (1+i); %! b = b*r; -%! assert (fftfilt (b, x ), r*[1 1 0 0 0 0 0 0 0 0] , eps); -%! assert (fftfilt (b, r*x), r*r*[1 1 0 0 0 0 0 0 0 0], eps); -%! assert (fftfilt (b, x.'), r*[1 1 0 0 0 0 0 0 0 0].', eps); +%! assert (fftfilt (b, x ), r*[1 1 0 0 0 0 0 0 0 0] , eps ); +%! assert (fftfilt (b, r*x), r*r*[1 1 0 0 0 0 0 0 0 0], 2*eps); +%! assert (fftfilt (b, x.'), r*[1 1 0 0 0 0 0 0 0 0].', eps ); %!test -%! b = [1 1]; -%! x = zeros (10,3); x(1,1)=-1; x(1,2)=1; +%! b = [1 1]; +%! x = zeros (10,3); x(1,1)=-1; x(1,2)=1; %! y0 = zeros (10,3); y0(1:2,1)=-1; y0(1:2,2)=1; -%! y = fftfilt (b, x); -%! assert (y,y0); +%! y = fftfilt (b, x); +%! assert (y0, y); +%! y = fftfilt (b*i, x); +%! assert (y0*i, y); +%! y = fftfilt (b, x*i); +%! assert (y0*i, y); +%! y = fftfilt (b*i, x*i); +%! assert (-y0, y); +%! x = rand (10, 1); +%! y = fftfilt (b, [x x*i]); +%! assert (true, isreal (y(:,1))); +%! assert (false, any (real (y(:,2)))); %!test %! b = rand (10, 1); %! x = rand (10, 1); %! y0 = filter (b, 1, x); -%! y = filter (b, 1, x); -%! assert (y, y0); +%! y = fftfilt (b, x); +%! assert (y0, y, 16*eps); +%! y0 = filter (b*i, 1, x*i); +%! y = fftfilt (b*i, x*i); +%! assert (y0, y, 16*eps); + +%!test +%! b = rand (10, 1) + i*rand (10, 1); +%! x = rand (10, 1) + i*rand (10, 1); +%! y0 = filter (b, 1, x); +%! y = fftfilt (b, x); +%! assert (y0, y, 55*eps); %% Test input validation %!error fftfilt (1)
--- a/scripts/signal/freqz.m +++ b/scripts/signal/freqz.m @@ -17,7 +17,11 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {[@var{h}, @var{w}] =} freqz (@var{b}, @var{a}, @var{n}, "whole") +## @deftypefn {Function File} {[@var{h}, @var{w}] =} freqz (@var{b}, @var{a}, @var{n}, "whole") +## @deftypefnx {Function File} {@var{h} =} freqz (@var{b}, @var{a}, @var{w}) +## @deftypefnx {Function File} {[@dots{}] =} freqz (@dots{}, @var{Fs}) +## @deftypefnx {Function File} {} freqz (@dots{}) +## ## Return the complex frequency response @var{h} of the rational IIR filter ## whose numerator and denominator coefficients are @var{b} and @var{a}, ## respectively. The response is evaluated at @var{n} angular frequencies @@ -32,7 +36,15 @@ ## @noindent ## The output value @var{w} is a vector of the frequencies. ## -## If the fourth argument is omitted, the response is evaluated at +## If @var{a} is omitted, the denominator is assumed to be 1 (this +## corresponds to a simple FIR filter). +## +## If @var{n} is omitted, a value of 512 is assumed. +## +## For fastest computation, @var{n} should factor into a small number of +## small primes. +## +## If the fourth argument, "whole", is omitted the response is evaluated at ## frequencies between 0 and ## @ifnottex ## pi. @@ -41,24 +53,19 @@ ## $\pi$. ## @end tex ## -## If @var{n} is omitted, a value of 512 is assumed. -## -## If @var{a} is omitted, the denominator is assumed to be 1 (this -## corresponds to a simple FIR filter). +## @code{freqz (@var{b}, @var{a}, @var{w})} ## -## For fastest computation, @var{n} should factor into a small number of -## small primes. -## -## @deftypefnx {Function File} {@var{h} =} freqz (@var{b}, @var{a}, @var{w}) ## Evaluate the response at the specific frequencies in the vector @var{w}. ## The values for @var{w} are measured in radians. ## -## @deftypefnx {Function File} {[@dots{}] =} freqz (@dots{}, @var{Fs}) +## @code{[@dots{}] = freqz (@dots{}, @var{Fs})} +## ## Return frequencies in Hz instead of radians assuming a sampling rate ## @var{Fs}. If you are evaluating the response at specific frequencies ## @var{w}, those frequencies should be requested in Hz rather than radians. ## -## @deftypefnx {Function File} {} freqz (@dots{}) +## @code{freqz (@dots{})} +## ## Plot the pass band, stop band and phase response of @var{h} rather ## than returning them. ## @end deftypefn
--- a/scripts/sparse/svds.m +++ b/scripts/sparse/svds.m @@ -103,7 +103,7 @@ endif if (nargin < 4) - opts.tol = 1e-10 / root2; + opts.tol = 0; ## use ARPACK default opts.disp = 0; opts.maxit = 300; else @@ -111,7 +111,7 @@ error ("svds: OPTS must be a structure"); endif if (!isfield (opts, "tol")) - opts.tol = 1e-10 / root2; + opts.tol = 0; ## use ARPACK default else opts.tol = opts.tol / root2; endif @@ -152,7 +152,6 @@ b_opts = opts; ## Call to eigs is always a symmetric matrix by construction b_opts.issym = true; - b_opts.tol = opts.tol / max_a; b_sigma = sigma; if (!ischar (b_sigma)) b_sigma = b_sigma / max_a; @@ -235,14 +234,14 @@ endif if (nargout > 3) - flag = norm (A*v - u*s, 1) > root2 * opts.tol * norm (A, 1); + flag = (flag != 0); endif endif endfunction -%!shared n, k, A, u, s, v, opts, rand_state, randn_state +%!shared n, k, A, u, s, v, opts, rand_state, randn_state, tol %! n = 100; %! k = 7; %! A = sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),0.4*n*ones(1,n),ones(1,n-2)]); @@ -263,13 +262,15 @@ %! [u2,s2,v2,flag] = svds (A,k); %! s2 = diag (s2); %! assert (flag, !1); -%! assert (s2, s(end:-1:end-k+1), 1e-10); +%! tol = 10 * eps() * norm(s2, 1); +%! assert (s2, s(end:-1:end-k+1), tol); %! %!testif HAVE_ARPACK, HAVE_UMFPACK %! [u2,s2,v2,flag] = svds (A,k,0,opts); %! s2 = diag (s2); %! assert (flag, !1); -%! assert (s2, s(k:-1:1), 1e-10); +%! tol = 10 * eps() * norm(s2, 1); +%! assert (s2, s(k:-1:1), tol); %! %!testif HAVE_ARPACK, HAVE_UMFPACK %! idx = floor (n/2); @@ -278,7 +279,8 @@ %! [u2,s2,v2,flag] = svds (A,k,sigma,opts); %! s2 = diag (s2); %! assert (flag, !1); -%! assert (s2, s((idx+floor(k/2)):-1:(idx-floor(k/2))), 1e-10); +%! tol = 10 * eps() * norm(s2, 1); +%! assert (s2, s((idx+floor(k/2)):-1:(idx-floor(k/2))), tol); %! %!testif HAVE_ARPACK %! [u2,s2,v2,flag] = svds (zeros (10), k);
--- a/scripts/strings/module.mk +++ b/scripts/strings/module.mk @@ -21,6 +21,7 @@ strings/strcat.m \ strings/cstrcat.m \ strings/strchr.m \ + strings/strjoin.m \ strings/strjust.m \ strings/strmatch.m \ strings/strtok.m \
new file mode 100644 --- /dev/null +++ b/scripts/strings/strjoin.m @@ -0,0 +1,84 @@ +## Copyright (C) 2007 Muthiah Annamalai <muthiah.annamalai@uta.edu> +## Copyright (C) 2013 Ben Abbott <bpabbott@mac.com> +## +## This file is part of Octave. +## +## Octave 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 3 of the License, or (at +## your option) any later version. +## +## Octave 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} {@var{str} =} strjoin (@var{cstr}) +## @deftypefnx {Function File} {@var{str} =} strjoin (@var{cstr}, @var{delimiter}) +## Joins the elements of the cell-string array, @var{cstr}, into a single +## string. +## +## If no @var{delimiter} is specified, the elements of @var{cstr} +## seperated by a space. +## +## If @var{delimiter} is specified as a string, the cell-string array is +## joined using the string. +## +## If @var{delimiter} is a cell-string array whose length is one less +## than @var{cstr}, then the elemennts of @var{cstr} are joined by +## interleaving the cell-string elements of @var{delimiter}. +## +## @example +## @group +## strjoin (@{'Octave','Scilab','Lush','Yorick'@}, '*') +## @result{} 'Octave*Scilab*Lush*Yorick' +## @end group +## @end example +## @seealso {strsplit} +## @end deftypefn + +function rval = strjoin (cstr, delimiter) + + if (nargin == 1) + delimiter = " "; + elseif (nargin < 1 || nargin > 2) + print_usage (); + elseif (! (iscellstr (cstr) && (ischar (delimiter) || iscellstr (delimiter)))) + print_usage (); + endif + + if (numel (cstr) == 1) + rval = cstr{1}; + return + endif + + if (ischar (delimiter)) + delimiter = {delimiter}; + end + + num = numel (cstr); + if (numel (delimiter) == 1 && num > 1) + delimiter = repmat (delimiter, 1, num); + delimiter(end) = {""}; + elseif (numel (delimiter) != num - 1) + error ("strjoin:cellstring_delimiter_mismatch", + "strjoin: the number of delimiters does not match the number of strings") + else + delimiter(end+1) = {""}; + endif + + rval = sprintf ("%s", [cstr(:).'; delimiter(:).']{:}); + +endfunction + +%!assert (strjoin ({"hello"}, "-"), "hello") +%!assert (strjoin ({"hello", "world"}), "hello world") +%!assert (strjoin ({"Octave", "Scilab", "Lush", "Yorick"}, "*"), +%! "Octave*Scilab*Lush*Yorick") +%!assert (strjoin ({"space", "comma", "dash", "semicolon", "done"}, +%! {" ", ",", "-", ";"}), "space comma,dash-semicolon;done")
--- a/scripts/strings/strsplit.m +++ b/scripts/strings/strsplit.m @@ -17,20 +17,33 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {[@var{cstr}] =} strsplit (@var{s}, @var{sep}) -## @deftypefnx {Function File} {[@var{cstr}] =} strsplit (@var{s}, @var{sep}, @var{strip_empty}) -## Split the string @var{s} using one or more separators @var{sep} and return -## a cell array of strings. Consecutive separators and separators at -## boundaries result in empty strings, unless @var{strip_empty} is true. -## The default value of @var{strip_empty} is false. +## @deftypefn {Function File} {[@var{cstr}] =} strsplit (@var{s}) +## @deftypefnx {Function File} {[@var{cstr}] =} strsplit (@var{s}, @var{del}) +## @deftypefnx {Function File} {[@var{cstr}] =} strsplit (@var{s}, @var{del}, @var{collapsedelimiters}) +## @deftypefnx {Function File} {[@var{cstr}] =} strsplit (@dots{}, @var{name}, @var{value}) +## @deftypefnx {Function File} {[@var{cstr}, @var{matches}] =} strsplit (@dots{}) +## Split the string @var{s} using the delimiters specified by @var{del} +## and return a cell array of strings. For a single delimiter, @var{del} +## may be a string, or a scalar cell-string. For multible delimiters, +## @var{del} must be a cell-string array. Unless @var{collapsedelimiters} is +## specified to be @var{false}, consecutive delimiters are collapsed into one. ## -## 2-D character arrays are split at separators and at the original column -## boundaries. +## The second output, @var{matches}, returns the delmiters which were matched +## in the original string. The matched delimiters are uneffected by the +## @var{collapsedelimiters}. ## ## Example: ## ## @example ## @group +## strsplit ("a b c") +## @result{} +## @{ +## [1,1] = a +## [1,2] = b +## [1,3] = c +## @} +## ## strsplit ("a,b,c", ",") ## @result{} ## @{ @@ -39,80 +52,306 @@ ## [1,3] = c ## @} ## -## strsplit (["a,b" ; "cde"], ",") +## strsplit ("a foo b,bar c", @{"\s", "foo", "bar"@}) +## @result{} +## @{ +## [1,1] = a +## [1,2] = b +## [1,3] = c +## @} +## +## strsplit ("a,,b, c", @{",", " "@}, false) +## @result{} +## @{ +## [1,1] = a +## [1,2] = +## [1,3] = b +## [1,4] = +## [1,5] = c +## @} +## +## @end group +## @end example +## +## Supported @var{name}/@var{value} pair arguments are; +## +## @itemize +## @item @var{collapsedelimiters} may take the value of @var{true} or @var{false} +## with the default being @var{false}. +## @item @var{delimitertype} may take the value of @code{legacy}, +## @code{simple} or @code{regularexpression}. +## If @var{delimitertype} is equal to @code{legacy}, each individual +## character of @var{del} is used to split the input. +## If the specified delimiters are single characters, the default is +## @var{delimitertype} is @code{legacy}. Otherwise the default +## @var{delimitertype} is @code{simple}. +## @end itemize +## +## Example: +## +## @example +## @group +## strsplit ("a foo b,bar c", ",|\\s|foo|bar", "delimitertype", "regularexpression") +## @result{} +## @{ +## [1,1] = a +## [1,2] = b +## [1,3] = c +## @} +## +## strsplit ("a,,b, c", "[, ]", false, "delimitertype", "regularexpression") +## @result{} +## @{ +## [1,1] = a +## [1,2] = +## [1,3] = b +## [1,4] = +## [1,5] = c +## @} +## +## strsplit ("a,,b, c", ", ", false, "delimitertype", "legacy") +## @result{} +## @{ +## [1,1] = a +## [1,2] = +## [1,3] = b +## [1,4] = +## [1,5] = c +## @} +## +## strsplit ("a,\t,b, c", @{',', '\s'@}, "delimitertype", "regularexpression") ## @result{} ## @{ ## [1,1] = a ## [1,2] = b -## [1,3] = cde +## [1,3] = c ## @} ## @end group ## @end example -## @seealso{strtok} +## +## @seealso{strjoin, strtok, regexp} ## @end deftypefn -function cstr = strsplit (s, sep, strip_empty = false) +function [result, matches] = strsplit (str, del, varargin) - if (nargin < 2 || nargin > 3) + args.collapsedelimiters = true; + args.delimitertype = "default"; + + [reg, params] = parseparams (varargin); + + if (numel (reg) > 1) print_usage (); - elseif (! ischar (s) || ! ischar (sep)) - error ("strsplit: S and SEP must be string values"); - elseif (! isscalar (strip_empty)) - error ("strsplit: STRIP_EMPTY must be a scalar value"); + elseif (numel (reg) == 1) + if (islogical (reg{1}) || isnumeric (reg{1})) + args.collapsedelimiters = reg{1}; + else + print_usage (); + endif + endif + fields = fieldnames (args); + for n = 1:2:numel(params) + if (any (strcmpi (params{n}, fields))) + args.(lower(params{n})) = params{n+1}; + elseif (ischar (varargin{n})) + error ("strsplit:invalid_parameter_name", + sprintf ("strsplit: Invalid parameter name, `%s'", varargin{n})) + else + print_usage (); + endif + endfor + + if (strcmpi (args.delimitertype, "default")) + if (nargin == 1 || numel (del) == 1 + || (nargin > 1 && (islogical (del) || isnumeric (del))) + || iscell (del) && all (cellfun (@numel, del) < 2)) + ## For single character delimiters, default to "legacy" + args.delimitertype = "legacy"; + else + ## For multi-character delimiters, default to "simple" + args.delimitertype = "simple"; + endif endif - if (isempty (s)) - cstr = cell (size (s)); - else - if (rows (s) > 1) - ## For 2-D arrays, add separator character at line boundaries - ## and transform to single string - s(:, end+1) = sep(1); - s = reshape (s.', 1, numel (s)); - s(end) = []; + # Save the length of the "delimitertype" parameter + length_deltype = numel (args.delimitertype); + + if (nargin == 1 || (nargin > 1 && (islogical (del) || isnumeric (del)))) + if (nargin > 1) + ## Second input is the "collapsedelimiters" parameter + args.collapsedelimiters = del; + endif + ## Set proper default for the delimiter type + if (strncmpi (args.delimitertype, "simple", numel (args.delimitertype))) + del = {" ","\f","\n","\r","\t","\v"}; + elseif (strncmpi (args.delimitertype, "legacy", numel (args.delimitertype))) + del = " \f\n\r\t\v"; + else + del = "\\s"; endif + endif + if (nargin < 1) + print_usage (); + elseif (! ischar (str) || (! ischar (del) && ! iscellstr (del))) + error ("strsplit: S and DEL must be string values"); + elseif (! isscalar (args.collapsedelimiters)) + error ("strsplit: COLLAPSEDELIMITERS must be a scalar value"); + endif + + if (strncmpi (args.delimitertype, "simple", length_deltype)) + if (iscellstr (del)) + del = cellfun (@(x) regexp2simple (x, false), del, "uniformoutput", + false); + else + del = regexp2simple (del, false); + endif + endif + + if (rows (str) > 1) + tmp = char (del(1)); + str = [str, repmat(tmp,rows(str),1)]; + str = reshape (str.', 1, numel (str)); + str(end-numel(tmp)+1:end) = []; + endif + + if (isempty (str)) + result = {str}; + elseif (strncmpi (args.delimitertype, "legacy", length_deltype)) + ## Conventional splitting is preserved for its speed. Its delimiter type + ## + if (! ischar (del)) + if (iscell (del) && all (cellfun (@numel, del) < 2)) + del = [del{:}]; + else + error ("strsplit:legacy_delimiter_must_be_char", + "%s %s", "strsplit: for DELIMITERTYPE = ""legacy"" ", + "DEL must be a string, or a cell array scalar character elements.") + endif + endif ## Split s according to delimiter - if (isscalar (sep)) + if (isscalar (del)) ## Single separator - idx = find (s == sep); + idx = find (str == del); else ## Multiple separators - idx = strchr (s, sep); + idx = strchr (str, del); endif ## Get substring lengths. if (isempty (idx)) - strlens = length (s); + strlens = length (str); else - strlens = [idx(1)-1, diff(idx)-1, numel(s)-idx(end)]; + strlens = [idx(1)-1, diff(idx)-1, numel(str)-idx(end)]; + endif + if (nargout > 1) + ## Grab the separators + matches = num2cell (str(idx)(:)).'; endif ## Remove separators. - s(idx) = []; - if (strip_empty) + str(idx) = []; + if (args.collapsedelimiters) ## Omit zero lengths. strlens = strlens(strlens != 0); endif ## Convert! - cstr = mat2cell (s, 1, strlens); + result = mat2cell (str, 1, strlens); + elseif (strncmpi (args.delimitertype, "regularexpression", length_deltype) + || strncmpi (args.delimitertype, "simple", length_deltype)) + if (iscellstr (del)) + del = sprintf ('%s|', del{:}); + del(end) = []; + endif + [result, ~, ~, ~, matches] = regexp (str, del, "split"); + if (args.collapsedelimiters) + result(cellfun (@isempty, result)) = []; + endif + if (strncmpi (args.delimitertype, "simple", length_deltype)) + matches = cellfun (@(x) regexp2simple (x, true), matches, + "uniformoutput", false); + endif + else + error ("strsplit:invalid_delimitertype", + sprintf ("strsplit: Invalid DELIMITERTYPE")) endif +endfunction +function str = regexp2simple (str, reverse = false) + rep = {'\', '[', ']', '{', '}', '$', '^', '(', ')', '*', '+', '.', '?', '|'}; + if (reverse) + ## backslash must go last + for r = numel(rep):-1:1 + str = strrep (str, [char(92), rep{r}], rep{r}); + endfor + else + ## backslash must go first + for r = 1:numel(rep) + str = strrep (str, rep{r}, [char(92), rep{r}]); + endfor + endif endfunction +% Mimic the old strsplit() +%!assert (cellfun (@numel, strsplit (["a,b,c";"1,2 "], ",")), [1 1 2 1 4]) +%!shared str +%! str = "The rain in Spain stays mainly in the plain."; +% Split on all whitespace. +%!assert (strsplit (str), {"The", "rain", "in", "Spain", "stays", ... +%! "mainly", "in", "the", "plain."}) +% Split on "ain". +%!assert (strsplit (str, "ain"), {"The r", " in Sp", " stays m", ... +%! "ly in the pl", "."}) +% Split on " " and "ain" (treating multiple delimiters as one). +%!test +%! s = strsplit (str, '\s|ain', true, "delimitertype", "r"); +%! assert (s, {"The", "r", "in", "Sp", "stays", "m", "ly", "in", "the", "pl", "."}) +%!test +%! s = strsplit (str, "\\s|ain", true, "delimitertype", "r"); +%! assert (s, {"The", "r", "in", "Sp", "stays", "m", "ly", "in", "the", "pl", "."}) +%!test +%! [s, m] = strsplit (str, {"\\s", "ain"}, true, "delimitertype", "r"); +%! assert (s, {"The", "r", "in", "Sp", "stays", "m", "ly", "in", "the", "pl", "."}) +%! assert (m, {" ", "ain", " ", " ", "ain", " ", " ", "ain", " ", " ", " ", "ain"}) +% Split on " " and "ain", and treat multiple delimiters separately. +%!test +%! [s, m] = strsplit (str, {" ", "ain"}, "collapsedelimiters", false); +%! assert (s, {"The", "r", "", "in", "Sp", "", "stays", "m", "ly", "in", "the", "pl", "."}) +%! assert (m, {" ", "ain", " ", " ", "ain", " ", " ", "ain", " ", " ", " ", "ain"}) + +%!assert (strsplit ("road to hell"), {"road", "to", "hell"}) %!assert (strsplit ("road to hell", " "), {"road", "to", "hell"}) -%!assert (strsplit ("road to^hell", " ^"), {"road", "to", "hell"}) -%!assert (strsplit ("road to--hell", " -", true), {"road", "to", "hell"}) -%!assert (strsplit (["a,bc";",de"], ","), {"a", "bc", char(ones(1,0)), "de "}) -%!assert (strsplit (["a,bc";",de"], ",", true), {"a", "bc", "de "}) -%!assert (strsplit (["a,bc";",de"], ", ", true), {"a", "bc", "de"}) +%!assert (strsplit ("road to^hell", {" ","^"}), {"road", "to", "hell"}) +%!assert (strsplit ("road to--hell", {" ","-"}, true), {"road", "to", "hell"}) +%!assert (strsplit (["a,bc,,de"], ",", false, "delimitertype", "s"), {"a", "bc", "", "de"}) +%!assert (strsplit (["a,bc,,de"], ",", false), {"a", "bc", char(ones(1,0)), "de"}) +%!assert (strsplit (["a,bc,de"], ",", true), {"a", "bc", "de"}) +%!assert (strsplit (["a,bc,de"], {","," "}, true), {"a", "bc", "de"}) +%!test +%! [s, m] = strsplit ("hello \t world", 1); +%! assert (s, {"hello", "world"}); +%! assert (m, {" ", "\t", " "}); + +%!assert (strsplit ("road to hell", " ", "delimitertype", "r"), {"road", "to", "hell"}) +%!assert (strsplit ("road to^hell", '\^| ', "delimitertype", "r"), {"road", "to", "hell"}) +%!assert (strsplit ("road to^hell", "[ ^]", "delimitertype", "r"), {"road", "to", "hell"}) +%!assert (strsplit ("road to--hell", "[ -]", false, "delimitertype", "r"), {"road", "", "", "to", "", "hell"}) +%!assert (strsplit (["a,bc,de"], ",", "delimitertype", "r"), {"a", "bc", "de"}) +%!assert (strsplit (["a,bc,,de"], ",", false, "delimitertype", "r"), {"a", "bc", "", "de"}) +%!assert (strsplit (["a,bc,de"], ",", true, "delimitertype", "r"), {"a", "bc", "de"}) +%!assert (strsplit (["a,bc,de"], "[, ]", true, "delimitertype", "r"), {"a", "bc", "de"}) +%!assert (strsplit ("hello \t world", 1, "delimitertype", "r"), {"hello", "world"}); + +%!assert (strsplit ("road to hell", " ", false, "delimitertype", "l"), {"road", "to", "hell"}) +%!assert (strsplit ("road to^hell", " ^", false, "delimitertype", "l"), {"road", "to", "hell"}) +%!assert (strsplit ("road to--hell", " -", true, "delimitertype", "l"), {"road", "to", "hell"}) +%!assert (strsplit (["a,bc";",de"], ",", false, "delimitertype", "l"), {"a", "bc", char(ones(1,0)), "de "}) +%!assert (strsplit (["a,bc";",de"], ",", true, "delimitertype", "l"), {"a", "bc", "de "}) +%!assert (strsplit (["a,bc";",de"], ", ", true, "delimitertype", "l"), {"a", "bc", "de"}) %% Test input validation %!error strsplit () -%!error strsplit ("abc") %!error strsplit ("abc", "b", true, 4) -%!error <S and SEP must be string values> strsplit (123, "b") -%!error <S and SEP must be string values> strsplit ("abc", 1) -%!error <STRIP_EMPTY must be a scalar value> strsplit ("abc", "def", ones (3,3)) +%!error <S and DEL must be string values> strsplit (123, "b") +%!error <COLLAPSEDELIMITERS must be a scalar value> strsplit ("abc", "def", ones (3,3))
--- a/scripts/testfun/rundemos.m +++ b/scripts/testfun/rundemos.m @@ -30,7 +30,7 @@ function rundemos (directory) if (nargin == 0) - dirs = strsplit (path (), pathsep ()); + dirs = strsplit (path (), pathsep (), false); elseif (nargin == 1) if (is_absolute_filename (directory)) dirs = {directory};
--- a/scripts/testfun/runtests.m +++ b/scripts/testfun/runtests.m @@ -30,7 +30,7 @@ function runtests (directory) if (nargin == 0) - dirs = strsplit (path (), pathsep ()); + dirs = strsplit (path (), pathsep (), false); elseif (nargin == 1) if (is_absolute_filename (directory)) dirs = {directory};
rename from scripts/java/errordlg.m rename to scripts/ui/errordlg.m --- a/scripts/java/errordlg.m +++ b/scripts/ui/errordlg.m @@ -30,26 +30,20 @@ ## @seealso{helpdlg, inputdlg, listdlg, msgbox, questdlg, warndlg} ## @end deftypefn -function h = errordlg (msg, title = "Error Dialog") +function retval = errordlg (msg, title = "Error Dialog") if (nargin < 1 || nargin > 2) print_usage (); endif - if (! ischar (msg)) - if (iscell (msg)) - msg = sprintf ("%s\n", msg{:}); - msg(end) = ""; - else - error ("errordlg: MSG must be a string or cellstr array"); - endif - endif - - if (! ischar (title)) - error ("errordlg: TITLE must be a character string"); - endif - - h = javaMethod ("errordlg", "org.octave.JDialogBox", msg, title); + retval = message_dialog ("errdlg", msg, title, "error"); endfunction +%!demo +%! disp('- test errordlg with prompt only.'); +%! errordlg('Oops, an expected error occured'); + +%!demo +%! disp('- test errordlg with prompt and caption.'); +%! errordlg('Oops another error','This is a very long and informative caption');
rename from scripts/java/helpdlg.m rename to scripts/ui/helpdlg.m --- a/scripts/java/helpdlg.m +++ b/scripts/ui/helpdlg.m @@ -30,26 +30,20 @@ ## @seealso{errordlg, inputdlg, listdlg, msgbox, questdlg, warndlg} ## @end deftypefn -function h = helpdlg (msg, title = "Help Dialog") +function retval = helpdlg (msg, title = "Help Dialog") if (nargin < 1 || nargin > 2) print_usage (); endif - if (! ischar (msg)) - if (iscell (msg)) - msg = sprintf ("%s\n", msg{:}); - msg(end) = ""; - else - error ("helpdlg: MSG must be a string or cellstr array"); - endif - endif - - if (! ischar (title)) - error ("helpdlg: TITLE must be a character string"); - endif - - h = javaMethod ("helpdlg", "org.octave.JDialogBox", msg, title); + retval = message_dialog ("helpdlg", msg, title, "help"); endfunction +%!demo +%! disp('- test helpdlg with a help message only.'); +%! helpdlg("Below, you should see 3 lines:\nline #1\nline #2, and\nline #3."); + +%!demo +%! disp('- test helpdlg with help message and caption.'); +%! helpdlg('You should see a single line.','A help dialog');
rename from scripts/java/inputdlg.m rename to scripts/ui/inputdlg.m --- a/scripts/java/inputdlg.m +++ b/scripts/ui/inputdlg.m @@ -116,23 +116,90 @@ else error ("inputdlg: ROWSCOLS matrix does not match size of PROMPT"); endif - else ## dunno error ("inputdlg: unknown form of ROWSCOLS argument"); endif + rowscols = ceil (rowscols); ## convert numeric values in defaults cell array to strings defs = cellfun (@num2str, defaults, "UniformOutput", false); rc = arrayfun (@num2str, rowscols, "UniformOutput", false); - user_inputs = javaMethod ("inputdlg", "org.octave.JDialogBox", - prompt, title, rc, defs); - - if (isempty (user_inputs)) - cstr = {}; - else - cstr = cellstr (user_inputs); - endif + if (__octave_link_enabled__ ()) + cstr = __octave_link_input_dialog__ (prompt, title, rowscols, defs); + elseif (__have_feature__ ("JAVA")) + user_inputs = javaMethod ("inputdlg", "org.octave.JDialogBox", + prompt, title, rc, defs); + if (isempty (user_inputs)) + cstr = {}; + else + cstr = cellstr (user_inputs); + endif + else + error ("inputdlg is not available in this version of Octave"); + endif endfunction + +%!demo +%! 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 + +%!demo +%! 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 + +%!demo +%! 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 + +%!demo +%! 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
rename from scripts/java/listdlg.m rename to scripts/ui/listdlg.m --- a/scripts/java/listdlg.m +++ b/scripts/ui/listdlg.m @@ -24,40 +24,40 @@ ## closed the box with the OK button, otherwise it is 0 and @var{sel} is ## empty. ## -## The indices in @var{sel} are 1 based. +## The indices in @var{sel} are 1-based. ## ## The arguments are specified in form of @var{key}, @var{value} pairs. -## The @code{"ListString"} argument pair must be specified. +## The "ListString" argument pair must be specified. ## ## Valid @var{key} and @var{value} pairs are: ## -## @table @code +## @table @asis ## @item "ListString" -## a cell array of strings comprising the content of the list. +## a cell array of strings comprising the content of the list. ## ## @item "SelectionMode" -## can be either @code{"Single"} or @code{"Multiple"} (default). +## can be either "Single" or "Multiple" (default). ## ## @item "ListSize" -## a vector with two elements @var{width} and @var{height} defining -## the size of the list field in pixels. Default is [160 300]. +## a vector with two elements @var{width} and @var{height} defining +## the size of the list field in pixels. Default is [160 300]. ## ## @item "InitialValue" -## a vector containing 1-based indices of preselected elements. Default -## is 1 (first item). +## a vector containing 1-based indices of preselected elements. Default +## is 1 (first item). ## ## @item "Name" -## a string to be used as the dialog caption. Default is "". +## a string to be used as the dialog caption. Default is "". ## ## @item "PromptString" -## a cell array of strings to be displayed above the list field. Default -## is @{@}. +## a cell array of strings to be displayed above the list field. Default +## is @{@}. ## ## @item "OKString" -## a string used to label the OK button. Default is "OK". +## a string used to label the OK button. Default is "OK". ## ## @item "CancelString" -## a string used to label the Cancel button. Default is "Cancel". +## a string used to label the Cancel button. Default is "Cancel". ## @end table ## ## Example: @@ -77,66 +77,116 @@ ## @seealso{errordlg, helpdlg, inputdlg, msgbox, questdlg, warndlg} ## @end deftypefn -function varargout = listdlg (varargin) +function [sel, ok] = listdlg (varargin) + + if (nargin < 2) + print_usage (); + endif + + listcell = {""}; + selmode = "Multiple"; + listsize = [160, 300]; + initialvalue = 1; + name = ""; + prompt = {}; + okstring = "OK"; + cancelstring = "Cancel"; - if (nargin < 2) - print_usage (); - endif - - listcell = {""}; - selmode = "multiple"; - listsize = [160, 300]; - initialvalue = 1; - 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}; - endif - endfor + ## 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}; + endif + endfor - ## make sure prompt strings are a cell array - if (! iscell (prompt)) - prompt = {prompt}; - endif + ## make sure prompt strings are a cell array + if (! iscell (prompt)) + prompt = {prompt}; + endif + + ## make sure listcell strings are a cell array + if (! iscell (listcell)) + listcell = {listcell}; + endif + + ## make sure valid selection mode + if (! strcmp (selmode, "Multiple") && ! strcmp (selmode, "Single")) + error ("invalid SelectionMode"); + endif - ## make sure listcell strings are a cell array - if (! iscell (listcell)) - listcell = {listcell}; - endif - - ## transform matrices to cell arrays of strings - ## swap width and height to correct calling format for JDialogBox - listsize = {num2str(listsize(2)), num2str(listsize(1))}; - initialvalue = arrayfun (@num2str, initialvalue, "UniformOutput", false); - - ret = javaMethod ("listdlg", "org.octave.JDialogBox", listcell, + if (__octave_link_enabled__ ()) + [sel, ok] = __octave_link_list_dialog__ (listcell, selmode, listsize, + initialvalue, name, prompt, + okstring, cancelstring); + elseif (__have_feature__ ("JAVA")) + ## transform matrices to cell arrays of strings + ## swap width and height to correct calling format for JDialogBox + listsize = {num2str(listsize(2)), num2str(listsize(1))}; + initialvalue = arrayfun (@num2str, initialvalue, "UniformOutput", false); + if isempty(prompt) + prompt = {""}; + endif + + ret = javaMethod ("listdlg", "org.octave.JDialogBox", listcell, selmode, listsize, initialvalue, name, prompt, okstring, cancelstring); - if (numel (ret) > 0) - varargout = {ret, 1}; - else - varargout = {{}, 0}; - endif + if (numel (ret) > 0) + sel = ret; + ok = 1; + else + sel = {}; + ok = 0; + endif + else + error ("listdlg is not available in this version of Octave"); + endif endfunction +%!demo +%! disp('- test listdlg with selectionmode single. No caption, no prompt.'); +%! itemlist = {'An item \\alpha', 'another', 'yet another'}; +%! s = listdlg ( 'ListString',itemlist, 'SelectionMode','Single' ); +%! imax = numel (s); +%! for i=1:1:imax +%! disp(['Selected: ',num2str(i),': ', itemlist{s(i)}]); +%! end + +%!demo +%! disp('- test listdlg with selectionmode and preselection. Has caption and two lines prompt.'); +%! itemlist = {'An item \\alpha', 'another', 'yet another'}; +%! s = listdlg ( 'ListString',itemlist, ... +%! 'SelectionMode','Multiple', ... +%! 'Name','Selection Dialog', ... +%! 'InitialValue',[1,2,3,4], +%! 'PromptString',{'Select <b>an</b> item...', '...or <b>multiple</b> items'} ); +%! imax = numel (s); +%! for i=1:1:imax +%! disp(['Selected: ',num2str(i),': ', itemlist{s(i)}]); +%! end + +%!demo +%! disp('- test listdlg with listsize.'); +%! itemlist = {"Neutron","Electron","Quark","Proton","Neutrino"}; +%! s = listdlg ( "ListString",itemlist, +%! "Name","Bits and Pieces", +%! "ListSize",[200 75] ); +%! imax = numel (s); +%! for i=1:1:imax +%! disp(['Selected: ',num2str(i),': ', itemlist{s(i)}]); +%! end
new file mode 100644 --- /dev/null +++ b/scripts/ui/module.mk @@ -0,0 +1,20 @@ +FCN_FILE_DIRS += ui + +ui_PRIVATE_FCN_FILES = \ + ui/private/message_dialog.m + +ui_FCN_FILES = \ + ui/errordlg.m \ + ui/helpdlg.m \ + ui/inputdlg.m \ + ui/listdlg.m \ + ui/msgbox.m \ + ui/questdlg.m \ + ui/warndlg.m \ + $(ui_PRIVATE_FCN_FILES) + +FCN_FILES += $(ui_FCN_FILES) + +PKG_ADD_FILES += ui/PKG_ADD + +DIRSTAMP_FILES += ui/$(octave_dirstamp)
rename from scripts/java/msgbox.m rename to scripts/ui/msgbox.m --- a/scripts/java/msgbox.m +++ b/scripts/ui/msgbox.m @@ -28,49 +28,27 @@ ## decorate the dialog caption. ## ## The optional argument @var{icon} selects a dialog icon. -## It can be one of @code{"none"} (default), @code{"error"}, @code{"help"} or +## It can be one of @code{"none"} (default), @code{"error"}, @code{"help"}, or ## @code{"warn"}. ## ## The return value is always 1. ## @seealso{errordlg, helpdlg, inputdlg, listdlg, questdlg, warndlg} ## @end deftypefn -function h = msgbox (msg, title = "", icon) +function retval = msgbox (msg, title = "", varargin) if (nargin < 1 || nargin > 3) print_usage (); endif - if (! ischar (msg)) - if (iscell (msg)) - msg = sprintf ("%s\n", msg{:}); - msg(end) = ""; - else - error ("msgbox: MSG must be a character string or cellstr array"); - endif - endif - - if (! ischar (title)) - error ("msgbox: TITLE must be a character string"); - endif - - dlg = "emptydlg"; - if (nargin == 3) - switch (icon) - case "error" - dlg = "errordlg"; - case "help" - dlg = "helpdlg"; - case "warn" - dlg = "warndlg"; - case "none" - dlg = "emptydlg"; - otherwise - error ("msgbox: ICON is not a valid type"); - endswitch - endif - - h = javaMethod (dlg, "org.octave.JDialogBox", msg, title); + retval = message_dialog ("msgbox", msg, title, varargin{:}); endfunction +%!demo +%! disp('- test msgbox message only.'); +%! msgbox("Below, you should see 3 lines:\nline #1\nline #2, and\nline #3."); + +%!demo +%! disp('- test msgbox message and caption.'); +%! msgbox('You should see a single line.','A msgbox');
new file mode 100644 --- /dev/null +++ b/scripts/ui/private/message_dialog.m @@ -0,0 +1,65 @@ +## Copyright (C) 2010 Martin Hepperle +## +## This file is part of Octave. +## +## Octave 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 3 of the License, or (at +## your option) any later version. +## +## Octave 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} {@var{h} =} message_dialog (@var{caller}, @var{msg}, @var{title}, @var{icon}) +## Undocumented internal function. +## @end deftypefn + +function retval = message_dialog (caller, msg, title = "", icon) + + if (! ischar (msg)) + if (iscell (msg)) + msg = sprintf ("%s\n", msg{:}); + msg(end) = ""; + else + error ("%s: MSG must be a character string or cellstr array", caller); + endif + endif + + if (! ischar (title)) + error ("%s: TITLE must be a character string", caller); + endif + + dlg = "emptydlg"; + if (nargin == 4) + switch (icon) + case "error" + dlg = "errordlg"; + case "help" + dlg = "helpdlg"; + case "warn" + dlg = "warndlg"; + case "none" + dlg = "emptydlg"; + otherwise + error ("%s: ICON is not a valid type", caller); + endswitch + else + icon = "none"; + endif + + if (__octave_link_enabled__ ()) + retval = __octave_link_message_dialog__ (icon, msg, title); + elseif (__have_feature__ ("JAVA")) + retval = javaMethod (dlg, "org.octave.JDialogBox", msg, title); + else + error ("%s is not available in this version of Octave", dlg); + endif + +endfunction
rename from scripts/java/questdlg.m rename to scripts/ui/questdlg.m --- a/scripts/java/questdlg.m +++ b/scripts/ui/questdlg.m @@ -28,13 +28,13 @@ ## The dialog may contain two or three buttons which will all close the dialog. ## ## The message may have multiple lines separated by newline characters -## (@code{"\n"}), or it may be a cellstr array with one element for each +## ("\n"), or it may be a cellstr array with one element for each ## line. The optional @var{title} (character string) can be used to ## decorate the dialog caption. ## ## The string @var{default} identifies the default button, -## which is activated by pressing the @kbd{ENTER} key. -## It must match one of the strings given in @var{btn1}, @var{btn2} or +## which is activated by pressing the @key{ENTER} key. +## It must match one of the strings given in @var{btn1}, @var{btn2}, or ## @var{btn3}. ## ## If only @var{msg} and @var{title} are specified, three buttons with @@ -70,10 +70,18 @@ options{3} = "Cancel"; # button3 options{4} = "Yes"; # default + defbtn_error_msg = "questdlg: DEFAULT must match one of the button options"; + switch (numel (varargin)) + case 0 + ## use default default + case 1 ## default button string options{4} = varargin{1}; # default + if (! any (strcmp (options{4}, options(1:3)))) + error (defbtn_error_msg); + end case 3 ## two buttons and default button string @@ -81,6 +89,9 @@ options{2} = ""; # not used, no middle button options{3} = varargin{2}; # button3 options{4} = varargin{3}; # default + if (! any (strcmp (options{4}, options([1 3])))) + error (defbtn_error_msg); + end case 4 ## three buttons and default button string @@ -88,14 +99,76 @@ options{2} = varargin{2}; # button2 options{3} = varargin{3}; # button3 options{4} = varargin{4}; # default + if (! any (strcmp (options{4}, options(1:3)))) + error (defbtn_error_msg); + end otherwise print_usage (); endswitch - btn = javaMethod ("questdlg", "org.octave.JDialogBox", msg, - title, options); + if (__octave_link_enabled__ ()) + btn = __octave_link_question_dialog__ (msg, title, options{1}, options{2}, + options{3}, options{4}); + elseif (__have_feature__ ("JAVA")) + btn = javaMethod ("questdlg", "org.octave.JDialogBox", msg, + title, options); + else + error ("questdlg is not available in this version of Octave"); + endif endfunction +%!demo +%! disp('- test questdlg with two buttons'); +%! a = questdlg('Would you like some free money?',... +%! '$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $',... +%! 'No', 'Cancel', 'Cancel'); +%! if strcmp (a, 'No') +%! msgbox('Suit yourself.', 'Message Box'); +%! endif + +%!demo +%! disp('- test questdlg with message and title only.'); +%! a = 'No'; +%! c = 0; +%! while (strcmp(a, 'No') || !c) +%! a = questdlg('Close this Question Dialog?', 'Reductio Ad Absurdum'); +%! if strcmp(a, 'Yes') +%! q = 'Are you sure?'; +%! while (strcmp(a, 'Yes') && !c) +%! a = questdlg(q, 'Reductio Ad Absurdum'); +%! word = ' really'; +%! i = strfind(q, word); +%! if isempty( i ) +%! i = strfind(q, ' sure'); +%! q = [q '!']; +%! else +%! word = [word ',']; +%! endif +%! q = [q(1:i-1) word q(i:end)]; +%! endwhile +%! endif +%! if strcmp(a, 'Cancel') +%! warndlg('Answer "Yes" or "No".', 'Warning Dialog'); +%! a = 'No'; +%! c = 1; +%! endif +%! endwhile +%! msgbox('Whew!'); + +%!demo +%! disp('- test questdlg with five inputs'); +%! ans = questdlg('Are you ready Steve?', 'Brian', 'No', 'Uh huh', 'Uh huh'); +%! if !strcmp (ans, 'No') +%! ans = questdlg ('Andy?', 'Brian', 'No', 'Yeah', 'Yeah'); +%! if !strcmp (ans, 'No') +%! ans = questdlg ('Mick?', 'Brian', 'No', 'Okay', 'Okay'); +%! if !strcmp (ans, 'No') +%! ans = msgbox ("Well all right, fellas. \n\n Let''s GO!!!!!",... +%! 'Ballroom Blitz', 'none'); +%! endif +%! endif +%! endif +
rename from scripts/java/warndlg.m rename to scripts/ui/warndlg.m --- a/scripts/java/warndlg.m +++ b/scripts/ui/warndlg.m @@ -35,20 +35,14 @@ print_usage (); endif - if (! ischar (msg)) - if (iscell (msg)) - msg = sprintf ("%s\n", msg{:}); - msg(end) = ""; - else - error ("warndlg: MSG must be a string or cellstr array"); - endif - endif - - if (! ischar (title)) - error ("warndlg: TITLE must be a character string"); - endif - - retval = javaMethod ("warndlg", "org.octave.JDialogBox", msg, title); + retval = message_dialog ("warndlg", msg, title, "warn"); endfunction +%!demo +%! disp('- test warndlg with prompt only.'); +%! warndlg('Oh, a warning occured'); + +%!demo +%! disp('- test warndlg with prompt and caption.'); +%! warndlg('Oh, No...','This is the last Warning');
--- a/test/Makefile.am +++ b/test/Makefile.am @@ -24,6 +24,7 @@ fntests.m \ args.tst \ bug-31371.tst \ + bug-38576.tst \ diag-perm.tst \ error.tst \ eval-catch.tst \
--- a/test/bug-38236/u_vr.m +++ b/test/bug-38236/u_vr.m @@ -1,17 +1,12 @@ # u_vr.m -cmd = "\ -function __demo__ () \ - df_vr; \ - v = vr * 2; \ -endfunction \ -"; +## define and exectute "__demo__" once +eval ("function __demo__ (); df_vr; v = vr * 2; endfunction"); +__demo__; -for ii = 1:2 - unwind_protect - eval (cmd); - __demo__; - unwind_protect_cleanup - clear __demo__ - end_unwind_protect -endfor \ No newline at end of file +## clear definition of "__demo__" +clear __demo__ + +## define and exectute "__demo__" once more +eval ("function __demo__ (); df_vr; v = vr * 2; endfunction"); +__demo__;
new file mode 100644 --- /dev/null +++ b/test/bug-38565.tst @@ -0,0 +1,9 @@ +%!function r = f (x) +%! if (ischar (x)) +%! r = x; +%! else +%! error ("expecting character string"); +%! endif +%!endfunction + +%!assert (eval ("f 10;"), "10");
new file mode 100644 --- /dev/null +++ b/test/bug-38576.tst @@ -0,0 +1,16 @@ +%!function r = f1 () +%! ls = svd (1); +%! r = eval ("ls -1;"); +%!endfunction +%!function r = f2 () +%! [u,ls,v] = svd (1); +%! r = eval ("ls -1;"); +%!endfunction +%!function r = f3 (ls) +%! r = eval ("ls -1;"); +%!endfunction + +%!assert (f1 (), 0); +%!assert (f2 (), 0); +%!assert (ischar (f3 ()), true); +%!assert (f3 (1), 0);