From: Luca Padovani Date: Sat, 8 Feb 2003 22:13:29 +0000 (+0000) Subject: * this is a large commit X-Git-Tag: V_0_0_4_1~51 X-Git-Url: http://matita.cs.unibo.it/gitweb/?a=commitdiff_plain;h=387aeebf96181c051b7f527a0901b173cfcdf194;p=helm.git * this is a large commit * added freeze/thaw methods to parser * added XSLT + Diff class * added method for including dictionaries * added preliminary ocaml binding (C+ML) * code cleanup --- diff --git a/helm/DEVEL/mathml_editor/AUTHORS b/helm/DEVEL/mathml_editor/AUTHORS index 2ba63d6cc..7cec8397e 100644 --- a/helm/DEVEL/mathml_editor/AUTHORS +++ b/helm/DEVEL/mathml_editor/AUTHORS @@ -1 +1,2 @@ Luca Padovani +Paolo Marinelli diff --git a/helm/DEVEL/mathml_editor/BUGS-GDOME2 b/helm/DEVEL/mathml_editor/BUGS-GDOME2 index 2b89215f0..5f756359f 100644 --- a/helm/DEVEL/mathml_editor/BUGS-GDOME2 +++ b/helm/DEVEL/mathml_editor/BUGS-GDOME2 @@ -1,15 +1,4 @@ -* replaceChild on document root should work, but it is implemented as - an insertBefore + removeChild, and the insertBefore is not allowed - for the document must have xactly _one_ child -* the code to dispatch the events is wrong, because it stores - xmlNodes and not gdome wrappers, hence the nodes can be deleted -* when firing events, self is not always reffed, what is the reason for - doing it? -* DOMSubtreeModified must have bubble=yes -* when setting more event listeners for the same node, with same type - and same useCapture, the event listener also matters. It seems like - now one can set only one event per combination type/capture * /usr/lib is given by gdome-config * should optimize event propagation, remember only those nodes with listeners diff --git a/helm/DEVEL/mathml_editor/Makefile.am b/helm/DEVEL/mathml_editor/Makefile.am index edd3988bb..8f4639ebf 100644 --- a/helm/DEVEL/mathml_editor/Makefile.am +++ b/helm/DEVEL/mathml_editor/Makefile.am @@ -1,5 +1,5 @@ #EXTRA_DIST = BUGS HISTORY LICENSE aclocal.m4 debian/ -SUBDIRS = src test +SUBDIRS = src test ocaml CLEANFILES = core bin_SCRIPTS = editex-config diff --git a/helm/DEVEL/mathml_editor/Makefile.in b/helm/DEVEL/mathml_editor/Makefile.in index f68e1f659..fdf08ab3e 100644 --- a/helm/DEVEL/mathml_editor/Makefile.in +++ b/helm/DEVEL/mathml_editor/Makefile.in @@ -76,18 +76,32 @@ GMETADOM_CFLAGS = @GMETADOM_CFLAGS@ GMETADOM_LIBS = @GMETADOM_LIBS@ GTKMATHVIEW_CFLAGS = @GTKMATHVIEW_CFLAGS@ GTKMATHVIEW_LIBS = @GTKMATHVIEW_LIBS@ +HAVE_OCAMLC = @HAVE_OCAMLC@ +HAVE_OCAMLDEP = @HAVE_OCAMLDEP@ +HAVE_OCAMLFIND = @HAVE_OCAMLFIND@ +HAVE_OCAMLMKLIB = @HAVE_OCAMLMKLIB@ +HAVE_OCAMLOPT = @HAVE_OCAMLOPT@ LDFLAGS = @LDFLAGS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ MAKEINFO = @MAKEINFO@ +MLGDOME_CFLAGS = @MLGDOME_CFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OCAMLC = @OCAMLC@ +OCAMLDEP = @OCAMLDEP@ +OCAMLFIND = @OCAMLFIND@ +OCAMLMKLIB = @OCAMLMKLIB@ +OCAMLOPT = @OCAMLOPT@ +OCAMLSTDLIBDIR = @OCAMLSTDLIBDIR@ +OCAMLSTUBDIR = @OCAMLSTUBDIR@ +OCAML_INCLUDE_DIR = @OCAML_INCLUDE_DIR@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ STRIP = @STRIP@ VERSION = @VERSION@ -SUBDIRS = src test +SUBDIRS = src test ocaml CLEANFILES = core bin_SCRIPTS = editex-config diff --git a/helm/DEVEL/mathml_editor/configure.ac b/helm/DEVEL/mathml_editor/configure.ac index 0dca72c8c..dd7b07b7b 100644 --- a/helm/DEVEL/mathml_editor/configure.ac +++ b/helm/DEVEL/mathml_editor/configure.ac @@ -72,6 +72,11 @@ AC_PROG_CXX AC_PROG_INSTALL AC_HEADER_STDC([]) +AC_LANG_PUSH(C++) +AC_CHECK_HEADERS(hash_map) +AC_CHECK_HEADERS(ext/hash_map) +AC_LANG_POP(C++) + AC_SUBST(CFLAGS) AC_SUBST(CPPFLAGS) AC_SUBST(LDFLAGS) @@ -110,7 +115,7 @@ AC_SUBST(GMETADOM_CFLAGS) AC_SUBST(GMETADOM_LIBS) GDOMEXSLT_CONFIG="gdome_xslt_cpp_smart-config" -GDOMEXSLT_MIN_VERSION=0.0.1 +GDOMEXSLT_MIN_VERSION=0.0.4 AC_MSG_CHECKING([for gdome_xslt C++ library] >= $GDOMEXSLT_MIN_VERSION) if test "x$GDOMEXSLT_PREFIX" != "x" then @@ -171,10 +176,71 @@ fi AC_SUBST(GTKMATHVIEW_CFLAGS) AC_SUBST(GTKMATHVIEW_LIBS) +AC_CHECK_PROG(HAVE_OCAMLC, ocamlc, yes, no) +if test $HAVE_OCAMLC = "no"; then + AC_MSG_ERROR([could not find ocamlc in PATH, please make sure ocaml is installed]) +else + OCAMLC=ocamlc + OCAMLSTDLIBDIR="`ocamlc -where`" + OCAMLSTUBDIR="`ocamlc -where`/stublibs" + AC_SUBST(OCAMLC) + AC_SUBST(OCAMLSTDLIBDIR) + AC_SUBST(OCAMLSTUBDIR) +fi + +AC_CHECK_PROG(HAVE_OCAMLOPT, ocamlopt, yes, no) +if test $HAVE_OCAMLOPT = "no"; then + AC_MSG_WARN([ocaml native libraries won't be compiled since ocamlopt was not found]) +else + OCAMLOPT=ocamlopt + AC_SUBST(OCAMLOPT) +fi +AM_CONDITIONAL(HAVE_OCAMLOPT_COND, test x$HAVE_OCAMLOPT = xyes) + +AC_CHECK_PROG(HAVE_OCAMLFIND, ocamlfind, yes, no) +if test $HAVE_OCAMLFIND = "no"; then + AC_MSG_ERROR([could not find ocamlfind in PATH, please make sure findlib is installed]) +else + OCAMLFIND=ocamlfind + AC_SUBST(OCAMLFIND) +fi + +AC_CHECK_PROG(HAVE_OCAMLDEP, ocamldep, yes, no) +if test $HAVE_OCAMLDEP = "yes"; then + OCAMLDEP=ocamldep + AC_SUBST(OCAMLDEP) +fi + +AC_CHECK_PROG(HAVE_OCAMLMKLIB, ocamlmklib, yes, no) +if test $HAVE_OCAMLMKLIB = "no"; then + AC_MSG_ERROR([could not find ocamlmklib in PATH, please make sure ocamlmklib is installed]) +else + OCAMLMKLIB=ocamlmklib + AC_SUBST(OCAMLMKLIB) +fi + +AC_MSG_CHECKING(for gdome2 ocaml binding) +ocamlfind query gdome2 || + AC_MSG_ERROR(gdome2 not installed (according to findlib)) +MLGDOME_CFLAGS="`$OCAMLFIND query -i-format gdome2`" +AC_SUBST(MLGDOME_CFLAGS) + +AC_MSG_CHECKING(for the ocaml library dir) +OCAML_LIB_DIR=`ocamlc -where` +AC_MSG_RESULT($OCAML_LIB_DIR) + +AC_CHECK_FILE(/usr/include/caml/mlvalues.h, + OCAML_INCLUDE_DIR=/usr/include/caml, + OCAML_INCLUDE_DIR=$OCAML_LIB_DIR/caml +) + +AC_SUBST(OCAML_INCLUDE_DIR) + AC_CONFIG_FILES([ Makefile src/Makefile test/Makefile + ocaml/Makefile editex-config ]) AC_CONFIG_COMMANDS([default],[[chmod +x editex-config]],[[]]) diff --git a/helm/DEVEL/mathml_editor/dictionary-basic.xml b/helm/DEVEL/mathml_editor/dictionary-basic.xml new file mode 100644 index 000000000..ed2e26461 --- /dev/null +++ b/helm/DEVEL/mathml_editor/dictionary-basic.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/helm/DEVEL/mathml_editor/dictionary-test.xml b/helm/DEVEL/mathml_editor/dictionary-test.xml new file mode 100644 index 000000000..a9f3c0c11 --- /dev/null +++ b/helm/DEVEL/mathml_editor/dictionary-test.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/helm/DEVEL/mathml_editor/dictionary-tex.xml b/helm/DEVEL/mathml_editor/dictionary-tex.xml new file mode 100644 index 000000000..6bb3c5eb9 --- /dev/null +++ b/helm/DEVEL/mathml_editor/dictionary-tex.xml @@ -0,0 +1,357 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/helm/DEVEL/mathml_editor/dictionary.dtd b/helm/DEVEL/mathml_editor/dictionary.dtd index 4d092af2b..3fefc71fe 100644 --- a/helm/DEVEL/mathml_editor/dictionary.dtd +++ b/helm/DEVEL/mathml_editor/dictionary.dtd @@ -1,9 +1,12 @@ - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/helm/DEVEL/mathml_editor/ocaml/Makefile.am b/helm/DEVEL/mathml_editor/ocaml/Makefile.am new file mode 100644 index 000000000..9c1cc707b --- /dev/null +++ b/helm/DEVEL/mathml_editor/ocaml/Makefile.am @@ -0,0 +1,86 @@ +PKGNAME = mathml-editor +ARCHIVE = mlmathml-editor +REQUIRES = gdome2 gdome2-xslt +OCAMLFIND = @OCAMLFIND@ +OCAMLC = $(OCAMLFIND) @OCAMLC@ -package "$(REQUIRES)" +OCAMLOPT = $(OCAMLFIND) @OCAMLOPT@ -package "$(REQUIRES)" +OCAMLDEP = $(OCAMLFIND) @OCAMLDEP@ -package "$(REQUIRES)" +OCAMLMKLIB = @OCAMLMKLIB@ +DLL = dll$(ARCHIVE).so +OCAMLSTDLIBDIR = $(DESTDIR)/@OCAMLSTDLIBDIR@ +OCAMLSTUBDIR = $(DESTDIR)/@OCAMLSTUBDIR@ +OCAMLINSTALLDIR = $(OCAMLSTDLIBDIR)/$(PKGNAME) +MODULES = i_mathml_editor mathml_editor +INIT = +CMI_S = $(MODULES:%=%.cmi) +CMO_S = $(MODULES:%=%.cmo) +CMX_S = $(MODULES:%=%.cmx) +O_S = ml_mathml_editor.o +SHARED_LIBS = $(GMETADOM_LIBS) $(GDOMEXSLT_LIBS) +BYTE_STUFF = $(ARCHIVE).cma +NATIVE_STUFF = $(ARCHIVE).cmxa $(ARCHIVE).a +BYTE_INSTALL_STUFF = \ + i_mathml_editor.cmi mathml_editor.cmi $(ARCHIVE).cma $(DLL) META +NATIVE_INSTALL_STUFF = $(ARCHIVE).a $(ARCHIVE).cmxa + +EXTRA_DIST = \ + META.in mathml_editor.ml i_mathml_editor.ml \ + ml_mathml_editor.h c_mathml_editor.h .depend + +if HAVE_OCAMLOPT_COND +noinst_DATA = $(BYTE_STUFF) $(NATIVE_STUFF) +else +noinst_DATA = $(BYTE_STUFF) +endif + +noinst_LTLIBRARIES = libmlmathml_editor.la +libmlmathml_editor_la_SOURCES = \ + c_mathml_editor.cc \ + ml_mathml_editor.c + +#test: test.ml $(ARCHIVE).cma +# $(OCAMLC) -o $@ -linkpkg $(INCLUDES) $< + +#test.opt: test.ml $(ARCHIVE).cmxa +# $(OCAMLOPT) -o $@ -linkpkg $(INCLUDES) $< + +if HAVE_OCAMLOPT_COND +install-data-local: $(BYTE_INSTALL_STUFF) $(NATIVE_INSTALL_STUFF) +else +install-data-local: $(BYTE_INSTALL_STUFF) +endif + $(mkinstalldirs) $(OCAMLSTDLIBDIR) $(OCAMLSTUBDIR) + chmod -x $(DLL) + $(OCAMLFIND) install -destdir $(OCAMLSTDLIBDIR) $(PKGNAME) $^ + ln -fs $(DLL) $(OCAMLSTUBDIR)/lib$(ARCHIVE).so + +CLEANFILES = \ + $(ARCHIVE).{cma,cmxa,a} $(CMI_S) $(CMO_S) $(CMX_S) ml_mathml_editor.o \ + $(DLL) $(INIT).cm[iox] libmlmathml_editor.a + +INCLUDES = \ + $(GDOME_CFLAGS) $(MLGDOME_CFLAGS) \ + $(GMETADOM_CFLAGS) $(GDOMEXSLT_CFLAGS) \ + -I$(top_srcdir)/src + +$(ARCHIVE).cma $(DLL): $(CMO_S) + $(OCAMLMKLIB) -o $(ARCHIVE) -L@OCAMLSTUBDIR@ $(CMO_S) $(O_S) $(SHARED_LIBS) +$(ARCHIVE).cmxa $(ARCHIVE).a: $(CMX_S) + $(OCAMLMKLIB) -o $(ARCHIVE) -L@OCAMLSTUBDIR@ $(CMX_S) $(O_S) $(SHARED_LIBS) + +%.cmi: %.mli + $(OCAMLC) -c $< +%.cmo %.cmi: %.ml + $(OCAMLC) -c $< +%.cmx: %.ml %.cmi + $(OCAMLOPT) -c $< + +i_mathml_editor.cmo: i_mathml_editor.ml + $(OCAMLC) -c $< +i_mathml_editor.cmx: i_mathml_editor.ml + $(OCAMLOPT) -c $< + +depend: *.ml *.mli + $(OCAMLDEP) *.ml *.mli >.depend +include .depend + diff --git a/helm/DEVEL/mathml_editor/ocaml/c_mathml_editor.cc b/helm/DEVEL/mathml_editor/ocaml/c_mathml_editor.cc new file mode 100644 index 000000000..284f1ed50 --- /dev/null +++ b/helm/DEVEL/mathml_editor/ocaml/c_mathml_editor.cc @@ -0,0 +1,157 @@ + +#include + +#include "ALogger.hh" +#include "TDictionary.hh" +#include "CMathMLFactoryXSLT.hh" +#include "TPushLexer.hh" +#include "TPushParser.hh" + +class CCallbackLogger : public ALogger +{ +public: + CCallbackLogger(void (*)(int, const char*, void*), void*); + virtual ~CCallbackLogger() { }; + +protected: + virtual void message(Level, const std::string&); + +private: + void (*callback)(int, const char*, void*); + void* user_data; +}; + +CCallbackLogger::CCallbackLogger(void (*cb)(int, const char*, void*), void* data) : callback(cb), user_data(data) +{ + assert(callback); +} + +void +CCallbackLogger::message(Level l, const std::string& s) +{ + assert(callback); + callback(l, s.c_str(), user_data); +} + +struct Editor +{ + Editor(const DOM::Document&, const DOM::Document&, const DOM::Document&, void (*)(int, const char*, void*), void*); + ~Editor(); + + ALogger* logger; + TDictionary* dictionary; + DOMX::XSLTStylesheet* tml_mml; + DOMX::XSLTStylesheet* tml_tex; + AMathMLFactory* factory; + TPushParser* parser; + APushLexer* lexer; +}; + +Editor::Editor(const DOM::Document& dict, const DOM::Document& mml, const DOM::Document& tex, + void (*cb)(int, const char*, void*), void* data) +{ + assert(cb); + logger = new CCallbackLogger(cb, data); + dictionary = new TDictionary(*logger); + dictionary->load(DOM::Document(dict)); + tml_mml = new DOMX::XSLTStylesheet(mml); + tml_tex = new DOMX::XSLTStylesheet(tex); + factory = new CMathMLFactoryXSLT(*logger, *tml_mml); + parser = new TPushParser(*logger, *factory, *dictionary); + lexer = new TPushLexer(*logger, *parser); +} + +Editor::~Editor() +{ + delete lexer; + delete parser; + delete factory; + delete tml_tex; + delete tml_mml; + delete dictionary; + delete logger; +} + +extern "C" Editor* +c_mathml_editor_new(GdomeDocument* dictionary, + GdomeDocument* tml_mml, + GdomeDocument* tml_tex, + void (*log_message_cb)(int, const char*, void*), + void* user_data) +{ + return new Editor(DOM::Document(dictionary), + DOM::Document(tml_mml), + DOM::Document(tml_tex), log_message_cb, user_data); +} + +extern "C" void +c_mathml_editor_destroy(Editor* editor) +{ + assert(editor); + delete editor; +} + +extern "C" int +c_mathml_editor_freeze(Editor* editor) +{ + assert(editor); + return editor->parser->freeze(); +} + +extern "C" int +c_mathml_editor_thaw(Editor* editor) +{ + assert(editor); + return editor->parser->thaw(); +} + +extern "C" void +c_mathml_editor_push(Editor* editor, char ch) +{ + assert(editor); + editor->lexer->push(ch); +} + +extern "C" void +c_mathml_editor_drop(Editor* editor, int alt) +{ + assert(editor); + editor->lexer->drop(alt != 0); +} + +extern "C" char* +c_mathml_editor_get_tex(const Editor* editor) +{ + assert(editor); + DOM::Document res = editor->tml_tex->apply(editor->parser->document()); + DOM::Element root = res.get_documentElement(); + return strdup(std::string(root.get_nodeValue()).c_str()); +} + +extern "C" void +c_mathml_editor_reset(Editor* editor) +{ + assert(editor); + editor->parser->reset(); +} + +extern "C" GdomeDocument* +c_mathml_editor_get_tml(const Editor* editor) +{ + assert(editor); + GdomeNode* n = editor->parser->document().cloneNode(true).gdome_object(); + GdomeDocument* doc = gdome_cast_doc(n); + assert(n && doc); + return doc; +} + +extern "C" GdomeDocument* +c_mathml_editor_get_mml(const Editor* editor) +{ + assert(editor); + GdomeNode* n = editor->factory->document().gdome_object(); + GdomeDocument* doc = gdome_cast_doc(n); + assert(n && doc); + return doc; +} + diff --git a/helm/DEVEL/mathml_editor/ocaml/c_mathml_editor.h b/helm/DEVEL/mathml_editor/ocaml/c_mathml_editor.h new file mode 100644 index 000000000..7e7c0e38e --- /dev/null +++ b/helm/DEVEL/mathml_editor/ocaml/c_mathml_editor.h @@ -0,0 +1,20 @@ + +#ifndef __c_mathml_editor_h__ +#define __c_mathml_editor_h__ + +#include + +typedef struct Editor Editor; + +Editor* c_mathml_editor_new(GdomeDocument*, GdomeDocument*, GdomeDocument*, void (*)(int, const char*, void*), void*); +void c_mathml_editor_destroy(Editor*); +int c_mathml_editor_freeze(Editor*); +int c_mathml_editor_thaw(Editor*); +void c_mathml_editor_reset(Editor*); +void c_mathml_editor_push(Editor*, char); +void c_mathml_editor_drop(Editor*, int); +char* c_mathml_editor_get_tex(const Editor*); +GdomeDocument* c_mathml_editor_get_tml(const Editor*); +GdomeDocument* c_mathml_editor_get_mml(const Editor*); + +#endif /* __c_mathml_editor_h__ */ diff --git a/helm/DEVEL/mathml_editor/ocaml/i_mathml_editor.ml b/helm/DEVEL/mathml_editor/ocaml/i_mathml_editor.ml new file mode 100644 index 000000000..5019fbeff --- /dev/null +++ b/helm/DEVEL/mathml_editor/ocaml/i_mathml_editor.ml @@ -0,0 +1,35 @@ + +type t + +external create : + dictionary:[> `Document] GdomeT.t -> + mml: [> `Document] GdomeT.t -> + tex: [> `Document] GdomeT.t -> + log:(string -> unit) -> + t + = "ml_mathml_editor_new" + +external freeze : editor:t -> bool + = "ml_mathml_editor_freeze" + +external thaw : editor:t -> bool + = "ml_mathml_editor_thaw" + +external reset : editor:t -> unit + = "ml_mathml_editor_reset" + +external push : editor:t -> ch:char -> unit + = "ml_mathml_editor_push" + +external drop : editor:t -> alt:bool -> unit + = "ml_mathml_editor_drop" + +external get_tex : editor:t -> string + = "ml_mathml_editor_get_tex" + +external get_tml : editor:t -> TDocument.t + = "ml_mathml_editor_get_tml" + +external get_mml : editor:t -> TDocument.t + = "ml_mathml_editor_get_mml" + diff --git a/helm/DEVEL/mathml_editor/ocaml/mathml_editor.ml b/helm/DEVEL/mathml_editor/ocaml/mathml_editor.ml new file mode 100644 index 000000000..58ca8f769 --- /dev/null +++ b/helm/DEVEL/mathml_editor/ocaml/mathml_editor.ml @@ -0,0 +1,31 @@ + +let create ~dictionary ~mml ~tml ~log = + I_mathml_editor.create dictionary#as_Document mml#as_Document tml#as_Document log +;; + +let freeze = I_mathml_editor.freeze +;; + +let thaw = I_mathml_editor.thaw +;; + +let reset = I_mathml_editor.reset +;; + +let push = I_mathml_editor.push +;; + +let drop = I_mathml_editor.drop +;; + +let get_tex = I_mathml_editor.get_tex +;; + +let get_tml ~editor = + new Gdome.document (I_mathml_editor.get_tml ~editor) +;; + +let get_mml ~editor = + new Gdome.document (I_mathml_editor.get_mml ~editor) +;; + diff --git a/helm/DEVEL/mathml_editor/ocaml/ml_mathml_editor.c b/helm/DEVEL/mathml_editor/ocaml/ml_mathml_editor.c new file mode 100644 index 000000000..79594c2a8 --- /dev/null +++ b/helm/DEVEL/mathml_editor/ocaml/ml_mathml_editor.c @@ -0,0 +1,143 @@ + +#include +#include +#include + +#include "mlgdomevalue.h" + +#include "c_mathml_editor.h" + +typedef struct +{ + Editor* c_editor; + value callback; +} ml_Editor; + +ml_Editor* +Editor_val(value v) +{ + ml_Editor* editor = (ml_Editor*) Data_custom_val(v); + assert(editor != NULL); + return editor; +} + +static void +ml_mathml_editor_finalize(value v) +{ + ml_Editor* editor = Editor_val(v); + assert(editor); + + remove_global_root(&editor->callback); + c_mathml_editor_destroy(editor->c_editor); +} + +void +ml_mathml_editor_log_callback(int level, const char* msg, void* user_data) +{ + ml_Editor* ml_editor = (ml_Editor*) user_data; + assert(ml_editor); + callback2(ml_editor->callback, Val_int(level), copy_string(msg)); +} + +value +ml_mathml_editor_new(value dictionary, + value tml_mml, + value tml_tex, + value log_message_cb) +{ + static struct custom_operations ops = + { + "HELM/MathML Editor", + ml_mathml_editor_finalize, + custom_compare_default, + custom_hash_default, + custom_serialize_default, + custom_deserialize_default + }; + + value v = alloc_custom(&ops, sizeof(ml_Editor), 0, 1); + ml_Editor* ml_editor = (ml_Editor*) Data_custom_val(v); + ml_editor->c_editor = c_mathml_editor_new(Document_val(dictionary), + Document_val(tml_mml), + Document_val(tml_tex), + ml_mathml_editor_log_callback, + (void*) ml_editor); + ml_editor->callback = log_message_cb; + register_global_root(&ml_editor->callback); + + return v; +} + +value +ml_mathml_editor_freeze(value v) +{ + CAMLparam1(v); + ml_Editor* editor = Editor_val(v); + CAMLreturn(Val_bool(c_mathml_editor_freeze(editor->c_editor))); +} + +value +ml_mathml_editor_thaw(value v) +{ + CAMLparam1(v); + ml_Editor* editor = Editor_val(v); + CAMLreturn(Val_bool(c_mathml_editor_thaw(editor->c_editor))); +} + +value +ml_mathml_editor_push(value v, value ch) +{ + CAMLparam2(v, ch); + ml_Editor* editor = Editor_val(v); + c_mathml_editor_push(editor->c_editor, Int_val(ch)); + CAMLreturn(Val_unit); +} + +value +ml_mathml_editor_drop(value v, value alt) +{ + CAMLparam2(v, alt); + ml_Editor* editor = Editor_val(v); + c_mathml_editor_drop(editor->c_editor, Bool_val(alt)); + CAMLreturn(Val_unit); +} + +value +ml_mathml_editor_get_tex(value v) +{ + CAMLparam1(v); + ml_Editor* editor = Editor_val(v); + char* res = c_mathml_editor_get_tex(editor->c_editor); + CAMLlocal1(ml_res); + ml_res = copy_string(res); + free(res); + CAMLreturn(ml_res); +} + +value +ml_mathml_editor_reset(value v, value s) +{ + CAMLparam1(v); + ml_Editor* editor = Editor_val(v); + c_mathml_editor_reset(editor->c_editor); + CAMLreturn(Val_unit); +} + +value +ml_mathml_editor_get_tml(value v) +{ + CAMLparam1(v); + ml_Editor* editor = Editor_val(v); + GdomeDocument* doc = c_mathml_editor_get_tml(editor->c_editor); + CAMLreturn(Val_Document(doc)); +} + +value +ml_mathml_editor_get_mml(value v) +{ + CAMLparam1(v); + ml_Editor* editor = Editor_val(v); + GdomeDocument* doc = c_mathml_editor_get_mml(editor->c_editor); + CAMLreturn(Val_Document(doc)); +} + diff --git a/helm/DEVEL/mathml_editor/src/AMathMLFactory.hh b/helm/DEVEL/mathml_editor/src/AMathMLFactory.hh index a514e9453..5186c63bb 100644 --- a/helm/DEVEL/mathml_editor/src/AMathMLFactory.hh +++ b/helm/DEVEL/mathml_editor/src/AMathMLFactory.hh @@ -29,16 +29,15 @@ class AMathMLFactory { public: - AMathMLFactory(class ALogger& l) : logger(l), consumer(0) { }; - AMathMLFactory(class ALogger& l, class AMathMLConsumer& c) : logger(l), consumer(&c) { }; + AMathMLFactory(class ALogger& l) : logger(l) { }; virtual ~AMathMLFactory() { }; + virtual void reset(void) = 0; virtual void documentModified(class TDocument&) = 0; virtual DOM::Document document(void) const = 0; protected: class ALogger& logger; - class AMathMLConsumer* consumer; }; #endif // __AMathMLFactory_hh__ diff --git a/helm/DEVEL/mathml_editor/src/APushLexer.hh b/helm/DEVEL/mathml_editor/src/APushLexer.hh index 4fca8cf76..342d18fe9 100644 --- a/helm/DEVEL/mathml_editor/src/APushLexer.hh +++ b/helm/DEVEL/mathml_editor/src/APushLexer.hh @@ -9,6 +9,7 @@ public: virtual ~APushLexer() { }; virtual void push(char) = 0; + virtual void drop(bool = false) = 0; virtual void reset(void) = 0; virtual bool error(void) const = 0; diff --git a/helm/DEVEL/mathml_editor/src/APushParser.cc b/helm/DEVEL/mathml_editor/src/APushParser.cc new file mode 100644 index 000000000..9ff5eff1f --- /dev/null +++ b/helm/DEVEL/mathml_editor/src/APushParser.cc @@ -0,0 +1,24 @@ + +#include "APushParser.hh" +#include "AMathMLFactory.hh" + +void +APushParser::reset() +{ + if (factory) factory->reset(); +} + +bool +APushParser::freeze() +{ + return freeze_level++ == 0; +} + +bool +APushParser::thaw() +{ + if (freeze_level > 0) + return --freeze_level == 0; + else + return true; +} diff --git a/helm/DEVEL/mathml_editor/src/APushParser.hh b/helm/DEVEL/mathml_editor/src/APushParser.hh index c7989614e..3a3aa8842 100644 --- a/helm/DEVEL/mathml_editor/src/APushParser.hh +++ b/helm/DEVEL/mathml_editor/src/APushParser.hh @@ -24,19 +24,30 @@ #ifndef __APushParser_hh__ #define __APushParser_hh__ +#include + class APushParser { public: - APushParser(class ALogger& l) : logger(l), factory(0) { }; - APushParser(class ALogger& l, class AMathMLFactory& f) : logger(l), factory(&f) { }; - + APushParser(class ALogger& l) : logger(l), factory(0), freeze_level(0) { }; + APushParser(class ALogger& l, class AMathMLFactory& f) : logger(l), factory(&f), freeze_level(0) { }; virtual ~APushParser() { }; - virtual void push(const TToken&) = 0; + + virtual void reset(void); + virtual void push(const class TToken&) = 0; + virtual std::string drop(void) = 0; virtual void setCursorHint(const std::string&) = 0; + virtual bool freeze(void); + virtual bool thaw(void); + bool frozen(void) const { return freeze_level > 0; }; + protected: class ALogger& logger; class AMathMLFactory* factory; + +private: + unsigned freeze_level; }; #endif // __APushParser_hh__ diff --git a/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLT.cc b/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLT.cc index 244d3640b..2b714cb91 100644 --- a/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLT.cc +++ b/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLT.cc @@ -5,42 +5,48 @@ #include "CMathMLFactoryXSLT.hh" #include "AMathMLConsumer.hh" +CMathMLFactoryXSLT::CMathMLFactoryXSLT(ALogger& l, const DOMX::XSLTStylesheet& s) + : AMathMLFactory(l), style(s) +{ + reset(); +} + +void +CMathMLFactoryXSLT::reset() +{ + DOM::DOMImplementation di; + DOM::DocumentType dt; + result = di.createDocument(MATHML_NS_URI, "m:math", dt); +} + void CMathMLFactoryXSLT::documentModified(TDocument& doc) { if (TNode dirty = doc.dirtyNode()) { std::vector< std::pair > dirtyId; - if (result) + if (result.get_documentElement().hasAttribute("xref")) dirtyId.push_back(std::make_pair(DOM::GdomeString("id"), DOM::GdomeString("'" + std::string(dirty["id"]) + "'"))); DOM::Document res = style.apply(doc.document(), dirtyId); assert(res); - //style.save(doc.document(), stdout); - //style.save(res, stdout); - if (result) - { - DOM::Element root = res.get_documentElement(); - assert(root); - assert(root.hasAttribute("xref")); + style.save(doc.document(), stdout); + + DOM::Element root = res.get_documentElement(); + assert(root); + assert(root.hasAttribute("xref")); - try - { - bool ok = subst(result.get_documentElement(), root.getAttribute("xref"), result.importNode(root, true)); - assert(ok); - } - catch (DOM::DOMException& e) - { - cout << "!!!!!!!!!!!!!!!! EXCEPTION " << e.code << " " << e.msg << endl; - assert(0); - } + if (result.get_documentElement().hasAttribute("xref")) + { + bool ok = subst(result.get_documentElement(), root.getAttribute("xref"), result.importNode(root, true)); + assert(ok); } else - result = res; + result.replaceChild(result.importNode(root, true), result.get_documentElement()); + + style.save(result, stdout); doc.clearDirty(); - - if (consumer) consumer->documentModified(result); } } diff --git a/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLT.hh b/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLT.hh index 70998e092..9d129a378 100644 --- a/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLT.hh +++ b/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLT.hh @@ -2,22 +2,23 @@ #ifndef __CMathMLFactoryXSLT_hh__ #define __CMathMLFactoryXSLT_hh__ +#include #include "AMathMLFactory.hh" class CMathMLFactoryXSLT : public AMathMLFactory { public: - CMathMLFactoryXSLT(class ALogger& l, const DOM::XSLTStylesheet& s) : AMathMLFactory(l), style(s) { }; - CMathMLFactoryXSLT(class ALogger& l, class AMathMLConsumer& c, const DOM::XSLTStylesheet& s) : AMathMLFactory(l, c), style(s) { }; + CMathMLFactoryXSLT(class ALogger&, const class GdomeSmartDOMExt::XSLTStylesheet&); + virtual void reset(void); virtual void documentModified(class TDocument&); - virtual DOM::Document document(void) const { return result; }; + virtual GdomeSmartDOM::Document document(void) const { return result; }; private: - static bool subst(const DOM::Element& e1, const DOM::GdomeString& id, const DOM::Element& e2); + static bool subst(const GdomeSmartDOM::Element&, const GdomeSmartDOM::GdomeString&, const GdomeSmartDOM::Element&); - const DOM::XSLTStylesheet& style; - DOM::Document result; + const class GdomeSmartDOMExt::XSLTStylesheet& style; + GdomeSmartDOM::Document result; }; #endif // __CMathMLFactoryXSLT_hh__ diff --git a/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLTDiff.cc b/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLTDiff.cc new file mode 100644 index 000000000..53fa5aa36 --- /dev/null +++ b/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLTDiff.cc @@ -0,0 +1,87 @@ + +#include "dom.hh" +#include "Diff.hh" +#include "TNode.hh" +#include "TDocument.hh" +#include "CMathMLFactoryXSLTDiff.hh" +#include "AMathMLConsumer.hh" + +CMathMLFactoryXSLTDiff::CMathMLFactoryXSLTDiff(ALogger& l, const DOMX::XSLTStylesheet& s) + : AMathMLFactory(l), style(s) +{ + reset(); +} + +void +CMathMLFactoryXSLTDiff::reset() +{ + DOM::DOMImplementation di; + DOM::DocumentType dt; + result = di.createDocument(MATHML_NS_URI, "m:math", dt); +} + +void +CMathMLFactoryXSLTDiff::documentModified(TDocument& doc) +{ + if (TNode dirty = doc.dirtyNode()) + { + std::vector< std::pair > dirtyId; + if (false && result.get_documentElement().hasAttribute("xref")) + dirtyId.push_back(std::make_pair(DOM::GdomeString("id"), + DOM::GdomeString("'" + std::string(dirty["id"]) + "'"))); + DOM::Document res = style.apply(doc.document(), dirtyId); + assert(res); + //cout << "*** THE DIRTY FRAGMENT HAS ID = " << std::string(dirty["id"]) << endl; + //style.save(doc.document(), stdout); + cout << "*** THE CURRENT DOCUMENT:" << endl; + if (result) style.save(result, stdout); + cout << "*** THE NEW DOCUMENT:" << endl; + style.save(res, stdout); + cout << "*** THE DIFF:" << endl; + DOMX::Diff diff = DOMX::Diff::diff(result, res); + style.save(diff.document(), stdout); + diff.patch(); +#if 0 + DOM::Element root = res.get_documentElement(); + assert(root); + assert(root.hasAttribute("xref")); + if (result.get_documentElement().hasAttribute("xref")) + { + bool ok = subst(result.get_documentElement(), root.getAttribute("xref"), result.importNode(root, true)); + assert(ok); + } + else + result = res; +#endif + //style.save(result, stdout); + + doc.clearDirty(); + } +} + +bool +CMathMLFactoryXSLTDiff::subst(const DOM::Element& e1, const DOM::GdomeString& id, const DOM::Element& e2) +{ + assert(e1); + assert(e2); + if (e1.getAttribute("xref") == id) + { + DOMX::Diff diff = DOMX::Diff::diff(e1, e2); + style.save(diff.document(), stdout); + diff.patch(); + return true; + } + else + { + DOM::Node p = e1.get_firstChild(); + while (p) + { + while (p && p.get_nodeType() != DOM::Node::ELEMENT_NODE) p = p.get_nextSibling(); + if (p) + if (subst(p, id, e2)) return true; + else p = p.get_nextSibling(); + } + return false; + } +} + diff --git a/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLTDiff.hh b/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLTDiff.hh new file mode 100644 index 000000000..ac933b5d7 --- /dev/null +++ b/helm/DEVEL/mathml_editor/src/CMathMLFactoryXSLTDiff.hh @@ -0,0 +1,23 @@ + +#ifndef __CMathMLFactoryXSLTDiff_hh__ +#define __CMathMLFactoryXSLTDiff_hh__ + +#include "AMathMLFactory.hh" + +class CMathMLFactoryXSLTDiff : public AMathMLFactory +{ +public: + CMathMLFactoryXSLTDiff(class ALogger&, const DOMX::XSLTStylesheet&); + + virtual void reset(void); + virtual void documentModified(class TDocument&); + virtual DOM::Document document(void) const { return result; }; + +private: + bool subst(const DOM::Element& e1, const DOM::GdomeString& id, const DOM::Element& e2); + + const DOMX::XSLTStylesheet& style; + DOM::Document result; +}; + +#endif // __CMathMLFactoryXSLT_hh__ diff --git a/helm/DEVEL/mathml_editor/src/Diff.cc b/helm/DEVEL/mathml_editor/src/Diff.cc new file mode 100644 index 000000000..948baa6b6 --- /dev/null +++ b/helm/DEVEL/mathml_editor/src/Diff.cc @@ -0,0 +1,368 @@ + +#include +#include +#include +#include + +#include "Diff.hh" + +namespace GdomeSmartDOMExt +{ + + Diff + Diff::diff(const Document& dest, const Document& source, flatNodeEq flatEq) + { + assert(dest); + assert(source); + assert(flatEq); + + return diff(dest.get_documentElement(), source.get_documentElement(), flatEq); + } + + Diff + Diff::diff(const Element& dest, const Element& source, flatNodeEq flatEq) + { + assert(dest); + assert(source); + assert(flatEq); + + DOMImplementation di; + Document doc = di.createDocument(DDIFF_NS_URI, "diff:doc", DocumentType()); + Element root = doc.get_documentElement(); + root.setAttributeNS(XMLNS_NS_URI, "xmlns:diff", DDIFF_NS_URI); + + Diff diff(dest, doc, flatEq); + if (Node d = diff.diffNodes(dest, source)) root.appendChild(d); + else root.appendChild(doc.createElementNS(DDIFF_NS_URI, "diff:same")); + + return diff; + } + + struct NodeEqPredicate : std::binary_function + { + NodeEqPredicate(Diff::flatNodeEq e) : eq(e) { }; + bool operator()(const Node& n1, const Node& n2) const { return eq(n1, n2); }; + + private: + Diff::flatNodeEq eq; + }; + + std::vector + collectProperAttributes(const Node& n) + { + assert(n); + NamedNodeMap map = n.get_attributes(); + unsigned len = map.get_length(); + + std::vector res; + res.reserve(len); + for (unsigned i = 0; i < len; i++) + { + Node attr = map.item(i); + assert(attr); + if (attr.get_nodeName() != "xmlns" && attr.get_prefix() != "xmlns") res.push_back(attr); + } + + return res; + } + + bool + Diff::defaultFlatNodeEq(const Node& n1, const Node& n2) + { + assert(n1); + assert(n2); + + unsigned nodeType = n1.get_nodeType(); + if (nodeType != n2.get_nodeType()) return false; + + GdomeString ns1 = n1.get_namespaceURI(); + GdomeString ns2 = n2.get_namespaceURI(); + if (ns1 != ns2) return false; + + switch (nodeType) + { + case Node::ATTRIBUTE_NODE: + if (!ns1.null()) + { + assert(!ns2.null()); + if (n1.get_localName() != n2.get_localName()) return false; + } + else + { + assert(ns2.null()); + if (n1.get_nodeName() != n2.get_nodeName()) return false; + } + // WARNING: fallback for checking node value + case Node::TEXT_NODE: + case Node::CDATA_SECTION_NODE: + if (n1.get_nodeValue() != n2.get_nodeValue()) return false; + return true; + case Node::ELEMENT_NODE: + { + //cout << "comparing: " << n1.get_nodeName() << " ? " << n2.get_nodeName() << endl; + if (!ns1.null()) + { + assert(!ns2.null()); + if (n1.get_localName() != n2.get_localName()) return false; + } + else + { + assert(ns2.null()); + if (n1.get_nodeName() != n2.get_nodeName()) return false; + } +#if 1 + std::vector m1 = collectProperAttributes(n1); + std::vector m2 = collectProperAttributes(n2); + if (m1.size() != m2.size()) return false; + + for (unsigned i = 0; i < m1.size(); i++) + { + std::vector::iterator p2 = std::find_if(m2.begin(), m2.end(), std::bind2nd(NodeEqPredicate(defaultFlatNodeEq), m1[i])); + if (p2 == m2.end()) return false; + } +#endif + } + return true; + default: + return true; + } + + } + + void + Diff::sameChunk(const Node& res, unsigned long n) const + { + assert(n > 0); + Element s = doc.createElementNS(DDIFF_NS_URI, "diff:same"); + if (n != 1) + { + std::ostringstream os; + os << n; + s.setAttribute("count", os.str()); + } + res.appendChild(s); + } + + Node + Diff::diffNodes(const Node& p1, const Node& p2) const + { + if (eq(p1, p2)) + { + Element m = doc.createElementNS(DDIFF_NS_URI, "diff:merge"); + if (diffChildren(p1, p2, m)) return m; + else return Node(); + } + else + { + Element r = doc.createElementNS(DDIFF_NS_URI, "diff:replace"); + r.appendChild(doc.importNode(p2, true)); + return r; + } + } + + bool + Diff::diffChildren(const Node& n1, const Node& n2, const Node& res) const + { + assert(n1); + assert(n2); + assert(res); + + Node p1 = n1.get_firstChild(); + Node p2 = n2.get_firstChild(); + bool same = true; + unsigned nSame = 0; + while (p1 && p2) + { + if (Node d = diffNodes(p1, p2)) + { + same = false; + if (nSame > 0) + { + sameChunk(res, nSame); + nSame = 0; + } + res.appendChild(d); + } + else + nSame++; + + p1 = p1.get_nextSibling(); + p2 = p2.get_nextSibling(); + } + + if (p1) + { + same = false; + if (nSame > 0) + { + sameChunk(res, nSame); + nSame = 0; + } + + unsigned nRemoved = 0; + while (p1) + { + nRemoved++; + p1 = p1.get_nextSibling(); + } + + if (nRemoved > 0) + { + Element r = doc.createElementNS(DDIFF_NS_URI, "diff:remove"); + if (nRemoved > 1) + { + std::ostringstream os; + os << nRemoved; + r.setAttribute("count", os.str()); + } + res.appendChild(r); + } + } + + if (p2) + { + same = false; + if (nSame > 0) + { + sameChunk(res, nSame); + nSame = 0; + } + + Element i = doc.createElementNS(DDIFF_NS_URI, "diff:insert"); + while (p2) + { + i.appendChild(doc.importNode(p2, true)); + p2 = p2.get_nextSibling(); + } + res.appendChild(i); + } + + return !same; + } + + static Node + getFirstElement(const Node& n) + { + Node p = n.get_firstChild(); + while (p && p.get_nodeType() != Node::ELEMENT_NODE) + p = p.get_nextSibling(); + return p; + } + + static Node + getNextElement(const Node& n) + { + Node p = n.get_nextSibling(); + while (p && p.get_nodeType() != Node::ELEMENT_NODE) + p = p.get_nextSibling(); + return p; + } + + void + Diff::patchRootNode(const Node& node, const Element& elem) const + { + GdomeString name = elem.get_localName(); + if (name == "same") + { + if (elem.hasAttribute("count")) + { + unsigned count; + istringstream is(elem.getAttribute("count")); + is >> count; + assert(count == 1); + } + } + else if (name == "replace") + { + Document d1 = node.get_ownerDocument(); + Node parent = node.get_parentNode(); + assert(parent); +#if 0 + /* the following patch is because of gdome2 bug that prevents from + * replacing the root element of a document. + */ + assert(!node.get_previousSibling()); + assert(!node.get_nextSibling()); + parent.removeChild(node); + parent.appendChild(d1.importNode(getFirstElement(elem), true)); +#endif + parent.replaceChild(d1.importNode(getFirstElement(elem), true), node); + } + else if (name == "merge") + patchChildren(node, elem); + else + assert(0); + } + + void + Diff::patchChildren(const Node& n1, const Element& e2) const + { + Node p1 = n1.get_firstChild(); + Element p2 = getFirstElement(e2); + while (p2) + { + GdomeString name = p2.get_localName(); + if (name == "same") + { + unsigned count = 1; + if (p2.hasAttribute("count")) + { + istringstream is(p2.getAttribute("count")); + is >> count; + } + while (count-- > 0) + { + if (!p1) throw BADDiff("too few nodes in original document (same)"); + p1 = p1.get_nextSibling(); + } + } + else if (name == "replace") + { + Document d1 = n1.get_ownerDocument(); + if (!p1) throw BADDiff("no node to replace in original document"); + Node next = p1.get_nextSibling(); + n1.replaceChild(d1.importNode(p2.get_firstChild(), true), p1); + p1 = next; + } + else if (name == "insert") + { + Document d1 = n1.get_ownerDocument(); + for (Node i = p2.get_firstChild(); i; i = i.get_nextSibling()) + n1.insertBefore(d1.importNode(i, true), p1); + } + else if (name == "merge") + { + if (!p1) throw BADDiff("no node to merge in original document"); + patchChildren(p1, p2); + p1 = p1.get_nextSibling(); + } + else if (name == "remove") + { + unsigned count = 1; + if (p2.hasAttribute("count")) + { + istringstream is(p2.getAttribute("count")); + is >> count; + } + while (count-- > 0) + { + if (!p1) throw BADDiff("too few nodes in original document (remove)"); + Node next = p1.get_nextSibling(); + n1.removeChild(p1); + p1 = next; + } + } + else + assert(0); + + p2 = getNextElement(p2); + } + } + + void + Diff::patch() const + { + patchRootNode(dest, getFirstElement(doc.get_documentElement())); + } + +} diff --git a/helm/DEVEL/mathml_editor/src/Diff.hh b/helm/DEVEL/mathml_editor/src/Diff.hh new file mode 100644 index 000000000..099314bdd --- /dev/null +++ b/helm/DEVEL/mathml_editor/src/Diff.hh @@ -0,0 +1,53 @@ + +#ifndef __Diff_hh__ +#define __Diff_hh__ + +#include + +#define XMLNS_NS_URI "http://www.w3.org/2000/xmlns/" +#define DDIFF_NS_URI "http://helm.cs.unibo.it/2002/DDIFF" + +namespace GdomeSmartDOMExt +{ + + using namespace GdomeSmartDOM; + + class Diff + { + public: + typedef bool (*flatNodeEq)(const Node&, const Node&); + static bool defaultFlatNodeEq(const Node&, const Node&); + + private: + Diff(const Node& n, const Document& d, flatNodeEq e) : dest(n), doc(d), eq(e) { }; + + public: + static Diff diff(const Document&, const Document&, flatNodeEq = defaultFlatNodeEq); + static Diff diff(const Element&, const Element&, flatNodeEq = defaultFlatNodeEq); + + Document document(void) const { return doc; }; + Node node(void) const { return dest; }; + + void patch(void) const; + + struct BADDiff + { + BADDiff(const std::string& s) : msg(s) { }; + const std::string msg; + }; + + private: + Node diffNodes(const Node&, const Node&) const; + bool diffChildren(const Node&, const Node&, const Node&) const; + void sameChunk(const Node&, unsigned long) const; + void patchRootNode(const Node&, const Element&) const; + void patchChildren(const Node&, const Element&) const; + + Document doc; + Node dest; + flatNodeEq eq; + }; + +} + +#endif // __ddiff_hh__ diff --git a/helm/DEVEL/mathml_editor/src/Makefile.am b/helm/DEVEL/mathml_editor/src/Makefile.am index c0afe28ee..bfb6b97b6 100644 --- a/helm/DEVEL/mathml_editor/src/Makefile.am +++ b/helm/DEVEL/mathml_editor/src/Makefile.am @@ -4,22 +4,27 @@ lib_LTLIBRARIES = libeditex.la libeditex_la_LDFLAGS = -version-info @EDITEX_VERSION_INFO@ libeditex_la_SOURCES = \ + Diff.cc \ CLoggerConsole.cc \ TPushLexer.cc \ + APushParser.cc \ TPushParser.cc \ CMathMLFactoryXSLT.cc \ + CMathMLFactoryXSLTDiff.cc \ TDictionary.cc \ TDocument.cc \ TNode.cc \ TTokenizer.cc pkginclude_HEADERS = \ + Diff.hh \ ALogger.hh \ CLoggerConsole.hh \ APushLexer.hh \ APushParser.hh \ AMathMLFactory.hh \ CMathMLFactoryXSLT.hh \ + CMathMLFactoryXSLTDiff.hh \ TPushLexer.hh \ TPushParser.hh \ TTokenizer.hh \ diff --git a/helm/DEVEL/mathml_editor/src/Makefile.in b/helm/DEVEL/mathml_editor/src/Makefile.in index 0592ae444..4cd204308 100644 --- a/helm/DEVEL/mathml_editor/src/Makefile.in +++ b/helm/DEVEL/mathml_editor/src/Makefile.in @@ -74,12 +74,26 @@ GMETADOM_CFLAGS = @GMETADOM_CFLAGS@ GMETADOM_LIBS = @GMETADOM_LIBS@ GTKMATHVIEW_CFLAGS = @GTKMATHVIEW_CFLAGS@ GTKMATHVIEW_LIBS = @GTKMATHVIEW_LIBS@ +HAVE_OCAMLC = @HAVE_OCAMLC@ +HAVE_OCAMLDEP = @HAVE_OCAMLDEP@ +HAVE_OCAMLFIND = @HAVE_OCAMLFIND@ +HAVE_OCAMLMKLIB = @HAVE_OCAMLMKLIB@ +HAVE_OCAMLOPT = @HAVE_OCAMLOPT@ LDFLAGS = @LDFLAGS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ MAKEINFO = @MAKEINFO@ +MLGDOME_CFLAGS = @MLGDOME_CFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OCAMLC = @OCAMLC@ +OCAMLDEP = @OCAMLDEP@ +OCAMLFIND = @OCAMLFIND@ +OCAMLMKLIB = @OCAMLMKLIB@ +OCAMLOPT = @OCAMLOPT@ +OCAMLSTDLIBDIR = @OCAMLSTDLIBDIR@ +OCAMLSTUBDIR = @OCAMLSTUBDIR@ +OCAML_INCLUDE_DIR = @OCAML_INCLUDE_DIR@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ STRIP = @STRIP@ @@ -89,10 +103,10 @@ lib_LTLIBRARIES = libeditex.la libeditex_la_LDFLAGS = -version-info @EDITEX_VERSION_INFO@ -libeditex_la_SOURCES = CLoggerConsole.cc TPushLexer.cc TPushParser.cc CMathMLFactoryXSLT.cc TDictionary.cc TDocument.cc TNode.cc TTokenizer.cc +libeditex_la_SOURCES = Diff.cc CLoggerConsole.cc TPushLexer.cc APushParser.cc TPushParser.cc CMathMLFactoryXSLT.cc CMathMLFactoryXSLTDiff.cc TDictionary.cc TDocument.cc TNode.cc TTokenizer.cc -pkginclude_HEADERS = ALogger.hh CLoggerConsole.hh APushLexer.hh APushParser.hh AMathMLFactory.hh CMathMLFactoryXSLT.hh TPushLexer.hh TPushParser.hh TTokenizer.hh TDictionary.hh TDocument.hh TNode.hh TListener.hh dom.hh +pkginclude_HEADERS = Diff.hh ALogger.hh CLoggerConsole.hh APushLexer.hh APushParser.hh AMathMLFactory.hh CMathMLFactoryXSLT.hh CMathMLFactoryXSLTDiff.hh TPushLexer.hh TPushParser.hh TTokenizer.hh TDictionary.hh TDocument.hh TNode.hh TListener.hh dom.hh INCLUDES = $(GMETADOM_CFLAGS) $(GDOMEXSLT_CFLAGS) @@ -105,8 +119,9 @@ LTLIBRARIES = $(lib_LTLIBRARIES) DEFS = @DEFS@ -I. -I$(srcdir) -I.. LIBS = @LIBS@ libeditex_la_LIBADD = -libeditex_la_OBJECTS = CLoggerConsole.lo TPushLexer.lo TPushParser.lo \ -CMathMLFactoryXSLT.lo TDictionary.lo TDocument.lo TNode.lo \ +libeditex_la_OBJECTS = Diff.lo CLoggerConsole.lo TPushLexer.lo \ +APushParser.lo TPushParser.lo CMathMLFactoryXSLT.lo \ +CMathMLFactoryXSLTDiff.lo TDictionary.lo TDocument.lo TNode.lo \ TTokenizer.lo CXXFLAGS = @CXXFLAGS@ CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) @@ -122,7 +137,8 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best -DEP_FILES = .deps/CLoggerConsole.P .deps/CMathMLFactoryXSLT.P \ +DEP_FILES = .deps/APushParser.P .deps/CLoggerConsole.P \ +.deps/CMathMLFactoryXSLT.P .deps/CMathMLFactoryXSLTDiff.P .deps/Diff.P \ .deps/TDictionary.P .deps/TDocument.P .deps/TNode.P .deps/TPushLexer.P \ .deps/TPushParser.P .deps/TTokenizer.P SOURCES = $(libeditex_la_SOURCES) diff --git a/helm/DEVEL/mathml_editor/src/TDictionary.cc b/helm/DEVEL/mathml_editor/src/TDictionary.cc index 8c16d2ba9..3cf233487 100644 --- a/helm/DEVEL/mathml_editor/src/TDictionary.cc +++ b/helm/DEVEL/mathml_editor/src/TDictionary.cc @@ -9,11 +9,19 @@ static TDictionary::Entry undefinedEntry; void -TDictionary::load(const char* uri) +TDictionary::load(const std::string& uri) { + logger.debug("Dictionary: loading `" + uri + "'"); + DOM::DOMImplementation di; + DOM::Document doc = di.createDocumentFromURI(uri.c_str()); + assert(doc); + load(doc); +} - DOM::Document doc = di.createDocumentFromURI(uri); +void +TDictionary::load(const DOM::Document& doc) +{ assert(doc); DOM::Element root = doc.get_documentElement(); @@ -23,7 +31,17 @@ TDictionary::load(const char* uri) TTokenizer tokenizer(logger); for (DOM::Node p = root.get_firstChild(); p; p = p.get_nextSibling()) - if (p.get_nodeType() == DOM::Node::ELEMENT_NODE && p.get_nodeName() == "entry") + if (p.get_nodeType() == DOM::Node::ELEMENT_NODE && p.get_nodeName() == "include") + { + DOM::Element el = p; + assert(el); + if (el.hasAttribute("href")) + // WARNING: this may result into an infinite loop! + load(std::string(el.getAttribute("href"))); + else + logger.warning("Dictionary: include statement with no href attribute (ignored)"); + } + else if (p.get_nodeType() == DOM::Node::ELEMENT_NODE && p.get_nodeName() == "entry") { DOM::Element el = p; assert(el); @@ -31,7 +49,7 @@ TDictionary::load(const char* uri) std::string name = el.getAttribute("name"); if (entries.find(name) != entries.end()) - cerr << "WARNING: entry `" << name << "' is being redefined" << endl; + logger.info("Dictionary: `" + name + "' is being redefined"); Entry entry; @@ -50,13 +68,13 @@ TDictionary::load(const char* uri) { entry.value = el.getAttribute("val"); if (entry.cls == MACRO) - cerr << "WARNING: `" << name << "' has a specified value, but is classified as macro" << endl; + logger.warning("Dictionary: `" + name + "' has a specified value, but is classified as macro"); } if (el.hasAttribute("pattern")) { if (entry.cls != MACRO) - cerr << "WARNING: `" << name << "' has a specified pattern, but is not classified as macro" << endl; + logger.warning("Dictionary: `" + name + "' has a specified pattern, but is not classified as macro"); std::string pattern = el.getAttribute("pattern"); if (pattern == "{}") @@ -69,6 +87,7 @@ TDictionary::load(const char* uri) entry.pattern = tokenizer.tokenize(pattern); } +#if 0 if (el.hasAttribute("infix")) { std::istringstream is(el.getAttribute("infix")); @@ -104,6 +123,7 @@ TDictionary::load(const char* uri) if (!el.hasAttribute("prefix")) entry.prefix = postfix; } } +#endif if (el.hasAttribute("limits")) { @@ -124,7 +144,7 @@ TDictionary::load(const char* uri) if (el.hasAttribute("delimiter")) { if (entry.cls != OPERATOR && !entry.embellishment) - cerr << "WARNING: `" << name << "' delimiter ignored for non-operator" << endl; + logger.warning("Dictionary: `" + name + "' delimiter ignored for non-operator"); std::istringstream is(el.getAttribute("delimiter")); unsigned delimiter; @@ -135,7 +155,7 @@ TDictionary::load(const char* uri) if (el.hasAttribute("table")) { if (entry.cls != MACRO) - cerr << "WARNING: `" << name << "' table ignored for non-macro" << endl; + logger.warning("Dictionary: `" + name + "' table ignored for non-macro"); std::istringstream is(el.getAttribute("table")); unsigned table; diff --git a/helm/DEVEL/mathml_editor/src/TDictionary.hh b/helm/DEVEL/mathml_editor/src/TDictionary.hh index b769aaa4e..5349cf004 100644 --- a/helm/DEVEL/mathml_editor/src/TDictionary.hh +++ b/helm/DEVEL/mathml_editor/src/TDictionary.hh @@ -2,16 +2,19 @@ #ifndef __TDictionary_hh__ #define __TDictionary_hh__ +#include + #include #include #include +#include "dom.hh" #include "TToken.hh" class TDictionary { public: - TDictionary(void) { }; + TDictionary(class ALogger& l) : logger(l) { }; ~TDictionary() { }; enum Form @@ -35,7 +38,6 @@ public: Entry(void) { cls = UNDEFINED; - infix = prefix = postfix = 0; table = delimiter = limits = embellishment = leftOpen = rightOpen = 0; }; @@ -49,9 +51,6 @@ public: unsigned previousParam(unsigned) const; EntryClass cls; - unsigned infix : 8; - unsigned prefix : 8; - unsigned postfix : 8; unsigned delimiter : 1; unsigned limits : 1; unsigned embellishment : 1; @@ -60,7 +59,8 @@ public: unsigned table : 1; }; - void load(const char* uri); + void load(const std::string& uri); + void load(const DOM::Document& doc); const Entry& find(const std::string&) const; private: @@ -72,7 +72,14 @@ private: { bool operator()(const std::string&, const class String*) const; }; #endif + class ALogger& logger; +#if defined(HAVE_EXT_HASH_MAP) + typedef __gnu_cxx::hash_map< std::string, Entry, StringHash > Dictionary; +#elif defined(HAVE_HASH_MAP) typedef std::hash_map< std::string, Entry, StringHash > Dictionary; +#else +#error "no hash_map could be found" +#endif Dictionary entries; }; diff --git a/helm/DEVEL/mathml_editor/src/TDocument.cc b/helm/DEVEL/mathml_editor/src/TDocument.cc index a7b5c8d3a..e578b79f4 100644 --- a/helm/DEVEL/mathml_editor/src/TDocument.cc +++ b/helm/DEVEL/mathml_editor/src/TDocument.cc @@ -34,16 +34,19 @@ TDocument::serialize(const char* filename) const di.saveDocumentToFile(doc, filename, GDOME_SAVE_LIBXML_INDENT); } +std::string +TDocument::makeId(unsigned id) +{ + ostringstream os; + os << "I" << id; + return os.str(); +} + TNode TDocument::create(const std::string& name, unsigned id) const { DOM::Element elem = doc.createElementNS(TML_NS_URI, "tml:" + name); - if (id > 0) - { - ostringstream os; - os << "I" << id; - elem.setAttribute("id", os.str()); - } + if (id > 0) elem.setAttribute("id", makeId(id)); return elem; } @@ -130,6 +133,24 @@ TDocument::findIdNode(const DOM::Node& node) return DOM::Node(0); } +TNode +TDocument::getNodeByIdAux(const TNode& node, const std::string& id) +{ + if (node.hasId(id)) return node; + else + for (TNode p = node.first(); p; p = p.next()) + if (TNode res = getNodeByIdAux(p, id)) return res; + return TNode(); +} + +TNode +TDocument::getNodeById(unsigned id) const +{ + DOM::Element root = doc.get_documentElement(); + assert(root); + return getNodeByIdAux(root, makeId(id)); +} + void TDocument::handleEvent(const DOM::Event& ev) { diff --git a/helm/DEVEL/mathml_editor/src/TDocument.hh b/helm/DEVEL/mathml_editor/src/TDocument.hh index cf4b7c391..b1ca562c6 100644 --- a/helm/DEVEL/mathml_editor/src/TDocument.hh +++ b/helm/DEVEL/mathml_editor/src/TDocument.hh @@ -21,6 +21,7 @@ public: DOM::Document document(void) const { return doc; }; + TNode getNodeById(unsigned) const; TNode root(void) { return doc.get_documentElement(); }; TNode dirtyNode(void) const { return dirty; }; void clearDirty(void) { dirty = DOM::Element(0); }; @@ -32,6 +33,8 @@ private: DOM::Element dirty; virtual void handleEvent(const DOM::Event&); + static std::string makeId(unsigned); + static TNode getNodeByIdAux(const TNode&, const std::string&); static unsigned nodeDepth(const DOM::Node&); static DOM::Node findCommonAncestor(const DOM::Node&, const DOM::Node&); static DOM::Node findIdNode(const DOM::Node&); diff --git a/helm/DEVEL/mathml_editor/src/TNode.hh b/helm/DEVEL/mathml_editor/src/TNode.hh index b2c68fa69..c9f85b8f8 100644 --- a/helm/DEVEL/mathml_editor/src/TNode.hh +++ b/helm/DEVEL/mathml_editor/src/TNode.hh @@ -64,6 +64,7 @@ public: std::string name(void) const { return node.get_localName(); }; std::string nameC(void) const { return node.getAttribute("name"); }; bool hasId(void) const { return node.hasAttribute("id"); }; + bool hasId(const std::string& id) const { return node.getAttribute("id") == id; }; bool is(const std::string& s) const { return name() == s; }; bool isG(void) const { return is("g"); }; bool isSb(void) const { return is("sb"); }; diff --git a/helm/DEVEL/mathml_editor/src/TPushLexer.cc b/helm/DEVEL/mathml_editor/src/TPushLexer.cc index 1d25abbe9..c8d04f1bd 100644 --- a/helm/DEVEL/mathml_editor/src/TPushLexer.cc +++ b/helm/DEVEL/mathml_editor/src/TPushLexer.cc @@ -55,7 +55,6 @@ TPushLexer::push(char ch) case ACCEPT: if (ch == '\\') state = ESCAPE; else if (ch == '#') state = PARAMETER; - else if (ch == '\b') parser.push(TToken(TToken::GDELETE)); else if (ch == -1) ; else transaction(ch, ACCEPT); break; @@ -65,10 +64,6 @@ TPushLexer::push(char ch) buffer.push_back(ch); state = MACRO; } - else if (ch == '\b') - { - state = ACCEPT; - } else if (ch == -1) error(); else { @@ -89,11 +84,6 @@ TPushLexer::push(char ch) buffer.erase(); state = PARAMETER; } - else if (ch == '\b') - { - buffer.erase(buffer.length() - 1, 1); - if (buffer.length() == 0) state = ESCAPE; - } else if (isalpha(ch)) buffer.push_back(ch); else if (ch == -1) @@ -114,7 +104,6 @@ TPushLexer::push(char ch) if (ch == '\\') state = ESCAPE; else if (ch == '#') state = PARAMETER; else if (isspace(ch)) ; - else if (ch == '\b') parser.push(TToken(TToken::GDELETE)); else if (ch == -1) state = ACCEPT; else transaction(ch, ACCEPT); break; @@ -140,6 +129,45 @@ TPushLexer::push(char ch) } } +void +TPushLexer::drop(bool alt) +{ + std::string restore = ""; + + switch (state) + { + case ACCEPT: + case IGNORE_SPACE: + restore = parser.drop(); + if (restore.length() > 0 && restore[0] == '\\') + { + buffer = std::string(restore, 1, restore.length() - 1); + state = (buffer.length() > 0) ? MACRO : ESCAPE; + } + break; + case ESCAPE: + state = ACCEPT; + break; + case MACRO: + if (alt) buffer.erase(); + else buffer.erase(buffer.length() - 1, 1); + if (buffer.length() == 0) state = ESCAPE; + break; + case PARAMETER: + default: + assert(0); + break; + } + + switch (state) + { + case ESCAPE: parser.setCursorHint("\\"); break; + case MACRO: parser.setCursorHint("\\" + buffer); break; + case PARAMETER: parser.setCursorHint("#"); break; + default: parser.setCursorHint(""); break; + } +} + bool TPushLexer::error() const { diff --git a/helm/DEVEL/mathml_editor/src/TPushLexer.hh b/helm/DEVEL/mathml_editor/src/TPushLexer.hh index a12a9bf63..f2f409158 100644 --- a/helm/DEVEL/mathml_editor/src/TPushLexer.hh +++ b/helm/DEVEL/mathml_editor/src/TPushLexer.hh @@ -13,6 +13,7 @@ public: virtual ~TPushLexer() { }; virtual void push(char); + virtual void drop(bool = false); virtual void reset(void); virtual void flush(void); virtual bool error(void) const; diff --git a/helm/DEVEL/mathml_editor/src/TPushParser.cc b/helm/DEVEL/mathml_editor/src/TPushParser.cc index 62a9208e6..906e8f414 100644 --- a/helm/DEVEL/mathml_editor/src/TPushParser.cc +++ b/helm/DEVEL/mathml_editor/src/TPushParser.cc @@ -5,27 +5,27 @@ TPushParser::TPushParser(ALogger& l, const TDictionary& d) : APushParser(l), dictionary(d) { - init(); + reset(); } TPushParser::TPushParser(ALogger& l, AMathMLFactory& f, const TDictionary& d) : APushParser(l, f), dictionary(d) { - init(); + reset(); +} + +TPushParser::~TPushParser() +{ } void -TPushParser::init() +TPushParser::reset() { + APushParser::reset(); nextId = 1; cursor = doc.create("cursor"); cursor["id"] = "I0"; doc.clearDirty(); doc.root().append(cursor); - logger.verbosity(ALogger::Debug); -} - -TPushParser::~TPushParser() -{ } std::string @@ -1233,159 +1233,156 @@ TPushParser::process(const TToken& token) case TToken::ACTIVE: do_active(token.value); break; case TToken::COMMENT: do_comment(); break; case TToken::CONTROL: do_control(token.value); break; - case TToken::GDELETE: do_gdelete(); break; } } void TPushParser::push(const TToken& token) { - if (token.category == TToken::GDELETE) - { - process(token); - } - else - { - - TNode parent = cursor.parent(); - // If the cursor has no parent then it is detached from the editing - // tree, which means this token will be ignored - - if (parent) - // If the parent is a phantom group and the grand-parent is a - // control sequence, there are two cases: - // a. we are parsing a delimited argument of a entry - // b. we are parsing a side of a right- or left-open entry - if (parent.isG() && !parent.hasId() && parent.parent().isC()) - { - // There must be an open frame, for the grand-parent is a control sequence - assert(!frames.empty()); - Frame& frame = frames.top(); - if (!frame.entry.pattern.empty()) + TNode parent = cursor.parent(); + // If the cursor has no parent then it is detached from the editing + // tree, which means this token will be ignored + + if (parent) + // If the parent is a phantom group and the grand-parent is a + // control sequence, there are two cases: + // a. we are parsing a delimited argument of a entry + // b. we are parsing a side of a right- or left-open entry + if (parent.isG() && !parent.hasId() && parent.parent().isC()) + { + // There must be an open frame, for the grand-parent is a control sequence + assert(!frames.empty()); + Frame& frame = frames.top(); + if (!frame.entry.pattern.empty()) + { + // The entry pattern is not empty. By our conventions this means + // the entry cannot be open at either end, hence we are parsing + // a delimited argument + assert(frame.pos + 1 < frame.entry.pattern.size()); + assert(frame.entry.pattern[frame.pos + 1].category != TToken::PARAMETER); + if (frame.entry.pattern[frame.pos + 1] == token) { - // The entry pattern is not empty. By our conventions this means - // the entry cannot be open at either end, hence we are parsing - // a delimited argument - assert(frame.pos + 1 < frame.entry.pattern.size()); - assert(frame.entry.pattern[frame.pos + 1].category != TToken::PARAMETER); - if (frame.entry.pattern[frame.pos + 1] == token) - { - // The token matches with a delimiter of the argument, - // so we increment the frame.pos + // The token matches with a delimiter of the argument, + // so we increment the frame.pos + frame.pos++; + + if (frame.entry.lastDelimiter(frame.pos)) + { + // this delimiter is the last one for the argumet, + // so the argument is completed + cursor.remove(); frame.pos++; - if (frame.entry.lastDelimiter(frame.pos)) + if (frame.pos == frame.entry.pattern.size()) { - // this delimiter is the last one for the argumet, - // so the argument is completed - cursor.remove(); - frame.pos++; - - if (frame.pos == frame.entry.pattern.size()) - { - // This token has completed the entry - advance(parent); - } - else if (frame.entry.paramDelimited(frame.pos)) - { - // For the next is a delimited argument we have to place - // a suitable phantom group with the cursor inside - TNode g = doc.createG(); - parent.parent().append(g); - g.append(cursor); - } - else - parent.parent().append(cursor); + // This token has completed the entry + advance(parent); } - } - else - { - // Delimiter mismatch. - if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER) + else if (frame.entry.paramDelimited(frame.pos)) { - // in this case, there is a sequence of delimiters that delimitates - // the argument, and the user correctly inserted a portion of this - // sequence, but now has inserted a wrong delimiter. - // Here, there are some possibilities: - // - ignore the token, and wait for the correct delimiter - // - ignore the token, wait for the correct delimiter and emit an error - // At the moment, we implement the second possibily - logger.error("parser: it's not the correct delimiter...you have to type " + frame.entry.pattern[frame.pos + 1].value); + // For the next is a delimited argument we have to place + // a suitable phantom group with the cursor inside + TNode g = doc.createG(); + parent.parent().append(g); + g.append(cursor); } else - { - // in this case, the sequence of delimiters is composed of one - // delimiter. It means that we have to process the token - process(token); - } - } + parent.parent().append(cursor); + } } else { - // The entry pattern is empty, hence we are parsing a right-open - // entry. What happens if we actually are in the left side? - // This could happen only when re-editing an entered expression - // We'll see... - assert(frame.entry.rightOpen); - process(token); - } - } - else if (parent.isC()) - { - // We are parsing a non-delimited argument entry - // or a fixed token - Frame& frame = frames.top(); - assert(frame.pos < frame.entry.pattern.size()); - - if (frame.entry.pattern[frame.pos].category == TToken::PARAMETER) - { - // As by the TeX parsing rules of undelimited parameters, - // empty spaces are ignored - if (token.category != TToken::SPACE) - { - // We need to increase the frame position here, becase inside - // process the function advance will be called. At that point - // it will be important for the parser to know that the entry - // has been completed in order to place the cursor correctly - // in the next position - frame.pos++; + // Delimiter mismatch. + if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER) + { + // in this case, there is a sequence of delimiters that delimitates + // the argument, and the user correctly inserted a portion of this + // sequence, but now has inserted a wrong delimiter. + // Here, there are some possibilities: + // - ignore the token, and wait for the correct delimiter + // - ignore the token, wait for the correct delimiter and emit an error + // At the moment, we implement the second possibily + logger.error("parser: it's not the correct delimiter...you have to type " + frame.entry.pattern[frame.pos + 1].value); + } + else + { + // in this case, the sequence of delimiters is composed of one + // delimiter. It means that we have to process the token process(token); - } + } } - else if (frame.entry.pattern[frame.pos] == token) + } + else + { + // The entry pattern is empty, hence we are parsing a right-open + // entry. What happens if we actually are in the left side? + // This could happen only when re-editing an entered expression + // We'll see... + assert(frame.entry.rightOpen); + process(token); + } + } + else if (parent.isC()) + { + // We are parsing a non-delimited argument entry + // or a fixed token + Frame& frame = frames.top(); + assert(frame.pos < frame.entry.pattern.size()); + + if (frame.entry.pattern[frame.pos].category == TToken::PARAMETER) + { + // As by the TeX parsing rules of undelimited parameters, + // empty spaces are ignored + if (token.category != TToken::SPACE) { - // The token has been accepted - frame.pos++; - if (frame.pos < frame.entry.pattern.size() && - frame.entry.paramDelimited(frame.pos)) - { - // If the next is a delimited argument we have to place - // the phantom group with the cursor inside - TNode g = doc.createG(); - cursor.replace(g); - g.append(cursor); - } - else - advance(parent); + // We need to increase the frame position here, becase inside + // process the function advance will be called. At that point + // it will be important for the parser to know that the entry + // has been completed in order to place the cursor correctly + // in the next position + frame.pos++; + process(token); } - else + } + else if (frame.entry.pattern[frame.pos] == token) + { + // The token has been accepted + frame.pos++; + if (frame.pos < frame.entry.pattern.size() && + frame.entry.paramDelimited(frame.pos)) { - // There is a mismatch. Emit an error and ignore the token? - logger.debug("parser: token ignored: " + token.value); + // If the next is a delimited argument we have to place + // the phantom group with the cursor inside + TNode g = doc.createG(); + cursor.replace(g); + g.append(cursor); } + else + advance(parent); + } + else + { + // There is a mismatch. Emit an error and ignore the token? + logger.debug("parser: token ignored: " + token.value); + } - } - else - process(token); - else - { - logger.warning("ignored token"); - } - - } // this end corresponds to the else of the if (token.category == TToken::GDELETE) + } + else + process(token); + else + { + logger.warning("ignored token"); + } - if (factory) factory->documentModified(doc); + if (factory && doc.dirtyNode() && !frozen()) factory->documentModified(doc); +} +std::string +TPushParser::drop() +{ + do_gdelete(); + if (factory && doc.dirtyNode() && !frozen()) factory->documentModified(doc); + return ""; } void @@ -1426,6 +1423,21 @@ TPushParser::advance(const TNode& node) void TPushParser::setCursorHint(const std::string& c) { - cursor["val"] = c; - if (factory) factory->documentModified(doc); + if (cursor["val"] != c) + { + cursor["val"] = c; + if (factory && doc.dirtyNode() && !frozen()) factory->documentModified(doc); + } +} + +bool +TPushParser::thaw() +{ + if (APushParser::thaw() && factory && doc.dirtyNode()) + { + factory->documentModified(doc); + return true; + } + else + return false; } diff --git a/helm/DEVEL/mathml_editor/src/TPushParser.hh b/helm/DEVEL/mathml_editor/src/TPushParser.hh index e852bc607..b01524be4 100644 --- a/helm/DEVEL/mathml_editor/src/TPushParser.hh +++ b/helm/DEVEL/mathml_editor/src/TPushParser.hh @@ -17,15 +17,16 @@ public: TPushParser(class ALogger&, class AMathMLFactory&, const class TDictionary&); virtual ~TPushParser(); + virtual void reset(void); virtual void push(const TToken&); + virtual std::string drop(void); virtual void setCursorHint(const std::string&); -protected: - TDocument document(void) const { return doc; } + virtual bool thaw(void); -private: - void init(void); + DOM::Document document(void) const { return doc.document().cloneNode(true); } +private: std::string PRIME(void) const; bool isPrimes(const TNode&) const; diff --git a/helm/DEVEL/mathml_editor/src/TToken.hh b/helm/DEVEL/mathml_editor/src/TToken.hh index bf19fb187..1cb6ca15e 100644 --- a/helm/DEVEL/mathml_editor/src/TToken.hh +++ b/helm/DEVEL/mathml_editor/src/TToken.hh @@ -22,8 +22,7 @@ struct TToken OTHER, ACTIVE, COMMENT, - CONTROL, - GDELETE + CONTROL }; TToken(TCat c) : category(c) { }; diff --git a/helm/DEVEL/mathml_editor/src/TTokenizer.cc b/helm/DEVEL/mathml_editor/src/TTokenizer.cc index cfa10ec71..1002733a7 100644 --- a/helm/DEVEL/mathml_editor/src/TTokenizer.cc +++ b/helm/DEVEL/mathml_editor/src/TTokenizer.cc @@ -30,3 +30,9 @@ TTokenizer::push(const TToken& token) tokens.push_back(token); } +std::string +TTokenizer::drop() +{ + assert(0); + return ""; +} diff --git a/helm/DEVEL/mathml_editor/src/TTokenizer.hh b/helm/DEVEL/mathml_editor/src/TTokenizer.hh index 54618c88b..62d08241c 100644 --- a/helm/DEVEL/mathml_editor/src/TTokenizer.hh +++ b/helm/DEVEL/mathml_editor/src/TTokenizer.hh @@ -18,6 +18,7 @@ public: private: virtual void push(const TToken&); + virtual std::string drop(void); virtual void setCursorHint(const std::string&) { }; std::list tokens; diff --git a/helm/DEVEL/mathml_editor/src/dom.hh b/helm/DEVEL/mathml_editor/src/dom.hh index a2058302e..f31ecffb2 100644 --- a/helm/DEVEL/mathml_editor/src/dom.hh +++ b/helm/DEVEL/mathml_editor/src/dom.hh @@ -6,6 +6,7 @@ #include namespace DOM = GdomeSmartDOM; +namespace DOMX = GdomeSmartDOMExt; typedef DOM::Char32 TChar; typedef DOM::UCS4String TString; diff --git a/helm/DEVEL/mathml_editor/src/globals.hh b/helm/DEVEL/mathml_editor/src/globals.hh index 2f26a9159..25755a8a8 100644 --- a/helm/DEVEL/mathml_editor/src/globals.hh +++ b/helm/DEVEL/mathml_editor/src/globals.hh @@ -2,7 +2,8 @@ #ifndef __globals_hh__ #define __globals_hh__ -#define TML_NS_URI "http://helm.cs.unibo.it/2002/TML" -#define XMLNS_NS_URI "http://www.w3.org/2000/xmlns/" +#define TML_NS_URI "http://helm.cs.unibo.it/2002/TML" +#define XMLNS_NS_URI "http://www.w3.org/2000/xmlns/" +#define MATHML_NS_URI "http://www.w3.org/1998/Math/MathML" #endif // __globals_hh__ diff --git a/helm/DEVEL/mathml_editor/test/Makefile.in b/helm/DEVEL/mathml_editor/test/Makefile.in index 2bf438dc5..dae4241b2 100644 --- a/helm/DEVEL/mathml_editor/test/Makefile.in +++ b/helm/DEVEL/mathml_editor/test/Makefile.in @@ -74,12 +74,26 @@ GMETADOM_CFLAGS = @GMETADOM_CFLAGS@ GMETADOM_LIBS = @GMETADOM_LIBS@ GTKMATHVIEW_CFLAGS = @GTKMATHVIEW_CFLAGS@ GTKMATHVIEW_LIBS = @GTKMATHVIEW_LIBS@ +HAVE_OCAMLC = @HAVE_OCAMLC@ +HAVE_OCAMLDEP = @HAVE_OCAMLDEP@ +HAVE_OCAMLFIND = @HAVE_OCAMLFIND@ +HAVE_OCAMLMKLIB = @HAVE_OCAMLMKLIB@ +HAVE_OCAMLOPT = @HAVE_OCAMLOPT@ LDFLAGS = @LDFLAGS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ MAKEINFO = @MAKEINFO@ +MLGDOME_CFLAGS = @MLGDOME_CFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OCAMLC = @OCAMLC@ +OCAMLDEP = @OCAMLDEP@ +OCAMLFIND = @OCAMLFIND@ +OCAMLMKLIB = @OCAMLMKLIB@ +OCAMLOPT = @OCAMLOPT@ +OCAMLSTDLIBDIR = @OCAMLSTDLIBDIR@ +OCAMLSTUBDIR = @OCAMLSTUBDIR@ +OCAML_INCLUDE_DIR = @OCAML_INCLUDE_DIR@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ STRIP = @STRIP@ diff --git a/helm/DEVEL/mathml_editor/test/aux.cc b/helm/DEVEL/mathml_editor/test/aux.cc index 61f9e5d79..4b4404af4 100644 --- a/helm/DEVEL/mathml_editor/test/aux.cc +++ b/helm/DEVEL/mathml_editor/test/aux.cc @@ -124,6 +124,14 @@ findCommonSiblings(const DOM::Element& first, const DOM::Element& last, lastS = q; } +static DOM::Element +findElementWithRef(const DOM::Element& el) +{ + DOM::Element p = el; + while (p && !p.hasAttribute("xref")) p = p.get_parentNode(); + return p; +} + static DOM::Node leftmostChild(const DOM::Node& node) { @@ -188,17 +196,14 @@ rightSibling(const DOM::Node& node) extern "C" GdomeElement* find_common_ancestor(GdomeElement* first, GdomeElement* last) { - DOM::Element p(first); - DOM::Element q(last); - if (GdomeElement* res = gdome_cast_el(findCommonAncestor(p, q).gdome_object())) + if (GdomeNode* n = findCommonAncestor(DOM::Element(first), DOM::Element(last)).gdome_object()) { - GdomeException exc = 0; - gdome_el_ref(res, &exc); - assert(exc == 0); + GdomeElement* res = gdome_cast_el(n); + g_assert(res != NULL); return res; } else - return 0; + return NULL; } extern "C" void @@ -214,6 +219,32 @@ find_common_siblings(GdomeElement* first, GdomeElement* last, if (lastS != NULL) *lastS = gdome_cast_el(ls.gdome_object()); } +extern "C" GdomeElement* +find_element_with_ref(GdomeElement* elem) +{ + if (GdomeNode* n = findElementWithRef(DOM::Element(elem)).gdome_object()) + { + GdomeElement* res = gdome_cast_el(n); + g_assert(res != NULL); + return res; + } + else + return NULL; +} + +extern "C" GdomeElement* +find_common_ancestor_with_ref(GdomeElement* first, GdomeElement* last) +{ + if (GdomeNode* n = findElementWithRef(findCommonAncestor(DOM::Element(first), DOM::Element(last))).gdome_object()) + { + GdomeElement* res = gdome_cast_el(n); + g_assert(res != NULL); + return res; + } + else + return NULL; +} + extern "C" void delete_element(GdomeElement* elem) { diff --git a/helm/DEVEL/mathml_editor/test/editor.cc b/helm/DEVEL/mathml_editor/test/editor.cc index 9d548289c..62435ca78 100644 --- a/helm/DEVEL/mathml_editor/test/editor.cc +++ b/helm/DEVEL/mathml_editor/test/editor.cc @@ -5,36 +5,16 @@ #include "TDictionary.hh" #include "CLoggerConsole.hh" #include "CMathMLFactoryXSLT.hh" +#include "CMathMLFactoryXSLTDiff.hh" #include "AMathMLConsumer.hh" #include "guiGTK.h" -TDictionary dictionary; - extern void *parseMathMLFile(char *); -class CMathMLConsumer : public AMathMLConsumer -{ -public: - CMathMLConsumer(void) { firstTime = true; }; - - virtual void documentModified(const DOM::Document& result) - { - if (firstTime) - { - if (GUI_load_document(gdome_cast_doc(static_cast(result))) < 0) - cerr << "c'e' stato un errore" << endl; - firstTime = false; - } - } - -private: - bool firstTime; -}; - struct Context { - Context(const std::string& s, TPushLexer& l) : buffer(s), i(0), lexer(l) { }; + Context(const std::string& s, TPushLexer& l, TPushParser& p) : buffer(s), i(0), lexer(l), parser(p) { }; void send(void) { @@ -45,6 +25,7 @@ struct Context std::string buffer; unsigned i; TPushLexer& lexer; + TPushParser& parser; }; extern "C" int @@ -58,27 +39,52 @@ edit_timeout(Context* data) } extern "C" void -push_char(Context* context, gchar ch) +edit_push_char(Context* context, gchar ch) { + assert(context != NULL); GUI_freeze(); cout << "*** SENDING " << ch << endl; context->lexer.push(ch); GUI_thaw(); } +extern "C" void +edit_push_string(Context* context, const gchar* s) +{ + assert(context != NULL); + assert(s != NULL); + GUI_freeze(); + context->parser.freeze(); + for (unsigned i = 0; s[i]; i++) context->lexer.push(s[i]); + context->parser.thaw(); + GUI_thaw(); +} + +extern "C" void +edit_drop(Context* context, gboolean alt) +{ + assert(context != NULL); + GUI_freeze(); + context->lexer.drop(alt); + GUI_thaw(); +} + +void main(int argc, char* argv[]) { CLoggerConsole logger; + logger.verbosity(ALogger::Debug); + + TDictionary dictionary(logger); logger.info("loading the dictionary..."); - dictionary.load("dictionary.xml"); + dictionary.load("dictionary-test.xml"); logger.info("loading the stylesheet..."); DOM::DOMImplementation di; DOM::Document docStyle = di.createDocumentFromURI("./xsl/tml-mmlp.xsl"); - DOM::XSLTStylesheet style(docStyle); + DOMX::XSLTStylesheet style(docStyle); - CMathMLConsumer consumer; - CMathMLFactoryXSLT factory(logger, consumer, style); + CMathMLFactoryXSLTDiff factory(logger, style); TPushParser parser(logger, factory, dictionary); TPushLexer lexer(logger, parser); @@ -95,9 +101,10 @@ main(int argc, char* argv[]) style.save(result, stdout); #endif - Context context("", lexer); + Context context("", lexer, parser); GUI_init(&argc, &argv, "mathmleditor", 500, 600, &context); + GUI_load_document(gdome_cast_doc(static_cast(factory.document()))); GUI_run(); GUI_uninit(); GUI_unload_document(); diff --git a/helm/DEVEL/mathml_editor/test/guiGTK.c b/helm/DEVEL/mathml_editor/test/guiGTK.c index cd1c7c878..7426e3f5d 100644 --- a/helm/DEVEL/mathml_editor/test/guiGTK.c +++ b/helm/DEVEL/mathml_editor/test/guiGTK.c @@ -35,17 +35,14 @@ static GtkWidget* window; static GtkWidget* main_area; static GtkWidget* scrolled_area; -static GtkWidget* status_bar; static GtkMenuItem* anti_aliasing_item; static GtkMenuItem* transparency_item; -static GdkCursor* normal_cursor; -static GdkCursor* link_cursor; +static gpointer context = NULL; static gchar* doc_name = NULL; +static GdomeElement* first_selected = NULL; static GdomeElement* root_selected = NULL; -static guint statusbar_context; - static void create_widget_set(gpointer); static GtkWidget* get_main_menu(void); static void file_open(GtkWidget*, gpointer); @@ -57,9 +54,10 @@ static void options_change_font_size(GtkWidget*, gboolean); static void options_verbosity(GtkWidget*, guint); static void options_anti_aliasing(GtkWidget*, gpointer); static void options_transparency(GtkWidget*, gpointer); -static void selection_delete(GtkWidget*, gpointer); -static void selection_parent(GtkWidget*, gpointer); -static void selection_reset(GtkWidget*, gpointer); +static void edit_delete_selection(GtkWidget*, gpointer); +static void edit_select_parent(GtkWidget*, gpointer); +static void edit_reset_selection(GtkWidget*, gpointer); +static void edit_insert(GtkWidget*, gpointer); static void help_about(GtkWidget*, gpointer); static GtkItemFactoryEntry menu_items[] = { @@ -70,10 +68,12 @@ static GtkItemFactoryEntry menu_items[] = { { "/File/sep1", NULL, NULL, 0, "" }, { "/File/_Quit", "Q", gtk_main_quit, 0, NULL }, - { "/_Selection", NULL, NULL, 0, "" }, - { "/Selection/Reset", NULL, selection_reset, 0, NULL }, - { "/Selection/Delete", NULL, selection_delete, 0, NULL }, - { "/Selection/Select Parent", NULL, selection_parent, 0, NULL }, + { "/_Edit", NULL, NULL, 0, "" }, + { "/Edit/Reset Selection", NULL, edit_reset_selection, 0, NULL }, + { "/Edit/Delete Selection", NULL, edit_delete_selection, 0, NULL }, + { "/Edit/Select Parent", NULL, edit_select_parent, 0, NULL }, + { "/Edit/sep1", NULL, NULL, 0, "" }, + { "/Edit/Insert...", "I", edit_insert, 0, NULL }, { "/_Options", NULL, NULL, 0, "" }, { "/Options/Default _Font Size", NULL, NULL, 0, "" }, @@ -134,7 +134,7 @@ load_error_msg(const char* name) } void -GUI_init(int* argc, char*** argv, char* title, guint width, guint height, gpointer context) +GUI_init(int* argc, char*** argv, char* title, guint width, guint height, gpointer c) { gtk_init(argc, argv); @@ -146,15 +146,30 @@ GUI_init(int* argc, char*** argv, char* title, guint width, guint height, gpoint gtk_widget_show(window); - normal_cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW); - link_cursor = gdk_cursor_new(GDK_HAND2); - + context = c; /*edit_timeout_id = gtk_timeout_add(400, edit_timeout, context);*/ } void GUI_uninit() { + GdomeException exc = 0; + + if (first_selected != NULL) + { + gdome_el_unref(first_selected, &exc); + g_assert(exc == 0); + first_selected = NULL; + } + + if (root_selected != NULL) + { + gdome_el_unref(root_selected, &exc); + g_assert(exc == 0); + root_selected = NULL; + } + + context = NULL; } int @@ -199,9 +214,6 @@ GUI_unload_document() if (doc_name != NULL) g_free(doc_name); doc_name = NULL; - - gtk_statusbar_pop(GTK_STATUSBAR(status_bar), statusbar_context); - gtk_statusbar_push(GTK_STATUSBAR(status_bar), statusbar_context, ""); } void @@ -314,7 +326,7 @@ options_verbosity(GtkWidget* widget, guint level) } static void -selection_delete(GtkWidget* widget, gpointer data) +edit_delete_selection(GtkWidget* widget, gpointer data) { if (root_selected != NULL) { @@ -330,7 +342,7 @@ selection_delete(GtkWidget* widget, gpointer data) } static void -selection_parent(GtkWidget* widget, gpointer data) +edit_select_parent(GtkWidget* widget, gpointer data) { if (root_selected != NULL) { @@ -345,7 +357,7 @@ selection_parent(GtkWidget* widget, gpointer data) } static void -selection_reset(GtkWidget* widget, gpointer data) +edit_reset_selection(GtkWidget* widget, gpointer data) { if (root_selected != NULL) { @@ -357,6 +369,51 @@ selection_reset(GtkWidget* widget, gpointer data) } } +static void +insert_tex(GtkWidget* widget, GtkEntry* entry) +{ + gchar* text; + g_return_if_fail(entry != NULL); + + text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); + edit_push_string(context, text); + g_free(text); +} + +static void +edit_insert(GtkWidget* widget, gpointer data) +{ + GtkWidget* dialog; + GtkWidget* entry; + GtkWidget* ok; + GtkWidget* cancel; + + dialog = gtk_dialog_new(); + entry = gtk_entry_new(); + ok = gtk_button_new_with_label("OK"); + cancel = gtk_button_new_with_label("Cancel"); + + gtk_signal_connect (GTK_OBJECT (ok), "clicked", + GTK_SIGNAL_FUNC (insert_tex), (gpointer) entry); + + gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog); + + gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog); + + gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) dialog); + + gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 5); + + gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), entry); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), ok); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), cancel); + + gtk_widget_show_all (dialog); +} + static void help_about(GtkWidget* widget, gpointer data) { @@ -365,7 +422,7 @@ help_about(GtkWidget* widget, gpointer data) GtkWidget* ok; dialog = gtk_dialog_new(); - label = gtk_label_new("\n MathML Viewer \n Copyright (C) 2000-2003 Luca Padovani \n"); + label = gtk_label_new("\n MathML Editor \n Copyright (C) 2003 Luca Padovani \n"); ok = gtk_button_new_with_label("Close"); gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", @@ -379,7 +436,7 @@ help_about(GtkWidget* widget, gpointer data) } static void -change_default_font_size(GtkSpinButton* widget, GtkSpinButton* spin) +change_default_font_size(GtkWidget* widget, GtkSpinButton* spin) { g_return_if_fail(spin != NULL); gtk_math_view_set_font_size( GTK_MATH_VIEW(main_area), gtk_spin_button_get_value_as_int(spin)); @@ -436,97 +493,75 @@ options_set_font_size(GtkWidget* widget, gpointer data) gtk_widget_show_all (dialog); } -#if 0 -#if defined(HAVE_GMETADOM) static void -element_changed(GtkMathView* math_view, GdomeElement* elem) +select_begin(GtkMathView* math_view, GdomeElement* first, gint state) { - GdomeDOMString* link = NULL; - - g_return_if_fail(math_view != NULL); - g_return_if_fail(GTK_IS_MATH_VIEW(math_view)); - -/* printf("pointer is on %p\n", elem); */ + GdomeException exc = 0; - link = find_hyperlink(elem, XLINK_NS_URI, "href"); - if (link != NULL) - gdk_window_set_cursor(GTK_WIDGET(math_view)->window, link_cursor); - else - gdk_window_set_cursor(GTK_WIDGET(math_view)->window, normal_cursor); - - if (link != NULL) - gdome_str_unref(link); -} -#endif -#endif - -static void -selection_changed(GtkMathView* math_view, GdomeElement* first, GdomeElement* last) -{ g_return_if_fail(math_view != NULL); g_return_if_fail(GTK_IS_MATH_VIEW(math_view)); g_return_if_fail(first != NULL); -/* printf("selection changed %p %p\n", first, last); */ + gtk_math_view_freeze(math_view); - if (last != NULL) + if (root_selected != NULL) { - GdomeException exc = 0; + gtk_math_view_unselect(math_view, root_selected); + gdome_el_unref(root_selected, &exc); + g_assert(exc == 0); + } - if (root_selected != NULL) - { - gdome_el_unref(root_selected, &exc); - g_assert(exc == 0); - } + root_selected = first_selected = find_element_with_ref(first); - root_selected = find_common_ancestor(first, last); -/* printf("selecting root %p\n", first, last, root_selected); */ - /* gtk_math_view_set_selection(math_view, root_selected); */ + if (root_selected != NULL) + { + gtk_math_view_select(math_view, root_selected); + gdome_el_ref(root_selected, &exc); g_assert(exc == 0); } + + gtk_math_view_thaw(math_view); } -#if 0 -#if defined(HAVE_GMETADOM) static void -clicked(GtkMathView* math_view, GdomeElement* elem) +select_over(GtkMathView* math_view, GdomeElement* elem, gint state) { - GdomeException exc; - GdomeDOMString* name; - GdomeDOMString* ns_uri; - GdomeElement* p; + GdomeElement* new_selected = NULL; + GdomeException exc = 0; g_return_if_fail(math_view != NULL); + g_return_if_fail(GTK_IS_MATH_VIEW(math_view)); + g_return_if_fail(elem != NULL); - /* printf("clicked on %p\n", elem); */ + if (first_selected == NULL || elem == NULL) + new_selected = NULL; + else + new_selected = find_common_ancestor_with_ref(first_selected, elem); - if (elem != NULL) + if (new_selected != root_selected) { - GdomeElement* action; - GdomeDOMString* href = find_hyperlink(elem, XLINK_NS_URI, "href"); - if (href != NULL) - { -/* printf("hyperlink %s\n", href->str); */ - gdome_str_unref(href); - } - - action = find_self_or_ancestor(elem, MATHML_NS_URI, "maction"); -/* printf("action? %p\n", action); */ - if (action != NULL) + gtk_math_view_freeze(math_view); + if (root_selected != NULL) { - gtk_math_view_freeze(math_view); - action_toggle(action); - gtk_math_view_thaw(math_view); - gdome_el_unref(action, &exc); + gtk_math_view_unselect(math_view, root_selected); + gdome_el_unref(root_selected, &exc); g_assert(exc == 0); } + root_selected = new_selected; + if (root_selected != NULL) + gtk_math_view_select(math_view, root_selected); + gtk_math_view_thaw(math_view); + } + else if (new_selected != NULL) + { + gdome_el_unref(new_selected, &exc); + g_assert(exc == 0); } + } -#endif -#endif static gboolean -key_press_event(gpointer context, +key_press_event(gpointer c, GdkEventKey* event, GtkWidget* widget) { @@ -536,36 +571,16 @@ key_press_event(gpointer context, if (event->type != GDK_KEY_PRESS) return FALSE; - switch (event->keyval) { - case GDK_Up: - case GDK_KP_Up: - break; - case GDK_Down: - case GDK_KP_Down: - break; - case GDK_Left: - case GDK_KP_Left: - break; - case GDK_Right: - case GDK_KP_Right: - break; - case GDK_Page_Up: - case GDK_KP_Page_Up: - break; - case GDK_Page_Down: - case GDK_KP_Page_Down: - break; - case GDK_Home: - case GDK_KP_Home: - break; - case GDK_End: - case GDK_KP_End: - break; - case GDK_BackSpace: push_char(context, event->keyval); break; - default: - if (event->keyval < 0x80) push_char(context, event->keyval); - return FALSE; - } + switch (event->keyval) + { + case GDK_BackSpace: + edit_drop(context, event->state & GDK_MOD1_MASK); + break; + default: + if ((event->state & (~GDK_SHIFT_MASK)) == 0 && event->keyval < 0x80) + edit_push_char(context, event->keyval); + return FALSE; + } return TRUE; } @@ -590,33 +605,19 @@ create_widget_set(gpointer context) //gtk_math_view_set_log_verbosity(GTK_MATH_VIEW(main_area), 3); -#if 0 gtk_signal_connect_object (GTK_OBJECT (main_area), - "selection_changed", GTK_SIGNAL_FUNC (selection_changed), + "select_begin", GTK_SIGNAL_FUNC (select_begin), (gpointer) main_area); gtk_signal_connect_object (GTK_OBJECT (main_area), - "element_changed", GTK_SIGNAL_FUNC (element_changed), - (gpointer) main_area); - - gtk_signal_connect_object (GTK_OBJECT (main_area), - "action_changed", GTK_SIGNAL_FUNC (action_changed), - (gpointer) main_area); - - gtk_signal_connect_object (GTK_OBJECT (main_area), - "clicked", GTK_SIGNAL_FUNC(clicked), + "select_over", GTK_SIGNAL_FUNC (select_over), (gpointer) main_area); -#endif gtk_signal_connect_object (GTK_OBJECT(window), "key_press_event", GTK_SIGNAL_FUNC(key_press_event), context); - gtk_widget_add_events(GTK_WIDGET(main_area), - GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_POINTER_MOTION_MASK - | GDK_KEY_PRESS_MASK); + gtk_widget_add_events(GTK_WIDGET(main_area), GDK_KEY_PRESS_MASK); scrolled_area = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area), @@ -626,71 +627,11 @@ create_widget_set(gpointer context) gtk_container_add(GTK_CONTAINER(scrolled_area), main_area); gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0); - status_bar = gtk_statusbar_new(); - gtk_widget_show(status_bar); - gtk_box_pack_start(GTK_BOX(main_vbox), status_bar, FALSE, TRUE, 0); - statusbar_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "filename"); - - gtk_widget_show(main_vbox); - - if (gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area))) - gtk_menu_item_activate(anti_aliasing_item); -} - -#if 0 -static void -create_widget_set() -{ - GtkWidget* main_vbox; - GtkWidget* menu_bar; - - main_vbox = gtk_vbox_new(FALSE, 1); - gtk_container_border_width(GTK_CONTAINER(main_vbox), 1); - gtk_container_add(GTK_CONTAINER(window), main_vbox); - gtk_widget_show(main_vbox); - - menu_bar = get_main_menu(); - gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0); - gtk_widget_show(menu_bar); - - main_area = gtk_math_view_new(NULL, NULL); - gtk_widget_show(main_area); - - gtk_signal_connect_object (GTK_OBJECT (main_area), - "selection_changed", GTK_SIGNAL_FUNC (selection_changed), - (gpointer) main_area); - - gtk_signal_connect_object (GTK_OBJECT (main_area), - "element_changed", GTK_SIGNAL_FUNC (element_changed), - (gpointer) main_area); - - gtk_signal_connect_object (GTK_OBJECT (main_area), - "clicked", GTK_SIGNAL_FUNC(clicked), - (gpointer) main_area); - - gtk_widget_add_events(GTK_WIDGET(main_area), - GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_POINTER_MOTION_MASK); - - scrolled_area = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_area), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_widget_show(scrolled_area); - gtk_container_add(GTK_CONTAINER(scrolled_area), main_area); - gtk_box_pack_start(GTK_BOX(main_vbox), scrolled_area, TRUE, TRUE, 0); - - status_bar = gtk_statusbar_new(); - gtk_widget_show(status_bar); - gtk_box_pack_start(GTK_BOX(main_vbox), status_bar, FALSE, TRUE, 0); - statusbar_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "filename"); - gtk_widget_show(main_vbox); if (gtk_math_view_get_anti_aliasing(GTK_MATH_VIEW(main_area))) gtk_menu_item_activate(anti_aliasing_item); } -#endif GtkWidget* get_main_menu() diff --git a/helm/DEVEL/mathml_editor/xsl/tml-mmlp.xsl b/helm/DEVEL/mathml_editor/xsl/tml-mmlp.xsl index 9054b9c99..873605387 100644 --- a/helm/DEVEL/mathml_editor/xsl/tml-mmlp.xsl +++ b/helm/DEVEL/mathml_editor/xsl/tml-mmlp.xsl @@ -88,9 +88,7 @@ - - I - + I @@ -577,8 +575,16 @@ - - + + + + + + + + + +