ATable::split () added.

Split an ATable into several ATables by columns according to the limits.
This commit is contained in:
Kolan Sh 2014-07-25 18:29:22 +04:00
parent 87457ff03e
commit 62b56bcbb0
8 changed files with 520 additions and 3 deletions

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: laview-latex-struct-0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-07-18 18:10+0400\n"
"POT-Creation-Date: 2014-07-31 18:16+0400\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"
@ -41,6 +41,18 @@ msgstr ""
msgid "Incorrect longtable parameters doesn't match '%s' regexp."
msgstr ""
#: /home/kolan/projects/LAview/LaTeX-Struct/src/Table.vala:298
msgid "2nd param (ATable) isn't a child of the 1st (Glob)."
msgstr ""
#: /home/kolan/projects/LAview/LaTeX-Struct/src/Table.vala:312
msgid "3rd param (limits) is incorrect. Read the manual."
msgstr ""
#: /home/kolan/projects/LAview/LaTeX-Struct/src/Table.vala:329
msgid "Cann't split the table. Read the manual."
msgstr ""
#: /home/kolan/projects/LAview/LaTeX-Struct/src/TableParser.vala:413
#, c-format
msgid "Unexpected end external tag sequence '%s' without begin tag pair."

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: laview-latex-struct-0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-07-18 18:10+0400\n"
"POT-Creation-Date: 2014-07-31 18:16+0400\n"
"PO-Revision-Date: 2014-05-28 10:50+0400\n"
"Last-Translator: <backbone@backbone.ws>\n"
"Language-Team: Russian\n"
@ -44,6 +44,18 @@ msgstr "Ошибка разбора поддокумента."
msgid "Incorrect longtable parameters doesn't match '%s' regexp."
msgstr "Неверные параметры longtable не удовлетворяют рег. выражению '%s'."
#: /home/kolan/projects/LAview/LaTeX-Struct/src/Table.vala:298
msgid "2nd param (ATable) isn't a child of the 1st (Glob)."
msgstr "2-ой параметр (ATable) не является дочерним узлом 1-ого (Glob)."
#: /home/kolan/projects/LAview/LaTeX-Struct/src/Table.vala:312
msgid "3rd param (limits) is incorrect. Read the manual."
msgstr "3-ий параметр (limits) не верный. Смотрите документацию."
#: /home/kolan/projects/LAview/LaTeX-Struct/src/Table.vala:329
msgid "Cann't split the table. Read the manual."
msgstr "Невозможно разбить таблицу. Смотрите документацию."
#: /home/kolan/projects/LAview/LaTeX-Struct/src/TableParser.vala:413
#, c-format
msgid "Unexpected end external tag sequence '%s' without begin tag pair."

View File

@ -5,6 +5,27 @@ namespace LAview {
*/
namespace Table {
/**
* Any error at ``ATable`` splitting.
*/
public errordomain SplitError {
/**
* ``ATable`` isn't a child of the {@link Glob}.
*/
ISNT_CHILD,
/**
* Any errors in the split indexes.
*/
INDEX_ERROR,
/**
* Any other error.
*/
OTHER,
}
/**
* Any Table in the LaTeX document.
*/
@ -58,7 +79,7 @@ namespace LAview {
* Gets a copy of the ``ATable``.
*/
public override IDoc copy () {
var clone = Object.new (this.get_type ()) as ATable;
var clone = Object.new (get_type ()) as ATable;
clone.align = align;
clone.style = style;
@ -176,6 +197,139 @@ namespace LAview {
last_footer.clone_col (src_index, dest_index, multicol, line_style);
table.clone_col (src_index, dest_index, multicol, line_style);
}
/**
* Bounds of the ``ATable`` to split.
*/
public struct SplitLimit {
/**
* First column index [0; last].
*/
uint first;
/**
* Last column index [first; ncols - 1].
*/
uint last;
/**
* Maximum of columns per page [1; ncols].
*/
uint max_cols;
}
bool check_limits (Array<SplitLimit?> sorted_limits) {
/* check nearby limits */
for (var i = 1; i < sorted_limits.length; ++i)
if (sorted_limits.index (i - 1).last >= sorted_limits.index (i).first
|| sorted_limits.index (i).first > sorted_limits.index (i).last)
return false;
/* check limits of the first and last elements */
if (sorted_limits.index (0).first > sorted_limits.index (0).last
|| params.size <= sorted_limits.index (sorted_limits.length - 1).last)
return false;
return true;
}
uint [] get_indexes (Array<SplitLimit?> sorted_limits) {
var lim_indexes = new uint[sorted_limits.length];
for (var i = 0; i < sorted_limits.length; ++i)
lim_indexes[i] = sorted_limits.index (i).first;
return lim_indexes;
}
ATable? split_table (Array<SplitLimit?> sorted_limits, uint [] lim_indexes,
Row.OpLineStyle line_style) {
var return_table = copy () as ATable;
bool split_finish = true;
/* removing spare columns */
for (uint i = sorted_limits.length - 1; i < sorted_limits.length; --i) { // group
for (uint j = sorted_limits.index (i).last;
j >= lim_indexes[i] + sorted_limits.index (i).max_cols
&& j <= sorted_limits.index (i).last; --j)
return_table.remove_col ((int)j, line_style);
for (uint j = lim_indexes[i] - 1; j >= sorted_limits.index (i).first && j < lim_indexes[i]; --j)
return_table.remove_col ((int)j, line_style);
/* count indexes */
if (lim_indexes[i] <= sorted_limits.index (i).last) {
split_finish = false;
lim_indexes[i] += sorted_limits.index (i).max_cols;
}
}
/* did any indexes updated */
if (split_finish)
return null;
return return_table;
}
/**
* Split an ``ATable`` into several ``ATable``s by columns according to the limits.
*
* For example: table<<BR>>
* ``[fix1 fix2 colA1 colA2 colA3 colA4 colA5 fix3 fix4 colB1 colB2 colB3 colB4 fix5 fix6]``<<BR>>
* with limits { {2, 6, 2}, {9, 12, 3} }<<BR>>
* will be splitted into 3 tables<<BR>>
* [fix1 fix2 colA1 colA2 fix3 fix4 colB1 colB2 colB3 fix5 fix6]<<BR>>
* [fix1 fix2 colA3 colA4 fix3 fix4 colB4 fix6]<<BR>>
* [fix1 fix2 colA5 fix3 fix4 fix6]<<BR>>
* 3rd param 'limits'. For all elements following conditions should be satisfied.
* last[i] < first[i+1], 0 <= first[i] <= last[i] <= ncols-1, 1 <= max_cols <= ncols.
*
* @param glob {@link Glob} document with a ``ATable``.
* @param limits array of {@link SplitLimit}s.
* @param line_style {@link Row.OpLineStyle} of the operation.
*
* @return number of ``ATable``s the table splitted to.
*/
public uint split (Glob glob, Array<SplitLimit?> limits,
Row.OpLineStyle line_style = Row.OpLineStyle.BORDER_DBLLINES) throws SplitError {
/* is table a child of glob */
var glob_index = glob.index_of (this);
if (glob_index == -1)
throw new SplitError.ISNT_CHILD (_("2nd param (ATable) isn't a child of the 1st (Glob)."));
/* sorting limits */
var sorted_limits = new Array<SplitLimit?>.sized (false, false, sizeof (SplitLimit), limits.length);
sorted_limits.append_vals (limits.data, limits.length);
sorted_limits.sort ((ref a, ref b) => {
if (a.first < b.first) return -1;
if (a.first > b.first) return 1;
return 0;
});
/* checking limits for intersections */
if (!check_limits (sorted_limits))
throw new SplitError.INDEX_ERROR (_("3rd param (limits) is incorrect. Read the manual."));
/* split the table on several longtables inserting them before glob_index + 1 */
var lim_indexes = get_indexes (sorted_limits);
ATable temp_table;
uint result = 0;
var part_idx = glob_index + 1;
while (null != (temp_table = split_table (sorted_limits, lim_indexes, line_style))) {
glob.insert (part_idx++, temp_table);
++result;
}
/* remove table from the doc */
if (result != 0)
glob.remove_at (glob_index);
else
throw new SplitError.OTHER (_("Cann't split the table. Read the manual."));
return result;
}
}
}
}

View File

@ -33,6 +33,18 @@ VALA_PRECOMPILE (LTableTest_C ${LTableTestSources}
ADD_EXECUTABLE (LTableTest ${LTableTest_C})
TARGET_LINK_LIBRARIES (LTableTest ${PROJ_LCASE} ${GEE_LIBRARIES})
# add split_test executable
FILE (GLOB_RECURSE LTableTestSources RELATIVE ${CMAKE_SOURCE_DIR}/test SplitTest.vala)
VALA_PRECOMPILE (SplitTest_C ${LTableTestSources}
PACKAGES gee-0.8 posix
OPTIONS --thread ${VALA_DEBUG}
CUSTOM_VAPIS ${PROJECT_BINARY_DIR}/src/${PROJ_LCASE}-${MAJOR}.vapi
GENERATE_VAPI
GENERATE_HEADER
)
ADD_EXECUTABLE (SplitTest ${SplitTest_C})
TARGET_LINK_LIBRARIES (SplitTest ${PROJ_LCASE} ${GEE_LIBRARIES})
# parsing test macro
MACRO (do_parse_test testname table_path etalon_path regexp)
IF ("${etalon_path}" STREQUAL "")
@ -386,5 +398,19 @@ ltable_test (clone_1000_0 ${PROJECT_SOURCE_DIR}/test/tex/formular.tex ${PROJECT_
ltable_test (append_row0 ${PROJECT_SOURCE_DIR}/test/tex/table_rows.tex ${PROJECT_SOURCE_DIR}/test/tex/table_rows.etalon.tex append_row0
"Etalon and generated text are EQUAL .-.")
MACRO (do_split_test testname limits table etalon regexp)
ADD_TEST (split_test-${testname} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/SplitTest
--limits ${limits} --table ${table} --etalon ${etalon})
SET_TESTS_PROPERTIES (split_test-${testname}
PROPERTIES PASS_REGULAR_EXPRESSION ${regexp}
FAIL_REGULAR_EXPRESSION "CRITICAL;WARNING")
ENDMACRO (do_split_test)
# test TeXReport_splitLongtable () function
do_split_test (split_test ${PROJECT_SOURCE_DIR}/test/tex/limits1.in
${PROJECT_SOURCE_DIR}/test/tex/limits_table1.tex
${PROJECT_SOURCE_DIR}/test/tex/limits_table1.etalon.tex
"Etalon and generated text are EQUAL ...\n")
# enable testing
ENABLE_TESTING ()

137
test/SplitTest.vala Normal file
View File

@ -0,0 +1,137 @@
using LAview;
public class Main : Object {
static string fname_limits = "";
static string fname_table = "";
static string fname_etalon = "";
static string fname_write = "";
const OptionEntry [] options = {
{ "limits", 'l', 0, OptionArg.FILENAME, ref fname_limits, "File with limits", null },
{ "table", 't', 0, OptionArg.FILENAME, ref fname_table, "File with a table", null },
{ "etalon", 'e', 0, OptionArg.FILENAME, ref fname_etalon, "File with etalon table", null },
{ "write", 'w', 0, OptionArg.FILENAME, ref fname_write, "File to write", null },
{ null }
};
public static int main (string [] args) {
Intl.setlocale (LocaleCategory.ALL, "");
/* commandline arguments processing */
try {
var opt_context = new OptionContext ("- tests LaTeX parser");
opt_context.set_help_enabled (true);
opt_context.add_main_entries (options, null);
opt_context.parse (ref args);
} catch (OptionError e) {
stderr.printf ("error: %s\n", e.message);
stderr.printf ("Run '%s --help' to see a full list of available command line options.\n", args[0]);
return -1;
}
/* read limits */
if (fname_limits == null) {
stderr.printf ("Specify file with limits\n");
return -1;
}
var stream = FileStream.open (fname_limits, "r");
if (stream == null) {
stdout.puts ("Cann't open limits file\n");
return -1;
}
uint lim[3] = { 0, 0, 0};
var limits = new Array<Table.ATable.SplitLimit?> ();
while (3 == stream.scanf ("%u %u %u", out lim[0], out lim[1], out lim[2])) {
var split_lim = Table.ATable.SplitLimit ();
split_lim.first = lim[0];
split_lim.last = lim[1];
split_lim.max_cols = lim[2];
limits.append_val (split_lim);
}
/* read table */
if (fname_table == null) {
stderr.printf ("Specify file with a table or read help (%s --help)", args[0]);
return -1;
}
/* load file contents */
string contents;
try {
FileUtils.get_contents (fname_table, out contents);
} catch (FileError e) {
stderr.printf ("error: %s\n", e.message);
return -1;
}
/* parse TeX */
Glob doc;
try {
doc = LAview.parse (contents);
stdout.printf ("TeX document successfully parsed\n");
} catch (Parsers.ParseError e) {
stderr.printf ("Error parsing TeX document: %s\n", e.message);
return -1;
}
/* find a longtable object */
Table.Longtable table = null;
foreach (var subdoc in doc) {
if (subdoc is Table.Longtable) {
table = subdoc as Table.Longtable;
break;
}
}
if (table == null) {
stderr.puts ("longtable object not found\n");
return -1;
}
/* split the table */
try {
table.split (doc, limits);
} catch (Table.SplitError e) {
stderr.puts (e.message);
return -1;
}
/* load etalon file */
if (fname_etalon != null) {
try {
FileUtils.get_contents (fname_etalon, out contents);
} catch (FileError e) {
stderr.printf ("error: %s\n", e.message);
return -1;
}
}
/* generate */
var generated = doc.generate ();
/* compare with an etalon */
if (contents == generated)
stdout.puts ("Etalon and generated text are EQUAL ;-)\n");
else
stdout.puts ("Etalon and generated text are NOT EQUAL ;-(\n");
stdout.printf ("--- Generated plain-TeX (generated) ---\n%s", generated);
/* write to file */
if (fname_write != null )
try {
FileUtils.set_contents (fname_write, generated);
} catch (FileError e) {
stderr.printf ("error: %s\n", e.message);
return -1;
}
return 0;
}
}

3
test/tex/limits1.in Normal file
View File

@ -0,0 +1,3 @@
9 11 3
2 6 2
13 16 1

View File

@ -0,0 +1,127 @@
%% LyX 2.0.3 created this file. For more info, see http://www.lyx.org/.
%% Do not edit unless you really know what you are doing.
\documentclass[english]{article}
\usepackage[T1]{fontenc}
\usepackage[latin9]{inputenc}
\usepackage{longtable}
\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.
%% Because html converters don't know tabularnewline
\providecommand{\tabularnewline}{\\}
\makeatother
\usepackage{babel}
\begin{document}
\begin{longtable}{|c|c|c|c|c|c|c|c|c|c|c|c|}
\hline
fh1 & fh2 & fh3 & fh4 & fh8 & fh9 & fh10 & fh11 & fh12 & fh13 & fh14 & fh18\tabularnewline
\endfirsthead
\hline
h1 & h2 & h3 & h4 & h8 & h9 & h10 & h11 & h12 & h13 & h14 & h18\tabularnewline
\endhead
\hline
f1 & f2 & f3 & f4 & f8 & f9 & f10 & f11 & f12 & f13 & f14 & f18\tabularnewline
\hline
a1 & a2 & a3 & a4 & a8 & a9 & a10 & a11 & a12 & a13 & a14 & a18\tabularnewline
\hline
\hline
b1 & b2 & \multicolumn{2}{c|}{b3} & b8 & b9 & b10 & b11 & b12 & b13 & b14 & \multicolumn{1}{c|}{b15}\tabularnewline
\hline
\multicolumn{4}{|c|}{c1} & c8 & c9 & \multicolumn{3}{c|}{c10} & c13 & c14 & c18\tabularnewline
\hline
d1 & d2 & d3 & \multicolumn{6}{c|}{d4} & d13 & d14 & \multicolumn{1}{c|}{d16}\tabularnewline
\hline
\multicolumn{4}{|c|}{e1} & e8 & e9 & e10 & e11 & \multicolumn{3}{c|}{e12} & e18\tabularnewline
\hline
g1 & g2 & \multicolumn{9}{c|}{g3} & g18\tabularnewline
\hline
\multicolumn{11}{|c|}{i1} & i3\tabularnewline
\hline
j1 & \multicolumn{11}{c|}{j2}\tabularnewline
\hline
\end{longtable}\begin{longtable}{|c|c|c|c|c|c|c|c|c|}
\hline
fh1 & fh2 & fh5 & fh6 & fh8 & fh9 & fh13 & fh15 & fh18\tabularnewline
\endfirsthead
\hline
h1 & h2 & h5 & h6 & h8 & h9 & h13 & h15 & h18\tabularnewline
\endhead
\hline
f1 & f2 & f5 & f6 & f8 & f9 & f13 & f15 & f18\tabularnewline
\hline
a1 & a2 & a5 & a6 & a8 & a9 & a13 & a15 & a18\tabularnewline
\hline
\hline
b1 & b2 & \multicolumn{2}{c|}{b3} & b8 & b9 & b13 & \multicolumn{2}{c|}{b15}\tabularnewline
\hline
\multicolumn{2}{|c|}{c1} & c5 & c6 & c8 & c9 & c13 & c15 & c18\tabularnewline
\hline
d1 & d2 & \multicolumn{4}{c|}{d4} & d13 & d15 & \multicolumn{1}{c|}{d16}\tabularnewline
\hline
\multicolumn{3}{|c|}{e1} & e6 & e8 & e9 & \multicolumn{2}{c|}{e12} & e18\tabularnewline
\hline
g1 & g2 & \multicolumn{6}{c|}{g3} & g18\tabularnewline
\hline
\multicolumn{8}{|c|}{i1} & i3\tabularnewline
\hline
j1 & \multicolumn{8}{c|}{j2}\tabularnewline
\hline
\end{longtable}\begin{longtable}{|c|c|c|c|c|c|c|c|}
\hline
fh1 & fh2 & fh7 & fh8 & fh9 & fh13 & fh16 & fh18\tabularnewline
\endfirsthead
\hline
h1 & h2 & h7 & h8 & h9 & h13 & h16 & h18\tabularnewline
\endhead
\hline
f1 & f2 & f7 & f8 & f9 & f13 & f16 & f18\tabularnewline
\hline
a1 & a2 & a7 & a8 & a9 & a13 & a16 & a18\tabularnewline
\hline
\hline
b1 & b2 & \multicolumn{1}{c|}{b3} & b8 & b9 & b13 & \multicolumn{2}{c|}{b15}\tabularnewline
\hline
\multicolumn{2}{|c|}{c1} & c7 & c8 & c9 & c13 & c16 & c18\tabularnewline
\hline
d1 & d2 & \multicolumn{3}{c|}{d4} & d13 & \multicolumn{2}{c|}{d16}\tabularnewline
\hline
\multicolumn{2}{|c|}{e1} & e7 & e8 & e9 & \multicolumn{1}{c|}{e12} & e16 & e18\tabularnewline
\hline
g1 & g2 & \multicolumn{5}{c|}{g3} & g18\tabularnewline
\hline
\multicolumn{7}{|c|}{i1} & i3\tabularnewline
\hline
j1 & \multicolumn{7}{c|}{j2}\tabularnewline
\hline
\end{longtable}\begin{longtable}{|c|c|c|c|c|c|}
\hline
fh1 & fh2 & fh9 & fh13 & fh17 & fh18\tabularnewline
\endfirsthead
\hline
h1 & h2 & h9 & h13 & h17 & h18\tabularnewline
\endhead
\hline
f1 & f2 & f9 & f13 & f17 & f18\tabularnewline
\hline
a1 & a2 & a9 & a13 & a17 & a18\tabularnewline
\hline
\hline
b1 & b2 & b9 & b13 & \multicolumn{2}{c|}{b15}\tabularnewline
\hline
\multicolumn{2}{|c|}{c1} & c9 & c13 & c17 & c18\tabularnewline
\hline
d1 & d2 & \multicolumn{1}{c|}{d4} & d13 & \multicolumn{2}{c|}{d16}\tabularnewline
\hline
\multicolumn{2}{|c|}{e1} & e9 & \multicolumn{1}{c|}{e12} & e17 & e18\tabularnewline
\hline
g1 & g2 & \multicolumn{2}{c|}{g3} & g17 & g18\tabularnewline
\hline
\multicolumn{4}{|c|}{i1} & i2 & i3\tabularnewline
\hline
j1 & \multicolumn{5}{c|}{j2}\tabularnewline
\hline
\end{longtable}
\end{document}

View File

@ -0,0 +1,46 @@
%% LyX 2.0.3 created this file. For more info, see http://www.lyx.org/.
%% Do not edit unless you really know what you are doing.
\documentclass[english]{article}
\usepackage[T1]{fontenc}
\usepackage[latin9]{inputenc}
\usepackage{longtable}
\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.
%% Because html converters don't know tabularnewline
\providecommand{\tabularnewline}{\\}
\makeatother
\usepackage{babel}
\begin{document}
\begin{longtable}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|}
\hline
fh1 & fh2 & fh3 & fh4 & fh5 & fh6 & fh7 & fh8 & fh9 & fh10 & fh11 & fh12 & fh13 & fh14 & fh15 & fh16 & fh17 & fh18\tabularnewline
\endfirsthead
\hline
h1 & h2 & h3 & h4 & h5 & h6 & h7 & h8 & h9 & h10 & h11 & h12 & h13 & h14 & h15 & h16 & h17 & h18\tabularnewline
\endhead
\hline
f1 & f2 & f3 & f4 & f5 & f6 & f7 & f8 & f9 & f10 & f11 & f12 & f13 & f14 & f15 & f16 & f17 & f18\tabularnewline
\hline
a1 & a2 & a3 & a4 & a5 & a6 & a7 & a8 & a9 & a10 & a11 & a12 & a13 & a14 & a15 & a16 & a17 & a18\tabularnewline
\hline
\hline
b1 & b2 & \multicolumn{5}{c|}{b3} & b8 & b9 & b10 & b11 & b12 & b13 & b14 & \multicolumn{4}{c|}{b15}\tabularnewline
\hline
\multicolumn{4}{|c|}{c1} & c5 & c6 & c7 & c8 & c9 & \multicolumn{3}{c|}{c10} & c13 & c14 & c15 & c16 & c17 & c18\tabularnewline
\hline
d1 & d2 & d3 & \multicolumn{9}{c|}{d4} & d13 & d14 & d15 & \multicolumn{3}{c|}{d16}\tabularnewline
\hline
\multicolumn{5}{|c|}{e1} & e6 & e7 & e8 & e9 & e10 & e11 & \multicolumn{4}{c|}{e12} & e16 & e17 & e18\tabularnewline
\hline
g1 & g2 & \multicolumn{14}{c|}{g3} & g17 & g18\tabularnewline
\hline
\multicolumn{16}{|c|}{i1} & i2 & i3\tabularnewline
\hline
j1 & \multicolumn{17}{c|}{j2}\tabularnewline
\hline
\end{longtable}
\end{document}