You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@corinthia.apache.org by pm...@apache.org on 2015/04/11 19:49:46 UTC

[2/4] incubator-corinthia git commit: Desktop app: Basic infrastructure for Editor lib

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/23c028c7/consumers/corinthia/res/sample.html
----------------------------------------------------------------------
diff --git a/consumers/corinthia/res/sample.html b/consumers/corinthia/res/sample.html
new file mode 100644
index 0000000..ef8be70
--- /dev/null
+++ b/consumers/corinthia/res/sample.html
@@ -0,0 +1,395 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+  <meta name="generator" content="UX Write 2.1.1 (build ad61a0a); iOS 8.2">
+  <meta charset="utf-8">
+  <style>
+body {
+    font-family: Palatino;
+    counter-reset: h1 h2 h3 h4 h5 h6 figure table;
+    margin: 10%;
+    text-align: justify;
+  }
+
+  caption {
+    caption-side: bottom;
+    counter-increment: table;
+  }
+
+  caption.Unnumbered {
+    counter-increment: table 0;
+  }
+
+  caption.Unnumbered::before {
+    content: "";
+  }
+
+  caption::before {
+    content: "Table " counter(table) ": ";
+  }
+
+  h1 {
+    counter-increment: h1;
+    counter-reset: h2 h3 h4 h5 h6;
+  }
+
+  h1::before {
+    content: counter(h1) " ";
+  }
+
+  h2 {
+    counter-increment: h2;
+    counter-reset: h3 h4 h5 h6;
+  }
+
+  h2::before {
+    content: counter(h1) "." counter(h2) " ";
+  }
+
+  h3 {
+    counter-increment: h3;
+    counter-reset: h4 h5 h6;
+  }
+
+  h3::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) " ";
+  }
+
+  h4 {
+    counter-increment: h4;
+    counter-reset: h5 h6;
+  }
+
+  h4::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) " ";
+  }
+
+  h5 {
+    counter-increment: h5;
+    counter-reset: h6;
+  }
+
+  h5::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) " ";
+  }
+
+  h6 {
+    counter-increment: h6;
+  }
+
+  h6::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) " ";
+  }
+
+  nav.tableofcontents::before {
+    content: "Contents";
+    display: block;
+    font-size: 2em;
+    font-weight: bold;
+    margin-bottom: .67em;
+    margin-top: .67em;
+  }
+
+  p.toc1 {
+    margin-bottom: 6pt;
+    margin-left: 0pt;
+    margin-top: 12pt;
+  }
+
+  p.toc2 {
+    margin-bottom: 6pt;
+    margin-left: 24pt;
+    margin-top: 6pt;
+  }
+
+  p.toc3 {
+    margin-bottom: 6pt;
+    margin-left: 48pt;
+    margin-top: 6pt;
+  }
+
+  table {
+    border-collapse: collapse;
+    margin-left: auto;
+    margin-right: auto;
+  }
+
+  td > :first-child, th > :first-child {
+    margin-top: 0;
+  }
+
+  td > :last-child, th > :last-child {
+    margin-bottom: 0;
+  }
+
+  td, th {
+    border: 1px solid black;
+  }
+  </style>
+
+  <title></title>
+</head>
+
+<body>
+  <p>Test document</p>
+
+  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at lorem
+  augue, at molestie risus. Sed bibendum augue metus, sed cursus tortor. Aenean
+  semper consectetur pulvinar. Aliquam ultrices tempus nibh, ut mollis ligula
+  ultrices nec. Curabitur vel eros in mi mattis vulputate in nec lorem. Nam
+  auctor faucibus diam, eget accumsan lorem auctor eu. Maecenas imperdiet
+  tristique nisi. Sed sed metus lacus. In consectetur tempus justo, vitae porta
+  urna dapibus nec. Duis vitae lorem sit amet quam suscipit mollis eget non
+  orci. Praesent porta neque et mauris molestie nec sagittis nulla
+  volutpat.</p>
+
+  <h1 id="item2">Introduction</h1>
+
+  <p>Vivamus nec cursus massa. Aenean hendrerit sagittis volutpat. Donec diam
+  erat, vehicula at ultrices vel, aliquet ac mauris. Nam vitae lectus eu eros
+  sagittis sollicitudin. Mauris consequat, est suscipit feugiat eleifend, leo
+  erat rutrum dui, at volutpat metus metus vitae leo. Fusce dictum tincidunt
+  dignissim. Vestibulum eu est purus, eu aliquam quam. Aenean ultricies ante
+  sit amet libero sodales eu feugiat velit ornare.</p>
+
+  <h2 id="item3">Background</h2>
+
+  <p>Proin facilisis cursus elementum. Proin ac lorem ut odio ultricies
+  vehicula sit amet in diam. Proin ut nunc et nisl tristique sagittis. Aenean
+  aliquet eleifend enim non molestie. Vivamus tincidunt augue nec erat suscipit
+  ullamcorper. Nulla ornare risus odio. Nullam vestibulum tellus ac odio mattis
+  quis sollicitudin arcu interdum. Donec convallis malesuada ultricies. Sed
+  sodales porta commodo. Ut nec fringilla est. Nulla aliquet feugiat orci in
+  lobortis. Duis adipiscing aliquam orci, ac tempus leo posuere id. Nam neque
+  enim, faucibus id luctus ut, blandit eu est. Nullam non convallis mauris.</p>
+
+  <h2 id="item4">Motivation</h2>
+
+  <p>Nunc tincidunt, ante vel hendrerit cursus, lectus quam dapibus ipsum, eget
+  vestibulum odio turpis eleifend augue. Ut pharetra ultricies risus, id
+  gravida risus tincidunt eget. Nam eros massa, condimentum quis aliquet nec,
+  aliquam id enim. Integer diam justo, sagittis at faucibus eget, vestibulum id
+  lectus. Suspendisse pharetra lobortis diam sit amet fermentum. Donec nisl
+  ipsum, faucibus et bibendum a, viverra nec nunc. Cras vel arcu mauris. In hac
+  habitasse platea dictumst.</p>
+
+  <h2 id="item5">Project overview</h2>
+
+  <p>Donec sagittis dui sollicitudin massa congue et mollis nulla cursus.
+  Maecenas eget tempor risus. Nam euismod placerat ante viverra gravida. Mauris
+  nec arcu eget turpis accumsan vestibulum. Phasellus luctus, massa vel laoreet
+  faucibus, nulla tellus luctus ipsum, nec imperdiet lacus urna id diam. In
+  libero lacus, rutrum id rhoncus at, mollis consequat mauris. Ut et lectus
+  nulla, nec sagittis massa. Praesent tortor dui, elementum sed tempor eget,
+  porta vehicula ligula. Fusce aliquam lacus in ipsum tristique
+  pellentesque.</p>
+
+  <table style="width: 60%;" id="item16">
+    <caption>
+      A sample table
+    </caption>
+    <col width="50%">
+    <col width="50%">
+
+    <tbody>
+      <tr>
+        <td>
+          <p>Cell 1,1</p>
+        </td>
+
+        <td>
+          <p>Cell 1,2</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cell 2,1</p>
+        </td>
+
+        <td>
+          <p>Cell 2,2</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cell 3,1</p>
+        </td>
+
+        <td>
+          <p>Cell 3,2</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cell 4,1</p>
+        </td>
+
+        <td>
+          <p>Cell 4,2</p>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+
+  <p>In nisi felis, ornare nec feugiat at, sodales posuere nibh. Etiam suscipit
+  congue nunc, at sollicitudin est adipiscing viverra. Aenean sed augue quis
+  sem commodo pretium. Maecenas quis elit urna. Donec non arcu dui. Praesent
+  faucibus ornare purus id dignissim. Quisque dictum viverra orci id lacinia.
+  Etiam mollis egestas tortor, id iaculis augue malesuada non. Sed elementum
+  ornare quam, vel iaculis nibh vulputate facilisis.</p>
+
+  <p>Nunc sit amet ipsum tellus, ut laoreet magna. Phasellus consectetur, velit
+  vitae laoreet posuere, eros diam venenatis ante, quis dignissim turpis turpis
+  at quam. Cras ac justo quis nibh sollicitudin gravida. Vestibulum ac
+  vulputate dui. Suspendisse ac nulla mauris, eget condimentum nulla. Nullam
+  mollis metus sed magna facilisis ac accumsan est facilisis. Pellentesque
+  consequat tincidunt sapien in vehicula.</p>
+
+  <h1 id="item6">Implementation</h1>
+
+  <h2 id="item7">Phase One</h2>
+
+  <p>Phasellus dignissim ultricies mauris placerat molestie. Nunc sed orci nec
+  orci mollis suscipit. Maecenas eget quam non arcu dapibus volutpat. Quisque
+  ac turpis ut libero interdum tristique id in quam. Praesent eros velit,
+  dictum eu auctor ut, lobortis ac sem. Duis ipsum neque, volutpat id blandit
+  sed, tempor a dui. Sed ut magna ligula, et sagittis nunc. Phasellus at
+  eleifend orci. Quisque non nunc ipsum. Curabitur eu erat nec ante suscipit
+  mollis. Fusce dictum laoreet volutpat. Vivamus rutrum luctus mattis.</p>
+
+  <p>Sed augue velit, eleifend sed auctor sed, consectetur quis augue. Nulla
+  consectetur imperdiet quam et elementum. Praesent suscipit magna id diam
+  cursus in faucibus arcu semper. Phasellus pretium, nisl in sagittis viverra,
+  arcu tellus aliquam urna, et scelerisque eros lorem et diam. In ut nunc vel
+  nisi imperdiet mattis quis at massa. Phasellus quis tortor est. Sed ac
+  blandit eros. Curabitur ante mauris, condimentum in tempus sit amet, accumsan
+  ac leo. Ut quis tincidunt nunc. Vestibulum ante ipsum primis in faucibus orci
+  luctus et ultrices posuere cubilia Curae; Curabitur tincidunt, nisl id
+  interdum fringilla, mauris tortor volutpat libero, et consectetur purus magna
+  quis nibh.</p>
+
+  <h2 id="item8">Phase Two</h2>
+
+  <p>Aliquam dapibus tincidunt purus in aliquet. In sed ultricies sapien. Cras
+  risus nulla, ultrices ut vulputate ac, luctus in purus. Maecenas at lorem
+  sem, a vestibulum sem. Donec ante nisl, facilisis vel convallis vel, blandit
+  quis turpis. Sed id erat vitae metus cursus consectetur. Integer ac dapibus
+  dui. Nam mi ante, sollicitudin eu fringilla quis, fringilla nec lorem.
+  Aliquam ut nisi accumsan odio pulvinar euismod quis ac libero. Curabitur sit
+  amet ultrices risus. Class aptent taciti sociosqu ad litora torquent per
+  conubia nostra, per inceptos himenaeos. Nulla eu dui ut est aliquet iaculis
+  accumsan et leo. Donec dignissim lorem non arcu hendrerit vel feugiat quam
+  accumsan. Etiam mollis fermentum mi vel egestas. Cum sociis natoque penatibus
+  et magnis dis parturient montes, nascetur ridiculus mus.</p>
+
+  <p>Ut facilisis leo nec neque tempus a molestie libero consequat. Duis et
+  justo eu lorem accumsan eleifend sed nec quam. Duis a ligula ante. Donec
+  egestas lacus id mi convallis ut ullamcorper lorem consequat. Curabitur quis
+  sapien vel odio sodales consequat. Maecenas eget commodo eros. In hac
+  habitasse platea dictumst. Donec commodo venenatis consequat. Nulla
+  vestibulum adipiscing nulla id adipiscing. Nam congue, enim et lobortis
+  rhoncus, urna purus tempor magna, a eleifend mi nisl eu magna. Vestibulum
+  ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia
+  Curae;</p>
+
+  <h2 id="item9">Phase Three</h2>
+
+  <p>Proin placerat sapien eu odio ornare eu pharetra nunc lacinia. Duis tellus
+  nisl, condimentum eget tristique sit amet, imperdiet id felis. Nunc at lectus
+  non risus tristique sollicitudin. Etiam at tellus vitae velit sagittis
+  aliquam. Vivamus bibendum pellentesque dictum. Ut auctor interdum congue.
+  Cras ultrices sem sed sem convallis viverra.</p>
+
+  <p>Nunc pulvinar, diam quis dictum gravida, nulla augue sodales lectus, id
+  pharetra leo purus nec augue. Cum sociis natoque penatibus et magnis dis
+  parturient montes, nascetur ridiculus mus. Praesent consequat venenatis justo
+  tincidunt semper. Praesent egestas, ipsum id pharetra lobortis, arcu risus
+  viverra dui, nec sollicitudin augue leo et neque. Proin commodo pharetra
+  lacus, vitae lobortis libero posuere in. Vestibulum tellus ante, luctus quis
+  luctus at, laoreet feugiat turpis. Morbi commodo tellus non leo faucibus
+  ornare. Ut volutpat, diam et mollis dignissim, felis ante lobortis nibh, sed
+  ullamcorper nibh nunc sed dolor. Phasellus viverra leo erat, luctus vehicula
+  dui. Mauris quis ipsum mollis odio accumsan consectetur lacinia feugiat
+  risus. Pellentesque habitant morbi tristique senectus et netus et malesuada
+  fames ac turpis egestas. Fusce vel lectus non risus facilisis suscipit vitae
+  vitae velit. Fusce lacinia enim dapibus mauris porta luctus. Vivamus
+  venenatis sodales nunc non porttitor. Sed posuere commodo consectetur.</p>
+
+  <h1 id="item10">Required resources</h1>
+
+  <p>Vestibulum suscipit posuere elementum. Nullam volutpat, sapien at eleifend
+  congue, dolor sapien pulvinar nibh, eu vulputate velit urna quis nisl.
+  Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
+  cubilia Curae; Nunc auctor libero sed metus dictum quis placerat elit
+  varius.</p>
+
+  <h2 id="item11">Equipment</h2>
+
+  <p>Praesent fermentum augue sem. Cum sociis natoque penatibus et magnis dis
+  parturient montes, nascetur ridiculus mus. Fusce non lorem ligula, ac rhoncus
+  odio. Fusce ac magna lectus. Integer iaculis congue quam, sit amet tincidunt
+  orci mattis quis. Maecenas tempor, turpis nec euismod bibendum, orci dui
+  suscipit purus, iaculis mattis nunc magna at dui. Cras non neque tellus.
+  Integer lobortis, elit ac pretium imperdiet, nulla metus tempus nulla, vitae
+  bibendum diam nisl sed tellus. Class aptent taciti sociosqu ad litora
+  torquent per conubia nostra, per inceptos himenaeos.</p>
+
+  <p>Aliquam vehicula magna pharetra tortor pellentesque vestibulum. Vivamus ut
+  ullamcorper ante. Integer eu auctor lorem. Morbi sapien erat, viverra vitae
+  gravida id, bibendum eu augue. Maecenas nec dolor augue. Lorem ipsum dolor
+  sit amet, consectetur adipiscing elit. Donec aliquet dui at odio lacinia
+  placerat. Mauris a ipsum justo, id faucibus risus.</p>
+
+  <p>Sed vitae elit sed lectus varius vehicula. Maecenas pulvinar laoreet
+  metus, quis dignissim ipsum hendrerit fringilla. Quisque in neque sed ipsum
+  eleifend tempor. Etiam at posuere neque. Maecenas dapibus lacus tincidunt
+  neque elementum sed porta mauris luctus. Donec sit amet libero augue, at
+  hendrerit odio. Nulla consectetur, sem a vestibulum viverra, est nisl congue
+  leo, eget consectetur turpis justo et dolor. Fusce mollis mollis dui, eget
+  aliquet enim sollicitudin sed. Proin dictum sollicitudin rutrum. Curabitur
+  lorem risus, tempus ac ultricies id, suscipit ac nisl. Duis ultricies
+  facilisis arcu, vel congue risus tincidunt sit amet.</p>
+
+  <h2 id="item13">Personnel</h2>
+
+  <p>Etiam condimentum neque non dolor faucibus eu commodo nibh sodales.
+  Vivamus tempus est in risus malesuada vitae gravida nulla tristique. Maecenas
+  vitae justo a enim imperdiet euismod. Pellentesque porttitor metus nec enim
+  fermentum accumsan. Duis gravida ultricies aliquet. Etiam a risus turpis, sed
+  consequat arcu. Proin cursus quam non leo rutrum molestie. Ut eu orci ac nisl
+  lobortis porttitor a at massa. Nam id fringilla enim. Aenean pellentesque
+  molestie dui, sed dignissim urna mollis in. Ut ut metus non leo pharetra
+  tempor eu molestie metus. Aliquam iaculis nulla eget nisl ullamcorper vel
+  varius erat pretium.</p>
+
+  <p>Phasellus at magna tortor, eu elementum ligula. Etiam malesuada vehicula
+  elementum. Donec quis blandit dui. Phasellus tincidunt ullamcorper pharetra.
+  Integer egestas elementum egestas. Phasellus porta, neque a ultricies
+  pharetra, elit leo sodales purus, non auctor quam magna sed lectus. In et
+  ligula ipsum. Morbi vehicula auctor dolor cursus elementum. Cras vestibulum,
+  enim quis luctus posuere, metus enim mollis libero, at dictum enim magna eget
+  dolor. Vestibulum sagittis mi ac nibh dignissim placerat. Praesent vehicula
+  facilisis luctus. Donec ultrices, est non convallis lacinia, diam neque
+  blandit est, sed tincidunt felis ante sed dolor. Fusce laoreet justo sed
+  neque congue scelerisque.</p>
+
+  <h1 id="item14">Summary</h1>
+
+  <p>Nulla vitae ipsum orci. Suspendisse potenti. In sagittis quam non augue
+  blandit dapibus. Nulla dignissim viverra ante a egestas. In augue mi, porta
+  sit amet tempus eget, venenatis ac purus. Pellentesque non sapien et quam
+  molestie consectetur at ut magna. Maecenas turpis justo, adipiscing eu
+  tincidunt vulputate, ultricies sit amet magna.</p>
+
+  <p>Maecenas eget felis at massa pellentesque blandit ac eget lectus. Ut sit
+  amet nibh nunc, sit amet consequat massa. Suspendisse sit amet tempor tellus.
+  Vivamus nec lectus metus. Morbi id nibh neque. Pellentesque semper, sapien id
+  suscipit tincidunt, eros velit rhoncus dolor, non sagittis turpis erat vitae
+  velit. Nulla ligula turpis, lacinia non consequat in, lobortis sollicitudin
+  felis. Suspendisse pulvinar est eu felis congue id vehicula est luctus.</p>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/23c028c7/consumers/corinthia/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/consumers/corinthia/src/CMakeLists.txt b/consumers/corinthia/src/CMakeLists.txt
index 2f56fce..ef4b5ae 100644
--- a/consumers/corinthia/src/CMakeLists.txt
+++ b/consumers/corinthia/src/CMakeLists.txt
@@ -24,11 +24,17 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 ## group source objects
 ###
 set(SOURCES
-    editWindows.h
-    desktop.cpp
-    main.cpp)
-set(UI_SOURCES
-    desktop.ui)
+    Editor.h
+    Editor.cpp
+    JSInterface.h
+    JSInterface.cpp
+    main.cpp
+    MainWindow.h
+    MainWindow.cpp
+    Toolbar.h
+    Toolbar.cpp)
+#set(UI_SOURCES
+#    desktop.ui)
 
 
 
@@ -45,12 +51,14 @@ link_directories(${LIB_DIRS})
 ###
 ## Qt magic
 ###
-set(CMAKE_PREFIX_PATH         "C:/Qt/5.4/msvc2013_64")
+set(CMAKE_PREFIX_PATH         "/usr/local/opt/qt5")
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 set(CMAKE_AUTOMOC             ON)
 
 find_package(Qt5Widgets REQUIRED)
-include_directories("C:/Qt/5.4/msvc2013_64/include")
+find_package(Qt5WebKit REQUIRED)
+find_package(Qt5WebKitWidgets REQUIRED)
+include_directories("/usr/local/opt/qt5/include")
 
 qt5_wrap_ui(UI_HEADERS ${UI_SOURCES})
 source_group("Generated UI Headers" FILES ${UI_HEADERS})
@@ -62,7 +70,18 @@ source_group("Generated UI Headers" FILES ${UI_HEADERS})
 # executable (release artifact)
 ###
 add_executable(corinthia ${SOURCES} ${UI_HEADERS} ${UI_FILES})
-qt5_use_modules(corinthia Widgets)
+qt5_use_modules(corinthia Widgets WebKit WebKitWidgets)
 target_link_libraries(corinthia DocFormats ${LIBS})
 source_group(src FILES ${SOURCES})
 set_property(TARGET corinthia PROPERTY FOLDER consumers)
+
+message(CMAKE_SOURCE_DIR " is " ${CMAKE_SOURCE_DIR})
+message(TARGET_FILE_DIR ":corinthia is " $<TARGET_FILE_DIR:corinthia>)
+message(CMAKE_BINARY_DIR " is " ${CMAKE_BINARY_DIR})
+
+add_custom_command(TARGET corinthia PRE_BUILD
+                   COMMAND ${CMAKE_COMMAND} -E copy_directory
+                   ${CMAKE_SOURCE_DIR}/Editor/src ${CMAKE_BINARY_DIR}/share/corinthia/js)
+add_custom_command(TARGET corinthia PRE_BUILD
+                   COMMAND ${CMAKE_COMMAND} -E copy_directory
+                   ${CMAKE_SOURCE_DIR}/consumers/corinthia/res ${CMAKE_BINARY_DIR}/share/corinthia)

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/23c028c7/consumers/corinthia/src/Editor.cpp
----------------------------------------------------------------------
diff --git a/consumers/corinthia/src/Editor.cpp b/consumers/corinthia/src/Editor.cpp
new file mode 100644
index 0000000..9cce7b8
--- /dev/null
+++ b/consumers/corinthia/src/Editor.cpp
@@ -0,0 +1,296 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "Editor.h"
+#include "JSInterface.h"
+#include <QWebView>
+#include <QWebFrame>
+#include <QFile>
+#include <QLayout>
+#include <QBoxLayout>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QCoreApplication>
+
+class EditorJSCallbacks : public JSCallbacks
+{
+public:
+    EditorJSCallbacks(Editor *editor) : _editor(editor) {}
+    void debug(const QString &message);
+    void addOutlineItem(const QString &itemId, const QString &type, const QString &title);
+    void updateOutlineItem(const QString &itemId, const QString &title);
+    void removeOutlineItem(const QString &itemId);
+    void outlineUpdated();
+    void setCursor(int x, int y, int width, int height);
+    void setSelectionHandles(int x1, int y1, int height1, int x2, int y2, int height2);
+    void setTableSelection(int x, int y, int width, int height);
+    void setSelectionBounds(int left, int top, int right, int bottom);
+    void clearSelectionHandlesAndCursor();
+    void updateAutoCorrect();
+    void error(const QString &message, const QString &operation);
+//private:
+    Editor *_editor;
+};
+
+class EditorJSEvaluator : public JSEvaluator
+{
+public:
+    EditorJSEvaluator(QWebView *webView, JSCallbacks *callbacks) : _webView(webView), _callbacks(callbacks) {}
+    virtual QString evaluate(const QString &script);
+    virtual JSCallbacks *callbacks() { return _callbacks; }
+private:
+    QWebView *_webView;
+    JSCallbacks *_callbacks;
+};
+
+class EditorPrivate : public QObject
+{
+    Q_OBJECT
+public:
+    EditorPrivate(Editor *editor);
+    virtual ~EditorPrivate();
+    public slots:
+    void webViewloadFinished(bool ok);
+public:
+
+    Editor *_editor;
+    QWebView *_webView;
+    EditorJSCallbacks *_callbacks;
+    EditorJSEvaluator *_evaluator;
+    JSInterface *_js;
+};
+
+
+
+const char *jsSources[] = {
+    "first.js",
+    "ElementTypes.js",
+    "AutoCorrect.js",
+    "ChangeTracking.js",
+    "Clipboard.js",
+    "Cursor.js",
+    "DOM.js",
+    "Editor.js",
+    "Equations.js",
+    "Figures.js",
+    "Formatting.js",
+    "Hierarchy.js",
+    "Input.js",
+    "Lists.js",
+    "Main.js",
+    "Metadata.js",
+    "NodeSet.js",
+    "Outline.js",
+    "Position.js",
+    "PostponedActions.js",
+    "Preview.js",
+    "Range.js",
+    "Scan.js",
+    "Selection.js",
+    "StringBuilder.js",
+    "Styles.js",
+    "Tables.js",
+    "Text.js",
+    "traversal.js",
+    "types.js",
+    "UndoManager.js",
+    "util.js",
+    "Viewport.js",
+    NULL,
+};
+
+
+
+
+void EditorJSCallbacks::debug(const QString &message)
+{
+    qStdOut() << "CB debug \"" << message << "\"" << endl;
+}
+
+void EditorJSCallbacks::addOutlineItem(const QString &itemId, const QString &type, const QString &title)
+{
+    qStdOut() << "CB addOutlineItem " << itemId << " " << type << " \"" << title << "\"" << endl;
+}
+
+void EditorJSCallbacks::updateOutlineItem(const QString &itemId, const QString &title)
+{
+    qStdOut() << "CB updateOutlineItem " << itemId << " \"" << title << "\"" << endl;
+}
+
+void EditorJSCallbacks::removeOutlineItem(const QString &itemId)
+{
+    qStdOut() << "CB removeOutlineItem " << itemId << endl;
+}
+
+void EditorJSCallbacks::outlineUpdated()
+{
+    qStdOut() << "CB outlineUpdated" << endl;
+}
+
+void EditorJSCallbacks::setCursor(int x, int y, int width, int height)
+{
+    qStdOut() << "CB setCursor " << x << " " << y << " " << width << " " << height << endl;
+}
+
+void EditorJSCallbacks::setSelectionHandles(int x1, int y1, int height1, int x2, int y2, int height2)
+{
+    qStdOut() << "CB setSelectionHandles " << x1 << " " << y1 << " " << height1 << " "
+    << x2 << " " << y2 << " " << height2 << endl;
+}
+
+void EditorJSCallbacks::setTableSelection(int x, int y, int width, int height)
+{
+    qStdOut() << "CB setTableSelection" << x << " " << y << " " << width << " " << height << endl;
+}
+
+void EditorJSCallbacks::setSelectionBounds(int left, int top, int right, int bottom)
+{
+    qStdOut() << "CB setSelectionBounds " << left << " " << top << " " << right << " " << bottom << endl;
+}
+
+void EditorJSCallbacks::clearSelectionHandlesAndCursor()
+{
+    qStdOut() << "CB clearSelectionHandlesAndCursor" << endl;
+}
+
+void EditorJSCallbacks::updateAutoCorrect()
+{
+    qStdOut() << "CB updateAutoCorrect" << endl;
+}
+
+void EditorJSCallbacks::error(const QString &message, const QString &operation)
+{
+    qStdOut() << "CB error \"" << message << "\" \"" << operation << "\"" << endl;
+}
+
+QString EditorJSEvaluator::evaluate(const QString &script)
+{
+    QWebFrame *frame = _webView->page()->mainFrame();
+    QVariant result = frame->evaluateJavaScript(script);
+    if (result.userType() != QMetaType::QString)
+        return QString::null;
+    else
+        return result.toString();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+EditorPrivate::EditorPrivate(Editor *editor) : _editor(editor)
+{
+    _webView = new QWebView(editor);
+    _callbacks = new EditorJSCallbacks(editor);
+    _evaluator = new EditorJSEvaluator(_webView,_callbacks);
+    _js = new JSInterface(_evaluator);
+    QObject::connect(_webView,SIGNAL(loadFinished(bool)),this,SLOT(webViewloadFinished(bool)));
+}
+
+EditorPrivate::~EditorPrivate()
+{
+    delete _webView;
+    delete _callbacks;
+    delete _evaluator;
+    delete _js;
+}
+
+void EditorPrivate::webViewloadFinished(bool ok)
+{
+    qStdOut() << "webViewloadFinished: ok = " << ok << endl;
+    if (!ok)
+        return;
+    QWebFrame *frame = _editor->webView()->page()->mainFrame();
+    //    frame->evaluateJavaScript("alert('This is a test')");
+
+    QString appPath = QCoreApplication::applicationDirPath();
+    QString baseDir = appPath + "/../share/corinthia/js";
+    baseDir = QUrl::fromLocalFile(baseDir).path();
+    qStdOut() << "js base dir = " << baseDir << endl;
+
+    for (int i = 0; jsSources[i] != NULL; i++) {
+        QString fullPath = baseDir + "/" + QString(jsSources[i]);
+        QFile file(fullPath);
+        if (file.open(QFile::ReadOnly)) {
+            QTextStream stream(&file);
+            QString content = stream.readAll();
+            frame->evaluateJavaScript(content);
+        }
+        else {
+            qStdOut() << "Can't open file " << fullPath << endl;
+            return;
+        }
+    }
+
+    frame->evaluateJavaScript("Main_init()");
+
+    processCallbacks(_evaluator);
+}
+
+Editor::Editor(QWidget *parent, Qt::WindowFlags f) : QWidget(parent,f)
+{
+    _p = new EditorPrivate(this);
+    QVBoxLayout *layout = new QVBoxLayout(this);
+    layout->addWidget(_p->_webView);
+    setLayout(layout);
+}
+
+Editor::~Editor()
+{
+    delete _p;
+}
+
+QWebView *Editor::webView() const
+{
+    return _p->_webView;
+}
+
+JSInterface *Editor::js() const
+{
+    return _p->_js;
+}
+
+#include <Editor.moc>

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/23c028c7/consumers/corinthia/src/Editor.h
----------------------------------------------------------------------
diff --git a/consumers/corinthia/src/Editor.h b/consumers/corinthia/src/Editor.h
new file mode 100644
index 0000000..117a18d
--- /dev/null
+++ b/consumers/corinthia/src/Editor.h
@@ -0,0 +1,35 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#import <QWidget>
+
+class Editor;
+class EditorPrivate;
+class QWebView;
+class JSInterface;
+
+class Editor : public QWidget
+{
+    Q_OBJECT
+public:
+    Editor(QWidget *parent = 0, Qt::WindowFlags f = 0);
+    virtual ~Editor();
+    QWebView *webView() const;
+    JSInterface *js() const;
+private:
+    EditorPrivate *_p;
+};

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/23c028c7/consumers/corinthia/src/JSInterface.cpp
----------------------------------------------------------------------
diff --git a/consumers/corinthia/src/JSInterface.cpp b/consumers/corinthia/src/JSInterface.cpp
new file mode 100644
index 0000000..f6b549f
--- /dev/null
+++ b/consumers/corinthia/src/JSInterface.cpp
@@ -0,0 +1,1307 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "JSInterface.h"
+#include <QJsonDocument>
+#include <assert.h>
+
+QTextStream& qStdOut()
+{
+    static QTextStream ts( stdout );
+    return ts;
+}
+
+class JSArgs
+{
+public:
+    QString toString() const;
+    JSArgs &operator<<(int value);
+    JSArgs &operator<<(unsigned int value);
+    JSArgs &operator<<(double value);
+    JSArgs &operator<<(bool value);
+    JSArgs &operator<<(const char *value);
+    JSArgs &operator<<(const QString &value);
+    JSArgs &operator<<(const QJsonArray &value);
+    JSArgs &operator<<(const QJsonObject &value);
+    JSArgs &operator<<(const QJsonValue &value);
+    JSArgs &operator<<(const QRect &value);
+    JSArgs &operator<<(const QPoint &value);
+    JSArgs &operator<<(const QSize &value);
+    JSArgs &operator<<(const QMap<QString,QString> map);
+private:
+    QJsonArray _array;
+};
+
+QString JSArgs::toString() const
+{
+    QString argsStr = QJsonDocument(_array).toJson(QJsonDocument::Compact);
+    assert(argsStr.size() >= 2);
+    assert(argsStr[0] == '[');
+    assert(argsStr[argsStr.size()-1] == ']');
+    argsStr.remove(0,1);
+    argsStr.remove(argsStr.size()-1,1);
+    return argsStr;
+}
+
+JSArgs &JSArgs::operator<<(int value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(unsigned int value)
+{
+    _array.append((double)value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(double value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(bool value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const char *value)
+{
+    if (value == NULL)
+        _array.append(QJsonValue::Null);
+    else
+        _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QString &value)
+{
+    if (value.isNull())
+        _array.append(QJsonValue::Null);
+    else
+        _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QJsonArray &value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QJsonObject &value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QJsonValue &value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QRect &value)
+{
+    QJsonObject obj;
+    obj["x"] = QJsonValue(value.x());
+    obj["y"] = QJsonValue(value.y());
+    obj["width"] = QJsonValue(value.width());
+    obj["height"] = QJsonValue(value.height());
+    _array.append(obj);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QPoint &value)
+{
+    QJsonObject obj;
+    obj["x"] = QJsonValue(value.x());
+    obj["y"] = QJsonValue(value.y());
+    _array.append(obj);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QSize &value)
+{
+    QJsonObject obj;
+    obj["width"] = QJsonValue(value.width());
+    obj["height"] = QJsonValue(value.height());
+    _array.append(obj);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QMap<QString,QString> map)
+{
+    QJsonObject obj;
+    QMapIterator<QString,QString> it(map);
+    while (it.hasNext()) {
+        it.next();
+        QString key = it.key();
+        QString value = it.value();
+        if (value.isNull())
+            obj[key] = QJsonValue::Null;
+        else
+            obj[key] = value;
+    }
+    _array.append(obj);
+    return *this;
+}
+
+void testargs()
+{
+    int intVal = 4294967295;
+    unsigned int uintVal = 4294967295;
+    QMap<QString,QString> map;
+    map["color"] = "red";
+    map["font-size"] = "24";
+    map["font-family"] = "Helvetica";
+    map["background-color"] = QString::null;
+    JSArgs args = JSArgs()
+    << intVal
+    << uintVal
+    << 3.2
+    << true
+    << false
+    << "test"
+    << (char *)NULL
+    << QString("test")
+    << QString::null
+    << QJsonArray()
+    << QJsonObject()
+    << QJsonValue("value")
+    << QRect(1,2,3,4)
+    << QPoint(5,6)
+    << QSize(7,8)
+    << map;
+    qStdOut() << args.toString() << endl;
+}
+
+QRect QRectFromJson(QJsonValue value)
+{
+    if (!value.isObject()) {
+        qStdOut() << "QRectFromJson: value is not an object" << endl;
+        return QRect();
+    }
+
+    QJsonObject obj = value.toObject();
+    QJsonValue x = obj["x"];
+    QJsonValue y = obj["y"];
+    QJsonValue width = obj["width"];
+    QJsonValue height = obj["height"];
+    if (!x.isDouble() || !y.isDouble() || !width.isDouble() || !height.isDouble()) {
+        qStdOut() << "QRectFromJson: invalid value(s)" << endl;
+        return QRect();
+    }
+
+    return QRect(x.toDouble(),y.toDouble(),width.toDouble(),height.toDouble());
+}
+
+QString QRectString(QRect rect)
+{
+    return QString().sprintf("(%d,%d,%d,%d)",rect.x(),rect.y(),rect.width(),rect.height());
+}
+
+void processCallbacks(JSEvaluator *evaluator)
+{
+    JSCallbacks *callbacks = evaluator->callbacks();
+
+    QString messagesStr = evaluator->evaluate("Editor_getBackMessages()");
+    if (messagesStr.isNull()) {
+        qStdOut() << "Editor_getBackMessages failed" << endl;
+        return;
+    }
+
+    //    QJsonDocument doc = QJsonDocument::fromVariant(var);
+    QJsonDocument doc = QJsonDocument::fromJson(messagesStr.toUtf8());
+    if (doc.isNull()) {
+        qStdOut() << "JSON parse failed" << endl;
+        return;
+    }
+
+    if (!doc.isArray()) {
+        qStdOut() << "JSON is not an array" << endl;
+        return;
+    }
+
+    qStdOut() << "JSON parse succeeded; top-level is an array with " << doc.array().size() << " items" << endl;
+    QJsonArray topArray = doc.array();
+    for (int i = 0; i < topArray.size(); i++) {
+        QJsonValue val = topArray.at(i);
+        if (!val.isArray()) {
+            qStdOut() << "Entry " << i << " is not an array" << endl;
+            return;
+        }
+        //        printf("entry %d: %s\n",i,qcstring(val.toString()));
+        QJsonArray array = val.toArray();
+        if (array.size() < 1) {
+            qStdOut() << "Callback array " << i << " is empty" << endl;
+            return;
+        }
+        if (!array.at(0).isString()) {
+            qStdOut() << "Callback array " << i << " does not start with a string" << endl;
+            return;
+        }
+        QString functionName = array.at(0).toString();
+
+        //        if (functionName == "addOutlineItem") {
+        //            qStdOut() << "cbName " << i << " = " << functionName << " *************************" << endl;
+        //        }
+        //        else {
+        //            qStdOut() << "cbName " << i << " = " << functionName << endl;
+        //        }
+
+        if ((functionName == "debug") &&
+            (array.size() == 2) &&
+            (array.at(1).isString())) {
+            callbacks->debug(array.at(1).toString());
+        }
+        else if ((functionName == "addOutlineItem") &&
+                 (array.size() == 4) &&
+                 (array.at(1).isString()) &&
+                 (array.at(2).isString()) &&
+                 ((array.at(3).isString()) || (array.at(3).isNull()))) {
+            callbacks->addOutlineItem(array.at(1).toString(),array.at(2).toString(),array.at(3).toString());
+        }
+        else if ((functionName == "updateOutlineItem") &&
+                 (array.size() == 3) &&
+                 array.at(1).isString() &&
+                 array.at(2).isString()) {
+            callbacks->updateOutlineItem(array.at(1).toString(),array.at(2).toString());
+        }
+        else if ((functionName == "removeOutlineItem") &&
+                 (array.size() == 2) &&
+                 array.at(1).isString()) {
+            callbacks->removeOutlineItem(array.at(1).toString());
+        }
+        else if ((functionName == "outlineUpdated") &&
+                 (array.size() == 1)) {
+            callbacks->outlineUpdated();
+        }
+        else if ((functionName == "setSelectionHandles") &&
+                 (array.size() == 7) &&
+                 array.at(1).isDouble() &&
+                 array.at(2).isDouble() &&
+                 array.at(3).isDouble() &&
+                 array.at(4).isDouble() &&
+                 array.at(5).isDouble() &&
+                 array.at(6).isDouble()) {
+            callbacks->setSelectionHandles(array.at(1).toDouble(),
+                                            array.at(2).toDouble(),
+                                            array.at(3).toDouble(),
+                                            array.at(4).toDouble(),
+                                            array.at(5).toDouble(),
+                                            array.at(6).toDouble());
+        }
+        else if ((functionName == "setTableSelection") &&
+                 (array.size() == 5) &&
+                 array.at(1).isDouble() &&
+                 array.at(2).isDouble() &&
+                 array.at(3).isDouble() &&
+                 array.at(4).isDouble()) {
+            callbacks->setTableSelection(array.at(1).toDouble(),
+                                          array.at(2).toDouble(),
+                                          array.at(3).toDouble(),
+                                          array.at(4).toDouble());
+        }
+        else if ((functionName == "setCursor") &&
+                 (array.size() == 5) &&
+                 array.at(1).isDouble() &&
+                 array.at(2).isDouble() &&
+                 array.at(3).isDouble() &&
+                 array.at(4).isDouble()) {
+            callbacks->setCursor(array.at(1).toDouble(),
+                                  array.at(2).toDouble(),
+                                  array.at(3).toDouble(),
+                                  array.at(4).toDouble());
+        }
+        else if ((functionName == "clearSelectionHandlesAndCursor") &&
+                 (array.size() == 1)) {
+            callbacks->clearSelectionHandlesAndCursor();
+        }
+        else if ((functionName == "setSelectionBounds") &&
+                 (array.size() == 5) &&
+                 array.at(1).isDouble() &&
+                 array.at(2).isDouble() &&
+                 array.at(3).isDouble() &&
+                 array.at(4).isDouble()) {
+            callbacks->setSelectionBounds(array.at(1).toDouble(),
+                                           array.at(2).toDouble(),
+                                           array.at(3).toDouble(),
+                                           array.at(4).toDouble());
+        }
+        else if ((functionName == "updateAutoCorrect") &&
+                 (array.size() == 1)) {
+            callbacks->updateAutoCorrect();
+        }
+        else if ((functionName == "error") &&
+                 (array.size() == 3) &&
+                 array.at(1).isString() &&
+                 array.at(2).isString()) {
+            callbacks->error(array.at(1).toString(),array.at(2).toString());
+        }
+        else {
+            qStdOut() << "INVALID CALLBACK OR ARGS: " << functionName << endl;
+        }
+    }
+}
+
+QJsonValue evaljsStr(JSEvaluator *ev, const QString &functionName, const QString &argsStr)
+{
+    QString script;
+    QTextStream stream(&script);
+    stream << "Main_execute(function() { return JSON.stringify({ result: ";
+    stream << functionName << "(";
+    stream << argsStr;
+    stream << ")}); });";
+
+    qStdOut() << "EVALUATE: " << script << endl;
+
+    QString resultStr = ev->evaluate(script);
+    qStdOut() << "RESULT: " << resultStr << endl;
+    processCallbacks(ev);
+    if (resultStr.isNull())
+        return QJsonValue(QJsonValue::Null);
+
+    QJsonDocument doc = QJsonDocument::fromJson(resultStr.toUtf8());
+    if (!doc.isObject()) {
+        ev->callbacks()->error("Error parsing returned JSON","evaluate");
+        return QJsonValue(QJsonValue::Null);
+    }
+
+    QJsonObject obj = doc.object();
+    if (!obj.contains("result")) {
+        return QJsonValue(QJsonValue::Null);
+        //        ev->callbacks()->error("Returned JSON does not contain a result","evaluate");
+        //        return QJsonValue(QJsonValue::Null);
+    }
+    
+    return obj["result"];
+}
+
+QJsonValue evaljs(JSEvaluator *ev, const QString &functionName, const JSArgs &args)
+{
+    return evaljsStr(ev,functionName,args.toString());
+}
+
+// Functions implemented in AutoCorrect.js
+
+void JSAutoCorrect::correctPrecedingWord(int numChars, const QString &replacement, bool confirmed)
+{
+    JSArgs args = JSArgs() << numChars << replacement << confirmed;
+    evaljs(_evaluator,"AutoCorrect_correctPrecedingWord",args);
+}
+
+QJsonObject JSAutoCorrect::getCorrection()
+{
+    QJsonValue result = evaljs(_evaluator,"AutoCorrect_getCorrection",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+QJsonObject JSAutoCorrect::getCorrectionCoords()
+{
+    QJsonValue result = evaljs(_evaluator,"AutoCorrect_getCorrectionCoords",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSAutoCorrect::acceptCorrection()
+{
+    evaljs(_evaluator,"AutoCorrect_acceptCorrection",JSArgs());
+}
+
+void JSAutoCorrect::replaceCorrection(const QString &replacement)
+{
+    JSArgs args = JSArgs() << replacement;
+    evaljs(_evaluator,"AutoCorrect_replaceCorrection",args);
+}
+
+// Functions implemented in ChangeTracking.js
+
+bool JSChangeTracking::showChanges()
+{
+    QJsonValue result = evaljs(_evaluator,"ChangeTracking_showChanges",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+bool JSChangeTracking::trackChanges()
+{
+    QJsonValue result = evaljs(_evaluator,"ChangeTracking_trackChanges",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+void JSChangeTracking::setShowChanges(bool showChanges)
+{
+    JSArgs args = JSArgs() << showChanges;
+    evaljs(_evaluator,"ChangeTracking_setShowChanges",args);
+}
+
+void JSChangeTracking::setTrackChanges(bool trackChanges)
+{
+    JSArgs args = JSArgs() << trackChanges;
+    evaljs(_evaluator,"ChangeTracking_setTrackChanges",args);
+}
+
+// Functions implemented in Clipboard.js
+
+QJsonObject JSClipboard::clipboardCut()
+{
+    QJsonValue result = evaljs(_evaluator,"Clipboard_cut",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+QJsonObject JSClipboard::clipboardCopy()
+{
+    QJsonValue result = evaljs(_evaluator,"Clipboard_copy",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSClipboard::pasteHTML(const QString &html)
+{
+    JSArgs args = JSArgs() << html;
+    evaljs(_evaluator,"Clipboard_pasteHTML",args);
+}
+
+void JSClipboard::pasteText(const QString &text)
+{
+    JSArgs args = JSArgs() << text;
+    evaljs(_evaluator,"Clipboard_pasteText",args);
+}
+
+// Functions implemented in Cursor.js
+
+
+QString JSCursor::positionCursor(int x, int y, bool wordBoundary)
+{
+    JSArgs args = JSArgs() << x << y << wordBoundary;
+    QJsonValue result = evaljs(_evaluator,"Cursor_positionCursor",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QRect JSCursor::getCursorPosition()
+{
+    QJsonValue result = evaljs(_evaluator,"Cursor_getCursorPosition",JSArgs());
+    return QRectFromJson(result);
+}
+
+void JSCursor::moveLeft()
+{
+    evaljs(_evaluator,"Cursor_moveLeft",JSArgs());
+}
+
+void JSCursor::moveRight()
+{
+    evaljs(_evaluator,"Cursor_moveRight",JSArgs());
+}
+
+void JSCursor::moveToStartOfDocument()
+{
+    evaljs(_evaluator,"Cursor_moveToStartOfDocument",JSArgs());
+}
+
+void JSCursor::moveToEndOfDocument()
+{
+    evaljs(_evaluator,"Cursor_moveToEndOfDocument",JSArgs());
+}
+
+void JSCursor::insertReference(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    evaljs(_evaluator,"Cursor_insertReference",args);
+}
+
+void JSCursor::insertLink(const QString &text, const QString &url)
+{
+    JSArgs args = JSArgs() << text << url;
+    evaljs(_evaluator,"Cursor_insertLink",args);
+}
+
+void JSCursor::insertCharacter(unsigned short character, bool allowInvalidPos)
+{
+    JSArgs args = JSArgs() << QString(character) << allowInvalidPos;
+    evaljs(_evaluator,"Cursor_insertCharacter",args);
+}
+
+void JSCursor::deleteCharacter()
+{
+    evaljs(_evaluator,"Cursor_deleteCharacter",JSArgs());
+}
+
+void JSCursor::enterPressed()
+{
+    evaljs(_evaluator,"Cursor_enterPressed",JSArgs());
+}
+
+QString JSCursor::getPrecedingWord()
+{
+    QJsonValue result = evaljs(_evaluator,"Cursor_getPrecedingWord",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QJsonObject JSCursor::getLinkProperties()
+{
+    QJsonValue result = evaljs(_evaluator,"Cursor_getLinkProperties",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSCursor::setLinkProperties(QJsonObject properties)
+{
+    JSArgs args = JSArgs() << properties;
+    evaljs(_evaluator,"Cursor_setLinkProperties",args);
+}
+
+void JSCursor::setReferenceTarget(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    evaljs(_evaluator,"Cursor_setReferenceTarget",args);
+}
+
+void JSCursor::insertFootnote(const QString &content)
+{
+    JSArgs args = JSArgs() << content;
+    evaljs(_evaluator,"Cursor_insertFootnote",args);
+}
+
+void JSCursor::insertEndnote(const QString &content)
+{
+    JSArgs args = JSArgs() << content;
+    evaljs(_evaluator,"Cursor_insertEndnote",args);
+}
+
+// Functions implemented in Equations.js
+
+void JSEquations::insertEquation()
+{
+    evaljs(_evaluator,"Equations_insertEquation",JSArgs());
+}
+
+// Functions implemented in Figures.js
+
+void JSFigures::insertFigure(const QString &filename, const QString &width,
+                             bool numbered, const QString &caption)
+{
+    JSArgs args = JSArgs() << filename << width << numbered << caption;
+    evaljs(_evaluator,"Figures_insertFigure",args);
+}
+
+QString JSFigures::getSelectedFigureId()
+{
+    QJsonValue result = evaljs(_evaluator,"Figures_getSelectedFigureId",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QJsonObject JSFigures::getProperties(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    QJsonValue result = evaljs(_evaluator,"Figures_getProperties",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSFigures::setProperties(const QString &itemId, const QString &width, const QString &src)
+{
+    JSArgs args = JSArgs() << itemId << width << src;
+    evaljs(_evaluator,"Figures_setProperties",args);
+}
+
+QJsonObject JSFigures::getGeometry(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    QJsonValue result = evaljs(_evaluator,"Figures_getGeometry",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+// Functions implemented in Formatting.js
+
+QJsonObject JSFormatting::getFormatting()
+{
+    QJsonValue result = evaljs(_evaluator,"Formatting_getFormatting",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSFormatting::applyFormattingChanges(const QString &style, QJsonObject properties)
+{
+    JSArgs args = JSArgs() << style << properties;
+    evaljs(_evaluator,"Formatting_applyFormattingChanges",args);
+}
+
+// Functions implemented in Input.js
+
+void JSInput::removePosition(int posId)
+{
+    JSArgs args = JSArgs() << posId;
+    evaljs(_evaluator,"Input_removePosition",args);
+}
+
+QString JSInput::textInRange(int startId, int startAdjust, int endId, int endAdjust)
+{
+    JSArgs args = JSArgs() << startId << startAdjust << endId << endAdjust;
+    QJsonValue result = evaljs(_evaluator,"Input_textInRange",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSInput::replaceRange(int startId, int endId, const QString &text)
+{
+    JSArgs args = JSArgs() << startId << endId << text;
+    evaljs(_evaluator,"Input_replaceRange",args);
+}
+
+QJsonObject JSInput::selectedTextRange()
+{
+    QJsonValue result = evaljs(_evaluator,"Input_selectedTextRange",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSInput::setSelectedTextRange(int startId, int endId)
+{
+    JSArgs args = JSArgs() << startId << endId;
+    evaljs(_evaluator,"Input_setSelectedTextRange",args);
+}
+
+QJsonObject JSInput::markedTextRange()
+{
+    QJsonValue result = evaljs(_evaluator,"Input_markedTextRange",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSInput::setMarkedText(const QString &text, int startOffset, int endOffset)
+{
+    JSArgs args = JSArgs() << text << startOffset << endOffset;
+    evaljs(_evaluator,"Input_setMarkedText",args);
+}
+
+void JSInput::unmarkText()
+{
+    evaljs(_evaluator,"Input_unmarkText",JSArgs());
+}
+
+bool JSInput::forwardSelectionAffinity()
+{
+    QJsonValue result = evaljs(_evaluator,"Input_forwardSelectionAffinity",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+void JSInput::setForwardSelectionAffinity(bool forwardSelectionAffinity)
+{
+    JSArgs args = JSArgs() << forwardSelectionAffinity;
+    evaljs(_evaluator,"Input_setForwardSelectionAffinity",args);
+}
+
+int JSInput::positionFromPositionOffset(int posId, int offset)
+{
+    JSArgs args = JSArgs() << posId << offset;
+    QJsonValue result = evaljs(_evaluator,"Input_positionFromPositionOffset",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::positionFromPositionInDirectionOffset(int posId, const QString &direction, int offset)
+{
+    JSArgs args = JSArgs() << posId << direction << offset;
+    QJsonValue result = evaljs(_evaluator,"Input_positionFromPositionInDirectionOffset",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::comparePositionToPosition(int positionId, int otherId)
+{
+    JSArgs args = JSArgs() << positionId << otherId;
+    QJsonValue result = evaljs(_evaluator,"Input_comparePositionToPosition",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::offsetFromPositionToPosition(int fromPosition, int toPosition)
+{
+    JSArgs args = JSArgs() << fromPosition << toPosition;
+    QJsonValue result = evaljs(_evaluator,"Input_offsetFromPositionToPosition",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::positionWithinRangeFarthestInDirection(int startId, int endId, const QString &direction)
+{
+    JSArgs args = JSArgs() << startId << endId << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_positionWithinRangeFarthestInDirection",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+QJsonObject JSInput::characterRangeByExtendingPositionInDirection(int positionId, const QString &direction)
+{
+    JSArgs args = JSArgs() << positionId << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_characterRangeByExtendingPositionInDirection",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+QJsonObject JSInput::firstRectForRange(int startId, int endId)
+{
+    JSArgs args = JSArgs() << startId << endId;
+    QJsonValue result = evaljs(_evaluator,"Input_firstRectForRange",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+QJsonObject JSInput::caretRectForPosition(int posId)
+{
+    JSArgs args = JSArgs() << posId;
+    QJsonValue result = evaljs(_evaluator,"Input_caretRectForPosition",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+int JSInput::closestPositionToPoint(int x, int y)
+{
+    JSArgs args = JSArgs() << x << y;
+    QJsonValue result = evaljs(_evaluator,"Input_closestPositionToPoint",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::closestPositionToPointWithinRange(int x, int y, int startId, int endId)
+{
+    JSArgs args = JSArgs() << x << y << startId << endId;
+    QJsonValue result = evaljs(_evaluator,"Input_closestPositionToPointWithinRange",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+QJsonObject JSInput::characterRangeAtPoint(int x, int y)
+{
+    JSArgs args = JSArgs() << x << y;
+    QJsonValue result = evaljs(_evaluator,"Input_characterRangeAtPoint",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+int JSInput::positionWithinRangeAtCharacterOffset(int startId, int endId, int offset)
+{
+    JSArgs args = JSArgs() << startId << endId << offset;
+    QJsonValue result = evaljs(_evaluator,"Input_positionWithinRangeAtCharacterOffset",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::characterOffsetOfPositionWithinRange(int positionId, int startId, int endId)
+{
+    JSArgs args = JSArgs() << positionId << startId << endId;
+    QJsonValue result = evaljs(_evaluator,"Input_characterOffsetOfPositionWithinRange",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+bool JSInput::isPositionAtBoundaryGranularityInDirection(int posId, const QString &granularity,
+                                                         const QString &direction)
+{
+    JSArgs args = JSArgs() << posId << granularity << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_isPositionAtBoundaryGranularityInDirection",args);
+    return result.isBool() ? result.toBool() : false;
+}
+
+bool JSInput::isPositionWithinTextUnitInDirection(int posId, const QString &granularity,
+                                                  const QString &direction)
+{
+    JSArgs args = JSArgs() << posId << granularity << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_isPositionWithinTextUnitInDirection",args);
+    return result.isBool() ? result.toBool() : false;
+}
+
+int JSInput::positionFromPositionToBoundaryInDirection(int posId, const QString &granularity,
+                                                       const QString &direction)
+{
+    JSArgs args = JSArgs() << posId << granularity << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_positionFromPositionToBoundaryInDirection",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+QJsonObject JSInput::rangeEnclosingPositionWithGranularityInDirection(int posId,
+                                                                      const QString &granularity,
+                                                                      const QString &direction)
+{
+    JSArgs args = JSArgs() << posId << granularity << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_rangeEnclosingPositionWithGranularityInDirection",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+// Functions implemented in Lists.js
+
+void JSLists::increaseIndent()
+{
+    evaljs(_evaluator,"Lists_increaseIndent",JSArgs());
+}
+
+void JSLists::decreaseIndent()
+{
+    evaljs(_evaluator,"Lists_decreaseIndent",JSArgs());
+}
+
+void JSLists::clearList()
+{
+    evaljs(_evaluator,"Lists_clearList",JSArgs());
+}
+
+void JSLists::setUnorderedList()
+{
+    evaljs(_evaluator,"Lists_setUnorderedList",JSArgs());
+}
+
+void JSLists::setOrderedList()
+{
+    evaljs(_evaluator,"Lists_setOrderedList",JSArgs());
+}
+
+// Functions implemented in Main.js
+
+QString JSMain::getLanguage()
+{
+    QJsonValue result = evaljs(_evaluator,"Main_getLanguage",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSMain::setLanguage(const QString &language)
+{
+    JSArgs args = JSArgs() << language;
+    evaljs(_evaluator,"Main_setLanguage",args);
+}
+
+QString JSMain::setGenerator(const QString &generator)
+{
+    JSArgs args = JSArgs() << generator;
+    QJsonValue result = evaljs(_evaluator,"Main_setGenerator",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+bool JSMain::prepareForSave()
+{
+    QJsonValue result = evaljs(_evaluator,"Main_prepareForSave",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+QString JSMain::getHTML()
+{
+    QJsonValue result = evaljs(_evaluator,"Main_getHTML",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+bool JSMain::isEmptyDocument()
+{
+    QJsonValue result = evaljs(_evaluator,"Main_isEmptyDocument",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+// Functions implemented in Metadata.js
+
+QJsonObject JSMetadata::getMetadata()
+{
+    QJsonValue result = evaljs(_evaluator,"Metadata_getMetadata",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSMetadata::setMetadata(const QJsonObject &metadata)
+{
+    JSArgs args = JSArgs() << metadata;
+    evaljs(_evaluator,"Metadata_setMetadata",args);
+}
+
+// Functions implemented in Outline.js
+
+QJsonObject JSOutline::getOutline()
+{
+    QJsonValue result = evaljs(_evaluator,"Outline_getOutline",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSOutline::moveSection(const QString &sectionId, const QString &parentId, const QString &nextId)
+{
+    JSArgs args = JSArgs() << sectionId << parentId << nextId;
+    evaljs(_evaluator,"Outline_moveSection",args);
+}
+
+void JSOutline::deleteItem(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    evaljs(_evaluator,"Outline_deleteItem",args);
+}
+
+void JSOutline::goToItem(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    evaljs(_evaluator,"Outline_goToItem",args);
+}
+
+void JSOutline::scheduleUpdateStructure()
+{
+    evaljs(_evaluator,"Outline_scheduleUpdateStructure",JSArgs());
+}
+
+void JSOutline::setNumbered(const QString &itemId, bool numbered)
+{
+    JSArgs args = JSArgs() << itemId << numbered;
+    evaljs(_evaluator,"Outline_setNumbered",args);
+}
+
+void JSOutline::setTitle(const QString &itemId, const QString &title)
+{
+    JSArgs args = JSArgs() << itemId << title;
+    evaljs(_evaluator,"Outline_setTitle",args);
+}
+
+void JSOutline::insertTableOfContents()
+{
+    evaljs(_evaluator,"Outline_insertTableOfContents",JSArgs());
+}
+
+void JSOutline::insertListOfFigures()
+{
+    evaljs(_evaluator,"Outline_insertListOfFigures",JSArgs());
+}
+
+void JSOutline::insertListOfTables()
+{
+    evaljs(_evaluator,"Outline_insertListOfTables",JSArgs());
+}
+
+void JSOutline::setPrintMode(bool printMode)
+{
+    JSArgs args = JSArgs() << printMode;
+    evaljs(_evaluator,"Outline_setPrintMode",args);
+}
+
+QJsonObject JSOutline::examinePrintLayout(int pageHeight)
+{
+    JSArgs args = JSArgs() << pageHeight;
+    QJsonValue result = evaljs(_evaluator,"Outline_examinePrintLayout",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+bool JSOutline::detectSectionNumbering()
+{
+    QJsonValue result = evaljs(_evaluator,"Outline_detectSectionNumbering",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+QJsonObject JSOutline::findUsedStyles()
+{
+    QJsonValue result = evaljs(_evaluator,"Outline_findUsedStyles",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+// Functions implemented in Preview.js
+
+void JSPreview::showForStyle(const QString &styleId, const QString &uiName, const QString &title)
+{
+    JSArgs args = JSArgs() << styleId << uiName << title;
+    evaljs(_evaluator,"Preview_showForStyle",args);
+    // TODO
+}
+
+// Functions implemented in Scan.js
+
+void JSScan::reset()
+{
+    evaljs(_evaluator,"Scan_reset",JSArgs());
+}
+
+EDScanParagraph *JSScan::next()
+{
+    // TODO
+    return NULL;
+}
+
+int JSScan::addMatch(int start, int end)
+{
+    JSArgs args = JSArgs() << start << end;
+    QJsonValue result = evaljs(_evaluator,"Scan_addMatch",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+void JSScan::showMatch(int matchId)
+{
+    JSArgs args = JSArgs() << matchId;
+    evaljs(_evaluator,"Scan_showMatch",args);
+}
+
+void JSScan::replaceMatch(int matchId, const QString &text)
+{
+    JSArgs args = JSArgs() << matchId << text;
+    evaljs(_evaluator,"Scan_replaceMatch",args);
+}
+
+void JSScan::removeMatch(int matchId)
+{
+    JSArgs args = JSArgs() << matchId;
+    evaljs(_evaluator,"Scan_removeMatch",args);
+}
+
+void JSScan::goToMatch(int matchId)
+{
+    JSArgs args = JSArgs() << matchId;
+    evaljs(_evaluator,"Scan_goToMatch",args);
+}
+
+// Functions implemented in Selection.js
+
+void JSSelection::update()
+{
+    evaljs(_evaluator,"Selection_update",JSArgs());
+}
+
+void JSSelection::selectAll()
+{
+    evaljs(_evaluator,"Selection_selectAll",JSArgs());
+}
+
+void JSSelection::selectParagraph()
+{
+    evaljs(_evaluator,"Selection_selectParagraph",JSArgs());
+}
+
+void JSSelection::selectWordAtCursor()
+{
+    evaljs(_evaluator,"Selection_selectWordAtCursor",JSArgs());
+}
+
+QString JSSelection::dragSelectionBegin(int x, int y, bool selectWord)
+{
+    JSArgs args = JSArgs() << x << y << selectWord;
+    QJsonValue result = evaljs(_evaluator,"Selection_dragSelectionBegin",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::dragSelectionUpdate(int x, int y, bool selectWord)
+{
+    JSArgs args = JSArgs() << x << y << selectWord;
+    QJsonValue result = evaljs(_evaluator,"Selection_dragSelectionUpdate",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::moveStartLeft()
+{
+    QJsonValue result = evaljs(_evaluator,"Selection_moveStartLeft",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::moveStartRight()
+{
+    QJsonValue result = evaljs(_evaluator,"Selection_moveStartRight",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::moveEndLeft()
+{
+    QJsonValue result = evaljs(_evaluator,"Selection_moveEndLeft",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::moveEndRight()
+{
+    QJsonValue result = evaljs(_evaluator,"Selection_moveEndRight",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSSelection::setSelectionStartAtCoords(int x, int y)
+{
+    JSArgs args = JSArgs() << x << y;
+    evaljs(_evaluator,"Selection_setSelectionStartAtCoords",args);
+}
+
+void JSSelection::setSelectionEndAtCoords(int x, int y)
+{
+    JSArgs args = JSArgs() << x << y;
+    evaljs(_evaluator,"Selection_setSelectionEndAtCoords",args);
+}
+
+void JSSelection::setTableSelectionEdgeAtCoords(const QString &edge, int x, int y)
+{
+    JSArgs args = JSArgs() << edge << x << y;
+    evaljs(_evaluator,"Selection_setTableSelectionEdgeAtCoords",args);
+}
+
+void JSSelection::print()
+{
+    evaljs(_evaluator,"Selection_print",JSArgs());
+}
+
+// Functions implemented in Styles.js
+
+QString JSStyles::getCSSText()
+{
+    QJsonValue result = evaljs(_evaluator,"Styles_getCSSText",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSStyles::setCSSText(const QString &cssText, const QJsonObject &rules)
+{
+    JSArgs args = JSArgs() << cssText << rules;
+    evaljs(_evaluator,"Styles_setCSSText",args);
+}
+
+QString JSStyles::paragraphClass()
+{
+    QJsonValue result = evaljs(_evaluator,"Styles_getParagraphClass",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSStyles::setParagraphClass(const QString &paragraphClass)
+{
+    JSArgs args = JSArgs() << paragraphClass;
+    evaljs(_evaluator,"Styles_setParagraphClass",args);
+}
+
+// Functions implemented in Tables.js
+
+void JSTables::insertTable(int rows, int cols, const QString &width, bool numbered,
+                           const QString &caption, const QString &className)
+{
+    JSArgs args = JSArgs() << rows << cols << width << numbered << caption << className;
+    evaljs(_evaluator,"Tables_insertTable",args);
+}
+
+void JSTables::addAdjacentRow()
+{
+    evaljs(_evaluator,"Tables_addAdjacentRow",JSArgs());
+}
+
+void JSTables::addAdjacentColumn()
+{
+    evaljs(_evaluator,"Tables_addAdjacentColumn",JSArgs());
+}
+
+void JSTables::removeAdjacentRow()
+{
+    evaljs(_evaluator,"Tables_removeAdjacentRow",JSArgs());
+}
+
+void JSTables::removeAdjacentColumn()
+{
+    evaljs(_evaluator,"Tables_removeAdjacentColumn",JSArgs());
+}
+
+void JSTables::clearCells()
+{
+    evaljs(_evaluator,"Tables_clearCells",JSArgs());
+}
+
+void JSTables::mergeCells()
+{
+    evaljs(_evaluator,"Tables_mergeCells",JSArgs());
+}
+
+void JSTables::splitSelection()
+{
+    evaljs(_evaluator,"Tables_splitSelection",JSArgs());
+}
+
+QString JSTables::getSelectedTableId()
+{
+    QJsonValue result = evaljs(_evaluator,"Tables_getSelectedTableId",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QJsonObject JSTables::getProperties(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    QJsonValue result = evaljs(_evaluator,"Tables_getProperties",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSTables::setProperties(const QString &itemId, const QString &width)
+{
+    JSArgs args = JSArgs() << itemId << width;
+    evaljs(_evaluator,"Tables_setProperties",args);
+}
+
+void JSTables::setColWidths(const QString &itemId, const QJsonArray &colWidths)
+{
+    JSArgs args = JSArgs() << itemId << colWidths;
+    evaljs(_evaluator,"Tables_setColWidths",args);
+}
+
+QJsonObject JSTables::getGeometry(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    QJsonValue result = evaljs(_evaluator,"Tables_getGeometry",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+// Functions implemented in UndoManager.js
+
+int JSUndoManager::getLength()
+{
+    QJsonValue result = evaljs(_evaluator,"UndoManager_getLength",JSArgs());
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSUndoManager::getIndex()
+{
+    QJsonValue result = evaljs(_evaluator,"UndoManager_getIndex",JSArgs());
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+void JSUndoManager::setIndex(int index)
+{
+    JSArgs args = JSArgs() << index;
+    evaljs(_evaluator,"UndoManager_setIndex",args);
+}
+
+void JSUndoManager::undo()
+{
+    evaljs(_evaluator,"UndoManager_undo",JSArgs());
+}
+
+void JSUndoManager::redo()
+{
+    evaljs(_evaluator,"UndoManager_redo",JSArgs());
+}
+
+void JSUndoManager::newGroup(const QString &name)
+{
+    JSArgs args = JSArgs() << name;
+    evaljs(_evaluator,"UndoManager_newGroup",args);
+}
+
+QString JSUndoManager::groupType()
+{
+    QJsonValue result = evaljs(_evaluator,"UndoManager_groupType",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+// Functions implemented in Viewport.js
+
+void JSViewport::setViewportWidth(int width)
+{
+    JSArgs args = JSArgs() << width;
+    evaljs(_evaluator,"Viewport_setViewportWidth",args);
+}
+
+void JSViewport::setTextScale(int textScale)
+{
+    JSArgs args = JSArgs() << textScale;
+    evaljs(_evaluator,"Viewport_setTextScale",args);
+}
+
+// All modules
+
+JSInterface::JSInterface(JSEvaluator *evaluator)
+: autoCorrect(evaluator),
+  changeTracking(evaluator),
+  clipboard(evaluator),
+  cursor(evaluator),
+  equations(evaluator),
+  figures(evaluator),
+  formatting(evaluator),
+  input(evaluator),
+  lists(evaluator),
+  main(evaluator),
+  metadata(evaluator),
+  outline(evaluator),
+  preview(evaluator),
+  scan(evaluator),
+  selection(evaluator),
+  styles(evaluator),
+  tables(evaluator),
+  undoManager(evaluator),
+  viewport(evaluator)
+{
+}

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/23c028c7/consumers/corinthia/src/JSInterface.h
----------------------------------------------------------------------
diff --git a/consumers/corinthia/src/JSInterface.h b/consumers/corinthia/src/JSInterface.h
new file mode 100644
index 0000000..8cb9e85
--- /dev/null
+++ b/consumers/corinthia/src/JSInterface.h
@@ -0,0 +1,478 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <QString>
+#include <QRect>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <QTextStream>
+
+/**
+ * \file JSInterface.h
+ *
+ * C++ interface to the JavaScript editor library
+ *
+ * All of the core editing operations for Corinthia are implemented in the Editor library, which is
+ * written in JavaScript. This library can be used either from within a web browser, or, in the case
+ * of the Qt application, from an embedded web view. For this app, we use a QWebView instance which
+ * maintains the in-memory DOM tree of the document, and has injected into it all of the javascript
+ * code that is part of the editor library.
+ *
+ * The source code of the Editor library lives in (repository-root)/Editor/src. During build of the
+ * Qt app, all the javascript files are copied into (build-dir)/share/corinthia/js. If you wish to
+ * make changes to the javascript code, you should modify the files in the former location, as the
+ * latter files will be overwritten on every build.
+ *
+ * The purpose of JSInterface.h and JSInterface.cpp is to provide a C++ wrapper over this. All of
+ * the methods defined in the classes below (with the exception of callbacks) ultimately result in a
+ * call to QWebFrame's evaluateJavaScript() method. See the documentation for JSInterface.cpp for
+ * details.
+ *
+ * The editor library is divided into *modules*, each of which implements a specific aspect of
+ * editing functionality. For example, the Cursor module contains methods for moving the cursor
+ * around the document, and inserting or deleting text at the current cursor position. Similarly,
+ * the Tables module contains methods for inserting, deleting, and modifying tables. A separate C++
+ * class is defined for each module, and an instance of each class is maintained by the "container"
+ * class, JSInterface. When using the code here, you should do so via a JSInterface instance.
+ */
+
+#define JS_MODULE_COMMON(className) \
+Q_DISABLE_COPY(className) \
+public: \
+className(JSEvaluator *evaluator) : JSModule(evaluator) {}
+
+QTextStream& qStdOut();
+QString QRectString(QRect rect);
+
+/**
+ * Callback interface
+ *
+ * While the module classes are for making calls from C++ to JavaScript, the JSCallbacks abstract
+ * class is for responding to requests from JavaScript to invoke C++ code. This is declared here as
+ * an abstract class (that is, with all methods virtual and no implementations provided) to avoid
+ * dependencies between the code in this file and other parts of the application. The
+ * EditorJSCallbacks class in Editor.cpp provides a concrete implementation of this, which is where
+ * the actual callback functions are implemented.
+ *
+ * Callbacks are always invoked *after* the execution of a particular editor library API function,
+ * not during. The reason for this design design in the library was to enable support for web view
+ * classes that did not provide native support for callbacks (as was the case for iOS, at least at
+ * the time the library was originally written).
+ *
+ * The way that callbacks are invoked is that after each editor API call, a query is performed for a
+ * list of pending callback messages. The evaluation logic iterates through these and invokes the
+ * appropriate callback method for each. For this reason, callbacks method are all 'void' - they
+ * never return a value. Callbacks are for notification purposes only - typically telling the
+ * application to update the UI in some manner.
+ */
+class JSCallbacks
+{
+public:
+    virtual ~JSCallbacks() {}
+    virtual void debug(const QString &message) = 0;
+    virtual void addOutlineItem(const QString &itemId, const QString &type, const QString &title) = 0;
+    virtual void updateOutlineItem(const QString &itemId, const QString &title) = 0;
+    virtual void removeOutlineItem(const QString &itemId) = 0;
+    virtual void outlineUpdated() = 0;
+    virtual void setCursor(int x, int y, int width, int height) = 0;
+    virtual void setSelectionHandles(int x1, int y1, int height1, int x2, int y2, int height2) = 0;
+    virtual void setTableSelection(int x, int y, int width, int height) = 0;
+    virtual void setSelectionBounds(int left, int top, int right, int bottom) = 0;
+    virtual void clearSelectionHandlesAndCursor() = 0;
+    virtual void updateAutoCorrect() = 0;
+    virtual void error(const QString &message, const QString &operation) = 0;
+};
+
+/**
+ * The JSEvaluator abstract class provides an evaluate() method which is called (indirectly) by all
+ * of the individual module methods. As with JSCallbacks, it is defined as abstract to avoid a
+ * dependency on the code outside of this file. The EditorJSEvaluator class in Editor.cpp provides a
+ * concrete implementation of this; its evaluate() method simply calls through to the
+ * evaluateJavaScript() method of QWebView.
+ *
+ * JSEvaluator also has a callbacks() method, which must return an instance of JSCallbacks. This
+ * makes JSEvaluator the "central point of contact" between the JavaScript interface and the rest of
+ * the application, in that it provides the necessary access to call *in* to javascript, and to
+ * respond (via callbacks) to calls *out* of javascript. Upon initialisation of a document window,
+ * concrete implementations of both JSCallbacks and JSEvaluator are created, the latter maintaining
+ * a reference to the former. See EditorPrivate::EditorPrivate() for where ths is actually done.
+ */
+class JSEvaluator
+{
+public:
+    virtual ~JSEvaluator() {}
+    virtual QString evaluate(const QString &script) = 0;
+    virtual JSCallbacks *callbacks() = 0;
+};
+
+class JSAutoCorrect;
+class JSChangeTracking;
+class JSClipboard;
+class JSCursor;
+class JSEquations;
+class JSFigures;
+class JSFormatting;
+class JSInput;
+class JSLists;
+class JSMain;
+class JSMetadata;
+class JSOutline;
+class JSPreview;
+class JSScan;
+class JSSelection;
+class JSStyles;
+class JSTables;
+class JSUndoManager;
+class JSViewport;
+class EDScanParagraph;
+
+class JSError
+{
+public:
+    const QString &type() { return _type; }
+    const QString &message() { return _message; }
+    const QString &operation() { return _operation; }
+    const QString &html() { return _html; }
+
+private:
+
+    QString _type;
+    QString _message;
+    QString _operation;
+    QString _html;
+};
+
+class JSModule
+{
+    Q_DISABLE_COPY(JSModule)
+public:
+    JSModule(JSEvaluator *evaluator) : _evaluator(evaluator) {};
+protected:
+    JSEvaluator *_evaluator;
+};
+
+// Functions implemented in AutoCorrect.js
+
+class JSAutoCorrect : public JSModule
+{
+    JS_MODULE_COMMON(JSAutoCorrect)
+    void correctPrecedingWord(int numChars, const QString &replacement, bool confirmed);
+    QJsonObject getCorrection();
+    QJsonObject getCorrectionCoords();
+    void acceptCorrection();
+    void replaceCorrection(const QString &replacement);
+};
+
+// Functions implemented in ChangeTracking.js
+
+class JSChangeTracking : public JSModule
+{
+    JS_MODULE_COMMON(JSChangeTracking)
+    bool showChanges();
+    bool trackChanges();
+    void setShowChanges(bool showChanges);
+    void setTrackChanges(bool trackChanges);
+};
+
+// Functions implemented in Clipboard.js
+
+class JSClipboard : public JSModule
+{
+    JS_MODULE_COMMON(JSClipboard)
+    QJsonObject clipboardCut();
+    QJsonObject clipboardCopy();
+    void pasteHTML(const QString &html);
+    void pasteText(const QString &text);
+};
+
+// Functions implemented in Cursor.js
+
+class JSCursor : public JSModule
+{
+    JS_MODULE_COMMON(JSCursor)
+    QString positionCursor(int x, int y, bool wordBoundary);
+    QRect getCursorPosition();
+    void moveLeft();
+    void moveRight();
+    void moveToStartOfDocument();
+    void moveToEndOfDocument();
+    void insertReference(const QString &itemId);
+    void insertLink(const QString &text, const QString &url);
+    void insertCharacter(unsigned short character, bool allowInvalidPos);
+    void deleteCharacter();
+    void enterPressed();
+    QString getPrecedingWord();
+    QJsonObject getLinkProperties();
+    void setLinkProperties(QJsonObject properties);
+    void setReferenceTarget(const QString &itemId);
+    void insertFootnote(const QString &content);
+    void insertEndnote(const QString &content);
+};
+
+// Functions implemented in Equations.js
+
+class JSEquations : public JSModule
+{
+    JS_MODULE_COMMON(JSEquations)
+    void insertEquation();
+};
+
+// Functions implemented in Figures.js
+
+class JSFigures : public JSModule
+{
+    JS_MODULE_COMMON(JSFigures)
+    void insertFigure(const QString &filename, const QString &width,
+                      bool numbered, const QString &caption);
+    QString getSelectedFigureId();
+    QJsonObject getProperties(const QString &itemId);
+    void setProperties(const QString &itemId, const QString &width, const QString &src);
+    QJsonObject getGeometry(const QString &itemId);
+};
+
+// Functions implemented in Formatting.js
+
+class JSFormatting : public JSModule
+{
+    JS_MODULE_COMMON(JSFormatting)
+    QJsonObject getFormatting();
+    void applyFormattingChanges(const QString &style, QJsonObject properties);
+};
+
+// Functions implemented in Input.js
+
+class JSInput : public JSModule
+{
+    JS_MODULE_COMMON(JSInput)
+    void removePosition(int posId);
+
+    QString textInRange(int startId, int startAdjust, int endId, int endAdjust);
+    void replaceRange(int startId, int endId, const QString &text);
+    QJsonObject selectedTextRange();
+    void setSelectedTextRange(int startId, int endId);
+    QJsonObject markedTextRange();
+    void setMarkedText(const QString &text, int startOffset, int endOffset);
+    void unmarkText();
+    bool forwardSelectionAffinity();
+    void setForwardSelectionAffinity(bool forwardSelectionAffinity);
+    int positionFromPositionOffset(int posId, int offset);
+    int positionFromPositionInDirectionOffset(int posId, const QString &direction, int offset);
+    int comparePositionToPosition(int positionId, int otherId);
+    int offsetFromPositionToPosition(int fromPosition, int toPosition);
+    int positionWithinRangeFarthestInDirection(int startId, int endId, const QString &direction);
+    QJsonObject characterRangeByExtendingPositionInDirection(int positionId, const QString &direction);
+    QJsonObject firstRectForRange(int startId, int endId);
+    QJsonObject caretRectForPosition(int posId);
+    int closestPositionToPoint(int x, int y);
+    int closestPositionToPointWithinRange(int x, int y, int startId, int endId);
+    QJsonObject characterRangeAtPoint(int x, int y);
+    int positionWithinRangeAtCharacterOffset(int startId, int endId, int offset);
+    int characterOffsetOfPositionWithinRange(int positionId, int startId, int endId);
+
+    bool isPositionAtBoundaryGranularityInDirection(int posId, const QString &granularity,
+                                                    const QString &direction);
+    bool isPositionWithinTextUnitInDirection(int posId, const QString &granularity,
+                                             const QString &direction);
+    int positionFromPositionToBoundaryInDirection(int posId, const QString &granularity,
+                                                  const QString &direction);
+    QJsonObject rangeEnclosingPositionWithGranularityInDirection(int posId,
+                                                                 const QString &granularity,
+                                                                 const QString &direction);
+};
+
+// Functions implemented in Lists.js
+
+class JSLists : public JSModule
+{
+    JS_MODULE_COMMON(JSLists)
+    void increaseIndent();
+    void decreaseIndent();
+    void clearList();
+    void setUnorderedList();
+    void setOrderedList();
+};
+
+// Functions implemented in Main.js
+
+class JSMain : public JSModule
+{
+    JS_MODULE_COMMON(JSMain)
+    QString getLanguage();
+    void setLanguage(const QString &language);
+    QString setGenerator(const QString &generator);
+    bool prepareForSave();
+    QString getHTML();
+    bool isEmptyDocument();
+};
+
+// Functions implemented in Metadata.js
+
+class JSMetadata : public JSModule
+{
+    JS_MODULE_COMMON(JSMetadata)
+    QJsonObject getMetadata();
+    void setMetadata(const QJsonObject &metadata);
+};
+
+// Functions implemented in Outline.js
+
+class JSOutline : public JSModule
+{
+    JS_MODULE_COMMON(JSOutline)
+    QJsonObject getOutline();
+    void moveSection(const QString &sectionId, const QString &parentId, const QString &nextId);
+    void deleteItem(const QString &itemId);
+    void goToItem(const QString &itemId);
+    void scheduleUpdateStructure();
+    void setNumbered(const QString &itemId, bool numbered);
+    void setTitle(const QString &itemId, const QString &title);
+    void insertTableOfContents();
+    void insertListOfFigures();
+    void insertListOfTables();
+    void setPrintMode(bool printMode);
+    QJsonObject examinePrintLayout(int pageHeight);
+    bool detectSectionNumbering();
+    QJsonObject findUsedStyles();
+};
+
+// Functions implemented in Preview.js
+
+class JSPreview : public JSModule
+{
+    JS_MODULE_COMMON(JSPreview)
+    void showForStyle(const QString &styleId, const QString &uiName, const QString &title);
+};
+
+// Functions implemented in Scan.js
+
+class JSScan : public JSModule
+{
+    JS_MODULE_COMMON(JSScan)
+    void reset();
+    EDScanParagraph *next();
+    int addMatch(int start, int end);
+    void showMatch(int matchId);
+    void replaceMatch(int matchId, const QString &text);
+    void removeMatch(int matchId);
+    void goToMatch(int matchId);
+};
+
+// Functions implemented in Selection.js
+
+class JSSelection : public JSModule
+{
+    JS_MODULE_COMMON(JSSelection)
+    void update();
+    void selectAll();
+    void selectParagraph();
+    void selectWordAtCursor();
+    QString dragSelectionBegin(int x, int y, bool selectWord);
+    QString dragSelectionUpdate(int x, int y, bool selectWord);
+    QString moveStartLeft();
+    QString moveStartRight();
+    QString moveEndLeft();
+    QString moveEndRight();
+    void setSelectionStartAtCoords(int x, int y);
+    void setSelectionEndAtCoords(int x, int y);
+    void setTableSelectionEdgeAtCoords(const QString &edge, int x, int y);
+    void print();
+};
+
+// Functions implemented in Styles.js
+
+class JSStyles : public JSModule
+{
+    JS_MODULE_COMMON(JSStyles)
+    QString getCSSText();
+    void setCSSText(const QString &cssText, const QJsonObject &rules);
+    QString paragraphClass();
+    void setParagraphClass(const QString &paragraphClass);
+};
+
+// Functions implemented in Tables.js
+
+class JSTables : public JSModule
+{
+    JS_MODULE_COMMON(JSTables)
+    void insertTable(int rows, int cols, const QString &width, bool numbered,
+                     const QString &caption, const QString &className);
+    void addAdjacentRow();
+    void addAdjacentColumn();
+    void removeAdjacentRow();
+    void removeAdjacentColumn();
+    void clearCells();
+    void mergeCells();
+    void splitSelection();
+    QString getSelectedTableId();
+    QJsonObject getProperties(const QString &itemId);
+    void setProperties(const QString &itemId, const QString &width);
+    void setColWidths(const QString &itemId, const QJsonArray &colWidths);
+    QJsonObject getGeometry(const QString &itemId);
+};
+
+// Functions implemented in UndoManager.js
+
+class JSUndoManager : public JSModule
+{
+    JS_MODULE_COMMON(JSUndoManager)
+    int getLength();
+    int getIndex();
+    void setIndex(int index);
+    void undo();
+    void redo();
+    void newGroup(const QString &name);
+    QString groupType();
+};
+
+// Functions implemented in Viewport.js
+
+class JSViewport : public JSModule
+{
+    JS_MODULE_COMMON(JSViewport)
+    void setViewportWidth(int width);
+    void setTextScale(int textScale);
+};
+
+// All modules
+
+class JSInterface
+{
+    Q_DISABLE_COPY(JSInterface)
+public:
+    JSInterface(JSEvaluator *evaluator);
+    JSAutoCorrect autoCorrect;
+    JSChangeTracking changeTracking;
+    JSClipboard clipboard;
+    JSCursor cursor;
+    JSEquations equations;
+    JSFigures figures;
+    JSFormatting formatting;
+    JSInput input;
+    JSLists lists;
+    JSMain main;
+    JSMetadata metadata;
+    JSOutline outline;
+    JSPreview preview;
+    JSScan scan;
+    JSSelection selection;
+    JSStyles styles;
+    JSTables tables;
+    JSUndoManager undoManager;
+    JSViewport viewport;
+};
+
+void processCallbacks(JSEvaluator *evaluator);