Browse Source

Initial commit.

#111_valadoc
Kolan Sh 4 years ago
parent
commit
c070ac6d3a
40 changed files with 3433 additions and 0 deletions
  1. +6
    -0
      .gitmodules
  2. +1
    -0
      AUTHORS
  3. +22
    -0
      CMakeLists.txt
  4. +165
    -0
      COPYING
  5. +86
    -0
      INSTALL
  6. +2
    -0
      MAINTAINERS
  7. +1
    -0
      cmake/backbone
  8. +5
    -0
      config/CMakeLists.txt
  9. +6
    -0
      config/Config.vapi
  10. +3
    -0
      config/config.h.in
  11. +47
    -0
      config/ws.backbone.laview.core.gschema.xml
  12. +10
    -0
      cpack/CMakeLists.txt
  13. +17
    -0
      pkg-config/CMakeLists.txt
  14. +1
    -0
      po/CMakeLists.txt
  15. +114
    -0
      po/laview-core.pot
  16. +1
    -0
      po/ru/CMakeLists.txt
  17. +115
    -0
      po/ru/laview-core.po
  18. +9
    -0
      src/CMakeLists.txt
  19. +9
    -0
      src/conv/CMakeLists.txt
  20. +112
    -0
      src/conv/main.vala
  21. +8
    -0
      src/core-iface/CMakeLists.txt
  22. +99
    -0
      src/core-iface/CoreInterface.vala
  23. +41
    -0
      src/core/AppDirs.vala
  24. +17
    -0
      src/core/CMakeLists.txt
  25. +791
    -0
      src/core/Core.vala
  26. +16
    -0
      src/core/FileUtils.vala
  27. +92
    -0
      src/core/Templates.vala
  28. +7
    -0
      test/CMakeLists.txt
  29. +36
    -0
      test/conv-test/CMakeLists.txt
  30. +106
    -0
      test/conv-test/ConvTest.vala
  31. BIN
      test/conv-test/templates/pic/lyx.png
  32. +187
    -0
      test/conv-test/templates/templ_ex1.lyx
  33. +1295
    -0
      test/core-test/templates/example.lyx
  34. BIN
      test/core-test/templates/pics/laview-desktop.png
  35. +1
    -0
      test/host-test/CMakeLists.txt
  36. +2
    -0
      test/host-test/plugins/CMakeLists.txt
  37. +0
    -0
      test/host-test/plugins/data/CMakeLists.txt
  38. +0
    -0
      test/host-test/plugins/protocol/CMakeLists.txt
  39. +1
    -0
      util/backbone
  40. +2
    -0
      valadoc_env

+ 6
- 0
.gitmodules View File

@ -0,0 +1,6 @@
[submodule "cmake/backbone"]
path = cmake/backbone
url = git@git.backbone.ws:cmake/backbone.git
[submodule "util/backbone-utils"]
path = util/backbone
url = git@git.backbone.ws:cmake/backbone-utils.git

+ 1
- 0
AUTHORS View File

@ -0,0 +1 @@
Kolan Sh <backbone@backbone.ws>

+ 22
- 0
CMakeLists.txt View File

@ -0,0 +1,22 @@
PROJECT (LAviewCore C)
CMAKE_MINIMUM_REQUIRED (VERSION 2.8)
SET (PROJECT_LOWERCASE_NAME "laview-core")
SET (PROJECT_DESCRIPTION "LAview Core Libraries.")
SET (MAJOR 0)
SET (MINOR 0)
SET (PATCH 0)
LIST (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/backbone)
ADD_SUBDIRECTORY (config)
ADD_SUBDIRECTORY (src)
ADD_SUBDIRECTORY (po)
ADD_SUBDIRECTORY (pkg-config)
ADD_SUBDIRECTORY (test)
ADD_SUBDIRECTORY (cpack)
# enable testing
ENABLE_TESTING ()

+ 165
- 0
COPYING View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

+ 86
- 0
INSTALL View File

@ -0,0 +1,86 @@
Requirements
------------
Build-Time Dependencies
Vala: https://wiki.gnome.org/Projects/Vala
LAview-LaTeX-Struct: https://redmine.backbone.ws/projects/latex-struct
GObject-Plugin: https://redmine.backbone.ws/projects/plugin
CMake: http://www.cmake.org
NSIS (W32): http://nsis.sourceforge.net
Run-Time Dependencies
LAview-LaTeX-Struct: https://redmine.backbone.ws/projects/latex-struct
GObject-Plugin: https://redmine.backbone.ws/projects/plugin
Operation Systems
* GNU/Linux (Gentoo, Debian, etc.)
* MS Windows (Windows 5.1 aka XP)
* BSD-based (FreeBSD, OpenBSD, NetBSD, Mac OS X)
If you need support of one more OS, be free in writing of patches and sending
pull-requests to the mainstream.
Compilation
-----------
Compilation under GNU/Linux
$ mkdir build-gcc && cd build-gcc
$ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
$ make -j$((`getconf _NPROCESSORS_ONLN`+1))
Compilation under MS Windows
$ mkdir build-mingw && cd build-mingw
$ cmake -G "MSYS Makefiles" .. -DCMAKE_BUILD_TYPE=Release
$ make -j$((NUMBER_OF_PROCESSORS + 1))
Compilation under BSD-based Systems.
TODO: add description here.
Packing/Installation
--------------------
Packing/Installation under GNU/Linux
$ cpack
Install using System Package Manager.
Packing/Installation under MS Windows
$ cpack
Install using generated by NSIS executable.
Packing/Installation under BSD-based
$ cpack
Install using System Package Manager.
Testing
-------
Testing under GNU/Linux
$ ctest -j$((`getconf _NPROCESSORS_ONLN`+1))
Automated tests for memory leaks:
$ ctest -j$((NUMBER_OF_PROCESSORS + 1)) -D NightlyMemCheck && grep definitely Testing/Temporary/LastDynamicAnalysis_*.log
Testing under MS Windows
$ ctest -j$((NUMBER_OF_PROCESSORS + 1))
Automated tests for memory leaks are not available as far as Valgrind not
present on this platform.
Testing under BSD-based
$ ctest
Automated tests for memory leaks are not available as far as Valgrind not
present on this platform.

+ 2
- 0
MAINTAINERS View File

@ -0,0 +1,2 @@
Kolan Sh
email: backbone@backbone.ws

+ 1
- 0
cmake/backbone

@ -0,0 +1 @@
Subproject commit 784ca10a530e629885236e9df7fdf5647ddffa7c

+ 5
- 0
config/CMakeLists.txt View File

@ -0,0 +1,5 @@
SET (GSchemaFile "ws.backbone.laview.core")
INCLUDE (GSchemaCommonRules)
CONFIGURE_FILE ("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/config.h")

+ 6
- 0
config/Config.vapi View File

@ -0,0 +1,6 @@
[CCode (cheader_filename = "config.h")]
namespace Config {
const int VERSION_MAJOR;
const int VERSION_MINOR;
const int VERSION_PATCH;
}

+ 3
- 0
config/config.h.in View File

@ -0,0 +1,3 @@
#define CONFIG_VERSION_MAJOR @MAJOR@
#define CONFIG_VERSION_MINOR @MINOR@
#define CONFIG_VERSION_PATCH @PATCH@

+ 47
- 0
config/ws.backbone.laview.core.gschema.xml View File

@ -0,0 +1,47 @@
<schemalist>
<schema id="ws.backbone.laview.core-@MAJOR@" path="/ws/backbone/laview/core-@MAJOR@/" gettext-domain="laview-core-@MAJOR@">
<key name="templates" type="as">
<default>[]</default>
<summary>Templates</summary>
<description>Loaded templates.</description>
</key>
<key name="lyx-path" type="s">
<default>"lyx"</default>
<summary>Path to LyX binary (win32 only).</summary>
<description>Microsoft doesn't follow any file hierarchy standarts.</description>
</key>
<key name="latexmk-pl-path" type="s">
<default>"latexmk"</default>
<summary>Path to latexmk script (win32 only).</summary>
<description>Microsoft doesn't follow any file hierarchy standarts.</description>
</key>
<key name="perl-path" type="s">
<default>"perl"</default>
<summary>Path to Perl (win32 only).</summary>
<description>Microsoft doesn't follow any file hierarchy standarts.</description>
</key>
<key name="greeting" type="s">
<default l10n="messages">"Hello, earthlings"</default>
<summary>A greeting</summary>
<description>Greeting of the invading martians</description>
</key>
<key name="bottles-of-beer" type="i">
<default>99</default>
<summary>Bottles of beer</summary>
<description>Number of bottles of beer on the wall</description>
</key>
<key name="lighting" type="b">
<default>false</default>
<summary>Is the light switched on?</summary>
<description>State of an imaginary light switch.</description>
</key>
</schema>
</schemalist>

+ 10
- 0
cpack/CMakeLists.txt View File

@ -0,0 +1,10 @@
SET (CONTACT "backbone@backbone.ws")
SET (DEBIAN_DEPENDENCIES "laview-latex-struct-0 (>= 0.1.0), gobject-plugin-0 (>= 0.1.0)")
SET (DEBIAN_SECTION "Libraries")
SET (REDHAT_DEPENDENCIES "laview-latex-struct-0 >= 0.1.0, gobject-plugin-0 >= 0.1.0")
SET (REDHAT_SECTION "Applications/Text")
SET (LICENSE "LGPLv3+")
SET (WIN32_UNINSTALL_NAME "LAvCore") # <= 8 symbols for the name
SET (CPACK_NSIS_MENU_LINKS "https://redmine.backbone.ws/projects/laview-core"
"Homepage for ${PROJECT_DESCRIPTION}")
INCLUDE (CPackCommonRules)

+ 17
- 0
pkg-config/CMakeLists.txt View File

@ -0,0 +1,17 @@
INCLUDE (PkgConfigCommonRules)
SET (PkgConfigLibs "-L\${libdir}")
IF (WIN32)
SET (PkgConfigLibs "${PkgConfigLibs} -l${PROJECT_LOWERCASE_NAME}-${MAJOR}")
SET (PkgConfigLibs "${PkgConfigLibs} -l${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}")
SET (PkgConfigLibs "${PkgConfigLibs} -l${PROJECT_LOWERCASE_NAME}-conv-${MAJOR}")
ELSE (WIN32)
SET (PkgConfigLibs "${PkgConfigLibs} -l${PROJECT_LOWERCASE_NAME}.so.${MAJOR}")
SET (PkgConfigLibs "${PkgConfigLibs} -l${PROJECT_LOWERCASE_NAME}-iface.so.${MAJOR}")
SET (PkgConfigLibs "${PkgConfigLibs} -l${PROJECT_LOWERCASE_NAME}-conv.so.${MAJOR}")
ENDIF (WIN32)
CONFIGURE_FILE (
"${CMAKE_SOURCE_DIR}/cmake/backbone/templates/pkg-config.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_LOWERCASE_NAME}-${MAJOR}.pc"
)

+ 1
- 0
po/CMakeLists.txt View File

@ -0,0 +1 @@
INCLUDE (GettextCommonRules)

+ 114
- 0
po/laview-core.pot View File

@ -0,0 +1,114 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the laview-core package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: laview-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-06-23 22:28+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: config/ws.backbone.laview.core.gschema.xml.h:1
msgid "Templates"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:2
msgid "Loaded templates."
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:3
msgid "Path to LyX binary (win32 only)."
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:4
msgid "Microsoft doesn't follow any file hierarchy standarts."
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:5
msgid "Path to latexmk.pl script (win32 only)."
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:6
msgid "Path to Perl (win32 only)."
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:7
msgid "\"Hello, earthlings\""
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:8
msgid "A greeting"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:9
msgid "Greeting of the invading martians"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:10
msgid "Bottles of beer"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:11
msgid "Number of bottles of beer on the wall"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:12
msgid "Is the light switched on?"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:13
msgid "State of an imaginary light switch."
msgstr ""
#: src/conv/main.vala:37 src/conv/main.vala:52 src/conv/main.vala:71
#: src/conv/main.vala:86 src/core/Core.vala:220
msgid " not found"
msgstr ""
#: src/conv/main.vala:37 src/conv/main.vala:52 src/conv/main.vala:71
#: src/conv/main.vala:86
msgid "File "
msgstr ""
#: src/conv/main.vala:39 src/conv/main.vala:54 src/conv/main.vala:73
#: src/conv/main.vala:88
msgid " does not exists"
msgstr ""
#: src/conv/main.vala:39 src/conv/main.vala:54 src/conv/main.vala:73
#: src/conv/main.vala:88
msgid "Target directory for "
msgstr ""
#: src/conv/main.vala:56
msgid "Cann't find tex2lyx command"
msgstr ""
#: src/core/Core.vala:161
msgid "Error running lyx2tex subprocess for "
msgstr ""
#: src/core/Core.vala:204 src/core/Core.vala:213 src/core/Core.vala:533
msgid "Prepare document first."
msgstr ""
#: src/core/Core.vala:220
msgid "PDF file "
msgstr ""
#: src/core/Core.vala:544
msgid "Error running tex2lyx subprocess."
msgstr ""
#: src/core/Core.vala:546
msgid "Cann't create lyx document for editing."
msgstr ""

+ 1
- 0
po/ru/CMakeLists.txt View File

@ -0,0 +1 @@
INCLUDE (GettextLangRules)

+ 115
- 0
po/ru/laview-core.po View File

@ -0,0 +1,115 @@
# Russian translations for laview-core package.
# Copyright (C) 2015 THE laview-core'S COPYRIGHT HOLDER
# This file is distributed under the same license as the laview-core package.
# <backbone@backbone.ws>, 2015.
#
msgid ""
msgstr ""
"Project-Id-Version: laview-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-06-23 22:28+0300\n"
"PO-Revision-Date: 2015-08-30 12:46+0300\n"
"Last-Translator: <backbone@backbone.ws>\n"
"Language-Team: Russian\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: config/ws.backbone.laview.core.gschema.xml.h:1
msgid "Templates"
msgstr "Шаблоны"
#: config/ws.backbone.laview.core.gschema.xml.h:2
msgid "Loaded templates."
msgstr "Загруженные шаблоны."
#: config/ws.backbone.laview.core.gschema.xml.h:3
msgid "Path to LyX binary (win32 only)."
msgstr "Путь к исполняемому файлу LyX (только win32)."
#: config/ws.backbone.laview.core.gschema.xml.h:4
msgid "Microsoft doesn't follow any file hierarchy standarts."
msgstr "Микрософт не следует каким-либо стандартам файловой иерархии."
#: config/ws.backbone.laview.core.gschema.xml.h:5
msgid "Path to latexmk.pl script (win32 only)."
msgstr "Путь к скрипту latexmk.pl (только win32)."
#: config/ws.backbone.laview.core.gschema.xml.h:6
msgid "Path to Perl (win32 only)."
msgstr "Путь к исполняемому файлу Perl (только win32)."
#: config/ws.backbone.laview.core.gschema.xml.h:7
msgid "\"Hello, earthlings\""
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:8
msgid "A greeting"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:9
msgid "Greeting of the invading martians"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:10
msgid "Bottles of beer"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:11
msgid "Number of bottles of beer on the wall"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:12
msgid "Is the light switched on?"
msgstr ""
#: config/ws.backbone.laview.core.gschema.xml.h:13
msgid "State of an imaginary light switch."
msgstr ""
#: src/conv/main.vala:37 src/conv/main.vala:52 src/conv/main.vala:71
#: src/conv/main.vala:86 src/core/Core.vala:220
msgid " not found"
msgstr " не найден"
#: src/conv/main.vala:37 src/conv/main.vala:52 src/conv/main.vala:71
#: src/conv/main.vala:86
msgid "File "
msgstr "Файл "
#: src/conv/main.vala:39 src/conv/main.vala:54 src/conv/main.vala:73
#: src/conv/main.vala:88
msgid " does not exists"
msgstr " отсутствует"
#: src/conv/main.vala:39 src/conv/main.vala:54 src/conv/main.vala:73
#: src/conv/main.vala:88
msgid "Target directory for "
msgstr "Целевая директория для "
#: src/conv/main.vala:56
msgid "Cann't find tex2lyx command"
msgstr "Не удаётся найти команду tex2lyx"
#: src/core/Core.vala:161
msgid "Error running lyx2tex subprocess for "
msgstr "Ошибка запуска подпроцесса lyx2tex для "
#: src/core/Core.vala:204 src/core/Core.vala:213 src/core/Core.vala:533
msgid "Prepare document first."
msgstr "Сначала подготовьте документ."
#: src/core/Core.vala:220
msgid "PDF file "
msgstr "PDF файл "
#: src/core/Core.vala:544
msgid "Error running tex2lyx subprocess."
msgstr "Ошибка запуска подпроцесса tex2lyx."
#: src/core/Core.vala:546
msgid "Cann't create lyx document for editing."
msgstr "Невозможно создать lyx документ для редактирования."

+ 9
- 0
src/CMakeLists.txt View File

@ -0,0 +1,9 @@
IF (WIN32)
SET (LibValaOpts -D WINDOWS)
ELSE (WIN32)
SET (LibValaOpts -D UNIX)
ENDIF (WIN32)
ADD_SUBDIRECTORY (conv)
ADD_SUBDIRECTORY (core)
ADD_SUBDIRECTORY (core-iface)

+ 9
- 0
src/conv/CMakeLists.txt View File

@ -0,0 +1,9 @@
SET (LibName ${PROJECT_LOWERCASE_NAME}-conv)
FILE (GLOB_RECURSE LibSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.vala)
SET (LibPackages laview-latex-struct-0 gobject-plugin-iface-0 gee-0.8 gio-2.0 posix)
SET (LibPkgModules laview-latex-struct-0 gobject-plugin-0 gee-0.8 gio-2.0)
SET (LibInstall ON)
SET (LibExtraSources ${CMAKE_CURRENT_BINARY_DIR}/library_constructor.c)
SET (LC_RELATIVE_PREFIX "..")
CONFIGURE_FILE ( "${CMAKE_SOURCE_DIR}/cmake/backbone/templates/library_constructor.c.in" "${LibExtraSources}")
INCLUDE (ValaLibCommonRules)

+ 112
- 0
src/conv/main.vala View File

@ -0,0 +1,112 @@
/**
* LaTeX view.
*
* Public system of data view in the LaTeX format.
*/
namespace LAview {
/**
* LAview conversion methods.
*
* Supported formats: TeX, LyX, PDF, etc...
*/
namespace Conv {
/**
* File format converter (lyx, tex, pdf).
*/
public class Converter : Object {
public string lyx_path { get; construct; }
public string latexmk_pl_path { get; construct; }
public string perl_path { get; construct; }
/**
* Constructs a new ``Converter``.
*/
public Converter () { Object(lyx_path: "lyx", latexmk_pl_path: "latexmk", perl_path: "perl"); }
public Converter.new_with_paths (string lyx_path, string latexmk_pl_path, string perl_path) {
Object(lyx_path: lyx_path, latexmk_pl_path: latexmk_pl_path, perl_path: perl_path);
}
/**
* LyX->TeX conversion.
*/
public Subprocess lyx2tex (string lyx_file, string tex_path) throws Error {
/* check paths */
if (!File.new_for_path(lyx_file).query_exists())
throw new IOError.NOT_FOUND(_("File ")+lyx_file+_(" not found"));
if (!File.new_for_path(tex_path).get_parent().query_exists())
throw new IOError.NOT_FOUND(_("Target directory for ")+tex_path+_(" does not exists"));
return (new SubprocessLauncher( SubprocessFlags.STDIN_PIPE
| SubprocessFlags.STDOUT_PIPE
| SubprocessFlags.STDERR_PIPE))
.spawnv({ lyx_path, "-batch", "--force-overwrite", "all",
"--export-to", "latex", tex_path, lyx_file });
}
/**
* TeX->LyX conversion.
*/
public Subprocess tex2lyx (string tex_file, string lyx_file_path) throws Error {
/* check paths */
if (!File.new_for_path(tex_file).query_exists())
throw new IOError.NOT_FOUND(_("File ")+tex_file+_(" not found"));
if (!File.new_for_path(lyx_file_path).get_parent().query_exists())
throw new IOError.NOT_FOUND(_("Target directory for ")+lyx_file_path+_(" does not exists"));
var last_index_of = lyx_path.last_index_of ("lyx");
if (last_index_of == -1) throw new IOError.NOT_FOUND(_("Cann't find tex2lyx command"));
var tex2lyx_path = lyx_path.substring(0, last_index_of)
+ "tex2" + lyx_path.offset(last_index_of);
return (new SubprocessLauncher( SubprocessFlags.STDIN_PIPE
| SubprocessFlags.STDOUT_PIPE
| SubprocessFlags.STDERR_PIPE))
.spawnv({ tex2lyx_path, "-f", /*"-copyfiles",*/ tex_file, lyx_file_path });
}
/**
* LyX->PDF conversion.
*/
public Subprocess lyx2pdf (string lyx_file, string pdf_path) throws Error {
/* check paths */
if (!File.new_for_path(lyx_file).query_exists())
throw new IOError.NOT_FOUND(_("File ")+lyx_file+_(" not found"));
if (!File.new_for_path(pdf_path).get_parent().query_exists())
throw new IOError.NOT_FOUND(_("Target directory for ")+pdf_path+_(" does not exists"));
return (new SubprocessLauncher( SubprocessFlags.STDIN_PIPE
| SubprocessFlags.STDOUT_PIPE
| SubprocessFlags.STDERR_PIPE))
.spawnv({ lyx_path, "-batch", "--force-overwrite", "all",
"--export-to", "pdf", pdf_path, lyx_file });
}
/**
* TeX->PDF conversion.
*/
public Subprocess tex2pdf (string tex_file, string pdf_path) throws Error {
/* check paths */
if (!File.new_for_path(tex_file).query_exists())
throw new IOError.NOT_FOUND(_("File ")+tex_file+_(" not found"));
if (!File.new_for_path(pdf_path).get_parent().query_exists())
throw new IOError.NOT_FOUND(_("Target directory for ")+pdf_path+_(" does not exists"));
var pdf_dir = File.new_for_path(pdf_path).get_parent().get_path();
var pdf_name = File.new_for_path(pdf_path).get_basename();
pdf_name = /.pdf$/i.replace(pdf_name, -1, 0, "");
var sl = new SubprocessLauncher( SubprocessFlags.STDIN_PIPE
| SubprocessFlags.STDOUT_PIPE
| SubprocessFlags.STDERR_PIPE);
sl.set_cwd(File.new_for_path(tex_file).get_parent().get_path());
#if (UNIX)
return sl.spawnv({ "latexmk", "-output-directory="+pdf_dir,
"-jobname="+pdf_name, "-pdf", tex_file });
#elif (WINDOWS)
return sl.spawnv({ perl_path, latexmk_pl_path, "-output-directory="+pdf_dir,
"-jobname="+pdf_name, "-pdf", tex_file });
#else
assert_not_reached ();
#endif
}
}
}
}

+ 8
- 0
src/core-iface/CMakeLists.txt View File

@ -0,0 +1,8 @@
SET (LibName ${PROJECT_LOWERCASE_NAME}-iface)
FILE (GLOB_RECURSE LibSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CoreInterface.vala)
SET (LibPackages gee-0.8 gmodule-2.0 gio-2.0 gobject-plugin-iface-0)
SET (LibInstall ON)
SET (LibExtraSources ${CMAKE_CURRENT_BINARY_DIR}/library_constructor.c)
SET (LC_RELATIVE_PREFIX "..")
CONFIGURE_FILE ( "${CMAKE_SOURCE_DIR}/cmake/backbone/templates/library_constructor.c.in" "${LibExtraSources}")
INCLUDE (ValaLibCommonRules)

+ 99
- 0
src/core-iface/CoreInterface.vala View File

@ -0,0 +1,99 @@
using GObject.Plugins;
/**
* LaTeX view.
*
* Public system of data view in the LaTeX format.
*/
namespace LAview.Core {
/**
* Core Host Interface.
*/
public interface IHostCore : IHost {
/**
* Get cache directory path.
*/
public abstract string get_cache_dir ();
/**
* Get data object.
*/
public abstract PluginData get_data_object (string name);
}
/**
* Abstract plugin of type Data.
*/
public abstract class PluginData: Plugin {
/**
* Get Plugin name.
*/
public abstract string get_name ();
/**
* Get Plugin readable name.
*/
public abstract string get_readable_name ();
}
/**
* Abstract plugin of type Protocol.
*/
public abstract class PluginObject : Plugin {
/**
* Get Plugin name.
*/
public abstract string get_name ();
/**
* Get Plugin readable name.
*/
public abstract string get_readable_name ();
/**
* Compose the object.
*/
public abstract bool compose (Object parent, Gee.HashMap<string, AnswerValue> answers) throws Error;
}
/**
* Request Answer Value.
*/
public abstract class AnswerValue : Object {
}
/**
* String.
*/
public class AnswerString : AnswerValue {
public string value;
public AnswerString (string value = "") {
this.value = value;
}
}
/**
* 1D Array.
*/
public class AnswerArray1D : AnswerValue {
public string[] value;
}
/**
* 2D Array;
*/
public class AnswerArray2D : AnswerValue {
public string[,] value;
}
/**
* Picture Buffer (Currently path (String) is enough).
*/
/*public class AnswerPicBuffer : AnswerValue {
}*/
}

+ 41
- 0
src/core/AppDirs.vala View File

@ -0,0 +1,41 @@
extern void get_library_path (string so_path, void *addr);
namespace LAview.Core {
class AppDirs {
public static File so_path;
public static File exec_dir;
public static File common_dir;
public static string data_plugins_dir;
public static string object_plugins_dir;
public static string ui_dir;
public static string settings_dir;
public static string temp_dir;
public static string cache_dir;
public static void init () throws FileError {
char _so_path[256];
get_library_path ((string)_so_path, (void*)init);
so_path = File.new_for_path ((string)_so_path);
exec_dir = so_path.get_parent ();
common_dir = exec_dir.get_parent ();
ui_dir = Path.build_path (Path.DIR_SEPARATOR_S, common_dir.get_path(),
"share/laview-core-"+Config.VERSION_MAJOR.to_string()+"/ui");
settings_dir = Path.build_path (Path.DIR_SEPARATOR_S, common_dir.get_path(), "share/glib-2.0/schemas");
string w32dhack_sdir = settings_dir+"/laview-core-"+Config.VERSION_MAJOR.to_string();
if (File.new_for_path(w32dhack_sdir+"/gschemas.compiled").query_exists ())
settings_dir = w32dhack_sdir;
data_plugins_dir = Path.build_path (Path.DIR_SEPARATOR_S, exec_dir.get_path(),
"laview-core-"+Config.VERSION_MAJOR.to_string()+"/data-plugins");
object_plugins_dir = Path.build_path (Path.DIR_SEPARATOR_S, exec_dir.get_path(),
"laview-core-"+Config.VERSION_MAJOR.to_string()+"/object-plugins");
temp_dir = DirUtils.make_tmp ("laview-core-XXXXXX.temp");
cache_dir = Path.build_path (Path.DIR_SEPARATOR_S, AppDirs.temp_dir, "cache");
}
public static void terminate () throws Error {
rm_rf (File.new_for_path(temp_dir));
}
}
}

+ 17
- 0
src/core/CMakeLists.txt View File

@ -0,0 +1,17 @@
SET (LibName ${PROJECT_LOWERCASE_NAME})
FILE (GLOB_RECURSE LibSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.vala)
SET (LibPackages laview-latex-struct-0 gobject-plugin-iface-0 gobject-plugin-loader-0 gee-0.8 gio-2.0 gmodule-2.0 posix)
SET (LibCustomVapis
${CMAKE_BINARY_DIR}/src/core-iface/${PROJECT_LOWERCASE_NAME}-iface-${MAJOR}.vapi
${CMAKE_BINARY_DIR}/src/conv/${PROJECT_LOWERCASE_NAME}-conv-${MAJOR}.vapi
${CMAKE_SOURCE_DIR}/config/Config.vapi)
INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/config")
SET (LibLinkLibs ${PROJECT_LOWERCASE_NAME}-iface ${PROJECT_LOWERCASE_NAME}-conv)
INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/core-iface")
INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/conv")
SET (LibPkgModules laview-latex-struct-0 gobject-plugin-0 gee-0.8 gio-2.0 gmodule-2.0)
SET (LibInstall ON)
SET (LibExtraSources ${CMAKE_CURRENT_BINARY_DIR}/library_constructor.c)
SET (LC_RELATIVE_PREFIX "..")
CONFIGURE_FILE ( "${CMAKE_SOURCE_DIR}/cmake/backbone/templates/library_constructor.c.in" "${LibExtraSources}")
INCLUDE (ValaLibCommonRules)

+ 791
- 0
src/core/Core.vala View File

@ -0,0 +1,791 @@
using GObject, Plugins;
namespace LAview.Core {
/**
* LAview Core.
*/
public class Core : Object, IHost, IHostCore {
/** **
* --- I N T E R F A C E --- *
*/ /**/
public string lyx_path {
get { return _lyx_path; }
set {
if (settings != null) settings.set_string ("lyx-path", value);
_lyx_path = value;
}
default = "lyx";
}
public string latexmk_pl_path {
get { return _latexmk_pl_path; }
set {
if (settings != null) settings.set_string ("latexmk-pl-path", value);
_latexmk_pl_path = value;
}
default = "latexmk";
}
public string perl_path {
get { return _perl_path; }
set {
if (settings != null) settings.set_string ("perl-path", value);
_perl_path = value;
}
default = "perl";
}
public Gee.HashMap<Type, PluginData> data_plugins = new Gee.HashMap<Type, PluginData>();
public Gee.HashMap<Type, PluginObject> object_plugins = new Gee.HashMap<Type, PluginObject>();
/**
* Load Data Modules.
*/
public void load_data_modules (string dir_path) {
Gee.ArrayList<Plugins.Module> tmp_modules = null;
GObject.Plugins.load_modules (dir_path, ref tmp_modules);
foreach (var m in tmp_modules) {
if (!data_modules.contains(m)) {
data_modules.add(m);
var plugin_data = m.create_instance (this) as PluginData;
data_plugins[m.get_type()] = plugin_data;
data_plugins2[plugin_data.get_name()] = plugin_data;
}
}
}
/**
* Load Protocol Objects Modules.
*/
public void load_object_modules (string dir_path) {
Gee.ArrayList<Plugins.Module> tmp_modules = null;
GObject.Plugins.load_modules (dir_path, ref tmp_modules);
foreach (var m in tmp_modules) {
if (!object_modules.contains(m)) {
object_modules.add(m);
var plugin_object = m.create_instance (this) as PluginObject;
object_plugins[m.get_type()] = plugin_object;
object_plugins2[plugin_object.get_name()] = plugin_object;
}
}
}
/**
* Unload all Modules.
*/
public void unload_modules () {
GObject.Plugins.unload_modules (data_modules);
GObject.Plugins.unload_modules (object_modules);
}
public Core () throws Error {
/* Initialization */
AppDirs.init ();
load_data_modules (AppDirs.data_plugins_dir);
load_object_modules (AppDirs.object_plugins_dir);
settings_init ();
load_templates_list ();
_lyx_path = settings.get_string("lyx-path");
settings.changed["lyx-path"].connect (() => {
_lyx_path = settings.get_string("lyx-path");
});
_latexmk_pl_path = settings.get_string("latexmk-pl-path");
settings.changed["latexmk-pl-path"].connect (() => {
_latexmk_pl_path = settings.get_string("latexmk-pl-path");
});
_perl_path = settings.get_string("perl-path");
settings.changed["perl-path"].connect (() => {
_perl_path = settings.get_string("perl-path");
});
clear_cache ();
}
public string get_cache_dir () {
return AppDirs.cache_dir;
}
public string[] get_templates_readable_names () {
string[] names = {};
foreach (var t in templates)
names += t.get_readable_name ();
return names;
}
public string get_template_path_by_index (int index) {
return templates[index].get_path ();
}
public void add_template (string path) {
var file = File.new_for_path (path);
if (!file.query_exists() || file.query_file_type(FileQueryInfoFlags.NONE) != FileType.REGULAR)
return;
if (path.has_suffix ("lyx")) {
var t = new LyxTemplate(path);
if (!templates.contains (t))
templates.add (t);
} else if (path.has_suffix ("tex")) {
var t = new TexTemplate(path);
if (!templates.contains (t))
templates.add (t);
}
save_templates_list ();
}
public void remove_template (int index) {
if (index < templates.size)
templates.remove_at (index);
save_templates_list ();
}
public string[] get_objects_list (int template_index) throws Error {
if (template_index == last_template_index) return objects_list;
last_template_index = template_index;
/* clear */
clear_cache ();
requests = new Gee.HashMap<string, Gee.HashMap<string, AnswerValue>> ();
objects_list = { };
composed_objects = { };
var converter = new Conv.Converter.new_with_paths (_lyx_path, _latexmk_pl_path, _perl_path);
var t_path = Path.build_path (Path.DIR_SEPARATOR_S, AppDirs.cache_dir, "template.tex");
var lyx_file_path = templates[template_index].get_path();
try {
var sp = converter.lyx2tex (lyx_file_path, t_path);
#if (UNIX)
if (sp.wait_check() == false) throw new IOError.FAILED("");
#elif (WINDOWS)
sp.wait();
if (!File.new_for_path(t_path).query_exists()) throw new IOError.FAILED("");
#else
assert_not_reached ();
#endif
} catch (Error e) {
throw new IOError.FAILED(_("Error running lyx2tex subprocess for ")+lyx_file_path+".");
}
/* parse TeX */
string contents;
FileUtils.get_contents (t_path, out contents);
document = LAview.parse (contents);
var doc_stack = new Queue<IDoc> ();
doc_stack.push_tail (document);
recursive_walk (doc_stack, requests, Stage.ANALYSE);
// Return readable objects names by requests and objects plugins readable names
foreach (var req in requests.entries) {
string object_suffix, object_cmd;
var plugin = find_plugin (req.key, out object_suffix, out object_cmd);
if (plugin != null) {
objects_list += plugin.get_readable_name() + " " + object_suffix;
composed_objects += false;
}
}
return objects_list;
}
public bool compose_object (Object parent, int object_index) throws Error {
var cnt = object_index;
foreach (var req in requests.entries)
if (cnt-- == 0) {
string object_suffix, object_cmd;
var plugin = find_plugin (req.key, out object_suffix, out object_cmd);
var result = object_plugins2[plugin.get_name()].compose(parent, req.value);
if (composed_objects[object_index] == false && result == true) {
composed_objects[object_index] = true;
objects_list[object_index] = "✔ " + objects_list[object_index];
}
}
return composed_objects[object_index];;
}
public Subprocess print_document () throws Error {
foreach (var c in composed_objects)
if (c == false)
throw new IOError.FAILED (_("Prepare document first."));
generate_document_tex ();
var converter = new Conv.Converter.new_with_paths (_lyx_path, _latexmk_pl_path, _perl_path);
return converter.tex2pdf (doc_tex_path(), doc_pdf_path());
}
public string get_lyx_file_path () throws Error {
foreach (var c in composed_objects)
if (c == false)
throw new IOError.FAILED (_("Prepare document first."));
return generate_document_lyx();
}
public string get_pdf_file_path () throws Error {
var pdf_path = Path.build_path (Path.DIR_SEPARATOR_S, AppDirs.cache_dir, "document.pdf");
if (!File.new_for_path(pdf_path).query_exists())
throw new IOError.FAILED(_("PDF file ")+@"$pdf_path"+_(" not found"));
return pdf_path;
}
public PluginData get_data_object (string name) {
return data_plugins2[name];
}
/** **
* --- I M P L E M E N T A T I O N --- *
*/ /**/
string _lyx_path;
string _latexmk_pl_path;
string _perl_path;
Gee.HashMap<string, unowned PluginData> data_plugins2 = new Gee.HashMap<string, unowned PluginData>();
Gee.HashMap<string, unowned PluginObject> object_plugins2 = new Gee.HashMap<string, unowned PluginObject>();
Settings settings;
TemplateList templates = new TemplateList ();
static Gee.ArrayList<Plugins.Module> data_modules = new Gee.ArrayList<Plugins.Module>();
static Gee.ArrayList<Plugins.Module> object_modules = new Gee.ArrayList<Plugins.Module>();
Gee.HashMap<string, Gee.HashMap<string, AnswerValue>> requests;
Glob document = null;
Glob out_document = null;
string[] objects_list = { };
bool[] composed_objects = {};
int last_template_index = -1;
void settings_init () throws Error {
string schema_file = AppDirs.settings_dir+"/gschemas.compiled";
if (!File.new_for_path (schema_file).query_exists ())
throw new IOError.NOT_FOUND ("File "+schema_file+" not found");
SettingsSchemaSource sss = new SettingsSchemaSource.from_directory (AppDirs.settings_dir, null, false);
string schema_name = "ws.backbone.laview.core-"+Config.VERSION_MAJOR.to_string();
SettingsSchema schema = sss.lookup (schema_name, false);
if (schema == null) {
throw new IOError.NOT_FOUND ("Schema "+schema_name+" not found in "+schema_file);
}
settings = new Settings.full (schema, null, null);
}
void load_templates_list () {
var templates_strv = settings.get_strv("templates");
templates.clear ();
foreach (var ts in templates_strv)
add_template (ts);
}
void save_templates_list () {
string[] templates_strv = {};
foreach (var t in templates) {
templates_strv += (t.get_path ());
}
settings.set_strv("templates", templates_strv);
}
~Core () {
AppDirs.terminate ();
}
PluginObject? find_plugin (string request, out string object_suffix, out string object_cmd) {
object_suffix = null;
object_cmd = null;
var first_ = request.split_set(":?.", 2)[0];
foreach (var p in object_plugins.entries) {
if (first_.has_prefix (p.value.get_name())) {
object_suffix = first_.substring (p.value.get_name().length);
object_cmd = request.offset (first_.length + 1);
return p.value;
}
}
return null;
}
bool in_table (Queue<IDoc> doc_stack) {
var len = doc_stack.length;
return (len >= 6
&& doc_stack.peek_nth(len - 6) is Table.ATable
&& doc_stack.peek_nth(len - 5) is Table.Subtable
&& doc_stack.peek_nth(len - 4) is Table.Row
&& doc_stack.peek_nth(len - 3) is Table.Cell
&& doc_stack.peek_nth(len - 2) is Glob
) ? true : false;
}
bool check_for_addrows (Table.Cell cell, bool remove = false) {
var ret = false;
foreach (var doc in cell.contents)
if (doc is Text) {
var t = doc as Text;
if (/#\baddrows\b/.match(t.text)) {
if (remove) {
t.text = t.text.replace("#addrows", "");
}
ret = true;
}
}
return ret;
}
bool check_for_addcols (Table.Cell cell, out int max_cols, bool remove = false) {
max_cols = 0;
var ret = false;
foreach (var doc in cell.contents)
if (doc is Text) {
var t = doc as Text;
if (/\\#\baddcols\b/.match(t.text)) {
try {
var regex = new Regex ("\\\\#addcols\\\\#[0-9]+");
MatchInfo match_info;
regex.match (t.text, 0, out match_info);
while (match_info.matches ()) {
var word = match_info.fetch (0).substring(11);
max_cols = int.max(max_cols, int.parse(word));
match_info.next();
}
if (remove)
t.text = regex.replace_literal (t.text, -1, 0, "");
} catch (RegexError e) {}
ret = true;
}
}
return ret;
}
// current row contains #addrows => ++dimension
bool row_has_addrows (Table.Row row) {
foreach (var cell in row)
if (check_for_addrows(cell))
return true;
return false;
}
bool row_has_addcols (Table.Row row, uint col_index) {
uint index = 0;
foreach (var cell in row) {
if (index >= col_index)
if (check_for_addcols(cell, null))
return true;
else
return false;
else
index += cell.multitype == Table.Cell.Multitype.MULTICOL ? cell.ncells : 1;
}
return false;
}
bool subtable_has_addcols (Table.Subtable subtable, uint col_index) {
foreach (var row in subtable)
if (row_has_addcols (row, col_index)) return true;
return false;
}
// one of 5 subtables contains #addcols in current column => ++dimension
bool atable_has_addcols (Table.ATable table, Table.Row row, Table.Cell cell) {
uint col_index = 0;
foreach (var c in row) {
if (cell == c) break;
col_index += c.multitype == Table.Cell.Multitype.MULTICOL ? c.ncells : 1;
}
switch (table.get_type().name()) {
case "LAviewTableTabular":
if (subtable_has_addcols ((table as Table.Tabular).table, col_index)) return true;
break;
case "LAviewTableLongtable":
var longtable = table as Table.Longtable;
if (subtable_has_addcols (longtable.first_header, col_index)) return true;
if (subtable_has_addcols (longtable.header, col_index)) return true;
if (subtable_has_addcols (longtable.table, col_index)) return true;
if (subtable_has_addcols (longtable.footer, col_index)) return true;
if (subtable_has_addcols (longtable.last_footer, col_index)) return true;
break;
}
return false;
}
enum Stage {
ANALYSE,
FILL
}
void resize_table (Table.ATable table, ResizeInfo resize_info) {
Table.Subtable tables[] = { table.first_header, table.header, table.table,
table.footer, table.last_footer };
var ncols = table.params.size;
int nrows = 0;
foreach (var subtable in tables)
if (nrows < subtable.size)
nrows = subtable.size;
var rowsvv_b = new bool[5,nrows]; // has #addrows
var colsv_b = new bool[ncols]; // has #addcols
resize_info.colsv_max = new int[ncols]; // cols per subtable when splitting
for (var t = 0; t < 5; ++t) {
for (var i = 0; i < tables[t].size; ++i) {
for (uint j = 0, col_cnt = 0; j < tables[t][i].size; ++j) {
var cell = tables[t][i][(int)j];
if (check_for_addrows(cell)) {
rowsvv_b[t,i] = true;
check_for_addrows(cell, true);
}
int max_cols;
if (check_for_addcols(cell, out max_cols)) {
colsv_b[col_cnt] = true;
resize_info.colsv_max[col_cnt] = max_cols;
check_for_addcols(cell, null, true);
}
col_cnt += ( cell.multitype == Table.Cell.Multitype.MULTICOL
|| cell.multitype == Table.Cell.Multitype.MULTICOLROW) ?
cell.ncells : 1;
}
}
}
resize_info.colsv = new int[ncols]; // X grow size
resize_info.rowsvv = new int[5,nrows]; // Y grow size
for (var t = 0; t < 5; ++t) {
for (var i = 0; i < tables[t].size; ++i) {
for (var j = 0; j < tables[t][i].size; ++j) {
var cell = tables[t][i][j];
foreach (var subdoc in cell.contents) {
try {
var regex = new Regex ("{\\[}[^][}{]*{\\]}");
MatchInfo match_info;
regex.match ((subdoc as Text).text, 0, out match_info);
while (match_info.matches ()) {
string object_suffix, object_cmd;
var word = match_info.fetch (0);
var request = word.substring (3, word.length - 6);
var plugin = find_plugin (request, out object_suffix, out object_cmd);
if (plugin == null) { match_info.next(); continue; }
var req = requests[plugin.get_name() + object_suffix][object_cmd];
if (req is AnswerArray1D) {
if (rowsvv_b[t,i] && ! colsv_b[j])
resize_info.rowsvv[t,i] = int.max(resize_info.rowsvv[t,i], (req as AnswerArray1D).value.length);
else if (colsv_b[j] && !rowsvv_b[t,i])
resize_info.colsv[j] = int.max(resize_info.colsv[j], (req as AnswerArray1D).value.length);
} else if (req is AnswerArray2D) {
if (colsv_b[j] && rowsvv_b[t,i]) {
resize_info.rowsvv[t,i] = int.max(resize_info.rowsvv[t,i], (req as AnswerArray2D).value.length[0]);
resize_info.colsv[j] = int.max(resize_info.colsv[j], (req as AnswerArray2D).value.length[1]);
}
}
match_info.next();
}
} catch (RegexError e) {}
}
}
}
}
// add cols
for (int i = ncols - 1; i >= 0; --i)
if (colsv_b[i])
for (var j = 1; j < resize_info.colsv[i]; ++j)
table.clone_col (i, i, true);
// add rows
for (var t = 0; t < 5; ++t)
for (int r = tables[t].size; r >=0; --r)
if (rowsvv_b[t, r])
for (var j = 1; j < resize_info.rowsvv[t, r]; ++j)
tables[t].insert(r, tables[t][r].copy() as Table.Row);
}
uint split_table (Glob glob, Table.ATable table, ResizeInfo resize_info) {
try {
var limits = new List<Table.ATable.SplitLimit?> ();
if (resize_info.colsv.length != resize_info.colsv_max.length) return 1;
uint f = 0, l = 0;
for (var i = 0; i < resize_info.colsv.length; ++i) {
var colsv_i = resize_info.colsv[i] == 0 ? 1 : resize_info.colsv[i];
l = f + colsv_i - 1;
if (f != l)
limits.append(Table.ATable.SplitLimit()
{ first = f, last = l, max_cols = resize_info.colsv_max[i] });
f += colsv_i;
l = f;
}
if (limits.length() != 0) {
var delimiter = (table is Table.Tabular) ? "\\\\" : "";
return table.split(glob, limits, delimiter);
}
} catch (Error e) {
}
return 1;
}
class ResizeInfo {
public int[] colsv;
public int[] colsv_max;
public int[,] rowsvv;
}
// TODO #102: get subtable, row, col indexes by doc_stack + resize_info
void get_relative_indexes (Queue<IDoc> doc_stack, ResizeInfo resize_info, out int row_idx, out int col_idx) {
row_idx = col_idx = 0;
var subtable_idx = 0, ridx = 0, cidx = 0;
var len = doc_stack.get_length();
var c = doc_stack.peek_nth(len - 3);
var r = doc_stack.peek_nth(len - 4);
var s = doc_stack.peek_nth(len - 5);
var tab = doc_stack.peek_nth(len - 6);
if (!(c is Table.Cell && r is Table.Row && s is Table.Subtable)) return;
var row = r as Table.Row;
cidx = row.index_of(c as Table.Cell);
var subtable = s as Table.Subtable;
ridx = subtable.index_of(row);
var atable = tab as Table.ATable;
if (subtable == atable.first_header)
subtable_idx = 0;
else if (subtable == atable.header)
subtable_idx = 1;
else if (subtable == atable.table)
subtable_idx = 2;
else if (subtable == atable.footer)
subtable_idx = 3;
else if (subtable == atable.last_footer)
subtable_idx = 4;
for (int i = 0, sum = 0; i < resize_info.rowsvv.length[1]; ++i) {
var rowsvv_i = resize_info.rowsvv[subtable_idx,i];
if (rowsvv_i == 0) rowsvv_i = 1;
if (ridx >= sum && ridx < sum + rowsvv_i) {
row_idx = ridx - sum;
break;
} else {
sum += rowsvv_i;
}
}
for (int i = 0, sum = 0; i < resize_info.colsv.length; ++i) {
var colsv_i = resize_info.colsv[i];
if (colsv_i == 0) colsv_i = 1;
if (cidx >= sum && cidx < sum + colsv_i) {
col_idx = cidx - sum;
break;
} else {
sum += colsv_i;
}
}
}
uint recursive_walk (Queue<IDoc> doc_stack,
// Plugin name // Object suffix
Gee.HashMap<string, Gee.HashMap<string, AnswerValue>> requests,
Stage stage, ResizeInfo? resize_info = null) {
uint ret = 1;
var doc = doc_stack.peek_tail ();
var stack_len = doc_stack.get_length();
switch (doc.get_type().name()) {
case "LAviewTableTabular":
var tabular = doc as Table.Tabular;
var resize_info_new = new ResizeInfo();
if (stage == Stage.FILL) resize_table (tabular, resize_info_new);
doc_stack.push_tail ((doc as Table.Tabular).table);
recursive_walk (doc_stack, requests, stage, resize_info_new);
doc_stack.pop_tail ();
if (stage == Stage.FILL && stack_len > 1)
ret = split_table (doc_stack.peek_nth (stack_len - 2) as Glob, tabular, resize_info_new);
break;
case "LAviewTableLongtable":
var longtable = doc as Table.Longtable;
var resize_info_new = new ResizeInfo();
if (stage == Stage.FILL) resize_table (longtable, resize_info_new);
doc_stack.push_tail (longtable.first_header);
recursive_walk (doc_stack, requests, stage, resize_info_new);
doc_stack.pop_tail ();
doc_stack.push_tail (longtable.header);
recursive_walk (doc_stack, requests, stage, resize_info_new);
doc_stack.pop_tail ();
doc_stack.push_tail (longtable.table);
recursive_walk (doc_stack, requests, stage, resize_info_new);
doc_stack.pop_tail ();
doc_stack.push_tail (longtable.footer);
recursive_walk (doc_stack, requests, stage, resize_info_new);
doc_stack.pop_tail ();
doc_stack.push_tail (longtable.last_footer);
recursive_walk (doc_stack, requests, stage, resize_info_new);
doc_stack.pop_tail ();
if (stage == Stage.FILL && stack_len > 1)
ret = split_table (doc_stack.peek_nth (stack_len - 2) as Glob, longtable, resize_info_new);
break;
case "LAviewTableSubtable":
doc_stack.push_tail ((doc as Table.Subtable).caption);
recursive_walk (doc_stack, requests, stage, resize_info);
doc_stack.pop_tail ();
foreach (var subdoc in doc as Table.Subtable) {
doc_stack.push_tail (subdoc);
recursive_walk (doc_stack, requests, stage, resize_info);
doc_stack.pop_tail ();
}
break;
case "LAviewTableCell":
doc_stack.push_tail ((doc as Table.Cell).contents);
recursive_walk (doc_stack, requests, stage, resize_info);
doc_stack.pop_tail ();
break;
case "LAviewGraphics":
var path = (doc as Graphics).path;
string object_suffix, object_cmd;
var plugin = find_plugin (path, out object_suffix, out object_cmd);
if (plugin == null) break;
switch (stage) {
case Stage.ANALYSE:
if (!requests.has_key(plugin.get_name() + object_suffix))
requests[plugin.get_name() + object_suffix] = new Gee.HashMap<string,AnswerValue>();
requests[plugin.get_name() + object_suffix][object_cmd] = new AnswerString();
break;
case Stage.FILL:
(doc as Graphics).path =
(requests[plugin.get_name() + object_suffix][object_cmd] as AnswerString).value;
break;
}
break;
case "LAviewText":
try {
/* Replace requests with answers */
var regex = new Regex ("{\\[}[^][}{]*{\\]}");
MatchInfo match_info;
regex.match ((doc as Text).text, 0, out match_info);
var out_text = (doc as Text).text;
while (match_info.matches ()) {
var word = match_info.fetch (0);
var request = word.substring (3, word.length - 6);
// Find plugin which name conforms to request
string object_suffix, object_cmd;
var plugin = find_plugin (request, out object_suffix, out object_cmd);
if (plugin == null) { match_info.next(); continue; }
switch (stage) {
case Stage.ANALYSE:
AnswerValue answer;
var dimension = 0;
if (in_table(doc_stack)) {
// Determine answer type (text, vector, matrix).
dimension += row_has_addrows (doc_stack.peek_nth(doc_stack.length - 4) as Table.Row) ? 1 : 0;
var len = doc_stack.length;
var table = doc_stack.peek_nth(len - 6) as Table.ATable;
var row = doc_stack.peek_nth(len - 4) as Table.Row;
var cell = doc_stack.peek_nth(len - 3) as Table.Cell;
dimension += atable_has_addcols (table, row, cell) ? 1 : 0;
}
switch (dimension) {
case 1: answer = new AnswerArray1D(); break;
case 2: answer = new AnswerArray2D(); break;
default: answer = new AnswerString(); break;
}
if (!requests.has_key(plugin.get_name() + object_suffix))
requests[plugin.get_name() + object_suffix] = new Gee.HashMap<string,AnswerValue>();
requests[plugin.get_name() + object_suffix][object_cmd] = answer;
break;
case Stage.FILL:
var answer = requests[plugin.get_name() + object_suffix].get(object_cmd);
var dimension = 0;
if (answer is AnswerArray1D) dimension = 1;
if (answer is AnswerArray2D) dimension = 2;
switch (dimension) {
case 1: // Array 1D
var arr = answer as AnswerArray1D;
var row_idx = 0, col_idx = 0;
get_relative_indexes(doc_stack, resize_info, out row_idx, out col_idx);
var max_idx = int.max(row_idx, col_idx);
if (max_idx < arr.value.length)
out_text = arr.value[max_idx];
else
out_text = _("IdxError");
break;
case 2: // Array 2D
var arr = answer as AnswerArray2D;
var row_idx = 0, col_idx = 0;
get_relative_indexes(doc_stack, resize_info, out row_idx, out col_idx);
if (row_idx < arr.value.length[0] && col_idx < arr.value.length[1])
out_text = arr.value[row_idx, col_idx];
else
out_text = _("IdxError");
break;
default: // Text/String
out_text = out_text.replace("{[}"+request+"{]}", (answer as AnswerString).value);
break;
}
break;
}
match_info.next();
}
/* Replace ViewName */
regex = new Regex ("@LAview\\.ViewName=[^@]+@");
regex.match (out_text, 0, out match_info);
if (match_info.matches ()) {
var word = match_info.fetch (0);
out_text = out_text.replace(word, "");
}
(doc as Text).text = out_text ;
} catch (RegexError e) {}
break;
default:
if (doc is ADocList) {
var d = doc as ADocList<IDoc>;
for (var i = 0; i < d.size; ) {
var subdoc = d[i];
doc_stack.push_tail (subdoc);
i += (int)recursive_walk (doc_stack, requests, stage, resize_info);
doc_stack.pop_tail ();
}
}
break;
}
return 1;
}
string doc_tex_path () {
return Path.build_path (Path.DIR_SEPARATOR_S, AppDirs.cache_dir, "document.tex");
}
string doc_lyx_path () {
return Path.build_path (Path.DIR_SEPARATOR_S, AppDirs.cache_dir, "document.lyx");
}
string doc_pdf_path () {
return Path.build_path (Path.DIR_SEPARATOR_S, AppDirs.cache_dir, "document.pdf");
}
void generate_document_tex () throws Error {
if (document == null)
throw new IOError.FAILED (_("Prepare document first."));
var doc_stack = new Queue<IDoc> ();
out_document = document.copy () as Glob;
doc_stack.push_tail (out_document);
recursive_walk (doc_stack, requests, Stage.FILL);
FileUtils.set_contents (doc_tex_path (), out_document.generate ());
}
string generate_document_lyx () throws Error {
generate_document_tex ();
var converter = new Conv.Converter.new_with_paths (_lyx_path, _latexmk_pl_path, _perl_path);
var sp = converter.tex2lyx (doc_tex_path(), doc_lyx_path());
if (sp.wait_check() == false) throw new IOError.FAILED(_("Error running tex2lyx subprocess."));
if (!File.new_for_path(doc_lyx_path()).query_exists())
throw new IOError.FAILED(_("Cann't create lyx document for editing."));
return doc_lyx_path();
}
void clear_cache () throws Error {
try {
rm_rf (File.new_for_path (AppDirs.cache_dir));
} catch (Error e) {
}
File.new_for_path (AppDirs.cache_dir).make_directory();
}
}
}

+ 16
- 0
src/core/FileUtils.vala View File

@ -0,0 +1,16 @@
namespace LAview.Core {
void rm_rf (File directory) throws Error {
var children = directory.enumerate_children ("standard::*",
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
FileInfo fileinfo = null;
while ((fileinfo = children.next_file (null)) != null ) {
File child = directory.resolve_relative_path (fileinfo.get_name ());
if (fileinfo.get_file_type () == FileType.DIRECTORY) {
rm_rf (child);
} else {
child.delete();
}
}
directory.delete();
}
}

+ 92
- 0
src/core/Templates.vala View File

@ -0,0 +1,92 @@
using GObject, Plugins;
namespace LAview.Core {
/**
* Template Interface.
*/
public abstract interface ITemplate : Object {
public abstract string get_readable_name ();
public abstract string get_path ();
public abstract bool is_equal_to (ITemplate template);
}
/**
* LyX File Template.
*/
public class LyxTemplate : Object, ITemplate {
File file;
string _readable_name = null;
public LyxTemplate (string file) {
this.file = File.new_for_path (file);
}
public string get_readable_name () {
if (_readable_name == null) {
string contents;
try {
FileUtils.get_contents (file.get_path(), out contents);
var regex = new Regex ("@LAview\\.ViewName=[^@]+@");
MatchInfo match_info;
regex.match (contents, 0, out match_info);
if (match_info.matches ()) {
var word = match_info.fetch (0);
_readable_name = word.substring(17, word.length - 17 - 1).strip();
}
} catch (Error e) {
_readable_name = file.get_basename();
}
}
return _readable_name;
}
public bool is_equal_to (ITemplate template) {
if (template is LyxTemplate)
return (template as LyxTemplate).file.get_path() == file.get_path();
return false;
}
public string get_path () { return file.get_path(); }
}
/**
* LyX File Template.
*/
public class TexTemplate : Object, ITemplate {
File file;
public TexTemplate (string file) {
this.file = File.new_for_path (file);
}
public string get_readable_name () {
return file.get_basename();
}
public bool is_equal_to (ITemplate template) {
if (template is TexTemplate)
return (template as TexTemplate).file.get_path() == file.get_path();
return false;
}
public string get_path () { return file.get_path(); }
}
public class TemplateList : Gee.ArrayList<ITemplate> {
public override bool contains (ITemplate template) {
foreach (var t in this)
if (t.is_equal_to (template))
return true;
return false;
}
}
}

+ 7
- 0
test/CMakeLists.txt View File

@ -0,0 +1,7 @@
ADD_SUBDIRECTORY (conv-test)
ADD_SUBDIRECTORY (host-test)
INSTALL (DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/core-test/templates
DESTINATION share/${PROJECT_LOWERCASE_NAME}-${MAJOR})
INCLUDE (CTest)

+ 36
- 0
test/conv-test/CMakeLists.txt View File

@ -0,0 +1,36 @@
SET (BinName conv_test)
FILE (GLOB_RECURSE BinSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ConvTest.vala)
SET (BinPackages gee-0.8 gio-2.0)
SET (BinCustomVapis ${CMAKE_BINARY_DIR}/src/conv/${PROJECT_LOWERCASE_NAME}-conv-${MAJOR}.vapi)
SET (BinLinkLibs ${PROJECT_LOWERCASE_NAME}-conv)
INCLUDE_DIRECTORIES ("${CMAKE_BINARY_DIR}/src/conv")
INCLUDE (ValaBinCommonRules)
## Parse tests
#MACRO (do_parse_test testname table_path etalon_path regexp)
# IF ("${etalon_path}" STREQUAL "")
# SET (extra_args "")
# ELSE ()
# SET (extra_args --etalon ${etalon_path})
# ENDIF ()
# ADD_TEST (ParseTest-${testname} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/parse_test --table ${table_path} ${extra_args})
# SET_TESTS_PROPERTIES (ParseTest-${testname}
# PROPERTIES PASS_REGULAR_EXPRESSION ${regexp}
# FAIL_REGULAR_EXPRESSION "CRITICAL;WARNING")
#ENDMACRO (do_parse_test)
#
## test throttle.tex
#do_parse_test (throttleList ${PROJECT_SOURCE_DIR}/test/tex/throttle.tex ""
#"list all objects
#LAviewText
#LAviewTableLongtable
#LAviewText
#LAviewTableTabular
#LAviewText
#end of objects
#
#")
#SET_TESTS_PROPERTIES(ParseTest-throttleList PROPERTIES ENVIRONMENT "LANG=en")
#
## enable testing
#ENABLE_TESTING ()

+ 106
- 0
test/conv-test/ConvTest.vala View File

@ -0,0 +1,106 @@
/**
* LyX->PDF test
*/
void lyx2pdf_test (string[] args) {
Subprocess sp = null;
try {
sp = (new LAview.Conv.Converter()).lyx2pdf(Path.build_path (Path.DIR_SEPARATOR_S,
File.new_for_path(args[0]).get_parent().get_parent().get_parent().get_path(),
"test/conv-test/templates/templ_ex1.lyx"), "templ_ex1.pdf");
if (sp.wait_check() == false) throw new IOError.FAILED("Error running subprocess.");
stdout.puts("=== Converting LyX->PDF... ===\n");
var ds_out = new DataInputStream(sp.get_stdout_pipe());
try {
for (string s = ds_out.read_line(); s != null; s = ds_out.read_line())
stdout.printf("%s\n", s);
} catch (IOError err) {
assert_not_reached();
}
} catch (Error err) {
stdout.printf("Error: %s\n", err.message);
if (sp != null) {
var ds_err = new DataInputStream(sp.get_stderr_pipe());
try {
for (string s = ds_err.read_line(); s != null; s = ds_err.read_line())
stdout.printf("%s\n", s);
} catch (IOError err) {
assert_not_reached();
}
}
}
}